补充 用户态 GPIO 示例.

Signed-off-by: lion.chan <cy187lion@sina.com>
This commit is contained in:
lion.chan 2022-04-05 13:12:22 +08:00
parent a50314c4e2
commit 6dddc8e048
1 changed files with 205 additions and 0 deletions

View File

@ -98,3 +98,208 @@ block 目录包含所有的块设备devices 目录包含系统所有的设备
在 /sys/bus 的 pci 等子目录下,又会在分出 drivers 和 devices 目录,而 devices 目录中的文件是对 /sys/devices 目录中文件的符号链接。同样地,/sys/class 目录下包含许多对 /sys/devices 下文件的链接。这与设备、驱动、总线和类的现实状况是直接对应的,也正符合 Linux 2.6 内核的设备模型。
![sysfs 文件系统下的文件相互交织](./imgs/8.5_Linux_文件系统与设备文件系统/002.png)
## 用户态 GPIO 示例
下面以 GPIO 操作为例,演示设备文件系统的使用方法,该示例为 c++ 工程,包含一个 cmake 文件,一个 Gpio 类和一个 main.cpp 文件,其中 Gpio 类封装了 GPIO 端口导出和读写机制。
main.cpp 内容如下:
```cpp
/**
* @file: main.cpp
*/
#include <iostream>
#include "Gpio.h"
using namespace std;
const char* Gpio::GpioPortTbl[] =
{
"372",
};
int main()
{
Gpio* gpio = new Gpio(0, Gpio::EC_ATTR_R);
Gpio::EU_PORT_LEVEL rlevel = gpio->ReadPort();
cout << "Read GPIO Port Level: " << rlevel << endl;
return 0;
}
```
Gpio.h 内容如下:
```cpp
/**
* @file: Gpio.h
*/
#ifndef GPIO_H
#define GPIO_H
#include <string>
#define POLL_TIMEOUT (1 * 1000)
using namespace std;
class Gpio
{
public:
enum EU_PORT_LEVEL
{
EC_PORT_N = 0,
EC_PORT_L = '0',
EC_PORT_H = '1'
};
enum EU_PORT_ATTR
{
EC_ATTR_R, // Readable
EC_ATTR_W // Writeable
};
static const char* GpioPortTbl[];
Gpio(int id=0, EU_PORT_ATTR attr=EC_ATTR_R);
EU_PORT_ATTR GetAttr(void) const { return PortAttr; }
const char* GetNo(void) const { return GpioPortTbl[PortID]; }
int GetFd(void) const { return Fd; }
bool WritePort(EU_PORT_LEVEL val);
EU_PORT_LEVEL ReadPort(void);
protected:
const int PortID;
const EU_PORT_ATTR PortAttr;
int Fd;
char LastStu;
char CurtStu;
private:
void Export(void);
};
#endif // GPIO_H
```
Gpio.cpp 内容如下:
```cpp
/**
* @file: Gpio.cpp
*/
#include "Gpio.h"
#include <string.h>
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
Gpio::Gpio(int id, EU_PORT_ATTR attr):
PortID(id), PortAttr(attr)
{
Fd = -1;
LastStu = EC_PORT_L;
CurtStu = EC_PORT_L;
Export();
}
bool Gpio::WritePort(EU_PORT_LEVEL val)
{
int ret = -1;
char wVal = (char)val;
if(0>=Fd)
return false;
if(EC_ATTR_W!=PortAttr)
return false;
lseek(Fd, 0, SEEK_SET);
ret = write(Fd, &wVal, 1);
if(0>ret)
return false;
return true;
}
Gpio::EU_PORT_LEVEL Gpio::ReadPort(void)
{
int ret = -1;
if(0>=Fd)
{
cout << "Read Gpio" << GpioPortTbl[PortID] << "Error Fd=" << Fd;
return EC_PORT_N;
}
lseek(Fd, 0, SEEK_SET);
ret = read(Fd, &CurtStu, 1);
cout << "Read Gpio" << GpioPortTbl[PortID] << " Ret=" << ret << " Val=" << CurtStu << endl;
switch(CurtStu)
{
case EC_PORT_L:
return EC_PORT_L;
case EC_PORT_H:
return EC_PORT_H;
default:
return EC_PORT_N;
}
}
void Gpio::Export(void)
{
// Export.
int fd = open("/sys/class/gpio/export", O_WRONLY);
if(fd<0)
return;
write(fd, GpioPortTbl[PortID], strlen(GpioPortTbl[PortID]));
close(fd);
// Set direction.
string dir = string("/sys/class/gpio/gpio")+
string(GpioPortTbl[PortID])+
string("/direction");
fd = open(dir.c_str(), O_WRONLY);
if(fd<0)
return;
if(PortAttr==EC_ATTR_R)
write(fd, "in", 2);
else
write(fd, "out", 3);
close(fd);
// Set edge.
if(PortAttr==EC_ATTR_R)
{
string edge = string("/sys/class/gpio/gpio")+
string(GpioPortTbl[PortID])+
string("/edge");
fd = open(edge.c_str(), O_WRONLY);
if(fd<0)
return;
write(fd, "both", 4);
close(fd);
}
string name = string("/sys/class/gpio/gpio")+
string(GpioPortTbl[PortID])+
string("/value");
Fd = open(name.c_str(), (PortAttr==EC_ATTR_R) ? O_RDONLY|O_NONBLOCK : O_WRONLY|O_NONBLOCK);
cout << "Open:" << name << "Fd=" << Fd << endl;
}
```
CMakeLists.txt 如下:
```cmake
cmake_minimum_required(VERSION 3.5)
project(c08_05 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(c08_05 main.cpp Gpio.h Gpio.cpp)
```