From cb982ac4f190d464ed15e42c47e1e949cd2173f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 6 Dec 2016 11:18:45 +0100 Subject: [PATCH] final fix for gpio --- libguh/hardware/gpio.cpp | 193 +++++++++++++++++++++++++++------------ libguh/hardware/gpio.h | 4 +- 2 files changed, 137 insertions(+), 60 deletions(-) diff --git a/libguh/hardware/gpio.cpp b/libguh/hardware/gpio.cpp index 396f731b..a9216550 100644 --- a/libguh/hardware/gpio.cpp +++ b/libguh/hardware/gpio.cpp @@ -32,11 +32,57 @@ (BGA) packages. Board schematics show which external hardware connects to which GPIOs. Drivers can be written generically, so that board setup code 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 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. + + + \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 @@ -84,11 +130,13 @@ #include /*! 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), - 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}. */ @@ -100,13 +148,20 @@ Gpio::~Gpio() /*! Returns the directory \tt {/sys/class/gpio/gpio} of this Gpio. */ 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() { - 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. */ @@ -118,12 +173,12 @@ bool Gpio::exportGpio() QFile exportFile("/sys/class/gpio/export"); 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; } QTextStream out(&exportFile); - out << m_gpio << "\n"; + out << m_gpio; exportFile.close(); return true; } @@ -133,36 +188,42 @@ bool Gpio::unexportGpio() { QFile unexportFile("/sys/class/gpio/unexport"); 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; } QTextStream out(&unexportFile); - out << m_gpio << "\n"; + out << m_gpio; unexportFile.close(); 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) { - QFile directionFile(m_gpioDirectory.path() + "/direction"); - if (!directionFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "direction file."; + if (direction == Gpio::DirectionInvalid) { + qCWarning(dcHardware()) << "Gpio: Setting an invalid direction is forbidden."; 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); - switch (direction) { + switch (m_direction) { case DirectionInput: - out << "in" << "\n"; + out << "in"; break; case DirectionOutput: - out << "out" << "\n"; + out << "out"; break; default: - directionFile.close(); - return false; + break; } directionFile.close(); @@ -174,7 +235,7 @@ Gpio::Direction Gpio::direction() { QFile directionFile(m_gpioDirectory.path() + "/direction"); 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; } @@ -197,22 +258,36 @@ Gpio::Direction Gpio::direction() /*! Returns true if the digital \a value of this \l{Gpio} could be set correctly. */ 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; + } + + // 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"); 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; } QTextStream out(&valueFile); switch (value) { case ValueLow: - out << "0" << "\n"; + out << "0"; break; case ValueHigh: - out << "1" << "\n"; + out << "1"; break; default: valueFile.close(); @@ -228,7 +303,7 @@ Gpio::Value Gpio::value() { QFile valueFile(m_gpioDirectory.path() + "/value"); 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; } @@ -251,15 +326,15 @@ bool Gpio::setActiveLow(bool activeLow) { QFile activeLowFile(m_gpioDirectory.path() + "/active_low"); 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; } QTextStream out(&activeLowFile); if (activeLow) { - out << "0" << "\n"; + out << "0"; } else { - out << "1" << "\n"; + out << "1"; } activeLowFile.close(); @@ -271,7 +346,7 @@ bool Gpio::activeLow() { QFile activeLowFile(m_gpioDirectory.path() + "/active_low"); 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; } @@ -291,29 +366,29 @@ bool Gpio::activeLow() bool Gpio::setEdgeInterrupt(Gpio::Edge edge) { 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; } QFile edgeFile(m_gpioDirectory.path() + "/edge"); 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; } QTextStream out(&edgeFile); switch (edge) { case EdgeFalling: - out << "falling" << "\n"; + out << "falling"; break; case EdgeRising: - out << "rising" << "\n"; + out << "rising"; break; case EdgeBoth: - out << "both" << "\n"; + out << "both"; break; case EdgeNone: - out << "none" << "\n"; + out << "none"; break; default: return false; @@ -328,7 +403,7 @@ Gpio::Edge Gpio::edgeInterrupt() { QFile edgeFile(m_gpioDirectory.path() + "/edge"); 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; } @@ -350,11 +425,6 @@ Gpio::Edge Gpio::edgeInterrupt() return Gpio::EdgeNone; } -/*! Returns the number of this \l{Gpio}. */ -int Gpio::gpioNumber() const -{ - return m_gpio; -} QDebug operator<<(QDebug debug, Gpio *gpio) @@ -362,28 +432,35 @@ QDebug operator<<(QDebug debug, Gpio *gpio) debug.nospace() << "Gpio(" << gpio->gpioNumber() << ", "; if (gpio->direction() == Gpio::DirectionInput) { 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) { debug.nospace() << "Output, "; } else { 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) { debug.nospace() << "Value: 1)"; } else if (gpio->value() == Gpio::ValueLow) { diff --git a/libguh/hardware/gpio.h b/libguh/hardware/gpio.h index e61874d8..f57356b3 100644 --- a/libguh/hardware/gpio.h +++ b/libguh/hardware/gpio.h @@ -52,10 +52,11 @@ public: EdgeNone }; - explicit Gpio(int gpio = 0, QObject *parent = 0); + explicit Gpio(const int &gpio, QObject *parent = 0); ~Gpio(); QString gpioDirectory() const; + int gpioNumber() const; static bool isAvailable(); @@ -74,7 +75,6 @@ public: bool setEdgeInterrupt(Gpio::Edge edge); Gpio::Edge edgeInterrupt(); - int gpioNumber() const; private: int m_gpio;