ruuvi.drivers.c ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
Loading...
Searching...
No Matches
ruuvi_interface_communication_ble_advertising_test.c
Go to the documentation of this file.
2#if RUUVI_RUN_TESTS
4#include "ruuvi_driver_test.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
35static ri_comm_channel_t m_channel;
36static volatile bool m_has_connected;
37static volatile bool m_has_disconnected;
38static volatile bool m_has_sent;
39static volatile bool m_has_received;
40static volatile bool m_timeout;
41
42static 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.
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
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
87static 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
94static 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
102static 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
109static 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);
141 return status;
142}
143
153static 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
160static 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
167static 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
207static 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;
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
240static 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;
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
280static 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
287static 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
293static 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
355static 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.