From 4bb982f35bf45a53c28a73c2407644f992c33f28 Mon Sep 17 00:00:00 2001 From: Jan Strobl Date: Thu, 16 Mar 2023 17:01:28 +0000 Subject: [PATCH] Improve cloud4 a bart's rain sensor driver --- src/sensord/bart-rain.cpp | 111 +++++++++++++++++++++++++++++--------- src/sensord/cloud4.cpp | 24 +++++++-- 2 files changed, 107 insertions(+), 28 deletions(-) diff --git a/src/sensord/bart-rain.cpp b/src/sensord/bart-rain.cpp index 784ee1269..2ff34c82f 100644 --- a/src/sensord/bart-rain.cpp +++ b/src/sensord/bart-rain.cpp @@ -38,11 +38,15 @@ namespace rts2sensord class BartRain: public SensorWeather { private: + int ioctlSetRead (int flagsSet, int * flagsRead); + int rain_port; + int flags0, flags1; const char *rain_detector; rts2core::ValueBool *rain; rts2core::ValueInteger *timeoutRain; + rts2core::ValueInteger *timeoutTechnicalProblems; protected: virtual int processOption (int _opt); @@ -82,61 +86,117 @@ int BartRain::init () if (ret) return ret; // init rain detector - int flags; rain_port = open (rain_detector, O_RDWR | O_NOCTTY); if (rain_port == -1) { - logStream (MESSAGE_ERROR) << "Bart::init cannot open " << rain_detector << " " << strerror (errno) << sendLog; + logStream (MESSAGE_ERROR) << "BartRain::init cannot open " << rain_detector << " " << strerror (errno) << sendLog; return -1; } - ret = ioctl (rain_port, TIOCMGET, &flags); + ret = ioctl (rain_port, TIOCMGET, &flags0); if (ret) { - logStream (MESSAGE_ERROR) << "Bart::init cannot get flags: " << strerror (errno) << sendLog; + logStream (MESSAGE_ERROR) << "BartRain::init cannot get flags: " << strerror (errno) << sendLog; return -1; } - flags &= ~TIOCM_DTR; - flags |= TIOCM_RTS; - ret = ioctl (rain_port, TIOCMSET, &flags); + flags0 &= ~TIOCM_DTR; + flags0 |= TIOCM_RTS; + ret = ioctl (rain_port, TIOCMSET, &flags0); if (ret) { - logStream (MESSAGE_ERROR) << "Bart::init cannot set flags: " << strerror (errno) << sendLog; + logStream (MESSAGE_ERROR) << "BartRain::init cannot set flags: " << strerror (errno) << sendLog; return -1; } + + // flags1 are same but reversed logic of DTR/RTS, for testing if the rain sensor is really connected + flags1 = flags0 | TIOCM_DTR; + flags1 &= ~TIOCM_RTS; return 0; } int BartRain::info () { - int flags; + int flags_actual; int ret; - ret = ioctl (rain_port, TIOCMGET, &flags); - #ifdef DEBUG_EXTRA - logStream (MESSAGE_DEBUG) << "Bart::isGoodWeather flags: " << flags << " rain: " << (flags & TIOCM_RI) << sendLog; - #endif - // ioctl failed or it's raining.. - if (ret || !(flags & TIOCM_RI)) + + // first, try the "standard" setup, DTR off, RTS on + ret = ioctlSetRead (flags0, &flags_actual); + if (!ret) { - setWeatherTimeout (timeoutRain->getValueInteger (), "raining"); + if (flags_actual & TIOCM_RI) // it's raining (this also implies the device is really connected!) + { + setWeatherTimeout (timeoutRain->getValueInteger (), "raining"); + if (!rain->getValueBool ()) + { + rain->setValueBool (true); + maskState (WR_RAIN, WR_RAIN, "rain detected from rain sensor"); + setIdleInfoInterval (60); + } + } + else // it isn't raining or the device is not connected (let's find out!) + { + // let's try the "reversed" logic, DTR on, RTS off (if the RING state is reversed as well, device is connected) + ret = ioctlSetRead (flags1, &flags_actual); + if(!ret) + { + if (flags_actual & TIOCM_RI) // in reversed logic this means the sensor is connected and dry! + { + if (rain->getValueBool ()) + { + rain->setValueBool (false); + maskState (WR_RAIN, 0, "no rain"); + setIdleInfoInterval (1); + } + } + else // this means, the sensor device is not physically connected to the serial port + { + setWeatherTimeout (timeoutTechnicalProblems->getValueInteger (), "rain sensor not connected to serial port"); + if (!rain->getValueBool ()) + { + rain->setValueBool (true); + maskState (WR_RAIN, WR_RAIN, "rain sensor not connected to serial port"); + setIdleInfoInterval (60); + } + } + } + } + } + return SensorWeather::info (); +} + + +int BartRain::ioctlSetRead (int flagsSet, int * flagsRead) +{ + int ret; + ret = ioctl (rain_port, TIOCMSET, &flagsSet); + if (ret) + logStream (MESSAGE_ERROR) << "BartRain::ioctlSetRead cannot set flags: " << strerror (errno) << sendLog; + else + { + usleep (USEC_SEC / 5); + ret = ioctl (rain_port, TIOCMGET, flagsRead); + } + + if (ret) + { + setWeatherTimeout (timeoutTechnicalProblems->getValueInteger (), "serial port comm problem"); if (!rain->getValueBool ()) { rain->setValueBool (true); - maskState (WR_RAIN, WR_RAIN, "rain detected from rain sensor"); + maskState (WR_RAIN, WR_RAIN, "serial port comm problem"); setIdleInfoInterval (60); } + return -1; } else { - if (rain->getValueBool ()) - { - rain->setValueBool (false); - maskState (WR_RAIN, 0, "no rain"); - setIdleInfoInterval (1); - } + #ifdef DEBUG_EXTRA + logStream (MESSAGE_DEBUG) << "BartRain::ioctlSetRead flagsRead: " << *flagsRead << ", DTR: " << (*flagsRead & TIOCM_DTR) << ", RTS: " << (*flagsRead & TIOCM_RTS) << ", RING: " << (*flagsRead & TIOCM_RI) << sendLog; + #endif + return 0; } - return SensorWeather::info (); } + BartRain::BartRain (int argc, char **argv):SensorWeather (argc, argv) { rain_detector = "/dev/ttyS0"; @@ -148,6 +208,9 @@ BartRain::BartRain (int argc, char **argv):SensorWeather (argc, argv) createValue (timeoutRain, "timeout_rain", "rain timeout in seconds", false, RTS2_VALUE_WRITABLE); timeoutRain->setValueInteger (3600); + createValue (timeoutTechnicalProblems, "timeout_technical_problems", "technical problems timeout in seconds", false, RTS2_VALUE_WRITABLE); + timeoutTechnicalProblems->setValueInteger (600); + addOption ('f', NULL, 1, "/dev/file for rain detector, default to /dev/ttyS0"); addOption ('r', NULL, 1, "rain timeout in seconds. Default to 3600 seconds (= 60 minutes = 1 hour)"); diff --git a/src/sensord/cloud4.cpp b/src/sensord/cloud4.cpp index b7c4e8950..e40ea72dd 100644 --- a/src/sensord/cloud4.cpp +++ b/src/sensord/cloud4.cpp @@ -125,7 +125,7 @@ int Cloud4::readSensor (bool update) int x = sscanf (buf_start + 6, "%d %f %f %*d %*d *%2hhx", &tno, &temp0, &temp1, &checksum); if (x != 4) { - logStream (MESSAGE_ERROR) << "cannot parse reply from cloud senso, reply was: '" << buf << "', return " << x << sendLog; + logStream (MESSAGE_ERROR) << "cannot parse reply from cloud sensor, reply was: '" << buf << "', return " << x << sendLog; return -1; } } @@ -394,9 +394,25 @@ int Cloud4::info () ret = readSensor (true); if (ret) { - if (getLastInfoTime () > 60) - setWeatherTimeout (60, "cannot read data from device"); - return -1; + // OK, this is because of a partially broken hardware we have now, the response is sometimes wrong... + // Before we will solve this the correct way, let's use this hotfix... It isn't a bad thing anyway...? + // We don't need to solve potential errors in other calls of this function, as they are all related to heating - and the heating is being switched of automatically by the device's internal timer. + int retryAttempt; + for ( retryAttempt = 0; retryAttempt < 2; retryAttempt ++) + { + sleep (3); + mrakConn->flushPortIO (); + logStream (MESSAGE_ERROR) << "There was a problem in readSensor (), retrying..." << sendLog; + ret = readSensor (true); + if (!ret) + break; + } + if (retryAttempt >= 2) + { + if (getLastInfoTime () > 60) + setWeatherTimeout (60, "cannot read data from device"); + return -1; + } } if (tempDiff->getNumMes () >= numVal->getValueInteger ()) {