2016-01-17 14:54:54 +01: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/>.
*
*/
2017-12-12 13:56:28 +01:00
/** STM32F1 BusVoodoo application
2017-08-02 13:46:20 +02:00
* @ file application . c
2016-08-14 21:02:38 +02:00
* @ author King Kévin < kingkevin @ cuvoodoo . info >
2018-03-11 17:52:20 +01:00
* @ date 2016 - 2018
2016-08-14 21:02:38 +02:00
*/
2016-01-17 14:54:54 +01:00
/* standard libraries */
# include <stdint.h> // standard integer types
2016-08-14 21:02:38 +02:00
# include <string.h> // string utilities
2016-01-17 14:54:54 +01:00
/* STM32 (including CM3) libraries */
2016-01-18 16:23:35 +01:00
# include <libopencmsis/core_cm3.h> // Cortex M3 utilities
2016-10-23 17:42:27 +02:00
# include <libopencm3/stm32/gpio.h> // general purpose input output library
# include <libopencm3/stm32/rcc.h> // real-time control clock library
# include <libopencm3/stm32/dbgmcu.h> // debug utilities
2016-01-17 14:54:54 +01:00
/* own libraries */
2016-01-28 21:21:50 +01:00
# include "global.h" // board definitions
2017-04-03 13:32:45 +02:00
# include "print.h" // printing utilities
2017-12-16 13:37:35 +01:00
# include "uart.h" // USART utilities
2016-01-18 16:23:35 +01:00
# include "usb_cdcacm.h" // USB CDC ACM utilities
2018-01-14 13:49:16 +01:00
# include "terminal.h" // handle the terminal interface
2018-01-21 23:35:42 +01:00
# include "menu.h" // menu utilities
2018-01-14 22:15:00 +01:00
# include "busvoodoo_global.h" // BusVoodoo definitions
2018-02-06 12:31:46 +01:00
# include "busvoodoo_oled.h" // OLED utilities
2018-01-23 23:41:41 +01:00
# include "busvoodoo_hiz.h" // BusVoodoo HiZ mode
2018-01-24 16:37:00 +01:00
# include "busvoodoo_uart.h" // BusVoodoo UART mode
2018-03-11 17:52:20 +01:00
# include "busvoodoo_i2c.h" // BusVoodoo I2C mode
2018-03-15 19:00:04 +01:00
# include "busvoodoo_spi.h" // BusVoodoo SPI mode
2018-05-09 21:27:52 +02:00
# include "busvoodoo_onewire.h" // BusVoodoo 1-wire mode
2018-04-04 17:16:20 +02:00
# include "busvoodoo_rs232.h" // BusVoodoo RS-232 mode
2018-05-01 13:45:09 +02:00
# include "busvoodoo_rs485.h" // BusVoodoo RS-485/422 mode
2018-01-23 23:41:41 +01:00
/** all supported BusVoodoo modes */
2018-04-04 17:14:36 +02:00
static const struct busvoodoo_mode_t * busvoodoo_modes [ ] = {
2018-01-23 23:41:41 +01:00
& busvoodoo_hiz_mode ,
2018-01-24 16:37:00 +01:00
& busvoodoo_uart_mode ,
2018-03-11 17:52:20 +01:00
& busvoodoo_i2c_mode ,
2018-03-15 19:00:04 +01:00
& busvoodoo_spi_mode ,
2018-05-09 21:27:52 +02:00
& busvoodoo_onewire_mode ,
2018-04-04 17:16:20 +02:00
& busvoodoo_rs232_mode ,
2018-05-01 13:45:09 +02:00
& busvoodoo_rs485_mode ,
2018-01-23 23:41:41 +01:00
} ;
2017-12-12 13:56:28 +01:00
2018-01-23 15:36:05 +01:00
/** current BusVoodoo mode */
2018-04-04 17:14:36 +02:00
static struct busvoodoo_mode_t const * busvoodoo_mode = NULL ;
2018-01-23 23:41:41 +01:00
/** is mode setup complete */
static bool busvoodoo_mode_complete = false ;
2018-01-23 15:36:05 +01:00
2017-04-03 13:32:45 +02:00
size_t putc ( char c )
2016-01-17 14:54:54 +01:00
{
2017-04-03 13:32:45 +02:00
size_t length = 0 ; // number of characters printed
2018-01-14 13:49:16 +01:00
static char last_c = 0 ; // to remember on which character we last sent
if ( ' \n ' = = c ) { // send carriage return (CR) + line feed (LF) newline for each LF
if ( ' \r ' ! = last_c ) { // CR has not already been sent
2017-12-16 13:37:35 +01:00
uart_putchar_nonblocking ( ' \r ' ) ; // send CR over USART
2017-04-19 16:24:07 +02:00
usb_cdcacm_putchar ( ' \r ' ) ; // send CR over USB
2018-01-14 13:49:16 +01:00
length + + ; // remember we printed 1 character
2016-01-17 14:54:54 +01:00
}
}
2018-01-14 13:49:16 +01:00
uart_putchar_nonblocking ( c ) ; // send byte over USART
usb_cdcacm_putchar ( c ) ; // send byte over USB
length + + ; // remember we printed 1 character
last_c = c ; // remember last character
2017-04-03 13:32:45 +02:00
return length ; // return number of characters printed
2016-01-17 14:54:54 +01:00
}
2018-01-23 23:41:41 +01:00
/** switch BusVoddoo mode
* @ param [ in ] mode mode to switch to
*/
2018-04-04 17:14:36 +02:00
static void switch_mode ( const struct busvoodoo_mode_t * mode )
2018-01-23 23:41:41 +01:00
{
if ( busvoodoo_mode ) {
( * busvoodoo_mode - > exit ) ( ) ; // exit current mode
}
2018-05-03 12:56:09 +02:00
busvoodoo_leds_off ( ) ; // switch off LEDs
2018-03-11 17:52:20 +01:00
busvoodoo_safe_state ( ) ; // return to safe state
2018-02-06 17:28:03 +01:00
// reset pinout
for ( uint8_t i = 0 ; i < LENGTH ( busvoodoo_global_pinout_rscan ) ; i + + ) {
busvoodoo_global_pinout_rscan [ i ] = NULL ;
}
for ( uint8_t i = 0 ; i < LENGTH ( busvoodoo_global_pinout_io ) ; i + + ) {
busvoodoo_global_pinout_io [ i ] = NULL ;
}
2018-02-06 12:31:46 +01:00
busvoodoo_oled_clear ( ) ; // clear OLED display buffer
busvoodoo_oled_update ( ) ; // update OLED display
2018-01-23 23:41:41 +01:00
if ( NULL = = mode ) { // no mode provided
busvoodoo_mode = & busvoodoo_hiz_mode ; // use default mode
} else { // mode provided
busvoodoo_mode = mode ; // set provided mode a current mode
}
busvoodoo_mode_complete = ( * busvoodoo_mode - > setup ) ( & terminal_prefix , NULL ) ; // start setup
terminal_send ( 0 ) ; // update the terminal prompt
}
2018-01-21 23:35:42 +01:00
/** command to show help
* @ param [ in ] argument no argument required
*/
static void command_help ( void * argument ) ;
2018-01-23 23:41:41 +01:00
/** command to select mode
* @ param [ in ] argument mode to select
*/
static void command_mode ( void * argument ) ;
2018-01-23 15:36:05 +01:00
/** command to quit current BusVoodoo mode
* @ param [ in ] argument no argument required
*/
static void command_quit ( void * argument ) ;
2018-01-21 23:35:42 +01:00
/** command to reset board
* @ param [ in ] argument no argument required
*/
static void command_reset ( void * argument ) ;
/** command to reboot into bootloader
* @ param [ in ] argument no argument required
*/
/** list of all supported commands */
static const struct menu_command_t menu_commands [ ] = {
{
2018-04-04 17:14:36 +02:00
. shortcut = ' m ' ,
. name = " mode " ,
. command_description = " select mode " ,
. argument = MENU_ARGUMENT_STRING ,
. argument_description = " [mode] " ,
. command_handler = & command_mode ,
2018-01-21 23:35:42 +01:00
} ,
2018-01-23 15:36:05 +01:00
{
2018-04-04 17:14:36 +02:00
. shortcut = ' q ' ,
. name = " quit " ,
. command_description = " quit current mode " ,
. argument = MENU_ARGUMENT_NONE ,
. argument_description = NULL ,
. command_handler = & command_quit ,
2018-01-23 15:36:05 +01:00
} ,
2018-01-21 23:35:42 +01:00
{
2018-04-04 17:14:36 +02:00
. shortcut = ' R ' ,
. name = " reset " ,
. command_description = " reset board " ,
. argument = MENU_ARGUMENT_NONE ,
. argument_description = NULL ,
. command_handler = & command_reset ,
2018-01-21 23:35:42 +01:00
} ,
2018-01-23 23:41:41 +01:00
{
2018-04-04 17:14:36 +02:00
. shortcut = ' h ' ,
. name = " help " ,
. command_description = " display help " ,
. argument = MENU_ARGUMENT_NONE ,
. argument_description = NULL ,
. command_handler = & command_help ,
2018-01-23 23:41:41 +01:00
} ,
2018-01-21 23:35:42 +01:00
} ;
static void command_help ( void * argument )
{
( void ) argument ; // we won't use the argument
printf ( " available commands: \n " ) ;
menu_print_commands ( menu_commands , LENGTH ( menu_commands ) ) ; // print global commands
2018-03-15 19:20:27 +01:00
menu_print_commands ( busvoodoo_global_commands , busvoodoo_global_commands_nb ) ; // print BusVoodoo global commands
2018-04-04 17:14:36 +02:00
if ( busvoodoo_full ) {
menu_print_commands ( busvoodoo_global_full_commands , busvoodoo_global_full_commands_nb ) ; // print BusVoodoo global commands
}
if ( ! busvoodoo_mode - > full_only | | busvoodoo_full ) {
menu_print_commands ( busvoodoo_mode - > commands , busvoodoo_mode - > commands_nb ) ; // print BusVoodoo mode commands
}
2018-01-23 15:36:05 +01:00
}
2018-01-23 23:41:41 +01:00
static void command_mode ( void * argument )
{
if ( NULL = = argument | | 0 = = strlen ( argument ) ) { // no mode provided: list all modes
printf ( " available modes: \n " ) ;
for ( uint8_t i = 0 ; i < LENGTH ( busvoodoo_modes ) ; i + + ) { // go through all modes
2018-04-04 17:14:36 +02:00
if ( ! busvoodoo_modes [ i ] - > full_only | | busvoodoo_full ) {
printf ( " %s \t %s \n " , busvoodoo_modes [ i ] - > name , busvoodoo_modes [ i ] - > description ) ; // display mode information
}
2018-01-23 23:41:41 +01:00
}
} else { // mode provided
bool mode_found = false ; // to know if we found the matching mode
for ( uint8_t i = 0 ; i < LENGTH ( busvoodoo_modes ) ; i + + ) { // go through all modes
if ( 0 = = strcmp ( argument , busvoodoo_modes [ i ] - > name ) ) { // check for corresponding mode
2018-04-04 17:14:36 +02:00
if ( ! busvoodoo_mode - > full_only | | busvoodoo_full ) {
switch_mode ( busvoodoo_modes [ i ] ) ; // switch to mode
} else {
printf ( " mode only available for BusVoodoo full \n " ) ;
}
2018-01-23 23:41:41 +01:00
mode_found = true ; // remember we found the mode
break ; // stop searching for mode
}
}
if ( ! mode_found ) {
printf ( " unknown mode: %s \n " , argument ) ;
}
}
}
2018-01-23 15:36:05 +01:00
static void command_quit ( void * argument )
{
( void ) argument ; // we won't use the argument
2018-01-24 16:37:00 +01:00
switch_mode ( NULL ) ; // switch do default mode
2018-01-21 23:35:42 +01:00
}
static void command_reset ( void * argument )
{
( void ) argument ; // we won't use the argument
scb_reset_system ( ) ; // reset device
while ( true ) ; // wait for the reset to happen
}
2016-08-14 21:02:38 +02:00
/** process user command
* @ param [ in ] str user command string ( \ 0 ended )
*/
static void process_command ( char * str )
2016-01-17 14:54:54 +01:00
{
2018-01-21 23:35:42 +01:00
// ensure actions are available
if ( NULL = = menu_commands | | 0 = = LENGTH ( menu_commands ) ) {
return ;
}
// handle user input
2018-01-23 23:41:41 +01:00
if ( NULL = = busvoodoo_mode ) { // no mode set
switch_mode ( NULL ) ; // set default mode
}
if ( ! busvoodoo_mode_complete ) { // mode setup is not complete
busvoodoo_mode_complete = ( * busvoodoo_mode - > setup ) ( & terminal_prefix , str ) ; // continue setup
terminal_send ( 0 ) ; // update the terminal prompt
2018-04-04 17:14:36 +02:00
} else { // mode setup is complete
2018-01-24 16:37:00 +01:00
// don't handle empty lines
if ( ! str | | 0 = = strlen ( str ) ) {
return ;
}
2018-04-04 17:14:36 +02:00
bool command_handled = false ;
if ( ! busvoodoo_mode - > full_only | | busvoodoo_full ) {
command_handled = menu_handle_command ( str , busvoodoo_mode - > commands , busvoodoo_mode - > commands_nb ) ; // try if the mode can handle this command
}
if ( ! command_handled & & busvoodoo_full ) {
command_handled = menu_handle_command ( str , busvoodoo_global_full_commands , busvoodoo_global_full_commands_nb ) ; // try if full BusVoodoo can handle this command
}
if ( ! command_handled ) {
command_handled = menu_handle_command ( str , busvoodoo_global_commands , busvoodoo_global_commands_nb ) ; // try if the base BusVoodoo can handle this command
}
if ( ! command_handled ) {
command_handled = menu_handle_command ( str , menu_commands , LENGTH ( menu_commands ) ) ; // try if this is not a global command
}
if ( ! command_handled ) {
printf ( " command not recognized. enter help to list commands \n " ) ;
2018-01-21 23:35:42 +01:00
}
2016-08-14 21:02:38 +02:00
}
2016-01-17 14:54:54 +01:00
}
2016-08-14 21:02:38 +02:00
/** program entry point
* this is the firmware function started by the micro - controller
*/
2016-10-23 17:42:27 +02:00
void main ( void ) ;
void main ( void )
2016-01-17 15:03:10 +01:00
{
2016-01-29 00:24:49 +01:00
rcc_clock_setup_in_hse_8mhz_out_72mhz ( ) ; // use 8 MHz high speed external clock to generate 72 MHz internal clock
2016-08-14 21:02:38 +02:00
2018-04-07 11:15:05 +02:00
# if defined(DEBUG) && DEBUG
2017-01-30 09:44:51 +01:00
// enable functionalities for easier debug
2016-10-23 17:42:27 +02:00
DBGMCU_CR | = DBGMCU_CR_STANDBY ; // allow debug also in standby mode (keep digital part and clock powered)
DBGMCU_CR | = DBGMCU_CR_STOP ; // allow debug also in stop mode (keep clock powered)
DBGMCU_CR | = DBGMCU_CR_SLEEP ; // allow debug also in sleep mode (keep clock powered)
2018-04-07 11:15:05 +02:00
# endif
2016-10-23 17:42:27 +02:00
2018-04-07 11:15:05 +02:00
// setup board
2017-04-03 13:32:45 +02:00
board_setup ( ) ; // setup board
2017-12-16 13:37:35 +01:00
uart_setup ( ) ; // setup USART (for printing)
2017-04-19 16:26:40 +02:00
usb_cdcacm_setup ( ) ; // setup USB CDC ACM (for printing)
2018-01-14 22:15:00 +01:00
busvoodoo_setup ( ) ; // setup BusVoodoo board
2018-04-28 17:45:21 +02:00
printf ( " \n welcome to \x1b [32mBus \x1b [35mVoodoo \x1b [0m (%s) \n " , busvoodoo_full ? " full " : " light " ) ; // print welcome message
2017-12-22 17:25:05 +01:00
2018-01-23 15:18:41 +01:00
// setup terminal
2018-02-26 12:14:11 +01:00
terminal_prefix = " BV " ; // set default prefix
2018-01-23 15:18:41 +01:00
terminal_process = & process_command ; // set central function to process commands
2018-01-14 13:49:16 +01:00
terminal_setup ( ) ; // start terminal
2018-01-23 15:18:41 +01:00
2018-02-06 12:31:46 +01:00
// setup OLED display
sleep_ms ( 10 ) ; // wait a bit until the display is ready
busvoodoo_oled_setup ( ) ; // setup OLED display
2018-07-01 15:26:41 +02:00
// display version
busvoodoo_oled_clear ( ) ;
busvoodoo_oled_text_left ( " BusVoodoo " ) ;
char str [ 20 ] ;
snprintf ( str , sizeof ( str ) , " fl: %s " , busvoodoo_full ? " full " : " light " ) ;
busvoodoo_oled_text_pos ( 1 , 16 + ( fonts [ FONT_KING10 ] . height + 2 ) * 1 , FONT_KING10 , str ) ;
snprintf ( str , sizeof ( str ) , " hw: %c " , busvoodoo_version ) ;
busvoodoo_oled_text_pos ( 1 , 16 + ( fonts [ FONT_KING10 ] . height + 2 ) * 2 , FONT_KING10 , str ) ;
snprintf ( str , sizeof ( str ) , " fw: %04u-%02u-%02u \n " , BUILD_YEAR , BUILD_MONTH , BUILD_DAY ) ;
busvoodoo_oled_text_pos ( 1 , 16 + ( fonts [ FONT_KING10 ] . height + 2 ) * 3 , FONT_KING10 , str ) ;
snprintf ( str , sizeof ( str ) , " bus.cuvoodoo.info " ) ;
busvoodoo_oled_text_pos ( ( 127 - ( ( fonts [ FONT_KING8 ] . width + 1 ) * strlen ( str ) ) ) / 2 , 63 , FONT_KING8 , str ) ;
busvoodoo_oled_update ( ) ;
sleep_ms ( 500 ) ;
busvoodoo_oled_clear ( ) ;
2018-01-23 23:41:41 +01:00
// setup default mode
switch_mode ( NULL ) ;
2018-01-23 15:36:05 +01:00
2018-01-23 15:18:41 +01:00
// main loop
2016-02-18 10:39:08 +01:00
bool action = false ; // if an action has been performed don't go to sleep
button_flag = false ; // reset button flag
2016-01-29 00:24:49 +01:00
while ( true ) { // infinite loop
2018-01-24 22:19:11 +01:00
while ( user_input_available ) { // user input received
2016-02-18 10:39:08 +01:00
action = true ; // action has been performed
2018-01-24 22:19:11 +01:00
char c = user_input_get ( ) ; // get user input
2018-01-23 15:36:05 +01:00
if ( 0x04 = = c ) { // CTRL+D is used to quit the mode
2018-01-24 16:37:00 +01:00
printf ( " quit \n " ) ; // acknowledge quitting
2018-01-23 15:36:05 +01:00
command_quit ( NULL ) ; // quit current mode
} else {
terminal_send ( c ) ; // send received character to terminal
}
2016-08-14 21:02:38 +02:00
}
if ( action ) { // go to sleep if nothing had to be done, else recheck for activity
2016-02-18 10:39:08 +01:00
action = false ;
} else {
__WFI ( ) ; // go to sleep
}
2016-10-23 17:42:27 +02:00
} // main loop
2016-01-17 14:54:54 +01:00
}