2018-06-15 09:47:22 +02:00
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
*/
/** BusVoodoo generic UART mode (code)
* @ note this only contains the common UART methods and should be supplied with mode specific methods and information
* @ file busvoodoo_uart_generic . c
* @ author King Kévin < kingkevin @ cuvoodoo . info >
* @ date 2018
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdlib.h> // standard utilities
# include <string.h> // string utilities
/* STM32 (including CM3) libraries */
# include <libopencm3/stm32/gpio.h> // general purpose input output library
# include <libopencm3/stm32/rcc.h> // real-time control clock library
# include <libopencm3/stm32/usart.h> // USART utilities
/* own libraries */
# include "global.h" // board definitions
# include "print.h" // printing utilities
# include "menu.h" // menu definitions
# include "usart_enhanced.h" // utilities for USART enhancements
# include "busvoodoo_global.h" // BusVoodoo definitions
# include "busvoodoo_uart_generic.h" // own definitions
/** the USART mode specific information */
static const struct busvoodoo_uart_generic_specific_t * busvoodoo_uart_generic_specific = NULL ;
/** mode setup stage */
static enum busvoodoo_uart_generic_setting_t {
BUSVOODOO_UART_SETTING_NONE ,
BUSVOODOO_UART_SETTING_BAUDRATE ,
BUSVOODOO_UART_SETTING_DATABITS ,
BUSVOODOO_UART_SETTING_PARITY ,
BUSVOODOO_UART_SETTING_STOPBITS ,
BUSVOODOO_UART_SETTING_HWFLOWCTL ,
BUSVOODOO_UART_SETTING_DRIVE ,
BUSVOODOO_UART_SETTING_DONE ,
} busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_NONE ; /**< current mode setup stage */
/** UART baud rate (in bps) */
static uint32_t busvoodoo_uart_generic_baudrate = 115200 ;
/** UART data bits */
static uint8_t busvoodoo_uart_generic_databits = 8 ;
/** UART parity setting */
static enum usart_enhanced_parity_t busvoodoo_uart_generic_parity = USART_ENHANCED_PARITY_NONE ;
/** UART stop bits setting */
static uint32_t busvoodoo_uart_generic_stopbits = USART_STOPBITS_1 ;
/** UART hardware flow control setting (true = with hardware flow control, false = without hardware flow control */
static bool busvoodoo_uart_generic_hwflowctl = false ;
/** pin drive mode (true = push-pull, false = open-drain) */
static bool busvoodoo_uart_generic_drive = true ;
/** if embedded pull-up resistors are used */
static bool busvoodoo_uart_generic_pullup = false ;
bool busvoodoo_uart_generic_configure ( const struct busvoodoo_uart_generic_specific_t * conf )
{
busvoodoo_uart_generic_specific = NULL ; // reset specific information
if ( NULL = = conf ) {
return false ;
}
if ( ! conf - > usart | | ! conf - > usart_rcc | | ! conf - > usart_rst ) {
return false ;
}
if ( ! conf - > tx_rcc | | ! conf - > rx_rcc ) {
return false ;
}
if ( conf - > hwflowctl & & ( ! conf - > rts_rcc | | ! conf - > cts_rcc ) ) {
return false ;
}
busvoodoo_uart_generic_specific = conf ;
return true ;
}
bool busvoodoo_uart_generic_setup ( char * * prefix , const char * line )
{
if ( NULL = = busvoodoo_uart_generic_specific ) { // there is nothing to configure
return true ;
}
bool complete = false ; // is the setup complete
if ( NULL = = line ) { // first call
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_NONE ; // re-start configuration
}
switch ( busvoodoo_uart_generic_setting ) {
case BUSVOODOO_UART_SETTING_NONE :
snprintf ( busvoodoo_global_string , LENGTH ( busvoodoo_global_string ) , " baud rate in bps (1200-2000000) [%u] " , busvoodoo_uart_generic_baudrate ) ;
* prefix = busvoodoo_global_string ; // ask for baud rate
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_BAUDRATE ;
break ;
case BUSVOODOO_UART_SETTING_BAUDRATE :
if ( NULL = = line | | 0 = = strlen ( line ) ) { // use default setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DATABITS ; // go to next setting
} else { // setting provided
uint32_t baudrate = atoi ( line ) ; // parse setting
if ( baudrate > 0 & & baudrate < = 2000000 ) { // check setting
busvoodoo_uart_generic_baudrate = baudrate ; // remember setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DATABITS ; // go to next setting
}
}
if ( BUSVOODOO_UART_SETTING_DATABITS = = busvoodoo_uart_generic_setting ) { // if next setting
snprintf ( busvoodoo_global_string , LENGTH ( busvoodoo_global_string ) , " data bits (5-8) [%u] " , busvoodoo_uart_generic_databits ) ; // prepare next setting
* prefix = busvoodoo_global_string ; // display next setting
}
break ;
case BUSVOODOO_UART_SETTING_DATABITS :
if ( NULL = = line | | 0 = = strlen ( line ) ) { // use default setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_PARITY ; // go to next setting
} else if ( 1 = = strlen ( line ) ) { // setting provided
uint8_t databits = atoi ( line ) ; // parse setting
if ( databits > = 5 & & databits < = 8 ) { // check setting
busvoodoo_uart_generic_databits = databits ; // remember setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_PARITY ; // go to next setting
}
}
if ( BUSVOODOO_UART_SETTING_PARITY = = busvoodoo_uart_generic_setting ) { // if next setting
printf ( " 1) none \n " ) ;
printf ( " 2) even \n " ) ;
printf ( " 3) odd \n " ) ;
printf ( " 4) mark \n " ) ;
printf ( " 5) space \n " ) ;
snprintf ( busvoodoo_global_string , LENGTH ( busvoodoo_global_string ) , " parity (1,2,3,4,5) [%u] " , busvoodoo_uart_generic_parity + 1 ) ; // prepare next setting
* prefix = busvoodoo_global_string ; // display next setting
}
break ;
case BUSVOODOO_UART_SETTING_PARITY :
if ( NULL = = line | | 0 = = strlen ( line ) ) { // use default setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_STOPBITS ; // go to next setting
} else if ( 1 = = strlen ( line ) ) { // setting provided
uint8_t parity = atoi ( line ) ; // parse setting
if ( parity > 0 & & parity < 6 ) { // check settin
busvoodoo_uart_generic_parity = parity - 1 ;
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_STOPBITS ; // go to next setting
}
}
if ( BUSVOODOO_UART_SETTING_STOPBITS = = busvoodoo_uart_generic_setting ) { // if next setting
printf ( " 1) 0.5 \n " ) ;
printf ( " 2) 1 \n " ) ;
printf ( " 3) 1.5 \n " ) ;
printf ( " 4) 2 \n " ) ;
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
* prefix = busvoodoo_global_string ; // display next setting
}
break ;
case BUSVOODOO_UART_SETTING_STOPBITS :
if ( NULL = = line | | 0 = = strlen ( line ) ) { // use default setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL ; // go to next setting
} else if ( 1 = = strlen ( line ) ) { // setting provided
if ( ' 1 ' = = line [ 0 ] ) { // 0.5 stop bits
busvoodoo_uart_generic_stopbits = USART_STOPBITS_0_5 ; // remember setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL ; // go to next setting
} else if ( ' 2 ' = = line [ 0 ] ) { // 1 stop bits
busvoodoo_uart_generic_stopbits = USART_STOPBITS_1 ; // remember setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL ; // go to next setting
} else if ( ' 3 ' = = line [ 0 ] ) { // 1.5 stop bits
busvoodoo_uart_generic_stopbits = USART_STOPBITS_1_5 ; // remember setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL ; // go to next setting
} else if ( ' 4 ' = = line [ 0 ] ) { // 2 stop bits
busvoodoo_uart_generic_stopbits = USART_STOPBITS_2 ; // remember setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_HWFLOWCTL ; // go to next setting
}
}
if ( BUSVOODOO_UART_SETTING_HWFLOWCTL = = busvoodoo_uart_generic_setting ) { // if next setting
if ( ! busvoodoo_uart_generic_specific - > hwflowctl ) { // hardware flow control is not supported
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DRIVE ; // go to next setting
goto setting_drive ; // actually go to next setting
}
printf ( " 1) no flow control \n " ) ;
printf ( " 2) RTS/CTS hardware flow control \n " ) ;
snprintf ( busvoodoo_global_string , LENGTH ( busvoodoo_global_string ) , " flow control (1,2) [%c] " , busvoodoo_uart_generic_hwflowctl ? ' 2 ' : ' 1 ' ) ; // prepare next setting
* prefix = busvoodoo_global_string ; // display next setting
}
break ;
case BUSVOODOO_UART_SETTING_HWFLOWCTL :
if ( NULL = = line | | 0 = = strlen ( line ) ) { // use default setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DRIVE ; // go to next setting
} else if ( 1 = = strlen ( line ) ) { // setting provided
if ( ' 1 ' = = line [ 0 ] | | ' 2 ' = = line [ 0 ] ) { // setting provided
busvoodoo_uart_generic_hwflowctl = ( ' 2 ' = = line [ 0 ] ) ; // remember setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DRIVE ; // go to next setting
}
}
setting_drive :
if ( BUSVOODOO_UART_SETTING_DRIVE = = busvoodoo_uart_generic_setting ) { // if next setting
if ( ! busvoodoo_uart_generic_specific - > multidrive ) {
busvoodoo_uart_generic_drive = true ; // only push-pull driving mode is supported
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DONE ; // go to next setting
goto setting_done ; // actually go to next setting
}
printf ( " 1) push-pull (3.3V) \n " ) ;
printf ( " 2) open-drain, with embedded pull-up resistors (2kO) \n " ) ;
printf ( " 3) open-drain, with external pull-up resistors \n " ) ;
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
* prefix = busvoodoo_global_string ; // display next setting
}
break ;
case BUSVOODOO_UART_SETTING_DRIVE :
if ( NULL = = line | | 0 = = strlen ( line ) ) { // use default setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DONE ; // go to next setting
} else if ( 1 = = strlen ( line ) ) { // setting provided
uint8_t drive = atoi ( line ) ; // parse setting
if ( 1 = = drive | | 2 = = drive | | 3 = = drive ) { // check setting
busvoodoo_uart_generic_drive = ( 1 = = drive ) ; // remember setting
busvoodoo_uart_generic_pullup = ( 2 = = drive ) ; // remember setting
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_DONE ; // go to next setting
}
}
setting_done :
if ( BUSVOODOO_UART_SETTING_DONE = = busvoodoo_uart_generic_setting ) { // we have all settings, configure UART
rcc_periph_clock_enable ( RCC_AFIO ) ; // enable clock for USART alternate function
rcc_periph_clock_enable ( busvoodoo_uart_generic_specific - > usart_rcc ) ; // enable clock for USART peripheral
rcc_periph_reset_pulse ( busvoodoo_uart_generic_specific - > usart_rst ) ; // reset USART peripheral
usart_set_baudrate ( busvoodoo_uart_generic_specific - > usart , busvoodoo_uart_generic_baudrate ) ; // set baud rate
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
usart_set_stopbits ( busvoodoo_uart_generic_specific - > usart , busvoodoo_uart_generic_stopbits ) ; // set stop bits
if ( busvoodoo_uart_generic_specific - > hwflowctl & & busvoodoo_uart_generic_hwflowctl ) {
usart_set_flow_control ( busvoodoo_uart_generic_specific - > usart , USART_FLOWCONTROL_RTS_CTS ) ; // set RTS/CTS flow control
} else {
usart_set_flow_control ( busvoodoo_uart_generic_specific - > usart , USART_FLOWCONTROL_NONE ) ; // set no flow control
}
usart_set_mode ( busvoodoo_uart_generic_specific - > usart , USART_MODE_TX_RX ) ; // full-duplex communication
rcc_periph_clock_enable ( busvoodoo_uart_generic_specific - > tx_rcc ) ; // enable clock for USART GPIO peripheral
rcc_periph_clock_enable ( busvoodoo_uart_generic_specific - > rx_rcc ) ; // enable clock for USART GPIO peripheral
if ( busvoodoo_uart_generic_specific - > hwflowctl & & busvoodoo_uart_generic_hwflowctl ) {
rcc_periph_clock_enable ( busvoodoo_uart_generic_specific - > rts_rcc ) ; // enable clock for USART GPIO peripheral
rcc_periph_clock_enable ( busvoodoo_uart_generic_specific - > cts_rcc ) ; // enable clock for USART GPIO peripheral
}
if ( busvoodoo_uart_generic_drive ) { // use push-pull drive mode
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
gpio_set ( busvoodoo_uart_generic_specific - > rx_port , busvoodoo_uart_generic_specific - > rx_pin ) ; // pull up to avoid noise when not connected
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
if ( busvoodoo_uart_generic_specific - > hwflowctl & & busvoodoo_uart_generic_hwflowctl ) { // use open drain drive mode
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
gpio_set ( busvoodoo_uart_generic_specific - > cts_port , busvoodoo_uart_generic_specific - > cts_pin ) ; // pull up to block transmission unless requested
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
}
} else {
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
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
if ( busvoodoo_uart_generic_specific - > hwflowctl & & busvoodoo_uart_generic_hwflowctl ) {
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
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
}
}
if ( ! busvoodoo_uart_generic_drive & & busvoodoo_uart_generic_pullup ) { // enable embedded pull-ups if used
busvoodoo_embedded_pullup ( true ) ; // set embedded pull-ups
printf ( " use LV to set pull-up voltage \n " ) ;
}
usart_enable ( busvoodoo_uart_generic_specific - > usart ) ; // enable USART
busvoodoo_led_blue_off ( ) ; // disable blue LED because there is no activity
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_NONE ; // restart settings next time
complete = true ; // configuration is complete
}
break ;
default : // unknown case
busvoodoo_uart_generic_setting = BUSVOODOO_UART_SETTING_NONE ; // restart settings next time
break ;
}
return complete ;
}
void busvoodoo_uart_generic_exit ( void )
{
if ( NULL = = busvoodoo_uart_generic_specific ) {
return ;
}
usart_disable ( busvoodoo_uart_generic_specific - > usart ) ; // disable USART
rcc_periph_clock_disable ( busvoodoo_uart_generic_specific - > usart_rcc ) ; // disable domain clock
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
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
if ( busvoodoo_uart_generic_specific - > hwflowctl ) {
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
2018-06-17 12:09:50 +02:00
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
2018-06-15 09:47:22 +02:00
}
if ( busvoodoo_uart_generic_specific - > multidrive ) {
busvoodoo_embedded_pullup ( false ) ; // disable embedded pull-ups
}
busvoodoo_uart_generic_specific = NULL ; // remove specific information
}
/** write to UART
* @ param [ in ] value value to write
*/
static void busvoodoo_uart_generic_write ( uint8_t value )
{
if ( NULL = = busvoodoo_uart_generic_specific ) {
return ;
}
if ( busvoodoo_uart_generic_specific - > tx_pre ) {
( * busvoodoo_uart_generic_specific - > tx_pre ) ( ) ;
}
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)
if ( ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) ) & USART_SR_TXE ) { // we can send data
// send data
busvoodoo_led_blue_pulse ( BUSVOODOO_LED_PULSE ) ; // pulse blue LED to show transmission
usart_enhanced_send ( busvoodoo_uart_generic_specific - > usart , value ) ; // transmit data
// display data send
printf ( " write: '%c'/0x%02x \n " , value , value ) ;
}
2018-06-17 12:09:50 +02:00
while ( ( 0 = = ( ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) ) & USART_SR_TC ) & & ! user_input_available ) ) ; // wait for transfer to be complete
2018-06-16 11:05:48 +02:00
if ( user_input_available ) { // user interrupted flow
user_input_get ( ) ; // discard user input
}
2018-06-15 09:47:22 +02:00
if ( busvoodoo_uart_generic_specific - > tx_post ) {
( * busvoodoo_uart_generic_specific - > tx_post ) ( ) ;
}
}
/** read from UART
*/
static void busvoodoo_uart_generic_read ( void )
{
if ( NULL = = busvoodoo_uart_generic_specific ) {
return ;
}
if ( busvoodoo_uart_generic_specific - > rx_pre ) {
( * busvoodoo_uart_generic_specific - > rx_pre ) ( ) ;
}
printf ( " read: " ) ;
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)
if ( ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) & USART_SR_RXNE ) ) { // verify if data has been received
busvoodoo_led_blue_pulse ( BUSVOODOO_LED_PULSE ) ; // enable blue LED to show reception
// get the errors
bool error_noise = ( 0 ! = ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) & USART_SR_NE ) ) ; // read noise error flag
bool error_framing = ( 0 ! = ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) & USART_SR_FE ) ) ; // read frame error flag
uint8_t input = usart_enhanced_recv ( busvoodoo_uart_generic_specific - > usart ) ; // read received character (also clears the error flags)
// display data
printf ( " '%c'/0x%02x " , input , input ) ;
// display errors
printf ( " ( " ) ;
if ( error_noise ) {
printf ( " noise " ) ;
} else if ( error_framing ) {
printf ( " framing " ) ;
} else if ( usart_enhanced_parity_error ( busvoodoo_uart_generic_specific - > usart ) ) {
printf ( " parity " ) ;
} else {
printf ( " no " ) ;
}
printf ( " error) " ) ;
}
printf ( " \n " ) ;
2018-06-16 11:05:48 +02:00
if ( user_input_available ) { // user interrupted flow
user_input_get ( ) ; // discard user input
}
2018-06-15 09:47:22 +02:00
if ( busvoodoo_uart_generic_specific - > rx_post ) {
( * busvoodoo_uart_generic_specific - > rx_post ) ( ) ;
}
}
/** perform UART action
* @ param [ in ] action action to perform
* @ param [ in ] repetition how many times to perform the action
* @ param [ in ] perform the action ( true ) or just check it ( false )
* @ return true if the action has been performed , false if it is malformed
*/
static bool busvoodoo_uart_generic_action ( const char * action , uint32_t repetition , bool perform )
{
uint32_t length = strlen ( action ) ; // remember length since it will be used a number of times
if ( NULL = = action | | 0 = = length ) { // there is nothing to do
return true ;
}
if ( 1 = = length & & ' r ' = = action [ 0 ] ) { // read data
if ( ! perform ) {
return true ;
}
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
busvoodoo_uart_generic_read ( ) ; // read from UART
}
} else if ( 1 = = length & & ' u ' = = action [ 0 ] ) { // sleep us
if ( ! perform ) {
return true ;
}
printf ( " wait for %u us \n " , repetition ) ;
sleep_us ( repetition ) ; // sleep
} else if ( 1 = = length & & ' m ' = = action [ 0 ] ) { // sleep ms
if ( ! perform ) {
return true ;
}
printf ( " wait for %u ms \n " , repetition ) ;
sleep_ms ( repetition ) ; // sleep
} else if ( ' 0 ' = = action [ 0 ] ) { // send digit
if ( 1 = = length ) { // just send 0
if ( ! perform ) {
return true ;
}
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
busvoodoo_uart_generic_write ( 0 ) ; // write to UART
}
} else if ( ' x ' = = action [ 1 ] | | ' b ' = = action [ 1 ] ) { // send hex/binary
return busvoodoo_uart_generic_action ( action + 1 , repetition , perform ) ; // just retry without leading 0
} else if ( action [ 1 ] > = ' 0 ' & & action [ 1 ] < = ' 9 ' ) { // send decimal
return busvoodoo_uart_generic_action ( action + 1 , repetition , perform ) ; // just retry without leading 0
} else { // malformed action
return false ;
}
} else if ( ' x ' = = action [ 0 ] & & length > 1 ) { // send hexadecimal value
for ( uint32_t i = 1 ; i < length ; i + + ) { // check string
if ( ! ( ( action [ i ] > = ' 0 ' & & action [ i ] < = ' 9 ' ) | | ( action [ i ] > = ' a ' & & action [ i ] < = ' f ' ) | | ( action [ i ] > = ' A ' & & action [ i ] < = ' F ' ) ) ) { // check for hexadecimal character
return false ; // not an hexadecimal string
}
}
if ( ! perform ) {
return true ;
}
uint32_t value = strtol ( & action [ 1 ] , NULL , 16 ) ; // get hex value
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
busvoodoo_uart_generic_write ( value ) ; // write to SPI
}
} else if ( ' b ' = = action [ 0 ] & & length > 1 ) { // send binary value
for ( uint32_t i = 1 ; i < length ; i + + ) { // check string
if ( action [ i ] < ' 0 ' | | action [ i ] > ' 1 ' ) { // check for binary character
return false ; // not a binary string
}
}
if ( ! perform ) {
return true ;
}
uint32_t value = strtol ( & action [ 1 ] , NULL , 2 ) ; // get binary value
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
busvoodoo_uart_generic_write ( value ) ; // write to SPI
}
} else if ( action [ 0 ] > = ' 1 ' & & action [ 0 ] < = ' 9 ' ) { // send decimal value
for ( uint32_t i = 1 ; i < length ; i + + ) { // check string
if ( action [ i ] < ' 0 ' | | action [ i ] > ' 9 ' ) { // check for decimal character
return false ; // not a decimal string
}
}
if ( ! perform ) {
return true ;
}
uint32_t value = strtol ( & action [ 0 ] , NULL , 10 ) ; // get decimal value
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
busvoodoo_uart_generic_write ( value ) ; // write to SPI
}
} else if ( length > = 2 & & ( ' " ' = = action [ 0 ] | | ' \' ' = = action [ 0 ] ) & & ( action [ length - 1 ] = = action [ 0 ] ) ) { // send ASCII character
if ( ! perform ) {
return true ;
}
for ( uint32_t r = 0 ; r < repetition ; r + + ) {
for ( uint32_t i = 1 ; i < length - 1 ; i + + ) { // go through string
busvoodoo_uart_generic_write ( action [ i ] ) ; // write to SPI
}
}
} else { // malformed action
return false ;
}
return true ; // all went well
}
// command handlers
/** command to perform actions
* @ param [ in ] argument actions to perform
*/
static void busvoodoo_uart_generic_command_actions ( void * argument )
{
if ( NULL = = argument | | 0 = = strlen ( argument ) ) {
printf ( " available actions (separated by space or ,): \n " ) ;
printf ( " 0 \t write decimal value \n " ) ;
printf ( " 0x0 \t write hexadecimal value \n " ) ;
printf ( " 0b0 \t write binary value \n " ) ;
printf ( " \" a \" /'a' \t write ASCII characters \n " ) ;
printf ( " r \t read value \n " ) ;
printf ( " u/m \t wait 1 us/ms \n " ) ;
printf ( " :n \t repeat action n times \n " ) ;
return ;
}
// copy argument since it will be modified
char * copy = calloc ( strlen ( argument ) + 1 , sizeof ( char ) ) ;
if ( ! copy ) {
while ( true ) ;
}
strncpy ( copy , argument , strlen ( argument ) + 1 ) ;
// verify and perform actions
if ( ! busvoodoo_global_actions ( copy , false , & busvoodoo_uart_generic_action ) ) { // verify actions
printf ( " malformed action(s) \n " ) ;
} else { // action are ok
printf ( " press any key to exit \n " ) ;
busvoodoo_global_actions ( argument , true , & busvoodoo_uart_generic_action ) ; // perform action
if ( user_input_available ) { // user interrupted flow
user_input_get ( ) ; // discard user input
}
}
free ( copy ) ; // release memory
}
/** command to transmit a string
* @ param [ in ] argument string to transmit ( CR + LF when none provided )
*/
static void busvoodoo_uart_generic_command_transmit ( void * argument )
{
if ( NULL = = busvoodoo_uart_generic_specific ) {
return ;
}
if ( busvoodoo_uart_generic_specific - > tx_pre ) {
( * busvoodoo_uart_generic_specific - > tx_pre ) ( ) ;
}
if ( NULL = = argument | | 0 = = strlen ( argument ) ) { // nothing to transmit
argument = " \r \n " ; // transmit CR+LF
}
printf ( " press any key to exit \n " ) ;
for ( uint16_t i = 0 ; ( ( char * ) ( argument ) ) [ i ] & & ! user_input_available ; i + + ) {
while ( ( 0 = = ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) & USART_SR_TXE ) & & ! user_input_available ) ) ; // wait for transmit buffer to be empty
if ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) & USART_SR_TXE ) { // we can send a character
printf ( " %c " , ( ( char * ) ( argument ) ) [ i ] ) ; // echo character to transmit
busvoodoo_led_blue_pulse ( BUSVOODOO_LED_PULSE ) ; // pulse blue LED to show transmission
usart_enhanced_send ( busvoodoo_uart_generic_specific - > usart , ( ( char * ) ( argument ) ) [ i ] ) ; // transmit character
}
}
2018-06-17 12:09:50 +02:00
while ( ( 0 = = ( ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) ) & USART_SR_TC ) & & ! user_input_available ) ) ; // wait for transfer to be complete
2018-06-15 09:47:22 +02:00
if ( user_input_available ) { // user interrupted flow
user_input_get ( ) ; // discard user input
}
if ( strcmp ( argument , " \r \n " ) ) {
printf ( " \n " ) ;
}
if ( busvoodoo_uart_generic_specific - > tx_post ) {
( * busvoodoo_uart_generic_specific - > tx_post ) ( ) ;
}
}
/** command to receive data
* @ param [ in ] argument in which format to display
*/
static void busvoodoo_uart_generic_command_receive ( void * argument )
{
bool display_hex = false ; // display in hex
bool display_bin = false ; // display in bin
if ( NULL ! = argument & & strlen ( argument ) > 0 ) {
if ( 0 = = strcmp ( argument , " h " ) | | 0 = = strcmp ( argument , " hex " ) ) { // user wants hexadecimal display
display_hex = true ; // remember to display in hexadecimal
} else if ( 0 = = strcmp ( argument , " b " ) | | 0 = = strcmp ( argument , " bin " ) ) { // user wants binary display
display_bin = true ; // remember to display in binary
} else {
printf ( " malformed argument \n " ) ;
return ;
}
}
if ( NULL = = busvoodoo_uart_generic_specific ) {
return ;
}
if ( busvoodoo_uart_generic_specific - > rx_pre ) {
( * busvoodoo_uart_generic_specific - > rx_pre ) ( ) ;
}
printf ( " press any key to exit \n " ) ;
while ( ! user_input_available ) { // check for user input to exit
if ( ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) & USART_SR_RXNE ) ) { // verify if data has been received
uint8_t input = usart_enhanced_recv ( busvoodoo_uart_generic_specific - > usart ) ; // receive character
busvoodoo_led_blue_pulse ( BUSVOODOO_LED_PULSE ) ; // enable blue LED to show reception
if ( display_hex ) { // display data in hex
printf ( " %02x " , input ) ;
} else if ( display_bin ) { // display data in binary
printf ( " %08b " , input ) ;
} else { // display in ASCII
printf ( " %c " , input ) ; // print received character
}
}
}
user_input_get ( ) ; // discard user input
printf ( " \n " ) ; // get to next line
if ( busvoodoo_uart_generic_specific - > rx_post ) {
( * busvoodoo_uart_generic_specific - > rx_post ) ( ) ;
}
}
/** command to transmit and receive data
* @ param [ in ] argument no argument required
*/
static void busvoodoo_uart_generic_command_transceive ( void * argument )
{
( void ) argument ; // we won't use the argument
if ( NULL = = busvoodoo_uart_generic_specific ) {
return ;
}
if ( busvoodoo_uart_generic_specific - > rx_pre ) {
( * busvoodoo_uart_generic_specific - > rx_pre ) ( ) ;
}
printf ( " press 5 times escape to exit \n " ) ;
char last_c = 0 ; // last user character received
uint8_t esc_count = 0 ; // number of times escape has press received
while ( true ) { // check for escape sequence
if ( user_input_available ) { // check if user wants to transmit something
char c = user_input_get ( ) ; // get user input
if ( 0x1b = = c ) { // user pressed escape
if ( 0x1b ! = last_c ) { // this is the first escape press
esc_count = 0 ;
}
esc_count + + ; // increment escape count
}
last_c = c ; // remember key press
if ( esc_count < 5 ) { // check for escape sequence
if ( busvoodoo_uart_generic_specific - > rx_post ) {
( * busvoodoo_uart_generic_specific - > rx_post ) ( ) ;
}
if ( busvoodoo_uart_generic_specific - > tx_pre ) {
( * busvoodoo_uart_generic_specific - > tx_pre ) ( ) ;
}
while ( ( 0 = = ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) & USART_SR_TXE ) & & ! user_input_available ) ) ; // wait for transmit buffer to be empty
if ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) & USART_SR_TXE ) { // we can send a character
usart_enhanced_send ( busvoodoo_uart_generic_specific - > usart , c ) ; // send user character
busvoodoo_led_blue_pulse ( BUSVOODOO_LED_PULSE ) ; // enable blue LED to show transmission
}
2018-06-17 12:09:50 +02:00
while ( ( 0 = = ( ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) ) & USART_SR_TC ) & & ! user_input_available ) ) ; // wait for transfer to be complete
2018-06-15 09:47:22 +02:00
if ( busvoodoo_uart_generic_specific - > tx_post ) {
( * busvoodoo_uart_generic_specific - > tx_post ) ( ) ;
}
if ( busvoodoo_uart_generic_specific - > rx_pre ) {
( * busvoodoo_uart_generic_specific - > rx_pre ) ( ) ;
}
} else { // user wants to exit
break ; // exit infinite loop
}
}
if ( ( USART_SR ( busvoodoo_uart_generic_specific - > usart ) & USART_SR_RXNE ) ) { // verify if data has been received
char input = usart_enhanced_recv ( busvoodoo_uart_generic_specific - > usart ) ; // receive character
busvoodoo_led_blue_pulse ( BUSVOODOO_LED_PULSE ) ; // enable blue LED to show reception
printf ( " %c " , input ) ; // print received character
}
}
printf ( " \n " ) ; // get to next line
if ( busvoodoo_uart_generic_specific - > rx_post ) {
( * busvoodoo_uart_generic_specific - > rx_post ) ( ) ;
}
}
/** command to verify incoming transmission for error
* @ param [ in ] argument argument not required
*/
static void busvoodoo_uart_generic_command_error ( void * argument )
{
( void ) argument ; // argument not used
printf ( " press any key to exit \n " ) ;
while ( ! user_input_available ) { // wait until user interrupt
busvoodoo_uart_generic_read ( ) ; // read incoming data (this also checks for errors
}
user_input_get ( ) ; // discard user input
}
const struct menu_command_t busvoodoo_uart_generic_commands [ busvoodoo_uart_generic_commands_nb ] = {
{
. shortcut = ' a ' ,
. name = " action " ,
. command_description = " perform protocol actions " ,
. argument = MENU_ARGUMENT_STRING ,
. argument_description = " [actions] " ,
. command_handler = & busvoodoo_uart_generic_command_actions ,
} ,
{
. shortcut = ' r ' ,
. name = " receive " ,
. command_description = " show incoming data [in hexadecimal or binary] " ,
. argument = MENU_ARGUMENT_STRING ,
. argument_description = " [hex|bin] " ,
. command_handler = & busvoodoo_uart_generic_command_receive ,
} ,
{
. shortcut = ' t ' ,
. name = " transmit " ,
. command_description = " transmit ASCII text (empty for CR+LF) " ,
. argument = MENU_ARGUMENT_STRING ,
. argument_description = " [text] " ,
. command_handler = & busvoodoo_uart_generic_command_transmit ,
} ,
{
. shortcut = ' x ' ,
. name = " transceive " ,
. command_description = " transmit and receive data " ,
. argument = MENU_ARGUMENT_NONE ,
. argument_description = NULL ,
. command_handler = & busvoodoo_uart_generic_command_transceive ,
} ,
{
. shortcut = ' e ' ,
. name = " error " ,
. command_description = " verify incoming transmission for errors " ,
. argument = MENU_ARGUMENT_NONE ,
. argument_description = NULL ,
. command_handler = & busvoodoo_uart_generic_command_error ,
} ,
} ;