20.06.2016, 10:16 by Mare

Microcontroller with serial bus or USB CDC (virtual COM port) is usually connected to some terminal. User then type commands and firmware in the microcontroller interprets entered commands.

Developing simple interpreter is not very scientific task, more like PITA with repeating chunks of the code. After couple of successful projects with such interpreter I can say my code is somehow tested and proven in the practice. Now I prepared one application which can shorten development process and make my life easier when I start application in new device.

The source code generator generates only command line interpreter. It provides all identifiers for selected commands, provides function prototypes for each command and text template for help. Finally only the functions for executing specific commands should be then implemented.

The final application can be either multi-threaded with RTOS, or flat single thread. In both cases, there should be some function or ISR checking for new char and feeding this char to the command line editor. When new line “arrives”, the function cmd_proc() is called and then the magic happens.

Click here for the application for generating CLI source code. <<<< —- DOWNLOAD

Application requires maximum length of the command (including optional parameters) and list of commands. The commands are listed in the text box on the left:

When all commands are listed, hit the button “Generate code” and check the source code in the right text box. Button “Copy all” put the whole text in clipboard.

Here is example of using the code…

In main part of the microcontroller application (function main() or one thread in RTOS), put something like this:

int main ( void ) { /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init ( ) ; /* Configure the system clock */ SystemClock_Config ( ) ; /* Initialize all configured peripherals */ MX_GPIO_Init ( ) ; ///////// further initializations.... /* Infinite loop */ while ( 1 ) { if ( is_line_received ( ) ) { // Process received line cmd_proc ( get_line_buffer ( ) ) ; } // if } // while } int main(void) { /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); ///////// further initializations.... /* Infinite loop */ while (1) { if (is_line_received()) { // Process received line cmd_proc(get_line_buffer()); } // if } // while }

Then provide three functions:

process_rx_char ( char rx_char ) process_rx_char(char rx_char) — for command line editor and another unsigned char is_line_received ( void ) unsigned char is_line_received(void) — for indicating new line received char * get_line_buffer ( void ) char *get_line_buffer(void) — which only returns pointer to the newly received line

Example source code:

/** * Command line edit chars */ #define CNTLQ 0x11 #define CNTLS 0x13 #define DEL 0x7F #define BACKSPACE 0x08 #define CR 0x0D #define LF 0x0A static unsigned char line_flag ; // Flag to indicate new received line char line_buf [ 256 ] ; int line_idx = 0 ; extern void abort_autorun ( void ) ; /** * Process received char, check if LF or CR received * Set flag when line is done */ void process_rx_char ( char rx_char ) { abort_autorun ( ) ; if ( rx_char == CR ) rx_char = LF ; if ( rx_char == BACKSPACE || rx_char == DEL ) { // process backspace if ( line_idx != 0 ) { line_idx --; // decrement index #ifdef LOCALECHO putchar ( BACKSPACE ) ; // echo backspace putchar ( ' ' ) ; putchar ( BACKSPACE ) ; #endif } } else { #ifdef LOCALECHO putchar ( rx_char ) ; // echo #endif line_buf [ line_idx ++ ] = rx_char ; // store character and increment index } // check limit and end line feed if ( ( line_idx == 0xff ) || ( rx_char == LF ) ) { line_buf [ line_idx - 1 ] = 0 ; // mark end of string line_idx = 0 ; line_flag = 1 ; } } /** * Indicate new line received via UART. * Return 1 when new line received. Status flag is cleared to 0. * Return 0 if new line is not received yet */ unsigned char is_line_received ( void ) { if ( line_flag == 1 ) { line_flag = 0 ; return 1 ; } else { return 0 ; } } char * get_line_buffer ( void ) { return line_buf ; } /** * Command line edit chars */ #define CNTLQ 0x11 #define CNTLS 0x13 #define DEL 0x7F #define BACKSPACE 0x08 #define CR 0x0D #define LF 0x0A static unsigned char line_flag; // Flag to indicate new received line char line_buf[256]; int line_idx = 0; extern void abort_autorun(void); /** * Process received char, check if LF or CR received * Set flag when line is done */ void process_rx_char(char rx_char) { abort_autorun(); if (rx_char == CR) rx_char = LF; if (rx_char == BACKSPACE || rx_char == DEL) { // process backspace if (line_idx != 0) { line_idx--; // decrement index #ifdef LOCALECHO putchar (BACKSPACE); // echo backspace putchar (' '); putchar (BACKSPACE); #endif } } else { #ifdef LOCALECHO putchar (rx_char); // echo #endif line_buf[line_idx++] = rx_char; // store character and increment index } // check limit and end line feed if ((line_idx == 0xff) || (rx_char == LF)) { line_buf[line_idx-1] = 0; // mark end of string line_idx = 0; line_flag = 1; } } /** * Indicate new line received via UART. * Return 1 when new line received. Status flag is cleared to 0. * Return 0 if new line is not received yet */ unsigned char is_line_received(void) { if (line_flag == 1) { line_flag = 0; return 1; } else { return 0; } } char *get_line_buffer(void) { return line_buf; }

The commands in the autogenerated code are at the end of the source code: