ruuvi.drivers.c ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
Loading...
Searching...
No Matches
ruuvi_driver_sensor_test.c
Go to the documentation of this file.
1
11#include "ruuvi_driver_error.h"
12#include "ruuvi_driver_sensor.h"
16#include "ruuvi_interface_log.h"
17#include "ruuvi_interface_rtc.h"
20
21#include <float.h>
22#include <stdbool.h>
23#include <stddef.h>
24#include <string.h>
25#include <stdio.h>
26
27#if RUUVI_RUN_TESTS
28
29#define RETURN_ON_ERROR(status) if(status) \
30{ \
31RD_ERROR_CHECK(RD_ERROR_SELFTEST, ~RD_ERROR_FATAL); \
32return status; \
33}
34#define BITFIELD_MASK (1U)
35#define MAX_LOG_BUFFER_SIZE (128U)
36#define MAX_SENSOR_NAME_LEN (20U)
37#define MAX_BITS_PER_BYTE (8U)
38#define MAX_SENSORS (sizeof(rd_sensor_data_fields_t)* MAX_BITS_PER_BYTE)
39#define MAX_RETRIES (50U)
40#define MAX_FIFO_DEPTH (32U)
41#define MAX_SENSOR_PROVIDED_FIELDS (4U)
42
43#define LOG_PRINT_DELAY_MS (10U)
44
45
46static inline void LOG (const char * const msg)
47{
49 ri_delay_ms (LOG_PRINT_DELAY_MS); // Avoid overflowing log buffer.
50}
51
52static volatile bool fifo_int = false;
53static volatile bool level_int = false;
54
55static bool initialize_sensor_once (rd_sensor_t * DUT,
56 const rd_sensor_init_fp init,
57 const rd_bus_t bus, const uint8_t handle)
58{
59 rd_status_t err_code = RD_SUCCESS;
60 err_code = init (DUT, bus, handle);
61
62 if (RD_SUCCESS != err_code)
63 {
64 return true;
65 }
66
67 return false;
68}
69
70static bool uninitialize_sensor (rd_sensor_t * DUT,
71 const rd_sensor_init_fp init,
72 const rd_bus_t bus, const uint8_t handle)
73{
74 rd_status_t err_code = RD_SUCCESS;
75 err_code = DUT->uninit (DUT, bus, handle);
76
77 if (RD_SUCCESS != err_code)
78 {
79 return true;
80 }
81
82 return false;
83}
84
85static bool initialize_sensor_twice (rd_sensor_t * DUT,
86 const rd_sensor_init_fp init,
87 const rd_bus_t bus, const uint8_t handle)
88{
89 rd_status_t err_code = RD_SUCCESS;
90 err_code = init (DUT, bus, handle);
91 err_code = init (DUT, bus, handle);
92
93 if (RD_SUCCESS == err_code)
94 {
95 RD_ERROR_CHECK (err_code, ~RD_ERROR_FATAL);
96 return true;
97 }
98
99 return false;
100}
101
102static bool validate_sensor_setup (rd_sensor_t * DUT)
103{
104 // - None of the sensor function pointers may be NULL after init
105 if (DUT->init == NULL ||
106 DUT->uninit == NULL ||
107 DUT->configuration_get == NULL ||
108 DUT->configuration_set == NULL ||
109 DUT->data_get == NULL ||
110 DUT->dsp_get == NULL ||
111 DUT->dsp_set == NULL ||
112 DUT->fifo_enable == NULL ||
113 DUT->fifo_interrupt_enable == NULL ||
114 DUT->fifo_read == NULL ||
115 DUT->level_interrupt_set == NULL ||
116 DUT->mode_get == NULL ||
117 DUT->mode_set == NULL ||
118 DUT->resolution_get == NULL ||
119 DUT->resolution_set == NULL ||
120 DUT->samplerate_get == NULL ||
121 DUT->samplerate_set == NULL ||
122 DUT->scale_get == NULL ||
123 DUT->scale_set == NULL ||
124 DUT->name == NULL ||
125 DUT->provides.bitfield == 0)
126 {
127 return true;
128 }
129
130 return false;
131}
132
133static bool validate_sensor_teardown (rd_sensor_t * DUT)
134{
135 bool failed = false;
136 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->init (NULL, 0, 0)) ? true : false;
137 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->uninit (NULL, 0, 0)) ? true : false;
138 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->configuration_get (NULL,
139 NULL)) ? true : false;
140 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->configuration_set (NULL,
141 NULL)) ? true : false;
142 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->data_get (NULL)) ? true : false;
143 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->dsp_get (NULL, NULL)) ? true : false;
144 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->dsp_set (NULL, NULL)) ? true : false;
145 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->fifo_enable (false)) ? true : false;
147 false)) ? true : false;
148 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->fifo_read (NULL,
149 NULL)) ? true : false;
150 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->level_interrupt_set (false,
151 NULL)) ? true : false;
152 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->mode_get (NULL)) ? true : false;
153 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->mode_set (NULL)) ? true : false;
154 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->resolution_get (NULL)) ? true : false;
155 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->resolution_set (NULL)) ? true : false;
156 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->samplerate_get (NULL)) ? true : false;
157 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->samplerate_set (NULL)) ? true : false;
158 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->scale_get (NULL)) ? true : false;
159 failed |= (RD_ERROR_NOT_INITIALIZED != DUT->scale_set (NULL)) ? true : false;
160 failed |= (0 != DUT->provides.bitfield) ? true : false;
161 return failed;
162}
163
164static bool validate_sensor_mode_after_init (rd_sensor_t * DUT)
165{
166 uint8_t mode;
167 rd_status_t err_code = DUT->mode_get (&mode);
168
169 if (RD_SUCCESS != err_code || RD_SENSOR_CFG_SLEEP != mode)
170 {
172 return true;
173 }
174
175 return false;
176}
177
178static bool test_sensor_init_on_null (rd_sensor_t * DUT,
179 const rd_sensor_init_fp init,
180 const rd_bus_t bus, const uint8_t handle)
181{
182 rd_status_t err_init = DUT->init (NULL, bus, handle);
183 rd_status_t err_uninit = DUT->uninit (NULL, bus, handle);
184
185 if (RD_ERROR_NULL != err_init || RD_ERROR_NULL != err_uninit)
186 {
187 return true;
188 }
189
190 return false;
191}
192
217static bool test_sensor_init (const rd_sensor_init_fp init,
218 const rd_bus_t bus, const uint8_t handle)
219{
220 rd_sensor_t DUT = {0};
221 bool failed = false;
222 // - Sensor must return RD_SUCCESS on first init.
223 failed |= initialize_sensor_once (&DUT, init, bus, handle);
224 RETURN_ON_ERROR (failed);
225 // - None of the sensor function pointers may be NULL after init
226 failed |= validate_sensor_setup (&DUT);
227 // - Sensor must return RD_SUCCESS on first uninit
228 failed |= uninitialize_sensor (&DUT, init, bus, handle);
229 // - All of sensor function pointers must return RD_ERROR_NOT_INITIALIZED after uninit
230 failed |= validate_sensor_teardown (&DUT);
231 // - Sensor must return RD_ERROR_INVALID_STATE when initializing sensor which is already init
232 failed |= initialize_sensor_twice (&DUT, init, bus, handle);
233 // - Sensor must return RD_SUCCESS after uninit
234 failed |= uninitialize_sensor (&DUT, init, bus, handle);
235 // - Sensor initialization must be successful after uninit.
236 failed |= initialize_sensor_once (&DUT, init, bus, handle);
237 // - Sensor mode_get must return RD_SENSOR_CFG_SLEEP after init.
238 failed |= validate_sensor_mode_after_init (&DUT);
239 // - Init and Uninit must return RD_ERROR_NULL if pointer to sensor struct is NULL
240 failed |= test_sensor_init_on_null (&DUT, init, bus, handle);
241 // Uninitialise sensor after test
242 DUT.uninit (&DUT, bus, handle);
243 return failed;
244}
245
246static bool test_sensor_setup_set_get (const rd_sensor_t * DUT,
247 const rd_sensor_setup_fp set, const rd_sensor_setup_fp get)
248{
249 rd_status_t err_code = RD_SUCCESS;
250 bool failed = false;
251 uint8_t config = 0;
252 uint8_t original = 0;
253 // Test constant values
255
256 for (size_t ii = 0; ii < sizeof (cfg_constants); ii++)
257 {
258 config = cfg_constants[ii];
259 err_code = set (&config);
260 original = config;
261 err_code |= get (&config);
262
263 if (config != original ||
264 RD_SUCCESS != err_code)
265 {
266 failed = true;
267 }
268 }
269
270 if (RD_SUCCESS != err_code)
271 {
272 failed = true;
273 }
274
275 // Sensor must return RD_ERROR_INVALID_STATE if sensor is not in SLEEP mode while being configured.
276 uint8_t mode = RD_SENSOR_CFG_CONTINUOUS;
277 config = RD_SENSOR_CFG_DEFAULT;
278 err_code = DUT->mode_set (&mode);
279 err_code |= set (&config);
280
281 if (RD_ERROR_INVALID_STATE != err_code)
282 {
283 failed = true;
284 }
285
286 mode = RD_SENSOR_CFG_SLEEP;
287 err_code = DUT->mode_set (&mode);
288
289 // Test values 1 ... 200
290 for (uint8_t ii = 1; ii < 200; ii++)
291 {
292 config = ii;
293 original = config;
294 err_code = set (&config);
295
296 // Set value must be at least requested value
297 if (RD_SUCCESS == err_code &&
298 original > config)
299 {
300 failed = true;
301 }
302
303 // Get must be as what was returned in set
304 original = config;
305 err_code |= get (&config);
306
307 if (config != original &&
308 RD_SUCCESS == err_code)
309 {
310 failed = true;
311 break;
312 }
313
314 // Break on not supported
315 if (RD_ERROR_NOT_SUPPORTED == err_code)
316 {
317 break;
318 }
319
320 // Return error on any other error code
321 if (RD_SUCCESS != err_code)
322 {
323 return true;
324 }
325 }
326
327 // Check NULL check
328 err_code = set (NULL);
329
330 if (RD_ERROR_NULL != err_code)
331 {
332 failed = true;
333 }
334
335 err_code = get (NULL);
336
337 if (RD_ERROR_NULL != err_code)
338 {
339 failed = true;
340 }
341
342 return failed;
343}
344
361static bool test_sensor_setup (const rd_sensor_init_fp init,
362 const rd_bus_t bus, const uint8_t handle)
363{
364 // - Sensor must return RD_SUCCESS on first init.
365 rd_sensor_t DUT;
366 memset (&DUT, 0, sizeof (DUT));
367 bool failed = false;
368 failed |= init (&DUT, bus, handle);
369
370 if (failed)
371 {
372 // Return to avoid calling NULL function pointers
373 return failed;
374 }
375
376 // Test scale
377 failed |= test_sensor_setup_set_get (&DUT, DUT.scale_set, DUT.scale_get);
378 // Test samplerate
379 failed |= test_sensor_setup_set_get (&DUT, DUT.samplerate_set, DUT.samplerate_get);
380 // Test resolution
381 failed |= test_sensor_setup_set_get (&DUT, DUT.resolution_set, DUT.resolution_get);
382 // Uninitialise sensor after test
383 DUT.uninit (&DUT, bus, handle);
384 return failed;
385}
386
388static inline bool value_has_changed (rd_sensor_data_t * old,
389 const rd_sensor_data_t * const new_d)
390{
391 bool change = false;
392
393 for (uint8_t ii = 0; ii < rd_sensor_data_fieldcount (old); ii++)
394 {
395 if (old->data[ii] != new_d->data[ii]) { change = true; }
396
397 old->data[ii] = new_d->data[ii];
398 }
399
400 return change;
401}
402
403static bool sensor_sleeps_after_init (const rd_sensor_t * const DUT)
404{
405 rd_status_t err_code = RD_SUCCESS;
406 uint8_t mode;
407 err_code = DUT->mode_get (&mode);
408
409 if (RD_SUCCESS != err_code || RD_SENSOR_CFG_SLEEP != mode)
410 {
411 return true;
412 }
413
414 return false;
415}
416
417static bool sensor_returns_invalid_before_sampling (const rd_sensor_t * const DUT)
418{
419 rd_status_t err_code = RD_SUCCESS;
420 float values_new[MAX_SENSOR_PROVIDED_FIELDS];
421 rd_sensor_data_t new_data =
422 {
423 .fields = DUT->provides,
424 .data = values_new
425 };
426 err_code = DUT->data_get (&new_data);
427
428 if (RD_SUCCESS != err_code || new_data.valid.bitfield)
429 {
431 return true;
432 }
433
434 return false;
435}
436
437static bool sensor_returns_to_sleep (const rd_sensor_t * const DUT)
438{
439 rd_status_t err_code = RD_SUCCESS;
440 uint8_t mode;
442 err_code = DUT->mode_set (&mode);
443
444 if (RD_SUCCESS != err_code || RD_SENSOR_CFG_SLEEP != mode)
445 {
447 return true;
448 }
449
450 return false;
451}
452
453static bool sensor_returns_valid_data (const rd_sensor_t * const DUT)
454{
455 rd_status_t err_code = RD_SUCCESS;
456 uint8_t mode;
457 rd_sensor_data_t data = {0};
458 float values [MAX_SENSOR_PROVIDED_FIELDS];
459 data.fields = DUT->provides;
460 data.data = values;
462 err_code = DUT->mode_set (&mode);
463 err_code |= DUT->data_get (&data);
464
465 if (RD_SUCCESS != err_code ||
466 (DUT->provides.bitfield != data.valid.bitfield) ||
468 {
470 return true;
471 }
472
473 return false;
474}
475
476static bool single_sample_stays_valid (const rd_sensor_t * const DUT)
477{
478 rd_status_t err_code = RD_SUCCESS;
479 uint8_t mode = RD_SENSOR_CFG_SINGLE;
480 float old_values[MAX_SENSOR_PROVIDED_FIELDS] = {0};
481 float new_values[MAX_SENSOR_PROVIDED_FIELDS] = {0};
482 rd_sensor_data_t old_data = {.fields = DUT->provides,
483 .data = old_values
484 };
485 rd_sensor_data_t new_data = {.fields = DUT->provides,
486 .data = new_values
487 };
488 err_code = DUT->mode_set (&mode);
489 err_code |= DUT->data_get (&old_data);
490 ri_delay_ms (2); // wait 2 ms to ensure timestamp is not changed.
491 err_code |= DUT->data_get (&new_data);
492
493 if (RD_SUCCESS != err_code ||
494 old_data.timestamp_ms != new_data.timestamp_ms ||
495 0 != memcmp (old_values, new_values, sizeof (old_values)))
496 {
498 return true;
499 }
500
501 return false;
502}
503
504static bool sensor_remains_continuous (const rd_sensor_t * const DUT)
505{
506 rd_status_t err_code = RD_SUCCESS;
507 uint8_t mode = RD_SENSOR_CFG_SINGLE;
509 err_code = DUT->mode_set (&mode);
510 ri_delay_ms (20);
511 err_code |= DUT->mode_get (&mode);
512
513 if (RD_SUCCESS != err_code || RD_SENSOR_CFG_CONTINUOUS != mode)
514 {
515 return true;
516 }
517
518 return false;
519}
520
521static bool sensor_rejects_single_on_continuous (const rd_sensor_t * const DUT)
522{
523 rd_status_t err_code = RD_SUCCESS;
524 uint8_t mode = RD_SENSOR_CFG_SINGLE;
525 err_code = DUT->mode_set (&mode);
526
527 if (RD_ERROR_INVALID_STATE != err_code
528 || RD_SENSOR_CFG_CONTINUOUS != mode)
529 {
530 return true;
531 }
532
533 return false;
534}
535
536static bool sensor_mode_cannot_be_null (const rd_sensor_t * const DUT)
537{
538 rd_status_t err_code = RD_SUCCESS;
539 err_code = DUT->mode_set (NULL);
540
541 if (RD_ERROR_NULL != err_code)
542 {
543 return true;
544 }
545
546 err_code = DUT->mode_get (NULL);
547
548 if (RD_ERROR_NULL != err_code)
549 {
550 return true;
551 }
552
553 return false;
554}
555
556static bool sensor_returns_continuous_data (const rd_sensor_t * const DUT)
557{
558 rd_status_t err_code = RD_SUCCESS;
559 uint8_t mode = RD_SENSOR_CFG_SLEEP;
560 float old_values[MAX_SENSOR_PROVIDED_FIELDS];
561 float new_values[MAX_SENSOR_PROVIDED_FIELDS];
562 rd_sensor_data_t old_data = {.fields = DUT->provides,
563 .data = old_values
564 };
565 rd_sensor_data_t new_data = {.fields = DUT->provides,
566 .data = new_values
567 };
568 err_code = DUT->mode_set (&mode);
569 err_code |= DUT->data_get (&old_data);
570 ri_delay_ms (2); // wait 2 ms to ensure timestamp is not changed.
571 err_code |= DUT->data_get (&new_data);
572 err_code = DUT->mode_set (&mode);
573 uint8_t samplerate = RD_SENSOR_CFG_MAX;
574 err_code |= DUT->samplerate_set (&samplerate);
576 err_code |= DUT->mode_set (&mode);
577 uint32_t interval = (1000 / (samplerate + 1));
578 ri_delay_ms (2 * interval);
579 err_code |= DUT->data_get (&old_data);
580 int retries = 0;
581
582 for (; retries < MAX_RETRIES; retries++)
583 {
584 ri_delay_ms (2 * interval);
585 new_data.valid.bitfield = 0;
587 err_code |= DUT->data_get (&new_data);
588
589 if (old_data.timestamp_ms == new_data.timestamp_ms || RD_SUCCESS != err_code)
590 {
591 if (RD_STATUS_MORE_AVAILABLE == err_code)
592 {
593 do
594 {
595 err_code |= DUT->data_get (&new_data);
596 } while (RD_STATUS_MORE_AVAILABLE == err_code);
597
598 continue;
599 }
600 else
601 {
602 return true;
603 }
604 }
605
606 if (value_has_changed (&old_data, &new_data)) { break; }
607 }
608
609 if (MAX_RETRIES == retries)
610 {
611 return true;
612 }
613
614 return false;
615}
616
638static bool test_sensor_modes (const rd_sensor_init_fp init,
639 const rd_bus_t bus, const uint8_t handle)
640{
641 bool failed = false;
642 rd_sensor_t DUT;
643 memset (&DUT, 0, sizeof (DUT));
644 initialize_sensor_once (&DUT, init, bus, handle);
645 // - Sensor must be in SLEEP mode after init
646 failed |= sensor_sleeps_after_init (&DUT);
647 // - Sensor must return all values as INVALID if sensor is read before first sample
648 failed |= sensor_returns_invalid_before_sampling (&DUT);
649 // - Sensor must be in SLEEP mode after mode has been set to SINGLE
650 failed |= sensor_returns_to_sleep (&DUT);
651 // - Sensor must have new data after setting mode to SINGLE returns
652 failed |= sensor_returns_valid_data (&DUT);
653 // - Sensor must have same values, including timestamp, on successive calls to DATA_GET after SINGLE sample
654 failed |= single_sample_stays_valid (&DUT);
655 // - Sensor must stay in CONTINUOUS mode after being set to continuous.
656 failed |= sensor_remains_continuous (&DUT);
657 // - Sensor must return RD_ERROR_INVALID_STATE if set to SINGLE while in continuous mode and remain in continuous mode
658 failed |= sensor_rejects_single_on_continuous (&DUT);
659 // - Sensor must return RD_ERROR_NULL if null mode is passed as a parameter
660 failed |= sensor_mode_cannot_be_null (&DUT);
661 // Sensor must return updated data in CONTINUOUS mode, at least timestamp has to be updated after two ms wait.
662 failed |= sensor_returns_continuous_data (&DUT);
663 // Uninitialise sensor after test
664 failed |= DUT.uninit (&DUT, bus, handle);
665 return failed;
666}
667
668static void on_fifo (const ri_gpio_evt_t evt)
669{
670 fifo_int = true;
671}
672
673static void on_level (const ri_gpio_evt_t evt)
674{
675 level_int = true;
676}
677
689static bool test_sensor_interrupts_setup (rd_sensor_t * DUT,
690 rd_sensor_init_fp const init,
691 const rd_bus_t bus, const uint8_t handle,
692 ri_gpio_interrupt_fp_t * const interrupt_table,
693 const ri_gpio_id_t fifo_pin,
694 const ri_gpio_id_t level_pin)
695{
696 rd_status_t err_code = RD_SUCCESS;
697
699 {
700 err_code |= ri_gpio_interrupt_uninit();
701 }
702
703 err_code |= ri_gpio_interrupt_init (interrupt_table,
705 err_code |= ri_gpio_interrupt_enable (fifo_pin, RI_GPIO_SLOPE_LOTOHI,
707 err_code |= ri_gpio_interrupt_enable (level_pin, RI_GPIO_SLOPE_LOTOHI,
708 RI_GPIO_MODE_INPUT_PULLUP, on_level);
709 // - Sensor must return RD_SUCCESS on first init.
710 memset (DUT, 0, sizeof (rd_sensor_t));
711 err_code |= init (DUT, bus, handle);
712 err_code |= DUT->fifo_interrupt_enable (true);
713 return (RD_SUCCESS != err_code);
714}
715
719static void test_sensor_interrupts_teardown (rd_sensor_t * const DUT,
720 rd_sensor_init_fp const init,
721 const rd_bus_t bus, const uint8_t handle,
722 const ri_gpio_id_t fifo_pin,
723 const ri_gpio_id_t level_pin)
724{
725 DUT->fifo_interrupt_enable (false);
726 ri_gpio_interrupt_disable (fifo_pin);
727 ri_gpio_interrupt_disable (level_pin);
728 DUT->uninit (DUT, bus, handle);
730}
731
733static rd_status_t test_sensor_level_enable (const rd_sensor_t * DUT)
734{
735 float threshold_g = APP_MOTION_THRESHOLD;
736 DUT->level_interrupt_set (true, &threshold_g);
737 rd_sensor_configuration_t config = {0};
738 config.samplerate = 10;
740 DUT->configuration_set (DUT, &config);
741 level_int = false;
742 // Wait for LEVEL interrupt
743 uint32_t timeout = 0;
744 uint32_t max_time = 5U * 1000U * 1000U;
745
746 while ( (!level_int) && (timeout < max_time))
747 {
748 timeout += 10;
749 ri_delay_us (10);
750 }
751
752 if (timeout >= max_time)
753 {
754 return RD_ERROR_TIMEOUT;
755 }
756
757 return (level_int) ? false : true;
758}
759
761static rd_status_t test_sensor_fifo_enable (const rd_sensor_t * DUT)
762{
763 DUT->fifo_enable (true);
764 rd_sensor_configuration_t config = {0};
765 config.samplerate = 10;
767 DUT->configuration_set (DUT, &config);
768 fifo_int = false;
769 ri_delay_ms (100);
771 float old_values[MAX_SENSOR_PROVIDED_FIELDS];
772 old.data = old_values;
773 old.fields.bitfield = DUT->provides.bitfield;
774 size_t num_samples = MAX_FIFO_DEPTH;
775 rd_sensor_data_t data[MAX_FIFO_DEPTH] = { 0 };
776 float values[num_samples][MAX_SENSOR_PROVIDED_FIELDS];
777 uint32_t max_time = 4U * 1000U * 1000U;
778
779 for (size_t ii = 0; ii < num_samples; ii++)
780 {
781 data[ii].data = values[ii];
782 data[ii].fields.bitfield = DUT->provides.bitfield;
783 }
784
785 bool valid_data = false;
786 // Wait for FIFO interrupt
787 uint32_t timeout = 0;
788
789 while ( (!fifo_int) && (timeout < max_time))
790 {
791 timeout += 10;
792 ri_delay_us (10);
793 }
794
795 if (timeout >= max_time)
796 {
797 return RD_ERROR_TIMEOUT;
798 }
799
800 DUT->fifo_read (&num_samples, data);
801
802 if (10U > num_samples)
803 {
804 return RD_ERROR_SELFTEST;
805 }
806
807 // Check that FIFO has new values
808 value_has_changed (&old, & (data[0]));
809
810 for (size_t iii = 1; iii < num_samples; iii++)
811 {
812 if (value_has_changed (&old, & (data[iii])))
813 {
814 valid_data = true;
815 break;
816 }
817 }
818
819 return (valid_data) ? false : true;
820}
821
822
843static bool test_sensor_interrupts (const rd_sensor_init_fp init,
844 const rd_bus_t bus, const uint8_t handle,
845 const bool interactive,
846 const ri_gpio_id_t fifo_pin,
847 const ri_gpio_id_t level_pin,
848 const rd_test_print_fp printfp)
849{
851 interrupt_table[RI_GPIO_INTERRUPT_TEST_TABLE_SIZE];
852 rd_sensor_t DUT;
853 rd_status_t status;
854 status = test_sensor_interrupts_setup (&DUT, init, bus, handle, interrupt_table, fifo_pin,
855 level_pin);
856
857 if (RD_SUCCESS == status)
858 {
859 printfp ("{\r\n\"level\":");
860 status |= test_sensor_level_enable (&DUT);
861
862 if (status)
863 {
864 printfp ("\"fail\",\r\n");
865 }
866 else
867 {
868 printfp ("\"pass\",\r\n");
869 }
870
871 test_sensor_interrupts_teardown (&DUT, init, bus, handle, fifo_pin,
872 level_pin);
873 status = test_sensor_interrupts_setup (&DUT, init, bus, handle, interrupt_table, fifo_pin,
874 level_pin);
875 printfp ("\"fifo\":");
876 status |= test_sensor_fifo_enable (&DUT);
877
878 if (status)
879 {
880 printfp ("\"fail\"\r\n");
881 }
882 else
883 {
884 printfp ("\"pass\"\r\n");
885 }
886
887 printfp ("},");
888 }
889
890 test_sensor_interrupts_teardown (&DUT, init, bus, handle, fifo_pin,
891 level_pin);
892 return status;
893}
894
895static bool sensor_returns_valid_data_print (const rd_sensor_t * const DUT,
896 const rd_test_print_fp printfp)
897{
898 rd_status_t err_code = RD_SUCCESS;
899 uint8_t mode;
900 rd_sensor_data_t data = {0};
901 float values [MAX_SENSOR_PROVIDED_FIELDS];
902 data.fields = DUT->provides;
903 data.data = values;
905 err_code = DUT->mode_set (&mode);
906 err_code |= DUT->data_get (&data);
907
908 if (RD_SUCCESS != err_code)
909 {
911 return true;
912 }
913
914 rd_sensor_data_print (&data, printfp);
915 return false;
916}
917
918static bool test_sensor_data_print (const rd_sensor_init_fp init,
919 const rd_bus_t bus, const uint8_t handle,
920 const rd_test_print_fp printfp)
921{
922 // - Sensor must return RD_SUCCESS on first init.
923 rd_sensor_t DUT;
924 memset (&DUT, 0, sizeof (DUT));
925 bool failed = false;
926 failed |= init (&DUT, bus, handle);
927
928 if (failed)
929 {
930 // Return to avoid calling NULL function pointers
931 printfp ("\"data\":\"fail\",\r\n");
932 return failed;
933 }
934
935 failed |= sensor_returns_valid_data_print (&DUT, printfp);
936 DUT.uninit (&DUT, bus, handle);
937 return failed;
938}
939
941 rt_sensor_ctx_t * p_sensor_ctx)
942{
943 bool status = false;
944 rd_status_t err_code = RD_SUCCESS;
945 printfp ("\"");
946 printfp (p_sensor_ctx->sensor.name);
947 printfp ("\": {\r\n");
948 printfp ("\"init\":");
949
950 if (RD_HANDLE_UNUSED == p_sensor_ctx->handle)
951 {
952 err_code |= RD_ERROR_NOT_FOUND;
953 }
954 else
955 {
956 err_code |= p_sensor_ctx->init (&p_sensor_ctx->sensor,
957 p_sensor_ctx->bus,
958 p_sensor_ctx->handle);
959 }
960
961 if (RD_ERROR_NOT_FOUND == err_code)
962 {
963 printfp ("\"skip\"\r\n");
964 p_sensor_ctx->sensor.uninit (&p_sensor_ctx->sensor, p_sensor_ctx->bus,
965 p_sensor_ctx->handle);
966 }
967 else
968 {
969 p_sensor_ctx->sensor.uninit (&p_sensor_ctx->sensor, p_sensor_ctx->bus,
970 p_sensor_ctx->handle);
971 status = test_sensor_init (p_sensor_ctx->init, p_sensor_ctx->bus, p_sensor_ctx->handle);
972
973 if (status)
974 {
975 printfp ("\"fail\",\r\n");
976 }
977 else
978 {
979 printfp ("\"pass\",\r\n");
980 }
981
982 printfp ("\"modes\":");
983
984 if (!status)
985 {
986 status = test_sensor_modes (p_sensor_ctx->init, p_sensor_ctx->bus, p_sensor_ctx->handle);
987 }
988
989 if (status)
990 {
991 printfp ("\"fail\",\r\n");
992 }
993 else
994 {
995 printfp ("\"pass\",\r\n");
996 }
997
998 printfp ("\"configuration\":");
999
1000 if (!status)
1001 {
1002 status = test_sensor_setup (p_sensor_ctx->init, p_sensor_ctx->bus, p_sensor_ctx->handle);
1003 }
1004
1005 if (status)
1006 {
1007 printfp ("\"fail\",\r\n");
1008 }
1009 else
1010 {
1011 printfp ("\"pass\",\r\n");
1012 }
1013
1014 printfp ("\"interrupts\":");
1015
1016 if ( (RI_GPIO_ID_UNUSED != p_sensor_ctx->fifo_pin)
1017 && (RI_GPIO_ID_UNUSED != p_sensor_ctx->level_pin)
1018 && (!status))
1019 {
1020 status = test_sensor_interrupts (p_sensor_ctx->init, p_sensor_ctx->bus,
1021 p_sensor_ctx->handle, false,
1022 p_sensor_ctx->fifo_pin,
1023 p_sensor_ctx->level_pin,
1024 printfp);
1025 }
1026 else
1027 {
1028 printfp ("\"skipped\",\r\n");
1029 }
1030
1031 status = test_sensor_data_print (p_sensor_ctx->init, p_sensor_ctx->bus,
1032 p_sensor_ctx->handle, printfp);
1033 }
1034
1035 printfp ("}");
1036 return status;
1037}
1038
1039void rd_sensor_data_print (const rd_sensor_data_t * const p_data,
1040 const rd_test_print_fp printfp)
1041{
1042 uint8_t data_counter = 0;
1043 uint8_t data_available = 0;
1044 uint32_t data_check = p_data->fields.bitfield;
1045 char sensors_name[MAX_SENSORS][MAX_SENSOR_NAME_LEN] =
1046 {
1047 "acceleration_x_g",
1048 "acceleration_y_g",
1049 "acceleration_z_g",
1050 "co2_ppm",
1051 "gyro_x_dps",
1052 "gyro_y_dps",
1053 "gyro_z_dps",
1054 "humidity_rh",
1055 "luminosity",
1056 "magnetometer_x_g",
1057 "magnetometer_y_g",
1058 "magnetometer_z_g",
1059 "pm_1_ugm3",
1060 "pm_2_ugm3",
1061 "pm_4_ugm3",
1062 "pm_10_ugm3",
1063 "pressure_pa",
1064 "spl_dbz",
1065 "temperature_c",
1066 "voc_ppm",
1067 "voltage_v",
1068 "voltage_ratio",
1069 };
1070
1071 /* Count enabled sensors */
1072 for (int i = 0; i < MAX_SENSORS; i++)
1073 {
1074 if (data_check & BITFIELD_MASK)
1075 { data_available++; }
1076
1077 data_check = data_check >> 1;
1078 }
1079
1080 if (NULL != p_data)
1081 {
1082 printfp ("\"data\":{\r\n");
1083 char msg[MAX_LOG_BUFFER_SIZE];
1084
1085 if (RD_UINT64_INVALID == p_data->timestamp_ms)
1086 {
1087 snprintf (msg, sizeof (msg), "\"timestamp_ms\": \"RD_UINT64_INVALID\",\n");
1088 }
1089 else
1090 {
1091 // Cast to 32 bits, tests are run at boot so there is no danger of overflow.
1092 snprintf (msg, sizeof (msg), "\"timestamp_ms\": \"%ld\",\n",
1093 (uint32_t) p_data->timestamp_ms);
1094 }
1095
1096 printfp (msg);
1097
1098 for (uint8_t i = 0; i < MAX_SENSORS; i++)
1099 {
1100 if ( (p_data->fields.bitfield >> i) &
1101 BITFIELD_MASK)
1102 {
1103 char msg[MAX_LOG_BUFFER_SIZE];
1104
1105 if ( (p_data->valid.bitfield >> i) &
1106 BITFIELD_MASK)
1107 {
1108 if (0 == isnan (* ( (float *) (&p_data->data[data_counter]))))
1109 {
1110 snprintf (msg, sizeof (msg),
1111 "\"%s\": \"%.2f\"",
1112 (char *) &sensors_name[i][0],
1113 * ( (float *) (&p_data->data[data_counter])));
1114 }
1115 else
1116 {
1117 snprintf (msg, sizeof (msg),
1118 "\"%s\": \"NAN\"",
1119 (char *) &sensors_name[i][0]);
1120 }
1121
1122 data_counter++;
1123 }
1124 else
1125 {
1126 snprintf (msg, sizeof (msg),
1127 "\"%s\": \"NAN\"",
1128 (char *) &sensors_name[i][0]);
1129 }
1130
1131 if (data_counter == data_available)
1132 {
1133 char * str = "\r\n";
1134 strncat (msg, str, sizeof (str));
1135 }
1136 else
1137 {
1138 char * str = ",\r\n";
1139 strncat (msg, str, sizeof (str));
1140 }
1141
1142 printfp (msg);
1143 }
1144 }
1145
1146 printfp ("}\r\n");
1147 }
1148}
1149
1150#else //RUUVI_RUN_TESTS
1151
1152// Dummy implementation
1153rd_status_t test_sensor_status (size_t * total, size_t * passed)
1154{
1155 return RD_SUCCESS;
1156}
1157
1158// Dummy implementation
1160{}
1161#endif
#define RD_ERROR_NULL
Null Pointer.
#define RD_ERROR_NOT_INITIALIZED
Driver is not initialized.
#define RD_ERROR_FATAL
Program should always reset after this.
uint32_t rd_status_t
bitfield for representing errors
#define RD_STATUS_MORE_AVAILABLE
Driver has more data queued.
#define RD_ERROR_CHECK(error, mask)
Shorthand macro for calling the rd_error_check with current file & line.
#define RD_ERROR_NOT_SUPPORTED
Not supported.
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_TIMEOUT
Operation timed out.
#define RD_ERROR_SELFTEST
Self-test fail.
#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.
rd_status_t ri_gpio_interrupt_enable(const ri_gpio_id_t pin, const ri_gpio_slope_t slope, const ri_gpio_mode_t mode, const ri_gpio_interrupt_fp_t handler)
Enable interrupt on a pin.
#define RI_GPIO_INTERRUPT_TEST_TABLE_SIZE
Fixed 64 interrupt table size, adjust this if some device has more than 2 ports with 32 gpios each.
rd_status_t ri_gpio_interrupt_init(ri_gpio_interrupt_fp_t *const interrupt_table, const uint16_t max_interrupts)
Initialize interrupt functionality to GPIO. Takes address of interrupt table as a pointer to avoid ty...
void(* ri_gpio_interrupt_fp_t)(const ri_gpio_evt_t)
rd_status_t ri_gpio_interrupt_uninit(void)
Uninitialize interrupt functionality of GPIO.
rd_status_t ri_gpio_interrupt_disable(const ri_gpio_id_t pin)
Disable interrupt on a pin.
bool ri_gpio_interrupt_is_init(void)
Check if interrupt module is initialized.
void ri_log(const ri_log_severity_t severity, const char *const message)
Queues messages into log.
@ RI_LOG_LEVEL_INFO
rd_status_t(* rd_sensor_init_fp)(rd_sensor_t *const p_sensor, const rd_bus_t bus, const uint8_t handle)
Initialize and uninitialize sensor. Init and uninit will setup sensor with function pointers....
#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.
uint8_t rd_sensor_data_fieldcount(const rd_sensor_data_t *const target)
Count number of floats required for this data structure.
#define RD_SENSOR_INVALID_TIMSTAMP
Signal this timestamp value is erroneous.
rd_status_t(* rd_sensor_setup_fp)(uint8_t *parameter)
Setup a parameter of a sensor. The function will modify the pointed data to the actual value which wa...
#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.
#define RD_SENSOR_CFG_SINGLE
Sensor should go to sleep after single measurement.
#define RD_HANDLE_UNUSED
Mark sensor as unused with this handle.
void rd_sensor_data_print(const rd_sensor_data_t *const p_data, const rd_test_print_fp printfp)
Print Ruuvi Sensor data in human readable JSON.
bool rd_sensor_run_integration_test(const rd_test_print_fp printfp, rt_sensor_ctx_t *p_sensor_ctx)
void(* rd_test_print_fp)(const char *const msg)
function pointer to print test information
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
Ruuvi sensor interface Lifecycle: Beta
rd_status_t test_sensor_status(size_t *total, size_t *passed)
void test_sensor_run(void)
Run sensor integration tests.
uint16_t ri_gpio_id_t
port<<8 + pin
#define RI_GPIO_ID_UNUSED
Enable implementation selected by application.
@ RI_GPIO_MODE_INPUT_PULLUP
Input, can be read. Pulled up by internal resistor, value depends on IC.
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.
All sensors must implement configuration functions which accept this struct.
uint8_t mode
Mode, RD_SENSOR_SLEEP, _SINGLE, _CONTINOUS.
uint8_t samplerate
Samplerate, in Hz.
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_fifo_read_fp fifo_read
rd_sensor_level_interrupt_use_fp
rd_sensor_fifo_enable_fp fifo_interrupt_enable
rd_sensor_level_interrupt_use_fp
rd_sensor_level_interrupt_use_fp level_interrupt_set
rd_sensor_level_interrupt_use_fp
rd_sensor_setup_fp mode_get
rd_sensor_setup_fp
rd_sensor_setup_fp samplerate_set
rd_sensor_setup_fp
rd_sensor_fifo_enable_fp fifo_enable
rd_sensor_fifo_enable_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
rd_sensor_t sensor
Control structure for sensor.
uint8_t handle
Handle of sensor.
ri_gpio_id_t level_pin
Level interrupt.
ri_gpio_id_t fifo_pin
FIFO full interrupt.
rd_sensor_init_fp init
Initialization function.
rd_bus_t bus
Bus of sensor.
uint32_t bitfield
Bitfield used to access sensor data.