mirror of https://github.com/nymea/nymea.git
271 lines
8.5 KiB
C++
271 lines
8.5 KiB
C++
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* *
|
|
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.guru> *
|
|
* *
|
|
* This file is part of nymea. *
|
|
* *
|
|
* nymea is free software: you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation, version 2 of the License. *
|
|
* *
|
|
* *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
|
* *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include <QFile>
|
|
#include <QFileSystemWatcher>
|
|
#include <QDebug>
|
|
#include <sys/time.h>
|
|
|
|
#include "radio433receiver.h"
|
|
#include "loggingcategories.h"
|
|
|
|
Radio433Receiver::Radio433Receiver(QObject *parent, int gpio) :
|
|
QThread(parent),m_gpioPin(gpio)
|
|
{
|
|
m_timings.clear();
|
|
m_available = false;
|
|
|
|
m_mutex.lock();
|
|
m_enabled = false;
|
|
m_mutex.unlock();
|
|
|
|
connect(this, &Radio433Receiver::timingReady, this, &Radio433Receiver::handleTiming, Qt::DirectConnection);
|
|
}
|
|
|
|
Radio433Receiver::~Radio433Receiver()
|
|
{
|
|
quit();
|
|
wait();
|
|
deleteLater();
|
|
}
|
|
|
|
bool Radio433Receiver::stopReceiver()
|
|
{
|
|
m_mutex.lock();
|
|
m_enabled = false;
|
|
m_mutex.unlock();
|
|
return true;
|
|
}
|
|
|
|
bool Radio433Receiver::available()
|
|
{
|
|
return m_available;
|
|
}
|
|
|
|
void Radio433Receiver::run()
|
|
{
|
|
struct pollfd fdset[2];
|
|
int gpio_fd = m_gpio->openGpio();
|
|
char buf[1];
|
|
|
|
bool enabled = true;
|
|
m_mutex.lock();
|
|
m_enabled = true;
|
|
m_mutex.unlock();
|
|
|
|
int lastTime = micros();
|
|
// poll the gpio file, if something changes...emit the signal with the current pulse length
|
|
while(enabled){
|
|
memset((void*)fdset, 0, sizeof(fdset));
|
|
fdset[0].fd = STDIN_FILENO;
|
|
fdset[0].events = POLLIN;
|
|
|
|
fdset[1].fd = gpio_fd;
|
|
fdset[1].events = POLLPRI;
|
|
int rc = poll(fdset, 2, 1000);
|
|
|
|
if (rc < 0) {
|
|
qCWarning(dcHardware) << "ERROR: poll failed";
|
|
return;
|
|
}
|
|
if(rc == 0){
|
|
//timeout
|
|
}
|
|
if (fdset[1].revents & POLLPRI){
|
|
if(read(fdset[1].fd, buf, 1) != 1){
|
|
qCWarning(dcHardware) << "could not read GPIO";
|
|
}
|
|
int currentTime = micros();
|
|
int duration = currentTime - lastTime;
|
|
lastTime = currentTime;
|
|
emit timingReady(duration);
|
|
}
|
|
|
|
m_mutex.lock();
|
|
enabled = m_enabled;
|
|
m_mutex.unlock();
|
|
}
|
|
}
|
|
|
|
bool Radio433Receiver::setUpGpio()
|
|
{
|
|
if(!m_gpio){
|
|
m_gpio = new Gpio(this,m_gpioPin);
|
|
}
|
|
|
|
if(!m_gpio->exportGpio() || !m_gpio->setDirection(INPUT) || !m_gpio->setEdgeInterrupt(EDGE_BOTH)){
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Radio433Receiver::startReceiver()
|
|
{
|
|
if(!setUpGpio()){
|
|
m_available = false;
|
|
return false;
|
|
}
|
|
|
|
m_mutex.lock();
|
|
m_enabled = true;
|
|
m_mutex.unlock();
|
|
m_available = true;
|
|
|
|
start();
|
|
return true;
|
|
}
|
|
|
|
int Radio433Receiver::micros()
|
|
{
|
|
struct timeval tv ;
|
|
int now ;
|
|
gettimeofday (&tv, NULL) ;
|
|
now = (int)tv.tv_sec * (int)1000000 + (int)tv.tv_usec ;
|
|
|
|
return (int)(now - m_epochMicro) ;
|
|
}
|
|
|
|
bool Radio433Receiver::valueInTolerance(int value, int correctValue)
|
|
{
|
|
// in in range of +- 200 [us] of sollValue return true, eles return false
|
|
if(value >= (double)correctValue - 200 && value <= (double)correctValue + 200){
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Radio433Receiver::checkValue(int value)
|
|
{
|
|
if(valueInTolerance(value,m_pulseProtocolOne) || valueInTolerance(value,2*m_pulseProtocolOne) || valueInTolerance(value,3*m_pulseProtocolOne) || valueInTolerance(value,4*m_pulseProtocolOne) || valueInTolerance(value,8*m_pulseProtocolOne)){
|
|
return true;
|
|
}
|
|
if(valueInTolerance(value,m_pulseProtocolTwo) || valueInTolerance(value,2*m_pulseProtocolTwo) || valueInTolerance(value,3*m_pulseProtocolTwo) || valueInTolerance(value,4*m_pulseProtocolTwo) || valueInTolerance(value,8*m_pulseProtocolTwo)){
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Radio433Receiver::checkValues(Protocol protocol)
|
|
{
|
|
switch (protocol) {
|
|
case Protocol48:
|
|
for(int i = 1; i < m_timings.count(); i++){
|
|
if(!(valueInTolerance(m_timings.at(i),m_pulseProtocolOne) || valueInTolerance(m_timings.at(i),2*m_pulseProtocolOne) || valueInTolerance(m_timings.at(i),3*m_pulseProtocolOne) || valueInTolerance(m_timings.at(i),4*m_pulseProtocolOne) || valueInTolerance(m_timings.at(i),8*m_pulseProtocolOne))){
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
case Protocol64:
|
|
for(int i = 1; i < m_timings.count(); i++){
|
|
if(!(valueInTolerance(m_timings.at(i),m_pulseProtocolTwo) || valueInTolerance(m_timings.at(i),2*m_pulseProtocolTwo) || valueInTolerance(m_timings.at(i),3*m_pulseProtocolTwo) || valueInTolerance(m_timings.at(i),4*m_pulseProtocolTwo) || valueInTolerance(m_timings.at(i),8*m_pulseProtocolTwo))){
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Radio433Receiver::changeReading(bool reading)
|
|
{
|
|
if(reading != m_reading){
|
|
m_reading = reading;
|
|
|
|
//TODO: create colission detection
|
|
|
|
//emit readingChanged(reading);
|
|
}
|
|
}
|
|
|
|
void Radio433Receiver::handleTiming(int duration)
|
|
{
|
|
// to short...
|
|
if(duration < 60){
|
|
changeReading(false);
|
|
m_timings.clear();
|
|
return;
|
|
}
|
|
|
|
// could by a sync signal...
|
|
bool sync = false;
|
|
if(duration > 2400 && duration < 14000){
|
|
changeReading(false);
|
|
sync = true;
|
|
}
|
|
|
|
// got sync signal and list is not empty...
|
|
if(!m_timings.isEmpty() && sync){
|
|
// 1 sync bit + 48 data bit
|
|
if(m_timings.count() == 49 && checkValues(Protocol48)){
|
|
//qCWarning(dcHardware) << "48 bit ->" << m_timings << "\n--------------------------";
|
|
changeReading(false);
|
|
emit dataReceived(m_timings);
|
|
}
|
|
|
|
// 1 sync bit + 64 data bit
|
|
if(m_timings.count() == 65 && checkValues(Protocol64)){
|
|
//qCWarning(dcHardware) << "64 bit ->" << m_timings << "\n--------------------------";
|
|
changeReading(false);
|
|
emit dataReceived(m_timings);
|
|
}
|
|
m_timings.clear();
|
|
m_pulseProtocolOne = 0;
|
|
m_pulseProtocolTwo = 0;
|
|
changeReading(false);
|
|
}
|
|
|
|
// got sync signal and list is empty...
|
|
if(m_timings.isEmpty() && sync){
|
|
m_timings.append(duration);
|
|
m_pulseProtocolOne = (int)((double)m_timings.first()/31);
|
|
m_pulseProtocolTwo = (int)((double)m_timings.first()/10);
|
|
changeReading(false);
|
|
return;
|
|
}
|
|
|
|
// list not empty and this is a possible value
|
|
if(!m_timings.isEmpty() && checkValue(duration)){
|
|
m_timings.append(duration);
|
|
|
|
// check if it could be a signal -> if we have a sync and 15 valid values
|
|
// set reading true to prevent a collision from own transmitter
|
|
if(m_timings.count() == 20 && (checkValues(Protocol48) || checkValues(Protocol64))){
|
|
changeReading(true);
|
|
}
|
|
|
|
// check if we have already a vallid protocol
|
|
// 1 sync bit + 48 data bit
|
|
if(m_timings.count() == 49 && checkValues(Protocol48)){
|
|
//qCWarning(dcHardware) << "48 bit -> " << m_timings << "\n--------------------------";
|
|
emit dataReceived(m_timings);
|
|
}
|
|
|
|
// 1 sync bit + 64 data bit
|
|
if(m_timings.count() == 65 && checkValues(Protocol64)){
|
|
//qCWarning(dcHardware) << "64 bit -> " << m_timings << "\n--------------------------";
|
|
changeReading(false);
|
|
emit dataReceived(m_timings);
|
|
m_timings.clear();
|
|
}
|
|
}
|
|
}
|