Felipe Neves
/
TEN_mbedos_simple_shell
TEN MBED OS Course shell utility
shell.cpp@0:1e8461adc480, 2017-01-29 (annotated)
- Committer:
- uLipe
- Date:
- Sun Jan 29 20:57:17 2017 +0000
- Revision:
- 0:1e8461adc480
first;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
uLipe | 0:1e8461adc480 | 1 | /** |
uLipe | 0:1e8461adc480 | 2 | * @brief our first hello world threaded program with MBED OS |
uLipe | 0:1e8461adc480 | 3 | */ |
uLipe | 0:1e8461adc480 | 4 | #include "mbed.h" |
uLipe | 0:1e8461adc480 | 5 | #include "rtos.h" |
uLipe | 0:1e8461adc480 | 6 | #include "shell.h" |
uLipe | 0:1e8461adc480 | 7 | |
uLipe | 0:1e8461adc480 | 8 | /* declare a thread reserved only for shell command handler */ |
uLipe | 0:1e8461adc480 | 9 | const size_t shell_stk_size = 8192; |
uLipe | 0:1e8461adc480 | 10 | uint8_t shell_stk[shell_stk_size]; |
uLipe | 0:1e8461adc480 | 11 | Thread shell_thread(osPriorityNormal, shell_stk_size, &shell_stk[0]); |
uLipe | 0:1e8461adc480 | 12 | |
uLipe | 0:1e8461adc480 | 13 | /* reserve the debbuger uart to shell interface */ |
uLipe | 0:1e8461adc480 | 14 | Serial pc_serial(SHELL_TXD,SHELL_RXD); |
uLipe | 0:1e8461adc480 | 15 | |
uLipe | 0:1e8461adc480 | 16 | static shell_callback_t shell_handler = NULL; |
uLipe | 0:1e8461adc480 | 17 | static shell_usage_t shell_usage; |
uLipe | 0:1e8461adc480 | 18 | static int argc = 0; |
uLipe | 0:1e8461adc480 | 19 | static char *argv[16]; |
uLipe | 0:1e8461adc480 | 20 | |
uLipe | 0:1e8461adc480 | 21 | /** |
uLipe | 0:1e8461adc480 | 22 | * @brief show help menu |
uLipe | 0:1e8461adc480 | 23 | */ |
uLipe | 0:1e8461adc480 | 24 | static void print_usage(void) |
uLipe | 0:1e8461adc480 | 25 | { |
uLipe | 0:1e8461adc480 | 26 | pc_serial.printf("## use with the syntax below: \n\r"); |
uLipe | 0:1e8461adc480 | 27 | pc_serial.printf("## command <arg1> <arg2> ... <arg16> \n\r"); |
uLipe | 0:1e8461adc480 | 28 | pc_serial.printf("## Available commands: \n\r"); |
uLipe | 0:1e8461adc480 | 29 | if(shell_usage != NULL) { |
uLipe | 0:1e8461adc480 | 30 | shell_usage((void *)&pc_serial); |
uLipe | 0:1e8461adc480 | 31 | } |
uLipe | 0:1e8461adc480 | 32 | } |
uLipe | 0:1e8461adc480 | 33 | |
uLipe | 0:1e8461adc480 | 34 | |
uLipe | 0:1e8461adc480 | 35 | /** |
uLipe | 0:1e8461adc480 | 36 | * @brief parse the command received via comport |
uLipe | 0:1e8461adc480 | 37 | */ |
uLipe | 0:1e8461adc480 | 38 | static void shell_parser (char *cmd, int size) |
uLipe | 0:1e8461adc480 | 39 | { |
uLipe | 0:1e8461adc480 | 40 | int cmd_ptr = 0; |
uLipe | 0:1e8461adc480 | 41 | int arg_ptr = 0; |
uLipe | 0:1e8461adc480 | 42 | int cmd_size = 0; |
uLipe | 0:1e8461adc480 | 43 | char command_buffer[256]; |
uLipe | 0:1e8461adc480 | 44 | |
uLipe | 0:1e8461adc480 | 45 | |
uLipe | 0:1e8461adc480 | 46 | /* copy to the root command */ |
uLipe | 0:1e8461adc480 | 47 | memset(&command_buffer, 0, sizeof(command_buffer)); |
uLipe | 0:1e8461adc480 | 48 | |
uLipe | 0:1e8461adc480 | 49 | /* find the root command terminator (space) */ |
uLipe | 0:1e8461adc480 | 50 | while(cmd_ptr < size) { |
uLipe | 0:1e8461adc480 | 51 | if(cmd[cmd_ptr] == ' ') break; |
uLipe | 0:1e8461adc480 | 52 | cmd_ptr++; |
uLipe | 0:1e8461adc480 | 53 | } |
uLipe | 0:1e8461adc480 | 54 | cmd_size = size - cmd_ptr; |
uLipe | 0:1e8461adc480 | 55 | |
uLipe | 0:1e8461adc480 | 56 | |
uLipe | 0:1e8461adc480 | 57 | /* extract command arguments */ |
uLipe | 0:1e8461adc480 | 58 | strncpy(&command_buffer[0], &cmd[cmd_ptr + 1], (size - cmd_ptr)); |
uLipe | 0:1e8461adc480 | 59 | |
uLipe | 0:1e8461adc480 | 60 | /* terminates the root command */ |
uLipe | 0:1e8461adc480 | 61 | cmd[cmd_ptr] = 0; |
uLipe | 0:1e8461adc480 | 62 | arg_ptr = 0; |
uLipe | 0:1e8461adc480 | 63 | |
uLipe | 0:1e8461adc480 | 64 | //pc_serial.printf("## command: %s \n\r", cmd); |
uLipe | 0:1e8461adc480 | 65 | //pc_serial.printf("## arguments: %s \n\r", command_buffer); |
uLipe | 0:1e8461adc480 | 66 | |
uLipe | 0:1e8461adc480 | 67 | |
uLipe | 0:1e8461adc480 | 68 | /* extract the further arguments */ |
uLipe | 0:1e8461adc480 | 69 | while(arg_ptr < (cmd_size)) { |
uLipe | 0:1e8461adc480 | 70 | |
uLipe | 0:1e8461adc480 | 71 | argc++; |
uLipe | 0:1e8461adc480 | 72 | *(argv + (argc- 1)) = &command_buffer[arg_ptr]; |
uLipe | 0:1e8461adc480 | 73 | |
uLipe | 0:1e8461adc480 | 74 | /* find terminator */ |
uLipe | 0:1e8461adc480 | 75 | while(command_buffer[arg_ptr] != ' ') { |
uLipe | 0:1e8461adc480 | 76 | arg_ptr++; |
uLipe | 0:1e8461adc480 | 77 | } |
uLipe | 0:1e8461adc480 | 78 | |
uLipe | 0:1e8461adc480 | 79 | /* adds to argument list */ |
uLipe | 0:1e8461adc480 | 80 | command_buffer[arg_ptr] = 0; |
uLipe | 0:1e8461adc480 | 81 | arg_ptr++; |
uLipe | 0:1e8461adc480 | 82 | // pc_serial.printf("## argument no: %d : %s \n\r", argc, argv[argc-1]); |
uLipe | 0:1e8461adc480 | 83 | } |
uLipe | 0:1e8461adc480 | 84 | |
uLipe | 0:1e8461adc480 | 85 | |
uLipe | 0:1e8461adc480 | 86 | |
uLipe | 0:1e8461adc480 | 87 | /* finds and execute the command table */ |
uLipe | 0:1e8461adc480 | 88 | if(shell_handler != NULL){ |
uLipe | 0:1e8461adc480 | 89 | |
uLipe | 0:1e8461adc480 | 90 | int ret = shell_handler(cmd, argc, argv, (void *)&pc_serial); |
uLipe | 0:1e8461adc480 | 91 | if(ret < 0) { |
uLipe | 0:1e8461adc480 | 92 | print_usage(); |
uLipe | 0:1e8461adc480 | 93 | } |
uLipe | 0:1e8461adc480 | 94 | }else { |
uLipe | 0:1e8461adc480 | 95 | print_usage(); |
uLipe | 0:1e8461adc480 | 96 | } |
uLipe | 0:1e8461adc480 | 97 | } |
uLipe | 0:1e8461adc480 | 98 | |
uLipe | 0:1e8461adc480 | 99 | |
uLipe | 0:1e8461adc480 | 100 | |
uLipe | 0:1e8461adc480 | 101 | |
uLipe | 0:1e8461adc480 | 102 | /** |
uLipe | 0:1e8461adc480 | 103 | * @brief shell commands processing thread |
uLipe | 0:1e8461adc480 | 104 | */ |
uLipe | 0:1e8461adc480 | 105 | static void shell_task(void) |
uLipe | 0:1e8461adc480 | 106 | { |
uLipe | 0:1e8461adc480 | 107 | char serial_buffer[1024] = {0}; |
uLipe | 0:1e8461adc480 | 108 | int read_ptr = 0; |
uLipe | 0:1e8461adc480 | 109 | |
uLipe | 0:1e8461adc480 | 110 | /* setup the serial as 115200 bps */ |
uLipe | 0:1e8461adc480 | 111 | pc_serial.baud(115200); |
uLipe | 0:1e8461adc480 | 112 | |
uLipe | 0:1e8461adc480 | 113 | /* prints a welcome message */ |
uLipe | 0:1e8461adc480 | 114 | |
uLipe | 0:1e8461adc480 | 115 | pc_serial.printf("******************************************************************\n\r"); |
uLipe | 0:1e8461adc480 | 116 | pc_serial.printf("*** Welcome to MbedOS Simple Shell application ****\n\r"); |
uLipe | 0:1e8461adc480 | 117 | pc_serial.printf("*** Type some commands or just Enter key to see the available ****\n\r"); |
uLipe | 0:1e8461adc480 | 118 | pc_serial.printf("******************************************************************\n\r"); |
uLipe | 0:1e8461adc480 | 119 | pc_serial.printf(">>"); |
uLipe | 0:1e8461adc480 | 120 | |
uLipe | 0:1e8461adc480 | 121 | for(;;Thread::wait(50)) { |
uLipe | 0:1e8461adc480 | 122 | /* check if we have character available */ |
uLipe | 0:1e8461adc480 | 123 | if(pc_serial.readable()) { |
uLipe | 0:1e8461adc480 | 124 | bool new_cmd = false; |
uLipe | 0:1e8461adc480 | 125 | |
uLipe | 0:1e8461adc480 | 126 | /* get the incoming character */ |
uLipe | 0:1e8461adc480 | 127 | char c = pc_serial.getc(); |
uLipe | 0:1e8461adc480 | 128 | |
uLipe | 0:1e8461adc480 | 129 | if( (c == '\n') || (c == '\r')) { |
uLipe | 0:1e8461adc480 | 130 | /* handle enter key */ |
uLipe | 0:1e8461adc480 | 131 | new_cmd = true; |
uLipe | 0:1e8461adc480 | 132 | pc_serial.printf("\n\r"); |
uLipe | 0:1e8461adc480 | 133 | |
uLipe | 0:1e8461adc480 | 134 | }else if( (c == 0x7F) || (c == 0x08)){ |
uLipe | 0:1e8461adc480 | 135 | /* handle backspace and del keys */ |
uLipe | 0:1e8461adc480 | 136 | pc_serial.printf("\033[1D"); |
uLipe | 0:1e8461adc480 | 137 | pc_serial.putc(' '); |
uLipe | 0:1e8461adc480 | 138 | pc_serial.printf("\033[1D"); |
uLipe | 0:1e8461adc480 | 139 | |
uLipe | 0:1e8461adc480 | 140 | read_ptr--; |
uLipe | 0:1e8461adc480 | 141 | if(read_ptr < 0) read_ptr = 1023; |
uLipe | 0:1e8461adc480 | 142 | serial_buffer[read_ptr] = ' '; |
uLipe | 0:1e8461adc480 | 143 | |
uLipe | 0:1e8461adc480 | 144 | |
uLipe | 0:1e8461adc480 | 145 | } else { |
uLipe | 0:1e8461adc480 | 146 | /* loopback the pressed key */ |
uLipe | 0:1e8461adc480 | 147 | pc_serial.putc(c); |
uLipe | 0:1e8461adc480 | 148 | |
uLipe | 0:1e8461adc480 | 149 | /* store the incoming character on command circular buffer */ |
uLipe | 0:1e8461adc480 | 150 | serial_buffer[read_ptr] = c; |
uLipe | 0:1e8461adc480 | 151 | read_ptr = (read_ptr + 1) % 1024; |
uLipe | 0:1e8461adc480 | 152 | } |
uLipe | 0:1e8461adc480 | 153 | |
uLipe | 0:1e8461adc480 | 154 | |
uLipe | 0:1e8461adc480 | 155 | |
uLipe | 0:1e8461adc480 | 156 | if(new_cmd != false) { |
uLipe | 0:1e8461adc480 | 157 | /* command arrived, has other characters? */ |
uLipe | 0:1e8461adc480 | 158 | if(read_ptr != 0) { |
uLipe | 0:1e8461adc480 | 159 | shell_parser(&serial_buffer[0], read_ptr); |
uLipe | 0:1e8461adc480 | 160 | } else { |
uLipe | 0:1e8461adc480 | 161 | print_usage(); |
uLipe | 0:1e8461adc480 | 162 | } |
uLipe | 0:1e8461adc480 | 163 | /* reset the buffer command */ |
uLipe | 0:1e8461adc480 | 164 | memset(&serial_buffer, 0, sizeof(serial_buffer)); |
uLipe | 0:1e8461adc480 | 165 | read_ptr = 0; |
uLipe | 0:1e8461adc480 | 166 | pc_serial.printf(">>"); |
uLipe | 0:1e8461adc480 | 167 | } |
uLipe | 0:1e8461adc480 | 168 | |
uLipe | 0:1e8461adc480 | 169 | } |
uLipe | 0:1e8461adc480 | 170 | } |
uLipe | 0:1e8461adc480 | 171 | } |
uLipe | 0:1e8461adc480 | 172 | |
uLipe | 0:1e8461adc480 | 173 | void shell_set_command_handler(shell_callback_t sh) |
uLipe | 0:1e8461adc480 | 174 | { |
uLipe | 0:1e8461adc480 | 175 | shell_handler = sh; |
uLipe | 0:1e8461adc480 | 176 | } |
uLipe | 0:1e8461adc480 | 177 | void shell_set_cmd_list(shell_usage_t sh) |
uLipe | 0:1e8461adc480 | 178 | { |
uLipe | 0:1e8461adc480 | 179 | shell_usage = sh; |
uLipe | 0:1e8461adc480 | 180 | } |
uLipe | 0:1e8461adc480 | 181 | void shell_start(void) |
uLipe | 0:1e8461adc480 | 182 | { |
uLipe | 0:1e8461adc480 | 183 | shell_thread.start(shell_task); |
uLipe | 0:1e8461adc480 | 184 | } |
uLipe | 0:1e8461adc480 | 185 |