CuVoodoo STM32F1 firmware template
busvoodoo_uart_generic.c
Go to the documentation of this file.
1 /* This program is free software: you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation, either version 3 of the License, or
4  * (at your option) any later version.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program. If not, see <http://www.gnu.org/licenses/>.
13  *
14  */
21 /* standard libraries */
22 #include <stdint.h> // standard integer types
23 #include <stdlib.h> // standard utilities
24 #include <string.h> // string utilities
25 
26 /* STM32 (including CM3) libraries */
27 #include <libopencm3/cm3/nvic.h> // interrupt utilities
28 #include <libopencm3/stm32/gpio.h> // general purpose input output library
29 #include <libopencm3/stm32/rcc.h> // real-time control clock library
30 #include <libopencm3/stm32/usart.h> // USART utilities
31 #include <libopencm3/stm32/timer.h> // timer library
32 
33 /* own libraries */
34 #include "global.h" // board definitions
35 #include "print.h" // printing utilities
36 #include "menu.h" // menu definitions
37 #include "usart_enhanced.h" // utilities for USART enhancements
38 #include "busvoodoo_global.h" // BusVoodoo definitions
39 #include "busvoodoo_uart_generic.h" // own definitions
40 
45  BUSVOODOO_UART_SETTING_NONE,
46  BUSVOODOO_UART_SETTING_BAUDRATE,
47  BUSVOODOO_UART_SETTING_DATABITS,
48  BUSVOODOO_UART_SETTING_PARITY,
49  BUSVOODOO_UART_SETTING_STOPBITS,
50  BUSVOODOO_UART_SETTING_HWFLOWCTL,
51  BUSVOODOO_UART_SETTING_DRIVE,
52  BUSVOODOO_UART_SETTING_DONE,
53 } busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_NONE;
55 static uint32_t busvoodoo_uart_generic_baudrate = 115200;
61 static uint32_t busvoodoo_uart_generic_stopbits = USART_STOPBITS_1;
65 static bool busvoodoo_uart_generic_drive = true;
67 static bool busvoodoo_uart_generic_pullup = false;
68 
70 {
71  busvoodoo_uart_generic_specific = NULL; // reset specific information
72  if (NULL==conf) {
73  return false;
74  }
75  if (!conf->usart || !conf->usart_rcc || !conf->usart_rst) {
76  return false;
77  }
78  if (!conf->tx_rcc || !conf->rx_rcc) {
79  return false;
80  }
81  if (conf->hwflowctl && (!conf->rts_rcc || !conf->cts_rcc)) {
82  return false;
83  }
85  return true;
86 }
87 
88 bool busvoodoo_uart_generic_setup(char** prefix, const char* line)
89 {
90  if (NULL==busvoodoo_uart_generic_specific) { // there is nothing to configure
91  return true;
92  }
93  bool complete = false; // is the setup complete
94  if (NULL==line) { // first call
95  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_NONE; // re-start configuration
96  }
98  case BUSVOODOO_UART_SETTING_NONE:
100  *prefix = busvoodoo_global_string; // ask for baud rate
101  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_BAUDRATE;
102  break;
103  case BUSVOODOO_UART_SETTING_BAUDRATE:
104  if (NULL==line || 0==strlen(line)) { // use default setting
105  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DATABITS; // go to next setting
106  } else { // setting provided
107  uint32_t baudrate = atoi(line); // parse setting
108  if (baudrate>0 && baudrate<=2000000) { // check setting
109  busvoodoo_uart_generic_baudrate = baudrate; // remember setting
110  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DATABITS; // go to next setting
111  }
112  }
113  if (BUSVOODOO_UART_SETTING_DATABITS==busvoodoo_uart_generic_setting) { // if next setting
114  snprintf(busvoodoo_global_string, LENGTH(busvoodoo_global_string), "data bits (5-8) [%u]", busvoodoo_uart_generic_databits); // prepare next setting
115  *prefix = busvoodoo_global_string; // display next setting
116  }
117  break;
118  case BUSVOODOO_UART_SETTING_DATABITS:
119  if (NULL==line || 0==strlen(line)) { // use default setting
120  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_PARITY; // go to next setting
121  } else if (1==strlen(line)) { // setting provided
122  uint8_t databits = atoi(line); // parse setting
123  if (databits>=5 && databits<=8) { // check setting
124  busvoodoo_uart_generic_databits = databits; // remember setting
125  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_PARITY; // go to next setting
126  }
127  }
128  if (BUSVOODOO_UART_SETTING_PARITY==busvoodoo_uart_generic_setting) { // if next setting
129  printf("1) none\n");
130  printf("2) even\n");
131  printf("3) odd\n");
132  printf("4) mark\n");
133  printf("5) space\n");
134  snprintf(busvoodoo_global_string, LENGTH(busvoodoo_global_string), "parity (1,2,3,4,5) [%u]", busvoodoo_uart_generic_parity+1); // prepare next setting
135  *prefix = busvoodoo_global_string; // display next setting
136  }
137  break;
138  case BUSVOODOO_UART_SETTING_PARITY:
139  if (NULL==line || 0==strlen(line)) { // use default setting
140  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_STOPBITS; // go to next setting
141  } else if (1==strlen(line)) { // setting provided
142  uint8_t parity = atoi(line); // parse setting
143  if (parity>0 && parity<6) { // check settin
145  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_STOPBITS; // go to next setting
146  }
147  }
148  if (BUSVOODOO_UART_SETTING_STOPBITS==busvoodoo_uart_generic_setting) { // if next setting
149  printf("1) 0.5\n");
150  printf("2) 1\n");
151  printf("3) 1.5\n");
152  printf("4) 2\n");
153  snprintf(busvoodoo_global_string, LENGTH(busvoodoo_global_string), "stop bits (1,2,3,4) [%c]", USART_STOPBITS_0_5==busvoodoo_uart_generic_stopbits ? '1' : (USART_STOPBITS_1==busvoodoo_uart_generic_stopbits ? '2' : (USART_STOPBITS_1_5==busvoodoo_uart_generic_stopbits ? '3' : '4'))); // prepare next setting
154  *prefix = busvoodoo_global_string; // display next setting
155  }
156  break;
157  case BUSVOODOO_UART_SETTING_STOPBITS:
158  if (NULL==line || 0==strlen(line)) { // use default setting
159  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL; // go to next setting
160  } else if (1==strlen(line)) { // setting provided
161  if ('1'==line[0]) { // 0.5 stop bits
162  busvoodoo_uart_generic_stopbits = USART_STOPBITS_0_5; // remember setting
163  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL; // go to next setting
164  } else if ('2'==line[0]) { // 1 stop bits
165  busvoodoo_uart_generic_stopbits = USART_STOPBITS_1; // remember setting
166  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL; // go to next setting
167  } else if ('3'==line[0]) { // 1.5 stop bits
168  busvoodoo_uart_generic_stopbits = USART_STOPBITS_1_5; // remember setting
169  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL; // go to next setting
170  } else if ('4'==line[0]) { // 2 stop bits
171  busvoodoo_uart_generic_stopbits = USART_STOPBITS_2; // remember setting
172  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL; // go to next setting
173  }
174  }
175  if (BUSVOODOO_UART_SETTING_HWFLOWCTL==busvoodoo_uart_generic_setting) { // if next setting
176  if (!busvoodoo_uart_generic_specific->hwflowctl) { // hardware flow control is not supported
177  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DRIVE; // go to next setting
178  goto setting_drive; // actually go to next setting
179  }
180  printf("1) no flow control\n");
181  printf("2) RTS/CTS hardware flow control\n");
182  snprintf(busvoodoo_global_string, LENGTH(busvoodoo_global_string), "flow control (1,2) [%c]", busvoodoo_uart_generic_hwflowctl ? '2' : '1'); // prepare next setting
183  *prefix = busvoodoo_global_string; // display next setting
184  }
185  break;
186  case BUSVOODOO_UART_SETTING_HWFLOWCTL:
187  if (NULL==line || 0==strlen(line)) { // use default setting
188  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DRIVE; // go to next setting
189  } else if (1==strlen(line)) { // setting provided
190  if ('1'==line[0] || '2'==line[0]) { // setting provided
191  busvoodoo_uart_generic_hwflowctl = ('2'==line[0]); // remember setting
192  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DRIVE; // go to next setting
193  }
194  }
195 setting_drive:
196  if (BUSVOODOO_UART_SETTING_DRIVE==busvoodoo_uart_generic_setting) { // if next setting
198  busvoodoo_uart_generic_drive = true; // only push-pull driving mode is supported
199  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DONE; // go to next setting
200  goto setting_done; // actually go to next setting
201  }
202  printf("1) push-pull (3.3V)\n");
203  printf("2) open-drain, with embedded pull-up resistors (2kO)\n");
204  printf("3) open-drain, with external pull-up resistors\n");
205  snprintf(busvoodoo_global_string, LENGTH(busvoodoo_global_string), "drive mode (1,2,3) [%c]", busvoodoo_uart_generic_drive ? '1' : (busvoodoo_uart_generic_pullup ? '2' : '3')); // show drive mode
206  *prefix = busvoodoo_global_string; // display next setting
207  }
208  break;
209  case BUSVOODOO_UART_SETTING_DRIVE:
210  if (NULL==line || 0==strlen(line)) { // use default setting
211  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DONE; // go to next setting
212  } else if (1==strlen(line)) { // setting provided
213  uint8_t drive = atoi(line); // parse setting
214  if (1==drive || 2==drive || 3==drive) { // check setting
215  busvoodoo_uart_generic_drive = (1==drive); // remember setting
216  busvoodoo_uart_generic_pullup = (2==drive); // remember setting
217  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DONE; // go to next setting
218  }
219  }
220 setting_done:
221  if (BUSVOODOO_UART_SETTING_DONE==busvoodoo_uart_generic_setting) { // we have all settings, configure UART
222  rcc_periph_clock_enable(RCC_AFIO); // enable clock for USART alternate function
223  rcc_periph_clock_enable(busvoodoo_uart_generic_specific->usart_rcc); // enable clock for USART peripheral
224  rcc_periph_reset_pulse(busvoodoo_uart_generic_specific->usart_rst); // reset USART peripheral
225  usart_set_baudrate(busvoodoo_uart_generic_specific->usart, busvoodoo_uart_generic_baudrate); // set baud rate
226  usart_enhanced_config(busvoodoo_uart_generic_specific->usart, busvoodoo_uart_generic_databits, busvoodoo_uart_generic_parity); // use enhanced USART to configure the USART peripherals, supporting more data-bits and parity configurations
227  usart_set_stopbits(busvoodoo_uart_generic_specific->usart, busvoodoo_uart_generic_stopbits); // set stop bits
229  usart_set_flow_control(busvoodoo_uart_generic_specific->usart, USART_FLOWCONTROL_RTS_CTS); // set RTS/CTS flow control
230  } else {
231  usart_set_flow_control(busvoodoo_uart_generic_specific->usart, USART_FLOWCONTROL_NONE); // set no flow control
232  }
233  usart_set_mode(busvoodoo_uart_generic_specific->usart, USART_MODE_TX_RX); // full-duplex communication
234  rcc_periph_clock_enable(busvoodoo_uart_generic_specific->tx_rcc); // enable clock for USART GPIO peripheral
235  rcc_periph_clock_enable(busvoodoo_uart_generic_specific->rx_rcc); // enable clock for USART GPIO peripheral
237  rcc_periph_clock_enable(busvoodoo_uart_generic_specific->rts_rcc); // enable clock for USART GPIO peripheral
238  rcc_periph_clock_enable(busvoodoo_uart_generic_specific->cts_rcc); // enable clock for USART GPIO peripheral
239  }
240  if (busvoodoo_uart_generic_drive) { // use push-pull drive mode
241  gpio_set_mode(busvoodoo_uart_generic_specific->tx_port, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, busvoodoo_uart_generic_specific->tx_pin); // setup GPIO pin USART transmit
242  gpio_set(busvoodoo_uart_generic_specific->rx_port, busvoodoo_uart_generic_specific->rx_pin); // pull up to avoid noise when not connected
243  gpio_set_mode(busvoodoo_uart_generic_specific->rx_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, busvoodoo_uart_generic_specific->rx_pin); // setup GPIO pin USART receive
244  if (busvoodoo_uart_generic_specific->hwflowctl && busvoodoo_uart_generic_hwflowctl) { // use open drain drive mode
245  gpio_set_mode(busvoodoo_uart_generic_specific->rts_port, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, busvoodoo_uart_generic_specific->rts_pin); // setup GPIO pin USART transmit
246  gpio_set(busvoodoo_uart_generic_specific->cts_port, busvoodoo_uart_generic_specific->cts_pin); // pull up to block transmission unless requested
247  gpio_set_mode(busvoodoo_uart_generic_specific->cts_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, busvoodoo_uart_generic_specific->cts_pin); // setup GPIO pin USART receive
248  }
249  } else {
250  gpio_set_mode(busvoodoo_uart_generic_specific->tx_port, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, busvoodoo_uart_generic_specific->tx_pin); // setup GPIO pin USART transmit
251  gpio_set_mode(busvoodoo_uart_generic_specific->rx_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, busvoodoo_uart_generic_specific->rx_pin); // setup GPIO pin USART receive
253  gpio_set_mode(busvoodoo_uart_generic_specific->rts_port, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, busvoodoo_uart_generic_specific->rts_pin); // setup GPIO pin USART transmit
254  gpio_set_mode(busvoodoo_uart_generic_specific->cts_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, busvoodoo_uart_generic_specific->cts_pin); // setup GPIO pin USART receive
255  }
256  }
257  if (!busvoodoo_uart_generic_drive && busvoodoo_uart_generic_pullup) { // enable embedded pull-ups if used
258  busvoodoo_embedded_pullup(true); // set embedded pull-ups
259  printf("use LV to set pull-up voltage\n");
260  }
261  usart_enable(busvoodoo_uart_generic_specific->usart); // enable USART
262  busvoodoo_led_blue_off(); // disable blue LED because there is no activity
263  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_NONE; // restart settings next time
264  complete = true; // configuration is complete
265  }
266  break;
267  default: // unknown case
268  busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_NONE; // restart settings next time
269  break;
270  }
271  return complete;
272 }
273 
275 {
277  return;
278  }
279  usart_disable(busvoodoo_uart_generic_specific->usart); // disable USART
280  rcc_periph_clock_disable(busvoodoo_uart_generic_specific->usart_rcc); // disable domain clock
281  gpio_set_mode(busvoodoo_uart_generic_specific->tx_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, busvoodoo_uart_generic_specific->tx_pin); // set pin back to floating input
282  gpio_set_mode(busvoodoo_uart_generic_specific->rx_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, busvoodoo_uart_generic_specific->rx_pin); // set pin back to floating input
284  gpio_set_mode(busvoodoo_uart_generic_specific->rts_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, busvoodoo_uart_generic_specific->rts_pin); // set pin back to floating input
285  gpio_set_mode(busvoodoo_uart_generic_specific->cts_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, busvoodoo_uart_generic_specific->cts_pin); // set pin back to floating input
286  }
288  busvoodoo_embedded_pullup(false); // disable embedded pull-ups
289  }
290  busvoodoo_uart_generic_specific = NULL; // remove specific information
291 }
292 
296 static void busvoodoo_uart_generic_write(uint8_t value)
297 {
299  return;
300  }
303  }
304  while ((0==((USART_SR(busvoodoo_uart_generic_specific->usart)) & USART_SR_TXE) && !user_input_available)); // wait for transmit buffer to be empty (or user to interrupt)
305  if ((USART_SR(busvoodoo_uart_generic_specific->usart)) & USART_SR_TXE) { // we can send data
306  // send data
307  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // pulse blue LED to show transmission
309  // display data send
310  printf("write: '%c'/0x%02x\n", value, value);
311  }
312  while ((0==((USART_SR(busvoodoo_uart_generic_specific->usart)) & USART_SR_TC) && !user_input_available)); // wait for transfer to be complete
313  if (user_input_available) { // user interrupted flow
314  user_input_get(); // discard user input
315  }
318  }
319 }
320 
324 {
326  return;
327  }
330  }
331  printf("read: ");
332  while (!(USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_RXNE) && !user_input_available); // wait for incoming data to be available (or user input to exit)
333  if ((USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_RXNE)) { // verify if data has been received
334  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // enable blue LED to show reception
335  // get the errors
336  bool error_noise = (0!=(USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_NE)); // read noise error flag
337  bool error_framing = (0!=(USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_FE)); // read frame error flag
338  uint8_t input = usart_enhanced_recv(busvoodoo_uart_generic_specific->usart); // read received character (also clears the error flags)
339  // display data
340  printf("'%c'/0x%02x", input, input);
341  // display errors
342  printf("(");
343  if (error_noise) {
344  printf("noise");
345  } else if (error_framing) {
346  printf("framing");
348  printf("parity");
349  } else {
350  printf("no");
351  }
352  printf(" error)");
353  }
354  printf("\n");
355  if (user_input_available) { // user interrupted flow
356  user_input_get(); // discard user input
357  }
360  }
361 }
362 
369 static bool busvoodoo_uart_generic_action(const char* action, uint32_t repetition, bool perform)
370 {
371  uint32_t length = strlen(action); // remember length since it will be used a number of times
372  if (NULL==action || 0==length) { // there is nothing to do
373  return true;
374  }
375 
376  if (1==length && 'r'==action[0]) { // read data
377  if (!perform) {
378  return true;
379  }
380  for (uint32_t i=0; i<repetition; i++) {
381  busvoodoo_uart_generic_read(); // read from UART
382  }
383  } else if (1==length && 'u'==action[0]) { // sleep us
384  if (!perform) {
385  return true;
386  }
387  printf("wait for %u us\n", repetition);
388  sleep_us(repetition); // sleep
389  } else if (1==length && 'm'==action[0]) { // sleep ms
390  if (!perform) {
391  return true;
392  }
393  printf("wait for %u ms\n", repetition);
394  sleep_ms(repetition); // sleep
395  } else if ('0'==action[0]) { // send digit
396  if (1==length) { // just send 0
397  if (!perform) {
398  return true;
399  }
400  for (uint32_t i=0; i<repetition; i++) {
401  busvoodoo_uart_generic_write(0); // write to UART
402  }
403  } else if ('x'==action[1] || 'b'==action[1]) { // send hex/binary
404  return busvoodoo_uart_generic_action(action+1, repetition, perform); // just retry without leading 0
405  } else if (action[1]>='0' && action[1]<='9') { // send decimal
406  return busvoodoo_uart_generic_action(action+1, repetition, perform); // just retry without leading 0
407  } else { // malformed action
408  return false;
409  }
410  } else if ('x'==action[0] && length>1) { // send hexadecimal value
411  for (uint32_t i=1; i<length; i++) { // check string
412  if (!((action[i]>='0' && action[i]<='9') || (action[i]>='a' && action[i]<='f') || (action[i]>='A' && action[i]<='F'))) { // check for hexadecimal character
413  return false; // not an hexadecimal string
414  }
415  }
416  if (!perform) {
417  return true;
418  }
419  uint32_t value = strtol(&action[1], NULL, 16); // get hex value
420  for (uint32_t i=0; i<repetition; i++) {
421  busvoodoo_uart_generic_write(value); // write to SPI
422  }
423  } else if ('b'==action[0] && length>1) { // send binary value
424  for (uint32_t i=1; i<length; i++) { // check string
425  if (action[i]<'0' || action[i]>'1') { // check for binary character
426  return false; // not a binary string
427  }
428  }
429  if (!perform) {
430  return true;
431  }
432  uint32_t value = strtol(&action[1], NULL, 2); // get binary value
433  for (uint32_t i=0; i<repetition; i++) {
434  busvoodoo_uart_generic_write(value); // write to SPI
435  }
436  } else if (action[0]>='1' && action[0]<='9') { // send decimal value
437  for (uint32_t i=1; i<length; i++) { // check string
438  if (action[i]<'0' || action[i]>'9') { // check for decimal character
439  return false; // not a decimal string
440  }
441  }
442  if (!perform) {
443  return true;
444  }
445  uint32_t value = strtol(&action[0], NULL, 10); // get decimal value
446  for (uint32_t i=0; i<repetition; i++) {
447  busvoodoo_uart_generic_write(value); // write to SPI
448  }
449  } else if (length>=2 && ('"'==action[0] || '\''==action[0]) && (action[length-1]==action[0])) { // send ASCII character
450  if (!perform) {
451  return true;
452  }
453  for (uint32_t r=0; r<repetition; r++) {
454  for (uint32_t i=1; i<length-1; i++) { // go through string
455  busvoodoo_uart_generic_write(action[i]); // write to SPI
456  }
457  }
458  } else { // malformed action
459  return false;
460  }
461  return true; // all went well
462 }
463 
464 
465 // command handlers
466 
470 static void busvoodoo_uart_generic_command_actions(void* argument)
471 {
472  if (NULL==argument || 0==strlen(argument)) {
473  printf("available actions (separated by space or ,):\n");
474  printf("0\twrite decimal value\n");
475  printf("0x0\twrite hexadecimal value\n");
476  printf("0b0\twrite binary value\n");
477  printf("\"a\"/'a'\twrite ASCII characters\n");
478  printf("r\tread value\n");
479  printf("u/m\twait 1 us/ms\n");
480  printf(":n\trepeat action n times\n");
481  return;
482  }
483 
484  // copy argument since it will be modified
485  char* copy = calloc(strlen(argument)+1, sizeof(char));
486  if (!copy) {
487  while (true);
488  }
489  strncpy(copy, argument, strlen(argument)+1);
490  // verify and perform actions
491  if (!busvoodoo_global_actions(copy, false, &busvoodoo_uart_generic_action)) { // verify actions
492  printf("malformed action(s)\n");
493  } else { // action are ok
494  printf("press any key to exit\n");
495  busvoodoo_global_actions(argument, true, &busvoodoo_uart_generic_action); // perform action
496  if (user_input_available) { // user interrupted flow
497  user_input_get(); // discard user input
498  }
499  }
500  free(copy); // release memory
501 }
502 
506 static void busvoodoo_uart_generic_command_transmit(void* argument)
507 {
509  return;
510  }
513  }
514  if (NULL==argument || 0==strlen(argument)) { // nothing to transmit
515  argument = "\r\n"; // transmit CR+LF
516  }
517  printf("press any key to exit\n");
518  for (uint16_t i=0; ((char*)(argument))[i] && !user_input_available; i++) {
519  while ((0==(USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_TXE) && !user_input_available)); // wait for transmit buffer to be empty
520  if (USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_TXE) { // we can send a character
521  printf("%c", ((char*)(argument))[i]); // echo character to transmit
522  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // pulse blue LED to show transmission
523  usart_enhanced_send(busvoodoo_uart_generic_specific->usart, ((char*)(argument))[i]); // transmit character
524  }
525  }
526  while ((0==((USART_SR(busvoodoo_uart_generic_specific->usart)) & USART_SR_TC) && !user_input_available)); // wait for transfer to be complete
527  if (user_input_available) { // user interrupted flow
528  user_input_get(); // discard user input
529  }
530  if (strcmp(argument, "\r\n")) {
531  printf("\n");
532  }
535  }
536 }
537 
541 static void busvoodoo_uart_generic_command_receive(void* argument)
542 {
543  bool display_hex = false; // display in hex
544  bool display_bin = false; // display in bin
545  if (NULL!=argument && strlen(argument)>0) {
546  if (0==strcmp(argument, "h") || 0==strcmp(argument, "hex")) { // user wants hexadecimal display
547  display_hex = true; // remember to display in hexadecimal
548  } else if (0==strcmp(argument, "b") || 0==strcmp(argument, "bin")) { // user wants binary display
549  display_bin = true; // remember to display in binary
550  } else {
551  printf("malformed argument\n");
552  return;
553  }
554  }
556  return;
557  }
560  }
561  printf("press any key to exit\n");
562  while (!user_input_available) { // check for user input to exit
563  if ((USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_RXNE)) { // verify if data has been received
564  uint8_t input = usart_enhanced_recv(busvoodoo_uart_generic_specific->usart); // receive character
565  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // enable blue LED to show reception
566  if (display_hex) { // display data in hex
567  printf("%02x ", input);
568  } else if (display_bin) { // display data in binary
569  printf("%08b ", input);
570  } else { // display in ASCII
571  printf("%c", input); // print received character
572  }
573  }
574  }
575  user_input_get(); // discard user input
576  printf("\n"); // get to next line
579  }
580 }
581 
585 static void busvoodoo_uart_generic_command_transceive(void* argument)
586 {
587  (void)argument; // we won't use the argument
589  return;
590  }
593  }
594  printf("press 5 times escape to exit\n");
595  char last_c = 0; // last user character received
596  uint8_t esc_count = 0; // number of times escape has press received
597  while (true) { // check for escape sequence
598  if (user_input_available) { // check if user wants to transmit something
599  char c = user_input_get(); // get user input
600  if (0x1b==c) { // user pressed escape
601  if (0x1b!=last_c) { // this is the first escape press
602  esc_count = 0;
603  }
604  esc_count++; // increment escape count
605  }
606  last_c = c; // remember key press
607  if (esc_count<5) { // check for escape sequence
610  }
613  }
614  while ((0==(USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_TXE) && !user_input_available)); // wait for transmit buffer to be empty
615  if (USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_TXE) { // we can send a character
616  usart_enhanced_send(busvoodoo_uart_generic_specific->usart, c); // send user character
617  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // enable blue LED to show transmission
618  }
619  while ((0==((USART_SR(busvoodoo_uart_generic_specific->usart)) & USART_SR_TC) && !user_input_available)); // wait for transfer to be complete
622  }
625  }
626  } else { // user wants to exit
627  break; // exit infinite loop
628  }
629  }
630  if ((USART_SR(busvoodoo_uart_generic_specific->usart) & USART_SR_RXNE)) { // verify if data has been received
631  char input = usart_enhanced_recv(busvoodoo_uart_generic_specific->usart); // receive character
632  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // enable blue LED to show reception
633  printf("%c", input); // print received character
634  }
635  }
636  printf("\n"); // get to next line
639  }
640 }
641 
645 static void busvoodoo_uart_generic_command_error(void* argument)
646 {
647  (void)argument; // argument not used
648  printf("press any key to exit\n");
649  while (!user_input_available) { // wait until user interrupt
650  busvoodoo_uart_generic_read(); // read incoming data (this also checks for errors
651  }
652  user_input_get(); // discard user input
653 }
654 
656  {
657  .shortcut = 'a',
658  .name = "action",
659  .command_description = "perform protocol actions",
660  .argument = MENU_ARGUMENT_STRING,
661  .argument_description = "[actions]",
662  .command_handler = &busvoodoo_uart_generic_command_actions,
663  },
664  {
665  .shortcut = 'r',
666  .name = "receive",
667  .command_description = "show incoming data [in hexadecimal or binary]",
668  .argument = MENU_ARGUMENT_STRING,
669  .argument_description = "[hex|bin]",
670  .command_handler = &busvoodoo_uart_generic_command_receive,
671  },
672  {
673  .shortcut = 't',
674  .name = "transmit",
675  .command_description = "transmit ASCII text (empty for CR+LF)",
676  .argument = MENU_ARGUMENT_STRING,
677  .argument_description = "[text]",
678  .command_handler = &busvoodoo_uart_generic_command_transmit,
679  },
680  {
681  .shortcut = 'x',
682  .name = "transceive",
683  .command_description = "transmit and receive data",
684  .argument = MENU_ARGUMENT_NONE,
685  .argument_description = NULL,
686  .command_handler = &busvoodoo_uart_generic_command_transceive,
687  },
688  {
689  .shortcut = 'e',
690  .name = "error",
691  .command_description = "verify incoming transmission for errors",
692  .argument = MENU_ARGUMENT_NONE,
693  .argument_description = NULL,
694  .command_handler = &busvoodoo_uart_generic_command_error,
695  },
696 };
static uint32_t busvoodoo_uart_generic_baudrate
UART baud rate (in bps)
static enum busvoodoo_uart_generic_setting_t busvoodoo_uart_generic_setting
current mode setup stage
bool busvoodoo_uart_generic_setup(char **prefix, const char *line)
setup generic UART mode
command menu entry
Definition: menu.h:31
#define BUSVOODOO_LED_PULSE
recommended duration in ms for pulsing LEDs to show activity
void usart_enhanced_send(uint32_t usart, uint8_t data)
send data over the enhanced USART using the configuration
static bool busvoodoo_uart_generic_hwflowctl
UART hardware flow control setting (true = with hardware flow control, false = without hardware flow ...
BusVoodoo global definitions and methods (API)
static bool busvoodoo_uart_generic_action(const char *action, uint32_t repetition, bool perform)
perform UART action
busvoodoo_uart_generic_setting_t
mode setup stage
void(* tx_post)(void)
method to be called after transmitting data
void busvoodoo_led_blue_pulse(uint32_t ms)
pulse blue LED for short duration
uint32_t rx_pin
GPIO pin address of receive pin.
global definitions and methods (API)
uint32_t rts_port
GPIO port address of request to send pin.
void sleep_us(uint32_t duration)
go to sleep for some microseconds
Definition: global.c:102
static void busvoodoo_uart_generic_command_actions(void *argument)
command to perform actions
static const struct busvoodoo_uart_generic_specific_t * busvoodoo_uart_generic_specific
the USART mode specific information
static void busvoodoo_uart_generic_write(uint8_t value)
write to UART
usart_enhanced_parity_t
enhanced USART setting for the additional parity bit
static void busvoodoo_uart_generic_command_error(void *argument)
command to verify incoming transmission for error
void busvoodoo_led_blue_off(void)
switch off blue LED
void(* rx_pre)(void)
method to be called before receiving data
uint32_t usart
USART peripheral base address.
uint32_t rx_rcc
GPIO RCC address of receive pin.
bool multidrive
if multiple drive modes are supported (push-pull, open-drain with internal resistors, open-drain with external resistors), or just push-pull
uint32_t rx_port
GPIO port address of receive pin.
uint32_t tx_pin
GPIO pin address of transmit pin.
void(* rx_post)(void)
method to be called after receiving data
void busvoodoo_uart_generic_exit(void)
exit genetic UART mode
char shortcut
short command code (0 if not available)
Definition: menu.h:32
uint32_t tx_rcc
GPIO RCC address of transmit pin.
UART specific methods that will be called by the generic methods.
void(* tx_pre)(void)
method to be called before transmitting data
static bool busvoodoo_uart_generic_pullup
if embedded pull-up resistors are used
uint32_t rts_rcc
GPIO RCC address of request to send pin.
static void busvoodoo_uart_generic_command_transmit(void *argument)
command to transmit a string
uint32_t cts_port
GPIO port address of clear to send pin.
static enum usart_enhanced_parity_t busvoodoo_uart_generic_parity
UART parity setting.
char user_input_get(void)
get user input
Definition: global.c:145
char busvoodoo_global_string[64]
shared string buffer, i.e.
#define busvoodoo_uart_generic_commands_nb
number of commands supported by the generic UART mode
uint32_t usart_rst
USART RST address.
bool busvoodoo_global_actions(char *actions, bool perform, bool(*action_handler)(const char *action, uint32_t repetition, bool perform))
parse and perform actions
void sleep_ms(uint32_t duration)
go to sleep for some milliseconds
Definition: global.c:117
uint32_t rts_pin
GPIO pin address of request to send pin.
bool busvoodoo_uart_generic_configure(const struct busvoodoo_uart_generic_specific_t *conf)
provide the generic USART with mode specific information
uint32_t usart_rcc
USART RCC address.
bool usart_enhanced_config(uint32_t usart, uint8_t databits, enum usart_enhanced_parity_t parity)
configure enhanced USART
static void busvoodoo_uart_generic_read(void)
read from UART
BusVoodoo generic UART mode (API)
static uint32_t busvoodoo_uart_generic_stopbits
UART stop bits setting.
static void busvoodoo_uart_generic_command_receive(void *argument)
command to receive data
uint32_t cts_rcc
GPIO RCC address of clear to send pin.
uint8_t usart_enhanced_recv(uint32_t usart)
receive data over the enhanced USART using the configuration
const struct menu_command_t busvoodoo_uart_generic_commands[busvoodoo_uart_generic_commands_nb]
commands supported by the generic UART mode
float busvoodoo_embedded_pullup(bool on)
enable embedded pull-up resistors
static bool busvoodoo_uart_generic_drive
pin drive mode (true = push-pull, false = open-drain)
#define LENGTH(x)
get the length of an array
Definition: global.h:26
bool hwflowctl
if RTC/CTS hardware flow control is supported
static void busvoodoo_uart_generic_command_transceive(void *argument)
command to transmit and receive data
volatile bool user_input_available
flag set when user input is available
Definition: global.c:36
static uint8_t busvoodoo_uart_generic_databits
UART data bits.
uint32_t tx_port
GPIO port address of transmit pin.
bool usart_enhanced_parity_error(uint32_t usart)
get the parity status of the received data
library for enhanced USART communication (API)
uint32_t cts_pin
GPIO pin address of clear to send pin.