CuVoodoo STM32F1 firmware template
busvoodoo_rs232.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/stm32/gpio.h> // general purpose input output library
28 #include <libopencm3/stm32/rcc.h> // real-time control clock library
29 #include <libopencm3/stm32/usart.h> // USART utilities
30 
31 /* own libraries */
32 #include "global.h" // board definitions
33 #include "print.h" // printing utilities
34 #include "menu.h" // menu definitions
35 #include "busvoodoo_global.h" // BusVoodoo definitions
36 #include "busvoodoo_oled.h" // OLED utilities
37 #include "busvoodoo_rs232.h" // own definitions
38 
42 #define BUSVOODOO_RS232_USART 2
46 static enum busvoodoo_rs232_setting_t {
47  BUSVOODOO_RS232_SETTING_NONE,
48  BUSVOODOO_RS232_SETTING_BAUDRATE,
49  BUSVOODOO_RS232_SETTING_DATABITS,
50  BUSVOODOO_RS232_SETTING_PARITY,
51  BUSVOODOO_RS232_SETTING_STOPBITS,
52  BUSVOODOO_RS232_SETTING_HWFLOWCTL,
53  BUSVOODOO_RS232_SETTING_DONE,
54 } busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_NONE;
56 static uint32_t busvoodoo_rs232_baudrate = 115200;
58 static uint8_t busvoodoo_rs232_databits = 8;
60 static uint32_t busvoodoo_rs232_parity = USART_PARITY_NONE;
62 static uint32_t busvoodoo_rs232_stopbits = USART_STOPBITS_1;
64 static bool busvoodoo_rs232_hwflowctl = false;
65 
71 static bool busvoodoo_rs232_setup(char** prefix, const char* line)
72 {
73  bool complete = false; // is the setup complete
74  if (NULL==line) { // first call
75  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_NONE; // re-start configuration
76  }
77  switch (busvoodoo_rs232_setting) {
78  case BUSVOODOO_RS232_SETTING_NONE:
80  *prefix = busvoodoo_global_string; // ask for baud rate
81  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_BAUDRATE;
82  break;
83  case BUSVOODOO_RS232_SETTING_BAUDRATE:
84  if (NULL==line || 0==strlen(line)) { // use default setting
85  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_DATABITS; // go to next setting
86  } else { // setting provided
87  uint32_t baudrate = atoi(line); // parse setting
88  if (baudrate>0 && baudrate<=2000000) { // check setting
89  busvoodoo_rs232_baudrate = baudrate; // remember setting
90  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_DATABITS; // go to next setting
91  }
92  }
93  if (BUSVOODOO_RS232_SETTING_DATABITS==busvoodoo_rs232_setting) { // if next setting
94  snprintf(busvoodoo_global_string, LENGTH(busvoodoo_global_string), "data bits (8-9) [%u]", busvoodoo_rs232_databits); // prepare next setting
95  *prefix = busvoodoo_global_string; // display next setting
96  }
97  break;
98  case BUSVOODOO_RS232_SETTING_DATABITS:
99  if (NULL==line || 0==strlen(line)) { // use default setting
100  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_PARITY; // go to next setting
101  } else { // setting provided
102  uint8_t databits = atoi(line); // parse setting
103  if (8==databits || 9==databits) { // check setting
104  busvoodoo_rs232_databits = databits; // remember setting
105  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_PARITY; // go to next setting
106  }
107  }
108  if (BUSVOODOO_RS232_SETTING_PARITY==busvoodoo_rs232_setting) { // if next setting
109  printf("1) none\n");
110  printf("2) even\n");
111  printf("3) odd\n");
112  snprintf(busvoodoo_global_string, LENGTH(busvoodoo_global_string), "parity (1,2,3) [%c]", USART_PARITY_NONE==busvoodoo_rs232_parity ? '1' : (USART_PARITY_EVEN==busvoodoo_rs232_parity ? '2' : '3')); // prepare next setting
113  *prefix = busvoodoo_global_string; // display next setting
114  }
115  break;
116  case BUSVOODOO_RS232_SETTING_PARITY:
117  if (NULL==line || 0==strlen(line)) { // use default setting
118  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_STOPBITS; // go to next setting
119  } else if (1==strlen(line)) { // setting provided
120  if ('1'==line[0]) { // no parity
121  busvoodoo_rs232_parity = USART_PARITY_NONE;
122  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_STOPBITS; // go to next setting
123  } else if ('2'==line[0]) { // even parity
124  busvoodoo_rs232_parity = USART_PARITY_EVEN;
125  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_STOPBITS; // go to next setting
126  } else if ('3'==line[0]) { // odd parity
127  busvoodoo_rs232_parity = USART_PARITY_ODD;
128  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_STOPBITS; // go to next setting
129  }
130  }
131  if (BUSVOODOO_RS232_SETTING_STOPBITS==busvoodoo_rs232_setting) { // if next setting
132  printf("1) 0.5\n");
133  printf("2) 1\n");
134  printf("3) 1.5\n");
135  printf("4) 2\n");
136  snprintf(busvoodoo_global_string, LENGTH(busvoodoo_global_string), "stop bits (1,2,3,4) [%s]", USART_STOPBITS_0_5==busvoodoo_rs232_stopbits ? "0.5" : (USART_STOPBITS_1==busvoodoo_rs232_stopbits ? "1" : (USART_STOPBITS_1_5==busvoodoo_rs232_stopbits ? "1.5" : "2.0"))); // prepare next setting
137  *prefix = busvoodoo_global_string; // display next setting
138  }
139  break;
140  case BUSVOODOO_RS232_SETTING_STOPBITS:
141  if (NULL==line || 0==strlen(line)) { // use default setting
142  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_HWFLOWCTL; // go to next setting
143  } else if (1==strlen(line)) { // setting provided
144  if ('1'==line[0]) { // 0.5 stop bits
145  busvoodoo_rs232_stopbits = USART_STOPBITS_0_5; // remember setting
146  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_HWFLOWCTL; // go to next setting
147  } else if ('2'==line[0]) { // 1 stop bits
148  busvoodoo_rs232_stopbits = USART_STOPBITS_1; // remember setting
149  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_HWFLOWCTL; // go to next setting
150  } else if ('3'==line[0]) { // 1.5 stop bits
151  busvoodoo_rs232_stopbits = USART_STOPBITS_1_5; // remember setting
152  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_HWFLOWCTL; // go to next setting
153  } else if ('4'==line[0]) { // 2 stop bits
154  busvoodoo_rs232_stopbits = USART_STOPBITS_2; // remember setting
155  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_HWFLOWCTL; // go to next setting
156  }
157  }
158  if (BUSVOODOO_RS232_SETTING_HWFLOWCTL==busvoodoo_rs232_setting) { // if next setting
159  printf("1) no flow control\n");
160  printf("2) RTS/CTS hardware flow control\n");
161  snprintf(busvoodoo_global_string, LENGTH(busvoodoo_global_string), "flow control (1,2) [%c]", busvoodoo_rs232_hwflowctl ? '2' : '1'); // prepare next setting
162  *prefix = busvoodoo_global_string; // display next setting
163  }
164  break;
165  case BUSVOODOO_RS232_SETTING_HWFLOWCTL:
166  if (NULL==line || 0==strlen(line)) { // use default setting
167  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_DONE; // go to next setting
168  } else if (1==strlen(line)) { // setting provided
169  if ('1'==line[0] || '2'==line[0]) { // setting provided
170  busvoodoo_rs232_hwflowctl = ('2'==line[0]); // remember setting
171  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_DONE; // go to next setting
172  }
173  }
174  if (BUSVOODOO_RS232_SETTING_DONE==busvoodoo_rs232_setting) { // we have all settings, configure RS-232
175  rcc_periph_clock_enable(RCC_AFIO); // enable clock for USART alternate function
176  rcc_periph_clock_enable(RCC_USART(BUSVOODOO_RS232_USART)); // enable clock for USART peripheral
177  usart_set_baudrate(USART(BUSVOODOO_RS232_USART), busvoodoo_rs232_baudrate); // set baud rate
178  usart_set_databits(USART(BUSVOODOO_RS232_USART), busvoodoo_rs232_databits); // set data bits
179  usart_set_parity(USART(BUSVOODOO_RS232_USART), busvoodoo_rs232_parity); // set parity
180  usart_set_stopbits(USART(BUSVOODOO_RS232_USART), busvoodoo_rs232_stopbits); // set stop bits
182  usart_set_flow_control(USART(BUSVOODOO_RS232_USART), USART_FLOWCONTROL_RTS_CTS); // set RTS/CTS flow control
183  } else {
184  usart_set_flow_control(USART(BUSVOODOO_RS232_USART), USART_FLOWCONTROL_NONE); // set no flow control
185  }
186  usart_set_mode(USART(BUSVOODOO_RS232_USART), USART_MODE_TX_RX); // full-duplex communication
187  rcc_periph_clock_enable(RCC_USART_PORT(BUSVOODOO_RS232_USART)); // enable clock for USART GPIO peripheral
188  gpio_set_mode(USART_TX_PORT(BUSVOODOO_RS232_USART), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USART_TX_PIN(BUSVOODOO_RS232_USART)); // setup GPIO pin USART transmit
189  gpio_set_mode(USART_RX_PORT(BUSVOODOO_RS232_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, USART_RX_PIN(BUSVOODOO_RS232_USART)); // setup GPIO pin USART receive (no need to pull since the transceiver will drive it)
190  if (busvoodoo_rs232_hwflowctl) { // use open drain drive mode
191  gpio_set_mode(USART_RTS_PORT(BUSVOODOO_RS232_USART), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, USART_RTS_PIN(BUSVOODOO_RS232_USART)); // setup GPIO pin USART transmit
192  gpio_set_mode(USART_CTS_PORT(BUSVOODOO_RS232_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, USART_CTS_PIN(BUSVOODOO_RS232_USART)); // setup GPIO pin USART receive (no need to pull since the transceiver will drive it)
193  }
194  gpio_clear(GPIO(BUSVOODOO_RS232_EN_PORT), GPIO(BUSVOODOO_RS232_EN_PIN)); // set low to enable RS-232 transceiver receiver
195  gpio_set(GPIO(BUSVOODOO_RS232_SHDN_PORT), GPIO(BUSVOODOO_RS232_SHDN_PIN)); // set high to enable RS-232 transceiver transmitter
196  usart_enable(USART(BUSVOODOO_RS232_USART)); // enable USART
197  busvoodoo_led_blue_off(); // disable blue LED since there is no activity
198  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_NONE; // restart settings next time
199  *prefix = "RS-232"; // display mode
200  busvoodoo_oled_text_left(*prefix); // set mode title on OLED display
201  char* pinout_io[10] = {"GND", "5V", "3V3", "LV", NULL, NULL, NULL, NULL, NULL, NULL}; // RS-232 mode I/O pinout
202  for (uint8_t i=0; i<LENGTH(pinout_io) && i<LENGTH(busvoodoo_global_pinout_io); i++) {
203  busvoodoo_global_pinout_io[i] = pinout_io[i]; // set pin names
204  }
205  char* pinout_rscan[5] = {"HV", "Rx", "Tx", NULL, NULL}; // RS-232 mode RS/CAN pinout
206  if (busvoodoo_rs232_hwflowctl) { // hardware flow control is used
207  pinout_rscan[3] = "RTS"; // update pin name
208  pinout_rscan[4] = "CTS"; // update pin name
209  }
210  for (uint8_t i=0; i<LENGTH(pinout_rscan) && i<LENGTH(busvoodoo_global_pinout_rscan); i++) {
211  busvoodoo_global_pinout_rscan[i] = pinout_rscan[i]; // set pin names
212  }
213  char* pinout[10] = {pinout_rscan[0], pinout_io[0], pinout_rscan[1], pinout_io[2], pinout_rscan[2], pinout_io[4], pinout_rscan[3], pinout_io[6], pinout_rscan[4], pinout_io[8]}; // pinout to display
214  busvoodoo_oled_text_pinout((const char**)pinout, false); // set pinout on display
215  busvoodoo_oled_update(); // update display to show text and pinout
216  complete = true; // configuration is complete
217  }
218  break;
219  default: // unknown case
220  busvoodoo_rs232_setting = BUSVOODOO_RS232_SETTING_NONE; // restart settings next time
221  break;
222  }
223  return complete;
224 }
225 
228 static void busvoodoo_rs232_exit(void)
229 {
230  usart_disable(USART(BUSVOODOO_RS232_USART)); // disable USART
231  rcc_periph_clock_disable(RCC_USART(BUSVOODOO_RS232_USART)); // disable domain clock for USART peripheral
232  gpio_set_mode(USART_TX_PORT(BUSVOODOO_RS232_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, USART_TX_PIN(BUSVOODOO_RS232_USART)); // set pin back to floating input
233  gpio_set_mode(USART_RX_PORT(BUSVOODOO_RS232_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, USART_RX_PIN(BUSVOODOO_RS232_USART)); // set pin back to floating input
234  gpio_set_mode(USART_RTS_PORT(BUSVOODOO_RS232_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, USART_RTS_PIN(BUSVOODOO_RS232_USART)); // set pin back to floating input
235  gpio_set_mode(USART_CTS_PORT(BUSVOODOO_RS232_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, USART_CTS_PIN(BUSVOODOO_RS232_USART)); // set pin back to floating input
236  gpio_set(GPIO(BUSVOODOO_RS232_EN_PORT), GPIO(BUSVOODOO_RS232_EN_PIN)); // set high to disable RS-232 transceiver receiver
237  gpio_clear(GPIO(BUSVOODOO_RS232_SHDN_PORT), GPIO(BUSVOODOO_RS232_SHDN_PIN)); // set low to disable RS-232 transceiver transmitter
238 }
239 
243 static void busvoodoo_rs232_write(uint16_t value)
244 {
245  while ((0==(USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_TXE) && !user_input_available)); // wait for transmit buffer to be empty (or user to interrupt)
246  if (USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_TXE) { // we can send a character
247  // remove unused bits
248  if (USART_PARITY_NONE==busvoodoo_rs232_parity) { // no parity bit in frame
249  if (8==busvoodoo_rs232_databits) { // 8-bit frame
250  value &= 0xff;
251  } else { // 9-bit frame
252  value &= 0x1ff;
253  }
254  } else { // MSb is parity bit
255  if (8==busvoodoo_rs232_databits) { // 8-bit frame
256  value &= 0x7f;
257  } else { // 9-bit frame
258  value &= 0xff;
259  }
260  }
261  // send data
262  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // pulse blue LED to show transmission
263  usart_send(USART(BUSVOODOO_RS232_USART), value); // transmit character
264  // display data send
265  printf("write: '%c'/0x", value);
266  if ((USART_PARITY_NONE==busvoodoo_rs232_parity) && 9==busvoodoo_rs232_databits) { // case where the final data is 9 bits long
267  printf("%03x\n", value);
268  } else {
269  printf("%02x\n", value);
270  }
271  }
272 }
273 
276 static void busvoodoo_rs232_read(void)
277 {
278  printf("read: ");
279  while (!(USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_RXNE) && !user_input_available); // wait for incoming data to be available (or user input to exit)
280  if ((USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_RXNE)) { // verify if data has been received
281  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // enable blue LED to show reception
282  // get the errors
283  bool error_noise = (0!=(USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_NE)); // read noise error flag
284  bool error_framing = (0!=(USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_FE)); // read frame error flag
285  bool error_parity = (0!=(USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_PE)); // read parity error flag
286  uint16_t c = usart_recv(USART(BUSVOODOO_RS232_USART)); // read received character (also clears the error flags)
287  // remove unused bits
288  if (USART_PARITY_NONE==busvoodoo_rs232_parity) { // no parity bit in frame
289  if (8==busvoodoo_rs232_databits) { // 8-bit frame
290  c &= 0xff;
291  } else { // 9-bit frame
292  c &= 0x1ff;
293  }
294  } else { // MSb is parity bit
295  if (8==busvoodoo_rs232_databits) { // 8-bit frame
296  c &= 0x7f;
297  } else { // 9-bit frame
298  c &= 0xff;
299  }
300  }
301  // display data
302  printf("'%c'/0x", c);
303  if ((USART_PARITY_NONE==busvoodoo_rs232_parity) && 9==busvoodoo_rs232_databits) { // case where the final data is 9 bits long
304  printf("%03x ", c);
305  } else {
306  printf("%02x ", c);
307  }
308  // display errors
309  printf("(");
310  if (error_noise) {
311  printf("noise");
312  } else if (error_framing) {
313  printf("framing");
314  } else if (error_parity) {
315  printf("parity");
316  } else {
317  printf("no");
318  }
319  printf(" error)");
320  }
321  printf("\n");
322 }
323 
330 static bool busvoodoo_rs232_action(const char* action, uint32_t repetition, bool perform)
331 {
332  uint32_t length = strlen(action); // remember length since it will be used a number of times
333  if (NULL==action || 0==length) { // there is nothing to do
334  return true;
335  }
336 
337  if (1==length && 'r'==action[0]) { // read data
338  if (!perform) {
339  return true;
340  }
341  for (uint32_t i=0; i<repetition; i++) {
342  busvoodoo_rs232_read(); // read from RS-232
343  }
344  } else if (1==length && 'u'==action[0]) { // sleep us
345  if (!perform) {
346  return true;
347  }
348  printf("wait for %u us\n", repetition);
349  sleep_us(repetition); // sleep
350  } else if (1==length && 'm'==action[0]) { // sleep ms
351  if (!perform) {
352  return true;
353  }
354  printf("wait for %u ms\n", repetition);
355  sleep_ms(repetition); // sleep
356  } else if ('0'==action[0]) { // send digit
357  if (1==length) { // just send 0
358  if (!perform) {
359  return true;
360  }
361  for (uint32_t i=0; i<repetition; i++) {
362  busvoodoo_rs232_write(0); // write to RS-232
363  }
364  } else if ('x'==action[1] || 'b'==action[1]) { // send hex/binary
365  return busvoodoo_rs232_action(action+1, repetition, perform); // just retry without leading 0
366  } else if (action[1]>='0' && action[1]<='9') { // send decimal
367  return busvoodoo_rs232_action(action+1, repetition, perform); // just retry without leading 0
368  } else { // malformed action
369  return false;
370  }
371  } else if ('x'==action[0] && length>1) { // send hexadecimal value
372  for (uint32_t i=1; i<length; i++) { // check string
373  if (!((action[i]>='0' && action[i]<='9') || (action[i]>='a' && action[i]<='f') || (action[i]>='A' && action[i]<='F'))) { // check for hexadecimal character
374  return false; // not an hexadecimal string
375  }
376  }
377  if (!perform) {
378  return true;
379  }
380  uint32_t value = strtol(&action[1], NULL, 16); // get hex value
381  for (uint32_t i=0; i<repetition; i++) {
382  busvoodoo_rs232_write(value); // write to SPI
383  }
384  } else if ('b'==action[0] && length>1) { // send binary value
385  for (uint32_t i=1; i<length; i++) { // check string
386  if (action[i]<'0' || action[i]>'1') { // check for binary character
387  return false; // not a binary string
388  }
389  }
390  if (!perform) {
391  return true;
392  }
393  uint32_t value = strtol(&action[1], NULL, 2); // get binary value
394  for (uint32_t i=0; i<repetition; i++) {
395  busvoodoo_rs232_write(value); // write to SPI
396  }
397  } else if (action[0]>='1' && action[0]<='9') { // send decimal value
398  for (uint32_t i=1; i<length; i++) { // check string
399  if (action[i]<'0' || action[i]>'9') { // check for decimal character
400  return false; // not a decimal string
401  }
402  }
403  if (!perform) {
404  return true;
405  }
406  uint32_t value = strtol(&action[0], NULL, 10); // get decimal value
407  for (uint32_t i=0; i<repetition; i++) {
408  busvoodoo_rs232_write(value); // write to SPI
409  }
410  } else if (length>=2 && ('"'==action[0] || '\''==action[0]) && (action[length-1]==action[0])) { // send ASCII character
411  if (!perform) {
412  return true;
413  }
414  for (uint32_t r=0; r<repetition; r++) {
415  for (uint32_t i=1; i<length-1; i++) { // go through string
416  busvoodoo_rs232_write(action[i]); // write to SPI
417  }
418  }
419  } else { // malformed action
420  return false;
421  }
422  return true; // all went well
423 }
424 
425 
426 // command handlers
427 
431 static void busvoodoo_rs232_command_actions(void* argument)
432 {
433  if (NULL==argument || 0==strlen(argument)) {
434  printf("available actions (separated by space or ,):\n");
435  printf("0\twrite decimal value\n");
436  printf("0x0\twrite hexadecimal value\n");
437  printf("0b0\twrite binary value\n");
438  printf("\"a\"/'a'\twrite ASCII characters\n");
439  printf("r\tread value\n");
440  printf("u/m\twait 1 us/ms\n");
441  printf(":n\trepeat action n times\n");
442  return;
443  }
444 
445  // copy argument since it will be modified
446  char* copy = calloc(strlen(argument)+1, sizeof(char));
447  if (!copy) {
448  while (true);
449  }
450  strncpy(copy, argument, strlen(argument)+1);
451  // verify and perform actions
452  if (!busvoodoo_global_actions(copy, false, &busvoodoo_rs232_action)) { // verify actions
453  printf("malformed action(s)\n");
454  } else { // action are ok
455  printf("press any key to exit\n");
456  busvoodoo_global_actions(argument, true, &busvoodoo_rs232_action); // perform action
457  if (user_input_available) { // user interrupted flow
458  user_input_get(); // discard user input
459  }
460  }
461  free(copy); // release memory
462 }
463 
467 static void busvoodoo_rs232_command_transmit(void* argument)
468 {
469  if (NULL==argument || 0==strlen(argument)) { // nothing to transmit
470  argument = "\r\n"; // transmit CR+LF
471  }
472  printf("press any key to exit\n");
473  for (uint16_t i=0; ((char*)(argument))[i] && !user_input_available; i++) {
474  while ((0==(USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_TXE) && !user_input_available)); // wait for transmit buffer to be empty
475  if (USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_TXE) { // we can send a character
476  printf("%c", ((char*)(argument))[i]); // echo character to transmit
477  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // pulse blue LED to show transmission
478  usart_send(USART(BUSVOODOO_RS232_USART), ((char*)(argument))[i]); // transmit character
479  }
480  }
481  if (user_input_available) { // user interrupted flow
482  user_input_get(); // discard user input
483  }
484  if (strcmp(argument, "\r\n")) {
485  printf("\n");
486  }
487 }
488 
492 static void busvoodoo_rs232_command_receive(void* argument)
493 {
494  bool display_hex = false; // display in hex
495  bool display_bin = false; // display in bin
496  if (NULL!=argument && strlen(argument)>0) {
497  if (0==strcmp(argument, "h") || 0==strcmp(argument, "hex")) { // user wants hexadecimal display
498  display_hex = true; // remember to display in hexadecimal
499  } else if (0==strcmp(argument, "b") || 0==strcmp(argument, "bin")) { // user wants binary display
500  display_bin = true; // remember to display in binary
501  } else {
502  printf("malformed argument\n");
503  return;
504  }
505  }
506  printf("press any key to exit\n");
507  while (!user_input_available) { // check for user input to exit
508  if ((USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_RXNE)) { // verify if data has been received
509  uint16_t c = usart_recv(USART(BUSVOODOO_RS232_USART)); // receive character
510  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // enable blue LED to show reception
511  // remove unused bits (ignore parity bit)
512  if (USART_PARITY_NONE==busvoodoo_rs232_parity) { // no parity bit in frame
513  if (8==busvoodoo_rs232_databits) { // 8-bit frame
514  c &= 0xff;
515  } else { // 9-bit frame
516  c &= 0x1ff;
517  }
518  } else { // MSb is parity bit
519  if (8==busvoodoo_rs232_databits) { // 8-bit frame
520  c &= 0x7f;
521  } else { // 9-bit frame
522  c &= 0xff;
523  }
524  }
525  if (display_hex) { // display data in hex
526  if ((USART_PARITY_NONE==busvoodoo_rs232_parity) && 9==busvoodoo_rs232_databits) { // case where the final data is 9 bits long
527  printf("%03x ", c);
528  } else {
529  printf("%02x ", c);
530  }
531  } else if (display_bin) { // display data in binary
532  if (USART_PARITY_NONE==busvoodoo_rs232_parity) {
533  if (8==busvoodoo_rs232_databits) { // 8-bit frame
534  printf("%08b ", c);
535  } else { // 9-bit frame
536  printf("%09b ", c);
537  }
538  } else { // one bit is a parity bit
539  if (8==busvoodoo_rs232_databits) { // 8-bit frame
540  printf("%07b ", c);
541  } else { // 9-bit frame
542  printf("%08b ", c);
543  }
544  }
545  } else { // display in ASCII
546  printf("%c", c); // print received character
547  }
548  }
549  }
550  user_input_get(); // discard user input
551  printf("\n"); // get to next line
552 }
553 
557 static void busvoodoo_rs232_command_transceive(void* argument)
558 {
559  (void)argument; // we won't use the argument
560  printf("press 5 times escape to exit\n");
561  char last_c = 0; // last user character received
562  uint8_t esc_count = 0; // number of times escape has press received
563  while (true) { // check for escape sequence
564  if (user_input_available) { // check if user wants to transmit something
565  char c = user_input_get(); // get user input
566  if (0x1b==c) { // user pressed escape
567  if (0x1b!=last_c) { // this is the first escape press
568  esc_count = 0;
569  }
570  esc_count++; // increment escape count
571  }
572  last_c = c; // remember key press
573  if (esc_count<5) { // check for escape sequence
574  while ((0==(USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_TXE) && !user_input_available)); // wait for transmit buffer to be empty
575  if (USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_TXE) { // we can send a character
576  usart_send_blocking(USART(BUSVOODOO_RS232_USART), c); // send user character
577  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // enable blue LED to show transmission
578  }
579  } else { // user wants to exit
580  break; // exit infinite loop
581  }
582  }
583  if ((USART_SR(USART(BUSVOODOO_RS232_USART)) & USART_SR_RXNE)) { // verify if data has been received
584  char c = usart_recv(USART(BUSVOODOO_RS232_USART)); // receive character
585  busvoodoo_led_blue_pulse(BUSVOODOO_LED_PULSE); // enable blue LED to show reception
586  printf("%c", c); // print received character
587  }
588  }
589  printf("\n"); // get to next line
590 }
591 
595 static void busvoodoo_rs232_command_error(void* argument)
596 {
597  (void)argument; // argument not used
598  printf("press any key to exit\n");
599  while (!user_input_available) { // wait until user interrupt
600  busvoodoo_rs232_read(); // read incoming data (this also checks for errors
601  }
602  user_input_get(); // discard user input
603 }
604 
606 static const struct menu_command_t busvoodoo_rs232_commands[] = {
607  {
608  .shortcut = 'a',
609  .name = "action",
610  .command_description = "perform protocol actions",
611  .argument = MENU_ARGUMENT_STRING,
612  .argument_description = "[actions]",
613  .command_handler = &busvoodoo_rs232_command_actions,
614  },
615  {
616  .shortcut = 'r',
617  .name = "receive",
618  .command_description = "show incoming data [in hexadecimal or binary]",
619  .argument = MENU_ARGUMENT_STRING,
620  .argument_description = "[hex|bin]",
621  .command_handler = &busvoodoo_rs232_command_receive,
622  },
623  {
624  .shortcut = 't',
625  .name = "transmit",
626  .command_description = "transmit ASCII text (empty for CR+LF)",
627  .argument = MENU_ARGUMENT_STRING,
628  .argument_description = "[text]",
629  .command_handler = &busvoodoo_rs232_command_transmit,
630  },
631  {
632  .shortcut = 'x',
633  .name = "transceive",
634  .command_description = "transmit and receive data",
635  .argument = MENU_ARGUMENT_NONE,
636  .argument_description = NULL,
637  .command_handler = &busvoodoo_rs232_command_transceive,
638  },
639  {
640  .shortcut = 'e',
641  .name = "error",
642  .command_description = "verify incoming transmission for errors",
643  .argument = MENU_ARGUMENT_NONE,
644  .argument_description = NULL,
645  .command_handler = &busvoodoo_rs232_command_error,
646  },
647 };
648 
650  .name = "rs232",
651  .description = "Recommended Standard 232",
652  .full_only = true,
653  .setup = &busvoodoo_rs232_setup,
654  .commands = busvoodoo_rs232_commands,
655  .commands_nb = LENGTH(busvoodoo_rs232_commands),
656  .exit = &busvoodoo_rs232_exit,
657 };
#define USART_TX_PORT(x)
get port for USART transmit pin based on USART identifier
Definition: global.h:190
#define RCC_USART(x)
get RCC for USART based on USART identifier
Definition: global.h:184
static void busvoodoo_rs232_command_actions(void *argument)
command to perform actions
static uint8_t busvoodoo_rs232_databits
RS-232 data bits.
command menu entry
Definition: menu.h:31
#define BUSVOODOO_LED_PULSE
recommended duration in ms for pulsing LEDs to show activity
static uint32_t busvoodoo_rs232_parity
RS-232 parity setting.
BusVoodoo global definitions and methods (API)
static void busvoodoo_rs232_exit(void)
exit RS-232 mode
static const struct menu_command_t busvoodoo_rs232_commands[]
RS-232 menu commands.
void busvoodoo_oled_text_pinout(const char *pins[10], bool io_connector)
draw pin names on bottom (blue) part in display buffer
const char * name
name of the mode (i.e.
void busvoodoo_led_blue_pulse(uint32_t ms)
pulse blue LED for short duration
static void busvoodoo_rs232_command_transceive(void *argument)
command to transmit and receive data
#define BUSVOODOO_RS232_EN_PORT
RS-232 pin to enable receiver (active low, pulled up)
static void busvoodoo_rs232_command_error(void *argument)
command to verify incoming transmission for error
static void busvoodoo_rs232_write(uint16_t value)
write to RS-232
#define RCC_USART_PORT(x)
get RCC for USART port based on USART identifier
Definition: global.h:206
void busvoodoo_oled_update(void)
update OLED display RAM with current display buffer
const char * busvoodoo_global_pinout_rscan[5]
RS/CAN connector pinout.
static void busvoodoo_rs232_command_receive(void *argument)
command to receive data
global definitions and methods (API)
#define GPIO(x)
get GPIO based on GPIO identifier
Definition: global.h:103
static bool busvoodoo_rs232_setup(char **prefix, const char *line)
setup RS-232 mode
void sleep_us(uint32_t duration)
go to sleep for some microseconds
Definition: global.c:102
void busvoodoo_led_blue_off(void)
switch off blue LED
#define USART_RX_PIN(x)
get pin for USART receive pin based on USART identifier
Definition: global.h:200
#define USART_TX_PIN(x)
get pin for USART transmit pin based on USART identifier
Definition: global.h:198
static enum busvoodoo_rs232_setting_t busvoodoo_rs232_setting
current mode setup stage
static void busvoodoo_rs232_command_transmit(void *argument)
command to transmit a string
#define USART_CTS_PORT(x)
get port for USART CTS pin based on USART identifier
Definition: global.h:196
#define USART(x)
get USART based on USART identifier
Definition: global.h:182
char shortcut
short command code (0 if not available)
Definition: menu.h:32
const char * busvoodoo_global_pinout_io[10]
I/O connector pinout.
char user_input_get(void)
get user input
Definition: global.c:145
#define BUSVOODOO_RS232_EN_PIN
RS-232 pin to enable receiver (active low, pulled up)
static uint32_t busvoodoo_rs232_baudrate
RS-232 baud rate (in bps)
static bool busvoodoo_rs232_hwflowctl
RS-232 hardware flow control setting (true = with hardware flow control, false = without hardware flo...
char busvoodoo_global_string[64]
shared string buffer, i.e.
#define BUSVOODOO_RS232_USART
USART peripheral.
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
#define USART_RX_PORT(x)
get port for USART receive pin based on USART identifier
Definition: global.h:192
#define USART_RTS_PIN(x)
get pin for USART RTS pin based on USART identifier
Definition: global.h:202
const struct busvoodoo_mode_t busvoodoo_rs232_mode
RS-232 mode interface definition.
#define USART_CTS_PIN(x)
get pin for USART CTS pin based on USART identifier
Definition: global.h:204
static void busvoodoo_rs232_read(void)
read from RS-232
void busvoodoo_oled_text_left(char *text)
draw mode text on top (yellow) left side in display buffer
#define LENGTH(x)
get the length of an array
Definition: global.h:26
BusVoodoo RS-232 mode (API)
library to show BusVoodoo mode information on SSD1306 OLED display: name, activity, pinout (API)
static bool busvoodoo_rs232_action(const char *action, uint32_t repetition, bool perform)
perform RS-232 action
volatile bool user_input_available
flag set when user input is available
Definition: global.c:36
BusVoodoo mode interface.
static uint32_t busvoodoo_rs232_stopbits
RS-232 stop bits setting.
#define USART_RTS_PORT(x)
get port for USART RTS pin based on USART identifier
Definition: global.h:194
#define BUSVOODOO_RS232_SHDN_PORT
RS-232 pin to enable transmitter (active high, pulled low)
#define BUSVOODOO_RS232_SHDN_PIN
RS-232 pin to enable transmitter (active high, pulled low)