SHT41 bug resolved. It now logs reading failures.
This commit is contained in:
parent
d3514f7d2b
commit
6c1941cc80
|
|
@ -28,6 +28,11 @@ public:
|
||||||
bool writeRead(const std::vector<uint8_t>& tx, std::vector<uint8_t>& rx);
|
bool writeRead(const std::vector<uint8_t>& tx, std::vector<uint8_t>& rx);
|
||||||
bool write(const std::vector<uint8_t>& tx);
|
bool write(const std::vector<uint8_t>& tx);
|
||||||
|
|
||||||
|
// For diagnostics: what this bus is actually pointed at. A silent sensor is
|
||||||
|
// almost always the wrong bus or address, so error messages should name both.
|
||||||
|
const std::string& device() const { return device_; }
|
||||||
|
uint8_t address() const { return addr_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string device_;
|
std::string device_;
|
||||||
uint8_t addr_;
|
uint8_t addr_;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "fgc/sensors/Sht41Protocol.h"
|
#include "fgc/sensors/Sht41Protocol.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <ios>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
@ -36,11 +37,37 @@ struct Sht41EnvSensor::Impl {
|
||||||
EnvSample latest;
|
EnvSample latest;
|
||||||
clock::time_point last_ok{};
|
clock::time_point last_ok{};
|
||||||
|
|
||||||
|
// Consecutive failed reads. The transfers run every `period` forever, so the
|
||||||
|
// failure is logged on the FIRST one only: a wrong bus would otherwise print
|
||||||
|
// the same line every couple of seconds for the life of the process. Reset on
|
||||||
|
// a good read, which also gives us a recovery message.
|
||||||
|
long long fail_streak = 0;
|
||||||
|
|
||||||
|
// A silent sensor is nearly always the wrong bus or address, and neither
|
||||||
|
// open() nor the I2C_SLAVE ioctl can tell you that - the ioctl only records
|
||||||
|
// the target address, it never probes. This is the first point where the
|
||||||
|
// absence of a device is actually observable, so it is where it gets said.
|
||||||
|
void reportFailure(const char* what) {
|
||||||
|
if (fail_streak++ > 0) return;
|
||||||
|
LOG_ERROR << "SHT41: " << what << " at address 0x" << std::hex
|
||||||
|
<< static_cast<int>(bus.address()) << std::dec << " on " << bus.device()
|
||||||
|
<< " - check [Env] i2c_device/i2c_addr and the wiring"
|
||||||
|
<< " (probe with: i2cdetect -l, then i2ctransfer -y <bus> w1@0x"
|
||||||
|
<< std::hex << static_cast<int>(bus.address()) << std::dec << " 0x89)";
|
||||||
|
LOG_ERROR << "SHT41: further read failures will not be logged until it responds";
|
||||||
|
}
|
||||||
|
|
||||||
void readOnce() {
|
void readOnce() {
|
||||||
if (!bus.write({kSht41CmdMeasureHighPrec})) return;
|
if (!bus.write({kSht41CmdMeasureHighPrec})) {
|
||||||
|
reportFailure("no response to the measure command");
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::this_thread::sleep_for(kConversionDelay);
|
std::this_thread::sleep_for(kConversionDelay);
|
||||||
std::vector<uint8_t> rx(kSht41ResponseBytes);
|
std::vector<uint8_t> rx(kSht41ResponseBytes);
|
||||||
if (!bus.writeRead({}, rx)) return;
|
if (!bus.writeRead({}, rx)) {
|
||||||
|
reportFailure("command acknowledged but no measurement came back");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto reading = decodeSht41Measurement(rx);
|
auto reading = decodeSht41Measurement(rx);
|
||||||
if (!reading) {
|
if (!reading) {
|
||||||
|
|
@ -48,6 +75,11 @@ struct Sht41EnvSensor::Impl {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fail_streak > 0) {
|
||||||
|
LOG_INFO << "SHT41: responding again after " << fail_streak << " failed read(s)";
|
||||||
|
fail_streak = 0;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
latest.valid = true;
|
latest.valid = true;
|
||||||
latest.temp_c = reading->temp_c;
|
latest.temp_c = reading->temp_c;
|
||||||
|
|
@ -81,7 +113,11 @@ void Sht41EnvSensor::start() {
|
||||||
std::this_thread::sleep_for(kSoftResetSettle);
|
std::this_thread::sleep_for(kSoftResetSettle);
|
||||||
impl_->running = true;
|
impl_->running = true;
|
||||||
impl_->worker = std::thread([this] { impl_->run(); });
|
impl_->worker = std::thread([this] { impl_->run(); });
|
||||||
LOG_INFO << "SHT41 env sensor started";
|
// Deliberately not "started OK": opening the node proves nothing about the
|
||||||
|
// sensor being there. The first read either succeeds quietly or logs why not.
|
||||||
|
LOG_INFO << "SHT41 env sensor polling 0x" << std::hex << static_cast<int>(impl_->bus.address())
|
||||||
|
<< std::dec << " on " << impl_->bus.device() << " every "
|
||||||
|
<< impl_->period.count() << " ms";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sht41EnvSensor::stop() {
|
void Sht41EnvSensor::stop() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue