/* * https://github.com/bnielsen1965/pi-pico-c-console * * This demo uses a multicore application to setup a command prompt on the stdio serial port. * The second Pi Pico core runs a process that reads input from stdio and echoes the characters * back. When enter is received the process releases a semaphore to trigger the command * processing thread. The command processing thread runs on core0 and waits on a semaphore for a command string to process. Two commands are provided in the demo application, "help" and "bootrom". The help command will display a help message in the terminal and the bootrom command will reset the Pi Pico and boot into BOOTSEL mode. */ #include "console.h" #include "command.h" #define UART_ID uart0 #define BAUD_RATE 115200 #define DATA_BITS 8 #define STOP_BITS 1 #define PARITY UART_PARITY_NONE #define UART_TX_PIN 0 #define UART_RX_PIN 1 // declare initialization method void init (); // declare semaphore to control command execution semaphore_t semCommand; // main runs on core0 int main () { init(); // run console on core1 multicore_launch_core1(console); // run command processor here on core0 commandProcessor(); } // initialize application void init () { // initialize stdio stdio_init_all(); sleep_ms(2000); // without this it doesn't //https://stackoverflow.com/questions/72156148/how-to-run-code-on-the-second-core-on-raspberry-pico stdio_flush(); setbuf(stdout, NULL); // make sure character input is buffered // initialize command semaphore sem_init(&semCommand, 0, 1); } /////////////////////// // console.h ////////////////////// #include #include #include "pico/stdlib.h" #include "pico/multicore.h" #include "pico/mutex.h" #include // console line settings #define LINE_LEN 80 // declare console methods void console (); void initConsole (char * lineBuffer, char * commandLine); size_t appendChar(char * buffer, char c); size_t deleteChar(char * buffer); size_t clearBuffer (char * buffer); void flushInput (); // console needs access to external command semaphore extern semaphore_t semCommand; ////////////////////// // console.c ////////////////////// #include "console.h" // define command line buffer that will be used internallly and externally char commandLine[LINE_LEN + 1]; // console process thread to handle stdin void console () { int16_t c; // must be 16 bit to get the error codes char lineBuffer[LINE_LEN + 1]; // define input buffer size_t cursor = 0; // initialize console initConsole (lineBuffer, commandLine); printf("goodbye\n"); // main console loop for (;;) { c = getchar(); // some characters will not be processed if (c <= 0x07) continue; if (c >= 0x09 && c <= 0x0c) continue; if (c >= 0x0e && c <= 0x1a) continue; if (c >= 0x1c && c <= 0x1f) continue; // handle escape sequence if (c == 0x1b) { flushInput(); continue; } // handle enter if (c == 0x0d) { // copy input line buffer to command line buffer memcpy(commandLine, lineBuffer, LINE_LEN); // clear input line buffer and send newline to terminal cursor = clearBuffer(lineBuffer); printf("\n"); // release command semaphore to enable processing of command line sem_release(&semCommand); continue; } // handle backspace / del if (c == 0x7f || c == 0x08) { if (cursor == 0) continue; cursor = deleteChar(lineBuffer); // use backspace, space, backspace to erase character on terminal printf("%c%c%c", 0x08, ' ', 0x08); continue; } // don't allow characters when at end of buffer if (cursor == LINE_LEN) continue; // handle character input cursor = appendChar(lineBuffer, c); printf("%c", c); } } // initialize console void initConsole (char * lineBuffer, char * commandLine) { // clear line buffers and set end of line nulls clearBuffer(commandLine); commandLine[LINE_LEN] = '\0'; clearBuffer(lineBuffer); lineBuffer[LINE_LEN] = '\0'; // flush all input flushInput(); } // clear contents of the specified buffer size_t clearBuffer (char * buffer) { memset(buffer, '\0', LINE_LEN); return strlen(buffer); } // append a character to the input buffer and return new length size_t appendChar (char * buffer, char c) { if (strlen(buffer) == LINE_LEN) return LINE_LEN; buffer[strlen(buffer)] = c; return strlen(buffer); } // delete character from input buffer and return length size_t deleteChar (char * buffer) { if (strlen(buffer) == 0) return 0; buffer[strlen(buffer) - 1] = '\0'; return strlen(buffer); } // flush stdio input void flushInput () { int16_t c; // must be 16 bit to capture error codes do { // read characters until nothing left to read c = getchar_timeout_us(500); } while (c != PICO_ERROR_TIMEOUT && c != PICO_ERROR_GENERIC); } ///////////////////////////// // command.h ////////////////////////////// #include #include #include #include #include "pico/mutex.h" #include "pico/stdlib.h" #include "pico/multicore.h" #include "console.h" // access to externally defined variables extern semaphore_t semCommand; extern char commandLine[]; void commandProcessor (); //////////////////////////////// // command.c ////////////////////////////// #include "command.h" #include "pico/bootrom.h" // help message const char * HELP = "Pi Pico Basic Command Prompt - A simple 80 character command\n" "line buffer used to control the Pi Pico\n" "Commands:\n" "help - Display this help message\n" "bootrom - Reset and boot into BOOTSEL ROM\n"; // thread to process commands void commandProcessor () { printf("command processor\n"); for (;;) { // block until console permits command processing sem_acquire_blocking(&semCommand); // continue if command line is empty if (0 == strlen(commandLine)) continue; // help command else if (0 == strcmp(commandLine, "help")) printf("%s", HELP); // bootrom command else if (0 == strcmp(commandLine, "bootrom")) reset_usb_boot(0, 0); // invalid input error else printf("Unknown command %s. Enter help command for help.\n", commandLine); } } #################### ## CMakeLists.txt #################### cmake_minimum_required(VERSION 3.13) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake) project(console C CXX) pico_sdk_init() add_executable(console main.c console.c command.c) pico_enable_stdio_uart(console 1) pico_enable_stdio_usb(console 0) target_link_libraries(console pico_stdlib pico_multicore) pico_add_extra_outputs(console)