I2C reclock guard - avoid gazillion calls to reclock on SENXX sensors (#11412)

* Add SEN6X

* Adds new SENXX class for SEN5X and SEN6X
* Adds CO2 sensor calibration class to be shared among othre CO2 sensors

* Make existing CO2 sensor draw from CO2Sensor class

* Minor coment for CO2 sensor class

* Move away from getRTC in SENXX class to keep track of time changes.

* Change all sensors to millis for tracking time, instead of using getRTC

* Add comments regarding VOC state

* Avoid storing non-valid RTC

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Avoid CO2 sensor warm-up time to be below PM measured started

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Fix limits in CO2 sensor calibration

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Add pragma once on headers

* Avoid non-working ASC commands

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Fix data poll

* Move pm measure started before warmup check

* Make cleaning non-blocking

* Restore previous state if cleaning fails. Fix data ready condition.

* Fix CO2 sensor checks for calibration

* Add ReClockI2C guard to simplify calls to Reclock. Make SENXX calls to reclock outside of readBuffer, to avoid bizillion calls

* Add new reClockGuard to all sensor classes that require it

* Make clock guard store values on each construction and restore them directly

* Reduce log messages

* Update ADS1X15 to new guard

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
oscgonfer
2026-08-16 11:58:59 +00:00
committed by GitHub
co-authored by coderabbitai[bot]
parent bca7c0b480
commit c773049b1d
10 changed files with 126 additions and 232 deletions
+37 -20
View File
@@ -13,7 +13,8 @@
https://github.com/sandeepmistry/arduino-nRF5/blob/master/libraries/Wire/Wire.h#L50
https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60
https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103
For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes)
For cases when I2C speed is different to the ones defined by sensors
(see defines in sensor classes)
we need to reclock I2C and set it back to the previous established speed.
Only for cases where we can know it (ESP32 or known screen) we can do this.
*/
@@ -27,10 +28,16 @@ class ReClockI2C
{
this->i2cBus = i2cBus;
this->port = port;
this->previousClock = 0;
}
bool setClock(uint32_t desiredClock)
// Sets the I2C clock to desiredClock and returns whatever clock was active
// beforehand, so the caller can hand it back to restoreClock() later. The
// previous clock is returned rather than stored on this object, so callers
// that nest calls (see ReClockI2CGuard) each keep their own restoration
// value instead of clobbering a single shared one.
// Returns 0 if the clock was already at desiredClock, or if the previous
// clock couldn't be determined - in both cases there's nothing to restore.
uint32_t setClock(uint32_t desiredClock)
{
uint32_t currentClock = this->getClock();
@@ -41,36 +48,27 @@ class ReClockI2C
if (currentClock != desiredClock) {
LOG_TRACE("Changing I2C clock to %uHz", desiredClock);
this->i2cBus->setClock(desiredClock);
// If the clock is 0Hz, we still store it
// We'll check in restoreClock function
setPreviousClock(currentClock);
LOG_TRACE("Stored previous clock I2C clock: %uHz", this->previousClock);
return true;
LOG_TRACE("Previous I2C clock: %uHz", currentClock);
return currentClock;
}
LOG_TRACE("I2C clock was already %uHz. Skipping", desiredClock);
setPreviousClock(0);
return false;
return 0;
}
bool restoreClock()
void restoreClock(uint32_t previousClock)
{
if (this->previousClock) {
LOG_TRACE("Restoring I2C clock to %uHz", this->previousClock);
i2cBus->setClock(this->previousClock);
setPreviousClock(0);
return true;
if (previousClock) {
LOG_TRACE("Restoring I2C clock to %uHz", previousClock);
i2cBus->setClock(previousClock);
return;
}
LOG_TRACE("I2C clock was unknown. Not restored");
return false;
}
private:
TwoWire *i2cBus{};
ScanI2C::I2CPort port{};
uint32_t previousClock = 0;
void setPreviousClock(uint32_t clock) { this->previousClock = clock; }
uint32_t getClock()
{
@@ -95,4 +93,23 @@ class ReClockI2C
}
};
/* Helper for ReClockI2C: sets the clock on construction and restores it on
destruction, so a caller with multiple early-return paths doesn't need to
remember to call restoreClock() on each one.
*/
class ReClockI2CGuard
{
public:
ReClockI2CGuard(ReClockI2C &reClock, uint32_t desiredClock) : reClock(reClock), previousClock(reClock.setClock(desiredClock))
{
}
~ReClockI2CGuard() { reClock.restoreClock(previousClock); }
ReClockI2CGuard(const ReClockI2CGuard &) = delete;
ReClockI2CGuard &operator=(const ReClockI2CGuard &) = delete;
private:
ReClockI2C &reClock;
uint32_t previousClock;
};
#endif