Add documentation for GpioMonitor and Gpio
This commit is contained in:
parent
237925b497
commit
60027f5580
2
debian/changelog
vendored
2
debian/changelog
vendored
@ -1,4 +1,4 @@
|
||||
nymea-gpio (1.0.0) bionic; urgency=medium
|
||||
nymea-gpio (1.0.0) UNRELEASED; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
|
||||
|
||||
4
debian/libnymea-gpio-dev.install.in
vendored
4
debian/libnymea-gpio-dev.install.in
vendored
@ -1,3 +1,3 @@
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-gpio.so
|
||||
usr/include/libnymea-gpio/* usr/include/libnymea-gpio
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/pkgconfig/libnymea-gpio.pc
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/pkgconfig/nymea-gpio.pc
|
||||
usr/include/nymea-gpio/* usr/include/nymea-gpio/
|
||||
|
||||
@ -1,5 +1,89 @@
|
||||
#include "gpio.h"
|
||||
|
||||
/*!
|
||||
\class Gpio
|
||||
\brief Represents a system GPIO in linux systems.
|
||||
|
||||
A "General Purpose Input/Output" (GPIO) is a flexible software-controlled
|
||||
digital signal. They are provided from many kinds of chip, and are familiar
|
||||
to Linux developers working with embedded and custom hardware. Each GPIO
|
||||
represents a bit connected to a particular pin, or "ball" on Ball Grid Array
|
||||
(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}).
|
||||
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" << gpioIn->value();
|
||||
\endcode
|
||||
\sa GpioMonitor, GpioButton
|
||||
*/
|
||||
|
||||
/*! \enum Gpio::Direction
|
||||
This enum type specifies the dirction a \l{Gpio}.
|
||||
\value DirectionInput
|
||||
The \l{Gpio} is configured as \b input.
|
||||
\value DirectionOutput
|
||||
The \l{Gpio} is configured as \b output.
|
||||
\value DirectionInvalid
|
||||
The direction is not valid.
|
||||
*/
|
||||
|
||||
/*! \enum Gpio::Value
|
||||
This enum type specifies the value a \l{Gpio}.
|
||||
\value ValueLow
|
||||
The \l{Gpio} is low.
|
||||
\value ValueHigh
|
||||
The \l{Gpio} is high.
|
||||
\value ValueInvalid
|
||||
The value is not valid.
|
||||
*/
|
||||
|
||||
/*! \enum Gpio::Edge
|
||||
This enum type specifies the edge interrupt type of a \l{Gpio}.
|
||||
\value EdgeFalling
|
||||
The \l{Gpio} reacts on falling edge interrupt.
|
||||
\value EdgeRising
|
||||
The \l{Gpio} reacts on rising edge interrupt.
|
||||
\value EdgeBoth
|
||||
The \l{Gpio} reacts on both, rising and falling edge interrupt.
|
||||
\value EdgeNone
|
||||
The \l{Gpio} does not react on interrupts.
|
||||
*/
|
||||
|
||||
Q_LOGGING_CATEGORY(dcGpio, "Gpio")
|
||||
|
||||
/*! Constructs a \l{Gpio} object to represent a GPIO with the given \a gpio number and \a parent. */
|
||||
|
||||
131
libnymea-gpio/gpiobutton.cpp
Normal file
131
libnymea-gpio/gpiobutton.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include "gpiobutton.h"
|
||||
|
||||
GpioButton::GpioButton(int gpioNumber, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_gpioNumber(gpioNumber)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int GpioButton::gpioNumber() const
|
||||
{
|
||||
return m_gpioNumber;
|
||||
}
|
||||
|
||||
bool GpioButton::activeLow() const
|
||||
{
|
||||
return m_activeLow;
|
||||
}
|
||||
|
||||
void GpioButton::setActiveLow(bool activeLow)
|
||||
{
|
||||
m_activeLow = activeLow;
|
||||
}
|
||||
|
||||
bool GpioButton::repeateLongPressed() const
|
||||
{
|
||||
return m_repeateLongPressed;
|
||||
}
|
||||
|
||||
void GpioButton::setRepeateLongPressed(bool repeateLongPressed)
|
||||
{
|
||||
m_repeateLongPressed = repeateLongPressed;
|
||||
}
|
||||
|
||||
int GpioButton::longPressedTimeout() const
|
||||
{
|
||||
return m_longPressedTimeout;
|
||||
}
|
||||
|
||||
void GpioButton::setLongPressedTimeout(int longPressedTimeout)
|
||||
{
|
||||
m_longPressedTimeout = longPressedTimeout;
|
||||
}
|
||||
|
||||
QString GpioButton::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void GpioButton::setName(const QString &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
void GpioButton::onTimeout()
|
||||
{
|
||||
qCDebug(dcGpio()) << this << "long pressed";
|
||||
emit longPressed();
|
||||
}
|
||||
|
||||
void GpioButton::onInterruptOccured(bool value)
|
||||
{
|
||||
if (value) {
|
||||
// Pressed
|
||||
qCDebug(dcGpio()) << this << "pressed";
|
||||
emit pressed();
|
||||
|
||||
m_timer->setSingleShot(!m_repeateLongPressed);
|
||||
m_timer->start(m_longPressedTimeout);
|
||||
m_time.restart();
|
||||
} else {
|
||||
// Released
|
||||
qCDebug(dcGpio()) << this << "released";
|
||||
emit released();
|
||||
|
||||
m_timer->stop();
|
||||
int duration = m_time.elapsed();
|
||||
|
||||
// Debounce and limit to 500 ms
|
||||
if (duration >= 10 && duration <= 500) {
|
||||
qCDebug(dcGpio()) << this << "clicked";
|
||||
emit clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GpioButton::enable()
|
||||
{
|
||||
// Make sure we have a clean start
|
||||
disable();
|
||||
|
||||
m_monitor = new GpioMonitor(m_gpioNumber, this);
|
||||
m_monitor->setEdge(Gpio::EdgeBoth);
|
||||
m_monitor->setActiveLow(m_activeLow);
|
||||
|
||||
if (!m_monitor->enable()) {
|
||||
qCWarning(dcGpio()) << "Could not enable GPIO monitor for" << this;
|
||||
delete m_monitor;
|
||||
m_monitor = nullptr;
|
||||
return false;
|
||||
}
|
||||
connect(m_monitor, &GpioMonitor::interruptOccured, this, &GpioButton::onInterruptOccured, Qt::DirectConnection);
|
||||
|
||||
// Setup timer, if this timer reaches timeout, a long pressed happend
|
||||
m_timer = new QTimer(this);
|
||||
m_timer->setTimerType(Qt::PreciseTimer);
|
||||
m_timer->setSingleShot(!m_repeateLongPressed);
|
||||
m_timer->setInterval(m_longPressedTimeout);
|
||||
connect(m_timer, &QTimer::timeout, this, &GpioButton::onTimeout, Qt::DirectConnection);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GpioButton::disable()
|
||||
{
|
||||
if (m_monitor) {
|
||||
delete m_monitor;
|
||||
m_monitor = nullptr;
|
||||
}
|
||||
|
||||
if (m_timer) {
|
||||
delete m_timer;
|
||||
m_timer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, GpioButton *gpioButton)
|
||||
{
|
||||
debug.nospace() << "GpioButton(" << gpioButton->gpioNumber() << ", ";
|
||||
debug.nospace() << "name: " << gpioButton->name() << ")";
|
||||
return debug.space();
|
||||
}
|
||||
61
libnymea-gpio/gpiobutton.h
Normal file
61
libnymea-gpio/gpiobutton.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef GPIOBUTTON_H
|
||||
#define GPIOBUTTON_H
|
||||
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
|
||||
#include "gpiomonitor.h"
|
||||
|
||||
class GpioButton : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GpioButton(int gpioNumber, QObject *parent = nullptr);
|
||||
|
||||
int gpioNumber() const;
|
||||
|
||||
bool activeLow() const;
|
||||
void setActiveLow(bool activeLow);
|
||||
|
||||
bool repeateLongPressed() const;
|
||||
void setRepeateLongPressed(bool repeateLongPressed);
|
||||
|
||||
int longPressedTimeout() const;
|
||||
void setLongPressedTimeout(int longPressedTimeout);
|
||||
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
private:
|
||||
int m_gpioNumber;
|
||||
bool m_activeLow = true;
|
||||
bool m_repeateLongPressed = false;
|
||||
int m_longPressedTimeout = 250;
|
||||
QString m_name;
|
||||
|
||||
GpioMonitor *m_monitor = nullptr;
|
||||
QTimer *m_timer = nullptr;
|
||||
|
||||
QTime m_time;
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
void pressed();
|
||||
void released();
|
||||
void longPressed();
|
||||
|
||||
private slots:
|
||||
void onTimeout();
|
||||
void onInterruptOccured(bool value);
|
||||
|
||||
public slots:
|
||||
bool enable();
|
||||
void disable();
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<< (QDebug debug, GpioButton *gpioButton);
|
||||
|
||||
|
||||
#endif // GPIOBUTTON_H
|
||||
@ -1,8 +1,42 @@
|
||||
/*!
|
||||
\class GpioMonitor
|
||||
\brief Monitor for GPIO interrupts.
|
||||
|
||||
This class allows to monitor an input GPIO for the interrupts depending on the \l{Gpio:Edge} configuration.
|
||||
|
||||
\code
|
||||
GpioMonitor *monitor = new GpioMonitor(112, this);
|
||||
|
||||
if (!monitor->enable()) {
|
||||
qWarning() << "Could not enable GPIO monitor";
|
||||
monitor->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
connect(monitor, &GpioMonitor::interruptOccured, this, [this, monitor](bool value){
|
||||
qDebug() << "GPIO value changed" << value;
|
||||
});
|
||||
|
||||
\endcode
|
||||
|
||||
*/
|
||||
|
||||
/*! \fn void GpioMonitor::interruptOccured(bool value);
|
||||
This signal will be emitted, if an interrupt on the monitored Gpio occured with the new \a value. This event depends on the Gpio::Edge configuration of the Gpio.
|
||||
|
||||
\sa edge(), setEdge()
|
||||
*/
|
||||
|
||||
/*! \fn void GpioMonitor::enabledChanged(bool enabled);
|
||||
This signal will be emitted when the GpioMonitor \a enabled changed.
|
||||
*/
|
||||
|
||||
#include "gpiomonitor.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include <QMutexLocker>
|
||||
|
||||
/*! Constructs a \l{GpioMonitor} object with the given \a gpio number and \a parent. */
|
||||
GpioMonitor::GpioMonitor(int gpio, QObject *parent) :
|
||||
QThread(parent),
|
||||
m_gpioNumber(gpio)
|
||||
@ -12,17 +46,28 @@ GpioMonitor::GpioMonitor(int gpio, QObject *parent) :
|
||||
connect(this, &GpioMonitor::finished, this, &GpioMonitor::onThreadFinished, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
/*! Destroys and unexports the Gpio. */
|
||||
GpioMonitor::~GpioMonitor()
|
||||
{
|
||||
disable();
|
||||
wait(200);
|
||||
}
|
||||
|
||||
/*! Returns the edge interrupt configuration for this GpioMonitor.
|
||||
|
||||
\sa Gpio::Edge
|
||||
|
||||
*/
|
||||
Gpio::Edge GpioMonitor::edge() const
|
||||
{
|
||||
return m_edge;
|
||||
}
|
||||
|
||||
/*! Sets the edge interrupt configuration for this GpioMonitor to the given \a edge.
|
||||
|
||||
\sa Gpio::Edge
|
||||
|
||||
*/
|
||||
void GpioMonitor::setEdge(Gpio::Edge edge)
|
||||
{
|
||||
if (m_edge == edge)
|
||||
@ -31,11 +76,13 @@ void GpioMonitor::setEdge(Gpio::Edge edge)
|
||||
m_edge = edge;
|
||||
}
|
||||
|
||||
/*! Returns true, if the monitor is configured as active low. If active low is true, the GPIO values and interrupt behavior will be inverted. */
|
||||
bool GpioMonitor::activeLow() const
|
||||
{
|
||||
return m_activeLow;
|
||||
}
|
||||
|
||||
/*! Sets the the monitor to \a activeLow. If active low is true, the GPIO values and interrupt behavior will be inverted. */
|
||||
void GpioMonitor::setActiveLow(bool activeLow)
|
||||
{
|
||||
if (m_activeLow == activeLow)
|
||||
@ -44,12 +91,14 @@ void GpioMonitor::setActiveLow(bool activeLow)
|
||||
m_activeLow = activeLow;
|
||||
}
|
||||
|
||||
/*! Returns the current value of the Gpio. */
|
||||
Gpio::Value GpioMonitor::value()
|
||||
{
|
||||
QMutexLocker valueLocker(&m_valueMutex);
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/*! Returns true if this GpioMonitor is enabled. */
|
||||
bool GpioMonitor::enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
@ -181,6 +230,7 @@ void GpioMonitor::onThreadFinished()
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
/*! Returns true, if this GpioMonitor was enabled successfully. */
|
||||
bool GpioMonitor::enable()
|
||||
{
|
||||
qCDebug(dcGpio()) << "Enable gpio monitor";
|
||||
@ -203,6 +253,7 @@ bool GpioMonitor::enable()
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Disables this GpioMonitor. The \l{interruptOccured()} signal will not be emitted any more and the Gpio will be unexported. */
|
||||
void GpioMonitor::disable()
|
||||
{
|
||||
qCDebug(dcGpio()) << "Disable gpio monitor";
|
||||
|
||||
@ -32,7 +32,7 @@ private:
|
||||
|
||||
// Thread stuff
|
||||
QMutex m_valueMutex;
|
||||
Gpio::Value m_value = Gpio::ValueInvalid;
|
||||
Gpio::Value m_value = Gpio::ValueInvalid;
|
||||
|
||||
QMutex m_stopMutex;
|
||||
bool m_stop = false;
|
||||
|
||||
@ -5,10 +5,12 @@ TEMPLATE = lib
|
||||
|
||||
HEADERS += \
|
||||
gpio.h \
|
||||
gpiobutton.h \
|
||||
gpiomonitor.h
|
||||
|
||||
SOURCES += \
|
||||
gpio.cpp \
|
||||
gpiobutton.cpp \
|
||||
gpiomonitor.cpp
|
||||
|
||||
target.path = $$[QT_INSTALL_LIBS]
|
||||
@ -16,7 +18,7 @@ INSTALLS += target
|
||||
|
||||
# install header file with relative subdirectory
|
||||
for(header, HEADERS) {
|
||||
path = /usr/include/libnymea-gpio/$${dirname(header)}
|
||||
path = $$[QT_INSTALL_PREFIX]/include/nymea-gpio/$${dirname(header)}
|
||||
eval(headers_$${path}.files += $${header})
|
||||
eval(headers_$${path}.path = $${path})
|
||||
eval(INSTALLS *= headers_$${path})
|
||||
@ -24,11 +26,11 @@ for(header, HEADERS) {
|
||||
|
||||
# Create pkgconfig file
|
||||
CONFIG += create_pc create_prl no_install_prl
|
||||
QMAKE_PKGCONFIG_NAME = libnymea-gpio
|
||||
QMAKE_PKGCONFIG_NAME = nymea-gpio
|
||||
QMAKE_PKGCONFIG_DESCRIPTION = nymea gpio development library
|
||||
QMAKE_PKGCONFIG_PREFIX = $$[QT_INSTALL_PREFIX]
|
||||
QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_PREFIX]/include/libnymea-gpio/
|
||||
QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_PREFIX]/include/nymea-gpio/
|
||||
QMAKE_PKGCONFIG_LIBDIR = $$target.path
|
||||
QMAKE_PKGCONFIG_VERSION = $$VERSION_STRING
|
||||
QMAKE_PKGCONFIG_FILE = libnymea-gpio
|
||||
QMAKE_PKGCONFIG_FILE = nymea-gpio
|
||||
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
|
||||
|
||||
Reference in New Issue
Block a user