3 #define _TWR_SGPC3_DELAY_RUN 30
4 #define _TWR_SGPC3_DELAY_INITIALIZE 500
5 #define _TWR_SGPC3_DELAY_READ_FEATURE_SET 30
6 #define _TWR_SGPC3_DELAY_SET_POWER_MODE 30
7 #define _TWR_SGPC3_DELAY_INIT_AIR_QUALITY 30
8 #define _TWR_SGPC3_DELAY_SET_HUMIDITY 30
9 #define _TWR_SGPC3_DELAY_MEASURE_AIR_QUALITY 30
10 #define _TWR_SGPC3_DELAY_READ_AIR_QUALITY 150
12 static void _twr_sgpc3_task_interval(
void *param);
14 static void _twr_sgpc3_task_measure(
void *param);
16 static uint8_t _twr_sgpc3_calculate_crc(uint8_t *buffer,
size_t length);
20 memset(
self, 0,
sizeof(*
self));
22 self->_i2c_channel = i2c_channel;
23 self->_i2c_address = i2c_address;
28 self->_tick_ready = _TWR_SGPC3_DELAY_RUN;
42 self->_event_handler = event_handler;
43 self->_event_param = event_param;
48 self->_update_interval = interval;
64 if (self->_event_handler == NULL)
69 if (self->_hit_error && !self->_measurement_valid)
73 else if (self->_measurement_valid)
83 if (!self->_measurement_valid)
95 if (t_celsius == NULL || rh_percentage == NULL)
102 double t = *t_celsius;
103 double rh = *rh_percentage;
104 double pws = 611.2 * exp(17.67 * t / (243.5 + t));
105 double pw = pws * rh / 100.0;
106 double ah = 2.165 * pw / (273.15 + t);
108 self->_ah_scaled = ((uint64_t) (ah * 1000.0) * 256 * 16777) >> 24;
113 static void _twr_sgpc3_task_interval(
void *param)
122 static void _twr_sgpc3_task_measure(
void *param)
128 switch (self->_state)
130 case TWR_SGPC3_STATE_ERROR:
132 self->_hit_error =
true;
134 self->_measurement_valid =
false;
136 self->_state = TWR_SGPC3_STATE_INITIALIZE;
142 case TWR_SGPC3_STATE_INITIALIZE:
144 self->_state = TWR_SGPC3_STATE_GET_FEATURE_SET;
148 case TWR_SGPC3_STATE_GET_FEATURE_SET:
150 self->_state = TWR_SGPC3_STATE_ERROR;
152 static const uint8_t buffer[] = { 0x20, 0x2f };
157 transfer.
buffer = (uint8_t *) buffer;
158 transfer.
length =
sizeof(buffer);
165 self->_state = TWR_SGPC3_STATE_READ_FEATURE_SET;
171 case TWR_SGPC3_STATE_SET_POWER_MODE:
173 self->_state = TWR_SGPC3_STATE_ERROR;
181 buffer[4] = _twr_sgpc3_calculate_crc(&buffer[2], 2);
187 transfer.
length =
sizeof(buffer);
194 self->_state = TWR_SGPC3_STATE_READ_FEATURE_SET;
200 case TWR_SGPC3_STATE_READ_FEATURE_SET:
202 self->_state = TWR_SGPC3_STATE_ERROR;
210 transfer.
length =
sizeof(buffer);
217 if (_twr_sgpc3_calculate_crc(&buffer[0], 3) != 0)
222 if (buffer[0] != 0x10 || buffer[1] != 0x06)
227 self->_state = TWR_SGPC3_STATE_INIT_AIR_QUALITY;
233 case TWR_SGPC3_STATE_INIT_AIR_QUALITY:
235 self->_state = TWR_SGPC3_STATE_ERROR;
237 static const uint8_t buffer[] = { 0x20, 0xae };
242 transfer.
buffer = (uint8_t *) buffer;
243 transfer.
length =
sizeof(buffer);
250 self->_state = TWR_SGPC3_STATE_SET_HUMIDITY;
256 case TWR_SGPC3_STATE_SET_HUMIDITY:
258 self->_state = TWR_SGPC3_STATE_ERROR;
264 buffer[2] =
self->_ah_scaled >> 8;
265 buffer[3] =
self->_ah_scaled;
266 buffer[4] = _twr_sgpc3_calculate_crc(&buffer[2], 2);
272 transfer.
length =
sizeof(buffer);
279 self->_state = TWR_SGPC3_STATE_MEASURE_AIR_QUALITY;
287 case TWR_SGPC3_STATE_MEASURE_AIR_QUALITY:
289 self->_state = TWR_SGPC3_STATE_ERROR;
291 static const uint8_t buffer[] = { 0x20, 0x08 };
296 transfer.
buffer = (uint8_t *) buffer;
297 transfer.
length =
sizeof(buffer);
304 self->_state = TWR_SGPC3_STATE_READ_AIR_QUALITY;
310 case TWR_SGPC3_STATE_READ_AIR_QUALITY:
312 self->_state = TWR_SGPC3_STATE_ERROR;
320 transfer.
length =
sizeof(buffer);
327 if (_twr_sgpc3_calculate_crc(&buffer[0], 3) != 0)
332 self->_tvoc = (buffer[0] << 8) | buffer[1];
334 self->_measurement_valid =
true;
336 self->_state = TWR_SGPC3_STATE_SET_HUMIDITY;
344 self->_state = TWR_SGPC3_STATE_ERROR;
351 static uint8_t _twr_sgpc3_calculate_crc(uint8_t *buffer,
size_t length)
355 for (
size_t i = 0; i < length; i++)
359 for (
int j = 0; j < 8; j++)
361 if ((crc & 0x80) != 0)
363 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_sgpc3_event_t
Callback events.
void twr_sgpc3_set_update_interval(twr_sgpc3_t *self, twr_tick_t interval)
Set measurement interval.
float twr_sgpc3_set_compensation(twr_sgpc3_t *self, float *t_celsius, float *rh_percentage)
Set sensor compensation (absolute humidity is calculated from temperature and relative humidity)
bool twr_sgpc3_measure(twr_sgpc3_t *self)
Start measurement manually.
void twr_sgpc3_deinit(twr_sgpc3_t *self)
Deinitialize SGPC3.
bool twr_sgpc3_get_tvoc_ppb(twr_sgpc3_t *self, uint16_t *ppb)
Get measured TVOC in ppb (parts per billion)
void twr_sgpc3_init(twr_sgpc3_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize SGPC3.
void twr_sgpc3_set_event_handler(twr_sgpc3_t *self, void(*event_handler)(twr_sgpc3_t *, twr_sgpc3_event_t, void *), void *event_param)
Set callback function.
struct twr_sgpc3_t twr_sgpc3_t
SGPC3 instance.
@ TWR_SGPC3_EVENT_UPDATE
Update event.
@ TWR_SGPC3_EVENT_ERROR
Error 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.