我儿子在Raspberry Pi上实现一个服务器,允许通过网络连接控制GPIO引脚。他发现了一些奇怪的行为,最初看起来像一个错误(但请参阅下面的答案)。Raspberry Pi GPIO/value文件暂时出现错误权限
首先,使用的操作系统是Raspbian,Debian Linux的一个版本。他正在使用标准系统文件来控制GPIO端口。
我们从一个GPIO引脚开始,例如,引脚17,处于非导出状态。例如,现在
echo "17" > /sys/class/gpio/unexport
,如果服务器被要求打开销17,它执行以下操作:
- 打开
/sys/class/gpio/export
,写道:“17”的微博,关闭导出文件 - 打开
/sys/class/gpio/gpio17/direction
文件进行读取,检查它是否设置为输入或输出。关闭文件。然后,如有必要,重新打开要写入的文件并将“out”写入文件,将该引脚设置为输出引脚,然后关闭方向文件。
此时,我们应该可以打开/sys/class/gpio/gpio17/value
进行写入,并写入“1”。
但是,存在/sys/class/gpio/gpio17/value
文件的权限,但组权限是只读的。如果我们为了等待几分之一秒而进入“睡眠”状态,权限会发生变化,因此组权限具有写入权限。
我原以为操作系统不应该从写入到direction
文件返回,直到它正确设置了值文件的权限。
这是怎么发生的? 这看起来像一个错误。我应该在哪里报告(更详细的...)?请参阅下面的答案。
以下是代码的相关位。代码已经被编辑和解释了一下,但它基本上是被使用的。 (请记住,这是一个12年级的学生努力学习C++和Unix概念的代码):
class GpioFileOut
{
private:
const string m_fName;
fstream m_fs;
public:
GpioFileOut(const string& sName)
: m_fName(("/sys/class/gpio/" + sName).c_str())
{
m_fs.open(m_fName.c_str());
if (m_fs.fail())
{
cout<<"ERROR: attempted to open " << m_fName << " but failed" << endl << endl;
}
else
{
cout << m_fName << " opened" << endl;
}
}
~GpioFileOut()
{
m_fs.close();
cout << m_fName << " closed" << endl << endl;
}
void reOpen()
{
m_fs.close();
m_fs.open(m_fName);
if (m_fs.fail())
{
cout<<"ERROR: attempted to re-open " << m_fName << " but failed" << endl << endl;
}
else
{
cout << m_fName << " re-opened" << endl;
}
}
GpioFileOut& operator<<(const string &s)
{
m_fs << s << endl;
cout << s << " sent to " << m_fName << endl;
return *this;
}
GpioFileOut& operator<<(int n)
{
return *this << to_string(n); //ostringstream
}
bool fail()
{
return m_fs.fail();
}
};
class GpioFileIn
{
private:
ifstream m_fs;
string m_fName;
public:
GpioFileIn(const string& sName)
: m_fs(("/sys/class/gpio/" + sName).c_str())
, m_fName(("/sys/class/gpio/" + sName).c_str())
{
if (m_fs <= 0 || m_fs.fail())
{
cout<<"ERROR: attempted to open " << m_fName << " but failed" << endl;
}
else
{
cout << m_fName << " opened" << endl;
}
}
~GpioFileIn()
{
m_fs.close();
cout << m_fName << " closed" << endl << endl;
}
void reOpen()
{
m_fs.close();
m_fs.open(m_fName);
if (m_fs <= 0 || m_fs.fail())
{
cout<<"ERROR: attempted to re-open " << m_fName << " but failed" << endl;
}
else
{
cout << m_fName << " re-opened" << endl;
}
}
GpioFileIn& operator>>(string &s)
{
m_fs >> s;
cout << s << " read from " << m_fName << endl;
return *this;
}
bool fail()
{
return m_fs.fail();
}
};
class Gpio
{
public:
static const bool OUT = true;
static const bool IN = false;
static const bool ON = true;
static const bool OFF = false;
static bool setPinDirection(const int pinId, const bool direction)
{
GpioFileOut dirFOut(("gpio" + to_string(pinId) + "/direction").c_str());
if (dirFOut.fail())
{
if (!openPin(pinId))
{
cout << "ERROR! Pin direction not set: Failed to export pin" << endl;
return false;
}
dirFOut.reOpen();
}
dirFOut << (direction == OUT ? "out" : "in");
}
static bool setPinValue(const int pinId, const bool pinValue)
{
string s;
{
GpioFileIn dirFIn(("gpio" + to_string(pinId) + "/direction").c_str());
if (dirFIn.fail())
{
if (!openPin(pinId))
{
cout << "ERROR! Pin not set: Failed to export pin"<<endl;
return false;
}
dirFIn.reOpen();
}
dirFIn >> s;
}
if (strncmp(s.c_str(), "out", 3) == 0)
{
struct stat _stat;
int nTries = 0;
string fname("/sys/class/gpio/gpio"+to_string(pinId)+"/value");
for(;;)
{
if (stat(fname.c_str(), &_stat) == 0)
{
cout << _stat.st_mode << endl;
if (_stat.st_mode & 020)
break;
}
else
{
cout << "stat failed. (Did the pin get exported successfully?)" << endl;
}
cout << "sleeping until value file appears with correct permissions." << endl;
if (++nTries > 10)
{
cout << "giving up!";
return false;
}
usleep(100*1000);
};
GpioFileOut(("gpio" + to_string(pinId) + "/value").c_str()) << pinValue;
return true;
}
return false;
}
static bool openPin(const int pinId)
{
GpioFileOut fOut("export");
if (fOut.fail())
return false;
fOut << to_string(pinId);
return true;
}
}
int main()
{
Gpio::openPin(17);
Gpio::setPinDirection(17, Gpio::OUT)
Gpio::setPinValue(17, Gpio::ON);
}
关键的一点是:没有for(;;)
环路stat
的文件,执行失败,我们可以在100ms内看到文件权限的变化。
您应该最好尝试将您的问题发布到http://raspberrypi.stackexchange.com/ – mpromonet 2014-09-06 13:43:05
谢谢。会做。 – 2014-09-06 16:41:11
感谢您的编辑 - 现在我知道如何制作一个列表。 – 2014-09-06 16:47:09