/* 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 . * */ /** STM32F1 BusVoodoo application * @file application.c * @author King Kévin * @date 2016-2017 */ /* standard libraries */ #include // standard integer types #include // string utilities /* STM32 (including CM3) libraries */ #include // Cortex M3 utilities #include // general purpose input output library #include // real-time control clock library #include // debug utilities /* own libraries */ #include "global.h" // board definitions #include "print.h" // printing utilities #include "uart.h" // USART utilities #include "usb_cdcacm.h" // USB CDC ACM utilities #include "terminal.h" // handle the terminal interface #include "menu.h" // menu utilities #include "busvoodoo_global.h" // BusVoodoo definitions #include "busvoodoo_oled.h" // OLED utilities #include "busvoodoo_hiz.h" // BusVoodoo HiZ mode #include "busvoodoo_uart.h" // BusVoodoo UART mode /** all supported BusVoodoo modes */ static struct busvoodoo_mode_t* busvoodoo_modes[] = { &busvoodoo_hiz_mode, &busvoodoo_uart_mode, }; /** current BusVoodoo mode */ static struct busvoodoo_mode_t* busvoodoo_mode = NULL; /** is mode setup complete */ static bool busvoodoo_mode_complete = false; size_t putc(char c) { size_t length = 0; // number of characters printed 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 uart_putchar_nonblocking('\r'); // send CR over USART usb_cdcacm_putchar('\r'); // send CR over USB length++; // remember we printed 1 character } } 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 return length; // return number of characters printed } /** switch BusVoddoo mode * @param[in] mode mode to switch to */ static void switch_mode(struct busvoodoo_mode_t* mode) { if (busvoodoo_mode) { (*busvoodoo_mode->exit)(); // exit current mode } // reset pinout for (uint8_t i=0; isetup)(&terminal_prefix, NULL); // start setup terminal_send(0); // update the terminal prompt } /** command to show help * @param[in] argument no argument required */ static void command_help(void* argument); /** command to select mode * @param[in] argument mode to select */ static void command_mode(void* argument); /** command to quit current BusVoodoo mode * @param[in] argument no argument required */ static void command_quit(void* argument); /** 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 */ static void command_bootloader(void* argument); /** command to show version * @param[in] argument no argument required */ static void command_version(void* argument); /** list of all supported commands */ static const struct menu_command_t menu_commands[] = { { 'm', "mode", "select mode", MENU_ARGUMENT_STRING, "[mode]", &command_mode, }, { 'q', "quit", "quit current mode", MENU_ARGUMENT_NONE, NULL, &command_quit, }, { 'r', "reset", "reset board", MENU_ARGUMENT_NONE, NULL, &command_reset, }, { 'b', "bootloader", "reboot into DFU bootloader", MENU_ARGUMENT_NONE, NULL, &command_bootloader, }, { 'v', "version", "show hardware and firmware version", MENU_ARGUMENT_NONE, NULL, &command_version, }, { 'h', "help", "display help", MENU_ARGUMENT_NONE, NULL, &command_help, }, }; 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 menu_print_commands(busvoodoo_global_commands, LENGTH(busvoodoo_global_commands)); // print BusVoodoo global commands menu_print_commands(busvoodoo_mode->commands, busvoodoo_mode->commands_nb); // print BusVoodoo mode commands } 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; iname, busvoodoo_modes[i]->description); // display mode information } } else { // mode provided bool mode_found = false; // to know if we found the matching mode for (uint8_t i=0; iname)) { // check for corresponding mode (*busvoodoo_mode->exit)(); // exit current mode led_off(); // switch off LEDs busvoodoo_mode = busvoodoo_modes[i]; // set matching mode as current mode busvoodoo_mode_complete = (*busvoodoo_mode->setup)(&terminal_prefix, NULL); // start setup terminal_send(0); // update the terminal prompt mode_found = true; // remember we found the mode break; // stop searching for mode } } if (!mode_found) { printf("unknown mode: %s\n", argument); } } } static void command_quit(void* argument) { (void)argument; // we won't use the argument switch_mode(NULL); // switch do default mode } 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 } static void command_bootloader(void* argument) { (void)argument; // we won't use the argument RCC_CSR |= RCC_CSR_RMVF; // clear reset flags scb_reset_core(); // reset core (the bootloader will interpret it as starting into DFU) while (true); // wait for the reset to happen } static void command_version(void* argument) { (void)argument; // we won't use the argument printf("BusVoodoo board: %s\n", busvoodoo_full ? "full" : "light"); printf("hardware revision: "); if (busvoodoo_revision) { printf("%u", busvoodoo_revision); } else { printf("unknown"); } printf("\n"); printf("firmware date: %04u-%02u-%02u\n", BUILD_YEAR, BUILD_MONTH, BUILD_DAY); printf("board ID: %08x%08x%08x\n", DESIG_UNIQUE_ID0, DESIG_UNIQUE_ID1, DESIG_UNIQUE_ID2); } /** process user command * @param[in] str user command string (\0 ended) */ static void process_command(char* str) { // ensure actions are available if (NULL==menu_commands || 0==LENGTH(menu_commands)) { return; } // handle user input 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 } else { // don't handle empty lines if (!str || 0==strlen(str)) { return; } if (!menu_handle_command(str, busvoodoo_mode->commands, busvoodoo_mode->commands_nb)) { if (!menu_handle_command(str, busvoodoo_global_commands, LENGTH(busvoodoo_global_commands))) { if (!menu_handle_command(str, menu_commands, LENGTH(menu_commands))) { printf("command not recognized. enter help to list commands\n"); } } } } } /** program entry point * this is the firmware function started by the micro-controller */ void main(void); void main(void) { rcc_clock_setup_in_hse_8mhz_out_72mhz(); // use 8 MHz high speed external clock to generate 72 MHz internal clock // enable functionalities for easier debug 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) board_setup(); // setup board uart_setup(); // setup USART (for printing) usb_cdcacm_setup(); // setup USB CDC ACM (for printing) busvoodoo_setup(); // setup BusVoodoo board printf("\nwelcome to BusVoodoo ("); // print welcome message if (busvoodoo_full) { printf("full"); } else { printf("light"); } printf(" version)\n"); // setup terminal terminal_prefix = "BV: "; // set default prefix terminal_process = &process_command; // set central function to process commands terminal_setup(); // start terminal // setup OLED display sleep_ms(10); // wait a bit until the display is ready busvoodoo_oled_setup(); // setup OLED display // setup default mode switch_mode(NULL); // main loop bool action = false; // if an action has been performed don't go to sleep button_flag = false; // reset button flag while (true) { // infinite loop while (user_input_available) { // user input received action = true; // action has been performed char c = user_input_get(); // get user input if (0x04==c) { // CTRL+D is used to quit the mode printf("quit\n"); // acknowledge quitting command_quit(NULL); // quit current mode } else { terminal_send(c); // send received character to terminal } } if (action) { // go to sleep if nothing had to be done, else recheck for activity action = false; } else { __WFI(); // go to sleep } } // main loop }