ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ruuvi_interface_communication_ble_advertising_test.c
Go to the documentation of this file.
2 #if RUUVI_RUN_TESTS
3 #include "ruuvi_driver_error.h"
4 #include "ruuvi_driver_test.h"
9 #include "ruuvi_interface_rtc.h"
10 #include "ruuvi_interface_yield.h"
11 #include <stdbool.h>
12 #include <string.h>
13 #include <stdio.h>
14 
15 #define TEST_STRING "Ave mundi!"
16 #define EXTENDED_STRING "Lorem ipsum dolor sit amet, consectetur adipiscing elit."\
17  " Donec nisl "\
18  "ligula, lacinia malesuada pellentesque molestie, venenatis "\
19  "non neque. Cras eget ligula eget nunc pharetra tincidunt. "\
20  "Etiam volutpat."
21 
35 static ri_comm_channel_t m_channel;
36 static volatile bool m_has_connected;
37 static volatile bool m_has_disconnected;
38 static volatile bool m_has_sent;
39 static volatile bool m_has_received;
40 static volatile bool m_timeout;
41 
42 static rd_status_t ble_isr (ri_comm_evt_t evt,
43  void * p_data, size_t data_len)
44 {
45  switch (evt)
46  {
47  // Note: This gets called only after the NFC notifications have been registered.
48  case RI_COMM_CONNECTED:
49  m_has_connected = true;
50  break;
51 
53  m_has_disconnected = true;
54  break;
55 
56  case RI_COMM_SENT:
57  m_has_sent = true;
58  break;
59 
60  case RI_COMM_RECEIVED:
61  m_has_received = true;
62  break;
63 
64  case RI_COMM_TIMEOUT:
65  m_timeout = true;
66  break;
67 
68  default:
69  break;
70  }
71 
72  return RD_SUCCESS;
73 }
74 
75 
87 static bool ri_adv_init_null_test (void)
88 {
89  rd_status_t err_code = RD_SUCCESS;
90  err_code |= ri_adv_init (NULL);
91  return (RD_ERROR_NULL != err_code);
92 }
93 
94 static bool ri_adv_init_twice_test (void)
95 {
96  rd_status_t err_code = RD_SUCCESS;
97  err_code |= ri_adv_init (&m_channel);
98  err_code |= ri_adv_init (&m_channel);
99  return (RD_ERROR_INVALID_STATE != err_code);
100 }
101 
102 static bool ri_adv_init_norad_test (void)
103 {
104  rd_status_t err_code = RD_SUCCESS;
105  err_code |= ri_adv_init (&m_channel);
106  return (RD_ERROR_INVALID_STATE != err_code);
107 }
108 
109 static bool ri_adv_init_test (const rd_test_print_fp printfp,
110  const ri_radio_modulation_t modulation)
111 {
112  bool status = false;
113  rd_status_t err_code = RD_SUCCESS;
114  printfp ("\"init\":");
115  status |= ri_adv_init_norad_test();
116  err_code |= ri_radio_init (modulation);
117  err_code |= ri_adv_init (&m_channel);
118  err_code |= ri_adv_uninit (&m_channel);
119 
120  if (RD_SUCCESS == err_code)
121  {
122  status |= ri_adv_init_null_test();
123  status |= ri_adv_init_twice_test();
124  }
125  else
126  {
127  status |= true;
128  }
129 
130  if (status)
131  {
132  printfp ("\"fail\",\r\n");
133  }
134  else
135  {
136  printfp ("\"pass\",\r\n");
137  }
138 
139  ri_adv_uninit (&m_channel);
140  ri_radio_uninit();
141  return status;
142 }
143 
153 static bool ri_adv_interval_short_test (void)
154 {
155  rd_status_t err_code = RD_SUCCESS;
157  return (RD_ERROR_INVALID_PARAM != err_code);
158 }
159 
160 static bool ri_adv_interval_long_test (void)
161 {
162  rd_status_t err_code = RD_SUCCESS;
164  return (RD_ERROR_INVALID_PARAM != err_code);
165 }
166 
167 static bool ri_adv_tx_test (ri_comm_message_t * const msg)
168 {
169  rd_status_t err_code = RD_SUCCESS;
170  uint32_t interval = 0;
171  bool status = false;
173 
174  if (RD_SUCCESS == err_code)
175  {
176  m_has_sent = false;
177  m_channel.send (msg);
178  uint64_t start = ri_rtc_millis();
179 
180  while (!m_has_sent
181  && (ri_rtc_millis() - start) < (RI_TEST_ADV_FAST * msg->repeat_count))
182  {
183  ri_yield();
184  }
185 
186  uint64_t end = ri_rtc_millis();
187 
188  if ( (RI_TEST_ADV_FAST > (end - start))
189  || (RI_TEST_ADV_FAST * (msg->repeat_count - 1) + (2 * RI_ADV_RND_DELAY)) < (end - start))
190  {
191  status = true;
192  }
193  }
194  else
195  {
196  status = true;
197  }
198 
199  err_code |= ri_adv_tx_interval_get (NULL);
200  status |= (RD_ERROR_NULL != err_code);
201  err_code = ri_adv_tx_interval_get (&interval);
202  status |= (RD_SUCCESS != err_code);
203  status |= (RI_TEST_ADV_FAST != interval);
204  return status;
205 }
206 
207 static bool ri_adv_interval_test (const rd_test_print_fp printfp,
208  const ri_radio_modulation_t modulation)
209 {
210  bool status = false;
211  rd_status_t err_code = RD_SUCCESS;
212  ri_comm_message_t msg;
213  msg.repeat_count = 2;
214  snprintf ( (char *) & (msg.data), sizeof (msg.data), TEST_STRING);
215  msg.data_length = strlen (TEST_STRING);
216  printfp ("\"interval\":");
217  err_code |= ri_rtc_init();
218  err_code |= ri_radio_init (modulation);
219  err_code |= ri_adv_init (&m_channel);
220  m_channel.on_evt = &ble_isr;
221  status |= ri_adv_interval_short_test();
222  status |= ri_adv_interval_long_test();
223  status |= ri_adv_tx_test (&msg);
224 
225  if (status)
226  {
227  printfp ("\"fail\",\r\n");
228  }
229  else
230  {
231  printfp ("\"pass\",\r\n");
232  }
233 
234  (void) ri_rtc_uninit();
235  (void) ri_adv_uninit (&m_channel);
236  (void) ri_radio_uninit();
237  return status;
238 }
239 
240 static bool ri_adv_extended_test (const rd_test_print_fp printfp,
241  const ri_radio_modulation_t modulation)
242 {
243  bool status = false;
244  rd_status_t err_code = RD_SUCCESS;
245  ri_comm_message_t msg;
246  msg.repeat_count = 2;
247  snprintf ( (char *) & (msg.data), sizeof (msg.data), EXTENDED_STRING);
248  msg.data_length = strlen (EXTENDED_STRING);
249  printfp ("\"extended\":");
250  err_code |= ri_rtc_init();
251  err_code |= ri_radio_init (modulation);
252  err_code |= ri_adv_init (&m_channel);
253  m_channel.on_evt = &ble_isr;
254  status |= ri_adv_tx_test (&msg);
255 
256  if (status)
257  {
258  printfp ("\"fail\",\r\n");
259  }
260  else
261  {
262  printfp ("\"pass\",\r\n");
263  }
264 
265  (void) ri_rtc_uninit();
266  (void) ri_adv_uninit (&m_channel);
267  (void) ri_radio_uninit();
268  return status;
269 }
270 
280 static bool ri_adv_pwr_test_noinit (void)
281 {
282  int8_t pwr = 0;
283  rd_status_t err_code = ri_adv_tx_power_set (&pwr);
284  return (RD_ERROR_INVALID_STATE != err_code);
285 }
286 
287 static bool ri_adv_pwr_test_null (void)
288 {
289  rd_status_t err_code = ri_adv_tx_power_set (NULL);
290  return (RD_ERROR_NULL != err_code);
291 }
292 
293 static bool ri_adv_power_test (const rd_test_print_fp printfp,
294  const ri_radio_modulation_t modulation)
295 {
296  rd_status_t err_code = RD_SUCCESS;
297  bool status = false;
298  printfp ("\"power\":");
299  int8_t pwr = -127;
300  int8_t original = pwr;
301  status |= ri_adv_pwr_test_noinit();
302  err_code |= ri_radio_init (modulation);
303  err_code |= ri_adv_init (&m_channel);
304  status |= ri_adv_pwr_test_null();
305  err_code = ri_adv_tx_power_set (&pwr);
306  // pwr should be updated.
307  status |= (original == pwr);
308  original = pwr;
309  pwr = 126;
310  // Check invalid param.
311  err_code = ri_adv_tx_power_set (&pwr);
312  status |= (RD_ERROR_INVALID_PARAM != err_code);
313  // Check that power was not modified with invalid param.
314  err_code = ri_adv_tx_power_get (&pwr);
315  status |= (original != pwr);
316 
317  if (status)
318  {
319  printfp ("\"fail\",\r\n");
320  }
321  else
322  {
323  printfp ("\"pass\",\r\n");
324  }
325 
326  (void) ri_adv_uninit (&m_channel);
327  (void) ri_radio_uninit();
328  return status;
329 }
330 
355 static bool ri_adv_rx_interval_test (const rd_test_print_fp printfp,
356  const ri_radio_modulation_t modulation)
357 {
358  bool status = false;
359  rd_status_t err_code = RD_SUCCESS;
360  uint64_t test_start = 0;
361  uint64_t test_end = 0;
362  printfp ("\"scan\":");
363  err_code |= ri_rtc_init();
364  err_code |= ri_radio_init (modulation);
365  err_code |= ri_adv_init (&m_channel);
366  m_channel.on_evt = ble_isr;
367  m_timeout = false;
368  m_has_received;
369  test_start = ri_rtc_millis();
372 
373  while (!m_timeout
375  test_start))
376  {
377  // Sleep - woken up on event
378  // ri_yield();
379  // Prevent loop being optimized away
380  __asm__ ("");
381  }
382 
383  test_end = ri_rtc_millis();
384  const uint32_t test_min_ms = (RI_TEST_ADV_SCAN_CH_NUM - 1U) * RI_TEST_ADV_SCAN_INTERVAL;
385  const uint32_t test_max_ms = (RI_TEST_ADV_SCAN_CH_NUM * RI_TEST_ADV_SCAN_INTERVAL) + 5U;
386  const uint32_t test_time_ms = (test_end - test_start);
387 
388  // Fail if:
389  // * Scanned less than (number of channels - 1) * interval + 1 scan window
390  // - can timeout immediately after last scan window, not waiting for interval.
391  // * Scanned more than number if intervals + 1 scan window. Must finish asap, but
392  // allow a little margin.
393  // * Error code was returned.
394  // * No advertisements were seen.
395  // * Advertising didn't timeout at all.
396  if ( (test_min_ms > test_time_ms)
397  || (test_max_ms < test_time_ms)
398  || (RD_SUCCESS != err_code)
399  || (!m_has_received)
400  || (!m_timeout))
401  {
402  status = true;
403  }
404 
405  if (status)
406  {
407  printfp ("\"fail\"\r\n");
408  }
409  else
410  {
411  printfp ("\"pass\"\r\n");
412  }
413 
414  (void) ri_rtc_uninit();
415  (void) ri_adv_uninit (&m_channel);
416  (void) ri_radio_uninit();
417  return status;
418 }
419 
434 //rd_status_t ri_adv_scan_response_setup (const char * const name,
435 // const bool advertise_nus);
436 
447 //rd_status_t ri_adv_type_set (ri_adv_type_t type);
448 
466 
468  printfp,
469  const ri_radio_modulation_t modulation)
470 {
471  bool status = false;
472  printfp ("\"ble_adv_");
473  print_modulation (printfp, modulation);
474  printfp ("\":{\r\n");
475  status |= ri_adv_init_test (printfp, modulation);
476  status |= ri_adv_interval_test (printfp, modulation);
477  status |= ri_adv_extended_test (printfp, modulation);
478  status |= ri_adv_power_test (printfp, modulation);
479  status |= ri_adv_rx_interval_test (printfp, modulation);
480  printfp ("},\r\n");
481  return status;
482 }
483 
484 #endif
#define RI_TEST_ADV_TOO_FAST
Interval shorter than allowed for non-connectable advertising.
bool ri_communication_ble_advertising_run_integration_test(const rd_test_print_fp printfp, const ri_radio_modulation_t modulation)
Run advertising test.
#define RI_TEST_ADV_SCAN_INTERVAL
Scan interval for test.
#define RI_TEST_ADV_SCAN_CH_NUM
Number of channels to scan.
#define RI_TEST_ADV_FAST
Fastest allowed interval for connectable advertising.
#define RI_TEST_ADV_TOO_SLOW
Interval longer than allowed for non-connectable advertising.
#define RI_ADV_RND_DELAY
Maximum random delay in adv interval.
#define RI_TEST_ADV_SCAN_WINDOW
Scan window for test.
#define RD_ERROR_INVALID_PARAM
Invalid Parameter.
#define RD_ERROR_NULL
Null Pointer.
uint32_t rd_status_t
bitfield for representing errors
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
void print_modulation(const rd_test_print_fp printfp, const ri_radio_modulation_t modulation)
Print used modulation to printfp.
rd_status_t ri_radio_init(const ri_radio_modulation_t modulation)
Enable radio stack for an user. This function also starts radio activity callbacks internally.
rd_status_t ri_radio_uninit()
Release radio stack.
ri_radio_modulation_t
type of radio modulation to be used.
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.
Functions for testing drivers.
ri_comm_evt_t
Communication event type.
@ RI_COMM_TIMEOUT
Operation timed out.
@ RI_COMM_CONNECTED
Connection established, OK to send, may receive data.
@ RI_COMM_RECEIVED
New data received, available to read with read function.
@ RI_COMM_SENT
One queued message was sent with all repetitions.
@ RI_COMM_DISCONNECTED
Connection lost, cannot send, may not receive data.
rd_status_t ri_adv_scan_start(const uint32_t window_interval_ms, const uint32_t window_size_ms)
setup scan window interval and window size.
rd_status_t ri_adv_tx_power_get(int8_t *dbm)
Get radio TX power.
rd_status_t ri_adv_init(ri_comm_channel_t *const channel)
Initialize Advertising module and scanning module.
rd_status_t ri_adv_tx_interval_get(uint32_t *ms)
Getter for broadcast advertisement interval.
rd_status_t ri_adv_uninit(ri_comm_channel_t *const channel)
rd_status_t ri_adv_tx_interval_set(const uint32_t ms)
rd_status_t ri_adv_tx_power_set(int8_t *dbm)
Set radio TX power.
rd_status_t ri_adv_scan_stop(void)
Stop ongoing scanning.
rd_status_t ri_rtc_init(void)
Initializes RTC at 0 ms.
rd_status_t ri_rtc_uninit(void)
Stop RTC if applicable.
uint64_t ri_rtc_millis(void)
Get milliseconds since init.
rd_status_t ri_yield(void)
Function which will release execution.
control API for communication via outside world
ri_comm_evt_handler_fp_t on_evt
Callback to application-level event handler, must be set in application.
ri_comm_xfer_fp_t send
Asynchronous send function.
Application message structure used for communication.
uint8_t data[RI_COMM_MESSAGE_MAX_LENGTH]
Data payload.
uint8_t repeat_count
Number of times to repeat the message,.
uint8_t data_length
Length of data.