1@page page_component_finsh FinSH Console 2 3In the early days of computer development, before the advent of graphics systems, there was no mouse or even a keyboard. How did people interact with computers at the time? The earliest computers used a punched note to enter commands into the computer and write the program. Later, with the continuous development of computers, monitors and keyboards became the standard configuration of computers, but the operating system at this time did not support the graphical interface. Computer pioneers developed a software that accepts commands entered by the user, and after interpretation, passes it to The operating system and return the results of the operating system execution to the user. This program wraps around the operating system like a layer of shell, so it's called a shell. 4 5Embedded devices usually need to connect the development board to the PC for communication. Common connections include: serial port, USB, Ethernet, Wi-Fi, etc. A flexible shell should also support working on multiple connection methods. With the shell, the developer can easily get the system running and control the operation of the system through commands. Especially in the debugging phase, with the shell, in addition to being able to locate the problem more quickly, the developer can also use the shell to call the test function, change the parameters of the test function, reduce the number of times the code is downloaded, and shorten the development time of the project. 6 7FinSH is the command line component (shell) of RT-Thread. It is based on the above considerations. FinSH is pronounced [ˈfɪnʃ]. After reading this chapter, we will have a deeper understanding of how FinSH works and how to export your own commands to FinSH. 8 9# Introduction of FinSH 10 11FinSH is the command line component of RT-Thread. It provides a set of operation interfaces for users to call from the command line. It is mainly used to debug or view system information. It can communicate with a PC using serial/Ethernet/USB, etc. The hardware topology is shown below: 12 13 14 15The user inputs a command in the control terminal, and the control terminal transmits the command to the FinSH in the device through the serial port, USB, network, etc., FinSH will read the device input command, parse and automatically scan the internal function table, find the corresponding function name, and execute the function. The response is output, the response is returned through the original path, and the result is displayed on the control terminal. 16 17When using a serial port to connect a device to a control terminal, the execution flow of the FinSH command is as follows: 18 19 20 21FinSH supports the rights verification function. After the system is started, the system will perform the rights verification. Only when the rights verification is passed, the FinSH function will be enabled. This improves the security of system input. 22 23FinSH supports auto-completion, and viewing history commands, etc. These functions can be easily accessed through the keys on the keyboard. The keys supported by FinSH are shown in the following table: 24 25|Keys| **Functional Description** | 26|----------|--------------| 27| Tab key | Pressing the Tab key when no characters are entered will print all commands supported by the current system. If you press the Tab key when you have entered some characters, it will find the matching command, and will also complete the file name according to the file system's current directory, and you can continue to input, multiple completions. | 28| ↑↓ key | Scroll up and down the recently entered history command | 29| Backspace key | Delete character | 30| ←→ key | Move the cursor left or right | 31 32FinSH supports two input modes, the traditional command line mode and the C language interpreter mode. 33 34## Traditional Command Line Mode 35 36This mode is also known as msh(module shell). In msh mode, FinSH is implemented in the same way as the traditional shell (dos/bash). For example, you can switch directories to the root directory with the `cd /` command. 37 38MSH can parse commands into parameters and parameters separated by spaces. Its command execution format is as follows: 39 40``` 41command [arg1] [arg2] [...] 42``` 43 44The command can be either a built-in command in RT-Thread or an executable file. 45 46## C Language Interpreter Mode 47 48This mode is also known as C-Style mode. In C language interpreter mode, FinSH can solve and parse most C language expressions, and use functions like C to access functions and global variables in the system. In addition, it can create variables through the command line. In this mode, the command entered must be similar to the function call in C language, that is, you must carry the `()` symbol. For example, to output all current threads and their status in the system, type `list_thread()` in FinSH to print out the required information. The output of the FinSH command is the return value of this function. For some functions that do not have a return value (void return value), this printout has no meaning. 49 50Initially FinSH only supported C-Style mode. Later, with the development of RT-Thread, C-Style mode is not convenient when running scripts or programs, and it is more convenient to use traditional shell method. In addition, in C-Style mode, FinSH takes up a lot of volume. For these reasons, the msh mode has been added to RT-Thread. The msh mode is small and easy to use. It is recommended that you use the msh mode. 51 52If both modes are enabled in the RT-Thread, they can be dynamically switched. Enter the `exit` in msh mode and press `Enter` to switch to C-Style mode. Enter `msh()` in C-Style mode and press `Enter` to enter msh mode. The commands of the two modes are not common, and the msh command cannot be used in C-Style mode, and vice versa. 53 54# FinSH Built-in Commands 55 56Some FinSH commands are built in by default in RT-Thread. You can print all commands supported by the current system by entering help in FinSH and pressing Enter or directly pressing Tab. The built-in commands in C-Style and msh mode are basically the same, so msh is taken as an example here. 57 58In msh mode, you can list all currently supported commands by pressing the Tab key. The number of default commands is not fixed, and the various components of RT-Thread will output some commands to FinSH. For example, when the DFS component is opened, commands such as `ls`, `cp`, and `cd` are added to FinSH for developers to debug. 59 60The following are all currently supported commands that display RT-Thread kernel status information after pressing the Tab key. The command name is on the left and the description of the command on the right: 61 62```c 63RT-Thread shell commands: 64version - show RT-Thread version information 65list_thread - list thread 66list_sem - list semaphore in system 67list_event - list event in system 68list_mutex - list mutex in system 69list_mailbox - list mail box in system 70list_msgqueue - list message queue in system 71list_timer - list timer in system 72list_device - list device in system 73exit - return to RT-Thread shell mode. 74help - RT-Thread shell help. 75ps - List threads in the system. 76time - Execute command with time. 77free - Show the memory usage in the system. 78``` 79 80Here lists the field information returned after entering the common commands, so that the developer can understand the content of the returned information. 81 82## Display Thread Status 83 84Use the `ps` or `list_thread` command to list all thread information in the system, including thread priority, state, maximum stack usage, and more. 85 86```c 87msh />list_thread 88thread pri status sp stack size max used left tick error 89-------- --- ------- ---------- ---------- ------ ---------- --- 90tshell 20 ready 0x00000118 0x00001000 29% 0x00000009 000 91tidle 31 ready 0x0000005c 0x00000200 28% 0x00000005 000 92timer 4 suspend 0x00000078 0x00000400 11% 0x00000009 000 93``` 94list_thread Return field description: 95 96|**Field** |**Description** | 97|------------|----------------------------| 98| thread | Thread name | 99| pri | Thread priority | 100| status | The current state of the thread | 101| sp | The current stack position of the thread | 102| stack size | Thread stack size | 103| max used | The maximum stack position used in thread history | 104| left tick | The number of remaining ticks of the thread | 105| error | Thread error code | 106 107## Display Semaphore Status 108 109Use the `list_sem` command to display all semaphore information in the system, including the name of the semaphore, the value of the semaphore, and the number of threads waiting for this semaphore. 110 111```c 112msh />list_sem 113semaphore v suspend thread 114-------- --- -------------- 115shrx 000 0 116e0 000 0 117``` 118 119list_sem Return field description: 120 121|**Field** | **Description** | 122|----------------|--------------------------| 123| semaphore | Semaphore name | 124| v | The current value of semaphore | 125| suspend thread | The number of threads waiting for this semaphore | 126 127## Display Event Status 128 129Use the `list_event` command to display all event information in the system, including the event name, the value of the event, and the number of threads waiting for this event. 130 131```c 132msh />list_event 133event set suspend thread 134----- ---------- -------------- 135``` 136 137list_event Return field description: 138 139| Field | **Description** | 140|----------------|----------------------------------| 141| event | Event set name | 142| set | The current event in the event set | 143| suspend thread | The number of threads waiting for an event in this event set | 144 145## Display Mutex Status 146 147Use the `list_mutex` command to display all mutex information in the system, including the mutex name, the owner of the mutex, and the number of nestings the owner holds on the mutex. 148 149```c 150msh />list_mutex 151mutex owner hold suspend thread 152-------- -------- ---- -------------- 153fat0 (NULL) 0000 0 154sal_lock (NULL) 0000 0 155``` 156 157list_mutex Return field description: 158 159| **Field** | **Description** | 160|----------------|------------------------------------| 161| mutxe | Mutex name | 162| owner | The thread currently holding the mutex | 163| hold | The number of times the holder is nested on this mutex | 164| suspend thread | The number of threads waiting for this mutex | 165 166## Display Mailbox Status 167 168Use the `list_mailbox` command to display all mailbox information in the system, including the mailbox name, the number of messages in the mailbox, and the maximum number of messages the mailbox can hold. 169 170```c 171msh />list_mailbox 172mailbox entry size suspend thread 173-------- ---- ---- -------------- 174etxmb 0000 0008 1:etx 175erxmb 0000 0008 1:erx 176``` 177 178list_mailbox Return field description: 179 180| Field | **Description** | 181|----------------|----------------------------| 182| mailbox | Mailbox name | 183| entry | The number of messages included in the mailbox | 184| size | The maximum number of messages a mailbox can hold | 185| suspend thread | The number of threads waiting for this mailbox | 186 187## Display Message Queue Status 188 189Use the `list_msgqueue` command to display all message queue information in the system, including the name of the message queue, the number of messages it contains, and the number of threads waiting for this message queue. 190 191```c 192msh />list_msgqueue 193msgqueue entry suspend thread 194-------- ---- -------------- 195``` 196 197list_msgqueue Return field description: 198 199| Field | **Description** | 200|----------------|----------------------------| 201| msgqueue | Message queue name | 202| entry | The number of messages currently included in the message queue | 203| suspend thread | Number of threads waiting for this message queue | 204 205## Display Memory Pool Status 206 207Use the `list_mempool` command to display all the memory pool information in the system, including the name of the memory pool, the size of the memory pool, and the maximum memory size used. 208 209```c 210msh />list_mempool 211mempool block total free suspend thread 212------- ---- ---- ---- -------------- 213signal 0012 0032 0032 0 214``` 215 216list_mempool Return field description: 217 218| Field | **Description** | 219|----------------|--------------------| 220| mempool | Memory pool name | 221| block | Memory block size | 222| total | Total memory block | 223| free | Free memory block | 224| suspend thread | The number of threads waiting for this memory pool | 225 226## Display Timer Status 227 228Use the `list_timer` command to display all the timer information in the system, including the name of the timer, whether it is the periodic timer, and the number of beats of the timer timeout. 229 230```c 231msh />list_timer 232timer periodic timeout flag 233-------- ---------- ---------- ----------- 234tshell 0x00000000 0x00000000 deactivated 235tidle 0x00000000 0x00000000 deactivated 236timer 0x00000000 0x00000000 deactivated 237``` 238 239list_timer Return field description: 240 241| Field | **Description** | 242|----------|--------------------------------| 243| timer | Timer name | 244| periodic | Whether the timer is periodic | 245| timeout | The number of beats when the timer expires | 246| flag | The state of the timer, activated indicates active, and deactivated indicates inactive | 247 248## Display Device Status 249 250Use the `list_device` command to display all device information in the system, including the device name, device type, and the number of times the device was opened. 251 252```c 253msh />list_device 254device type ref count 255------ ----------------- ---------- 256e0 Network Interface 0 257uart0 Character Device 2 258``` 259 260list_device Return field description: 261 262| Field | Description | 263|-----------|----------------| 264| device | Device name | 265| type | Device type | 266| ref count | The number of times the device was opened | 267 268## Display Dynamic Memory Status 269 270Use the `free` command to display all memory information in the system. 271 272```c 273msh />free 274total memory: 7669836 275used memory : 15240 276maximum allocated memory: 18520 277``` 278 279free Return field description: 280 281| Field | Description | 282|--------------------------|------------------| 283| total memory | Total memory size | 284| used memory | Used memory size | 285| maximum allocated memory | Maximum allocated memory | 286 287# Custom FinSH Command 288 289In addition to the commands that come with FinSH, FinSH also provides multiple macro interfaces to export custom commands. The exported commands can be executed directly in FinSH. 290 291## Custom msh Command 292 293The custom msh command can be run in msh mode. To export a command to msh mode, you can use the following macro interface: 294 295``` 296MSH_CMD_EXPORT(name, desc); 297``` 298 299|**Parameter**|**Description** | 300|----------|----------------| 301| name | The command to export | 302| desc | Description of the export command | 303 304This command can export commands with parameters, or export commands without parameters. When exporting a parameterless command, the input parameter of the function is void. The example is as follows: 305 306```c 307void hello(void) 308{ 309 rt_kprintf("hello RT-Thread!\n"); 310} 311 312MSH_CMD_EXPORT(hello , say hello to RT-Thread); 313``` 314 315When exporting a command with parameters, the function's input parameters are `int argc` and `char**argv`. Argc represents the number of arguments, and argv represents a pointer to a command-line argument string pointer array. An example of exporting a parameter command is as follows: 316 317```c 318static void atcmd(int argc, char**argv) 319{ 320 …… 321} 322 323MSH_CMD_EXPORT(atcmd, atcmd sample: atcmd <server|client>); 324``` 325 326## Custom C-Style Commands and Variables 327 328Export custom commands to C-Style mode can use the following interface: 329 330``` 331FINSH_FUNCTION_EXPORT(name, desc); 332``` 333 334|**Parameter**| **Description** | 335|----------|----------------| 336| name | The command to export | 337| desc | Description of the export command | 338 339The following example defines a `hello` function and exports it as a command in C-Style mode: 340 341```c 342void hello(void) 343{ 344 rt_kprintf("hello RT-Thread!\n"); 345} 346 347FINSH_FUNCTION_EXPORT(hello , say hello to RT-Thread); 348``` 349 350In a similar way, you can also export a variable that can be accessed through the following interface: 351 352``` 353FINSH_VAR_EXPORT(name, type, desc); 354``` 355 356| Parameter | **Description** | 357|----------|----------------| 358| name | The variable to be exported | 359| type | Type of variable | 360| desc | Description of the exported variable | 361 362The following example defines a `dummy` variable and exports it to a variable command in C-Style mode.: 363 364```c 365static int dummy = 0; 366FINSH_VAR_EXPORT(dummy, finsh_type_int, dummy variable for finsh) 367``` 368## Custom Command Rename 369 370The function name length of FinSH is limited. It is controlled by the macro definition `FINSH_NAME_MAX` in `finsh.h`. The default is 16 bytes, which means that the FinSH command will not exceed 16 bytes in length. There is a potential problem here: when a function name is longer than FINSH_NAME_MAX, after using FINSH_FUNCTION_EXPORT to export the function to the command table, the full function name is seen in the FinSH symbol table, but a full node execution will result in a *null node* error. This is because although the full function name is displayed, in fact FinSH saves the first 16 bytes as a command. Too many inputs will result in the command not being found correctly. In this case, you can use `FINSH_FUNCTION_EXPORT_ALIAS` to re-export the command name. 371 372``` 373FINSH_FUNCTION_EXPORT_ALIAS(name, alias, desc); 374``` 375 376| Parameter | Description | 377|----------|-------------------------| 378| name | The command to export | 379| alias | The name that is displayed when exporting to FinSH | 380| desc | Description of the export command | 381 382The command can be exported to msh mode by adding `__cmd_` to the renamed command name. Otherwise, the command will be exported to C-Style mode. The following example defines a `hello` function and renames it to `ho` and exports it to a command in C-Style mode. 383 384```c 385void hello(void) 386{ 387 rt_kprintf("hello RT-Thread!\n"); 388} 389 390FINSH_FUNCTION_EXPORT_ALIAS(hello , ho, say hello to RT-Thread); 391``` 392# FinSH Function Configuration 393 394The FinSH function can be cropped, and the macro configuration options are defined in the rtconfig.h file. The specific configuration items are shown in the following table. 395 396| **Macro Definition** | **Value Type** | Description | Default | 397|-----------------------------------|----------------|------------------------------------------------------------|---------| 398| `#define RT_USING_FINSH` | None | Enable FinSH | on | 399| `#define FINSH_THREAD_NAME` | String | FinSH thread name | "tshell"| 400| `#define FINSH_USING_HISTORY` | None | Turn on historical traceback | on | 401| `#define FINSH_HISTORY_LINES` | Integer type | Number of historical command lines that can be traced back | 5 | 402| `#define FINSH_USING_SYMTAB` | None | Symbol table can be used in FinSH | on | 403| `#define FINSH_USING_DESCRIPTION` | None | Add a description to each FinSH symbol | on | 404| `#define FINSH_USING_MSH` | None | Enable msh mode | on | 405| `#define FINSH_USING_MSH_ONLY` | None | Use only msh mode | on | 406| `#define FINSH_ARG_MAX` | Integer type | Maximum number of input parameters | 10 | 407| `#define FINSH_USING_AUTH` | None | Enable permission verification | off | 408| `#define FINSH_DEFAULT_PASSWORD` | String | Authority verification password | off | 409 410The reference configuration example in rtconfig.h is as follows, and can be configured according to actual functional requirements. 411 412```c 413/* Open FinSH */ 414#define RT_USING_FINSH 415 416/* Define the thread name as tshell */ 417#define FINSH_THREAD_NAME "tshell" 418 419/* Open history command */ 420#define FINSH_USING_HISTORY 421/* Record 5 lines of history commands */ 422#define FINSH_HISTORY_LINES 5 423 424/* Enable the use of symbol table */ 425#define FINSH_USING_SYMTAB 426/* Turn on description */ 427#define FINSH_USING_DESCRIPTION 428 429/* Define FinSH thread priority to 20 */ 430#define FINSH_THREAD_PRIORITY 20 431/* Define the stack size of the FinSH thread to be 4KB */ 432#define FINSH_THREAD_STACK_SIZE 4096 433/* Define the command character length to 80 bytes */ 434#define FINSH_CMD_SIZE 80 435 436/* Open msh function */ 437#define FINSH_USING_MSH 438/* Use msh function by default */ 439#define FINSH_USING_MSH_DEFAULT 440/* The maximum number of input parameters is 10 */ 441#define FINSH_ARG_MAX 10 442``` 443 444# FinSH Application Examples 445 446## Examples of msh Command without Arguments 447 448This section demonstrates how to export a custom command to msh. The sample code is as follows, the hello function is created in the code, and the `hello` function can be exported to the FinSH command list via the `MSH_CMD_EXPORT` command. 449 450```c 451#include <rtthread.h> 452 453void hello(void) 454{ 455 rt_kprintf("hello RT-Thread!\n"); 456} 457 458MSH_CMD_EXPORT(hello , say hello to RT-Thread); 459``` 460 461Once the system is up and running, press the tab key in the FinSH console to see the exported command: 462 463```c 464msh /> 465RT-Thread shell commands: 466hello - say hello to RT-Thread 467version - show RT-Thread version information 468list_thread - list thread 469…… 470``` 471 472Run the `hello` command and the results are as follows: 473 474```c 475msh />hello 476hello RT_Thread! 477msh /> 478``` 479 480## Example of msh Command with Parameters 481 482This section demonstrates how to export a custom command with parameters to FinSH. The sample code is as follows, the `atcmd()` function is created in the code, and the `atcmd()` function can be exported to the msh command list via the MSH_CMD_EXPORT command. 483 484```c 485#include <rtthread.h> 486 487static void atcmd(int argc, char**argv) 488{ 489 if (argc < 2) 490 { 491 rt_kprintf("Please input'atcmd <server|client>'\n"); 492 return; 493 } 494 495 if (!rt_strcmp(argv[1], "server")) 496 { 497 rt_kprintf("AT server!\n"); 498 } 499 else if (!rt_strcmp(argv[1], "client")) 500 { 501 rt_kprintf("AT client!\n"); 502 } 503 else 504 { 505 rt_kprintf("Please input'atcmd <server|client>'\n"); 506 } 507} 508 509MSH_CMD_EXPORT(atcmd, atcmd sample: atcmd <server|client>); 510``` 511 512Once the system is running, press the Tab key in the FinSH console to see the exported command: 513 514```c 515msh /> 516RT-Thread shell commands: 517hello - say hello to RT-Thread 518atcmd - atcmd sample: atcmd <server|client> 519version - show RT-Thread version information 520list_thread - list thread 521…… 522``` 523 524Run the `atcmd` command and the result is as follows: 525 526```c 527msh />atcmd 528Please input 'atcmd <server|client>' 529msh /> 530``` 531 532Run the `atcmd server` command and the result is as follows: 533 534```c 535msh />atcmd server 536AT server! 537msh /> 538``` 539 540Run the `atcmd client` command and the result is as follows: 541 542```c 543msh />atcmd client 544AT client! 545msh /> 546``` 547 548# FinSH Porting 549 550FinSH is written entirely in ANSI C and has excellent portability; it has a small memory footprint, and FinSH will not dynamically request memory if you do not use the functions described in the previous section to dynamically add symbols to FinSH. The FinSH source is located in the `components/finsh` directory. Porting FinSH requires attention to the following aspects: 551 552* FinSH thread: 553 554Each command execution is done in the context of a FinSH thread (that is, a tshell thread). When the RT_USING_FINSH macro is defined, the FinSH thread can be initialized by calling `finsh_system_init()` in the initialization thread. In RT-Thread 1.2.0 and later, you don't have to use the `finsh_set_device(const char* device_name)` function to explicitly specify the device to be used. Instead, the `rt_console_get_device()` function is called automatically to use the console device (The `finsh_set_device(const char* device_name)` must be used in 1.1.x and below to specify the device used by FinSH. The FinSH thread is created in the function `finsh_system_init()` function, which will wait for the rx_sem semaphore. 555 556* FinSH output: 557 558The output of FinSH depends on the output of the system and relies on the `rt_kprintf()` output in RT-Thread. In the startup function `rt_hw_board_init()`, the `rt_console_set_device(const char* name)` function sets the FinSH printout device. 559 560* FinSH input: 561 562After the rin_sem semaphore is obtained, the FinSH thread calls the `rt_device_read()` function to obtain a character from the device (select serial device) and then process it. So the migration of FinSH requires the implementation of the `rt_device_read()` function. The release of the rx_sem semaphore completes the input notification to the FinSH thread by calling the `rx_indicate()` function. The usual process is that when the serial port receive interrupt occurs (that is, the serial port has input character), the interrupt service routine calls the `rx_indicate()` function to notify the FinSH thread that there is input, and then the FinSH thread obtains the serial port input and finally performs the corresponding command processing. 563