FinSH Console
Last updated
Last updated
Assoc. Prof. Wiroon Sriborrirux, Founder of Advance Innovation Center (AIC) and Bangsaen Design House (BDH), Electrical Engineering Department, Faculty of Engineering, Burapha University
In the early days of computer development, before the emergence of graphics systems, there was no mouse, or even keyboard. How did people interact with computers at that time? The earliest computers used punched paper strips to input commands to the computer and write programs. Later, as computers continued to develop, monitors and keyboards became standard configurations of computers, but the operating system at that time did not support graphical interfaces. Computer pioneers developed a software that accepted commands entered by users, interpreted them, passed them to the operating system, and returned the results of the operating system's execution to the user. This program was like a shell wrapped around the outside of the operating system, so it was called a shell.
Embedded devices usually need to connect the development board to the PC for communication. Common connection methods include: serial port, USB, Ethernet, Wi-Fi, etc. A flexible shell should also support working on multiple connection methods. With a shell, it is like building a bridge of communication between the developer and the computer. The developer can easily obtain the system operation status and control the system operation through commands. Especially in the debugging stage, with a shell, the developer can not only locate the problem faster, but also use the shell to call the test function, change the parameters of the test function, reduce the number of code burning times, and shorten the project development time.
FinSH is the command line component (shell) of RT-Thread, which was born 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 our own commands to FinSH.
FinSH is the command line component of RT-Thread, which provides a set of operation interfaces for users to call in the command line, mainly used for debugging or viewing system information. It can communicate with the PC using serial port/Ethernet/USB, etc. The hardware topology is shown in the figure below:
The user inputs commands on the control terminal, and the control terminal transmits the commands to FinSH in the device through 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, execute the function and output a response. The response is returned through the original path and the result is displayed on the control terminal.
When the serial port is used to connect the device to the control terminal, the execution process of the FinSH command is as shown in the figure below:
FinSH supports permission verification function. The system will perform permission verification after startup. Only when the permission verification is passed will the FinSH function be enabled to improve the security of system input.
FinSH supports functions such as auto-completion and viewing historical commands. These functions can be easily used through the keys on the keyboard. The keys supported by FinSH are shown in the following table:
button
Functional Description
Tab key
If you press the Tab key without entering any characters, all commands supported by the current system will be printed. If you press the Tab key after entering some characters, it will search for matching commands and complete the command according to the file name in the current directory of the file system. You can continue to enter and complete the command multiple times.
↑↓ keys
Scroll up and down through the history of recently entered commands
Backspace key
Delete
←→ key
Move the cursor left or right
FinSH supports command line mode, which is also called msh (module shell). In msh mode, FinSH is executed in the same way as traditional shells (dos/bash). For example, you can cd /
switch the directory to the root directory through the command.
msh parses the input characters and decomposes them into commands and parameters separated by spaces. The command execution format is as follows:
command [arg1] [arg2] [...]
The command can be either a built-in command of RT-Thread or an executable file.
Some FinSH commands are built-in by default in RT-Thread. Enter help in FinSH and press Enter or press the Tab key to print all the commands supported by the current system.
In msh mode, press the Tab key to list all currently supported commands. The number of default commands is not fixed, and each component of RT-Thread will output some commands to FinSH. For example, when the DFS component is turned on, commands such as ls, cp, and cd will be added to FinSH to facilitate debugging by developers.
The following are all currently supported commands for displaying RT-Thread kernel status information, which are printed out after pressing the Tab key. The command name is on the left and the description of the command is on the right:
Here is a list of field information returned after entering common commands, which helps developers understand the returned information content.
Use the ps or list thread command to list all thread information in the system, including thread priority, status, maximum stack usage, etc.
list thread Returns the following fields:
Fields
describe
thread
The name of the thread
pri
Thread priority
status
The current state of the thread
sp
The thread's current stack position
stack size
Thread stack size
max used
Maximum stack position used in thread history
left tick
The number of ticks remaining for the thread to run
error
Thread error code
Use the list sem command to display all semaphore information in the system, including the semaphore name, semaphore value, and the number of threads waiting for the semaphore.
list sem returns a description of the fields:
Fields
describe
semaphore
The name of the semaphore
v
The current value of the semaphore
suspend thread
The number of threads waiting for this semaphore
Use the list event command to display all event information in the system, including the event name, event value, and the number of threads waiting for this event.
list event returns a description of the fields:
Fields
describe
event
The name of the event set
set
The current event in the event set
suspend thread
The number of threads waiting for events in this event set
Use 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.
list mutex returns a description of the fields:
Fields
describe
mutxe
The name of the mutex
owner
The thread currently holding the mutex
hold
The number of times the holder has nested holds on this mutex
suspend thread
The number of threads waiting for this mutex
priority
Holds the thread priority
Use the list mailbox command to display all mailbox information in the system, including the mailbox name, the number of emails in the mailbox, and the maximum number of emails that the mailbox can hold.
list mailbox Returns a description of the fields:
Fields
describe
mailbox
Name of the mailbox
entry
The number of messages contained in the mailbox
size
The maximum number of messages that a mailbox can hold
suspend thread
The number of threads waiting for this mailbox
Use the list msgqueue command to display all message queue information in the system, including the name of the message queue, the number of messages contained in it, and the number of threads waiting for this message queue.
list msgqueue returns a description of the fields:
Fields
describe
msgqueue
The name of the message queue
entry
The number of messages currently contained in the message queue
suspend thread
The number of threads waiting for this message queue
Use the list mempool command to display all memory pool information in the system, including the name of the memory pool, the size of the memory pool, and the maximum used memory size.
List mempool returns a description of the fields:
Fields
describe
mempool
Memory pool name
block
Memory block size
total
Total memory blocks
free
Free memory blocks
suspend thread
The number of threads waiting for this memory pool
Use the list timer command to display information about all timers in the system, including the name of the timer, whether it is a periodic timer, and the number of beats for the timer to time out.
list timer returns a description of the fields:
Fields
describe
timer
Timer name
periodic
Is the timer periodic?
timeout
The number of ticks when the timer times out
activated
The state of the timer, activated means active, deactivated means inactive
mode
Timer type, one shot means one-shot timing, periodic means periodic timing
Current tick indicates the current system tick number.
Use the list device command to display all device information in the system, including the device name, device type, and number of times the device has been opened.
list device Returns the following fields:
Fields
describe
device
Name of the device
type
Type of device
ref count
Number of times the device has been opened
Use the free command to display all memory information in the system.
Description of the fields returned by free:
Fields
describe
total memory
Total memory size
used memory
The amount of memory used
maximum allocated memory
Maximum allocated memory
available
Available memory size
In 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.
Customized msh commands can be run in msh mode. To export a command to msh mode, you can use the following macro interface:
MSH_CMD_EXPORT(name, desc);
parameter
describe
name
Commands to export
desc
Description of the export command
This command can export commands with parameters or without parameters. When exporting commands without parameters, the function input parameter is void, as shown in the following example:
When exporting a command with parameters, the function input parameters are int argc
and char**argv
. argc indicates the number of parameters, and argv indicates the pointer to the array of command line parameter string pointers. The following is an example of exporting a command with parameters:
There is a certain limit on the length of FinSH function names, which is controlled by the macro definition FINSH_NAME_MAX in finsh.h. The default is 16 bytes, which means that the length of FinSH commands will not exceed 16 bytes. 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 complete function name can be seen in the FinSH symbol table, but a null node error will occur when the complete input is executed. This is because although the complete function name is displayed, the first 16 bytes are actually saved as commands in FinSH. Too much input will result in the command not being found correctly. At this time, FINSH_FUNCTION_EXPORT_ALIAS can be used to rename the exported command.
FINSH_FUNCTION_EXPORT_ALIAS(name, alias, desc);
parameter
describe
name
Commands to export
alias
The name displayed when exporting to FinSH
desc
Description of the export command
You can export the command to msh mode by adding before the renamed command name __cmd_
, otherwise, the command will be exported to C-Style mode. The following example defines a hello function, renames it to ho, and then exports it as a command in C-Style mode.
FinSH functions can be tailored. The macro configuration options are defined in the rtconfig.h file. The specific configuration items are shown in the following table.
Macro Definition
Value Type
describe
default value
#define RT_USING_FINSH
none
Enable FinSH
Open
#define FINSH_THREAD_NAME
String
The name of the FinSH thread
"tshell"
#define FINSH_USING_HISTORY
none
Enable the history backtracking function
Open
#define FINSH_HISTORY_LINES
Integer
The number of historical command lines that can be traced back
5
#define FINSH_USING_SYMTAB
none
Symbol tables can be used in FinSH
Open
#define FINSH_USING_DESCRIPTION
none
Add a description to each FinSH symbol
Open
#define FINSH_USING_MSH
none
Enable msh mode
Open
#define FINSH_ARG_MAX
Integer
Maximum number of input parameters
10
#define FINSH_USING_AUTH
none
Enable permission verification
closure
#define FINSH_DEFAULT_PASSWORD
String
Permission verification password
closure
The reference configuration example in rtconfig.h is shown below, which can be configured according to actual functional requirements.
This section will demonstrate how to export a custom command to msh. The sample code is shown below. The hello function is created in the code, and then the hello function can be exported to the FinSH command list through the MSH_CMD_EXPORT command.
After the system is running, press the tab key in the FinSH console to see the exported commands:
Run the hello command, and the results are as follows:
This section will demonstrate how to export a custom command with parameters to FinSH. The sample code is shown below. atcmd()
A function is created in the code, and then the function can be atcmd()
exported to the msh command list through the MSH_CMD_EXPORT command.
After the system is running, press the tab key in the FinSH console to see the exported commands:
Run the atcmd command, and the results are as follows:
Run the atcmd server command. The results are as follows:
Run the atcmd client command. The results are as follows:
FinSH is written entirely in ANSI C and has excellent portability. It takes up little memory. If you do not use the function method introduced in the previous chapter to dynamically add symbols to FinSH, FinSH will not dynamically request memory. The FinSH source code is located in components/finsh
the directory. When porting FinSH, you need to pay attention to the following aspects:
FinSH Thread:
Each command execution is completed in the context of the FinSH thread (i.e., tshell thread). When the RT_USING_FINSH macro is defined, finsh_system_init() can be called in the initialization thread to initialize the FinSH thread. In versions after RT-Thread 1.2.0, you do not need to use finsh_set_device(const char* device_name)
the function to explicitly specify the device to be used, but will automatically call rt_console_get_device()
the function to use the console device (RT-Thread 1.1.x and below must use to finsh_set_device(const char* device_name)
specify the device used by FinSH). The FinSH thread finsh_system_init()
is created in the function function, and it will always wait for the rx_sem semaphore.
Output of FinSH:
The output of FinSH depends on the output of the system, and in RT-Thread it depends on rt_kprintf()
the output. In the startup function rt_hw_board_init()
, rt_console_set_device(const char* name)
the function sets the print output device of FinSH.
FinSH input:
After the FinSH thread obtains the rx_sem semaphore, it calls rt_device_read()
the function to obtain a character from the device (select the serial port device) and then processes it. Therefore, the porting of FinSH requires rt_device_read()
the implementation of the function. The release of the rx_sem semaphore rx_indicate()
completes the input notification to the FinSH thread by calling the function. The usual process is that when the serial port receive interrupt occurs (that is, the serial port has input), the receiving interrupt service routine calls rx_indicate()
the 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.