更新: 新增类似linux的重定向符号,支持xcmd_print到文件
This commit is contained in:
parent
840076a741
commit
c23f3288e9
49
README.md
49
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**
|
||||
2. **资源占用很小**
|
||||
3. **支持历史记录**
|
||||
4. **支持命令自动补全**
|
||||
5. **支持注册快捷键**
|
||||
5. **支持`xcmd_cmd_register()/xcmd_key_register`方法注册命令或按键**
|
||||
5. **支持`XCMD_EXPORT_CMD()/XCMD_EXPORT_KEY()`方法直接导出命令或按键,不需要额外运行注册函数**
|
||||
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)
|
||||
|
@ -66,10 +79,13 @@ 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的插件来打开
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<FF_VOLUMES; i++)
|
||||
{
|
||||
if(!g_Disks[id])
|
||||
if(!g_Disks[i])
|
||||
{
|
||||
g_Disks[i] = disk;
|
||||
return i;
|
||||
id = i;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,10 +42,39 @@ int f_disk_regist(DiskIo_t * disk, int id)
|
|||
if((id < FF_VOLUMES) && !g_Disks[id])
|
||||
{
|
||||
g_Disks[id] = disk;
|
||||
return id;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
||||
ok:
|
||||
#if FF_STR_VOLUME_ID >= 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;
|
||||
}
|
|
@ -14,9 +14,11 @@
|
|||
#include "diskio.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#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
|
|
@ -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);
|
||||
char * disk_path;
|
||||
for(int i=0; i<FF_VOLUMES; i++)
|
||||
{
|
||||
disk_path = f_disk_path(i);
|
||||
if(disk_path)
|
||||
{
|
||||
res = df(disk_path, &tot_bytes, &fre_bytes);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
xcmd_print("0: Failure:%s\r\n", RESAULT_TO_STR(res));
|
||||
return -1;
|
||||
xcmd_print("%s Failure:%s\r\n", disk_path, RESAULT_TO_STR(res));
|
||||
}
|
||||
xcmd_print("0:/ %lu/%lu KiB.\r\n", fre_bytes/1024, tot_bytes / 1024);
|
||||
|
||||
res = df("1:", &tot_bytes, &fre_bytes);
|
||||
if (res != FR_OK)
|
||||
else
|
||||
{
|
||||
xcmd_print("1: Failure:%s\r\n", RESAULT_TO_STR(res));
|
||||
return -1;
|
||||
xcmd_print("%s %lu/%lu KiB.\r\n", disk_path, fre_bytes/1024, tot_bytes / 1024);
|
||||
}
|
||||
}
|
||||
}
|
||||
xcmd_print("1:/ %lu/%lu KiB.\r\n", fre_bytes/1024, tot_bytes / 1024);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -220,50 +224,6 @@ static int cmd_cd(int argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_read(int argc, char *argv[])
|
||||
{
|
||||
if (argc >= 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<br; i++)
|
||||
{
|
||||
xcmd_print("%c", buf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xcmd_print("%s\r\n", HELP_READ);
|
||||
return -1;
|
||||
}
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_rm(int argc, char *argv[])
|
||||
{
|
||||
FRESULT res;
|
||||
|
@ -385,70 +345,125 @@ static int cmd_touch(int argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_write(int argc, char *argv[])
|
||||
static int cmd_cat(int argc, char *argv[])
|
||||
{
|
||||
uint8_t append_flag = 0;
|
||||
uint8_t param_num = 3;
|
||||
/* 查找可选参数 */
|
||||
if (strcmp(argv[1], "-a") == 0)
|
||||
if (argc >= 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);
|
||||
while (1)
|
||||
{
|
||||
res = f_read(&fp, buf, 128, &br);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
xcmd_print("Failure:%s", RESAULT_TO_STR(res));
|
||||
xcmd_print("Failure:%s\r\n", RESAULT_TO_STR(res));
|
||||
f_close(&fp);
|
||||
return -1;
|
||||
}
|
||||
if (br == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
for(UINT i=0; i<br; i++)
|
||||
{
|
||||
xcmd_print("%c", buf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xcmd_print("%s\r\n", HELP_WRITE);
|
||||
xcmd_print("%s\r\n", HELP_CAT);
|
||||
return -1;
|
||||
}
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t file_open(char *name, int is_write, int is_append)
|
||||
{
|
||||
FRESULT res;
|
||||
BYTE mode = 0;
|
||||
if(is_write)
|
||||
{
|
||||
if (is_append)
|
||||
{
|
||||
mode = FA_WRITE | FA_OPEN_APPEND;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = FA_WRITE | FA_CREATE_ALWAYS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = FA_READ;
|
||||
}
|
||||
res = f_open(&fp, name, mode);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return (ssize_t)&fp;
|
||||
}
|
||||
|
||||
void file_close(ssize_t fd)
|
||||
{
|
||||
if(fd != -1)
|
||||
f_close((FIL*)fd);
|
||||
}
|
||||
|
||||
int file_read(ssize_t fd, char *buf, int buflen)
|
||||
{
|
||||
FRESULT res;
|
||||
UINT br;
|
||||
if(fd != -1)
|
||||
{
|
||||
res = f_read((FIL*)fd, buf, buflen, &br);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int file_write(ssize_t fd, const char *str)
|
||||
{
|
||||
|
||||
FRESULT res = FR_INVALID_PARAMETER;
|
||||
if(fd != -1)
|
||||
{
|
||||
UINT br;
|
||||
res = f_write((FIL*)fd, str, strlen(str), &br);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
XCMD_EXPORT_CMD(ls, cmd_ls, HELP_LS)
|
||||
XCMD_EXPORT_CMD(df, cmd_df, HELP_DF)
|
||||
XCMD_EXPORT_CMD(cd, cmd_cd, HELP_CD)
|
||||
XCMD_EXPORT_CMD(read, cmd_read, HELP_READ)
|
||||
XCMD_EXPORT_CMD(cat, cmd_cat, HELP_CAT)
|
||||
XCMD_EXPORT_CMD(rm, cmd_rm, HELP_RM)
|
||||
XCMD_EXPORT_CMD(mv, cmd_mv, HELP_MV)
|
||||
XCMD_EXPORT_CMD(sync, cmd_sync, HELP_SYNC)
|
||||
XCMD_EXPORT_CMD(mkdir, cmd_mkdir, HELP_MKDIR)
|
||||
XCMD_EXPORT_CMD(touch, cmd_touch, HELP_TOUCH)
|
||||
XCMD_EXPORT_CMD(write, cmd_write, HELP_WRITE)
|
||||
|
||||
static xcmd_t cmds[] =
|
||||
{
|
||||
|
@ -456,13 +471,12 @@ static xcmd_t cmds[] =
|
|||
{"ls", cmd_ls, HELP_LS, NULL},
|
||||
{"df", cmd_df, HELP_DF, NULL},
|
||||
{"cd", cmd_cd, HELP_CD, NULL},
|
||||
{"read", cmd_read, HELP_READ, NULL},
|
||||
{"cat", cmd_cat, HELP_CAT, NULL},
|
||||
{"rm", cmd_rm, HELP_RM, NULL},
|
||||
{"mv", cmd_mv, HELP_MV, NULL},
|
||||
{"sync", cmd_sync, HELP_SYNC, NULL},
|
||||
{"mkdir", cmd_mkdir, HELP_MKDIR, NULL},
|
||||
{"touch", cmd_touch, HELP_TOUCH, NULL},
|
||||
{"write", cmd_write, HELP_WRITE, NULL},
|
||||
{"touch", cmd_touch, HELP_TOUCH, NULL}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
60
src/xcmd.c
60
src/xcmd.c
|
@ -21,6 +21,8 @@ struct
|
|||
{
|
||||
struct
|
||||
{
|
||||
ssize_t write_fd;
|
||||
ssize_t read_fd;
|
||||
int (*get_c)(uint8_t*);
|
||||
int (*put_c)(uint8_t);
|
||||
}io;
|
||||
|
@ -65,6 +67,31 @@ struct
|
|||
uint8_t _initOK;
|
||||
} g_xcmder = {0};
|
||||
|
||||
ssize_t file_open(char *name, int is_write, int is_append) __attribute__((weak));
|
||||
void file_close(ssize_t fd) __attribute__((weak));
|
||||
int file_write(ssize_t fd, const char *str) __attribute__((weak));
|
||||
int file_read(ssize_t fd, char *buf, int buflen) __attribute__((weak));
|
||||
|
||||
void file_close(ssize_t fd)
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t file_open(char *name, int is_write, int is_append)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int file_write(ssize_t fd, const char *str)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int file_read(ssize_t fd, char *buf, int buflen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *xcmd_strpbrk(char*s, const char *delim) //返回s1中第一个满足条件的字符的指针, 并且保留""号内的源格式
|
||||
{
|
||||
uint8_t flag = 0;
|
||||
|
@ -159,6 +186,27 @@ static int xcmd_get_param(char* msg, char*delim, char* get[], int max_num)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int xcmd_redirected(int argc, char*argv[])
|
||||
{
|
||||
for(int i=1; i<(argc-1); i++)
|
||||
{
|
||||
if(argv[i][0] == '>')
|
||||
{
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue