final fix for gpio

This commit is contained in:
Simon Stürz 2016-12-06 11:18:45 +01:00 committed by Michael Zanetti
parent 78306cf751
commit cb982ac4f1
2 changed files with 137 additions and 60 deletions

View File

@ -32,11 +32,57 @@
(BGA) packages. Board schematics show which external hardware connects to (BGA) packages. Board schematics show which external hardware connects to
which GPIOs. Drivers can be written generically, so that board setup code which GPIOs. Drivers can be written generically, so that board setup code
passes such pin configuration data to drivers passes such pin configuration data to drivers
(\l{https://www.kernel.org/doc/Documentation/gpio/gpio.txt}{source}. (\l{https://www.kernel.org/doc/Documentation/gpio/gpio.txt}{source}).
General Purpose Input/Output (a.k.a. GPIO) is a generic pin on a chip whose 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 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. through this class. An object of of the Gpio class represents a pin.
\code
Gpio *gpioOut = new Gpio(23, this);
// Export Gpio
if (!gpioOut->exportGpio()) {
qWarning() << "Could not export Gpio" << gpioOut->gpioNumber();
gpioOut->deleteLater();
return;
}
// Configure Gpio direction
if (!gpioOut->setDirection(PiGpio::DirectionOutput)) {
qWarning() << "Could not set direction of Gpio" << gpioOut->gpioNumber();
gpioOut->deleteLater();
return;
}
gpioOut->setValue(Gpio::ValueHigh)
\endcode
\code
Gpio *gpioIn = new Gpio(24, this);
// Export Gpio
if (!gpioIn->exportGpio()) {
qWarning() << "Could not export Gpio" << gpioIn->gpioNumber();
gpioIn->deleteLater();
return;
}
// Configure Gpio direction
if (!gpioIn->setDirection(PiGpio::DirectionInput)) {
qWarning() << "Could not set direction of Gpio" << gpioIn->gpioNumber();
gpioIn->deleteLater();
return;
}
qDebug() << "Current value" << (bool)gpioIn->value();
\endcode
\sa GpioMonitor
*/ */
/*! \enum Gpio::Direction /*! \enum Gpio::Direction
@ -84,11 +130,13 @@
#include <QDebug> #include <QDebug>
/*! Constructs a \l{Gpio} object to represent a GPIO with the given \a gpio number and \a parent. */ /*! Constructs a \l{Gpio} object to represent a GPIO with the given \a gpio number and \a parent. */
Gpio::Gpio(int gpio, QObject *parent) : Gpio::Gpio(const int &gpio, QObject *parent) :
QObject(parent), QObject(parent),
m_gpio(gpio) m_gpio(gpio),
m_direction(Gpio::DirectionInvalid),
m_gpioDirectory(QDir(QString("/sys/class/gpio/gpio%1/").arg(QString::number(gpio))))
{ {
m_gpioDirectory = QDir(QString("/sys/class/gpio/gpio%1/").arg(QString::number(m_gpio))); m_direction = direction();
} }
/*! Destroys and unexports the \l{Gpio}. */ /*! Destroys and unexports the \l{Gpio}. */
@ -100,13 +148,20 @@ Gpio::~Gpio()
/*! Returns the directory \tt {/sys/class/gpio/gpio<number>} of this Gpio. */ /*! Returns the directory \tt {/sys/class/gpio/gpio<number>} of this Gpio. */
QString Gpio::gpioDirectory() const QString Gpio::gpioDirectory() const
{ {
return m_gpioDirectory.path(); return m_gpioDirectory.canonicalPath();
} }
/*! Returns true if the directory \tt {/sys/class/gpio} does exist. */ /*! Returns the number of this \l{Gpio}. \note The Gpio number is mostly not equivalent with the pin number. */
int Gpio::gpioNumber() const
{
return m_gpio;
}
/*! Returns true if the directories \tt {/sys/class/gpio} and \tt {/sys/class/gpio/export} do exist. */
bool Gpio::isAvailable() bool Gpio::isAvailable()
{ {
return QDir("/sys/class/gpio").exists(); return QDir("/sys/class/gpio").exists() && QDir("/sys/class/gpio/export").exists();
} }
/*! Returns true if this \l{Gpio} could be exported in the system file \tt {/sys/class/gpio/export}. If this Gpio is already exported, this function will return true. */ /*! Returns true if this \l{Gpio} could be exported in the system file \tt {/sys/class/gpio/export}. If this Gpio is already exported, this function will return true. */
@ -118,12 +173,12 @@ bool Gpio::exportGpio()
QFile exportFile("/sys/class/gpio/export"); QFile exportFile("/sys/class/gpio/export");
if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text)) { if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Could not export GPIO" << m_gpio; qCWarning(dcHardware()) << "Gpio: Could not open GPIO export file:" << exportFile.errorString();
return false; return false;
} }
QTextStream out(&exportFile); QTextStream out(&exportFile);
out << m_gpio << "\n"; out << m_gpio;
exportFile.close(); exportFile.close();
return true; return true;
} }
@ -133,36 +188,42 @@ bool Gpio::unexportGpio()
{ {
QFile unexportFile("/sys/class/gpio/unexport"); QFile unexportFile("/sys/class/gpio/unexport");
if (!unexportFile.open(QIODevice::WriteOnly | QIODevice::Text)) { if (!unexportFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Could not unexport GPIO" << m_gpio; qCWarning(dcHardware()) << "Gpio: Could not open GPIO unexport file:" << unexportFile.errorString();
return false; return false;
} }
QTextStream out(&unexportFile); QTextStream out(&unexportFile);
out << m_gpio << "\n"; out << m_gpio;
unexportFile.close(); unexportFile.close();
return true; return true;
} }
/*! Returns true if the \a direction of this GPIO could be set. */ /*! Returns true if the \a direction of this GPIO could be set. \sa Gpio::Direction, */
bool Gpio::setDirection(Gpio::Direction direction) bool Gpio::setDirection(Gpio::Direction direction)
{ {
QFile directionFile(m_gpioDirectory.path() + "/direction"); if (direction == Gpio::DirectionInvalid) {
if (!directionFile.open(QIODevice::WriteOnly | QIODevice::Text)) { qCWarning(dcHardware()) << "Gpio: Setting an invalid direction is forbidden.";
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "direction file.";
return false; return false;
} }
QFile directionFile(m_gpioDirectory.path() + "/direction");
if (!directionFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Gpio: Could not open GPIO" << m_gpio << "direction file:" << directionFile.errorString();
return false;
}
m_direction = direction;
QTextStream out(&directionFile); QTextStream out(&directionFile);
switch (direction) { switch (m_direction) {
case DirectionInput: case DirectionInput:
out << "in" << "\n"; out << "in";
break; break;
case DirectionOutput: case DirectionOutput:
out << "out" << "\n"; out << "out";
break; break;
default: default:
directionFile.close(); break;
return false;
} }
directionFile.close(); directionFile.close();
@ -174,7 +235,7 @@ Gpio::Direction Gpio::direction()
{ {
QFile directionFile(m_gpioDirectory.path() + "/direction"); QFile directionFile(m_gpioDirectory.path() + "/direction");
if (!directionFile.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!directionFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "direction file."; qCWarning(dcHardware()) << "Gpio: Could not open GPIO" << m_gpio << "direction file:" << directionFile.errorString();
return Gpio::DirectionInvalid; return Gpio::DirectionInvalid;
} }
@ -197,22 +258,36 @@ Gpio::Direction Gpio::direction()
/*! Returns true if the digital \a value of this \l{Gpio} could be set correctly. */ /*! Returns true if the digital \a value of this \l{Gpio} could be set correctly. */
bool Gpio::setValue(Gpio::Value value) bool Gpio::setValue(Gpio::Value value)
{ {
if (value == Gpio::ValueInvalid || m_direction == Gpio::DirectionInput) // Check given value
if (value == Gpio::ValueInvalid) {
qCWarning(dcHardware()) << "Gpio: Setting an invalid value is forbidden.";
return false; return false;
}
// Check current direction
if (m_direction == Gpio::DirectionInput) {
qCWarning(dcHardware()) << "Gpio: Setting the value of an input GPIO is forbidden.";
return false;
}
if (m_direction == Gpio::DirectionInvalid) {
qCWarning(dcHardware()) << "Gpio: The direction of GPIO" << m_gpio << "is invalid.";
return false;
}
QFile valueFile(m_gpioDirectory.path() + "/value"); QFile valueFile(m_gpioDirectory.path() + "/value");
if (!valueFile.open(QIODevice::WriteOnly | QIODevice::Text)) { if (!valueFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "value file."; qCWarning(dcHardware()) << "Gpio: Could not open GPIO" << m_gpio << "value file:" << valueFile.errorString();
return false; return false;
} }
QTextStream out(&valueFile); QTextStream out(&valueFile);
switch (value) { switch (value) {
case ValueLow: case ValueLow:
out << "0" << "\n"; out << "0";
break; break;
case ValueHigh: case ValueHigh:
out << "1" << "\n"; out << "1";
break; break;
default: default:
valueFile.close(); valueFile.close();
@ -228,7 +303,7 @@ Gpio::Value Gpio::value()
{ {
QFile valueFile(m_gpioDirectory.path() + "/value"); QFile valueFile(m_gpioDirectory.path() + "/value");
if (!valueFile.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!valueFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "value file."; qCWarning(dcHardware()) << "Gpio: Could not open GPIO" << m_gpio << "value file:" << valueFile.errorString();
return Gpio::ValueInvalid; return Gpio::ValueInvalid;
} }
@ -251,15 +326,15 @@ bool Gpio::setActiveLow(bool activeLow)
{ {
QFile activeLowFile(m_gpioDirectory.path() + "/active_low"); QFile activeLowFile(m_gpioDirectory.path() + "/active_low");
if (!activeLowFile.open(QIODevice::WriteOnly | QIODevice::Text)) { if (!activeLowFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "active_low file."; qCWarning(dcHardware()) << "Gpio: Could not open GPIO" << m_gpio << "active_low file:" << activeLowFile.errorString();
return false; return false;
} }
QTextStream out(&activeLowFile); QTextStream out(&activeLowFile);
if (activeLow) { if (activeLow) {
out << "0" << "\n"; out << "0";
} else { } else {
out << "1" << "\n"; out << "1";
} }
activeLowFile.close(); activeLowFile.close();
@ -271,7 +346,7 @@ bool Gpio::activeLow()
{ {
QFile activeLowFile(m_gpioDirectory.path() + "/active_low"); QFile activeLowFile(m_gpioDirectory.path() + "/active_low");
if (!activeLowFile.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!activeLowFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "active_low file."; qCWarning(dcHardware()) << "Gpio: Could not open GPIO" << m_gpio << "active_low file:" << activeLowFile.errorString();
return false; return false;
} }
@ -291,29 +366,29 @@ bool Gpio::activeLow()
bool Gpio::setEdgeInterrupt(Gpio::Edge edge) bool Gpio::setEdgeInterrupt(Gpio::Edge edge)
{ {
if (m_direction == Gpio::DirectionOutput) { if (m_direction == Gpio::DirectionOutput) {
qCWarning(dcHardware()) << "Could not set edge interrupt, GPIO is configured as an output."; qCWarning(dcHardware()) << "Gpio: Could not set edge interrupt, GPIO is configured as an output.";
return false; return false;
} }
QFile edgeFile(m_gpioDirectory.path() + "/edge"); QFile edgeFile(m_gpioDirectory.path() + "/edge");
if (!edgeFile.open(QIODevice::WriteOnly | QIODevice::Text)) { if (!edgeFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "edge file."; qCWarning(dcHardware()) << "Gpio: Could not open GPIO" << m_gpio << "edge file:" << edgeFile.errorString();
return false; return false;
} }
QTextStream out(&edgeFile); QTextStream out(&edgeFile);
switch (edge) { switch (edge) {
case EdgeFalling: case EdgeFalling:
out << "falling" << "\n"; out << "falling";
break; break;
case EdgeRising: case EdgeRising:
out << "rising" << "\n"; out << "rising";
break; break;
case EdgeBoth: case EdgeBoth:
out << "both" << "\n"; out << "both";
break; break;
case EdgeNone: case EdgeNone:
out << "none" << "\n"; out << "none";
break; break;
default: default:
return false; return false;
@ -328,7 +403,7 @@ Gpio::Edge Gpio::edgeInterrupt()
{ {
QFile edgeFile(m_gpioDirectory.path() + "/edge"); QFile edgeFile(m_gpioDirectory.path() + "/edge");
if (!edgeFile.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!edgeFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "edge file."; qCWarning(dcHardware()) << "Gpio: Could not open GPIO" << m_gpio << "edge file:" << edgeFile.errorString();
return Gpio::EdgeNone; return Gpio::EdgeNone;
} }
@ -350,11 +425,6 @@ Gpio::Edge Gpio::edgeInterrupt()
return Gpio::EdgeNone; return Gpio::EdgeNone;
} }
/*! Returns the number of this \l{Gpio}. */
int Gpio::gpioNumber() const
{
return m_gpio;
}
QDebug operator<<(QDebug debug, Gpio *gpio) QDebug operator<<(QDebug debug, Gpio *gpio)
@ -362,28 +432,35 @@ QDebug operator<<(QDebug debug, Gpio *gpio)
debug.nospace() << "Gpio(" << gpio->gpioNumber() << ", "; debug.nospace() << "Gpio(" << gpio->gpioNumber() << ", ";
if (gpio->direction() == Gpio::DirectionInput) { if (gpio->direction() == Gpio::DirectionInput) {
debug.nospace() << "Input, "; debug.nospace() << "Input, ";
switch (gpio->edgeInterrupt()) {
case Gpio::EdgeFalling:
debug.nospace() << "Falling, ";
break;
case Gpio::EdgeRising:
debug.nospace() <<"Rising, ";
break;
case Gpio::EdgeBoth:
debug.nospace() << "Both, ";
break;
case Gpio::EdgeNone:
debug.nospace() << "None, ";
break;
default:
break;
}
} else if (gpio->direction() == Gpio::DirectionOutput) { } else if (gpio->direction() == Gpio::DirectionOutput) {
debug.nospace() << "Output, "; debug.nospace() << "Output, ";
} else { } else {
debug.nospace() << "Invalid, "; debug.nospace() << "Invalid, ";
} }
switch (gpio->edgeInterrupt()) {
case Gpio::EdgeFalling:
debug.nospace() << "Ir: Falling, ";
break;
case Gpio::EdgeRising:
debug.nospace() << "Ir: Rising, ";
break;
case Gpio::EdgeBoth:
debug.nospace() << "Ir: Both, ";
break;
case Gpio::EdgeNone:
debug.nospace() << "Ir: None, ";
break;
default:
break;
}
if (gpio->activeLow()) {
debug.nospace() << "Active Low: 1, ";
} else {
debug.nospace() << "Active Low: 0, ";
}
if (gpio->value() == Gpio::ValueHigh) { if (gpio->value() == Gpio::ValueHigh) {
debug.nospace() << "Value: 1)"; debug.nospace() << "Value: 1)";
} else if (gpio->value() == Gpio::ValueLow) { } else if (gpio->value() == Gpio::ValueLow) {

View File

@ -52,10 +52,11 @@ public:
EdgeNone EdgeNone
}; };
explicit Gpio(int gpio = 0, QObject *parent = 0); explicit Gpio(const int &gpio, QObject *parent = 0);
~Gpio(); ~Gpio();
QString gpioDirectory() const; QString gpioDirectory() const;
int gpioNumber() const;
static bool isAvailable(); static bool isAvailable();
@ -74,7 +75,6 @@ public:
bool setEdgeInterrupt(Gpio::Edge edge); bool setEdgeInterrupt(Gpio::Edge edge);
Gpio::Edge edgeInterrupt(); Gpio::Edge edgeInterrupt();
int gpioNumber() const;
private: private:
int m_gpio; int m_gpio;