renew gpio and pwm classes
This commit is contained in:
parent
f5ee163c48
commit
4191b8f37c
@ -40,8 +40,6 @@
|
||||
No Resource required.
|
||||
\value HardwareResourceRadio433
|
||||
Refers to the 433 MHz radio.
|
||||
\value HardwareResourceRadio868
|
||||
Refers to the 868 MHz radio.
|
||||
\value HardwareResourceTimer
|
||||
Refers to the global timer managed by the \l{DeviceManager}. Plugins should not create their own timers,
|
||||
but rather request the global timer using the hardware resources.
|
||||
@ -207,7 +205,6 @@ DeviceManager::DeviceManager(QObject *parent) :
|
||||
connect(&m_pluginTimer, &QTimer::timeout, this, &DeviceManager::timerEvent);
|
||||
|
||||
m_radio433 = new Radio433(this);
|
||||
connect(m_radio433, &Radio433::dataReceived, this, &DeviceManager::radio433SignalReceived);
|
||||
m_radio433->enable();
|
||||
// TODO: error handling if no Radio433 detected (GPIO or network), disable radio433 plugins or something...
|
||||
|
||||
|
||||
@ -57,13 +57,12 @@ class LIBGUH_EXPORT DeviceManager : public QObject
|
||||
|
||||
public:
|
||||
enum HardwareResource {
|
||||
HardwareResourceNone = 0x00,
|
||||
HardwareResourceRadio433 = 0x01,
|
||||
HardwareResourceRadio868 = 0x02,
|
||||
HardwareResourceTimer = 0x04,
|
||||
HardwareResourceNetworkManager = 0x08,
|
||||
HardwareResourceUpnpDisovery = 0x10,
|
||||
HardwareResourceBluetoothLE = 0x20
|
||||
HardwareResourceNone = 0,
|
||||
HardwareResourceRadio433 = 1,
|
||||
HardwareResourceTimer = 2,
|
||||
HardwareResourceNetworkManager = 4,
|
||||
HardwareResourceUpnpDisovery = 8,
|
||||
HardwareResourceBluetoothLE = 16
|
||||
};
|
||||
Q_DECLARE_FLAGS(HardwareResources, HardwareResource)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.guru> *
|
||||
* Copyright (C) 2015 -2016 Simon Stürz <simon.stuerz@guh.guru> *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
@ -37,32 +37,44 @@
|
||||
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.
|
||||
*/
|
||||
|
||||
\chapter Example
|
||||
/*! \enum Gpio::Direction
|
||||
|
||||
Following example shows how to initialize and interact with a GPIO. The GPIO will be configured as an input,
|
||||
set active high and the edge interrupt will be set to EDGE_BOTH.
|
||||
This enum type specifies the dirction a \l{Gpio}.
|
||||
|
||||
\code
|
||||
Gpio *gpio = new Gpio(this, 22);
|
||||
if (!gpio->exportGpio() || !gpio->setDirection(INPUT) || !gpio->setEdgeInterrupt(EDGE_BOTH) || !gpio->setActiveLow(true)) {
|
||||
return;
|
||||
}
|
||||
int value = gpio->getValue();
|
||||
qDebug() << "value = " << value;
|
||||
\endcode
|
||||
\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.
|
||||
*/
|
||||
|
||||
\chapter Raspberry Pi GPIOs
|
||||
In following table is a list of all GPIO's of the Raspberry Pi Rev. 2.0:
|
||||
/*! \enum Gpio::Value
|
||||
|
||||
\image Raspberry_Pi_GPIO_Map.png "Raspberry Pi GPIO map"
|
||||
This enum type specifies the value a \l{Gpio}.
|
||||
|
||||
Valid GPIO's for this class are those with a GPIO number (for example GPIO 22, which is on pin Nr. 15)
|
||||
\value ValueLow
|
||||
The \l{Gpio} is low.
|
||||
\value ValueHigh
|
||||
The \l{Gpio} is high.
|
||||
\value ValueInvalid
|
||||
The value is not valid.
|
||||
*/
|
||||
|
||||
\chapter Beaglebone Black GPIOs
|
||||
In following table is a list of all GPIO's of the Beaglebone Black (\l{http://pix.cs.olemiss.edu/csci581/BBBlackGPIOMap.png}{Source}):
|
||||
/*! \enum Gpio::Edge
|
||||
|
||||
\image Beaglebone_Black_GPIO_Map.png "Beaglebone Black GPIO map"
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
@ -71,339 +83,299 @@
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
/*! Constructs a \l{Gpio} object to represent a GPIO with the given \a gpio number and the \a parent. */
|
||||
Gpio::Gpio(QObject *parent, int gpio) :
|
||||
QObject(parent),m_gpio(gpio)
|
||||
/*! Constructs a \l{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_gpioDirectory = QDir(QString("/sys/class/gpio/gpio%1/").arg(QString::number(m_gpio)));
|
||||
}
|
||||
|
||||
/*! Destroys the Gpio object and unexports the GPIO. */
|
||||
/*! Destroys and unexports the \l{Gpio}. */
|
||||
Gpio::~Gpio()
|
||||
{
|
||||
unexportGpio();
|
||||
}
|
||||
|
||||
/*! Returns true if this GPIO could be exported in the system file "/sys/class/gpio/export". */
|
||||
/*! Returns true if the directory \tt {/sys/class/gpio} does exist. */
|
||||
bool Gpio::isAvailable()
|
||||
{
|
||||
return QDir("/sys/class/gpio").exists();
|
||||
}
|
||||
|
||||
/*! Returns true if this \l{Gpio} could be exported in the system file \tt {/sys/class/gpio/export}. */
|
||||
bool Gpio::exportGpio()
|
||||
{
|
||||
unexportGpio();
|
||||
|
||||
char buf[64];
|
||||
|
||||
int fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
//qCWarning(dcHardware) << "could not open /sys/class/gpio/export";
|
||||
QFile exportFile("/sys/class/gpio/export");
|
||||
if (!exportFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not export GPIO" << m_gpio;
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t len = snprintf(buf, sizeof(buf), "%d", m_gpio);
|
||||
if(write(fd, buf, len) != len){
|
||||
qCWarning(dcHardware) << "could not write to gpio (export)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
QTextStream out(&exportFile);
|
||||
out << m_gpio;
|
||||
exportFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns true if this GPIO could be unexported in the system file "/sys/class/gpio/unexport". */
|
||||
/*! Returns true if this \l{Gpio} could be unexported in the system file \tt {/sys/class/gpio/unexport}. */
|
||||
bool Gpio::unexportGpio()
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
int fd = open("/sys/class/gpio/unexport", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
//qCWarning(dcHardware) << "could not open /sys/class/gpio/unexport";
|
||||
QFile unexportFile("/sys/class/gpio/unexport");
|
||||
if (!unexportFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not unexport GPIO" << m_gpio;
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t len = snprintf(buf, sizeof(buf), "%d", m_gpio);
|
||||
if(write(fd, buf, len) != len){
|
||||
//qCWarning(dcHardware) << "could not write to gpio (unexport)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
QTextStream out(&unexportFile);
|
||||
out << m_gpio;
|
||||
unexportFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns true if the file of this GPIO could be opend.*/
|
||||
int Gpio::openGpio()
|
||||
/*! Returns true if the \a direction of this GPIO could be set. */
|
||||
bool Gpio::setDirection(Gpio::Direction direction)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", m_gpio);
|
||||
|
||||
int fd = open(buf, O_RDONLY | O_NONBLOCK );
|
||||
if (fd < 0) {
|
||||
qCWarning(dcHardware) << "could not open /sys/class/gpio" << m_gpio << "/direction";
|
||||
return fd;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*! Returns true if the direction \a dir of this GPIO could be set correctly.
|
||||
*
|
||||
* Possible directions are:
|
||||
*
|
||||
* \table
|
||||
* \header
|
||||
* \li {2,1} Pin directions
|
||||
* \row
|
||||
* \li 0
|
||||
* \li INPUT
|
||||
* \row
|
||||
* \li 1
|
||||
* \li OUTPUT
|
||||
* \endtable
|
||||
*/
|
||||
bool Gpio::setDirection(int dir)
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", m_gpio);
|
||||
|
||||
int fd = open(buf, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
qCWarning(dcHardware) << "could not open /sys/class/gpio" << m_gpio << "/direction";
|
||||
QFile directionFile(m_gpioDirectory.path() + "/direction");
|
||||
if (!directionFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "direction file.";
|
||||
return false;
|
||||
}
|
||||
if(dir == INPUT){
|
||||
if(write(fd, "in", 3) != 3){
|
||||
qCWarning(dcHardware) << "could not write to gpio (set INPUT)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
m_dir = INPUT;
|
||||
close(fd);
|
||||
return true;
|
||||
|
||||
QTextStream out(&directionFile);
|
||||
switch (direction) {
|
||||
case DirectionInput:
|
||||
out << "in";
|
||||
break;
|
||||
case DirectionOutput:
|
||||
out << "out";
|
||||
break;
|
||||
default:
|
||||
directionFile.close();
|
||||
return false;
|
||||
}
|
||||
if(dir == OUTPUT){
|
||||
if(write(fd, "out", 4) != 4){
|
||||
qCWarning(dcHardware) << "could not write to gpio (set OUTPUT)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
m_dir = OUTPUT;
|
||||
close(fd);
|
||||
return true;
|
||||
|
||||
directionFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns the direction of this \l{Gpio}. */
|
||||
Gpio::Direction Gpio::direction()
|
||||
{
|
||||
QFile directionFile(m_gpioDirectory.path() + "/direction");
|
||||
if (!directionFile.open(QIODevice::ReadOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "direction file.";
|
||||
return Gpio::DirectionInvalid;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
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 \l{Gpio} could be set correctly. */
|
||||
bool Gpio::setValue(Gpio::Value value)
|
||||
{
|
||||
if (value == Gpio::ValueInvalid || m_direction == Gpio::DirectionInput)
|
||||
return false;
|
||||
|
||||
QFile valueFile(m_gpioDirectory.path() + "/value");
|
||||
if (!valueFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "value file.";
|
||||
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 \l{Gpio}. */
|
||||
Gpio::Value Gpio::value()
|
||||
{
|
||||
QFile valueFile(m_gpioDirectory.path() + "/value");
|
||||
if (!valueFile.open(QIODevice::ReadOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "value file.";
|
||||
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 \l{Gpio}. Returns true, if the GPIO could be set \a activeLow. */
|
||||
bool Gpio::setActiveLow(bool activeLow)
|
||||
{
|
||||
QFile activeLowFile(m_gpioDirectory.path() + "/active_low");
|
||||
if (!activeLowFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "active_low file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&activeLowFile);
|
||||
if (activeLow) {
|
||||
out << "0";
|
||||
} else {
|
||||
out << "1";
|
||||
}
|
||||
|
||||
activeLowFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns true if the logic of this \l{Gpio} is inverted (1 = low, 0 = high). */
|
||||
bool Gpio::activeLow()
|
||||
{
|
||||
QFile activeLowFile(m_gpioDirectory.path() + "/active_low");
|
||||
if (!activeLowFile.open(QIODevice::ReadOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "active_low file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
QString value;
|
||||
QTextStream in(&activeLowFile);
|
||||
in >> value;
|
||||
activeLowFile.close();
|
||||
|
||||
if (value == "0")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Returns the direction of this GPIO.
|
||||
* \sa setDirection()
|
||||
*/
|
||||
int Gpio::getDirection()
|
||||
{
|
||||
return m_dir;
|
||||
}
|
||||
|
||||
/*! Returns true if the digital \a value of the GPIO could be set correctly.
|
||||
*
|
||||
* Possible \a value 's are:
|
||||
*
|
||||
* \table
|
||||
* \header
|
||||
* \li {2,1} Pin value
|
||||
* \row
|
||||
* \li 0
|
||||
* \li LOW
|
||||
* \row
|
||||
* \li 1
|
||||
* \li HIGH
|
||||
* \endtable
|
||||
*/
|
||||
bool Gpio::setValue(unsigned int value)
|
||||
{
|
||||
// check if gpio is a output
|
||||
if( m_dir == OUTPUT){
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", m_gpio);
|
||||
|
||||
int fd = open(buf, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
qCWarning(dcHardware) << "could not open /sys/class/gpio" << m_gpio << "/value";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(value == LOW){
|
||||
if(write(fd, "0", 2) != 2){
|
||||
qCWarning(dcHardware) << "could not write to gpio (set LOW)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
if(value == HIGH){
|
||||
if(write(fd, "1", 2) != 2){
|
||||
qCWarning(dcHardware) << "could not write to gpio (set HIGH)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
close(fd);
|
||||
return false;
|
||||
}else{
|
||||
qCWarning(dcHardware) << "Gpio" << m_gpio << "is not an OUTPUT.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Returns the current digital value of the GPIO.
|
||||
*
|
||||
* Possible values are:
|
||||
*
|
||||
* \table
|
||||
* \header
|
||||
* \li {2,1} Pin directions
|
||||
* \row
|
||||
* \li 0
|
||||
* \li LOW
|
||||
* \row
|
||||
* \li 1
|
||||
* \li HIGH
|
||||
* \endtable
|
||||
*/
|
||||
int Gpio::getValue()
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", m_gpio);
|
||||
|
||||
int fd = open(buf, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
qCWarning(dcHardware) << "could not open /sys/class/gpio" << m_gpio << "/value";
|
||||
return -1;
|
||||
}
|
||||
char ch;
|
||||
int value = -1;
|
||||
ssize_t len = read(fd, &ch, 1);
|
||||
if(len != 1){
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ch != '0') {
|
||||
value = 1;
|
||||
}else{
|
||||
value = 0;
|
||||
}
|
||||
close(fd);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*! Returns true if the \a edge of this GPIO could be set correctly. The \a edge parameter specifies,
|
||||
* when an interrupt occurs.
|
||||
*
|
||||
* Possible values are:
|
||||
*
|
||||
* \table
|
||||
* \header
|
||||
* \li {2,1} Edge possibilitys
|
||||
* \row
|
||||
* \li 0
|
||||
* \li EDGE_FALLING
|
||||
* \row
|
||||
* \li 1
|
||||
* \li EDGE_RISING
|
||||
* \row
|
||||
* \li 2
|
||||
* \li EDGE_BOTH
|
||||
* \endtable
|
||||
*/
|
||||
bool Gpio::setEdgeInterrupt(int edge)
|
||||
* when an interrupt occurs. */
|
||||
bool Gpio::setEdgeInterrupt(Gpio::Edge edge)
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/edge", m_gpio);
|
||||
|
||||
int fd = open(buf, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
qCWarning(dcHardware) << "could not open /sys/class/gpio" << m_gpio << "/edge";
|
||||
if (m_direction == Gpio::DirectionOutput) {
|
||||
qCWarning(dcHardware()) << "Could not set edge interrupt, GPIO is configured as an output.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(edge == EDGE_FALLING){
|
||||
if(write(fd, "falling", 8) != 8){
|
||||
qCWarning(dcHardware) << "could not write to gpio (set EDGE_FALLING)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
if(edge == EDGE_RISING){
|
||||
if(write(fd, "rising", 7) != 7){
|
||||
qCWarning(dcHardware) << "could not write to gpio (set EDGE_RISING)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
if(edge == EDGE_BOTH){
|
||||
if(write(fd, "both", 5) != 5){
|
||||
qCWarning(dcHardware) << "could not write to gpio (set EDGE_BOTH)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! 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)
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/active_low", m_gpio);
|
||||
int fd = open(buf, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
qCWarning(dcHardware) << "could not open /sys/class/gpio" << m_gpio << "/active_low";
|
||||
QFile edgeFile(m_gpioDirectory.path() + "/edge");
|
||||
if (!edgeFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "edge file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(activeLow){
|
||||
if(write(fd, "0", 2) != 2){
|
||||
qCWarning(dcHardware) << "could not write to gpio (set Active LOW)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
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;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if(!activeLow){
|
||||
if(write(fd, "1", 2) != 2){
|
||||
qCWarning(dcHardware) << "could not write to gpio (set Active HIGH)";
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
close(fd);
|
||||
return false;
|
||||
|
||||
edgeFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns the number of this GPIO.
|
||||
* \sa Gpio::Gpio()
|
||||
*/
|
||||
int Gpio::gpioNumber()
|
||||
/*! Returns the edge interrupt of this \l{Gpio}. */
|
||||
Gpio::Edge Gpio::edgeInterrupt()
|
||||
{
|
||||
QFile edgeFile(m_gpioDirectory.path() + "/edge");
|
||||
if (!edgeFile.open(QIODevice::ReadOnly)) {
|
||||
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "edge file.";
|
||||
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;
|
||||
}
|
||||
|
||||
/*! Returns the number of this \l{Gpio}. */
|
||||
int Gpio::gpioNumber() const
|
||||
{
|
||||
return m_gpio;
|
||||
}
|
||||
|
||||
/*! Returns true if the directory /sys/class/gpio does exist.
|
||||
*/
|
||||
bool Gpio::isAvailable()
|
||||
|
||||
QDebug operator<<(QDebug d, Gpio *gpio)
|
||||
{
|
||||
QDir gpioDirectory("/sys/class/gpio");
|
||||
return gpioDirectory.exists();
|
||||
d << "-----------------------------------";
|
||||
d << "\n--> gpio" << gpio->gpioNumber() << ":";
|
||||
d << "\n------------------";
|
||||
if (gpio->direction() == Gpio::DirectionInput) {
|
||||
d << "\n direction: input";
|
||||
} else if (gpio->direction() == Gpio::DirectionOutput) {
|
||||
d << "\n direction: output";
|
||||
}
|
||||
d << "\n value:" << gpio->value();
|
||||
d << "\n active low:" << gpio->activeLow();
|
||||
|
||||
switch (gpio->edgeInterrupt()) {
|
||||
case Gpio::EdgeFalling:
|
||||
d << "\n edge interrupt:" << "falling";
|
||||
break;
|
||||
case Gpio::EdgeRising:
|
||||
d << "\n edge interrupt:" << "rising";
|
||||
break;
|
||||
case Gpio::EdgeBoth:
|
||||
d << "\n edge interrupt:" << "both";
|
||||
break;
|
||||
case Gpio::EdgeNone:
|
||||
d << "\n edge interrupt:" << "none";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
d << "\n-----------------------------------\n";
|
||||
return d;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.guru> *
|
||||
* Copyright (C) 2015 -2016 Simon Stürz <simon.stuerz@guh.guru> *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
@ -22,86 +22,65 @@
|
||||
#define GPIO_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "libguh.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
#define INPUT 0
|
||||
#define OUTPUT 1
|
||||
#define LOW 0
|
||||
#define HIGH 1
|
||||
|
||||
#define EDGE_FALLING 0
|
||||
#define EDGE_RISING 1
|
||||
#define EDGE_BOTH 2
|
||||
|
||||
|
||||
/**********************************
|
||||
* Raspberry Pi Rev. 2.0 P1 Header Raspberry Pi Rev. 2.0 P5 Header
|
||||
* __________________________________ __________________________________
|
||||
* |______________________|__________| |______________________|__________|
|
||||
* | Name | PIN NR. | Function | | Name | PIN NR. | Function |
|
||||
* |___________|__________|__________| |___________|__________|__________|
|
||||
* | GPIO 2 | 3 | SDA | | GPIO 28 | 3 | SDA |
|
||||
* | GPIO 3 | 5 | SCL | | GPIO 29 | 4 | SCL |
|
||||
* | GPIO 4 | 7 | | | GPIO 30 | 5 | |
|
||||
* | GPIO 7 | 26 | CE1 | | GPIO 31 | 6 | |
|
||||
* | GPIO 8 | 24 | CE0 | |___________|__________|__________|
|
||||
* | GPIO 9 | 21 | MISO |
|
||||
* | GPIO 10 | 19 | MOSI |
|
||||
* | GPIO 11 | 23 | SCLK |
|
||||
* | GPIO 14 | 8 | TXD |
|
||||
* | GPIO 15 | 10 | RXD |
|
||||
* | GPIO 17 | 11 | |
|
||||
* | GPIO 18 | 12 | PCM_CLK |
|
||||
* | GPIO 22 | 15 | |
|
||||
* | GPIO 23 | 16 | |
|
||||
* | GPIO 24 | 18 | |
|
||||
* | GPIO 25 | 22 | |
|
||||
* | GPIO 27 | 13 | |
|
||||
* |___________|__________|__________|
|
||||
*
|
||||
**********************************
|
||||
*/
|
||||
|
||||
class LIBGUH_EXPORT Gpio : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Gpio(QObject *parent = 0, int gpio = 0);
|
||||
enum Direction {
|
||||
DirectionInput,
|
||||
DirectionOutput,
|
||||
DirectionInvalid
|
||||
};
|
||||
|
||||
enum Value {
|
||||
ValueLow = 0,
|
||||
ValueHigh = 1,
|
||||
ValueInvalid = -1
|
||||
};
|
||||
|
||||
enum Edge {
|
||||
EdgeFalling,
|
||||
EdgeRising,
|
||||
EdgeBoth,
|
||||
EdgeNone
|
||||
};
|
||||
|
||||
explicit Gpio(int gpio = 0, QObject *parent = 0);
|
||||
~Gpio();
|
||||
|
||||
static bool isAvailable();
|
||||
|
||||
bool exportGpio();
|
||||
bool unexportGpio();
|
||||
|
||||
int openGpio();
|
||||
bool setDirection(int dir);
|
||||
int getDirection();
|
||||
bool setDirection(Gpio::Direction direction);
|
||||
Gpio::Direction direction();
|
||||
|
||||
bool setValue(unsigned int value);
|
||||
int getValue();
|
||||
bool setValue(Gpio::Value value);
|
||||
Gpio::Value value();
|
||||
|
||||
bool setEdgeInterrupt(int edge);
|
||||
bool setActiveLow(bool activeLow);
|
||||
bool activeLow();
|
||||
|
||||
int gpioNumber();
|
||||
bool isAvailable();
|
||||
bool setEdgeInterrupt(Gpio::Edge edge);
|
||||
Gpio::Edge edgeInterrupt();
|
||||
|
||||
int gpioNumber() const;
|
||||
|
||||
private:
|
||||
int m_gpio;
|
||||
int m_dir;
|
||||
Gpio::Direction m_direction;
|
||||
QDir m_gpioDirectory;
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<< (QDebug d, Gpio *gpio);
|
||||
|
||||
#endif // GPIO_H
|
||||
|
||||
@ -19,246 +19,144 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/*!
|
||||
\class GpioMonitor
|
||||
\brief The GpioMonitor class allows to monitor GPIOs.
|
||||
\class GpioMonitor
|
||||
\brief The GpioMonitor class allows to monitor GPIOs.
|
||||
|
||||
\ingroup hardware
|
||||
\inmodule libguh
|
||||
\ingroup hardware
|
||||
\inmodule libguh
|
||||
|
||||
An instance of this class creates a thread, which monitors each of the added GPIOs. The object
|
||||
emits a signal if one of the added GPIOs changes its value. The GpioMonitor configures a GPIO as an
|
||||
input, with the edge interrupt EDGE_BOTH (\l{Gpio::setEdgeInterrupt()}{setEdgeInterrupt}).
|
||||
An instance of this class creates a thread, which monitors each of the added GPIOs. The object
|
||||
emits a signal if one of the added GPIOs changes its value. The GpioMonitor configures a GPIO as an
|
||||
input, with the edge interrupt EDGE_BOTH (\l{Gpio::setEdgeInterrupt()}{setEdgeInterrupt}).
|
||||
|
||||
\chapter Example
|
||||
Following example shows how to use the GpioMonitor class for a button on the Raspberry Pi. There are two possibilitys
|
||||
to connect a button. Following picture shows the schematics:
|
||||
\chapter Example
|
||||
Following example shows how to use the GpioMonitor class for a button on the Raspberry Pi. There are two possibilitys
|
||||
to connect a button. Following picture shows the schematics:
|
||||
|
||||
\image Raspberry_Pi_Button_Example.png "Raspberry Pi button example"
|
||||
\image Raspberry_Pi_Button_Example.png "Raspberry Pi button example"
|
||||
|
||||
Button A represents a clean solutin with a 10 k\unicode{0x2126} resistor (set up as activeLow = false).
|
||||
Button B represents a "dirty" solution, were the 3.3V will be directly connected to the GPIO if the button is pressed (set activeLow = true).
|
||||
Button A represents a clean solutin with a 10 k\unicode{0x2126} resistor (set up as activeLow = false).
|
||||
Button B represents a "dirty" solution, were the 3.3V will be directly connected to the GPIO if the button is pressed (set activeLow = true).
|
||||
|
||||
Here is the code example for a button class:
|
||||
Here is the code example for a button class:
|
||||
\code
|
||||
Button::Button(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_button = new GpioMonitor(110, this);
|
||||
connect(m_button, &GpioMonitor::valueChanged, this, &Button::stateChanged);
|
||||
}
|
||||
|
||||
\tt{guhbutton.h}
|
||||
\code
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
bool Button::init()
|
||||
{
|
||||
return m_button->enable();
|
||||
}
|
||||
|
||||
#include "hardware/gpiomonitor.h"
|
||||
|
||||
class GuhButton : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GuhButton(QObject *parent = 0, int gpio = 4);
|
||||
bool enable();
|
||||
void disable();
|
||||
|
||||
private:
|
||||
GpioMonitor *m_monitor;
|
||||
int m_gpioPin;
|
||||
Gpio *m_gpio;
|
||||
|
||||
bool m_buttonPressed;
|
||||
QTimer *m_longpressedTimer;
|
||||
QTimer *m_debounceTimer;
|
||||
|
||||
signals:
|
||||
void buttonPressed();
|
||||
void buttonReleased();
|
||||
void buttonLongPressed();
|
||||
|
||||
private slots:
|
||||
void gpioChanged(const int &gpioPin, const int &value);
|
||||
};
|
||||
\endcode
|
||||
|
||||
\tt{guhbutton.cpp}
|
||||
\code
|
||||
#include "guhbutton.h"
|
||||
|
||||
GuhButton::GuhButton(QObject *parent, int gpio) :
|
||||
QObject(parent), m_gpioPin(gpio)
|
||||
{
|
||||
m_buttonPressed = false;
|
||||
}
|
||||
|
||||
bool GuhButton::enable()
|
||||
{
|
||||
qDebug() << "setup button on GPIO " << m_gpioPin;
|
||||
m_monitor = new GpioMonitor(this);
|
||||
|
||||
m_gpio = new Gpio(this, m_gpioPin);
|
||||
|
||||
if(!m_monitor->addGpio(m_gpio, false)){
|
||||
return false;
|
||||
}
|
||||
connect(m_monitor, &GpioMonitor::changed, this, &GuhButton::gpioChanged);
|
||||
|
||||
// Timer to generate the long pressed signal
|
||||
m_longpressedTimer = new QTimer(this);
|
||||
m_longpressedTimer->setInterval(500);
|
||||
m_longpressedTimer->setSingleShot(true);
|
||||
connect(m_longpressedTimer, &QTimer::timeout, this, &GuhButton::buttonLongPressed);
|
||||
|
||||
// Timer to debounce the button
|
||||
m_debounceTimer = new QTimer(this);
|
||||
m_debounceTimer->setSingleShot(true);
|
||||
m_debounceTimer->setInterval(50);
|
||||
|
||||
m_monitor->enable();
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuhButton::disable()
|
||||
{
|
||||
m_monitor->disable();
|
||||
}
|
||||
|
||||
void GuhButton::gpioChanged(const int &gpioPin, const int &value)
|
||||
{
|
||||
if (gpioPin == m_gpioPin){
|
||||
if(m_debounceTimer->isActive()){
|
||||
return;
|
||||
}
|
||||
// check button state
|
||||
bool buttonState = !QVariant(value).toBool();
|
||||
if (m_buttonPressed != buttonState) {
|
||||
if (buttonState) {
|
||||
emit buttonPressed();
|
||||
m_longpressedTimer->start();
|
||||
m_debounceTimer->start();
|
||||
} else {
|
||||
emit buttonReleased();
|
||||
m_longpressedTimer->stop();
|
||||
}
|
||||
m_buttonPressed = buttonState;
|
||||
}
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
void Button::stateChanged(const bool &value)
|
||||
{
|
||||
if (m_pressed != value) {
|
||||
m_pressed = value;
|
||||
if (value) {
|
||||
emit buttonPressed();
|
||||
} else {
|
||||
emit buttonReleased();
|
||||
}
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
/*! \fn void GpioMonitor::changed(const int &gpioPin, const int &value);
|
||||
* This signal will be emited, if one of the monitored \l{Gpio}{Gpios} changed his \a value. The \a gpioPin
|
||||
* paramter describes which \l{Gpio} changed his \a value.
|
||||
* \sa Gpio::gpioNumber()
|
||||
*/
|
||||
/*! \fn void GpioMonitor::valueChanged(const bool &value);
|
||||
* This signal will be emited, if the monitored \l{Gpio}{Gpios} changed his \a value. */
|
||||
|
||||
#include "gpiomonitor.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
/*! Constructs a \l{GpioMonitor} object with the given \a parent. */
|
||||
GpioMonitor::GpioMonitor(QObject *parent) :
|
||||
QThread(parent)
|
||||
/*! Constructs a \l{GpioMonitor} object with the given \a gpio number and \a parent. */
|
||||
GpioMonitor::GpioMonitor(int gpio, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_gpioNumber(gpio)
|
||||
{
|
||||
m_valueFile.setFileName("/sys/class/gpio/gpio" + QString::number(m_gpioNumber) + "/value");
|
||||
}
|
||||
|
||||
/*! Destructs the object of this \l{GpioMonitor}.*/
|
||||
GpioMonitor::~GpioMonitor()
|
||||
/*! Returns true if this \l{GpioMonitor} could be enabled successfully. With the \a activeLow parameter the values can be inverted.
|
||||
With the \a edgeInterrupt parameter the interrupt type can be specified. */
|
||||
bool GpioMonitor::enable(bool activeLow, Gpio::Edge edgeInterrupt)
|
||||
{
|
||||
foreach (Gpio* gpio, m_gpioList) {
|
||||
gpio->unexportGpio();
|
||||
}
|
||||
quit();
|
||||
wait();
|
||||
deleteLater();
|
||||
}
|
||||
if (!Gpio::isAvailable())
|
||||
return false;
|
||||
|
||||
/*! Starts the \l{GpioMonitor}. While the \l{GpioMonitor} is running there can not be added new \l{Gpio}{Gpios}.
|
||||
* \sa disable(), */
|
||||
void GpioMonitor::enable()
|
||||
{
|
||||
m_enabledMutex.lock();
|
||||
m_enabled = true;
|
||||
m_enabledMutex.unlock();
|
||||
start();
|
||||
}
|
||||
|
||||
/*! Stops the \l{GpioMonitor}. No changes on the \l{Gpio} will be recognized.*/
|
||||
void GpioMonitor::disable()
|
||||
{
|
||||
m_enabledMutex.lock();
|
||||
m_enabled = false;
|
||||
m_enabledMutex.unlock();
|
||||
}
|
||||
|
||||
/*! Adds the given \l{Gpio} \a gpio to the monitor. This function can only be called if the monitor is not running.
|
||||
* The given \a gpio will be configured as \a activeLow.
|
||||
* Return true if the gpio could be added and set up correctly.
|
||||
* \sa Gpio::setActiveLow(), */
|
||||
bool GpioMonitor::addGpio(Gpio *gpio, bool activeLow)
|
||||
{
|
||||
if (!gpio->exportGpio() || !gpio->setDirection(INPUT) || !gpio->setEdgeInterrupt(EDGE_BOTH) || !gpio->setActiveLow(activeLow)) {
|
||||
m_gpio = new Gpio(m_gpioNumber, this);
|
||||
if (!m_gpio->exportGpio() ||
|
||||
!m_gpio->setDirection(Gpio::DirectionInput) ||
|
||||
!m_gpio->setActiveLow(activeLow) ||
|
||||
!m_gpio->setEdgeInterrupt(edgeInterrupt)) {
|
||||
qDebug() << "ERROR: while initializing GPIO" << m_gpio->gpioNumber();
|
||||
return false;
|
||||
}
|
||||
m_gpioListMutex.lock();
|
||||
m_gpioList.append(gpio);
|
||||
m_gpioListMutex.unlock();
|
||||
|
||||
if (!m_valueFile.open(QFile::ReadOnly)) {
|
||||
qWarning() << "ERROR: could not open value file for gpio monitor" << m_gpio->gpioNumber();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_notifier = new QSocketNotifier(m_valueFile.handle(), QSocketNotifier::Exception);
|
||||
connect(m_notifier, &QSocketNotifier::activated, this, &GpioMonitor::readyReady);
|
||||
|
||||
m_notifier->setEnabled(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Returns the list of \l{Gpio}{Gpios} which currently are monitored.
|
||||
* \sa addGpio(), */
|
||||
QList<Gpio *> GpioMonitor::gpioList()
|
||||
/*! Disables this \l{GpioMonitor}. */
|
||||
void GpioMonitor::disable()
|
||||
{
|
||||
m_gpioListMutex.lock();
|
||||
QList<Gpio*> gpioList = m_gpioList;
|
||||
m_gpioListMutex.unlock();
|
||||
return gpioList;
|
||||
delete m_notifier;
|
||||
delete m_gpio;
|
||||
|
||||
m_notifier = 0;
|
||||
m_gpio = 0;
|
||||
|
||||
m_valueFile.close();
|
||||
}
|
||||
|
||||
/*! This method represents the reimplementation of the virtual void QThread::run() method. This method will be called from
|
||||
* QThread by calling the method void QThread::start(). Never call this method directly.
|
||||
* \sa enable(), */
|
||||
void GpioMonitor::run()
|
||||
/*! Returns true if this \l{GpioMonitor} is running. */
|
||||
bool GpioMonitor::isRunning() const
|
||||
{
|
||||
struct pollfd *fds;
|
||||
char val;
|
||||
int ret;
|
||||
int retVal;
|
||||
|
||||
fds = (pollfd*) malloc(sizeof(pollfd) * m_gpioList.size());
|
||||
m_gpioListMutex.lock();
|
||||
for (int i = 0; i < m_gpioList.size(); i++) {
|
||||
fds[i].fd = m_gpioList[i]->openGpio();
|
||||
fds[i].events = POLLPRI | POLLERR;
|
||||
if (!m_notifier) {
|
||||
return false;
|
||||
}
|
||||
m_gpioListMutex.unlock();
|
||||
|
||||
bool enabled = true;
|
||||
|
||||
m_enabledMutex.lock();
|
||||
m_enabled = true;
|
||||
m_enabledMutex.unlock();
|
||||
|
||||
while (enabled) {
|
||||
m_gpioListMutex.lock();
|
||||
ret = poll(fds, m_gpioList.size(), 2000);
|
||||
|
||||
if (ret > 0) {
|
||||
for (int i=0; i < m_gpioList.size(); i++) {
|
||||
if ((fds[i].revents & POLLPRI) || (fds[i].revents & POLLERR)) {
|
||||
lseek(fds[i].fd, 0, SEEK_SET);
|
||||
retVal = read(fds[i].fd, &val, 1);
|
||||
|
||||
emit changed(m_gpioList[i]->gpioNumber(), m_gpioList[i]->getValue());
|
||||
|
||||
if (retVal < 0) {
|
||||
qCWarning(dcHardware) << "GpioMonitor poll failed";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ret < 0) {
|
||||
qCWarning(dcHardware) << "poll failed: " << errno;
|
||||
}
|
||||
m_gpioListMutex.unlock();
|
||||
|
||||
m_enabledMutex.lock();
|
||||
enabled = m_enabled;
|
||||
m_enabledMutex.unlock();
|
||||
}
|
||||
free(fds);
|
||||
return m_notifier->isEnabled();
|
||||
}
|
||||
|
||||
/*! Returns the current value of this \l{GpioMonitor}. */
|
||||
bool GpioMonitor::value() const
|
||||
{
|
||||
return m_currentValue;
|
||||
}
|
||||
|
||||
/*! Returns the \l{Gpio} of this \l{GpioMonitor}. */
|
||||
Gpio *GpioMonitor::gpio()
|
||||
{
|
||||
return m_gpio;
|
||||
}
|
||||
|
||||
void GpioMonitor::readyReady(const int &ready)
|
||||
{
|
||||
Q_UNUSED(ready)
|
||||
|
||||
m_valueFile.seek(0);
|
||||
QByteArray data = m_valueFile.readAll();
|
||||
|
||||
bool value = false;
|
||||
if (data[0] == '1') {
|
||||
value = true;
|
||||
} else if (data[0] == '0') {
|
||||
value = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentValue = value;
|
||||
emit valueChanged(value);
|
||||
}
|
||||
|
||||
@ -21,41 +21,41 @@
|
||||
#ifndef GPIOMONITOR_H
|
||||
#define GPIOMONITOR_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <QSocketNotifier>
|
||||
#include <QFile>
|
||||
|
||||
#include "libguh.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "gpio.h"
|
||||
|
||||
class LIBGUH_EXPORT GpioMonitor : public QThread
|
||||
class LIBGUH_EXPORT GpioMonitor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GpioMonitor(QObject *parent = 0);
|
||||
~GpioMonitor();
|
||||
explicit GpioMonitor(int gpio, QObject *parent = 0);
|
||||
|
||||
void enable();
|
||||
bool enable(bool activeLow = false, Gpio::Edge edgeInterrupt = Gpio::EdgeBoth);
|
||||
void disable();
|
||||
bool addGpio(Gpio *gpio, bool activeLow);
|
||||
QList<Gpio*> gpioList();
|
||||
|
||||
bool isRunning() const;
|
||||
bool value() const;
|
||||
|
||||
Gpio* gpio();
|
||||
|
||||
private:
|
||||
QMutex m_enabledMutex;
|
||||
bool m_enabled;
|
||||
|
||||
QMutex m_gpioListMutex;
|
||||
QList<Gpio*> m_gpioList;
|
||||
|
||||
protected:
|
||||
void run();
|
||||
int m_gpioNumber;
|
||||
Gpio *m_gpio;
|
||||
QSocketNotifier *m_notifier;
|
||||
QFile m_valueFile;
|
||||
bool m_currentValue;
|
||||
|
||||
signals:
|
||||
void changed(const int &gpioPin, const int &value);
|
||||
void valueChanged(const bool &value);
|
||||
|
||||
private slots:
|
||||
void readyReady(const int &ready);
|
||||
|
||||
};
|
||||
|
||||
|
||||
280
libguh/hardware/pwm.cpp
Normal file
280
libguh/hardware/pwm.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
#include "pwm.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
Pwm::Pwm(int chipNumber, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_chipNumber(chipNumber),
|
||||
m_period(0),
|
||||
m_dutyCycle(0)
|
||||
{
|
||||
m_pwmDirectory = QDir("/sys/class/pwm/pwmchip" + QString::number(chipNumber) + "/");
|
||||
}
|
||||
|
||||
Pwm::~Pwm()
|
||||
{
|
||||
unexportPwm();
|
||||
}
|
||||
|
||||
bool Pwm::isAvailable()
|
||||
{
|
||||
QDir pwmDirectory("/sys/class/pwm");
|
||||
return pwmDirectory.exists() && !pwmDirectory.entryList().isEmpty();
|
||||
}
|
||||
|
||||
bool Pwm::exportPwm()
|
||||
{
|
||||
QFile exportFile(m_pwmDirectory.path() + "/export");
|
||||
if (!exportFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not export PWM" << m_chipNumber;
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&exportFile);
|
||||
out << 0;
|
||||
exportFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pwm::enable()
|
||||
{
|
||||
QFile enableFile(m_pwmDirectory.path() + "/pwm0/enable");
|
||||
if (!enableFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not enable PWM" << m_chipNumber;
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&enableFile);
|
||||
out << 1;
|
||||
enableFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pwm::disable()
|
||||
{
|
||||
QFile enableFile(m_pwmDirectory.path() + "/pwm0/enable");
|
||||
if (!enableFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not disable PWM" << m_chipNumber;
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&enableFile);
|
||||
out << 0;
|
||||
enableFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pwm::isEnabled()
|
||||
{
|
||||
QFile enableFile(m_pwmDirectory.path() + "/pwm0/enable");
|
||||
if (!enableFile.open(QIODevice::ReadOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not read" << enableFile.fileName();
|
||||
return false;
|
||||
}
|
||||
QString value;
|
||||
QTextStream in(&enableFile);
|
||||
in >> value;
|
||||
enableFile.close();
|
||||
|
||||
if (value == "1")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int Pwm::chipNumber()
|
||||
{
|
||||
return m_chipNumber;
|
||||
}
|
||||
|
||||
long Pwm::period()
|
||||
{
|
||||
// period = active + inactive time
|
||||
QFile periodFile(m_pwmDirectory.path() + "/pwm0/period");
|
||||
if (!periodFile.open(QIODevice::ReadOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not open" << periodFile.fileName();
|
||||
return false;
|
||||
}
|
||||
|
||||
QString value;
|
||||
QTextStream in(&periodFile);
|
||||
in >> value;
|
||||
periodFile.close();
|
||||
m_period = value.toLong();
|
||||
return m_period;
|
||||
}
|
||||
|
||||
bool Pwm::setPeriod(long nanoSeconds)
|
||||
{
|
||||
// the current duty cycle can not be greater than the period
|
||||
if (dutyCycle() > nanoSeconds && !setDutyCycle(nanoSeconds))
|
||||
return false;
|
||||
|
||||
// period = active + inactive time
|
||||
QFile periodFile(m_pwmDirectory.path() + "/pwm0/period");
|
||||
if (!periodFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not open" << periodFile.fileName();
|
||||
return false;
|
||||
}
|
||||
QTextStream out(&periodFile);
|
||||
out << QString::number(nanoSeconds);
|
||||
periodFile.close();
|
||||
m_period = nanoSeconds;
|
||||
return true;
|
||||
}
|
||||
|
||||
double Pwm::frequency()
|
||||
{
|
||||
return (100000000.0 / (period() * 1000));
|
||||
}
|
||||
|
||||
bool Pwm::setFrequency(double kHz)
|
||||
{
|
||||
// p = 1 / f
|
||||
long nanoSeconds = (long)(100000000 / (kHz * 1000));
|
||||
return setPeriod(nanoSeconds);
|
||||
}
|
||||
|
||||
// active time
|
||||
long Pwm::dutyCycle()
|
||||
{
|
||||
QFile dutyCycleFile(m_pwmDirectory.path() + "/pwm0/duty_cycle");
|
||||
if (!dutyCycleFile.open(QIODevice::ReadOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not open" << dutyCycleFile.fileName();
|
||||
return false;
|
||||
}
|
||||
|
||||
QString value;
|
||||
QTextStream in(&dutyCycleFile);
|
||||
in >> value;
|
||||
dutyCycleFile.close();
|
||||
m_dutyCycle = value.toLong();
|
||||
return m_dutyCycle;
|
||||
}
|
||||
|
||||
bool Pwm::setDutyCycle(long nanoSeconds)
|
||||
{
|
||||
// can not be greater than period or negative
|
||||
if (nanoSeconds > m_period || nanoSeconds < 0) {
|
||||
qCWarning(dcHardware()) << "ERROR: duty cycle has to be positive and smaller than the period";
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile dutyCycleFile(m_pwmDirectory.path() + "/pwm0/duty_cycle");
|
||||
if (!dutyCycleFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not open" << dutyCycleFile.fileName();
|
||||
return false;
|
||||
}
|
||||
QTextStream out(&dutyCycleFile);
|
||||
out << QString::number(nanoSeconds);
|
||||
dutyCycleFile.close();
|
||||
m_dutyCycle = nanoSeconds;
|
||||
return true;
|
||||
}
|
||||
|
||||
Pwm::Polarity Pwm::polarity()
|
||||
{
|
||||
QFile polarityFile(m_pwmDirectory.path() + "/pwm0/polarity");
|
||||
if (!polarityFile.open(QIODevice::ReadOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not open" << polarityFile.fileName();
|
||||
return PolarityInvalid;
|
||||
}
|
||||
|
||||
QString value;
|
||||
QTextStream in(&polarityFile);
|
||||
in >> value;
|
||||
polarityFile.close();
|
||||
|
||||
if (value == "normal") {
|
||||
return PolarityNormal;
|
||||
} else if(value == "inversed") {
|
||||
return PolarityInversed;
|
||||
}
|
||||
|
||||
return PolarityInvalid;
|
||||
}
|
||||
|
||||
bool Pwm::setPolarity(Pwm::Polarity polarity)
|
||||
{
|
||||
if (polarity == Pwm::PolarityInvalid)
|
||||
return false;
|
||||
|
||||
// Note: the polarity can only be changed if the pwm is disabled.
|
||||
bool wasEnabled = isEnabled();
|
||||
if (wasEnabled && !disable())
|
||||
return false;
|
||||
|
||||
QFile polarityFile(m_pwmDirectory.path() + "/pwm0/polarity");
|
||||
if (!polarityFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not open" << polarityFile.fileName();
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&polarityFile);
|
||||
switch (polarity) {
|
||||
case PolarityNormal:
|
||||
out << "normal";
|
||||
break;
|
||||
case PolarityInversed:
|
||||
out << "inversed";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
polarityFile.close();
|
||||
|
||||
if (wasEnabled)
|
||||
enable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Pwm::percentage()
|
||||
{
|
||||
return (int)(dutyCycle() * (100.0 / period()) + 0.5);
|
||||
}
|
||||
|
||||
bool Pwm::setPercentage(int percentage)
|
||||
{
|
||||
long nanoSeconds = period() * (percentage / 100.0);
|
||||
return setDutyCycle(nanoSeconds);
|
||||
}
|
||||
|
||||
bool Pwm::unexportPwm()
|
||||
{
|
||||
QFile unexportFile(m_pwmDirectory.path() + "/unexport");
|
||||
if (!unexportFile.open(QIODevice::WriteOnly)) {
|
||||
qCWarning(dcHardware()) << "ERROR: could not unexport PWM" << m_chipNumber;
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&unexportFile);
|
||||
out << 0;
|
||||
unexportFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug d, Pwm *pwm)
|
||||
{
|
||||
d << "-----------------------------------";
|
||||
d << "\n--> pwm0 on pwmChip" << pwm->chipNumber() << ":";
|
||||
d << "\n------------------";
|
||||
d << "\n enabled:" << pwm->isEnabled();
|
||||
d << "\n period:" << pwm->period() << "[ns]";
|
||||
d << "\n duty cycle:" << pwm->dutyCycle() << "[ns]";
|
||||
d << "\n frequency:" << pwm->frequency() << "[kHz]";
|
||||
d << "\n percentage:" << pwm->percentage() << "[%]";
|
||||
|
||||
switch (pwm->polarity()) {
|
||||
case Pwm::PolarityNormal:
|
||||
d << "\n polarity:" << "normal";
|
||||
break;
|
||||
case Pwm::PolarityInversed:
|
||||
d << "\n polarity:" << "inversed";
|
||||
break;
|
||||
default:
|
||||
d << "\n polarity:" << "invalid";
|
||||
break;
|
||||
}
|
||||
d << "\n-----------------------------------\n";
|
||||
return d;
|
||||
}
|
||||
88
libguh/hardware/pwm.h
Normal file
88
libguh/hardware/pwm.h
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef PWM_H
|
||||
#define PWM_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
|
||||
#include "libguh.h"
|
||||
|
||||
/* i.MX6 PWMs
|
||||
*
|
||||
* /sys/class/pwm/pwmchip0 -> pwm1 (npwm = 1)
|
||||
* /sys/class/pwm/pwmchip1 -> pwm2 (npwm = 1)
|
||||
* /sys/class/pwm/pwmchip2 -> pwm3 (npwm = 1)
|
||||
* /sys/class/pwm/pwmchip3 -> pwm4 (npwm = 1)
|
||||
*
|
||||
* each chip has 1 pwm ( -> pwm0)
|
||||
*
|
||||
* example:
|
||||
* echo 0 > /sys/class/pwm/pwmchip1/export
|
||||
*
|
||||
* ls -l /sys/class/pwm/pwmchip1/pwm0/
|
||||
* duty_cycle => nano seconds active time
|
||||
* enable => 0 = disable, 1 = enable
|
||||
* period => nano seconds active + inactive
|
||||
* polarity => "normal" or "inversed"
|
||||
*
|
||||
* |<--------- period --------->|
|
||||
*
|
||||
* |<--duty cycle -->|
|
||||
* 1_ _________________ _________________ _____
|
||||
* | | | | |
|
||||
* 0_ _| |___________| |___________| .......
|
||||
*
|
||||
*/
|
||||
|
||||
class LIBGUH_EXPORT Pwm : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Polarity {
|
||||
PolarityNormal,
|
||||
PolarityInversed,
|
||||
PolarityInvalid
|
||||
};
|
||||
|
||||
explicit Pwm(int chipNumber, QObject *parent = 0);
|
||||
~Pwm();
|
||||
|
||||
static bool isAvailable();
|
||||
|
||||
bool exportPwm();
|
||||
|
||||
bool enable();
|
||||
bool disable();
|
||||
|
||||
bool isEnabled();
|
||||
|
||||
int chipNumber();
|
||||
|
||||
long period();
|
||||
bool setPeriod(long nanoSeconds);
|
||||
|
||||
double frequency();
|
||||
bool setFrequency(double kHz);
|
||||
|
||||
long dutyCycle();
|
||||
bool setDutyCycle(long nanoSeconds);
|
||||
|
||||
Pwm::Polarity polarity();
|
||||
bool setPolarity(Pwm::Polarity polarity);
|
||||
|
||||
int percentage();
|
||||
bool setPercentage(int percentage);
|
||||
|
||||
private:
|
||||
int m_chipNumber;
|
||||
long m_period;
|
||||
long m_dutyCycle;
|
||||
QDir m_pwmDirectory;
|
||||
|
||||
bool unexportPwm();
|
||||
};
|
||||
|
||||
QDebug operator<< (QDebug d, Pwm *pwm);
|
||||
|
||||
#endif // PWM_H
|
||||
@ -42,16 +42,13 @@
|
||||
|
||||
\note: Radio 433 on GPIO's is by default disabled. If you want to enable it, you need to compile the source with the qmake config \tt{CONFIG+=radio433gpio}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/*! \fn void Radio433::dataReceived(QList<int> rawData)
|
||||
This signal is emitted when the receiver recognized a signal. The \a rawData parameter describes the signal.
|
||||
*/
|
||||
|
||||
#include "radio433.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "guhsettings.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
@ -63,14 +60,10 @@ Radio433::Radio433(QObject *parent) :
|
||||
GuhSettings settings(GuhSettings::SettingsRoleGlobal);
|
||||
qCDebug(dcHardware) << "Loading GPIO settings from:" << settings.fileName();
|
||||
settings.beginGroup("GPIO");
|
||||
int receiverGpioNumber = settings.value("rf433rx",27).toInt();
|
||||
int transmitterGpioNumber = settings.value("rf433tx",22).toInt();
|
||||
settings.endGroup();
|
||||
|
||||
m_receiver = new Radio433Receiver(this, receiverGpioNumber);
|
||||
m_transmitter = new Radio433Trasmitter(this, transmitterGpioNumber);
|
||||
connect(m_receiver, &Radio433Receiver::readingChanged, this, &Radio433::readingChanged);
|
||||
connect(m_receiver, &Radio433Receiver::dataReceived, this, &Radio433::dataReceived);
|
||||
#endif
|
||||
|
||||
m_brennenstuhlTransmitter = new Radio433BrennenstuhlGateway(this);
|
||||
@ -81,7 +74,6 @@ Radio433::Radio433(QObject *parent) :
|
||||
Radio433::~Radio433()
|
||||
{
|
||||
#ifdef GPIO433
|
||||
m_receiver->quit();
|
||||
m_transmitter->quit();
|
||||
#endif
|
||||
}
|
||||
@ -94,24 +86,19 @@ bool Radio433::enable()
|
||||
|
||||
#ifdef GPIO433
|
||||
// check if GPIOs are available
|
||||
QFileInfo gpioFile("/sys/class/gpio/export");
|
||||
if (gpioFile.exists()) {
|
||||
// bool receiverAvailable = m_receiver->startReceiver();
|
||||
// if (!receiverAvailable) {
|
||||
// //qWarning() << "ERROR: radio 433 MHz receiver not available on GPIO's";
|
||||
// }
|
||||
if (Gpio::isAvailable()) {
|
||||
|
||||
// bool transmitterAvailable = m_transmitter->startTransmitter();
|
||||
// if (!transmitterAvailable) {
|
||||
// //qWarning() << "ERROR: radio 433 MHz transmitter not available on GPIO's";
|
||||
// }
|
||||
bool transmitterAvailable = m_transmitter->startTransmitter();
|
||||
if (!transmitterAvailable) {
|
||||
//qCWarning(dcHardware) << "ERROR: radio 433 MHz transmitter not available on GPIO's";
|
||||
}
|
||||
|
||||
// if (!receiverAvailable && !transmitterAvailable) {
|
||||
// qWarning() << "--> Radio 433 MHz GPIO's not available.";
|
||||
// return false;
|
||||
// }
|
||||
if (!transmitterAvailable) {
|
||||
qCWarning(dcHardware) << "--> Radio 433 MHz GPIO's not available.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
qCDebug(dcDeviceManager) << "--> Radio 433 MHz GPIO's enabled.";
|
||||
qCDebug(dcDeviceManager()) << "--> Radio 433 MHz GPIO's enabled.";
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@ -121,22 +108,15 @@ bool Radio433::enable()
|
||||
bool Radio433::disabel()
|
||||
{
|
||||
m_brennenstuhlTransmitter->disable();
|
||||
|
||||
#ifdef GPIO433
|
||||
if (m_receiver->stopReceiver()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void Radio433::brennenstuhlAvailableChanged(const bool &available)
|
||||
{
|
||||
if (available) {
|
||||
qCDebug(dcDeviceManager) << "--> Radio 433 MHz Brennenstuhl LAN Gateway available.";
|
||||
qCDebug(dcHardware()) << "--> Radio 433 MHz Brennenstuhl LAN Gateway available.";
|
||||
} else {
|
||||
qCWarning(dcHardware) << "--> Radio 433 MHz Brennenstuhl LAN Gateway NOT available.";
|
||||
qCWarning(dcHardware()) << "--> Radio 433 MHz Brennenstuhl LAN Gateway NOT available.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
#include <QObject>
|
||||
|
||||
#ifdef GPIO433
|
||||
#include "radio433receiver.h"
|
||||
#include "radio433transmitter.h"
|
||||
#endif
|
||||
|
||||
@ -43,15 +42,11 @@ public:
|
||||
|
||||
private:
|
||||
#ifdef GPIO433
|
||||
Radio433Receiver *m_receiver;
|
||||
Radio433Trasmitter *m_transmitter;
|
||||
#endif
|
||||
|
||||
Radio433BrennenstuhlGateway *m_brennenstuhlTransmitter;
|
||||
|
||||
signals:
|
||||
void dataReceived(QList<int> rawData);
|
||||
|
||||
private slots:
|
||||
void brennenstuhlAvailableChanged(const bool &available);
|
||||
|
||||
|
||||
@ -52,17 +52,18 @@ void Radio433Trasmitter::run()
|
||||
rawData = m_rawDataQueue.dequeue();
|
||||
m_queueMutex.unlock();
|
||||
|
||||
m_gpio->setValue(LOW);
|
||||
m_gpio->setValue(Gpio::ValueLow);
|
||||
int flag=1;
|
||||
|
||||
foreach (int delay, rawData) {
|
||||
// 1 = High, 0 = Low
|
||||
m_gpio->setValue(flag %2);
|
||||
int value = flag %2;
|
||||
m_gpio->setValue((Gpio::Value)value);
|
||||
flag++;
|
||||
usleep(delay);
|
||||
}
|
||||
|
||||
m_gpio->setValue(LOW);
|
||||
m_gpio->setValue(Gpio::ValueLow);
|
||||
}
|
||||
m_queueMutex.unlock();
|
||||
}
|
||||
@ -76,9 +77,9 @@ void Radio433Trasmitter::allowSending(bool sending)
|
||||
|
||||
bool Radio433Trasmitter::setUpGpio()
|
||||
{
|
||||
m_gpio = new Gpio(this,m_gpioPin);
|
||||
m_gpio = new Gpio(m_gpioPin, this);
|
||||
|
||||
if(!m_gpio->exportGpio() || !m_gpio->setDirection(OUTPUT) || !m_gpio->setValue(LOW)){
|
||||
if(!m_gpio->exportGpio() || !m_gpio->setDirection(Gpio::DirectionOutput) || !m_gpio->setValue(Gpio::ValueLow)){
|
||||
m_available = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "libguh.h"
|
||||
#include "../gpio.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
|
||||
class LIBGUH_EXPORT Radio433Trasmitter : public QThread
|
||||
|
||||
@ -34,7 +34,6 @@ HEADERS += devicemanager.h \
|
||||
hardware/gpiomonitor.h \
|
||||
hardware/radio433/radio433.h \
|
||||
hardware/radio433/radio433transmitter.h \
|
||||
hardware/radio433/radio433receiver.h \
|
||||
hardware/radio433/radio433brennenstuhlgateway.h \
|
||||
network/upnpdiscovery/upnpdiscovery.h \
|
||||
network/upnpdiscovery/upnpdevice.h \
|
||||
@ -65,6 +64,7 @@ HEADERS += devicemanager.h \
|
||||
types/ruleaction.h \
|
||||
types/ruleactionparam.h \
|
||||
types/statedescriptor.h \
|
||||
hardware/pwm.h
|
||||
|
||||
|
||||
SOURCES += devicemanager.cpp \
|
||||
@ -79,7 +79,6 @@ SOURCES += devicemanager.cpp \
|
||||
hardware/gpiomonitor.cpp \
|
||||
hardware/radio433/radio433.cpp \
|
||||
hardware/radio433/radio433transmitter.cpp \
|
||||
hardware/radio433/radio433receiver.cpp \
|
||||
hardware/radio433/radio433brennenstuhlgateway.cpp \
|
||||
network/upnpdiscovery/upnpdiscovery.cpp \
|
||||
network/upnpdiscovery/upnpdevice.cpp \
|
||||
@ -110,6 +109,7 @@ SOURCES += devicemanager.cpp \
|
||||
types/ruleaction.cpp \
|
||||
types/ruleactionparam.cpp \
|
||||
types/statedescriptor.cpp \
|
||||
hardware/pwm.cpp
|
||||
|
||||
|
||||
# install plugininfo python script for libguh-dev
|
||||
|
||||
@ -614,9 +614,6 @@ bool DevicePlugin::transmitData(int delay, QList<int> rawData, int repetitions)
|
||||
switch (requiredHardware()) {
|
||||
case DeviceManager::HardwareResourceRadio433:
|
||||
return deviceManager()->m_radio433->sendData(delay, rawData, repetitions);
|
||||
case DeviceManager::HardwareResourceRadio868:
|
||||
qCDebug(dcDeviceManager) << "Radio868 not connected yet";
|
||||
return false;
|
||||
default:
|
||||
qCWarning(dcDeviceManager) << "Unknown harware type. Cannot send.";
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
|
||||
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.guru> *
|
||||
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
|
||||
Reference in New Issue
Block a user