27 #include <libopencm3/cm3/nvic.h> 28 #include <libopencm3/stm32/gpio.h> 29 #include <libopencm3/stm32/rcc.h> 30 #include <libopencm3/stm32/usart.h> 31 #include <libopencm3/stm32/timer.h> 46 BUSVOODOO_UART_SETTING_NONE,
47 BUSVOODOO_UART_SETTING_BAUDRATE,
48 BUSVOODOO_UART_SETTING_DATABITS,
49 BUSVOODOO_UART_SETTING_PARITY,
50 BUSVOODOO_UART_SETTING_STOPBITS,
51 BUSVOODOO_UART_SETTING_HWFLOWCTL,
52 BUSVOODOO_UART_SETTING_DRIVE,
53 BUSVOODOO_UART_SETTING_DONE,
74 #define BUSVOODOO_UART_TIMER_USE_INTERRUPT_TABLE false 103 bool complete =
false;
108 case BUSVOODOO_UART_SETTING_NONE:
113 case BUSVOODOO_UART_SETTING_BAUDRATE:
114 if (NULL==line || 0==strlen(line)) {
117 uint32_t baudrate = atoi(line);
118 if (baudrate>0 && baudrate<=2000000) {
128 case BUSVOODOO_UART_SETTING_DATABITS:
129 if (NULL==line || 0==strlen(line)) {
131 }
else if (1==strlen(line)) {
132 uint8_t databits = atoi(line);
133 if (databits>=5 && databits<=8) {
148 case BUSVOODOO_UART_SETTING_PARITY:
149 if (NULL==line || 0==strlen(line)) {
151 }
else if (1==strlen(line)) {
152 uint8_t parity = atoi(line);
153 if (parity>0 && parity<6) {
167 case BUSVOODOO_UART_SETTING_STOPBITS:
168 if (NULL==line || 0==strlen(line)) {
170 }
else if (1==strlen(line)) {
174 }
else if (
'2'==line[0]) {
177 }
else if (
'3'==line[0]) {
180 }
else if (
'4'==line[0]) {
190 printf(
"1) no flow control\n");
191 printf(
"2) RTS/CTS hardware flow control\n");
196 case BUSVOODOO_UART_SETTING_HWFLOWCTL:
197 if (NULL==line || 0==strlen(line)) {
199 }
else if (1==strlen(line)) {
200 if (
'1'==line[0] ||
'2'==line[0]) {
212 printf(
"1) push-pull (3.3V)\n");
213 printf(
"2) open-drain, with embedded pull-up resistors (2kO)\n");
214 printf(
"3) open-drain, with external pull-up resistors\n");
219 case BUSVOODOO_UART_SETTING_DRIVE:
220 if (NULL==line || 0==strlen(line)) {
222 }
else if (1==strlen(line)) {
223 uint8_t drive = atoi(line);
224 if (1==drive || 2==drive || 3==drive) {
232 rcc_periph_clock_enable(RCC_AFIO);
269 printf(
"use LV to set pull-up voltage\n");
323 printf(
"write: '%c'/0x%02x\n", value, value);
353 printf(
"'%c'/0x%02x", input, input);
358 }
else if (error_framing) {
384 uint32_t length = strlen(action);
385 if (NULL==action || 0==length) {
389 if (1==length &&
'r'==action[0]) {
393 for (uint32_t i=0; i<repetition; i++) {
396 }
else if (1==length &&
'u'==action[0]) {
400 printf(
"wait for %u us\n", repetition);
402 }
else if (1==length &&
'm'==action[0]) {
406 printf(
"wait for %u ms\n", repetition);
408 }
else if (
'0'==action[0]) {
413 for (uint32_t i=0; i<repetition; i++) {
416 }
else if (
'x'==action[1] ||
'b'==action[1]) {
418 }
else if (action[1]>=
'0' && action[1]<=
'9') {
423 }
else if (
'x'==action[0] && length>1) {
424 for (uint32_t i=1; i<length; i++) {
425 if (!((action[i]>=
'0' && action[i]<=
'9') || (action[i]>=
'a' && action[i]<=
'f') || (action[i]>=
'A' && action[i]<=
'F'))) {
432 uint32_t value = strtol(&action[1], NULL, 16);
433 for (uint32_t i=0; i<repetition; i++) {
436 }
else if (
'b'==action[0] && length>1) {
437 for (uint32_t i=1; i<length; i++) {
438 if (action[i]<
'0' || action[i]>
'1') {
445 uint32_t value = strtol(&action[1], NULL, 2);
446 for (uint32_t i=0; i<repetition; i++) {
449 }
else if (action[0]>=
'1' && action[0]<=
'9') {
450 for (uint32_t i=1; i<length; i++) {
451 if (action[i]<
'0' || action[i]>
'9') {
458 uint32_t value = strtol(&action[0], NULL, 10);
459 for (uint32_t i=0; i<repetition; i++) {
462 }
else if (length>=2 && (
'"'==action[0] ||
'\''==action[0]) && (action[length-1]==action[0])) {
466 for (uint32_t r=0; r<repetition; r++) {
467 for (uint32_t i=1; i<length-1; i++) {
484 if (NULL==argument || 0==strlen(argument)) {
485 printf(
"available actions (separated by space or ,):\n");
486 printf(
"0\twrite decimal value\n");
487 printf(
"0x0\twrite hexadecimal value\n");
488 printf(
"0b0\twrite binary value\n");
489 printf(
"\"a\"/'a'\twrite ASCII characters\n");
490 printf(
"r\tread value\n");
491 printf(
"u/m\twait 1 us/ms\n");
492 printf(
":n\trepeat action n times\n");
497 char* copy = calloc(strlen(argument)+1,
sizeof(
char));
501 strncpy(copy, argument, strlen(argument)+1);
504 printf(
"malformed action(s)\n");
506 printf(
"press any key to exit\n");
526 if (NULL==argument || 0==strlen(argument)) {
529 printf(
"press any key to exit\n");
533 printf(
"%c", ((
char*)(argument))[i]);
542 if (strcmp(argument,
"\r\n")) {
555 bool display_hex =
false;
556 bool display_bin =
false;
557 if (NULL!=argument && strlen(argument)>0) {
558 if (0==strcmp(argument,
"h") || 0==strcmp(argument,
"hex")) {
560 }
else if (0==strcmp(argument,
"b") || 0==strcmp(argument,
"bin")) {
563 printf(
"malformed argument\n");
573 printf(
"press any key to exit\n");
580 }
else if (display_bin) {
606 printf(
"press 5 times escape to exit\n");
608 uint8_t esc_count = 0;
660 printf(
"press any key to exit\n");
695 #if defined(BUSVOODOO_UART_TIMER_USE_INTERRUPT_TABLE) && BUSVOODOO_UART_TIMER_USE_INTERRUPT_TABLE 696 static void timer_isr(
void)
702 static uint32_t pulse = UINT32_MAX;
705 if (pulse>(UINT32_MAX-0x10000)) {
717 if (UINT32_MAX!=pulse) {
718 pulse = ((pulse&0xffff0000)+edge)-(pulse&0xffff);
736 printf(
"baud rate detection not possible (no timer available)\n");
739 printf(
"the more traffic is incoming, the better the detection\n");
740 printf(
"press any key to exit\n");
743 uint8_t uart_databits = 8;
777 #if defined(BUSVOODOO_UART_TIMER_USE_INTERRUPT_TABLE) && BUSVOODOO_UART_TIMER_USE_INTERRUPT_TABLE 792 bool reset_state =
true;
794 bool wait_for_idle =
false;
803 uint8_t uart_configuration_valid =
LENGTH(uart_configurations);
804 char uart_configuration_parity =
'?';
805 const uint32_t baudrates[] = { 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 576000, 921600 };
806 uint32_t uart_baudrate = 0;
810 for (uint8_t i=0; i<
LENGTH(uart_configurations); i++) {
821 if (baudrate>uart_baudrate+100) {
822 uart_baudrate = baudrate;
823 if (uart_baudrate>=1200) {
825 uint32_t standard_baudrate = 0;
826 for (uint8_t i=0; i<
LENGTH(baudrates); i++) {
827 if (uart_baudrate>=baudrates[i]*0.9 && uart_baudrate<=baudrates[i]*1.1) {
828 standard_baudrate = baudrates[i];
832 if (standard_baudrate) {
833 uart_baudrate = standard_baudrate;
838 printf(
"\nnew baud rate: %u bps\n", uart_baudrate);
840 printf(
"\ndetected %u bps baud rate is lower than minimum supported 1200 bps\n", baudrate);
852 uart_databits = ((8==uart_databits) ? 9 : 8);
859 printf(
"\nrestarting guessing because too detected error\n");
861 wait_for_idle =
true;
870 wait_for_idle =
false;
878 if (0 == uart_baudrate) {
881 uint16_t usart_data_padded = ((8 == uart_databits) ? usart_data | 0xff00 : usart_data | 0xfe00);
882 uint16_t usart_data_relevant = usart_data & ~(0xffff << uart_configurations[uart_configuration_valid].
databits);
884 for (uint8_t i = 0; i <
LENGTH(uart_configurations); i++) {
897 uart_configurations[i].
parity_mark &= (usart_data_padded & (1 << uart_configurations[i].
databits));
900 uart_configurations[i].
parity_space &= !(usart_data_padded & (1 << uart_configurations[i].
databits));
918 if (~usart_data_padded & databits_mask) {
922 bool no_valid_configuration =
true;
923 uint8_t new_valid_configuration =
LENGTH(uart_configurations);
925 for (uint8_t i=0; i<
LENGTH(uart_configurations); i++) {
930 no_valid_configuration =
false;
935 }
else if (uart_configurations[i].
parity_odd) {
944 new_valid_configuration = i;
947 if (no_valid_configuration) {
951 }
else if (new_valid_configuration <
LENGTH(uart_configurations) &&
'?' != parity && (new_valid_configuration != uart_configuration_valid || parity != uart_configuration_parity)) {
952 uart_configuration_valid = new_valid_configuration;
953 uart_configuration_parity = parity;
954 printf(
"\nnew UART configuration found: %u %u%c1\n", uart_baudrate, uart_configurations[uart_configuration_valid].
databits, uart_configuration_parity);
957 if (uart_configuration_valid <
LENGTH(uart_configurations)) {
958 if (uart_configurations[uart_configuration_valid].
databits >= 7 && usart_data_relevant < 0x80) {
959 printf(
"%c", usart_data_relevant);
961 printf(
"0x%02x ", usart_data_relevant);
964 printf(
"0b%09b\n", usart_data_relevant);
978 #if defined(BUSVOODOO_UART_TIMER_USE_INTERRUPT_TABLE) && BUSVOODOO_UART_TIMER_USE_INTERRUPT_TABLE 990 if (uart_configuration_valid <
LENGTH(uart_configurations)) {
991 printf(
"press y to use configuration found: %u %u%c1\n", uart_baudrate, uart_configurations[uart_configuration_valid].
databits, uart_configuration_parity);
996 if (uart_configurations[uart_configuration_valid].
parity_even) {
998 }
else if (uart_configurations[uart_configuration_valid].
parity_odd) {
1000 }
else if (uart_configurations[uart_configuration_valid].
parity_mark) {
1002 }
else if (uart_configurations[uart_configuration_valid].
parity_space) {
1022 .command_description =
"perform protocol actions",
1024 .argument_description =
"[actions]",
1030 .command_description =
"show incoming data [in hexadecimal or binary]",
1032 .argument_description =
"[hex|bin]",
1038 .command_description =
"transmit ASCII text (empty for CR+LF)",
1040 .argument_description =
"[text]",
1045 .name =
"transceive",
1046 .command_description =
"transmit and receive data",
1048 .argument_description = NULL,
1054 .command_description =
"verify incoming transmission for errors",
1056 .argument_description = NULL,
1062 .command_description =
"auto-detect serial configuration (baud rate, data bits, parity)",
1064 .argument_description = NULL,
static uint32_t busvoodoo_uart_generic_baudrate
UART baud rate (in bps)
uint32_t timer_pin
pin of timer capture channel
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
volatile uint32_t pulse_duration
smallest pulse duration measured
bool parity_odd
if the date is still matching the additional odd parity bit
#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
the possible properties of a UART configuration (to be updated with every character) ...
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
uint8_t parity_possibilities
the number to still matching parity possibilities (number of parity_* at true)
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
enum tim_ic_id timer_ic
timer input capture channel
volatile bool pulse_flag
set when a small pulse time is detected
uint32_t rx_pin
GPIO pin address of receive pin.
uint32_t timer_port
port of timer capture channel
global definitions and methods (API)
uint32_t timer_dier_ccie
timer channel capture interrupt enable
uint32_t timer_port_rcc
port RCC of timer capture channel
uint32_t rts_port
GPIO port address of request to send pin.
volatile uint32_t * timer_ccr
timer channel capture register
void sleep_us(uint32_t duration)
go to sleep for some microseconds
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
uint32_t timer
timer peripheral
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
static void busvoodoo_uart_generic_command_detect(void *argument)
command to auto-detect incoming UART configuration (baud rate, data bits, parity) ...
void TIM_ISR(2)
timer ISR to measure edge timing
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.
bool parity_even
if the date is still matching the additional even parity bit
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 timer_rcc
timer RCC address
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)
vector_table_entry_t interrupt_table[NVIC_IRQ_COUNT]
table of interrupts which can set to user functions
uint32_t tx_rcc
GPIO RCC address of transmit pin.
UART specific methods that will be called by the generic methods.
uint32_t timer_sr_ccif
timer channel capture interrupt flag
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
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
BusVoodoo runtime interrupt table.
uint32_t usart_rst
USART RST address.
size_t snprintf(char *str, size_t size, const char *format,...)
print format string on string or user output
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
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
uint8_t databits
data word size in bits
uint32_t usart_rcc
USART RCC address.
size_t printf(const char *format,...)
print format string on user output
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)
uint32_t timer_nvic_irq
timer IRQ
static uint32_t busvoodoo_uart_generic_stopbits
UART stop bits setting.
static void busvoodoo_uart_generic_command_receive(void *argument)
command to receive data
printing utilities to replace the large printf from the standard library (API)
uint32_t timer_sr_ccof
timer channel capture overrun flag
uint32_t cts_rcc
GPIO RCC address of clear to send pin.
bool databits_matching
if the data is still matching the data bits
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)
bool parity_space
if the date is still matching the additional space parity bit
#define LENGTH(x)
get the length of an array
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
static void uart_configuration_reset(struct uart_configuration_t *configuration)
reset all matching values of UART configuration
bool parity_mark
if the date is still matching the additional mark parity bit
volatile bool user_input_available
flag set when user input is available
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.
enum tim_ic_input timer_ic_in_ti
timer input capture channel TIn
const bool usart_enhanced_even_parity_lut[256]
know if there is an even number of 1's in a integer