3 #define _TWR_SGP30_DELAY_RUN 100
4 #define _TWR_SGP30_DELAY_INITIALIZE 500
5 #define _TWR_SGP30_DELAY_READ_FEATURE_SET 30
6 #define _TWR_SGP30_DELAY_INIT_AIR_QUALITY 30
7 #define _TWR_SGP30_DELAY_SET_HUMIDITY 30
8 #define _TWR_SGP30_DELAY_MEASURE_AIR_QUALITY 30
9 #define _TWR_SGP30_DELAY_READ_AIR_QUALITY 30
11 static void _twr_sgp30_task_interval(
void *param);
13 static void _twr_sgp30_task_measure(
void *param);
15 static uint8_t _twr_sgp30_calculate_crc(uint8_t *buffer,
size_t length);
19 memset(
self, 0,
sizeof(*
self));
21 self->_i2c_channel = i2c_channel;
22 self->_i2c_address = i2c_address;
27 self->_tick_ready = _TWR_SGP30_DELAY_RUN;
41 self->_event_handler = event_handler;
42 self->_event_param = event_param;
47 self->_update_interval = interval;
63 if (self->_event_handler == NULL)
68 if (self->_hit_error && !self->_measurement_valid)
72 else if (self->_measurement_valid)
82 if (!self->_measurement_valid)
94 if (!self->_measurement_valid)
106 if (t_celsius == NULL || rh_percentage == NULL)
108 self->_ah_scaled = 0;
113 double t = *t_celsius;
114 double rh = *rh_percentage;
115 double pws = 611.2 * exp(17.67 * t / (243.5 + t));
116 double pw = pws * rh / 100.0;
117 double ah = 2.165 * pw / (273.15 + t);
119 self->_ah_scaled = ((uint64_t) (ah * 1000.0) * 256 * 16777) >> 24;
124 static void _twr_sgp30_task_interval(
void *param)
133 static void _twr_sgp30_task_measure(
void *param)
139 switch (self->_state)
141 case TWR_SGP30_STATE_ERROR:
143 self->_hit_error =
true;
145 self->_measurement_valid =
false;
147 self->_state = TWR_SGP30_STATE_INITIALIZE;
153 case TWR_SGP30_STATE_INITIALIZE:
155 self->_state = TWR_SGP30_STATE_GET_FEATURE_SET;
159 case TWR_SGP30_STATE_GET_FEATURE_SET:
161 self->_state = TWR_SGP30_STATE_ERROR;
163 static const uint8_t buffer[] = { 0x20, 0x2f };
168 transfer.
buffer = (uint8_t *) buffer;
169 transfer.
length =
sizeof(buffer);
176 self->_state = TWR_SGP30_STATE_READ_FEATURE_SET;
182 case TWR_SGP30_STATE_READ_FEATURE_SET:
184 self->_state = TWR_SGP30_STATE_ERROR;
192 transfer.
length =
sizeof(buffer);
199 if (_twr_sgp30_calculate_crc(&buffer[0], 3) != 0)
204 if (buffer[0] != 0x00 || (buffer[1] != 0x20 && buffer[1] != 0x22))
209 self->_state = TWR_SGP30_STATE_INIT_AIR_QUALITY;
215 case TWR_SGP30_STATE_INIT_AIR_QUALITY:
217 self->_state = TWR_SGP30_STATE_ERROR;
219 static const uint8_t buffer[] = { 0x20, 0x03 };
224 transfer.
buffer = (uint8_t *) buffer;
225 transfer.
length =
sizeof(buffer);
232 self->_state = TWR_SGP30_STATE_SET_HUMIDITY;
238 case TWR_SGP30_STATE_SET_HUMIDITY:
240 self->_state = TWR_SGP30_STATE_ERROR;
246 buffer[2] =
self->_ah_scaled >> 8;
247 buffer[3] =
self->_ah_scaled;
248 buffer[4] = _twr_sgp30_calculate_crc(&buffer[2], 2);
254 transfer.
length =
sizeof(buffer);
261 self->_state = TWR_SGP30_STATE_MEASURE_AIR_QUALITY;
269 case TWR_SGP30_STATE_MEASURE_AIR_QUALITY:
271 self->_state = TWR_SGP30_STATE_ERROR;
273 static const uint8_t buffer[] = { 0x20, 0x08 };
278 transfer.
buffer = (uint8_t *) buffer;
279 transfer.
length =
sizeof(buffer);
286 self->_state = TWR_SGP30_STATE_READ_AIR_QUALITY;
292 case TWR_SGP30_STATE_READ_AIR_QUALITY:
294 self->_state = TWR_SGP30_STATE_ERROR;
302 transfer.
length =
sizeof(buffer);
309 if (_twr_sgp30_calculate_crc(&buffer[0], 3) != 0 ||
310 _twr_sgp30_calculate_crc(&buffer[3], 3) != 0)
315 self->_co2eq = (buffer[0] << 8) | buffer[1];
316 self->_tvoc = (buffer[3] << 8) | buffer[4];
318 self->_measurement_valid =
true;
320 self->_state = TWR_SGP30_STATE_SET_HUMIDITY;
328 self->_state = TWR_SGP30_STATE_ERROR;
335 static uint8_t _twr_sgp30_calculate_crc(uint8_t *buffer,
size_t length)
339 for (
size_t i = 0; i < length; i++)
343 for (
int j = 0; j < 8; j++)
345 if ((crc & 0x80) != 0)
347 crc = (crc << 1) ^ 0x31;
void twr_i2c_init(twr_i2c_channel_t channel, twr_i2c_speed_t speed)
Initialize I2C channel.
bool twr_i2c_read(twr_i2c_channel_t channel, const twr_i2c_transfer_t *transfer)
Read from I2C channel.
bool twr_i2c_write(twr_i2c_channel_t channel, const twr_i2c_transfer_t *transfer)
Write to I2C channel.
twr_i2c_channel_t
I2C channels.
@ TWR_I2C_SPEED_100_KHZ
I2C communication speed is 100 kHz.
void twr_scheduler_plan_current_from_now(twr_tick_t tick)
Schedule current task to tick relative from now.
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
void twr_scheduler_plan_current_absolute(twr_tick_t tick)
Schedule current task to absolute tick.
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
void twr_scheduler_unregister(twr_scheduler_task_id_t task_id)
Unregister specified task.
twr_tick_t twr_scheduler_get_spin_tick(void)
Get current tick of spin in which task has been run.
void twr_scheduler_plan_relative(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to tick relative from current spin.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
twr_sgp30_event_t
Callback events.
bool twr_sgp30_measure(twr_sgp30_t *self)
Start measurement manually.
bool twr_sgp30_get_tvoc_ppb(twr_sgp30_t *self, uint16_t *ppb)
Get measured TVOC in ppb (parts per billion)
void twr_sgp30_set_update_interval(twr_sgp30_t *self, twr_tick_t interval)
Set measurement interval.
struct twr_sgp30_t twr_sgp30_t
SGP30 instance.
void twr_sgp30_init(twr_sgp30_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize SGP30.
float twr_sgp30_set_compensation(twr_sgp30_t *self, float *t_celsius, float *rh_percentage)
Set sensor compensation (absolute humidity is calculated from temperature and relative humidity)
void twr_sgp30_deinit(twr_sgp30_t *self)
Deinitialize SGP30.
void twr_sgp30_set_event_handler(twr_sgp30_t *self, void(*event_handler)(twr_sgp30_t *, twr_sgp30_event_t, void *), void *event_param)
Set callback function.
bool twr_sgp30_get_co2eq_ppm(twr_sgp30_t *self, uint16_t *ppm)
Get measured CO2eq in ppm (parts per million)
@ TWR_SGP30_EVENT_ERROR
Error event.
@ TWR_SGP30_EVENT_UPDATE
Update event.
#define TWR_TICK_INFINITY
Maximum timestamp value.
uint64_t twr_tick_t
Timestamp data type.
void * buffer
Pointer to buffer which is being written or read.
uint8_t device_address
7-bit I2C device address
size_t length
Length of buffer which is being written or read.