ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ruuvi_interface_communication_uart_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"
8 #include "ruuvi_interface_rtc.h"
10 #include <stdbool.h>
11 #include <string.h>
12 #include <stdio.h>
13 
27 static ri_comm_channel_t m_channel;
28 static uint8_t m_has_sent;
29 static uint8_t m_has_received;
30 static ri_comm_message_t rx_data;
31 
32 static rd_status_t uart_isr (ri_comm_evt_t evt,
33  void * p_data, size_t data_len)
34 {
35  switch (evt)
36  {
37  case RI_COMM_CONNECTED:
38  // Will never trigger on UART
39  break;
40 
42  // Will never trigger on UART
43  break;
44 
45  case RI_COMM_SENT:
46  m_has_sent++;
47  break;
48 
49  case RI_COMM_RECEIVED:
50  m_has_received++;
52  m_channel.read (&rx_data);
53  break;
54 
55  default:
56  break;
57  }
58 
59  return RD_SUCCESS;
60 }
61 
62 /*
63  * Initializes UART hardware.
64  *
65  * @retval RD_SUCCESS on success,
66  * @retval RD_ERROR_INVALID_STATE if UART is already initialized
67  */
68 static bool ri_uart_init_test (const rd_test_print_fp printfp)
69 {
70  bool status = false;
71  rd_status_t err_code = RD_SUCCESS;
72  printfp ("\"init\":");
73  err_code |= ri_uart_init (&m_channel);
74 
75  if (RD_SUCCESS == err_code)
76  {
77  err_code |= ri_uart_init (&m_channel);
78 
79  if (RD_ERROR_INVALID_STATE == err_code)
80  {
81  err_code = ri_uart_uninit (&m_channel);
82  err_code = ri_uart_init (&m_channel);
83 
84  if (RD_SUCCESS != err_code)
85  {
86  status = true;
87  }
88  }
89  else
90  {
91  status = true;
92  }
93  }
94  else
95  {
96  status = true;
97  }
98 
99  if (status)
100  {
101  printfp ("\"fail\",\r\n");
102  }
103  else
104  {
105  printfp ("\"pass\",\r\n");
106  }
107 
108  ri_uart_uninit (&m_channel);
109  return status;
110 }
111 
112 static rd_status_t uart_init_test (const ri_gpio_id_t input,
113  const ri_gpio_id_t output)
114 {
115  rd_status_t err_code = RD_SUCCESS;
116  m_has_sent = false;
117  m_has_received = false;
118  memset (&rx_data, 0, sizeof (rx_data));
119  ri_uart_init_t config =
120  {
121  .hwfc_enabled = false,
122  .parity_enabled = false,
123  .cts = RI_GPIO_ID_UNUSED,
124  .rts = RI_GPIO_ID_UNUSED,
125  .tx = output,
126  .rx = input,
127  .baud = RI_UART_BAUD_115200
128  };
129  err_code |= ri_uart_init (&m_channel);
130  m_channel.on_evt = uart_isr;
131  // TODO: Test different baudrates, parities etc.
132  err_code |= ri_uart_config (&config);
133  return err_code;
134 }
135 
136 static bool uart_run_test (const char * const test_data)
137 {
138  bool status = false;
139  bool timeout = false;
140  m_has_sent = false;
141  m_has_received = false;
142  memset (&rx_data, 0, sizeof (rx_data));
143  rd_status_t err_code = RD_SUCCESS;
144  ri_comm_message_t msg = { 0 };
145  msg.repeat_count = 1;
146  size_t written = 0;
147  written = snprintf ( (char *) & msg.data, RI_COMM_MESSAGE_MAX_LENGTH, "%s", test_data);
148  msg.data_length = (written > RI_COMM_MESSAGE_MAX_LENGTH)
149  ? RI_COMM_MESSAGE_MAX_LENGTH : written;
150  ri_rtc_init();
151  err_code |= m_channel.send (&msg);
152 
153  while (! (m_has_sent && m_has_received)
154  && (!timeout))
155  {
157  {
158  timeout = true;
159  }
160  }
161 
162  if ( (RD_SUCCESS != err_code)
163  || memcmp (&rx_data, &msg, sizeof (ri_comm_message_t))
164  || timeout
165  || (m_has_received != 1))
166  {
167  status = true;
168  }
169 
170  ri_rtc_uninit();
171  return status;
172 }
173 
177 bool ri_uart_tx_test (const rd_test_print_fp printfp, const ri_gpio_id_t input,
178  const ri_gpio_id_t output)
179 {
180  bool status = false;
181  rd_status_t err_code = RD_SUCCESS;
182  printfp ("\"tx_rx\":");
183  err_code |= uart_init_test (input, output);
184  char test_data[] =
185  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor"
186  " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis "
187  "nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
188  "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu "
189  "fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
190  "sunt in culpa qui officia deserunt mollit anim id est laborum";
191  test_data[RI_COMM_MESSAGE_MAX_LENGTH] = '\n';
192 
193  if (RD_SUCCESS == err_code)
194  {
195  status |= uart_run_test (test_data);
196  }
197  else
198  {
199  status = true;
200  }
201 
202  if (status)
203  {
204  printfp ("\"fail\",\r\n");
205  }
206  else
207  {
208  printfp ("\"pass\",\r\n");
209  }
210 
211  (void) ri_uart_uninit (&m_channel);
212  return status;
213 }
214 
218 bool ri_uart_rx_test (const rd_test_print_fp printfp, const ri_gpio_id_t input,
219  const ri_gpio_id_t output)
220 {
221  bool status = false;
222  bool timeout = false;
223  m_has_sent = 0;
224  m_has_received = 0;
225  rd_status_t err_code = RD_SUCCESS;
226  printfp ("\"rx_corrupt\":");
227  err_code |= uart_init_test (input, output);
228  const char test_data[] =
229  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "
230  "incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis "
231  "nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
232  "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu "
233  "fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in "
234  "culpa qui officia deserunt mollit anim id est laborum\n";
235  ri_comm_message_t msg = { 0 };
236  msg.repeat_count = 1;
237  memcpy (msg.data, test_data, RI_COMM_MESSAGE_MAX_LENGTH);
239 
240  if (RD_SUCCESS == err_code)
241  {
242  m_channel.on_evt = uart_isr;
243  ri_rtc_init();
244  err_code |= m_channel.send (&msg);
245 
246  while (! (m_has_sent && m_has_received)
247  && (!timeout))
248  {
250  {
251  timeout = true;
252  }
253  }
254 
255  size_t written = snprintf ( (char *) msg.data, RI_COMM_MESSAGE_MAX_LENGTH, "%s",
256  test_data + RI_COMM_MESSAGE_MAX_LENGTH);
257  msg.data_length = written;
258  const char * cutoff_index = test_data + strlen (test_data) - written;
259  memset (&rx_data, 0, sizeof (rx_data));
260  err_code |= m_channel.send (&msg);
261 
262  while ( ( (m_has_sent < 2) && (m_has_received < 2))
263  && (!timeout))
264  {
266  {
267  timeout = true;
268  }
269  }
270 
271  if ( (RD_SUCCESS != err_code)
272  || memcmp (&rx_data.data, cutoff_index, rx_data.data_length)
273  || timeout
274  || (m_has_received != 2)
275  || (m_has_sent != 2))
276  {
277  status = true;
278  }
279 
280  (void) ri_rtc_uninit();
281  }
282  else
283  {
284  status = true;
285  }
286 
287  if (status)
288  {
289  printfp ("\"fail\",\r\n");
290  }
291  else
292  {
293  printfp ("\"pass\",\r\n");
294  }
295 
296  (void) ri_uart_uninit (&m_channel);
297  return status;
298 }
299 
300 bool ri_uart_rx_short_test (const rd_test_print_fp printfp, const ri_gpio_id_t input,
301  const ri_gpio_id_t output)
302 {
303  bool status = false;
304  rd_status_t err_code = RD_SUCCESS;
305  printfp ("\"rx_short\":");
306  err_code |= uart_init_test (input, output);
307  const char test_data[] = "Lorem ipsum dolor sit amet\n";
308 
309  if (RD_SUCCESS == err_code)
310  {
311  status |= uart_run_test (test_data);
312  }
313  else
314  {
315  status = true;
316  }
317 
318  if (status)
319  {
320  printfp ("\"fail\"\r\n");
321  }
322  else
323  {
324  printfp ("\"pass\"\r\n");
325  }
326 
327  (void) ri_uart_uninit (&m_channel);
328  return status;
329 }
330 
332  const ri_gpio_id_t input, const ri_gpio_id_t output)
333 {
334  rd_status_t status = false;
335  printfp ("\"uart\":{\r\n");
336  status |= ri_uart_init_test (printfp);
337  status |= ri_uart_tx_test (printfp, input, output);
338  status |= ri_uart_rx_test (printfp, input, output);
339  status |= ri_uart_rx_short_test (printfp, input, output);
340  printfp ("},\r\n");
341  return status;
342 }
343 #endif
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.
bool ri_communication_uart_run_integration_test(const rd_test_print_fp printfp, const ri_gpio_id_t input, const ri_gpio_id_t output)
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.
#define RI_COMM_MESSAGE_MAX_LENGTH
The maximum length for the application message for sending over BLE, which depends on whether extende...
ri_comm_evt_t
Communication event type.
@ 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.
@ RI_UART_BAUD_115200
Run at 115200 baud.
rd_status_t ri_uart_uninit(ri_comm_channel_t *const channel)
rd_status_t ri_uart_config(const ri_uart_init_t *const config)
Configure UART.
rd_status_t ri_uart_init(ri_comm_channel_t *const channel)
Initialize UART.
#define TEST_TIMEOUT_MS
If TX/RX test not ready in this time, fail.
uint16_t ri_gpio_id_t
port<<8 + pin
#define RI_GPIO_ID_UNUSED
Enable implementation selected by application.
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.
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.
ri_comm_xfer_fp_t read
Asynchronous read 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.
UART initialization data.
bool hwfc_enabled
True to enable hardware flow control.