Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_atci.c
1 #include <bc_atci.h>
2 #include <bc_scheduler.h>
3 #include <bc_system.h>
4 
5 static void _bc_atci_uart_event_handler(bc_uart_channel_t channel, bc_uart_event_t event, void *event_param);
6 static void _bc_atci_uart_active_test(void);
7 static void _bc_atci_uart_active_test_task(void *param);
8 
9 static struct
10 {
11  const bc_atci_command_t *commands;
12  size_t commands_length;
13  char tx_buffer[256];
14  char rx_buffer[256];
15  size_t rx_length;
16  bool rx_error;
17  uint8_t read_fifo_buffer[128];
18  bc_fifo_t read_fifo;
19  bc_scheduler_task_id_t vbus_sense_test_task_id;
20  bool ready;
21  bool (*uart_active_callback)(void);
22  bc_tick_t scan_interval;
23  bool write_response;
24 
25 } _bc_atci;
26 
27 void bc_atci_init(const bc_atci_command_t *commands, int length)
28 {
29  memset(&_bc_atci, 0, sizeof(_bc_atci));
30 
31  _bc_atci.commands = commands;
32 
33  _bc_atci.commands_length = length;
34 
35  _bc_atci.rx_length = 0;
36 
37  _bc_atci.rx_error = false;
38 
39  _bc_atci.write_response = true;
40 
41  bc_fifo_init(&_bc_atci.read_fifo, _bc_atci.read_fifo_buffer, sizeof(_bc_atci.read_fifo_buffer));
42 
43  bc_atci_set_uart_active_callback(bc_system_get_vbus_sense, 200);
44 }
45 
46 void bc_atci_printf(const char *format, ...)
47 {
48  if (!_bc_atci.ready)
49  {
50  return;
51  }
52 
53  va_list ap;
54 
55  size_t length;
56 
57  va_start(ap, format);
58 
59  length = vsnprintf(_bc_atci.tx_buffer, sizeof(_bc_atci.tx_buffer) - 2, format, ap);
60 
61  va_end(ap);
62 
63  _bc_atci.tx_buffer[length++] = '\r';
64  _bc_atci.tx_buffer[length++] = '\n';
65 
66  bc_uart_write(BC_ATCI_UART, _bc_atci.tx_buffer, length);
67 }
68 
70 {
71  _bc_atci.write_response = false;
72 
73  return true;
74 }
75 
76 void bc_atci_write_ok(void)
77 {
78  bc_uart_write(BC_ATCI_UART, "OK\r\n", 4);
79 }
80 
82 {
83  bc_uart_write(BC_ATCI_UART, "ERROR\r\n", 7);
84 }
85 
87 {
88  for (size_t i = 0; i < _bc_atci.commands_length; i++)
89  {
90  bc_atci_printf("AT%s", _bc_atci.commands[i].command);
91  }
92  return true;
93 }
94 
96 {
97  for (size_t i = 0; i < _bc_atci.commands_length; i++)
98  {
99  bc_atci_printf("AT%s %s", _bc_atci.commands[i].command, _bc_atci.commands[i].hint);
100  }
101  return true;
102 }
103 
104 static bool _bc_atci_process_line(void)
105 {
106  if (_bc_atci.rx_length < 2 || _bc_atci.rx_buffer[0] != 'A' || _bc_atci.rx_buffer[1] != 'T')
107  {
108  return false;
109  }
110 
111  if (_bc_atci.rx_length == 2)
112  {
113  return true;
114  }
115 
116  _bc_atci.rx_buffer[_bc_atci.rx_length] = 0;
117 
118  char *line = _bc_atci.rx_buffer + 2;
119 
120  size_t length = _bc_atci.rx_length - 2;
121 
122  size_t command_len;
123 
124  const bc_atci_command_t *command;
125 
126  for (size_t i = 0; i < _bc_atci.commands_length; i++)
127  {
128  command = _bc_atci.commands + i;
129 
130  command_len = strlen(command->command);
131 
132  if (length < command_len)
133  {
134  continue;
135  }
136 
137  if (strncmp(line, command->command, command_len) != 0)
138  {
139  continue;
140  }
141 
142  if (command_len == length)
143  {
144  if (command->action != NULL)
145  {
146  return command->action();
147  }
148  }
149  else if (line[command_len] == '=')
150  {
151  if ((line[command_len + 1]) == '?' && (command_len + 2 == length))
152  {
153  if (command->help != NULL)
154  {
155  return command->help();
156  }
157  }
158 
159  if (command->set != NULL)
160  {
161  bc_atci_param_t param = {
162  .txt = line + command_len + 1,
163  .length = length - command_len - 1,
164  .offset = 0
165  };
166 
167  return command->set(&param);
168  }
169  }
170  else if (line[command_len] == '?' && command_len + 1 == length)
171  {
172  if (command->read != NULL)
173  {
174  return command->read();
175  }
176  }
177  else
178  {
179  return false;
180  }
181 
182  break;
183  }
184 
185  return false;
186 }
187 
188 static void _bc_atci_process_character(char character)
189 {
190  if (character == '\n')
191  {
192  if (!_bc_atci.rx_error && _bc_atci.rx_length > 0)
193  {
194  bool response = _bc_atci_process_line();
195 
196  if (_bc_atci.write_response)
197  {
198  if (response)
199  {
201  }
202  else
203  {
205  }
206  }
207  else
208  {
209  _bc_atci.write_response = true;
210  }
211  }
212  else if (_bc_atci.rx_error)
213  {
215  }
216 
217  _bc_atci.rx_length = 0;
218  _bc_atci.rx_error = false;
219  }
220  else if (character == '\r')
221  {
222  return;
223  }
224  else if (character == '\x1b')
225  {
226  _bc_atci.rx_length = 0;
227  _bc_atci.rx_error = false;
228  }
229  else if (_bc_atci.rx_length == sizeof(_bc_atci.rx_buffer) - 1)
230  {
231  _bc_atci.rx_error = true;
232  }
233  else if (!_bc_atci.rx_error)
234  {
235  _bc_atci.rx_buffer[_bc_atci.rx_length++] = character;
236  }
237 }
238 
239 static void _bc_atci_uart_event_handler(bc_uart_channel_t channel, bc_uart_event_t event, void *event_param)
240 {
241  (void) channel;
242  (void) event_param;
243 
244  if (event == BC_UART_EVENT_ASYNC_READ_DATA)
245  {
246  while (true)
247  {
248  static uint8_t buffer[16];
249 
250  size_t length = bc_uart_async_read(BC_ATCI_UART, buffer, sizeof(buffer));
251 
252  if (length == 0)
253  {
254  break;
255  }
256 
257  for (size_t i = 0; i < length; i++)
258  {
259  _bc_atci_process_character((char) buffer[i]);
260  }
261  }
262  }
263 }
264 
265 bool bc_atci_get_uint(bc_atci_param_t *param, uint32_t *value)
266 {
267  char c;
268 
269  *value = 0;
270 
271  while (param->offset < param->length)
272  {
273  c = param->txt[param->offset];
274 
275  if (isdigit(c))
276  {
277  *value *= 10;
278  *value += c - '0';
279  }
280  else
281  {
282  if (c == ',')
283  {
284  return true;
285  }
286  return false;
287  }
288 
289  param->offset++;
290  }
291 
292  return true;
293 }
294 
295 bool bc_atci_get_string(bc_atci_param_t *param, char *str, size_t length)
296 {
297  if (((param->length - param->offset) < 2) || (length < 1) || (str == NULL))
298  {
299  return false;
300  }
301 
302  if (param->txt[param->offset++] != '"')
303  {
304  return false;
305  }
306 
307  char c;
308  size_t i;
309 
310  for (i = 0; (i < length) && (param->offset < param->length); i++)
311  {
312  c = param->txt[param->offset++];
313 
314  if (c == '"')
315  {
316  str[i] = 0;
317 
318  return true;
319  }
320 
321  if ((c < ' ') || (c == ',') || (c > '~'))
322  {
323  return false;
324  }
325 
326  str[i] = c;
327  }
328 
329  return false;
330 }
331 
332 bool bc_atci_get_buffer_from_hex_string(bc_atci_param_t *param, void *buffer, size_t *length)
333 {
334  if (((param->length - param->offset) < 2) || (*length < 1) || (buffer == NULL))
335  {
336  return false;
337  }
338 
339  if (param->txt[param->offset++] != '"')
340  {
341  return false;
342  }
343 
344  char c;
345  size_t i;
346  size_t max_i = *length * 2;
347  uint8_t temp;
348  size_t l = 0;
349 
350  for (i = 0; (i < max_i) && (param->offset < param->length); i++)
351  {
352  c = param->txt[param->offset++];
353 
354  if (c == '"')
355  {
356  *length = l;
357 
358  return true;
359  }
360 
361  if ((c >= '0') && (c <= '9'))
362  {
363  temp = c - '0';
364  }
365  else if ((c >= 'A') && (c <= 'F'))
366  {
367  temp = c - 'A' + 10;
368  }
369  else if ((c >= 'a') && (c <= 'f'))
370  {
371  temp = c - 'a' + 10;
372  }
373  else
374  {
375  return false;
376  }
377 
378  if (i % 2 == 0)
379  {
380  if (l == *length)
381  {
382  return false;
383  }
384 
385  ((uint8_t *) buffer)[l] = temp << 4;
386  }
387  else
388  {
389  ((uint8_t *) buffer)[l++] |= temp;
390  }
391  }
392 
393  return false;
394 }
395 
397 {
398  return param->txt[param->offset++] == ',';
399 }
400 
402 {
403  return param->txt[param->offset++] == '"';
404 }
405 
406 void bc_atci_set_uart_active_callback(bool(*callback)(void), bc_tick_t scan_interval)
407 {
408  _bc_atci.uart_active_callback = callback;
409  _bc_atci.scan_interval = scan_interval;
410 
411  if (callback == NULL)
412  {
413  if (_bc_atci.vbus_sense_test_task_id)
414  {
415  bc_scheduler_unregister(_bc_atci.vbus_sense_test_task_id);
416 
417  _bc_atci.vbus_sense_test_task_id = 0;
418  }
419  }
420  else
421  {
422  if (_bc_atci.vbus_sense_test_task_id == 0)
423  {
424  _bc_atci.vbus_sense_test_task_id = bc_scheduler_register(_bc_atci_uart_active_test_task, NULL, scan_interval);
425  }
426  }
427 
428  _bc_atci_uart_active_test();
429 }
430 
431 static void _bc_atci_uart_active_test(void)
432 {
433  if ((_bc_atci.uart_active_callback == NULL) || _bc_atci.uart_active_callback())
434  {
435  if (!_bc_atci.ready)
436  {
438 
439  bc_uart_set_async_fifo(BC_ATCI_UART, NULL, &_bc_atci.read_fifo);
440 
441  bc_uart_set_event_handler(BC_ATCI_UART, _bc_atci_uart_event_handler, NULL);
442 
443  bc_uart_async_read_start(BC_ATCI_UART, 1000);
444 
445  _bc_atci.ready = true;
446 
447  bc_uart_write(BC_ATCI_UART, "\r\n", 2);
448  }
449  }
450  else
451  {
452  if (_bc_atci.ready)
453  {
454  _bc_atci.ready = false;
455 
456  bc_uart_deinit(BC_ATCI_UART);
457  }
458  }
459 }
460 
461 static void _bc_atci_uart_active_test_task(void *param)
462 {
463  (void) param;
464 
465  _bc_atci_uart_active_test();
466 
467  bc_scheduler_plan_current_relative(_bc_atci.scan_interval);
468 }
bool bc_atci_get_buffer_from_hex_string(bc_atci_param_t *param, void *buffer, size_t *length)
Decode HEX string to buffer and move parsing cursor forward.
Definition: bc_atci.c:332
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
bool bc_atci_get_uint(bc_atci_param_t *param, uint32_t *value)
Parse string to uint and move parsing cursor forward.
Definition: bc_atci.c:265
bool bc_atci_is_quotation_mark(bc_atci_param_t *param)
Check if the character at cursor is quotation mark (")
Definition: bc_atci.c:401
bc_uart_channel_t
UART channels.
Definition: bc_uart.h:13
Structure of FIFO instance.
Definition: bc_fifo.h:12
bool bc_atci_get_string(bc_atci_param_t *param, char *str, size_t length)
Copy string and move parsing cursor forward.
Definition: bc_atci.c:295
bool bc_uart_async_read_start(bc_uart_channel_t channel, bc_tick_t timeout)
Start async reading.
Definition: bc_uart.c:475
Event is reading done.
Definition: bc_uart.h:133
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
8N1: 8 data bits, none parity bit, 1 stop bit
Definition: bc_uart.h:70
void bc_atci_set_uart_active_callback(bool(*callback)(void), bc_tick_t scan_interval)
Set callback function for scan if uart is active. Used for low-power when USB is disconnected (defaul...
Definition: bc_atci.c:406
bool bc_atci_help_action(void)
Helper for help action.
Definition: bc_atci.c:95
void bc_uart_init(bc_uart_channel_t channel, bc_uart_baudrate_t baudrate, bc_uart_setting_t setting)
Initialize UART channel.
Definition: bc_uart.c:53
void bc_scheduler_plan_current_relative(bc_tick_t tick)
Schedule current task to tick relative from current spin.
Definition: bc_scheduler.c:149
bc_uart_event_t
Callback events.
Definition: bc_uart.h:127
bool bc_atci_clac_action(void)
Helper for clac action.
Definition: bc_atci.c:86
size_t bc_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: bc_scheduler.h:18
void bc_uart_deinit(bc_uart_channel_t channel)
Deinitialize UART channel.
Definition: bc_uart.c:248
AT command struct.
Definition: bc_atci.h:29
void bc_fifo_init(bc_fifo_t *fifo, void *buffer, size_t size)
Initialize FIFO buffer.
Definition: bc_fifo.c:4
void bc_atci_printf(const char *format,...)
Prinf message and add CR LF.
Definition: bc_atci.c:46
void bc_atci_init(const bc_atci_command_t *commands, int length)
Initialize.
Definition: bc_atci.c:27
void bc_uart_set_async_fifo(bc_uart_channel_t channel, bc_fifo_t *write_fifo, bc_fifo_t *read_fifo)
Set buffers for async transfers.
Definition: bc_uart.c:422
void bc_uart_set_event_handler(bc_uart_channel_t channel, void(*event_handler)(bc_uart_channel_t, bc_uart_event_t, void *), void *event_param)
Set callback function.
Definition: bc_uart.c:416
size_t bc_uart_write(bc_uart_channel_t channel, const void *buffer, size_t length)
Write data to UART channel (blocking call)
Definition: bc_uart.c:330
size_t bc_uart_async_read(bc_uart_channel_t channel, void *buffer, size_t length)
Get data that has been received in async mode.
Definition: bc_uart.c:571
bool bc_atci_skip_response(void)
Skip response, use in callback in bc_atci_command_t.
Definition: bc_atci.c:69
void bc_atci_write_ok(void)
Write OK.
Definition: bc_atci.c:76
UART baudrat 115200 bps.
Definition: bc_uart.h:43
void bc_scheduler_unregister(bc_scheduler_task_id_t task_id)
Unregister specified task.
Definition: bc_scheduler.c:80
bool bc_atci_is_comma(bc_atci_param_t *param)
Check if the character at cursor is comma.
Definition: bc_atci.c:396
void bc_atci_write_error(void)
Write ERROR.
Definition: bc_atci.c:81