mirror of https://github.com/nymea/nymea.git
314 lines
6.9 KiB
C++
314 lines
6.9 KiB
C++
/*!
|
|
\class Gpio
|
|
\brief The Gpio class helps to interact with the gpio pins of the Raspberry Pi.
|
|
|
|
\inmodule libguh
|
|
|
|
The Raspberry Pi offers lower-level interfaces (GPIO's) intended to connect more directly
|
|
with chips and subsystem modules. General Purpose Input/Output (a.k.a. GPIO) is a generic
|
|
pin on a chip whose behavior (including whether it is an input or output pin) can be controlled
|
|
through this class. An object of of the Gpio class represents a pin on the board.
|
|
|
|
In following table is a list of all GPIO's of the Raspberry Pi Rev. 2.0:
|
|
|
|
\image gpio.png "Gpio settings"
|
|
|
|
Valid GPIO's for this class are those with a GPIO number (for example GPIO 22, which is on pin Nr. 15)
|
|
|
|
*/
|
|
|
|
#include "gpio.h"
|
|
#include <QDebug>
|
|
|
|
/*! Constructs a \l{Gpio} object to represent a GPIO with the given \a gpio number and the \a parent. */
|
|
Gpio::Gpio(QObject *parent, int gpio) :
|
|
QThread(parent),m_gpio(gpio)
|
|
{
|
|
exportGpio();
|
|
}
|
|
|
|
/*! Destroys the Gpio object and unexports the GPIO. */
|
|
Gpio::~Gpio()
|
|
{
|
|
unexportGpio();
|
|
}
|
|
|
|
/*! The starting point for the thread. After calling start(), this thread calls this function and starts
|
|
* to poll the GPIO file. If an interrupt happens to this GPIO pin, the signal pinInterrupt() gets
|
|
* emited.
|
|
*/
|
|
void Gpio::run()
|
|
{
|
|
struct pollfd fdset[2];
|
|
int gpio_fd = openGpio();
|
|
int nfds = 2;
|
|
int rc;
|
|
int timeout = 3000;
|
|
char buf[64];
|
|
|
|
bool enabled = true;
|
|
|
|
m_mutex.lock();
|
|
m_enabled = true;
|
|
m_mutex.unlock();
|
|
|
|
|
|
while(enabled){
|
|
memset((void*)fdset, 0, sizeof(fdset));
|
|
fdset[0].fd = STDIN_FILENO;
|
|
fdset[0].events = POLLIN;
|
|
|
|
fdset[1].fd = gpio_fd;
|
|
fdset[1].events = POLLPRI;
|
|
|
|
rc = poll(fdset, nfds, timeout);
|
|
|
|
if (rc < 0) {
|
|
qDebug() << "ERROR: poll failed";
|
|
return;
|
|
}
|
|
if(rc == 0){
|
|
//timeout
|
|
}
|
|
if (fdset[1].revents & POLLPRI) {
|
|
read(fdset[1].fd, buf, 64);
|
|
emit pinInterrupt();
|
|
}
|
|
m_mutex.lock();
|
|
enabled = m_enabled;
|
|
m_mutex.unlock();
|
|
}
|
|
}
|
|
/*! Returns true if the GPIO could be exported in the system file "/sys/class/gpio/export".*/
|
|
bool Gpio::exportGpio()
|
|
{
|
|
char buf[64];
|
|
|
|
int fd = open("/sys/class/gpio/export", O_WRONLY);
|
|
if (fd < 0) {
|
|
qDebug() << "ERROR: could not open /sys/class/gpio/export";
|
|
return false;
|
|
}
|
|
|
|
int len = snprintf(buf, sizeof(buf), "%d", m_gpio);
|
|
write(fd, buf, len);
|
|
close(fd);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*! Returns true if the GPIO could be unexported in the system file "/sys/class/gpio/unexport".*/
|
|
bool Gpio::unexportGpio()
|
|
{
|
|
char buf[64];
|
|
|
|
int fd = open("/sys/class/gpio/unexport", O_WRONLY);
|
|
if (fd < 0) {
|
|
qDebug() << "ERROR: could not open /sys/class/gpio/unexport";
|
|
return false;
|
|
}
|
|
int len = snprintf(buf, sizeof(buf), "%d", m_gpio);
|
|
write(fd, buf, len);
|
|
close(fd);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*! Returns true if the GPIO file could be opend.*/
|
|
int Gpio::openGpio()
|
|
{
|
|
char buf[64];
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", m_gpio);
|
|
|
|
int fd = open(buf, O_RDONLY | O_NONBLOCK );
|
|
if (fd < 0) {
|
|
qDebug() << "ERROR: could not open /sys/class/gpio" << m_gpio << "/direction";
|
|
return fd;
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
/*! Returns true, if the direction \a dir of the GPIO could be set correctly.
|
|
*
|
|
* Possible directions are:
|
|
*
|
|
* \table
|
|
* \header
|
|
* \li {2,1} Pin directions
|
|
* \row
|
|
* \li 0
|
|
* \li INPUT
|
|
* \row
|
|
* \li 1
|
|
* \li OUTPUT
|
|
* \endtable
|
|
*/
|
|
bool Gpio::setDirection(int dir)
|
|
{
|
|
char buf[64];
|
|
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", m_gpio);
|
|
|
|
int fd = open(buf, O_WRONLY);
|
|
if (fd < 0) {
|
|
qDebug() << "ERROR: could not open /sys/class/gpio" << m_gpio << "/direction";
|
|
return false;
|
|
}
|
|
if(dir == INPUT){
|
|
write(fd, "in", 3);
|
|
m_dir = INPUT;
|
|
close(fd);
|
|
return true;
|
|
}
|
|
if(dir == OUTPUT){
|
|
write(fd, "out", 4);
|
|
m_dir = OUTPUT;
|
|
close(fd);
|
|
return true;
|
|
}
|
|
close(fd);
|
|
return false;
|
|
}
|
|
/*! Returns true, if the digital \a value of the GPIO could be set correctly.
|
|
*
|
|
* Possible \a value 's are:
|
|
*
|
|
* \table
|
|
* \header
|
|
* \li {2,1} Pin value
|
|
* \row
|
|
* \li 0
|
|
* \li LOW
|
|
* \row
|
|
* \li 1
|
|
* \li HIGH
|
|
* \endtable
|
|
*/
|
|
bool Gpio::setValue(unsigned int value)
|
|
{
|
|
// check if gpio is a output
|
|
if( m_dir == OUTPUT){
|
|
char buf[64];
|
|
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", m_gpio);
|
|
|
|
int fd = open(buf, O_WRONLY);
|
|
if (fd < 0) {
|
|
qDebug() << "ERROR: could not open /sys/class/gpio" << m_gpio << "/value";
|
|
return false;
|
|
}
|
|
|
|
if(value == LOW){
|
|
write(fd, "0", 2);
|
|
close(fd);
|
|
return true;
|
|
}
|
|
if(value == HIGH){
|
|
write(fd, "1", 2);
|
|
close(fd);
|
|
return true;
|
|
}
|
|
close(fd);
|
|
return false;
|
|
}else{
|
|
qDebug() << "ERROR: Gpio" << m_gpio << "is not a OUTPUT.";
|
|
return false;
|
|
}
|
|
}
|
|
/*! Returns the current digital value of the GPIO.
|
|
*
|
|
* Possible values are:
|
|
*
|
|
* \table
|
|
* \header
|
|
* \li {2,1} Pin directions
|
|
* \row
|
|
* \li 0
|
|
* \li LOW
|
|
* \row
|
|
* \li 1
|
|
* \li HIGH
|
|
* \endtable
|
|
*/
|
|
int Gpio::getValue()
|
|
{
|
|
char buf[64];
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", m_gpio);
|
|
|
|
int fd = open(buf, O_RDONLY);
|
|
if (fd < 0) {
|
|
qDebug() << "ERROR: could not open /sys/class/gpio" << m_gpio << "/value";
|
|
return -1;
|
|
}
|
|
char ch;
|
|
int value = -1;
|
|
read(fd, &ch, 1);
|
|
|
|
if (ch != '0') {
|
|
value = 1;
|
|
}else{
|
|
value = 0;
|
|
}
|
|
close(fd);
|
|
|
|
qDebug() << "gpio" << m_gpio << "value = " << value;
|
|
return value;
|
|
}
|
|
|
|
/*! Returns true, if the \a edge of the GPIO could be set correctly. The \a edge parameter specifies,
|
|
* when an interrupt occurs.
|
|
*
|
|
* Possible values are:
|
|
*
|
|
* \table
|
|
* \header
|
|
* \li {2,1} Edge possibilitys
|
|
* \row
|
|
* \li 0
|
|
* \li EDGE_FALLING
|
|
* \row
|
|
* \li 1
|
|
* \li EDGE_RISING
|
|
* \row
|
|
* \li 2
|
|
* \li EDGE_BOTH
|
|
* \endtable
|
|
*/
|
|
bool Gpio::setEdgeInterrupt(int edge)
|
|
{
|
|
char buf[64];
|
|
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/edge", m_gpio);
|
|
|
|
int fd = open(buf, O_WRONLY);
|
|
if (fd < 0) {
|
|
qDebug() << "ERROR: could not open /sys/class/gpio" << m_gpio << "/edge";
|
|
return false;
|
|
}
|
|
|
|
if(edge == EDGE_FALLING){
|
|
write(fd, "falling", 8);
|
|
close(fd);
|
|
return true;
|
|
}
|
|
if(edge == EDGE_RISING){
|
|
write(fd, "rising", 7);
|
|
close(fd);
|
|
return true;
|
|
}
|
|
if(edge == EDGE_BOTH){
|
|
write(fd, "both", 5);
|
|
close(fd);
|
|
return true;
|
|
}
|
|
close(fd);
|
|
return false;
|
|
}
|
|
|
|
/*! Stop the polling of the \l{run()} method.*/
|
|
void Gpio::stop()
|
|
{
|
|
m_mutex.lock();
|
|
m_enabled = false;
|
|
m_mutex.unlock();
|
|
}
|