From c23f3288e972079586659f2c002595842633678f Mon Sep 17 00:00:00 2001 From: hqm <13720409820@163.com> Date: Fri, 12 Aug 2022 22:42:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=EF=BC=9A=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E7=B1=BB=E4=BC=BClinux=E7=9A=84=E9=87=8D=E5=AE=9A?= =?UTF-8?q?=E5=90=91=E7=AC=A6=E5=8F=B7=EF=BC=8C=E6=94=AF=E6=8C=81xcmd=5Fpr?= =?UTF-8?q?int=E5=88=B0=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 55 ++++-- extensions/fs_cmds/FatFs/source/ffconf.h | 6 +- extensions/fs_cmds/fatfs_port.c | 58 ++++++- extensions/fs_cmds/fatfs_port.h | 8 +- extensions/fs_cmds/fs_cmds.c | 210 ++++++++++++----------- src/xcmd.c | 62 ++++++- 6 files changed, 274 insertions(+), 125 deletions(-) diff --git a/README.md b/README.md index 07dd70d..19b3369 100755 --- a/README.md +++ b/README.md @@ -1,40 +1,53 @@ # xcmd #### 效果展示 + ![输入图片说明](https://images.gitee.com/uploads/images/2021/0922/220957_66faa768_1680380.gif "演示1.gif") #### 介绍 + xcmd是一款单片机命令行工具,移植十分方便,并且对flash与ram占用很小,旨在为单片机提供一个能够快速搭建且占用资源很小的命令行工具,可以大大加快单片机程序调试工作,它有一下几个优点。 + 1. **移植十分简单** -2. **资源占用约8K rom 1K ram** -3. **支持历史记录** +2. **资源占用很小** +3. **支持历史记录** 4. **支持命令自动补全** -5. **支持注册快捷键** -5. **支持`xcmd_cmd_register()/xcmd_key_register`方法注册命令或按键** -5. **支持`XCMD_EXPORT_CMD()/XCMD_EXPORT_KEY()`方法直接导出命令或按键,不需要额外运行注册函数** +5. **支持注册快捷键** +6. **支持 `xcmd_cmd_register()/xcmd_key_register`方法注册命令或按键** +7. **支持 `XCMD_EXPORT_CMD()/XCMD_EXPORT_KEY()`方法直接导出命令或按键,不需要额外运行注册函数** + #### 支持的平台 + 1. linux 2. arduino 3. stm32 4. esp32 5. qemu-stm32 + #### 测试过的串口软件 + 2. (win/linux推荐)putty 3. (win推荐)MobaXterm -5. (linux端推荐)cu -1. SecureCRT:请设置成Xterm模式 -4. Xshell -6. nc(支持性很差) -7. minicom(支持性很差) +4. (linux端推荐)cu +5. SecureCRT:请设置成Xterm模式 +6. Xshell +7. nc(支持性很差) +8. minicom(支持性很差) + #### 支持的扩展功能 + 1. 类linux风格的快捷键:ctr+left、ctr+right、ctr+a、ctr+e、ctr+u、ctr+k、ctr+l快捷键 2. 支持字体、背景颜色显示 -3. 支持类linux的文件操作(Fatfs文件系统):ls、cd、rm、df、mv、mkdir、touch、read、write +3. 支持类linux的文件操作(Fatfs文件系统):ls、cd、rm、df、mv、mkdir、touch、rd、wr、cat 4. 支持基于socket的udp server、udp client测试程序 + #### 移植 + - 移植十分简单,可在example中查看各平台移植结果 + 1. 在初始化的时候提供字符输入输出函数即可 2. 从example中拷贝一个xcmd_confg.h到自己的项目 + ```C /* 例如移植到Arduino平台 */ int cmd_get_char(uint8_t *ch) @@ -62,14 +75,17 @@ void setup() { } void loop() { - + xcmd_task(); } ``` + #### 配置 + 配置xcmd_config.h **注意**: 如果不知道如何修改连接脚本,建议不要使能ENABLE_XCMD_EXPORT。不使能ENABLE_XCMD_EXPORT的情况下有更好的兼容性移植更加简单 + ```C #define XCMD_LINE_MAX_LENGTH (128) /* 命令行支持的最大字符数 */ #define XCMD_HISTORY_MAX_NUM (16) /* 支持的历史记录个数, 这个参数对内存的影响很大,建议arduino设置为0,0为不支持 */ @@ -78,8 +94,11 @@ void loop() { // #define XCMD_DEFAULT_PROMPT_CLOLR TX_GREEN /* 提示符颜色 */ // #define ENABLE_XCMD_EXPORT /* 需要修改lds,启用后支持XCMD_EXPORT_CMD和XCMD_EXPORT_KEY方法导出命令 */ ``` + #### 使用说明 + ##### xcmd_register()方法注册自定义命令 + ```C static int cmd_echo(int argc, char* argv[]) { @@ -100,7 +119,9 @@ void test_cmd_init(void) xcmd_cmd_register(cmds, sizeof(cmds)/sizeof(xcmd_t)); } ``` + ##### xcmd_key_register() 方法注册自定义快捷键 + ```C int cmd_ctr_a(void* pv) { @@ -117,7 +138,9 @@ void test_keys_init(void) xcmd_key_register(user_keys, sizeof(user_keys)/sizeof(xcmd_key_t)); } ``` -##### XCMD_EXPORT_CMD()方法注册自定义命令,需要使能宏ENABLE_XCMD_EXPORT并修改lds,见`example/stm32/qemu/demos/main.ld` + +##### XCMD_EXPORT_CMD()方法注册自定义命令,需要使能宏ENABLE_XCMD_EXPORT并修改lds,见 `example/stm32/qemu/demos/main.ld` + ```C static int cmd_echo(int argc, char* argv[]) { @@ -129,7 +152,9 @@ static int cmd_echo(int argc, char* argv[]) } XCMD_EXPORT_CMD(echo, cmd_echo, "print anything") ``` -##### XCMD_EXPORT_KEY() 方法注册自定义快捷键, 需要使能宏ENABLE_XCMD_EXPORT并修改lds,见`example/stm32/qemu/demos/main.ld` + +##### XCMD_EXPORT_KEY() 方法注册自定义快捷键, 需要使能宏ENABLE_XCMD_EXPORT并修改lds,见 `example/stm32/qemu/demos/main.ld` + ```C int cmd_ctr_a(void* pv) { @@ -137,5 +162,7 @@ int cmd_ctr_a(void* pv) } XCMD_EXPORT_KEY(KEY_CTR_A, cmd_ctr_a, "ctr+a") ``` + #### 其他 + 流程图需要使用drawio来打开,可以使用vscode drawio的插件来打开 diff --git a/extensions/fs_cmds/FatFs/source/ffconf.h b/extensions/fs_cmds/FatFs/source/ffconf.h index 6f03527..003402f 100644 --- a/extensions/fs_cmds/FatFs/source/ffconf.h +++ b/extensions/fs_cmds/FatFs/source/ffconf.h @@ -170,8 +170,8 @@ /* Number of volumes (logical drives) to be used. (1-10) */ -#define FF_STR_VOLUME_ID 0 -#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +#define FF_STR_VOLUME_ID 1 +// #define FF_VOLUME_STRS "RAM","NAND" //,"CF","SD","SD2","USB","USB2","USB3" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each @@ -194,7 +194,7 @@ #define FF_MIN_SS 512 -#define FF_MAX_SS 512 +#define FF_MAX_SS 4096 /* This set of options configures the range of sector size to be supported. (512, / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk, but a larger value may be required for on-board flash memory and some diff --git a/extensions/fs_cmds/fatfs_port.c b/extensions/fs_cmds/fatfs_port.c index 39e8e83..e12cf26 100644 --- a/extensions/fs_cmds/fatfs_port.c +++ b/extensions/fs_cmds/fatfs_port.c @@ -11,21 +11,29 @@ static DiskIo_t * g_Disks[FF_VOLUMES] = {0}; -int f_disk_regist(DiskIo_t * disk, int id) +#if FF_STR_VOLUME_ID >= 1 +#ifndef FF_VOLUME_STRS +const char* VolumeStr[FF_VOLUMES] = {0}; +#else +static char * VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; +#endif +#endif + +int f_disk_regist(DiskIo_t * disk, const char* volume_name, int id) { - if(!disk) + if(!disk || !volume_name) { return -1; } - if(id<0) { for(int i=0; i= 1 + +#ifndef FF_VOLUME_STRS + +#if FF_STR_VOLUME_ID == 1 + snprintf(disk->disk_path, MAX_VOL_NAME_LEN, "%s:", volume_name); +#endif +#if FF_STR_VOLUME_ID == 2 + snprintf(disk->disk_path, MAX_VOL_NAME_LEN, "/%s/", volume_name); +#endif + VolumeStr[id] = volume_name; + +#else + +#if FF_STR_VOLUME_ID == 1 + snprintf(disk->disk_path, MAX_VOL_NAME_LEN, "%s:", VolumeStr[id]); +#endif +#if FF_STR_VOLUME_ID == 2 + snprintf(disk->disk_path, MAX_VOL_NAME_LEN, "/%s/", VolumeStr[id]); +#endif + +#endif + +#else + snprintf(disk->disk_path, MAX_VOL_NAME_LEN, "%d:", id); +#endif + return id; } DiskIo_t * f_disk_get(int id) @@ -48,3 +85,12 @@ DiskIo_t * f_disk_get(int id) } return NULL; } + +char * f_disk_path(int id) +{ + if(id < FF_VOLUMES) + { + return g_Disks[id]->disk_path; + } + return NULL; +} \ No newline at end of file diff --git a/extensions/fs_cmds/fatfs_port.h b/extensions/fs_cmds/fatfs_port.h index b97254e..c810a36 100644 --- a/extensions/fs_cmds/fatfs_port.h +++ b/extensions/fs_cmds/fatfs_port.h @@ -14,9 +14,11 @@ #include "diskio.h" #include +#define MAX_VOL_NAME_LEN (16) + typedef struct __DiskIo { - char * disk_name; + char disk_path[MAX_VOL_NAME_LEN]; DSTATUS (*disk_status)(void); DSTATUS (*disk_initialize)(void); DRESULT (*disk_read)(BYTE *buff, LBA_t sector, UINT count); @@ -24,7 +26,7 @@ typedef struct __DiskIo DRESULT (*disk_ioctl) (BYTE cmd, void *buff); }DiskIo_t; -int f_disk_regist(DiskIo_t * disk, int id); +int f_disk_regist(DiskIo_t * disk, const char* volume_name, int id); DiskIo_t * f_disk_get(int id); - +char * f_disk_path(int id); #endif \ No newline at end of file diff --git a/extensions/fs_cmds/fs_cmds.c b/extensions/fs_cmds/fs_cmds.c index de6de95..d8745f5 100644 --- a/extensions/fs_cmds/fs_cmds.c +++ b/extensions/fs_cmds/fs_cmds.c @@ -9,6 +9,7 @@ #include "fs_cmds.h" #include "xcmd.h" #include "ff.h" +#include "fatfs_port.h" #define RESAULT_TO_STR(r) resault_to_str_map[r] static char *resault_to_str_map[] = @@ -41,13 +42,13 @@ static FILINFO fno; #define HELP_DF ("Show Disk Info. Usage: df") #define HELP_LS ("List information about the FILEs. Usage: ls") #define HELP_CD ("Change the shell working directory. Usage: cd path") -#define HELP_READ ("Read FILE. Usage: read path") +#define HELP_CAT ("Read FILE. Usage: cat path") #define HELP_RM ("Delete FILE. Usage: rm [-r:dir] path") #define HELP_MV ("Move FILE. Usage: mv path") #define HELP_SYNC ("Sync Usage: sync") #define HELP_MKDIR ("Make DIR. Usage: mkdir path") #define HELP_TOUCH ("Create empty FILE. Usage: touch path") -#define HELP_WRITE ("Write str to FILE. Usage: Write [-a:append] path str") +#define HELP_WRITE ("Write str to FILE. Usage: wr string (>|>>) filename") static FRESULT scan_files( char *path /* Start node to be scanned (***also used as work area***) */ @@ -152,9 +153,10 @@ static FRESULT df(char* path, DWORD* totle_byte, DWORD* free_byte) #if FF_MAX_SS != FF_MIN_SS *totle_byte = tot_sect * fs->ssize; *free_byte = fre_sect * fs->ssize; - #endif + #else *totle_byte = tot_sect * FF_MAX_SS; *free_byte = fre_sect * FF_MAX_SS; + #endif } return res; } @@ -163,21 +165,23 @@ static int cmd_df(int argc, char* argv[]) { FRESULT res; DWORD fre_bytes, tot_bytes; - res = df("0:", &tot_bytes, &fre_bytes); - if (res != FR_OK) + char * disk_path; + for(int i=0; i= 2) - { - FRESULT res; - res = f_open(&fp, argv[1], FA_READ); - if (res != FR_OK) - { - xcmd_print("Failure:%s\r\n", RESAULT_TO_STR(res)); - return -1; - } - else - { - char buf[128]; - UINT br; - while (1) - { - res = f_read(&fp, buf, 128, &br); - if (res != FR_OK) - { - xcmd_print("Failure:%s\r\n", RESAULT_TO_STR(res)); - f_close(&fp); - return -1; - } - if (br == 0) - { - break; - } - for(UINT i=0; i= 2) { - append_flag = 1; - param_num = 4; - } - - FRESULT res = FR_INVALID_PARAMETER; - char *str = NULL; - if (argc >= param_num) - { - if (append_flag) - { - res = f_open(&fp, argv[2], FA_WRITE | FA_OPEN_APPEND); - str = argv[3]; - } - else - { - res = f_open(&fp, argv[1], FA_WRITE | FA_CREATE_ALWAYS); - str = argv[2]; - } - + FRESULT res; + res = f_open(&fp, argv[1], FA_READ); if (res != FR_OK) { - xcmd_print("Failure:%s", RESAULT_TO_STR(res)); + xcmd_print("Failure:%s\r\n", RESAULT_TO_STR(res)); return -1; } else { + char buf[128]; UINT br; - res = f_write(&fp, str, strlen(str), &br); - res = f_write(&fp, "\n", 1, &br); - f_close(&fp); - if (res != FR_OK) + while (1) { - xcmd_print("Failure:%s", RESAULT_TO_STR(res)); - return -1; + res = f_read(&fp, buf, 128, &br); + if (res != FR_OK) + { + xcmd_print("Failure:%s\r\n", RESAULT_TO_STR(res)); + f_close(&fp); + return -1; + } + if (br == 0) + { + break; + } + for(UINT i=0; i') + { + argc = i; + if(argv[i][1] == '>') + { + g_xcmder.io.write_fd = file_open(argv[i+1], 1, 1); + } + else + { + g_xcmder.io.write_fd = file_open(argv[i+1], 1, 0); + } + break; + } + } + return argc; +} + static int xcmd_cmd_match(int argc, char*argv[]) { uint8_t flag = 0; @@ -178,7 +226,10 @@ static int xcmd_cmd_match(int argc, char*argv[]) break; } } + argc = xcmd_redirected(argc, argv); ret = p->func(argc, argv); + file_close(g_xcmder.io.write_fd); + g_xcmder.io.write_fd = -1; break; } } @@ -310,6 +361,13 @@ static void xcmd_parser(uint8_t byte) void xcmd_put_str(const char *str) { + if(g_xcmder.io.write_fd != -1) + { + if(file_write(g_xcmder.io.write_fd, str) != -1) + { + return; + } + } for(uint16_t i=0; str[i]; i++) { g_xcmder.io.put_c(str[i]); @@ -648,6 +706,8 @@ void xcmd_init( int (*get_c)(uint8_t*), int (*put_c)(uint8_t)) { g_xcmder.io.get_c = get_c; g_xcmder.io.put_c = put_c; + g_xcmder.io.read_fd = -1; + g_xcmder.io.write_fd = -1; g_xcmder.parser.prompt = XCMD_DEFAULT_PROMPT; g_xcmder.parser.byte_num = 0;