ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ruuvi_nrf5_sdk15_environmental_mcu.c
Go to the documentation of this file.
1 
48 #if RUUVI_NRF5_SDK15_NRF52832_ENVIRONMENTAL_ENABLED
49 #include "ruuvi_driver_error.h"
50 #include "ruuvi_driver_sensor.h"
53 
54 #include "nrf_sdm.h"
55 #include "nrf_temp.h"
56 
57 #include <string.h>
58 
59 #define NRF52_TEMP_SENSOR_RESOLUTION (10U)
60 #define NRF52_TEMP_FIXED_SCALE (128U)
61 
62 // Function for checking "ignored" parameters NO_CHANGE, MIN, MAX, DEFAULT
63 static inline __attribute__ ( (nonnull))
64 rd_status_t success_on_valid (uint8_t param)
65 {
67 
68  if ( (RD_SENSOR_CFG_DEFAULT == param) ||
69  (RD_SENSOR_CFG_MIN == param) ||
70  (RD_SENSOR_CFG_MAX == param) ||
71  (RD_SENSOR_CFG_NO_CHANGE == param))
72  {
73  err_code = RD_SUCCESS;
74  }
75 
76  return err_code;
77 }
78 
79 // Function for checking that sensor is in sleep mode before configuration
80 static inline __attribute__ ( (nonnull))
81 rd_status_t environmental_mcu_sensor_sleep (void)
82 {
83  rd_status_t err_code = RD_SUCCESS;
84  uint8_t mode = 0;
86 
87  if (RD_SENSOR_CFG_SLEEP != mode)
88  {
89  err_code = RD_ERROR_INVALID_STATE;
90  }
91 
92  return err_code;
93 }
94 
95 // Flag to keep track if we should update the temperature register on data read.
96 static bool autorefresh = false;
97 static float temperature;
98 static uint64_t tsample;
99 static const char m_tmp_name[] = "nRF5TMP";
100 
101 static void nrf52832_temperature_sample (void)
102 {
103  uint8_t sd_enabled = NRF_SDH_ENABLED;
104  int32_t raw_temp = 0;
105  // Check if softdevice is enabled
106  sd_softdevice_is_enabled (&sd_enabled);
107 
108  // If Nordic softdevice is enabled, we cannot use temperature peripheral directly
109  if (NRF_SDH_ENABLED == sd_enabled)
110  {
111  sd_temp_get (&raw_temp);
112  }
113  // If SD is not enabled, call the peripheral directly.
114  else
115  {
116  NRF_TEMP->TASKS_START = 1;
118  /* Busy wait while temperature measurement is not finished, you can skip waiting if you enable interrupt for DATARDY event and read the result in the interrupt. */
119  /*lint -e{845} // A zero has been given as right argument to operator '|'" */
120  while (NRF_TEMP->EVENTS_DATARDY == 0)
121  {
122  // Do nothing.
123  }
124 
125  NRF_TEMP->EVENTS_DATARDY = 0;
127  raw_temp = nrf_temp_read();
129  NRF_TEMP->TASKS_STOP = 1;
130  }
131 
132  temperature = raw_temp / 4.0F;
133  tsample = rd_sensor_timestamp_get();
134 }
135 
137  rd_bus_t bus,
138  uint8_t handle)
139 {
140  UNUSED_PARAMETER (bus);
141  UNUSED_PARAMETER (handle);
142  rd_status_t err_code = RD_SUCCESS;
143 
144  if (NULL == sensor)
145  {
146  err_code = RD_ERROR_NULL;
147  }
148  else if (rd_sensor_is_init (sensor))
149  {
150  err_code = RD_ERROR_INVALID_STATE;
151  }
152  else
153  {
154  rd_sensor_initialize (sensor);
155  // Workaround for PAN_028 rev2.0A anomaly 31 - TEMP: Temperature offset value has to be manually loaded to the TEMP module
156  nrf_temp_init();
157  tsample = RD_UINT64_INVALID;
158  temperature = RD_FLOAT_INVALID;
159  // Setup function pointers
175  sensor->name = m_tmp_name;
176  sensor->provides.datas.temperature_c = 1;
177  }
178 
179  return err_code;
180 }
181 
183  rd_bus_t bus,
184  uint8_t handle)
185 {
186  rd_status_t err_code = RD_SUCCESS;
187  UNUSED_PARAMETER (bus);
188  UNUSED_PARAMETER (handle);
189 
190  if (NULL == sensor)
191  {
192  err_code = RD_ERROR_NULL;
193  }
194  else
195  {
196  autorefresh = false;
197  rd_sensor_uninitialize (sensor);
198  tsample = RD_UINT64_INVALID;
199  }
200 
201  return err_code;
202 }
203 
204 // Continuous sampling is not supported, mark pointed value as default even if parameter is one of no-changes
206  uint8_t * samplerate)
207 {
208  rd_status_t err_code = RD_SUCCESS;
209 
210  if (NULL == samplerate)
211  {
212  err_code = RD_ERROR_NULL;
213  }
214  else if (RD_SUCCESS == environmental_mcu_sensor_sleep())
215  {
216  uint8_t original = *samplerate;
217  *samplerate = RD_SENSOR_CFG_DEFAULT;
218  err_code = success_on_valid (original);
219  }
220  else
221  {
222  err_code |= RD_ERROR_INVALID_STATE;
223  }
224 
225  return err_code;
226 }
227 
229  uint8_t * samplerate)
230 {
231  rd_status_t err_code = RD_SUCCESS;
232 
233  if (NULL == samplerate)
234  {
235  err_code = RD_ERROR_NULL;
236  }
237  else
238  {
239  *samplerate = RD_SENSOR_CFG_DEFAULT;
240  err_code = RD_SUCCESS;
241  }
242 
243  return err_code;
244 }
245 
246 // Temperature resolution is fixed to 10 bits, including sign. Return error to driver, but mark used value to pointer.
248  uint8_t * resolution)
249 {
250  rd_status_t err_code = RD_SUCCESS;
251  uint8_t original = *resolution;
252 
253  if (NULL == resolution)
254  {
255  err_code |= RD_ERROR_NULL;
256  }
257  else if (RD_SUCCESS == environmental_mcu_sensor_sleep())
258  {
259  *resolution = NRF52_TEMP_SENSOR_RESOLUTION;
260  err_code = success_on_valid (original);
261  }
262  else
263  {
264  err_code |= RD_ERROR_INVALID_STATE;
265  }
266 
267  return err_code;
268 }
269 
271  uint8_t * resolution)
272 {
273  rd_status_t err_code = RD_SUCCESS;
274 
275  if (NULL == resolution)
276  {
277  err_code = RD_ERROR_NULL;
278  }
279  else
280  {
281  *resolution = NRF52_TEMP_SENSOR_RESOLUTION;
282  }
283 
284  return err_code;
285 }
286 
287 // Scale cannot be set. Our scale is fixed at (2^9) / 4 = 128 (or -127).
289 {
290  rd_status_t err_code = RD_SUCCESS;
291  uint8_t original = *scale;
292 
293  if (NULL == scale)
294  {
295  err_code |= RD_ERROR_NULL;
296  }
297  else if (RD_SUCCESS == environmental_mcu_sensor_sleep())
298  {
299  *scale = NRF52_TEMP_FIXED_SCALE;
300  err_code = success_on_valid (original);
301  }
302  else
303  {
304  err_code |= RD_ERROR_INVALID_STATE;
305  }
306 
307  return err_code;
308 }
309 
311 {
312  rd_status_t err_code = RD_SUCCESS;
313 
314  if (NULL == scale)
315  {
316  err_code = RD_ERROR_NULL;
317  }
318  else
319  {
320  *scale = NRF52_TEMP_FIXED_SCALE;
321  }
322 
323  return err_code;
324 }
325 
326 // Return success on DSP_LAST and acceptable defaults, not supported otherwise
328  uint8_t * parameter)
329 {
331  uint8_t original = *dsp;
332 
333  if ( (NULL == dsp) || (NULL == parameter))
334  {
335  err_code |= RD_ERROR_NULL;
336  }
337  else if (RD_SUCCESS == environmental_mcu_sensor_sleep())
338  {
340  *parameter = RD_SENSOR_ERR_NOT_SUPPORTED;
341  err_code = success_on_valid (original);
342  }
343  else
344  {
345  err_code |= RD_ERROR_INVALID_STATE;
346  }
347 
348  return err_code;
349 }
350 
352  uint8_t * parameter)
353 {
354  *dsp = RD_SENSOR_DSP_LAST;
355  *parameter = 1;
356  return RD_SUCCESS;
357 }
358 
359 // Start single on command, mark autorefresh with continuous
361 {
363 
364  if (NULL == mode)
365  {
366  err_code = RD_ERROR_NULL;
367  }
368  // Enter sleep by default and by explicit sleep commmand
369  else if ( (RD_SENSOR_CFG_SLEEP == *mode) || (RD_SENSOR_CFG_DEFAULT == *mode))
370  {
371  autorefresh = false;
372  *mode = RD_SENSOR_CFG_SLEEP;
373  err_code = RD_SUCCESS;
374  }
375  else if (RD_SENSOR_CFG_SINGLE == *mode)
376  {
377  // Do nothing if sensor is in continuous mode
378  uint8_t current_mode;
379  ri_environmental_mcu_mode_get (&current_mode);
380 
381  if (RD_SENSOR_CFG_CONTINUOUS == current_mode)
382  {
383  *mode = RD_SENSOR_CFG_CONTINUOUS;
384  err_code = RD_ERROR_INVALID_STATE;
385  }
386  else
387  {
388  // Enter sleep after measurement
389  autorefresh = false;
390  *mode = RD_SENSOR_CFG_SLEEP;
391  // Global float is updated by sample
392  nrf52832_temperature_sample();
393  err_code = RD_SUCCESS;
394  }
395  }
396  else if (RD_SENSOR_CFG_CONTINUOUS == *mode)
397  {
398  autorefresh = true;
399  err_code = RD_SUCCESS;
400  }
401  else
402  {
403  err_code = RD_SENSOR_ERR_NOT_SUPPORTED;
404  }
405 
406  return err_code;
407 }
408 
410 {
411  rd_status_t err_code = RD_SUCCESS;
412 
413  if (NULL == mode)
414  {
415  err_code = RD_ERROR_NULL;
416  }
417  else if (autorefresh)
418  {
419  *mode = RD_SENSOR_CFG_CONTINUOUS;
420  }
421  else if (!autorefresh)
422  {
423  *mode = RD_SENSOR_CFG_SLEEP;
424  }
425  else
426  {
427  *mode = RD_SENSOR_ERR_INVALID;
428  }
429 
430  return err_code;
431 }
432 
434  rd_sensor_data_t * const p_data)
435 {
436  rd_status_t err_code = RD_SUCCESS;
437 
438  if (NULL == p_data)
439  {
440  err_code = RD_ERROR_NULL;
441  }
442  else
443  {
444  if (autorefresh)
445  {
446  nrf52832_temperature_sample();
447  }
448 
449  if (!isnan (temperature))
450  {
451  rd_sensor_data_t d_environmental;
452  rd_sensor_data_fields_t env_fields = {.bitfield = 0};
453  float env_values[1];
454  env_values[0] = temperature;
455  env_fields.datas.temperature_c = 1;
456  d_environmental.data = env_values;
457  d_environmental.valid = env_fields;
458  d_environmental.fields = env_fields;
459  rd_sensor_data_populate (p_data,
460  &d_environmental,
461  p_data->fields);
462  p_data->timestamp_ms = tsample;
463  }
464  }
465 
466  return err_code;
467 }
468 
469 #endif
rd_status_t ri_environmental_mcu_mode_set(uint8_t *)
rd_sensor_setup_fp
rd_status_t ri_environmental_mcu_scale_set(uint8_t *scale)
rd_sensor_setup_fp
rd_status_t ri_environmental_mcu_mode_get(uint8_t *)
rd_sensor_setup_fp
rd_status_t ri_environmental_mcu_init(rd_sensor_t *environmental_sensor, rd_bus_t bus, uint8_t handle)
rd_sensor_init_fp
rd_status_t ri_environmental_mcu_resolution_get(uint8_t *resolution)
rd_sensor_setup_fp
rd_status_t ri_environmental_mcu_samplerate_get(uint8_t *samplerate)
rd_sensor_setup_fp
rd_status_t ri_environmental_mcu_samplerate_set(uint8_t *samplerate)
rd_sensor_setup_fp
rd_status_t ri_environmental_mcu_resolution_set(uint8_t *resolution)
rd_sensor_setup_fp
rd_status_t ri_environmental_mcu_dsp_get(uint8_t *dsp, uint8_t *parameter)
rd_sensor_dsp_fp
rd_status_t ri_environmental_mcu_dsp_set(uint8_t *dsp, uint8_t *parameter)
rd_sensor_dsp_fp
rd_status_t ri_environmental_mcu_data_get(rd_sensor_data_t *const data)
rd_sensor_data_fp
rd_status_t ri_environmental_mcu_uninit(rd_sensor_t *environmental_sensor, rd_bus_t bus, uint8_t handle)
rd_sensor_init_fp
rd_status_t ri_environmental_mcu_scale_get(uint8_t *scale)
rd_sensor_setup_fp
#define RD_ERROR_INVALID_PARAM
Invalid Parameter.
#define RD_ERROR_NULL
Null Pointer.
uint32_t rd_status_t
bitfield for representing errors
#define RD_FLOAT_INVALID
Signal that value should not be used.
#define RD_ERROR_NOT_SUPPORTED
Not supported.
#define RD_SUCCESS
Internal Error.
#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_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.
#define RD_SENSOR_ERR_INVALID
Error code, given parameter is invalid.
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.
#define NRF_SDH_ENABLED
Required by SDK BLE module conditional compilation.
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
Ruuvi sensor interface Lifecycle: Beta
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.