Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/components/i2c/WipperSnapper_I2C.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,7 @@ bool WipperSnapper_Component_I2C::initI2CDevice(
_drivers_out.push_back(_ssd1306);
WS_DEBUG_PRINTLN("SSD1306 display initialized Successfully!");
} else {
WS_DEBUG_PRINTLN("ERROR: I2C device type not found!")
WS_DEBUG_PRINTLN("ERROR: I2C device type not found!");
_busStatusResponse =
wippersnapper_i2c_v1_BusResponse_BUS_RESPONSE_UNSUPPORTED_SENSOR;
return false;
Expand Down Expand Up @@ -1347,13 +1347,20 @@ void WipperSnapper_Component_I2C::update() {
msgi2cResponse.which_payload =
wippersnapper_signal_v1_I2CResponse_resp_i2c_device_event_tag;

// one fast pass for all drivers every update() call
for (auto *drv : drivers) {
if (drv)
drv->fastTick();
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use auto here or create a loop. It is redundant and adds a performance overhead for what should be a tight loop.

Instead, try calling drv->fastTick() when we are looping through the vectors below. Since fastTick is virtual, and the vect. of drivers exists, you dont need to check for nullptr either.

long curTime;
bool sensorsReturningFalse = true;
int retries = 3;

while (sensorsReturningFalse && retries > 0) {
sensorsReturningFalse = false;
retries--;
curTime = millis();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would curTime be modified here?


std::vector<WipperSnapper_I2C_Driver *>::iterator iter, end;
for (iter = drivers.begin(), end = drivers.end(); iter != end; ++iter) {
Expand Down
18 changes: 16 additions & 2 deletions src/components/i2c/drivers/WipperSnapper_I2C_Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class WipperSnapper_I2C_Driver {
public:
/*******************************************************************************/
/*!
@brief Instanciates an I2C sensor.
@brief Instanctiates an I2C sensor.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no middle c

@param i2c
The I2C hardware interface, default is Wire.
@param sensorAddress
Expand All @@ -53,6 +53,20 @@ class WipperSnapper_I2C_Driver {
/*******************************************************************************/
virtual ~WipperSnapper_I2C_Driver() {}

/*******************************************************************************/
/*!
@brief Per-update background hook for drivers that need faster internal
sampling than the user publish interval.
Default is a no-op; override in concrete drivers (e.g.,
SGP30/40) to maintain required ~1 Hz reads and accumulate/condition values
for later publish.
@note Call site: WipperSnapper_Component_I2C::update() will invoke
this once per loop for each driver. Implementations must be
non-blocking (do not delay); use millis()-based timing.
*/
/*******************************************************************************/
virtual void fastTick() {}

/*******************************************************************************/
/*!
@brief Initializes the I2C sensor and begins I2C.
Expand Down Expand Up @@ -1312,7 +1326,7 @@ class WipperSnapper_I2C_Driver {
@brief Updates the properties of a proximity sensor.
@param period
The time interval at which to return new data from the
proimity sensor.
proximity sensor.
*/
/*******************************************************************************/
virtual void updateSensorProximity(float period) {
Expand Down
97 changes: 82 additions & 15 deletions src/components/i2c/drivers/WipperSnapper_I2C_Driver_SGP30.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ class WipperSnapper_I2C_Driver_SGP30 : public WipperSnapper_I2C_Driver {
: WipperSnapper_I2C_Driver(i2c, sensorAddress) {
_i2c = i2c;
_sensorAddress = sensorAddress;
_sgp30 = nullptr;
}

/*******************************************************************************/
/*!
@brief Destructor for an SGP30 sensor.
*/
/*******************************************************************************/
~WipperSnapper_I2C_Driver_SGP30() {
~WipperSnapper_I2C_Driver_SGP30() override {
// Called when a SGP30 component is deleted.
delete _sgp30;
if (_sgp30) {
delete _sgp30;
_sgp30 = nullptr;
}
}

/*******************************************************************************/
Expand All @@ -44,27 +48,90 @@ class WipperSnapper_I2C_Driver_SGP30 : public WipperSnapper_I2C_Driver {
/*******************************************************************************/
bool begin() {
_sgp30 = new Adafruit_SGP30();
return _sgp30->begin(_i2c);
if (!_sgp30->begin(_i2c)) {
delete _sgp30; // avoid leak on init failure
_sgp30 = nullptr;
return false;
}
_sgp30->IAQinit(); // start IAQ algorithm
_lastFastMs = millis(); // reset fast sampler
_n = _eco2Sum = _tvocSum = 0; // clear accumulators
return true;
}

bool getEventECO2(sensors_event_t *senseEvent) {
bool result = _sgp30->IAQmeasure();
if (result) {
senseEvent->eCO2 = _sgp30->eCO2;
bool getEventECO2(sensors_event_t *senseEvent) override {
if (!_sgp30)
return false;
if (_n > 0) {
senseEvent->eCO2 = (uint16_t)(_eco2Sum / _n);
_eco2Sum = 0;
_tvocSum = 0;
_n = 0;
return true;
}
if (_sgp30->IAQmeasure()) {
senseEvent->eCO2 = (uint16_t)_sgp30->eCO2;
return true;
}
return result;
return false;
}

bool getEventTVOC(sensors_event_t *senseEvent) {
bool result = _sgp30->IAQmeasure();
if (result) {
senseEvent->tvoc = _sgp30->TVOC;
bool getEventTVOC(sensors_event_t *senseEvent) override {
if (!_sgp30)
return false;
if (_n > 0) {
senseEvent->tvoc = (uint16_t)(_tvocSum / _n);
_eco2Sum = 0;
_tvocSum = 0;
_n = 0;
return true;
}
if (_sgp30->IAQmeasure()) {
senseEvent->tvoc = (uint16_t)_sgp30->TVOC;
return true;
}
return false;
}

void fastTick() override {
if (!iaqEnabled())
return; // nothing enabled, save cycles
uint32_t now = millis();
if (now - _lastFastMs >= 1000) { // ~1 Hz cadence
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1000 is a magic number, please #define it.

if (_sgp30 && _sgp30->IAQmeasure()) {
_eco2Sum += _sgp30->eCO2; // uint16_t in library
_tvocSum += _sgp30->TVOC; // uint16_t in library
_n++;
}
_lastFastMs = now;
}
return result;
}

protected:
Adafruit_SGP30 *_sgp30; ///< Pointer to SGP30 temperature sensor object
Adafruit_SGP30 *_sgp30; ///< Pointer to SGP30 sensor object

/** Millis timestamp of last 1 Hz background read. */
uint32_t _lastFastMs = 0;

/** Number of samples accumulated since last publish. */
uint32_t _n = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change to _sample_num or something more descriptive


/** Running sum of eCO2 samples for averaging. */
uint32_t _eco2Sum = 0;

/** Running sum of TVOC samples for averaging. */
uint32_t _tvocSum = 0;

/*******************************************************************************/
/*!
@brief Returns whether IAQ background sampling should be active.
@return True if either eCO2 or TVOC metrics are configured to publish.
*/
/*******************************************************************************/
inline bool iaqEnabled() {
// Enable IAQ background reads if either metric is requested
return (getSensorECO2Period() > 0) || (getSensorTVOCPeriod() > 0);
}
};

#endif // WipperSnapper_I2C_Driver_SGP30
#endif // WipperSnapper_I2C_Driver_SGP30
100 changes: 90 additions & 10 deletions src/components/i2c/drivers/WipperSnapper_I2C_Driver_SGP40.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ class WipperSnapper_I2C_Driver_SGP40 : public WipperSnapper_I2C_Driver {
: WipperSnapper_I2C_Driver(i2c, sensorAddress) {
_i2c = i2c;
_sensorAddress = sensorAddress;
_sgp40 = nullptr;
}

/*******************************************************************************/
/*!
@brief Destructor for an SGP40 sensor driver.
Cleans up and deallocates the underlying Adafruit_SGP40 object
when the driver is destroyed.
*/
/*******************************************************************************/
~WipperSnapper_I2C_Driver_SGP40() override {
if (_sgp40) {
delete _sgp40;
_sgp40 = nullptr;
}
}

/*******************************************************************************/
Expand All @@ -50,12 +65,15 @@ class WipperSnapper_I2C_Driver_SGP40 : public WipperSnapper_I2C_Driver {
/*******************************************************************************/
bool begin() {
_sgp40 = new Adafruit_SGP40();
if (!_sgp40->begin(_i2c)) {
if (!_sgp40 || !_sgp40->begin(_i2c)) {
delete _sgp40;
_sgp40 = nullptr;
return false;
}

// TODO: update to use setCalibration() and pass in temp/humidity

_lastFastMs = millis();
_n = 0;
_vocSum = 0.0f;
_rawSum = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move these to the constructor

return true;
}

Expand All @@ -64,11 +82,20 @@ class WipperSnapper_I2C_Driver_SGP40 : public WipperSnapper_I2C_Driver {
@brief Gets the sensor's current raw unprocessed value.
@param rawEvent
Pointer to an Adafruit_Sensor event.
@returns True if the temperature was obtained successfully, False
@returns True if the raw value was obtained successfully, False
otherwise.
*/
/*******************************************************************************/
bool getEventRaw(sensors_event_t *rawEvent) {
bool getEventRaw(sensors_event_t *rawEvent) override {
if (!_sgp40)
return false;
if (_n > 0) {
rawEvent->data[0] = (float)_rawSum / (float)_n;
_rawSum = 0;
_vocSum = 0.0f;
_n = 0;
return true;
}
rawEvent->data[0] = (float)_sgp40->measureRaw();
return true;
}
Expand All @@ -82,13 +109,66 @@ class WipperSnapper_I2C_Driver_SGP40 : public WipperSnapper_I2C_Driver {
otherwise.
*/
/*******************************************************************************/
bool getEventVOCIndex(sensors_event_t *vocIndexEvent) {
vocIndexEvent->voc_index = (float)_sgp40->measureVocIndex();
bool getEventVOCIndex(sensors_event_t *vocIndexEvent) override {
if (!_sgp40)
return false;
if (_n > 0) {
vocIndexEvent->voc_index = (uint16_t)(_vocSum / (float)_n);
_rawSum = 0;
_vocSum = 0.0f;
_n = 0;
return true;
}
vocIndexEvent->voc_index = (uint16_t)_sgp40->measureVocIndex();
return true;
}

/*******************************************************************************/
/*!
@brief Performs background sampling for the SGP40.
Runs once per second to accumulate raw and VOC index values
for later averaging in getEventRaw() and getEventVOCIndex().
*/
/*******************************************************************************/
void fastTick() override {
if (!_sgp40)
return;
if (!vocEnabled())
return;

uint32_t now = millis();
if (now - _lastFastMs >= 1000) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1000 is a magic number, please #define what it is at the top of this header.

_rawSum += _sgp40->measureRaw();
_vocSum += _sgp40->measureVocIndex();
_n++;
_lastFastMs = now;
}
}

protected:
Adafruit_SGP40 *_sgp40; ///< SEN5X driver object
Adafruit_SGP40 *_sgp40; ///< SGP40

/** Millis timestamp of last 1 Hz background read. */
uint32_t _lastFastMs = 0;

/** Number of samples accumulated since last publish. */
uint32_t _n = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_num_samples


/** Running sum of VOC index samples for averaging. */
float _vocSum = 0.0f;

/** Running sum of raw samples for averaging. */
uint32_t _rawSum = 0;

/*******************************************************************************/
/*!
@brief Returns whether VOC background sampling should be active.
@return True if either VOC Index or raw value is configured to publish.
*/
/*******************************************************************************/
inline bool vocEnabled() {
return (getSensorVOCIndexPeriod() > 0) || (getSensorRawPeriod() > 0);
}
};

#endif // WipperSnapper_I2C_Driver_SEN5X
#endif // WipperSnapper_I2C_Driver_SGP40_H
Loading