ruuvi.drivers.c ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
Loading...
Searching...
No Matches
ruuvi_interface_shtcx.c
Go to the documentation of this file.
1
11#if RI_SHTCX_ENABLED || DOXYGEN
12// Ruuvi headers
13#include "ruuvi_driver_error.h"
14#include "ruuvi_driver_sensor.h"
18#include "ruuvi_interface_i2c.h"
20#include "ruuvi_interface_rtc.h"
22
23#include <string.h>
24
30// Sensirion driver.
31#include "shtc1.h"
32#define LOW_POWER_SLEEP_MS_MIN (1000U)
33#define SHTCX_PROBE_RETRIES_MAX (5U)
34
35static inline uint32_t US_TO_MS_ROUNDUP (uint32_t us)
36{
37 return (us / 1000) + 2;
38}
39
41#define RETURN_SUCCESS_ON_VALID(param) do {\
42 if(RD_SENSOR_CFG_DEFAULT == param ||\
43 RD_SENSOR_CFG_MIN == param ||\
44 RD_SENSOR_CFG_MAX == param ||\
45 RD_SENSOR_CFG_NO_CHANGE == param \
46 ) return RD_SUCCESS;\
47 } while(0)
48
50#define VERIFY_SENSOR_SLEEPS() do { \
51 uint8_t MACRO_MODE = 0; \
52 ri_shtcx_mode_get(&MACRO_MODE); \
53 if(RD_SENSOR_CFG_SLEEP != MACRO_MODE) { return RD_ERROR_INVALID_STATE; } \
54 } while(0)
55
56static uint64_t m_tsample;
57static bool m_autorefresh;
58static int32_t m_temperature;
59static int32_t m_humidity;
60static bool m_is_init;
61static const char m_sensor_name[] = "SHTCX";
62
63#define STATUS_OK 0
64#define STATUS_ERR_BAD_DATA (-1)
65#define STATUS_CRC_FAIL (-2)
66#define STATUS_UNKNOWN_DEVICE (-3)
67#define STATUS_WAKEUP_FAILED (-4)
68#define STATUS_SLEEP_FAILED (-5)
69
76static rd_status_t SHTCX_TO_RUUVI_ERROR (const int16_t rslt)
77{
78 if (STATUS_OK == rslt) { return RD_SUCCESS; }
79
81
82 if (STATUS_UNKNOWN_DEVICE == rslt) { err_code = RD_ERROR_NOT_FOUND; }
83 else if (STATUS_ERR_BAD_DATA == rslt) { err_code = RD_ERROR_INVALID_DATA; }
84 else if (STATUS_CRC_FAIL == rslt) { err_code = RD_ERROR_INVALID_DATA; }
85 else if (STATUS_WAKEUP_FAILED == rslt) { err_code = RD_ERROR_INTERNAL; }
86 else if (STATUS_SLEEP_FAILED == rslt) { err_code = RD_ERROR_INTERNAL; }
87
88 return err_code;
89}
90
91rd_status_t ri_shtcx_init (rd_sensor_t * sensor, rd_bus_t bus, uint8_t handle)
92{
93 rd_status_t err_code = RD_SUCCESS;
94
95 if (NULL == sensor)
96 {
97 err_code |= RD_ERROR_NULL;
98 }
99 else if (rd_sensor_is_init (sensor))
100 {
101 err_code |= RD_ERROR_INVALID_STATE;
102 }
103 else
104 {
105 rd_sensor_initialize (sensor);
106 sensor->name = m_sensor_name;
107 uint8_t retries = 0;
108
109 switch (bus)
110 {
111 case RD_BUS_I2C:
112 do
113 {
114 err_code = SHTCX_TO_RUUVI_ERROR (shtc1_probe());
115 retries++;
116 } while ( (RD_ERROR_INVALID_DATA == err_code)
117
118 && (retries < SHTCX_PROBE_RETRIES_MAX));
119
120 break;
121
122 default:
123 err_code |= RD_ERROR_INVALID_PARAM;
124 }
125
126 if (RD_SUCCESS != err_code)
127 {
128 err_code = RD_ERROR_NOT_FOUND;
129 }
130 else
131 {
132 // Sensirion driver delays high-power mode time in any case.
133 // Explicitly entering low-power mode has no effect.
134 shtc1_enable_low_power_mode (0);
135 sensor->init = ri_shtcx_init;
136 sensor->uninit = ri_shtcx_uninit;
143 sensor->dsp_set = ri_shtcx_dsp_set;
144 sensor->dsp_get = ri_shtcx_dsp_get;
145 sensor->mode_set = ri_shtcx_mode_set;
146 sensor->mode_get = ri_shtcx_mode_get;
147 sensor->data_get = ri_shtcx_data_get;
150 sensor->provides.datas.temperature_c = 1;
151 sensor->provides.datas.humidity_rh = 1;
152 err_code |= SHTCX_TO_RUUVI_ERROR (shtc1_sleep());
153 m_tsample = RD_UINT64_INVALID;
154 m_is_init = true;
155 }
156 }
157
158 return err_code;
159}
160
162 rd_bus_t bus, uint8_t handle)
163{
164 if (NULL == sensor) { return RD_ERROR_NULL; }
165
166 rd_status_t err_code = RD_SUCCESS;
167 shtc1_enable_low_power_mode (1);
168 err_code |= SHTCX_TO_RUUVI_ERROR (shtc1_sleep());
169 rd_sensor_uninitialize (sensor);
170 m_tsample = RD_UINT64_INVALID;
171 m_temperature = RD_INT32_INVALID;
172 m_humidity = RD_INT32_INVALID;
173 m_is_init = false;
174 m_autorefresh = false;
175 return err_code;
176}
177
179{
180 if (NULL == samplerate) { return RD_ERROR_NULL; }
181
183 rd_status_t err_code = RD_SUCCESS;
184
185 if (RD_SENSOR_CFG_DEFAULT == *samplerate) { *samplerate = RD_SENSOR_CFG_DEFAULT; }
186 else if (RD_SENSOR_CFG_NO_CHANGE == *samplerate) { *samplerate = RD_SENSOR_CFG_DEFAULT; }
187 else if (RD_SENSOR_CFG_MIN == *samplerate) { *samplerate = RD_SENSOR_CFG_DEFAULT; }
188 else if (RD_SENSOR_CFG_MAX == *samplerate) {*samplerate = RD_SENSOR_CFG_DEFAULT; }
189 else { *samplerate = RD_SENSOR_ERR_NOT_SUPPORTED; err_code |= RD_ERROR_NOT_SUPPORTED; }
190
191 return err_code;
192}
193
195{
196 if (NULL == samplerate) { return RD_ERROR_NULL; }
197
198 *samplerate = RD_SENSOR_CFG_DEFAULT;
199 return RD_SUCCESS;
200}
201
203{
204 if (NULL == resolution) { return RD_ERROR_NULL; }
205
207 uint8_t original = *resolution;
208 *resolution = RD_SENSOR_CFG_DEFAULT;
209 RETURN_SUCCESS_ON_VALID (original);
211}
212
214{
215 if (NULL == resolution) { return RD_ERROR_NULL; }
216
217 *resolution = RD_SENSOR_CFG_DEFAULT;
218 return RD_SUCCESS;
219}
220
222{
223 if (NULL == scale) { return RD_ERROR_NULL; }
224
226 uint8_t original = *scale;
227 *scale = RD_SENSOR_CFG_DEFAULT;
228 RETURN_SUCCESS_ON_VALID (original);
230}
231
233{
234 if (NULL == scale) { return RD_ERROR_NULL; }
235
236 *scale = RD_SENSOR_CFG_DEFAULT;
237 return RD_SUCCESS;
238}
239
240rd_status_t ri_shtcx_dsp_set (uint8_t * dsp, uint8_t * parameter)
241{
242 if (NULL == dsp || NULL == parameter) { return RD_ERROR_NULL; }
243
245
246 // Validate configuration
247 if ( (RD_SENSOR_CFG_DEFAULT != *parameter
248 && RD_SENSOR_CFG_MIN != *parameter
249 && RD_SENSOR_CFG_MAX != *parameter) ||
250 (RD_SENSOR_DSP_LAST != *dsp))
251 {
253 }
254
255 return RD_SUCCESS;
256}
257
258rd_status_t ri_shtcx_dsp_get (uint8_t * dsp, uint8_t * parameter)
259{
260 if (NULL == dsp || NULL == parameter) { return RD_ERROR_NULL; }
261
262 // Only default is available
264 *parameter = RD_SENSOR_CFG_DEFAULT;
265 return RD_SUCCESS;
266}
267
268// Start single on command, mark autorefresh with continuous
270{
271 rd_status_t err_code = RD_SUCCESS;
272
273 if (NULL == mode)
274 {
275 err_code |= RD_ERROR_NULL;
276 }
277 // Enter sleep by default and by explicit sleep commmand
278 else if ( (RD_SENSOR_CFG_SLEEP == *mode) || (RD_SENSOR_CFG_DEFAULT == *mode))
279 {
280 m_autorefresh = false;
281 *mode = RD_SENSOR_CFG_SLEEP;
282 err_code |= SHTCX_TO_RUUVI_ERROR (shtc1_sleep());
283 }
284 else if (RD_SENSOR_CFG_SINGLE == *mode)
285 {
286 // Do nothing if sensor is in continuous mode
287 uint8_t current_mode;
288 ri_shtcx_mode_get (&current_mode);
289
290 if (RD_SENSOR_CFG_CONTINUOUS == current_mode)
291 {
294 }
295
296 // Enter sleep after measurement
297 m_autorefresh = false;
298 *mode = RD_SENSOR_CFG_SLEEP;
299 m_tsample = rd_sensor_timestamp_get();
300 err_code |= SHTCX_TO_RUUVI_ERROR (shtc1_wake_up());
302 err_code |= SHTCX_TO_RUUVI_ERROR (shtc1_measure_blocking_read (&m_temperature,
303 &m_humidity));
304 err_code |= SHTCX_TO_RUUVI_ERROR (shtc1_sleep());
305 return err_code;
306 }
307 else if (RD_SENSOR_CFG_CONTINUOUS == *mode)
308 {
309 m_autorefresh = true;
310 err_code |= RD_SUCCESS;
311 }
312 else
313 {
314 err_code |= RD_ERROR_INVALID_PARAM;
315 }
316
317 return err_code;
318}
319
321{
322 if (NULL == mode) { return RD_ERROR_NULL; }
323
324 if (m_autorefresh)
325 {
327 }
328
329 if (!m_autorefresh)
330 {
331 *mode = RD_SENSOR_CFG_SLEEP;
332 }
333
334 return RD_SUCCESS;
335}
336
338{
339 rd_status_t err_code = RD_SUCCESS;
340
341 if (NULL == p_data)
342 {
343 err_code |= RD_ERROR_NULL;
344 }
345 else
346 {
347 if (m_autorefresh)
348 {
349 // Set autorefresh to false to take a single sample
350 m_autorefresh = false;
351 uint8_t mode = RD_SENSOR_CFG_SINGLE;
352 err_code |= ri_shtcx_mode_set (&mode);
353 // Restore autorefresh
354 m_autorefresh = true;
355 }
356
357 if ( (RD_SUCCESS == err_code) && (RD_UINT64_INVALID != m_tsample))
358 {
359 rd_sensor_data_t d_environmental;
360 rd_sensor_data_fields_t env_fields = {.bitfield = 0};
361 float env_values[2];
362 env_values[0] = m_humidity / 1000.0f;
363 env_values[1] = m_temperature / 1000.0f;
364 env_fields.datas.humidity_rh = 1;
365 env_fields.datas.temperature_c = 1;
366 d_environmental.data = env_values;
367 d_environmental.valid = env_fields;
368 d_environmental.fields = env_fields;
369 d_environmental.timestamp_ms = m_tsample;
371 &d_environmental,
372 p_data->fields);
373 }
374 }
375
376 return err_code;
377}
378
379// Ceedling mocks sensirion functions
380#ifndef CEEDLING
381
395void sensirion_sleep_usec (uint32_t useconds)
396{
397 if (useconds < LOW_POWER_SLEEP_MS_MIN)
398 {
399 ri_delay_us (useconds);
400 }
401 else
402 {
403 ri_delay_ms (US_TO_MS_ROUNDUP (useconds));
404 }
405}
406#endif
407
410#endif // RI_SHTCX_ENABLED || DOXYGEN
#define RD_ERROR_INVALID_PARAM
Invalid Parameter.
#define RD_ERROR_NULL
Null Pointer.
uint32_t rd_status_t
bitfield for representing errors
#define RD_ERROR_INVALID_DATA
Invalid Data.
#define RD_INT32_INVALID
Signal that value should not be used.
#define RD_ERROR_NOT_SUPPORTED
Not supported.
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_NOT_FOUND
Not found.
#define RD_UINT64_INVALID
Signal that value should not be used.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
#define RD_ERROR_INTERNAL
Internal Error.
#define LOW_POWER_SLEEP_MS_MIN
#define STATUS_OK
SHTC driver ok.
rd_status_t ri_shtcx_uninit(rd_sensor_t *sensor, rd_bus_t bus, uint8_t handle)
rd_sensor_init_fp
rd_status_t ri_shtcx_scale_set(uint8_t *scale)
rd_sensor_setup_fp
rd_status_t ri_shtcx_samplerate_set(uint8_t *samplerate)
rd_sensor_setup_fp
#define RETURN_SUCCESS_ON_VALID(param)
Macro for checking "ignored" parameters NO_CHANGE, MIN, MAX, DEFAULT.
rd_status_t ri_shtcx_dsp_get(uint8_t *dsp, uint8_t *parameter)
#define STATUS_UNKNOWN_DEVICE
Invalid WHOAMI.
#define STATUS_SLEEP_FAILED
Device didn't go to sleep.
void sensirion_sleep_usec(uint32_t useconds)
Implement sleep function for SHTC driver.
rd_status_t ri_shtcx_dsp_set(uint8_t *dsp, uint8_t *parameter)
rd_sensor_setup_fp
#define STATUS_WAKEUP_FAILED
Device didn't wake up.
#define STATUS_CRC_FAIL
SHTC driver CRC error.
rd_status_t ri_shtcx_init(rd_sensor_t *sensor, rd_bus_t bus, uint8_t handle)
rd_sensor_init_fp
rd_status_t ri_shtcx_scale_get(uint8_t *scale)
rd_sensor_setup_fp
rd_status_t ri_shtcx_data_get(rd_sensor_data_t *const p_data)
rd_sensor_data_fp
#define VERIFY_SENSOR_SLEEPS()
Macro for checking that sensor is in sleep mode before configuration.
#define STATUS_ERR_BAD_DATA
SHTC driver data invald.
rd_status_t ri_shtcx_samplerate_get(uint8_t *samplerate)
rd_sensor_setup_fp
rd_status_t ri_shtcx_resolution_get(uint8_t *resolution)
rd_sensor_setup_fp
#define SHTCX_PROBE_RETRIES_MAX
rd_status_t ri_shtcx_mode_get(uint8_t *mode)
rd_sensor_setup_fp
rd_status_t ri_shtcx_mode_set(uint8_t *mode)
rd_sensor_setup_fp
rd_status_t ri_shtcx_resolution_set(uint8_t *resolution)
rd_sensor_setup_fp
#define RD_SENSOR_DSP_LAST
Return last value from sensor. Parameter: No effect. Use default.
#define RD_SENSOR_ERR_NOT_SUPPORTED
Error code, given parameter is not supported by sensor.
bool rd_sensor_is_init(const rd_sensor_t *const sensor)
Check if given sensor structure is already initialized.
#define RD_SENSOR_CFG_SLEEP
Sensor should go to sleep immediately.
#define RD_SENSOR_CFG_MAX
Configure largest supported and implemented value.
#define RD_SENSOR_CFG_DEFAULT
Default value, always valid for the sensor.
void rd_sensor_uninitialize(rd_sensor_t *const p_sensor)
Mark sensor as uninitialized by calling the generic initialization. Will not clear the name of the se...
rd_status_t rd_sensor_configuration_get(const rd_sensor_t *sensor, rd_sensor_configuration_t *config)
Implementation of ref rd_configuration_fp.
void rd_sensor_initialize(rd_sensor_t *const p_sensor)
Initialize sensor struct with non-null pointers which return RD_ERROR_NOT_INITIALIZED.
void rd_sensor_data_populate(rd_sensor_data_t *const target, const rd_sensor_data_t *const provided, const rd_sensor_data_fields_t requested)
Populate given target data with data provided by sensor as requested.
rd_status_t rd_sensor_configuration_set(const rd_sensor_t *sensor, rd_sensor_configuration_t *config)
Implementation of ref rd_configuration_fp.
#define RD_SENSOR_CFG_MIN
Configure smallest supported and implemented value.
#define RD_SENSOR_CFG_CONTINUOUS
Sensor will keep sampling at defined sample rate.
#define RD_SENSOR_CFG_NO_CHANGE
Do not change configured value.
rd_bus_t
Type of bus sensor uses.
uint64_t rd_sensor_timestamp_get(void)
Calls the timestamp function and returns its value.
#define RD_SENSOR_CFG_SINGLE
Sensor should go to sleep after single measurement.
@ RD_BUS_I2C
I2C bus.
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
Ruuvi sensor interface Lifecycle: Beta
Interface for I2C operations.
#define RI_SHTCX_WAKEUP_US
Time from wakeup cmd to rdy.
rd_status_t ri_delay_us(uint32_t time)
Delay a given number of microseconds.
rd_status_t ri_delay_ms(uint32_t time)
Delay a given number of milliseconds.
unsigned int humidity_rh
Relative humidity, %.
unsigned int temperature_c
Temperature, celcius.
Generic sensor data struct.
float * data
Data of sensor. Must contain as many elements as fields has bits set.
uint64_t timestamp_ms
Timestamp of the event, rd_sensor_timestamp_get.
rd_sensor_data_fields_t valid
Listing of valid data in this sample.
rd_sensor_data_fields_t fields
Description of datafields which may be contained in this sample.
Interface to sensor. Some sensors can implement additional functions. The additional functions are de...
rd_sensor_data_fp data_get
rd_sensor_data_fp
rd_configuration_fp configuration_set
rd_configuration_fp
rd_sensor_setup_fp samplerate_get
rd_sensor_setup_fp
rd_sensor_setup_fp resolution_get
rd_sensor_setup_fp
rd_sensor_init_fp uninit
rd_sensor_init_fp
rd_configuration_fp configuration_get
rd_configuration_fp
rd_sensor_dsp_fp dsp_get
rd_sensor_dsp_fp
rd_sensor_data_fields_t provides
Description of data fields the sensor is able to provide.
rd_sensor_dsp_fp dsp_set
rd_sensor_dsp_fp
rd_sensor_setup_fp mode_set
rd_sensor_setup_fp
const char * name
Sensor human-readable name. Should be at most 8 bytes long.
rd_sensor_setup_fp mode_get
rd_sensor_setup_fp
rd_sensor_setup_fp samplerate_set
rd_sensor_setup_fp
rd_sensor_init_fp init
rd_sensor_init_fp
rd_sensor_setup_fp scale_set
rd_sensor_setup_fp
rd_sensor_setup_fp resolution_set
rd_sensor_setup_fp
rd_sensor_setup_fp scale_get
rd_sensor_setup_fp
Union to access sensor data.
uint32_t bitfield
Bitfield used to access sensor data.
rd_sensor_data_bitfield_t datas
Structured data field.