Merge PR #1: Initial version
This commit is contained in:
commit
62f0e9ac0c
2
.gitignore
vendored
2
.gitignore
vendored
@ -41,3 +41,5 @@ target_wrapper.*
|
||||
|
||||
# QtCreator CMake
|
||||
CMakeLists.txt.user*
|
||||
|
||||
.crossbuilder
|
||||
|
||||
3
debian/changelog
vendored
Normal file
3
debian/changelog
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
nymea-gpio (1.0.0) UNRELEASED; urgency=medium
|
||||
|
||||
-- Simon Stürz <simon.stuerz@nymea.io> Wed, 04 Sep 2019 11:50:53 +0200
|
||||
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
||||
9
|
||||
48
debian/control
vendored
Normal file
48
debian/control
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
Source: nymea-gpio
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Maintainer: Simon Stürz <simon.stuerz@nymea.io>
|
||||
Build-Depends: debhelper (>= 9.0.0),
|
||||
dpkg-dev (>= 1.16.1~),
|
||||
qt5-default,
|
||||
qt5-qmake,
|
||||
qtbase5-dev,
|
||||
qtbase5-dev-tools
|
||||
Standards-Version: 3.9.7
|
||||
|
||||
Package: libnymea-gpio
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends}
|
||||
Description: Qt 5 based library for GPIO interaction.
|
||||
Qt 5 based library for GPIO interaction.
|
||||
|
||||
Package: nymea-gpio-tool
|
||||
Section: tools
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
libnymea-gpio (= ${binary:Version})
|
||||
Description: Qt 5 based tool for GPIO interaction.
|
||||
Qt 5 based tool for GPIO interaction.
|
||||
|
||||
Package: libnymea-gpio-dev
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
pkg-config,
|
||||
libnymea-gpio (= ${binary:Version})
|
||||
Description: Qt 5 based library for GPIO interaction - development files
|
||||
Development files for Qt 5 based GPIO library.
|
||||
|
||||
Package: libnymea-gpio-dbg
|
||||
Priority: extra
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
libnymea-gpio (= ${binary:Version})
|
||||
Description: Qt 5 based library for GPIO interaction - debug symbols
|
||||
Debug Symbols for Qt 5 based GPIO library.
|
||||
19
debian/copyright
vendored
Normal file
19
debian/copyright
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Author: Simon Stürz <simon.stuerz@nymea.io>
|
||||
Download: https://github.com/guh/nymea-gpio
|
||||
|
||||
License: LGPL-3
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/LGPL-3'.
|
||||
|
||||
License: GPL-3+
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/GPL-3'.
|
||||
|
||||
Files: libnymea-gpio/*
|
||||
Copyright: (C) 2019 Simon Stürz <simon.stuerz@nymea.io>
|
||||
License: LGPL-3
|
||||
|
||||
Files: nymea-gpio-tool/*
|
||||
Copyright: (C) 2019 Simon Stürz <simon.stuerz@nymea.io>
|
||||
License: GPL-3+
|
||||
3
debian/libnymea-gpio-dev.install.in
vendored
Normal file
3
debian/libnymea-gpio-dev.install.in
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-gpio.so
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/pkgconfig/nymea-gpio.pc
|
||||
usr/include/nymea-gpio/* usr/include/nymea-gpio/
|
||||
3
debian/libnymea-gpio.install.in
vendored
Normal file
3
debian/libnymea-gpio.install.in
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-gpio.so.1
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-gpio.so.1.0
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-gpio.so.1.0.0
|
||||
1
debian/nymea-gpio-tool.install.in
vendored
Normal file
1
debian/nymea-gpio-tool.install.in
vendored
Normal file
@ -0,0 +1 @@
|
||||
nymea-gpio-tool/nymea-gpio-tool usr/bin
|
||||
22
debian/rules
vendored
Executable file
22
debian/rules
vendored
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
export DH_VERBOSE=1
|
||||
DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
|
||||
|
||||
PREPROCESS_FILES := $(wildcard debian/*.in)
|
||||
|
||||
$(PREPROCESS_FILES:.in=): %: %.in
|
||||
sed 's,/@DEB_HOST_MULTIARCH@,$(DEB_HOST_MULTIARCH:%=/%),g' $< > $@
|
||||
|
||||
%:
|
||||
dh $@ --buildsystem=qmake --parallel
|
||||
|
||||
override_dh_install: $(PREPROCESS_FILES:.in=)
|
||||
dh_install
|
||||
|
||||
override_dh_strip:
|
||||
dh_strip --dbg-package=libnymea-gpio-dbg
|
||||
|
||||
override_dh_auto_clean:
|
||||
dh_auto_clean
|
||||
rm -rf $(PREPROCESS_FILES:.in=)
|
||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@ -0,0 +1 @@
|
||||
3.0 (native)
|
||||
30
docs/config.qdocconf
Normal file
30
docs/config.qdocconf
Normal file
@ -0,0 +1,30 @@
|
||||
include(html-template.qdocconf)
|
||||
|
||||
project = nymea-gpio
|
||||
description = nymea-gpio documentation
|
||||
|
||||
dita.metadata.default.author = Simon Stürz
|
||||
dita.metadata.default.permissions = all
|
||||
dita.metadata.default.publisher = guh GmbH
|
||||
dita.metadata.default.copyryear = 2019
|
||||
dita.metadata.default.copyrholder = Simon Stürz
|
||||
dita.metadata.default.audience = programmer
|
||||
|
||||
outputdir = html
|
||||
outputformats = HTML
|
||||
|
||||
language = Cpp
|
||||
|
||||
naturallanguage = en_US
|
||||
outputencoding = UTF-8
|
||||
sourceencoding = UTF-8
|
||||
|
||||
syntaxhighlighting = true
|
||||
|
||||
headerdirs = ../libnymea-gpio
|
||||
sourcedirs = ../libnymea-gpio ../docs
|
||||
|
||||
headers.fileextensions = "*.h"
|
||||
sources.fileextensions = "*.cpp *.qdoc"
|
||||
|
||||
Cpp.ignoredirectives = Q_DECLARE_METATYPE Q_DECLARE_LOGGING_CATEGORY Q_LOGGING_CATEGORY Q_ENUM
|
||||
11
docs/html-template.qdocconf
Normal file
11
docs/html-template.qdocconf
Normal file
@ -0,0 +1,11 @@
|
||||
HTML.templatedir = .
|
||||
|
||||
HTML.postpostheader = \
|
||||
"<div class=\"content mainContent\">\n"
|
||||
|
||||
HTML.prologue = \
|
||||
"<div class=\"context\">\n"
|
||||
|
||||
HTML.footer = \
|
||||
"</div>\n" \
|
||||
"</div>\n"
|
||||
11
docs/index.qdoc
Normal file
11
docs/index.qdoc
Normal file
@ -0,0 +1,11 @@
|
||||
/*!
|
||||
\page index.html
|
||||
\title nymea-gpio documentation
|
||||
|
||||
The nymea-gpio library allowes to interact in an confortable way with system GPIOs.
|
||||
|
||||
\chapter Classes
|
||||
\annotatedlist gpio
|
||||
|
||||
*/
|
||||
|
||||
478
libnymea-gpio/gpio.cpp
Normal file
478
libnymea-gpio/gpio.cpp
Normal file
@ -0,0 +1,478 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||
* *
|
||||
* This file is part of nymea-gpio. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/*!
|
||||
\class Gpio
|
||||
\brief Represents a system GPIO in linux systems.
|
||||
\inmodule nymea-gpio
|
||||
\ingroup gpio
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\enum Gpio::Direction
|
||||
This enum type specifies the dirction a Gpio.
|
||||
|
||||
\value DirectionInput
|
||||
The Gpio is configured as \b input.
|
||||
\value DirectionOutput
|
||||
The Gpio is configured as \b output.
|
||||
\value DirectionInvalid
|
||||
The direction is not valid.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum Gpio::Value
|
||||
This enum type specifies the value a Gpio.
|
||||
|
||||
\value ValueInvalid
|
||||
The value is not valid.
|
||||
\value ValueLow
|
||||
The Gpio is low.
|
||||
\value ValueHigh
|
||||
The Gpio is high.
|
||||
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum Gpio::Edge
|
||||
This enum type specifies the edge interrupt type of a Gpio.
|
||||
|
||||
\value EdgeFalling
|
||||
The Gpio reacts on falling edge interrupt.
|
||||
\value EdgeRising
|
||||
The Gpio reacts on rising edge interrupt.
|
||||
\value EdgeBoth
|
||||
The Gpio reacts on both, rising and falling edge interrupt.
|
||||
\value EdgeNone
|
||||
The Gpio does not react on interrupts.
|
||||
*/
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(dcGpio, "Gpio")
|
||||
|
||||
/*! Constructs a Gpio object to represent a GPIO with the given \a gpio number and \a parent. */
|
||||
Gpio::Gpio(int gpio, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_gpio(gpio),
|
||||
m_direction(Gpio::DirectionInvalid),
|
||||
m_gpioDirectory(QDir(QString("/sys/class/gpio/gpio%1").arg(QString::number(gpio))))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Destroys and unexports the Gpio. */
|
||||
Gpio::~Gpio()
|
||||
{
|
||||
unexportGpio();
|
||||
}
|
||||
|
||||
/*! Returns true if the directories \tt {/sys/class/gpio} and \tt {/sys/class/gpio/export} do exist. */
|
||||
bool Gpio::isAvailable()
|
||||
{
|
||||
return QFile("/sys/class/gpio/export").exists();
|
||||
}
|
||||
|
||||
/*! Returns the directory \tt {/sys/class/gpio/gpio<number>} of this Gpio. */
|
||||
QString Gpio::gpioDirectory() const
|
||||
{
|
||||
return m_gpioDirectory.canonicalPath();
|
||||
}
|
||||
|
||||
/*! Returns the number of this Gpio.
|
||||
\note The Gpio number is mostly not equivalent with the pin number.
|
||||
*/
|
||||
int Gpio::gpioNumber() const
|
||||
{
|
||||
return m_gpio;
|
||||
}
|
||||
|
||||
/*! Returns true if this Gpio could be exported in the system file \tt {/sys/class/gpio/export}. If this Gpio is already exported, this function will return true. */
|
||||
bool Gpio::exportGpio()
|
||||
{
|
||||
qCDebug(dcGpio()) << "Export GPIO" << m_gpio;
|
||||
// Check if already exported
|
||||
if (m_gpioDirectory.exists()) {
|
||||
qCDebug(dcGpio()) << "GPIO" << m_gpio << "already exported.";
|
||||
return true;
|
||||
}
|
||||
|
||||
QFile exportFile("/sys/class/gpio/export");
|
||||
if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO export file:" << exportFile.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&exportFile);
|
||||
out << m_gpio;
|
||||
exportFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns true if this Gpio could be unexported in the system file \tt {/sys/class/gpio/unexport}. */
|
||||
bool Gpio::unexportGpio()
|
||||
{
|
||||
qCDebug(dcGpio()) << "Unexport GPIO" << m_gpio;
|
||||
|
||||
QFile unexportFile("/sys/class/gpio/unexport");
|
||||
if (!unexportFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO unexport file:" << unexportFile.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&unexportFile);
|
||||
out << m_gpio;
|
||||
unexportFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns true if the \a direction of this GPIO could be set. \sa Gpio::Direction, */
|
||||
bool Gpio::setDirection(Gpio::Direction direction)
|
||||
{
|
||||
qCDebug(dcGpio()) << "Set GPIO" << m_gpio << "direction" << direction;
|
||||
if (direction == Gpio::DirectionInvalid) {
|
||||
qCWarning(dcGpio()) << "Setting an invalid direction is forbidden.";
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile directionFile(m_gpioDirectory.path() + QDir::separator() + "direction");
|
||||
if (!directionFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO" << m_gpio << "direction file:" << directionFile.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_direction = direction;
|
||||
|
||||
QTextStream out(&directionFile);
|
||||
switch (m_direction) {
|
||||
case DirectionInput:
|
||||
out << "in";
|
||||
break;
|
||||
case DirectionOutput:
|
||||
out << "out";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
directionFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns the direction of this Gpio. */
|
||||
Gpio::Direction Gpio::direction()
|
||||
{
|
||||
QFile directionFile(m_gpioDirectory.path() + QDir::separator() + "direction");
|
||||
if (!directionFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO" << m_gpio << "direction file:" << directionFile.fileName() << directionFile.errorString();
|
||||
return Gpio::DirectionInvalid;
|
||||
}
|
||||
|
||||
QString direction;
|
||||
QTextStream in(&directionFile);
|
||||
in >> direction;
|
||||
directionFile.close();
|
||||
|
||||
if (direction == "in") {
|
||||
m_direction = DirectionInput;
|
||||
return Gpio::DirectionInput;
|
||||
} else if (direction == "out") {
|
||||
m_direction = DirectionOutput;
|
||||
return Gpio::DirectionOutput;
|
||||
}
|
||||
|
||||
return Gpio::DirectionInvalid;
|
||||
}
|
||||
|
||||
/*! Returns true if the digital \a value of this Gpio could be set correctly. */
|
||||
bool Gpio::setValue(Gpio::Value value)
|
||||
{
|
||||
qCDebug(dcGpio()) << "Set GPIO" << m_gpio << "value" << value;
|
||||
|
||||
// Check given value
|
||||
if (value == Gpio::ValueInvalid) {
|
||||
qCWarning(dcGpio()) << "Setting an invalid value is forbidden.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check current direction
|
||||
if (m_direction == Gpio::DirectionInput) {
|
||||
qCWarning(dcGpio()) << "Setting the value of an input GPIO is forbidden.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_direction == Gpio::DirectionInvalid) {
|
||||
qCWarning(dcGpio()) << "The direction of GPIO" << m_gpio << "is invalid.";
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile valueFile(m_gpioDirectory.path() + QDir::separator() + "value");
|
||||
if (!valueFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO" << m_gpio << "value file:" << valueFile.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&valueFile);
|
||||
switch (value) {
|
||||
case ValueLow:
|
||||
out << "0";
|
||||
break;
|
||||
case ValueHigh:
|
||||
out << "1";
|
||||
break;
|
||||
default:
|
||||
valueFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
valueFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns the current digital value of this Gpio. */
|
||||
Gpio::Value Gpio::value()
|
||||
{
|
||||
QFile valueFile(m_gpioDirectory.path() + QDir::separator() + "value");
|
||||
if (!valueFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO" << m_gpio << "value file:" << valueFile.errorString();
|
||||
return Gpio::ValueInvalid;
|
||||
}
|
||||
|
||||
QString value;
|
||||
QTextStream in(&valueFile);
|
||||
in >> value;
|
||||
valueFile.close();
|
||||
|
||||
if (value == "0") {
|
||||
return Gpio::ValueLow;
|
||||
} else if (value == "1") {
|
||||
return Gpio::ValueHigh;
|
||||
}
|
||||
|
||||
return Gpio::ValueInvalid;
|
||||
}
|
||||
|
||||
/*! This method allows to invert the logic of this Gpio. Returns true, if the GPIO could be set \a activeLow. */
|
||||
bool Gpio::setActiveLow(bool activeLow)
|
||||
{
|
||||
qCDebug(dcGpio()) << "Set GPIO" << m_gpio << "active low" << activeLow;
|
||||
|
||||
QFile activeLowFile(m_gpioDirectory.path() + QDir::separator() + "active_low");
|
||||
if (!activeLowFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO" << m_gpio << "active_low file:" << activeLowFile.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&activeLowFile);
|
||||
if (activeLow) {
|
||||
out << "0";
|
||||
} else {
|
||||
out << "1";
|
||||
}
|
||||
|
||||
activeLowFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns true if the logic of this Gpio is inverted (1 = low, 0 = high). */
|
||||
bool Gpio::activeLow()
|
||||
{
|
||||
QFile activeLowFile(m_gpioDirectory.path() + QDir::separator() + "active_low");
|
||||
if (!activeLowFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO" << m_gpio << "active_low file:" << activeLowFile.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QString value;
|
||||
QTextStream in(&activeLowFile);
|
||||
in >> value;
|
||||
activeLowFile.close();
|
||||
|
||||
if (value == "0")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Returns true if the \a edge of this GPIO could be set correctly. The \a edge parameter specifies, when an interrupt occurs. */
|
||||
bool Gpio::setEdgeInterrupt(Gpio::Edge edge)
|
||||
{
|
||||
|
||||
if (m_direction == Gpio::DirectionOutput) {
|
||||
qCWarning(dcGpio()) << "Could not set edge interrupt, GPIO is configured as an output.";
|
||||
return false;
|
||||
}
|
||||
|
||||
qCDebug(dcGpio()) << "Set GPIO" << m_gpio << "edge interrupt" << edge;
|
||||
QFile edgeFile(m_gpioDirectory.path() + QDir::separator() + "edge");
|
||||
if (!edgeFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO" << m_gpio << "edge file:" << edgeFile.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&edgeFile);
|
||||
switch (edge) {
|
||||
case EdgeFalling:
|
||||
out << "falling";
|
||||
break;
|
||||
case EdgeRising:
|
||||
out << "rising";
|
||||
break;
|
||||
case EdgeBoth:
|
||||
out << "both";
|
||||
break;
|
||||
case EdgeNone:
|
||||
out << "none";
|
||||
break;
|
||||
}
|
||||
|
||||
edgeFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns the edge interrupt of this Gpio. */
|
||||
Gpio::Edge Gpio::edgeInterrupt()
|
||||
{
|
||||
QFile edgeFile(m_gpioDirectory.path() + QDir::separator() + "edge");
|
||||
if (!edgeFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO" << m_gpio << "edge file:" << edgeFile.errorString();
|
||||
return Gpio::EdgeNone;
|
||||
}
|
||||
|
||||
QString edge;
|
||||
QTextStream in(&edgeFile);
|
||||
in >> edge;
|
||||
edgeFile.close();
|
||||
|
||||
if (edge.contains("falling")) {
|
||||
return Gpio::EdgeFalling;
|
||||
} else if (edge.contains("rising")) {
|
||||
return Gpio::EdgeRising;
|
||||
} else if (edge.contains("both")) {
|
||||
return Gpio::EdgeBoth;
|
||||
} else if (edge.contains("none")) {
|
||||
return Gpio::EdgeNone;
|
||||
}
|
||||
|
||||
return Gpio::EdgeNone;
|
||||
}
|
||||
|
||||
|
||||
/*! Prints the given \a gpio to \a debug. */
|
||||
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() << "edge: falling, ";
|
||||
break;
|
||||
case Gpio::EdgeRising:
|
||||
debug.nospace() << "edge: rising, ";
|
||||
break;
|
||||
case Gpio::EdgeBoth:
|
||||
debug.nospace() << "edge: both, ";
|
||||
break;
|
||||
case Gpio::EdgeNone:
|
||||
debug.nospace() << "edge: none, ";
|
||||
break;
|
||||
}
|
||||
} else if (gpio->direction() == Gpio::DirectionOutput) {
|
||||
debug.nospace() << "output, ";
|
||||
} else {
|
||||
debug.nospace() << "invalid, ";
|
||||
}
|
||||
|
||||
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) {
|
||||
debug.nospace() << "value: 0";
|
||||
} else {
|
||||
debug.nospace() << "value: invalid";
|
||||
}
|
||||
|
||||
debug.nospace() << ")";
|
||||
|
||||
return debug.space();
|
||||
}
|
||||
92
libnymea-gpio/gpio.h
Normal file
92
libnymea-gpio/gpio.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||
* *
|
||||
* This file is part of nymea-gpio. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef GPIO_H
|
||||
#define GPIO_H
|
||||
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcGpio)
|
||||
|
||||
class Gpio : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Direction {
|
||||
DirectionInvalid,
|
||||
DirectionInput,
|
||||
DirectionOutput
|
||||
};
|
||||
Q_ENUM(Direction)
|
||||
|
||||
enum Value {
|
||||
ValueInvalid = -1,
|
||||
ValueLow = 0,
|
||||
ValueHigh = 1
|
||||
};
|
||||
Q_ENUM(Value)
|
||||
|
||||
enum Edge {
|
||||
EdgeFalling,
|
||||
EdgeRising,
|
||||
EdgeBoth,
|
||||
EdgeNone
|
||||
};
|
||||
Q_ENUM(Edge)
|
||||
|
||||
explicit Gpio(int gpio, QObject *parent = nullptr);
|
||||
~Gpio();
|
||||
|
||||
static bool isAvailable();
|
||||
|
||||
QString gpioDirectory() const;
|
||||
int gpioNumber() const;
|
||||
|
||||
bool exportGpio();
|
||||
bool unexportGpio();
|
||||
|
||||
bool setDirection(Gpio::Direction direction);
|
||||
Gpio::Direction direction();
|
||||
|
||||
bool setValue(Gpio::Value value);
|
||||
Gpio::Value value();
|
||||
|
||||
bool setActiveLow(bool activeLow);
|
||||
bool activeLow();
|
||||
|
||||
bool setEdgeInterrupt(Gpio::Edge edge);
|
||||
Gpio::Edge edgeInterrupt();
|
||||
|
||||
private:
|
||||
int m_gpio = 0;
|
||||
Gpio::Direction m_direction = Gpio::DirectionOutput;
|
||||
QDir m_gpioDirectory;
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<< (QDebug debug, Gpio *gpio);
|
||||
|
||||
#endif // GPIO_H
|
||||
232
libnymea-gpio/gpiobutton.cpp
Normal file
232
libnymea-gpio/gpiobutton.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||
* *
|
||||
* This file is part of nymea-gpio. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/*!
|
||||
\class GpioButton
|
||||
\brief Represents a GPIO Button with some helper methods.
|
||||
\inmodule nymea-gpio
|
||||
\ingroup gpio
|
||||
|
||||
This class represents a Button based on a GPIO. The class takes care about the \l{clicked()} signal handling, debounces the GPIO signal
|
||||
and offers a nice interface for \l{longPressed()} behaviour.
|
||||
|
||||
In order to get the button signals, the button has to be enabled using \l{enable()}.
|
||||
|
||||
\code
|
||||
GpioButton *button = new GpioButton(15, this);
|
||||
button->setName("User button");
|
||||
if (!button->enable()) {
|
||||
qWarning() << "Could not enable the" << this;
|
||||
button->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
connect(button, &GpioButton::clicked, this, [this, button](){
|
||||
qDebug() << button << "clicked";
|
||||
});
|
||||
|
||||
\endcode
|
||||
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void GpioButton::clicked();
|
||||
This signal will be emitted when the button gets clicked. A button will has been clicked, if it was pressed at leased for 10 ms and at most 500 ms.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void GpioButton::pressed();
|
||||
This signal will be emitted when the button gets pressed.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void GpioButton::released();
|
||||
This signal will be emitted whenever the button gets released.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void GpioButton::longPressed();
|
||||
This signal will be emitted whenever the button gets pressed for a certain time.
|
||||
|
||||
\sa longPressedTimeout(), repeateLongPressed()
|
||||
*/
|
||||
|
||||
#include "gpiobutton.h"
|
||||
#include "gpiomonitor.h"
|
||||
|
||||
/*! Constructs a \l{GpioButton} object with the given \a gpio number and \a parent. */
|
||||
GpioButton::GpioButton(int gpio, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_gpioNumber(gpio)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Returns the gpio number for this GpioButton. */
|
||||
int GpioButton::gpioNumber() const
|
||||
{
|
||||
return m_gpioNumber;
|
||||
}
|
||||
|
||||
/*! Returns \c true the gpio button is configured as active low.
|
||||
|
||||
\sa Gpio::activeLow()
|
||||
*/
|
||||
bool GpioButton::activeLow() const
|
||||
{
|
||||
return m_activeLow;
|
||||
}
|
||||
|
||||
/*! Sets the gpio button active low configuration to \a activeLow for this GpioButton.
|
||||
|
||||
\sa Gpio::setActiveLow()
|
||||
*/
|
||||
void GpioButton::setActiveLow(bool activeLow)
|
||||
{
|
||||
m_activeLow = activeLow;
|
||||
}
|
||||
|
||||
/*! Returns \c true, if the \l{longPressed()} signal will be emited again if the button will be hold down. */
|
||||
bool GpioButton::repeateLongPressed() const
|
||||
{
|
||||
return m_repeateLongPressed;
|
||||
}
|
||||
|
||||
/*! Sets repeate long pressed configuration to \a repeateLongPressed. If \a repeateLongPressed is true, the longPressed() signal will be repeated as long the button will be hold down.
|
||||
|
||||
\sa longPressedTimeout()
|
||||
*/
|
||||
void GpioButton::setRepeateLongPressed(bool repeateLongPressed)
|
||||
{
|
||||
m_repeateLongPressed = repeateLongPressed;
|
||||
}
|
||||
|
||||
/*! Returns the long pressed timout duration in milliseconds. If the button gets hold down for this duration, the longPressed() signal will be emitted.
|
||||
|
||||
\sa longPressed()
|
||||
*/
|
||||
int GpioButton::longPressedTimeout() const
|
||||
{
|
||||
return m_longPressedTimeout;
|
||||
}
|
||||
|
||||
/*! Sets the long pressed timout duration to \a longPressedTimeout in milliseconds. If the button gets hold down for this duration, the longPressed() signal will be emitted.
|
||||
|
||||
\sa longPressed()
|
||||
*/
|
||||
void GpioButton::setLongPressedTimeout(int longPressedTimeout)
|
||||
{
|
||||
m_longPressedTimeout = longPressedTimeout;
|
||||
}
|
||||
|
||||
/*! Returns the \c name for this GpioButton. This is optional, but will be printed in the debug operator. */
|
||||
QString GpioButton::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/*! Sets the \a name for this GpioButton. This is optional, but will be printed in the debug operator. */
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! Returns \c true, if this GpioButton was enabled successfully. */
|
||||
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);
|
||||
|
||||
// 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);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Disable this GpioButton. The Gpio will be unexported. */
|
||||
void GpioButton::disable()
|
||||
{
|
||||
if (m_monitor) {
|
||||
delete m_monitor;
|
||||
m_monitor = nullptr;
|
||||
}
|
||||
|
||||
if (m_timer) {
|
||||
delete m_timer;
|
||||
m_timer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Prints the given \a gpioButton to \a debug. */
|
||||
QDebug operator<<(QDebug debug, GpioButton *gpioButton)
|
||||
{
|
||||
debug.nospace() << "GpioButton(" << gpioButton->gpioNumber() << ", ";
|
||||
debug.nospace() << "name: " << gpioButton->name() << ")";
|
||||
return debug.space();
|
||||
}
|
||||
83
libnymea-gpio/gpiobutton.h
Normal file
83
libnymea-gpio/gpiobutton.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||
* *
|
||||
* This file is part of nymea-gpio. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef GPIOBUTTON_H
|
||||
#define GPIOBUTTON_H
|
||||
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
|
||||
class GpioMonitor;
|
||||
|
||||
class GpioButton : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GpioButton(int gpio, 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
|
||||
282
libnymea-gpio/gpiomonitor.cpp
Normal file
282
libnymea-gpio/gpiomonitor.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||
* *
|
||||
* This file is part of nymea-gpio. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/*!
|
||||
\class GpioMonitor
|
||||
\brief Monitor for GPIO interrupts.
|
||||
\inmodule nymea-gpio
|
||||
\ingroup gpio
|
||||
|
||||
This class allows to monitor an input GPIO for the interrupts depending on the edge interrupt configuration.
|
||||
|
||||
This class will start a poll thread in the background. Depending on the Gpio::Edge configuration, the \l{interruptOccured()} signal
|
||||
will be emitted. Default is Gpio::EdgeBoth which means the interrupt will be on rising and falling signal of the Gpio.
|
||||
|
||||
The behavior of the interrupt can also be inverted using the \l{activeLow()} parameter.
|
||||
|
||||
\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)
|
||||
{
|
||||
// Inform about the thread status
|
||||
connect(this, &GpioMonitor::started, this, &GpioMonitor::onThreadStarted, Qt::DirectConnection);
|
||||
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. */
|
||||
Gpio::Edge GpioMonitor::edge() const
|
||||
{
|
||||
return m_edge;
|
||||
}
|
||||
|
||||
/*! Sets the edge interrupt configuration for this GpioMonitor to the given \a edge. */
|
||||
void GpioMonitor::setEdge(Gpio::Edge edge)
|
||||
{
|
||||
if (m_edge == edge)
|
||||
return;
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void GpioMonitor::setValue(Gpio::Value value)
|
||||
{
|
||||
QMutexLocker valueLocker(&m_valueMutex);
|
||||
m_value = value;
|
||||
|
||||
switch (m_value) {
|
||||
case Gpio::ValueLow:
|
||||
emit interruptOccured(false);
|
||||
break;
|
||||
case Gpio::ValueHigh:
|
||||
emit interruptOccured(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GpioMonitor::setEnabled(bool enabled)
|
||||
{
|
||||
if (m_enabled == enabled)
|
||||
return;
|
||||
|
||||
m_enabled = enabled;
|
||||
emit enabledChanged(m_enabled);
|
||||
}
|
||||
|
||||
/*! Reimplementation of the QThread run() method. Within the thread the Gpio value will be polled using poll() 2. */
|
||||
void GpioMonitor::run()
|
||||
{
|
||||
// Create GPIO in the thread for initialisation
|
||||
Gpio inputGpio(m_gpioNumber);
|
||||
if (!inputGpio.exportGpio()) {
|
||||
qCWarning(dcGpio()) << "Could not enable GPIO monitor.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inputGpio.setDirection(Gpio::DirectionInput)) {
|
||||
qCWarning(dcGpio()) << "Could not enable GPIO monitor.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inputGpio.setEdgeInterrupt(m_edge)) {
|
||||
qCWarning(dcGpio()) << "Could not set interrupt for the GPIO monitor.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inputGpio.setActiveLow(m_activeLow)) {
|
||||
qCWarning(dcGpio()) << "Could not set active low for the GPIO monitor.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// In order to do correctly, use poll (2) according to the kernel documentation
|
||||
// https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
|
||||
QFile valueFile(inputGpio.gpioDirectory() + QDir::separator() + "value");
|
||||
if (!valueFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qCWarning(dcGpio()) << "Could not open GPIO" << &inputGpio << "value file:" << valueFile.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
struct pollfd fdset[1];
|
||||
int rc = -1;
|
||||
uint nfds = 1;
|
||||
int timeout = 100; // ms
|
||||
fdset[0].fd = valueFile.handle();
|
||||
fdset[0].events = POLLPRI;
|
||||
|
||||
// Poll the GPIO value until stop is true
|
||||
while (true) {
|
||||
// Poll the value file
|
||||
rc = poll(fdset, nfds, timeout);
|
||||
|
||||
// Poll failed...
|
||||
if (rc < 0) {
|
||||
qCWarning(dcGpio()) << "Failed to poll" << &inputGpio;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if we should stop the thread
|
||||
QMutexLocker stopLocker(&m_stopMutex);
|
||||
if (m_stop) break;
|
||||
|
||||
// No interrupt occured
|
||||
if (rc == 0)
|
||||
continue;
|
||||
|
||||
// Interrupt occured
|
||||
if (fdset[0].revents & POLLPRI) {
|
||||
QString valueString;
|
||||
QTextStream readStream(&valueFile);
|
||||
if (!readStream.seek(0)) {
|
||||
qCWarning(dcGpio()) << "Failed to seek value file of" << &inputGpio;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Notify the main thread about the interrupt
|
||||
readStream >> valueString;
|
||||
if (valueString == "0") {
|
||||
setValue(Gpio::ValueLow);
|
||||
} else {
|
||||
setValue(Gpio::ValueHigh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up once done
|
||||
valueFile.close();
|
||||
}
|
||||
|
||||
void GpioMonitor::onThreadStarted()
|
||||
{
|
||||
qCDebug(dcGpio()) << "Monitor thread started";
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
void GpioMonitor::onThreadFinished()
|
||||
{
|
||||
qCDebug(dcGpio()) << "Monitor thread finished";
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
/*! Returns true, if this GpioMonitor was enabled successfully. */
|
||||
bool GpioMonitor::enable()
|
||||
{
|
||||
qCDebug(dcGpio()) << "Enable gpio monitor";
|
||||
if (isRunning()) {
|
||||
qCWarning(dcGpio()) << "This GPIO monitor is already running.";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Init the GPIO
|
||||
if (!Gpio::isAvailable()) {
|
||||
qCWarning(dcGpio()) << "Could not enable GPIO monitor. There are no GPIOs available on this platform.";
|
||||
return false;
|
||||
}
|
||||
|
||||
QMutexLocker locker(&m_stopMutex);
|
||||
m_stop = false;
|
||||
|
||||
// Everything looks good, lets start the poll thread and inform about the result
|
||||
start();
|
||||
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";
|
||||
// Stop the thread if not already disabled
|
||||
QMutexLocker locker(&m_stopMutex);
|
||||
if (m_stop) return;
|
||||
m_stop = true;
|
||||
}
|
||||
82
libnymea-gpio/gpiomonitor.h
Normal file
82
libnymea-gpio/gpiomonitor.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||
* *
|
||||
* This file is part of nymea-gpio. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef GPIOMONITOR_H
|
||||
#define GPIOMONITOR_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QThread>
|
||||
#include <QObject>
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
class GpioMonitor : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GpioMonitor(int gpio, QObject *parent = nullptr);
|
||||
~GpioMonitor() override;
|
||||
|
||||
Gpio::Edge edge() const;
|
||||
void setEdge(Gpio::Edge edge);
|
||||
|
||||
bool activeLow() const;
|
||||
void setActiveLow(bool activeLow);
|
||||
|
||||
Gpio::Value value();
|
||||
|
||||
bool enabled() const;
|
||||
|
||||
private:
|
||||
int m_gpioNumber = -1;
|
||||
Gpio::Edge m_edge = Gpio::EdgeBoth;
|
||||
bool m_activeLow = true;
|
||||
bool m_enabled = false;
|
||||
|
||||
// Thread stuff
|
||||
QMutex m_valueMutex;
|
||||
Gpio::Value m_value = Gpio::ValueInvalid;
|
||||
|
||||
QMutex m_stopMutex;
|
||||
bool m_stop = false;
|
||||
|
||||
void setValue(Gpio::Value value);
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
signals:
|
||||
void interruptOccured(bool value);
|
||||
void enabledChanged(bool enabled);
|
||||
|
||||
private slots:
|
||||
void onThreadStarted();
|
||||
void onThreadFinished();
|
||||
|
||||
public slots:
|
||||
bool enable();
|
||||
void disable();
|
||||
|
||||
};
|
||||
|
||||
#endif // GPIOMONITOR_H
|
||||
36
libnymea-gpio/libnymea-gpio.pro
Normal file
36
libnymea-gpio/libnymea-gpio.pro
Normal file
@ -0,0 +1,36 @@
|
||||
include(../nymea-gpio.pri)
|
||||
|
||||
TARGET = nymea-gpio
|
||||
TEMPLATE = lib
|
||||
|
||||
HEADERS += \
|
||||
gpio.h \
|
||||
gpiobutton.h \
|
||||
gpiomonitor.h
|
||||
|
||||
SOURCES += \
|
||||
gpio.cpp \
|
||||
gpiobutton.cpp \
|
||||
gpiomonitor.cpp
|
||||
|
||||
target.path = $$[QT_INSTALL_LIBS]
|
||||
INSTALLS += target
|
||||
|
||||
# install header file with relative subdirectory
|
||||
for(header, HEADERS) {
|
||||
path = $$[QT_INSTALL_PREFIX]/include/nymea-gpio/$${dirname(header)}
|
||||
eval(headers_$${path}.files += $${header})
|
||||
eval(headers_$${path}.path = $${path})
|
||||
eval(INSTALLS *= headers_$${path})
|
||||
}
|
||||
|
||||
# Create pkgconfig file
|
||||
CONFIG += create_pc create_prl no_install_prl
|
||||
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/nymea-gpio/
|
||||
QMAKE_PKGCONFIG_LIBDIR = $$target.path
|
||||
QMAKE_PKGCONFIG_VERSION = $$VERSION_STRING
|
||||
QMAKE_PKGCONFIG_FILE = nymea-gpio
|
||||
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
|
||||
68
nymea-gpio-tool/application.cpp
Normal file
68
nymea-gpio-tool/application.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||
* *
|
||||
* This file is part of nymea-gpio. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "application.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <signal.h>
|
||||
|
||||
static void catchUnixSignals(const std::vector<int>& quitSignals, const std::vector<int>& ignoreSignals = std::vector<int>())
|
||||
{
|
||||
auto handler = [](int sig) ->void {
|
||||
switch (sig) {
|
||||
case SIGQUIT:
|
||||
qDebug() << "Cought SIGQUIT quit signal...";
|
||||
break;
|
||||
case SIGINT:
|
||||
qDebug() << "Cought SIGINT quit signal...";
|
||||
break;
|
||||
case SIGTERM:
|
||||
qDebug() << "Cought SIGTERM quit signal...";
|
||||
break;
|
||||
case SIGHUP:
|
||||
qDebug() << "Cought SIGHUP quit signal...";
|
||||
break;
|
||||
case SIGSEGV: {
|
||||
qCritical() << "Cought SIGSEGV signal. Segmentation fault!";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Application::quit();
|
||||
};
|
||||
|
||||
// all these signals will be ignored.
|
||||
for (int sig : ignoreSignals)
|
||||
signal(sig, SIG_IGN);
|
||||
|
||||
for (int sig : quitSignals)
|
||||
signal(sig, handler);
|
||||
|
||||
}
|
||||
|
||||
Application::Application(int &argc, char **argv) :
|
||||
QCoreApplication(argc, argv)
|
||||
{
|
||||
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP, SIGSEGV});
|
||||
}
|
||||
37
nymea-gpio-tool/application.h
Normal file
37
nymea-gpio-tool/application.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||
* *
|
||||
* This file is part of nymea-gpio. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef APPLICATION_H
|
||||
#define APPLICATION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QCoreApplication>
|
||||
|
||||
class Application : public QCoreApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Application(int &argc, char **argv);
|
||||
|
||||
};
|
||||
|
||||
#endif // APPLICATION_H
|
||||
182
nymea-gpio-tool/main.cpp
Normal file
182
nymea-gpio-tool/main.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||
* *
|
||||
* This file is part of nymea-gpio. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "application.h"
|
||||
#include "gpiomonitor.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Application application(argc, argv);
|
||||
application.setOrganizationName("guh");
|
||||
application.setApplicationName("nymea-gpio-tool");
|
||||
application.setApplicationVersion(VERSION_STRING);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
QString applicationDescription = QString("\nnymea-gpio-tool is a command line tool which allowes to interact with GPIOs.\n"
|
||||
"Version: %1\n"
|
||||
"Copyright %2 2019 Simon Stürz <simon.stuerz@nymea.io>\n\n"
|
||||
"Released under the GNU GENERAL PUBLIC LICENSE Version 3.\n").arg(application.applicationVersion()).arg(QChar(0xA9));
|
||||
parser.setApplicationDescription(applicationDescription);
|
||||
|
||||
QCommandLineOption gpioOption(QStringList() << "g" << "gpio", "The gpio number to use.", "GPIO");
|
||||
parser.addOption(gpioOption);
|
||||
|
||||
QCommandLineOption interruptOption(QStringList() << "i" << "interrupt", "Configure the input GPIO to the given interrupt. This option is only allowed for monitoring. Allowerd interrupts are: [rising, falling, both, none]. Default is \"both\".", "INTERRUPT");
|
||||
parser.addOption(interruptOption);
|
||||
|
||||
QCommandLineOption valueOption(QStringList() << "s" << "set-value", "Configure the GPIO to output and set the value. Allowerd values are: [0, 1].", "VALUE");
|
||||
parser.addOption(valueOption);
|
||||
|
||||
QCommandLineOption monitorOption(QStringList() << "m" << "monitor", "Monitor the given GPIO. The GPIO will automatically configured as input and print any change regarding to the given interrupt behaviour.");
|
||||
parser.addOption(monitorOption);
|
||||
|
||||
QCommandLineOption activeLowOption(QStringList() << "a" << "active-low", "Set the GPIO to active low. Allowerd values are: [0, 1]", "VALUE");
|
||||
parser.addOption(activeLowOption);
|
||||
|
||||
parser.process(application);
|
||||
|
||||
// Make sure there is a GPIO number passed
|
||||
if (!parser.isSet(gpioOption)) {
|
||||
qCritical() << "No GPIO number specified. Please specify a valid GPIO number using -g, --gpio GPIO";
|
||||
parser.showHelp(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Verify GPIO number
|
||||
bool gpioNumberOk;
|
||||
int gpioNumber = parser.value(gpioOption).toInt(&gpioNumberOk);
|
||||
if (!gpioNumberOk || gpioNumber < 0) {
|
||||
qCritical() << "Invalid GPIO number" << parser.value(gpioOption) << "passed. The GPIO number has to be a positiv integer.";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Verify input output operations
|
||||
if ((parser.isSet(interruptOption) || parser.isSet(monitorOption)) && parser.isSet(valueOption)) {
|
||||
qCritical() << "Invalid parameter combination. The set value can only be used for output GPIO, the monitor and interrupt parameter can only be used for input GPIO.";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Gpio::Edge edge = Gpio::EdgeBoth;
|
||||
if (parser.isSet(interruptOption)) {
|
||||
if (parser.value(interruptOption).toLower() == "rising") {
|
||||
edge = Gpio::EdgeRising;
|
||||
} else if (parser.value(interruptOption).toLower() == "falling") {
|
||||
edge = Gpio::EdgeFalling;
|
||||
} else if (parser.value(interruptOption).toLower() == "none") {
|
||||
edge = Gpio::EdgeNone;
|
||||
} else if (parser.value(interruptOption).toLower() == "both") {
|
||||
edge = Gpio::EdgeBoth;
|
||||
} else {
|
||||
qCritical() << "Invalid interrupt parameter" << parser.value(interruptOption) << "passed. Valid options are [rising, falling, both, none].";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
bool activeLow = true;
|
||||
if (parser.isSet(activeLowOption)) {
|
||||
if (parser.value(activeLowOption) == "1") {
|
||||
activeLow = false;
|
||||
} else if (parser.value(activeLowOption) == "0") {
|
||||
activeLow = true;
|
||||
} else {
|
||||
qCritical() << "Invalid active low parameter" << parser.value(activeLowOption) << "passed. Valid options are [0, 1].";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
Gpio::Value value = Gpio::ValueInvalid;
|
||||
if (parser.isSet(valueOption)) {
|
||||
if (parser.value(valueOption) == "1") {
|
||||
value = Gpio::ValueHigh;
|
||||
} else if (parser.value(valueOption) == "0") {
|
||||
value = Gpio::ValueLow;
|
||||
} else {
|
||||
qCritical() << "Invalid set value parameter" << parser.value(valueOption) << "passed. Valid options are [0, 1].";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Gpio::isAvailable()) {
|
||||
qCritical() << "There are no GPIOs available on this platform.";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Configure the GPIO
|
||||
if (parser.isSet(valueOption)) {
|
||||
Gpio *gpio = new Gpio(gpioNumber);
|
||||
if (!gpio->exportGpio()) {
|
||||
qCritical() << "Could not export GPIO" << gpioNumber;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!gpio->setDirection(Gpio::DirectionOutput)) {
|
||||
qCritical() << "Could not configure GPIO" << gpioNumber << "as output.";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (parser.isSet(activeLowOption)) {
|
||||
if (!gpio->setActiveLow(activeLow)) {
|
||||
qCritical() << "Could not set GPIO" << gpioNumber << "to active low" << activeLow;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally set the value
|
||||
if (!gpio->setValue(value)) {
|
||||
qCritical() << "Could not set GPIO" << gpioNumber << "value to" << value;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
delete gpio;
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
GpioMonitor *monitor = new GpioMonitor(gpioNumber);
|
||||
monitor->setEdge(edge);
|
||||
monitor->setActiveLow(activeLow);
|
||||
|
||||
// Inform about enabled changed
|
||||
QObject::connect(monitor, &GpioMonitor::enabledChanged, [gpioNumber](bool enabled) {
|
||||
qDebug() << "GPIO" << gpioNumber << "monitor" << (enabled ? "enabled" : "disabled");
|
||||
});
|
||||
|
||||
// Inform about interrupt
|
||||
QObject::connect(monitor, &GpioMonitor::interruptOccured, [gpioNumber](bool value) {
|
||||
qDebug() << "GPIO" << gpioNumber << "interrupt occured. Current value:" << (value ? "1" : "0");
|
||||
});
|
||||
|
||||
// Enable the monitor
|
||||
if (!monitor->enable()) {
|
||||
qCritical() << "Could not enable GPIO" << gpioNumber << "monitor.";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Clean up the gpio once done
|
||||
QObject::connect(&application, &Application::aboutToQuit, [monitor](){
|
||||
delete monitor;
|
||||
});
|
||||
}
|
||||
|
||||
return application.exec();
|
||||
}
|
||||
19
nymea-gpio-tool/nymea-gpio-tool.pro
Normal file
19
nymea-gpio-tool/nymea-gpio-tool.pro
Normal file
@ -0,0 +1,19 @@
|
||||
include(../nymea-gpio.pri)
|
||||
|
||||
TARGET = nymea-gpio-tool
|
||||
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
TEMPLATE = app
|
||||
|
||||
INCLUDEPATH += $$top_srcdir/libnymea-gpio/
|
||||
LIBS += -L$$top_builddir/libnymea-gpio/ -lnymea-gpio
|
||||
|
||||
HEADERS += \
|
||||
application.h
|
||||
|
||||
SOURCES += main.cpp \
|
||||
application.cpp
|
||||
|
||||
target.path = /usr/bin
|
||||
INSTALLS += target
|
||||
11
nymea-gpio.pri
Normal file
11
nymea-gpio.pri
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
QMAKE_CXXFLAGS += -Werror -std=c++11 -g
|
||||
QMAKE_LFLAGS += -std=c++11
|
||||
|
||||
QT -= gui
|
||||
|
||||
top_srcdir=$$PWD
|
||||
top_builddir=$$shadowed($$PWD)
|
||||
|
||||
VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"')
|
||||
DEFINES += VERSION_STRING=\\\"$${VERSION_STRING}\\\"
|
||||
4
nymea-gpio.pro
Normal file
4
nymea-gpio.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = libnymea-gpio nymea-gpio-tool
|
||||
nymea-gpio-tool.depends = libnymea-gpio
|
||||
|
||||
Reference in New Issue
Block a user