renew gpio and pwm classes
This commit is contained in:
parent
f5ee163c48
commit
4191b8f37c
@ -40,8 +40,6 @@
|
|||||||
No Resource required.
|
No Resource required.
|
||||||
\value HardwareResourceRadio433
|
\value HardwareResourceRadio433
|
||||||
Refers to the 433 MHz radio.
|
Refers to the 433 MHz radio.
|
||||||
\value HardwareResourceRadio868
|
|
||||||
Refers to the 868 MHz radio.
|
|
||||||
\value HardwareResourceTimer
|
\value HardwareResourceTimer
|
||||||
Refers to the global timer managed by the \l{DeviceManager}. Plugins should not create their own timers,
|
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.
|
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);
|
connect(&m_pluginTimer, &QTimer::timeout, this, &DeviceManager::timerEvent);
|
||||||
|
|
||||||
m_radio433 = new Radio433(this);
|
m_radio433 = new Radio433(this);
|
||||||
connect(m_radio433, &Radio433::dataReceived, this, &DeviceManager::radio433SignalReceived);
|
|
||||||
m_radio433->enable();
|
m_radio433->enable();
|
||||||
// TODO: error handling if no Radio433 detected (GPIO or network), disable radio433 plugins or something...
|
// 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:
|
public:
|
||||||
enum HardwareResource {
|
enum HardwareResource {
|
||||||
HardwareResourceNone = 0x00,
|
HardwareResourceNone = 0,
|
||||||
HardwareResourceRadio433 = 0x01,
|
HardwareResourceRadio433 = 1,
|
||||||
HardwareResourceRadio868 = 0x02,
|
HardwareResourceTimer = 2,
|
||||||
HardwareResourceTimer = 0x04,
|
HardwareResourceNetworkManager = 4,
|
||||||
HardwareResourceNetworkManager = 0x08,
|
HardwareResourceUpnpDisovery = 8,
|
||||||
HardwareResourceUpnpDisovery = 0x10,
|
HardwareResourceBluetoothLE = 16
|
||||||
HardwareResourceBluetoothLE = 0x20
|
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(HardwareResources, HardwareResource)
|
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. *
|
* 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
|
General Purpose Input/Output (a.k.a. GPIO) is a generic pin on a chip whose
|
||||||
behavior (including whether it is an input or output pin) can be controlled
|
behavior (including whether it is an input or output pin) can be controlled
|
||||||
through this class. An object of of the Gpio class represents a pin.
|
through this class. An object of of the Gpio class represents a pin.
|
||||||
|
*/
|
||||||
|
|
||||||
\chapter Example
|
/*! \enum Gpio::Direction
|
||||||
|
|
||||||
Following example shows how to initialize and interact with a GPIO. The GPIO will be configured as an input,
|
This enum type specifies the dirction a \l{Gpio}.
|
||||||
set active high and the edge interrupt will be set to EDGE_BOTH.
|
|
||||||
|
|
||||||
\code
|
\value DirectionInput
|
||||||
Gpio *gpio = new Gpio(this, 22);
|
The \l{Gpio} is configured as \b input.
|
||||||
if (!gpio->exportGpio() || !gpio->setDirection(INPUT) || !gpio->setEdgeInterrupt(EDGE_BOTH) || !gpio->setActiveLow(true)) {
|
\value DirectionOutput
|
||||||
return;
|
The \l{Gpio} is configured as \b output.
|
||||||
}
|
\value DirectionInvalid
|
||||||
int value = gpio->getValue();
|
The direction is not valid.
|
||||||
qDebug() << "value = " << value;
|
*/
|
||||||
\endcode
|
|
||||||
|
|
||||||
\chapter Raspberry Pi GPIOs
|
/*! \enum Gpio::Value
|
||||||
In following table is a list of all GPIO's of the Raspberry Pi Rev. 2.0:
|
|
||||||
|
|
||||||
\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
|
/*! \enum Gpio::Edge
|
||||||
In following table is a list of all GPIO's of the Beaglebone Black (\l{http://pix.cs.olemiss.edu/csci581/BBBlackGPIOMap.png}{Source}):
|
|
||||||
|
|
||||||
\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>
|
#include <QDebug>
|
||||||
|
|
||||||
/*! Constructs a \l{Gpio} object to represent a GPIO with the given \a gpio number and the \a parent. */
|
/*! Constructs a \l{Gpio} object to represent a GPIO with the given \a gpio number and \a parent. */
|
||||||
Gpio::Gpio(QObject *parent, int gpio) :
|
Gpio::Gpio(int gpio, QObject *parent) :
|
||||||
QObject(parent),m_gpio(gpio)
|
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()
|
Gpio::~Gpio()
|
||||||
{
|
{
|
||||||
unexportGpio();
|
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()
|
bool Gpio::exportGpio()
|
||||||
{
|
{
|
||||||
unexportGpio();
|
QFile exportFile("/sys/class/gpio/export");
|
||||||
|
if (!exportFile.open(QIODevice::WriteOnly)) {
|
||||||
char buf[64];
|
qCWarning(dcHardware()) << "Could not export GPIO" << m_gpio;
|
||||||
|
|
||||||
int fd = open("/sys/class/gpio/export", O_WRONLY);
|
|
||||||
if (fd < 0) {
|
|
||||||
//qCWarning(dcHardware) << "could not open /sys/class/gpio/export";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t len = snprintf(buf, sizeof(buf), "%d", m_gpio);
|
QTextStream out(&exportFile);
|
||||||
if(write(fd, buf, len) != len){
|
out << m_gpio;
|
||||||
qCWarning(dcHardware) << "could not write to gpio (export)";
|
exportFile.close();
|
||||||
close(fd);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return true;
|
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()
|
bool Gpio::unexportGpio()
|
||||||
{
|
{
|
||||||
char buf[64];
|
QFile unexportFile("/sys/class/gpio/unexport");
|
||||||
|
if (!unexportFile.open(QIODevice::WriteOnly)) {
|
||||||
int fd = open("/sys/class/gpio/unexport", O_WRONLY);
|
qCWarning(dcHardware()) << "Could not unexport GPIO" << m_gpio;
|
||||||
if (fd < 0) {
|
|
||||||
//qCWarning(dcHardware) << "could not open /sys/class/gpio/unexport";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t len = snprintf(buf, sizeof(buf), "%d", m_gpio);
|
QTextStream out(&unexportFile);
|
||||||
if(write(fd, buf, len) != len){
|
out << m_gpio;
|
||||||
//qCWarning(dcHardware) << "could not write to gpio (unexport)";
|
unexportFile.close();
|
||||||
close(fd);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns true if the file of this GPIO could be opend.*/
|
/*! Returns true if the \a direction of this GPIO could be set. */
|
||||||
int Gpio::openGpio()
|
bool Gpio::setDirection(Gpio::Direction direction)
|
||||||
{
|
{
|
||||||
char buf[64];
|
QFile directionFile(m_gpioDirectory.path() + "/direction");
|
||||||
|
if (!directionFile.open(QIODevice::WriteOnly)) {
|
||||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", m_gpio);
|
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "direction file.";
|
||||||
|
|
||||||
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";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(dir == INPUT){
|
|
||||||
if(write(fd, "in", 3) != 3){
|
QTextStream out(&directionFile);
|
||||||
qCWarning(dcHardware) << "could not write to gpio (set INPUT)";
|
switch (direction) {
|
||||||
close(fd);
|
case DirectionInput:
|
||||||
return false;
|
out << "in";
|
||||||
}
|
break;
|
||||||
m_dir = INPUT;
|
case DirectionOutput:
|
||||||
close(fd);
|
out << "out";
|
||||||
return true;
|
break;
|
||||||
|
default:
|
||||||
|
directionFile.close();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if(dir == OUTPUT){
|
|
||||||
if(write(fd, "out", 4) != 4){
|
directionFile.close();
|
||||||
qCWarning(dcHardware) << "could not write to gpio (set OUTPUT)";
|
return true;
|
||||||
close(fd);
|
}
|
||||||
return false;
|
|
||||||
}
|
/*! Returns the direction of this \l{Gpio}. */
|
||||||
m_dir = OUTPUT;
|
Gpio::Direction Gpio::direction()
|
||||||
close(fd);
|
{
|
||||||
return true;
|
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;
|
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,
|
/*! Returns true if the \a edge of this GPIO could be set correctly. The \a edge parameter specifies,
|
||||||
* when an interrupt occurs.
|
* when an interrupt occurs. */
|
||||||
*
|
bool Gpio::setEdgeInterrupt(Gpio::Edge edge)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
char buf[64];
|
if (m_direction == Gpio::DirectionOutput) {
|
||||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/edge", m_gpio);
|
qCWarning(dcHardware()) << "Could not set edge interrupt, GPIO is configured as an output.";
|
||||||
|
|
||||||
int fd = open(buf, O_WRONLY);
|
|
||||||
if (fd < 0) {
|
|
||||||
qCWarning(dcHardware) << "could not open /sys/class/gpio" << m_gpio << "/edge";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(edge == EDGE_FALLING){
|
QFile edgeFile(m_gpioDirectory.path() + "/edge");
|
||||||
if(write(fd, "falling", 8) != 8){
|
if (!edgeFile.open(QIODevice::WriteOnly)) {
|
||||||
qCWarning(dcHardware) << "could not write to gpio (set EDGE_FALLING)";
|
qCWarning(dcHardware()) << "Could not open GPIO" << m_gpio << "edge file.";
|
||||||
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";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(activeLow){
|
QTextStream out(&edgeFile);
|
||||||
if(write(fd, "0", 2) != 2){
|
switch (edge) {
|
||||||
qCWarning(dcHardware) << "could not write to gpio (set Active LOW)";
|
case EdgeFalling:
|
||||||
close(fd);
|
out << "falling";
|
||||||
return false;
|
break;
|
||||||
}
|
case EdgeRising:
|
||||||
close(fd);
|
out << "rising";
|
||||||
return true;
|
break;
|
||||||
|
case EdgeBoth:
|
||||||
|
out << "both";
|
||||||
|
break;
|
||||||
|
case EdgeNone:
|
||||||
|
out << "none";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if(!activeLow){
|
|
||||||
if(write(fd, "1", 2) != 2){
|
edgeFile.close();
|
||||||
qCWarning(dcHardware) << "could not write to gpio (set Active HIGH)";
|
return true;
|
||||||
close(fd);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns the number of this GPIO.
|
/*! Returns the edge interrupt of this \l{Gpio}. */
|
||||||
* \sa Gpio::Gpio()
|
Gpio::Edge Gpio::edgeInterrupt()
|
||||||
*/
|
{
|
||||||
int Gpio::gpioNumber()
|
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;
|
return m_gpio;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns true if the directory /sys/class/gpio does exist.
|
|
||||||
*/
|
QDebug operator<<(QDebug d, Gpio *gpio)
|
||||||
bool Gpio::isAvailable()
|
|
||||||
{
|
{
|
||||||
QDir gpioDirectory("/sys/class/gpio");
|
d << "-----------------------------------";
|
||||||
return gpioDirectory.exists();
|
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. *
|
* This file is part of guh. *
|
||||||
* *
|
* *
|
||||||
@ -22,86 +22,65 @@
|
|||||||
#define GPIO_H
|
#define GPIO_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QThread>
|
#include <QDebug>
|
||||||
#include <QMutex>
|
|
||||||
#include <QMutexLocker>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
#include "libguh.h"
|
#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
|
class LIBGUH_EXPORT Gpio : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
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();
|
~Gpio();
|
||||||
|
|
||||||
|
static bool isAvailable();
|
||||||
|
|
||||||
bool exportGpio();
|
bool exportGpio();
|
||||||
bool unexportGpio();
|
bool unexportGpio();
|
||||||
|
|
||||||
int openGpio();
|
bool setDirection(Gpio::Direction direction);
|
||||||
bool setDirection(int dir);
|
Gpio::Direction direction();
|
||||||
int getDirection();
|
|
||||||
|
|
||||||
bool setValue(unsigned int value);
|
bool setValue(Gpio::Value value);
|
||||||
int getValue();
|
Gpio::Value value();
|
||||||
|
|
||||||
bool setEdgeInterrupt(int edge);
|
|
||||||
bool setActiveLow(bool activeLow);
|
bool setActiveLow(bool activeLow);
|
||||||
|
bool activeLow();
|
||||||
|
|
||||||
int gpioNumber();
|
bool setEdgeInterrupt(Gpio::Edge edge);
|
||||||
bool isAvailable();
|
Gpio::Edge edgeInterrupt();
|
||||||
|
|
||||||
|
int gpioNumber() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_gpio;
|
int m_gpio;
|
||||||
int m_dir;
|
Gpio::Direction m_direction;
|
||||||
|
QDir m_gpioDirectory;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QDebug operator<< (QDebug d, Gpio *gpio);
|
||||||
|
|
||||||
#endif // GPIO_H
|
#endif // GPIO_H
|
||||||
|
|||||||
@ -19,246 +19,144 @@
|
|||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class GpioMonitor
|
\class GpioMonitor
|
||||||
\brief The GpioMonitor class allows to monitor GPIOs.
|
\brief The GpioMonitor class allows to monitor GPIOs.
|
||||||
|
|
||||||
\ingroup hardware
|
\ingroup hardware
|
||||||
\inmodule libguh
|
\inmodule libguh
|
||||||
|
|
||||||
An instance of this class creates a thread, which monitors each of the added GPIOs. The object
|
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
|
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}).
|
input, with the edge interrupt EDGE_BOTH (\l{Gpio::setEdgeInterrupt()}{setEdgeInterrupt}).
|
||||||
|
|
||||||
\chapter Example
|
\chapter Example
|
||||||
Following example shows how to use the GpioMonitor class for a button on the Raspberry Pi. There are two possibilitys
|
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:
|
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 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 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}
|
bool Button::init()
|
||||||
\code
|
{
|
||||||
#include <QObject>
|
return m_button->enable();
|
||||||
#include <QDebug>
|
}
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#include "hardware/gpiomonitor.h"
|
void Button::stateChanged(const bool &value)
|
||||||
|
{
|
||||||
class GuhButton : public QObject
|
if (m_pressed != value) {
|
||||||
{
|
m_pressed = value;
|
||||||
Q_OBJECT
|
if (value) {
|
||||||
public:
|
emit buttonPressed();
|
||||||
explicit GuhButton(QObject *parent = 0, int gpio = 4);
|
} else {
|
||||||
bool enable();
|
emit buttonReleased();
|
||||||
void disable();
|
}
|
||||||
|
}
|
||||||
private:
|
}
|
||||||
GpioMonitor *m_monitor;
|
\endcode
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \fn void GpioMonitor::changed(const int &gpioPin, const int &value);
|
/*! \fn void GpioMonitor::valueChanged(const bool &value);
|
||||||
* This signal will be emited, if one of the monitored \l{Gpio}{Gpios} changed his \a value. The \a gpioPin
|
* This signal will be emited, if the monitored \l{Gpio}{Gpios} changed his \a value. */
|
||||||
* paramter describes which \l{Gpio} changed his \a value.
|
|
||||||
* \sa Gpio::gpioNumber()
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "gpiomonitor.h"
|
#include "gpiomonitor.h"
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
/*! Constructs a \l{GpioMonitor} object with the given \a parent. */
|
/*! Constructs a \l{GpioMonitor} object with the given \a gpio number and \a parent. */
|
||||||
GpioMonitor::GpioMonitor(QObject *parent) :
|
GpioMonitor::GpioMonitor(int gpio, QObject *parent) :
|
||||||
QThread(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}.*/
|
/*! Returns true if this \l{GpioMonitor} could be enabled successfully. With the \a activeLow parameter the values can be inverted.
|
||||||
GpioMonitor::~GpioMonitor()
|
With the \a edgeInterrupt parameter the interrupt type can be specified. */
|
||||||
|
bool GpioMonitor::enable(bool activeLow, Gpio::Edge edgeInterrupt)
|
||||||
{
|
{
|
||||||
foreach (Gpio* gpio, m_gpioList) {
|
if (!Gpio::isAvailable())
|
||||||
gpio->unexportGpio();
|
return false;
|
||||||
}
|
|
||||||
quit();
|
|
||||||
wait();
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Starts the \l{GpioMonitor}. While the \l{GpioMonitor} is running there can not be added new \l{Gpio}{Gpios}.
|
m_gpio = new Gpio(m_gpioNumber, this);
|
||||||
* \sa disable(), */
|
if (!m_gpio->exportGpio() ||
|
||||||
void GpioMonitor::enable()
|
!m_gpio->setDirection(Gpio::DirectionInput) ||
|
||||||
{
|
!m_gpio->setActiveLow(activeLow) ||
|
||||||
m_enabledMutex.lock();
|
!m_gpio->setEdgeInterrupt(edgeInterrupt)) {
|
||||||
m_enabled = true;
|
qDebug() << "ERROR: while initializing GPIO" << m_gpio->gpioNumber();
|
||||||
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)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_gpioListMutex.lock();
|
|
||||||
m_gpioList.append(gpio);
|
if (!m_valueFile.open(QFile::ReadOnly)) {
|
||||||
m_gpioListMutex.unlock();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns the list of \l{Gpio}{Gpios} which currently are monitored.
|
/*! Disables this \l{GpioMonitor}. */
|
||||||
* \sa addGpio(), */
|
void GpioMonitor::disable()
|
||||||
QList<Gpio *> GpioMonitor::gpioList()
|
|
||||||
{
|
{
|
||||||
m_gpioListMutex.lock();
|
delete m_notifier;
|
||||||
QList<Gpio*> gpioList = m_gpioList;
|
delete m_gpio;
|
||||||
m_gpioListMutex.unlock();
|
|
||||||
return gpioList;
|
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
|
/*! Returns true if this \l{GpioMonitor} is running. */
|
||||||
* QThread by calling the method void QThread::start(). Never call this method directly.
|
bool GpioMonitor::isRunning() const
|
||||||
* \sa enable(), */
|
|
||||||
void GpioMonitor::run()
|
|
||||||
{
|
{
|
||||||
struct pollfd *fds;
|
if (!m_notifier) {
|
||||||
char val;
|
return false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
m_gpioListMutex.unlock();
|
return m_notifier->isEnabled();
|
||||||
|
}
|
||||||
bool enabled = true;
|
|
||||||
|
/*! Returns the current value of this \l{GpioMonitor}. */
|
||||||
m_enabledMutex.lock();
|
bool GpioMonitor::value() const
|
||||||
m_enabled = true;
|
{
|
||||||
m_enabledMutex.unlock();
|
return m_currentValue;
|
||||||
|
}
|
||||||
while (enabled) {
|
|
||||||
m_gpioListMutex.lock();
|
/*! Returns the \l{Gpio} of this \l{GpioMonitor}. */
|
||||||
ret = poll(fds, m_gpioList.size(), 2000);
|
Gpio *GpioMonitor::gpio()
|
||||||
|
{
|
||||||
if (ret > 0) {
|
return m_gpio;
|
||||||
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);
|
void GpioMonitor::readyReady(const int &ready)
|
||||||
retVal = read(fds[i].fd, &val, 1);
|
{
|
||||||
|
Q_UNUSED(ready)
|
||||||
emit changed(m_gpioList[i]->gpioNumber(), m_gpioList[i]->getValue());
|
|
||||||
|
m_valueFile.seek(0);
|
||||||
if (retVal < 0) {
|
QByteArray data = m_valueFile.readAll();
|
||||||
qCWarning(dcHardware) << "GpioMonitor poll failed";
|
|
||||||
}
|
bool value = false;
|
||||||
}
|
if (data[0] == '1') {
|
||||||
}
|
value = true;
|
||||||
} else if (ret < 0) {
|
} else if (data[0] == '0') {
|
||||||
qCWarning(dcHardware) << "poll failed: " << errno;
|
value = false;
|
||||||
}
|
} else {
|
||||||
m_gpioListMutex.unlock();
|
return;
|
||||||
|
}
|
||||||
m_enabledMutex.lock();
|
|
||||||
enabled = m_enabled;
|
m_currentValue = value;
|
||||||
m_enabledMutex.unlock();
|
emit valueChanged(value);
|
||||||
}
|
|
||||||
free(fds);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,41 +21,41 @@
|
|||||||
#ifndef GPIOMONITOR_H
|
#ifndef GPIOMONITOR_H
|
||||||
#define GPIOMONITOR_H
|
#define GPIOMONITOR_H
|
||||||
|
|
||||||
#include <QThread>
|
#include <QObject>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <fcntl.h>
|
#include <QSocketNotifier>
|
||||||
#include <stdio.h>
|
#include <QFile>
|
||||||
#include <poll.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "libguh.h"
|
#include "libguh.h"
|
||||||
#include "hardware/gpio.h"
|
#include "gpio.h"
|
||||||
|
|
||||||
class LIBGUH_EXPORT GpioMonitor : public QThread
|
class LIBGUH_EXPORT GpioMonitor : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GpioMonitor(QObject *parent = 0);
|
explicit GpioMonitor(int gpio, QObject *parent = 0);
|
||||||
~GpioMonitor();
|
|
||||||
|
|
||||||
void enable();
|
bool enable(bool activeLow = false, Gpio::Edge edgeInterrupt = Gpio::EdgeBoth);
|
||||||
void disable();
|
void disable();
|
||||||
bool addGpio(Gpio *gpio, bool activeLow);
|
|
||||||
QList<Gpio*> gpioList();
|
|
||||||
|
|
||||||
|
bool isRunning() const;
|
||||||
|
bool value() const;
|
||||||
|
|
||||||
|
Gpio* gpio();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMutex m_enabledMutex;
|
int m_gpioNumber;
|
||||||
bool m_enabled;
|
Gpio *m_gpio;
|
||||||
|
QSocketNotifier *m_notifier;
|
||||||
QMutex m_gpioListMutex;
|
QFile m_valueFile;
|
||||||
QList<Gpio*> m_gpioList;
|
bool m_currentValue;
|
||||||
|
|
||||||
protected:
|
|
||||||
void run();
|
|
||||||
|
|
||||||
signals:
|
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}
|
\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 "radio433.h"
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
#include "guhsettings.h"
|
#include "guhsettings.h"
|
||||||
|
#include "hardware/gpio.h"
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
@ -63,14 +60,10 @@ Radio433::Radio433(QObject *parent) :
|
|||||||
GuhSettings settings(GuhSettings::SettingsRoleGlobal);
|
GuhSettings settings(GuhSettings::SettingsRoleGlobal);
|
||||||
qCDebug(dcHardware) << "Loading GPIO settings from:" << settings.fileName();
|
qCDebug(dcHardware) << "Loading GPIO settings from:" << settings.fileName();
|
||||||
settings.beginGroup("GPIO");
|
settings.beginGroup("GPIO");
|
||||||
int receiverGpioNumber = settings.value("rf433rx",27).toInt();
|
|
||||||
int transmitterGpioNumber = settings.value("rf433tx",22).toInt();
|
int transmitterGpioNumber = settings.value("rf433tx",22).toInt();
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
m_receiver = new Radio433Receiver(this, receiverGpioNumber);
|
|
||||||
m_transmitter = new Radio433Trasmitter(this, transmitterGpioNumber);
|
m_transmitter = new Radio433Trasmitter(this, transmitterGpioNumber);
|
||||||
connect(m_receiver, &Radio433Receiver::readingChanged, this, &Radio433::readingChanged);
|
|
||||||
connect(m_receiver, &Radio433Receiver::dataReceived, this, &Radio433::dataReceived);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_brennenstuhlTransmitter = new Radio433BrennenstuhlGateway(this);
|
m_brennenstuhlTransmitter = new Radio433BrennenstuhlGateway(this);
|
||||||
@ -81,7 +74,6 @@ Radio433::Radio433(QObject *parent) :
|
|||||||
Radio433::~Radio433()
|
Radio433::~Radio433()
|
||||||
{
|
{
|
||||||
#ifdef GPIO433
|
#ifdef GPIO433
|
||||||
m_receiver->quit();
|
|
||||||
m_transmitter->quit();
|
m_transmitter->quit();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -94,24 +86,19 @@ bool Radio433::enable()
|
|||||||
|
|
||||||
#ifdef GPIO433
|
#ifdef GPIO433
|
||||||
// check if GPIOs are available
|
// check if GPIOs are available
|
||||||
QFileInfo gpioFile("/sys/class/gpio/export");
|
if (Gpio::isAvailable()) {
|
||||||
if (gpioFile.exists()) {
|
|
||||||
// bool receiverAvailable = m_receiver->startReceiver();
|
|
||||||
// if (!receiverAvailable) {
|
|
||||||
// //qWarning() << "ERROR: radio 433 MHz receiver not available on GPIO's";
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bool transmitterAvailable = m_transmitter->startTransmitter();
|
bool transmitterAvailable = m_transmitter->startTransmitter();
|
||||||
// if (!transmitterAvailable) {
|
if (!transmitterAvailable) {
|
||||||
// //qWarning() << "ERROR: radio 433 MHz transmitter not available on GPIO's";
|
//qCWarning(dcHardware) << "ERROR: radio 433 MHz transmitter not available on GPIO's";
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (!receiverAvailable && !transmitterAvailable) {
|
if (!transmitterAvailable) {
|
||||||
// qWarning() << "--> Radio 433 MHz GPIO's not available.";
|
qCWarning(dcHardware) << "--> Radio 433 MHz GPIO's not available.";
|
||||||
// return false;
|
return false;
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
qCDebug(dcDeviceManager) << "--> Radio 433 MHz GPIO's enabled.";
|
qCDebug(dcDeviceManager()) << "--> Radio 433 MHz GPIO's enabled.";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -121,22 +108,15 @@ bool Radio433::enable()
|
|||||||
bool Radio433::disabel()
|
bool Radio433::disabel()
|
||||||
{
|
{
|
||||||
m_brennenstuhlTransmitter->disable();
|
m_brennenstuhlTransmitter->disable();
|
||||||
|
|
||||||
#ifdef GPIO433
|
|
||||||
if (m_receiver->stopReceiver()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Radio433::brennenstuhlAvailableChanged(const bool &available)
|
void Radio433::brennenstuhlAvailableChanged(const bool &available)
|
||||||
{
|
{
|
||||||
if (available) {
|
if (available) {
|
||||||
qCDebug(dcDeviceManager) << "--> Radio 433 MHz Brennenstuhl LAN Gateway available.";
|
qCDebug(dcHardware()) << "--> Radio 433 MHz Brennenstuhl LAN Gateway available.";
|
||||||
} else {
|
} 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>
|
#include <QObject>
|
||||||
|
|
||||||
#ifdef GPIO433
|
#ifdef GPIO433
|
||||||
#include "radio433receiver.h"
|
|
||||||
#include "radio433transmitter.h"
|
#include "radio433transmitter.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -43,15 +42,11 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef GPIO433
|
#ifdef GPIO433
|
||||||
Radio433Receiver *m_receiver;
|
|
||||||
Radio433Trasmitter *m_transmitter;
|
Radio433Trasmitter *m_transmitter;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Radio433BrennenstuhlGateway *m_brennenstuhlTransmitter;
|
Radio433BrennenstuhlGateway *m_brennenstuhlTransmitter;
|
||||||
|
|
||||||
signals:
|
|
||||||
void dataReceived(QList<int> rawData);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void brennenstuhlAvailableChanged(const bool &available);
|
void brennenstuhlAvailableChanged(const bool &available);
|
||||||
|
|
||||||
|
|||||||
@ -52,17 +52,18 @@ void Radio433Trasmitter::run()
|
|||||||
rawData = m_rawDataQueue.dequeue();
|
rawData = m_rawDataQueue.dequeue();
|
||||||
m_queueMutex.unlock();
|
m_queueMutex.unlock();
|
||||||
|
|
||||||
m_gpio->setValue(LOW);
|
m_gpio->setValue(Gpio::ValueLow);
|
||||||
int flag=1;
|
int flag=1;
|
||||||
|
|
||||||
foreach (int delay, rawData) {
|
foreach (int delay, rawData) {
|
||||||
// 1 = High, 0 = Low
|
// 1 = High, 0 = Low
|
||||||
m_gpio->setValue(flag %2);
|
int value = flag %2;
|
||||||
|
m_gpio->setValue((Gpio::Value)value);
|
||||||
flag++;
|
flag++;
|
||||||
usleep(delay);
|
usleep(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_gpio->setValue(LOW);
|
m_gpio->setValue(Gpio::ValueLow);
|
||||||
}
|
}
|
||||||
m_queueMutex.unlock();
|
m_queueMutex.unlock();
|
||||||
}
|
}
|
||||||
@ -76,9 +77,9 @@ void Radio433Trasmitter::allowSending(bool sending)
|
|||||||
|
|
||||||
bool Radio433Trasmitter::setUpGpio()
|
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;
|
m_available = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "libguh.h"
|
#include "libguh.h"
|
||||||
#include "../gpio.h"
|
#include "hardware/gpio.h"
|
||||||
|
|
||||||
|
|
||||||
class LIBGUH_EXPORT Radio433Trasmitter : public QThread
|
class LIBGUH_EXPORT Radio433Trasmitter : public QThread
|
||||||
|
|||||||
@ -34,7 +34,6 @@ HEADERS += devicemanager.h \
|
|||||||
hardware/gpiomonitor.h \
|
hardware/gpiomonitor.h \
|
||||||
hardware/radio433/radio433.h \
|
hardware/radio433/radio433.h \
|
||||||
hardware/radio433/radio433transmitter.h \
|
hardware/radio433/radio433transmitter.h \
|
||||||
hardware/radio433/radio433receiver.h \
|
|
||||||
hardware/radio433/radio433brennenstuhlgateway.h \
|
hardware/radio433/radio433brennenstuhlgateway.h \
|
||||||
network/upnpdiscovery/upnpdiscovery.h \
|
network/upnpdiscovery/upnpdiscovery.h \
|
||||||
network/upnpdiscovery/upnpdevice.h \
|
network/upnpdiscovery/upnpdevice.h \
|
||||||
@ -65,6 +64,7 @@ HEADERS += devicemanager.h \
|
|||||||
types/ruleaction.h \
|
types/ruleaction.h \
|
||||||
types/ruleactionparam.h \
|
types/ruleactionparam.h \
|
||||||
types/statedescriptor.h \
|
types/statedescriptor.h \
|
||||||
|
hardware/pwm.h
|
||||||
|
|
||||||
|
|
||||||
SOURCES += devicemanager.cpp \
|
SOURCES += devicemanager.cpp \
|
||||||
@ -79,7 +79,6 @@ SOURCES += devicemanager.cpp \
|
|||||||
hardware/gpiomonitor.cpp \
|
hardware/gpiomonitor.cpp \
|
||||||
hardware/radio433/radio433.cpp \
|
hardware/radio433/radio433.cpp \
|
||||||
hardware/radio433/radio433transmitter.cpp \
|
hardware/radio433/radio433transmitter.cpp \
|
||||||
hardware/radio433/radio433receiver.cpp \
|
|
||||||
hardware/radio433/radio433brennenstuhlgateway.cpp \
|
hardware/radio433/radio433brennenstuhlgateway.cpp \
|
||||||
network/upnpdiscovery/upnpdiscovery.cpp \
|
network/upnpdiscovery/upnpdiscovery.cpp \
|
||||||
network/upnpdiscovery/upnpdevice.cpp \
|
network/upnpdiscovery/upnpdevice.cpp \
|
||||||
@ -110,6 +109,7 @@ SOURCES += devicemanager.cpp \
|
|||||||
types/ruleaction.cpp \
|
types/ruleaction.cpp \
|
||||||
types/ruleactionparam.cpp \
|
types/ruleactionparam.cpp \
|
||||||
types/statedescriptor.cpp \
|
types/statedescriptor.cpp \
|
||||||
|
hardware/pwm.cpp
|
||||||
|
|
||||||
|
|
||||||
# install plugininfo python script for libguh-dev
|
# install plugininfo python script for libguh-dev
|
||||||
|
|||||||
@ -614,9 +614,6 @@ bool DevicePlugin::transmitData(int delay, QList<int> rawData, int repetitions)
|
|||||||
switch (requiredHardware()) {
|
switch (requiredHardware()) {
|
||||||
case DeviceManager::HardwareResourceRadio433:
|
case DeviceManager::HardwareResourceRadio433:
|
||||||
return deviceManager()->m_radio433->sendData(delay, rawData, repetitions);
|
return deviceManager()->m_radio433->sendData(delay, rawData, repetitions);
|
||||||
case DeviceManager::HardwareResourceRadio868:
|
|
||||||
qCDebug(dcDeviceManager) << "Radio868 not connected yet";
|
|
||||||
return false;
|
|
||||||
default:
|
default:
|
||||||
qCWarning(dcDeviceManager) << "Unknown harware type. Cannot send.";
|
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> *
|
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
|
||||||
* *
|
* *
|
||||||
* This file is part of guh. *
|
* This file is part of guh. *
|
||||||
|
|||||||
Reference in New Issue
Block a user