Firmware SDK
twr_atci.c
1 #include <twr_atci.h>
2 #include <twr_scheduler.h>
3 #include <twr_system.h>
4 
5 static void _twr_atci_uart_event_handler(twr_uart_channel_t channel, twr_uart_event_t event, void *event_param);
6 static void _twr_atci_uart_active_test(void);
7 static void _twr_atci_uart_active_test_task(void *param);
8 
9 static struct
10 {
11  const twr_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  twr_fifo_t read_fifo;
19  twr_scheduler_task_id_t vbus_sense_test_task_id;
20  bool ready;
21  bool (*uart_active_callback)(void);
22  twr_tick_t scan_interval;
23  bool write_response;
24 
25 } _twr_atci;
26 
27 void twr_atci_init(const twr_atci_command_t *commands, int length)
28 {
29  memset(&_twr_atci, 0, sizeof(_twr_atci));
30 
31  _twr_atci.commands = commands;
32 
33  _twr_atci.commands_length = length;
34 
35  _twr_atci.rx_length = 0;
36 
37  _twr_atci.rx_error = false;
38 
39  _twr_atci.write_response = true;
40 
41  twr_fifo_init(&_twr_atci.read_fifo, _twr_atci.read_fifo_buffer, sizeof(_twr_atci.read_fifo_buffer));
42 
43  twr_atci_set_uart_active_callback(twr_system_get_vbus_sense, 200);
44 }
45 
46 size_t twr_atci_print(const char *message)
47 {
48  return twr_uart_write(TWR_ATCI_UART, message, strlen(message));
49 }
50 
51 size_t twr_atci_println(const char *message)
52 {
53  size_t len = twr_uart_write(TWR_ATCI_UART, message, strlen(message));
54  return twr_uart_write(TWR_ATCI_UART, "\r\n", 2) + len;
55 }
56 
57 static size_t _twr_atci_printf(const char *format, va_list ap, size_t maxlen)
58 {
59  size_t length = vsnprintf(_twr_atci.tx_buffer, maxlen, format, ap);
60 
61  if (length > maxlen) {
62  length = maxlen;
63  }
64 
65  return length;
66 }
67 
68 size_t twr_atci_printf(const char *format, ...)
69 {
70  if (!_twr_atci.ready)
71  {
72  return 0;
73  }
74 
75  va_list ap;
76 
77  va_start(ap, format);
78  size_t length = _twr_atci_printf(format, ap, sizeof(_twr_atci.tx_buffer));
79  va_end(ap);
80 
81  return twr_uart_write(TWR_ATCI_UART, _twr_atci.tx_buffer, length);
82 }
83 
84 size_t twr_atci_printfln(const char *format, ...)
85 {
86  if (!_twr_atci.ready)
87  {
88  return 0;
89  }
90 
91  va_list ap;
92 
93  va_start(ap, format);
94  size_t length = _twr_atci_printf(format, ap, sizeof(_twr_atci.tx_buffer) - 2);
95  va_end(ap);
96 
97  _twr_atci.tx_buffer[length++] = '\r';
98  _twr_atci.tx_buffer[length++] = '\n';
99 
100  return twr_uart_write(TWR_ATCI_UART, _twr_atci.tx_buffer, length);
101 }
102 
103 size_t twr_atci_print_buffer_as_hex(const void *buffer, size_t length)
104 {
105  if (!_twr_atci.ready)
106  {
107  return 0;
108  }
109 
110  char byte;
111  size_t on_write = 0;
112 
113  for (size_t i = 0; i < length; i++)
114  {
115  byte = ((char *)buffer)[i];
116 
117  char upper = (byte >> 4) & 0xf;
118  char lower = byte & 0x0f;
119 
120  _twr_atci.tx_buffer[on_write++] = upper < 10 ? upper + '0' : upper - 10 + 'A';
121  _twr_atci.tx_buffer[on_write++] = lower < 10 ? lower + '0' : lower - 10 + 'A';
122  }
123 
124  return twr_uart_write(TWR_ATCI_UART, _twr_atci.tx_buffer, on_write);
125 }
126 
128 {
129  _twr_atci.write_response = false;
130 
131  return true;
132 }
133 
135 {
136  twr_uart_write(TWR_ATCI_UART, "OK\r\n", 4);
137 }
138 
140 {
141  twr_uart_write(TWR_ATCI_UART, "ERROR\r\n", 7);
142 }
143 
145 {
146  for (size_t i = 0; i < _twr_atci.commands_length; i++)
147  {
148  twr_atci_printfln("AT%s", _twr_atci.commands[i].command);
149  }
150  return true;
151 }
152 
154 {
155  for (size_t i = 0; i < _twr_atci.commands_length; i++)
156  {
157  twr_atci_printfln("AT%s %s", _twr_atci.commands[i].command, _twr_atci.commands[i].hint);
158  }
159  return true;
160 }
161 
162 static bool _twr_atci_process_line(void)
163 {
164  if (_twr_atci.rx_length < 2 || _twr_atci.rx_buffer[0] != 'A' || _twr_atci.rx_buffer[1] != 'T')
165  {
166  return false;
167  }
168 
169  if (_twr_atci.rx_length == 2)
170  {
171  return true;
172  }
173 
174  _twr_atci.rx_buffer[_twr_atci.rx_length] = 0;
175 
176  char *line = _twr_atci.rx_buffer + 2;
177 
178  size_t length = _twr_atci.rx_length - 2;
179 
180  size_t command_len;
181 
182  const twr_atci_command_t *command;
183 
184  for (size_t i = 0; i < _twr_atci.commands_length; i++)
185  {
186  command = _twr_atci.commands + i;
187 
188  command_len = strlen(command->command);
189 
190  if (length < command_len)
191  {
192  continue;
193  }
194 
195  if (strncmp(line, command->command, command_len) != 0)
196  {
197  continue;
198  }
199 
200  if (command_len == length)
201  {
202  if (command->action != NULL)
203  {
204  return command->action();
205  }
206  }
207  else if (line[command_len] == '=')
208  {
209  if ((line[command_len + 1]) == '?' && (command_len + 2 == length))
210  {
211  if (command->help != NULL)
212  {
213  return command->help();
214  }
215  }
216 
217  if (command->set != NULL)
218  {
219  twr_atci_param_t param = {
220  .txt = line + command_len + 1,
221  .length = length - command_len - 1,
222  .offset = 0
223  };
224 
225  return command->set(&param);
226  }
227  }
228  else if (line[command_len] == '?' && command_len + 1 == length)
229  {
230  if (command->read != NULL)
231  {
232  return command->read();
233  }
234  }
235  else
236  {
237  return false;
238  }
239 
240  break;
241  }
242 
243  return false;
244 }
245 
246 static void _twr_atci_process_character(char character)
247 {
248  if (character == '\n')
249  {
250  if (!_twr_atci.rx_error && _twr_atci.rx_length > 0)
251  {
252  bool response = _twr_atci_process_line();
253 
254  if (_twr_atci.write_response)
255  {
256  if (response)
257  {
259  }
260  else
261  {
263  }
264  }
265  else
266  {
267  _twr_atci.write_response = true;
268  }
269  }
270  else if (_twr_atci.rx_error)
271  {
273  }
274 
275  _twr_atci.rx_length = 0;
276  _twr_atci.rx_error = false;
277  }
278  else if (character == '\r')
279  {
280  return;
281  }
282  else if (character == '\x1b')
283  {
284  _twr_atci.rx_length = 0;
285  _twr_atci.rx_error = false;
286  }
287  else if (_twr_atci.rx_length == sizeof(_twr_atci.rx_buffer) - 1)
288  {
289  _twr_atci.rx_error = true;
290  }
291  else if (!_twr_atci.rx_error)
292  {
293  _twr_atci.rx_buffer[_twr_atci.rx_length++] = character;
294  }
295 }
296 
297 static void _twr_atci_uart_event_handler(twr_uart_channel_t channel, twr_uart_event_t event, void *event_param)
298 {
299  (void) channel;
300  (void) event_param;
301 
302  if (event == TWR_UART_EVENT_ASYNC_READ_DATA)
303  {
304  while (true)
305  {
306  static uint8_t buffer[16];
307 
308  size_t length = twr_uart_async_read(TWR_ATCI_UART, buffer, sizeof(buffer));
309 
310  if (length == 0)
311  {
312  break;
313  }
314 
315  for (size_t i = 0; i < length; i++)
316  {
317  _twr_atci_process_character((char) buffer[i]);
318  }
319  }
320  }
321 }
322 
323 bool twr_atci_get_uint(twr_atci_param_t *param, uint32_t *value)
324 {
325  char c;
326 
327  *value = 0;
328 
329  while (param->offset < param->length)
330  {
331  c = param->txt[param->offset];
332 
333  if (isdigit(c))
334  {
335  *value *= 10;
336  *value += c - '0';
337  }
338  else
339  {
340  if (c == ',')
341  {
342  return true;
343  }
344  return false;
345  }
346 
347  param->offset++;
348  }
349 
350  return true;
351 }
352 
353 bool twr_atci_get_string(twr_atci_param_t *param, char *str, size_t length)
354 {
355  if (((param->length - param->offset) < 2) || (length < 1) || (str == NULL))
356  {
357  return false;
358  }
359 
360  if (param->txt[param->offset++] != '"')
361  {
362  return false;
363  }
364 
365  char c;
366  size_t i;
367 
368  for (i = 0; (i < length) && (param->offset < param->length); i++)
369  {
370  c = param->txt[param->offset++];
371 
372  if (c == '"')
373  {
374  str[i] = 0;
375 
376  return true;
377  }
378 
379  if ((c < ' ') || (c == ',') || (c > '~'))
380  {
381  return false;
382  }
383 
384  str[i] = c;
385  }
386 
387  return false;
388 }
389 
390 bool twr_atci_get_buffer_from_hex_string(twr_atci_param_t *param, void *buffer, size_t *length)
391 {
392  if (((param->length - param->offset) < 2) || (*length < 1) || (buffer == NULL))
393  {
394  return false;
395  }
396 
397  if (param->txt[param->offset++] != '"')
398  {
399  return false;
400  }
401 
402  char c;
403  size_t i;
404  size_t max_i = *length * 2;
405  uint8_t temp;
406  size_t l = 0;
407 
408  for (i = 0; (i < max_i) && (param->offset < param->length); i++)
409  {
410  c = param->txt[param->offset++];
411 
412  if (c == '"')
413  {
414  *length = l;
415 
416  return true;
417  }
418 
419  if ((c >= '0') && (c <= '9'))
420  {
421  temp = c - '0';
422  }
423  else if ((c >= 'A') && (c <= 'F'))
424  {
425  temp = c - 'A' + 10;
426  }
427  else if ((c >= 'a') && (c <= 'f'))
428  {
429  temp = c - 'a' + 10;
430  }
431  else
432  {
433  return false;
434  }
435 
436  if (i % 2 == 0)
437  {
438  if (l == *length)
439  {
440  return false;
441  }
442 
443  ((uint8_t *) buffer)[l] = temp << 4;
444  }
445  else
446  {
447  ((uint8_t *) buffer)[l++] |= temp;
448  }
449  }
450 
451  return false;
452 }
453 
455 {
456  return param->txt[param->offset++] == ',';
457 }
458 
460 {
461  return param->txt[param->offset++] == '"';
462 }
463 
464 void twr_atci_set_uart_active_callback(bool(*callback)(void), twr_tick_t scan_interval)
465 {
466  _twr_atci.uart_active_callback = callback;
467  _twr_atci.scan_interval = scan_interval;
468 
469  if (callback == NULL)
470  {
471  if (_twr_atci.vbus_sense_test_task_id)
472  {
473  twr_scheduler_unregister(_twr_atci.vbus_sense_test_task_id);
474 
475  _twr_atci.vbus_sense_test_task_id = 0;
476  }
477  }
478  else
479  {
480  if (_twr_atci.vbus_sense_test_task_id == 0)
481  {
482  _twr_atci.vbus_sense_test_task_id = twr_scheduler_register(_twr_atci_uart_active_test_task, NULL, scan_interval);
483  }
484  }
485 
486  _twr_atci_uart_active_test();
487 }
488 
489 static void _twr_atci_uart_active_test(void)
490 {
491  if ((_twr_atci.uart_active_callback == NULL) || _twr_atci.uart_active_callback())
492  {
493  if (!_twr_atci.ready)
494  {
496 
497  twr_uart_set_async_fifo(TWR_ATCI_UART, NULL, &_twr_atci.read_fifo);
498 
499  twr_uart_set_event_handler(TWR_ATCI_UART, _twr_atci_uart_event_handler, NULL);
500 
501  twr_uart_async_read_start(TWR_ATCI_UART, 1000);
502 
503  _twr_atci.ready = true;
504 
505  twr_uart_write(TWR_ATCI_UART, "\r\n", 2);
506  }
507  }
508  else
509  {
510  if (_twr_atci.ready)
511  {
512  _twr_atci.ready = false;
513 
514  twr_uart_deinit(TWR_ATCI_UART);
515  }
516  }
517 }
518 
519 static void _twr_atci_uart_active_test_task(void *param)
520 {
521  (void) param;
522 
523  _twr_atci_uart_active_test();
524 
525  twr_scheduler_plan_current_relative(_twr_atci.scan_interval);
526 }
bool twr_atci_get_buffer_from_hex_string(twr_atci_param_t *param, void *buffer, size_t *length)
Decode HEX string to buffer and move parsing cursor forward.
Definition: twr_atci.c:390
bool twr_atci_skip_response(void)
Skip response, use in callback in twr_atci_command_t.
Definition: twr_atci.c:127
bool twr_atci_is_comma(twr_atci_param_t *param)
Check if the character at cursor is comma.
Definition: twr_atci.c:454
size_t twr_atci_printf(const char *format,...)
Prinf message.
Definition: twr_atci.c:68
bool twr_atci_clac_action(void)
Helper for clac action.
Definition: twr_atci.c:144
bool twr_atci_help_action(void)
Helper for help action.
Definition: twr_atci.c:153
bool twr_atci_is_quotation_mark(twr_atci_param_t *param)
Check if the character at cursor is quotation mark (")
Definition: twr_atci.c:459
size_t twr_atci_print(const char *message)
Print message.
Definition: twr_atci.c:46
void twr_atci_write_error(void)
Write ERROR.
Definition: twr_atci.c:139
bool twr_atci_get_uint(twr_atci_param_t *param, uint32_t *value)
Parse string to uint and move parsing cursor forward.
Definition: twr_atci.c:323
void twr_atci_init(const twr_atci_command_t *commands, int length)
Initialize.
Definition: twr_atci.c:27
bool twr_atci_get_string(twr_atci_param_t *param, char *str, size_t length)
Copy string and move parsing cursor forward.
Definition: twr_atci.c:353
void twr_atci_write_ok(void)
Write OK.
Definition: twr_atci.c:134
size_t twr_atci_print_buffer_as_hex(const void *buffer, size_t length)
Print buffer as HEX string.
Definition: twr_atci.c:103
size_t twr_atci_println(const char *message)
Print message and add CR LF.
Definition: twr_atci.c:51
void twr_atci_set_uart_active_callback(bool(*callback)(void), twr_tick_t scan_interval)
Set callback function for scan if uart is active. Used for low-power when USB is disconnected (defaul...
Definition: twr_atci.c:464
size_t twr_atci_printfln(const char *format,...)
Prinf message and add CR LF.
Definition: twr_atci.c:84
void twr_fifo_init(twr_fifo_t *fifo, void *buffer, size_t size)
Initialize FIFO buffer.
Definition: twr_fifo.c:4
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
void twr_scheduler_unregister(twr_scheduler_task_id_t task_id)
Unregister specified task.
Definition: twr_scheduler.c:77
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: twr_scheduler.h:22
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
twr_uart_channel_t
UART channels.
Definition: twr_uart.h:14
void twr_uart_init(twr_uart_channel_t channel, twr_uart_baudrate_t baudrate, twr_uart_setting_t setting)
Initialize UART channel.
Definition: twr_uart.c:54
void twr_uart_set_async_fifo(twr_uart_channel_t channel, twr_fifo_t *write_fifo, twr_fifo_t *read_fifo)
Set buffers for async transfers.
Definition: twr_uart.c:412
size_t twr_uart_write(twr_uart_channel_t channel, const void *buffer, size_t length)
Write data to UART channel (blocking call)
Definition: twr_uart.c:314
bool twr_uart_async_read_start(twr_uart_channel_t channel, twr_tick_t timeout)
Start async reading.
Definition: twr_uart.c:465
twr_uart_event_t
Callback events.
Definition: twr_uart.h:128
void twr_uart_set_event_handler(twr_uart_channel_t channel, void(*event_handler)(twr_uart_channel_t, twr_uart_event_t, void *), void *event_param)
Set callback function.
Definition: twr_uart.c:406
size_t twr_uart_async_read(twr_uart_channel_t channel, void *buffer, size_t length)
Get data that has been received in async mode.
Definition: twr_uart.c:561
void twr_uart_deinit(twr_uart_channel_t channel)
Deinitialize UART channel.
Definition: twr_uart.c:237
@ TWR_UART_EVENT_ASYNC_READ_DATA
Event is reading done.
Definition: twr_uart.h:133
@ TWR_UART_BAUDRATE_115200
UART baudrat 115200 bps.
Definition: twr_uart.h:43
@ TWR_UART_SETTING_8N1
8N1: 8 data bits, none parity bit, 1 stop bit
Definition: twr_uart.h:70
AT command struct.
Definition: twr_atci.h:30
Structure of FIFO instance.
Definition: twr_fifo.h:13