文章目錄
- 3. FINSH模塊
- 3.1MSH
- 3.1.1初始化
- 3.1.1.1FSymtab段
- 3.1.1.2 宏
- 3.1.2遍歷FINSH命令
- 3.1.3TAB補全實現
- 3.1.3.1 `msh_auto_complete`
- 3.1.3.2 `msh_opt_auto_complete`
- 3.1.4 TAB 子選項自動補全
- 3.2 SHELL
- 3.2.1 `finsh_system_init`分配finsh結構體使用內存
- 3.2.2 `finsh_thread_entry`
- 3.2.3 歷史命令顯示
- 3.2.4 MSH命令執行
- 3.3 cmd&msh_parse&&msh_file
3. FINSH模塊
https://github.com/wdfk-prog/RT-Thread-Study
3.1MSH
3.1.1初始化
- 根據鏈接腳本指明FINSH使用內存空間
_syscall_table_begin
_syscall_table_end
的地址
3.1.1.1FSymtab段
. = ALIGN(4);__fsymtab_start = .;KEEP(*(FSymTab))__fsymtab_end = .;
__fsymtab_start
和__fsymtab_end
用于指明finsh使用內存- FSymTab用于存放所有注冊命令的結構體
struct finsh_syscall
,包括命令名稱,命令選項,命令描述,命令函數執行地址信息
3.1.1.2 宏
/*** @ingroup msh** This macro exports a command to module shell.** @param command is the name of the command.* @param desc is the description of the command, which will show in help list.* @param opt This is an option, enter any content to enable option completion*/
/* MSH_CMD_EXPORT(command, desc) or MSH_CMD_EXPORT(command, desc, opt) */
#define MSH_CMD_EXPORT(...) \__MSH_GET_MACRO(__VA_ARGS__, _MSH_FUNCTION_CMD2_OPT, \_MSH_FUNCTION_CMD2)(__VA_ARGS__)#define __MSH_GET_MACRO(_1, _2, _3, _FUN, ...) _FUN#define _MSH_FUNCTION_CMD2(a0, a1) \MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, 0)#define _MSH_FUNCTION_CMD2_OPT(a0, a1, a2) \MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, a0##_msh_options)#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \const char __fsym_##cmd##_name[] rt_section(".rodata.name") = #cmd; \const char __fsym_##cmd##_desc[] rt_section(".rodata.name") = #desc; \rt_used const struct finsh_syscall __fsym_##cmd rt_section("FSymTab")= \{ \__fsym_##cmd##_name, \__fsym_##cmd##_desc, \(syscall_func)&name \};
- 宏過載語法,選擇2個參數使用
MSH_FUNCTION_CMD2
,_MSH_FUNCTION_CMD2
的desc為0;3個參數使用MSH_FUNCTION_CMD2_OPT
- 定義字符串成員,地址定義為.rodata.name;內容為#cmd;
const char __fsym_##cmd##_name[] rt_section(".rodata.name") = #cmd; \
const char __fsym_##cmd##_desc[] rt_section(".rodata.name") = #desc; \
__fsym_##cmd
存儲名稱,細節,掛鉤的函數指針地址
3.1.2遍歷FINSH命令
for (index = _syscall_table_begin;index < _syscall_table_end;FINSH_NEXT_SYSCALL(index)){}
3.1.3TAB補全實現
- 判斷輸入為
/t
- 將光標移動到行首;使用
/b
退格,一個個退回刪除之前的顯示字符 - 將命令首地址傳入
shell_auto_complete
- 計算偏移地址
shell_auto_complete
3.1.3.1 msh_auto_complete
- 首地址為
/0
,即無輸入任何字符串,直接TAB/t
,則調用msh_cmd
輸出所有支持的命令 - 匹配命令名字,并輸出命令
for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index)){/* skip finsh shell function */cmd_name = (const char *) index->name;if (strncmp(prefix, cmd_name, strlen(prefix)) == 0){if (min_length == 0){/* set name_ptr */name_ptr = cmd_name;/* set initial length */min_length = strlen(name_ptr);}length = str_common(name_ptr, cmd_name);if (length < min_length)min_length = length;rt_kprintf("%s\n", cmd_name);}}
- 輸出提示字符
msh />
與命令輸入的字符串
rt_kprintf("%s%s", FINSH_PROMPT, prefix);
- finsh_get_prompt輸出提示
#define FINSH_PROMPT finsh_get_prompt()finsh_prompt_custom 用于自定義替換默認提示
finsh_set_prompt("artpi@root");
3.1.3.2 msh_opt_auto_complete
argc = msh_get_argc(prefix, &opt_str);if (argc){opt = msh_get_cmd_opt(prefix);}else if (!msh_get_cmd(prefix, strlen(prefix)) && (' ' == prefix[strlen(prefix) - 1])){opt = msh_get_cmd_opt(prefix);}
msh_get_argc
獲取命令空格之后參數- 沒獲取到參數時,判斷
prefix
不是一個已知的命令,并且命令行字符串的最后一個字符是空格 msh_get_cmd_opt
獲取syscall_table
中是否有匹配的命令argc
為0,輸出msh_opt_help
所有的命令?msh_opt_complete
與msh_auto_complete
作用相同
3.1.4 TAB 子選項自動補全
- msh_opt_auto_complete
- 使用完成命令注冊
#define CMD_OPTIONS_STATEMENT(command) static struct msh_cmd_opt command##_msh_options[];
#define CMD_OPTIONS_NODE_START(command) static struct msh_cmd_opt command##_msh_options[] = {
#define CMD_OPTIONS_NODE(_id, _name, _des) {.id = _id, .name = #_name, .des = #_des},
#define CMD_OPTIONS_NODE_END {0},};CMD_OPTIONS_NODE_START(vref_temp_get)
CMD_OPTIONS_NODE(1, write, tx data)
CMD_OPTIONS_NODE(2, irq, irq list)
CMD_OPTIONS_NODE(3, speed-test, eth physical speed test)
CMD_OPTIONS_NODE_END
3.2 SHELL
3.2.1 finsh_system_init
分配finsh結構體使用內存
- 創建
finsh_thread_entry
線程 - 創建信號量,用于阻塞接字符串;信號量由控制臺設備對象解除
- 設置提示模式
- INIT_APP_EXPORT中調用
3.2.2 finsh_thread_entry
-
獲取控制臺設備對象
-
獲取控制臺密碼用于密碼確認
finsh_wait_auth
- 阻塞等待獲取密碼;密碼輸入顯示
*
- 敲入回車認為密碼輸入完成
- 進入密碼驗證判斷;失敗線程阻塞等待2S再次獲取輸入字符
- 阻塞等待獲取密碼;密碼輸入顯示
-
進入控制臺線程
finsh_getchar
rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER);
等待信號量釋放finsh_rx_ind
函數中釋放信號量
- handle control key判斷
/** handle control key* up key : 0x1b 0x5b 0x41* down key: 0x1b 0x5b 0x42* right key:0x1b 0x5b 0x43* left key: 0x1b 0x5b 0x44*/
- 上下鍵:歷史命令顯示
- 左右鍵:移動當前光標
- tab鍵 補全命令
- 刪除鍵:刪除
- 回車鍵:執行msh命令
-
設置控制臺設備模式
/*** @ingroup finsh** This function sets the input device of finsh shell.** @param device_name the name of new input device.*/
void finsh_set_device(const char *device_name)
{rt_device_t dev = RT_NULL;RT_ASSERT(shell != RT_NULL);dev = rt_device_find(device_name);if (dev == RT_NULL){rt_kprintf("finsh: can not find device: %s\n", device_name);return;}/* check whether it's a same device */if (dev == shell->device) return;/* open this device and set the new device in finsh shell */if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | \RT_DEVICE_FLAG_STREAM) == RT_EOK){if (shell->device != RT_NULL){/* close old finsh device */rt_device_close(shell->device);rt_device_set_rx_indicate(shell->device, RT_NULL);}/* clear line buffer before switch to new device */rt_memset(shell->line, 0, sizeof(shell->line));shell->line_curpos = shell->line_position = 0;shell->device = dev;rt_device_set_rx_indicate(dev, finsh_rx_ind);}
}
3.2.3 歷史命令顯示
- 回車存入歷史命令
shell_push_history
- 上下鍵顯示歷史命令
shell_handle_history
3.2.4 MSH命令執行
3.3 cmd&msh_parse&&msh_file
- 一些系統命令的輸出
- 一些共用的解析
- 文件系統的命令支持