mirror of
https://github.com/Fishwaldo/bl_mcu_sdk.git
synced 2025-07-07 05:18:34 +00:00
[feat][shell] add shell fs support
This commit is contained in:
parent
26d11a0174
commit
e7bdfee4eb
2 changed files with 250 additions and 52 deletions
|
@ -1,27 +1,31 @@
|
||||||
/**
|
/**
|
||||||
* @file shell.c
|
* @file shell.c
|
||||||
* @brief
|
* @brief
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021 Bouffalolab team
|
* Copyright (c) 2021 Bouffalolab team
|
||||||
*
|
*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership. The
|
* this work for additional information regarding copyright ownership. The
|
||||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
* "License"); you may not use this file except in compliance with the
|
* "License"); you may not use this file except in compliance with the
|
||||||
* License. You may obtain a copy of the License at
|
* License. You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
* License for the specific language governing permissions and limitations
|
* License for the specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
|
|
||||||
|
#if defined(SHELL_USING_FS)
|
||||||
|
#include "ff.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
struct shell_syscall *_syscall_table_begin = NULL;
|
struct shell_syscall *_syscall_table_begin = NULL;
|
||||||
struct shell_syscall *_syscall_table_end = NULL;
|
struct shell_syscall *_syscall_table_end = NULL;
|
||||||
struct shell_sysvar *_sysvar_table_begin = NULL;
|
struct shell_sysvar *_sysvar_table_begin = NULL;
|
||||||
|
@ -58,12 +62,13 @@ static char *shell_get_prompt(void)
|
||||||
{
|
{
|
||||||
static char shell_prompt[SHELL_CONSOLEBUF_SIZE + 1] = { 0 };
|
static char shell_prompt[SHELL_CONSOLEBUF_SIZE + 1] = { 0 };
|
||||||
|
|
||||||
strcpy(shell_prompt, SHELL_NAME);
|
strcpy(shell_prompt, "\r\n");
|
||||||
|
strcat(shell_prompt, SHELL_NAME);
|
||||||
|
|
||||||
#if defined(SHELL_USING_FS)
|
#if defined(SHELL_USING_FS)
|
||||||
/* get current working directory */
|
/* get current working directory */
|
||||||
getcwd(&shell_prompt[strlen(shell_prompt)],
|
f_getcwd(&shell_prompt[strlen(shell_prompt)],
|
||||||
SHELL_CONSOLEBUF_SIZE - strlen(shell_prompt));
|
SHELL_CONSOLEBUF_SIZE - strlen(shell_prompt));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
strcat(shell_prompt, "/>");
|
strcat(shell_prompt, "/>");
|
||||||
|
@ -135,25 +140,24 @@ static void shell_push_history(struct shell *shell)
|
||||||
|
|
||||||
void shell_auto_complete_path(char *path)
|
void shell_auto_complete_path(char *path)
|
||||||
{
|
{
|
||||||
DIR *dir = RT_NULL;
|
DIR dir;
|
||||||
struct dirent *dirent = RT_NULL;
|
FILINFO fno;
|
||||||
char *full_path, *ptr, *index;
|
char *full_path, *ptr, *index;
|
||||||
|
char str_buff[256];
|
||||||
|
|
||||||
if (!path)
|
if (!path)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
full_path = (char *)rt_malloc(256);
|
full_path = str_buff;
|
||||||
if (full_path == RT_NULL)
|
|
||||||
return; /* out of memory */
|
|
||||||
|
|
||||||
if (*path != '/') {
|
// if (*path != '/') {
|
||||||
getcwd(full_path, 256);
|
// f_getcwd(full_path, 256);
|
||||||
if (full_path[rt_strlen(full_path) - 1] != '/')
|
// if (full_path[strlen(full_path) - 1] != '/')
|
||||||
strcat(full_path, "/");
|
// strcat(full_path, "/");
|
||||||
} else
|
// } else
|
||||||
*full_path = '\0';
|
*full_path = '\0';
|
||||||
|
|
||||||
index = RT_NULL;
|
index = NULL;
|
||||||
ptr = path;
|
ptr = path;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (*ptr == '/')
|
if (*ptr == '/')
|
||||||
|
@ -163,10 +167,10 @@ void shell_auto_complete_path(char *path)
|
||||||
|
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
if (index == RT_NULL)
|
if (index == NULL)
|
||||||
index = path;
|
index = path;
|
||||||
|
|
||||||
if (index != RT_NULL) {
|
if (index != NULL) {
|
||||||
char *dest = index;
|
char *dest = index;
|
||||||
|
|
||||||
/* fill the parent path */
|
/* fill the parent path */
|
||||||
|
@ -176,12 +180,10 @@ void shell_auto_complete_path(char *path)
|
||||||
|
|
||||||
for (index = path; index != dest;)
|
for (index = path; index != dest;)
|
||||||
*ptr++ = *index++;
|
*ptr++ = *index++;
|
||||||
*ptr = '\0';
|
*(ptr - 1) = '\0';
|
||||||
|
|
||||||
dir = opendir(full_path);
|
if (f_opendir(&dir, full_path)) /* open directory failed! */
|
||||||
if (dir == RT_NULL) /* open directory failed! */
|
|
||||||
{
|
{
|
||||||
rt_free(full_path);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,31 +194,32 @@ void shell_auto_complete_path(char *path)
|
||||||
/* auto complete the file or directory name */
|
/* auto complete the file or directory name */
|
||||||
if (*index == '\0') /* display all of files and directories */
|
if (*index == '\0') /* display all of files and directories */
|
||||||
{
|
{
|
||||||
|
f_rewinddir(&dir);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
dirent = readdir(dir);
|
f_readdir(&dir, &fno);
|
||||||
if (dirent == RT_NULL)
|
if (fno.fname[0] == '\0')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
SHELL_PRINTF("%s\n", dirent->d_name);
|
SHELL_PRINTF("%s%s%s\r\n", fno.fname, (fno.fattrib & AM_DIR) ? "/" : "", (fno.fattrib & AM_HID) ? "(Hidden)" : "");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rt_size_t length, min_length;
|
uint32_t length, min_length = 0;
|
||||||
|
|
||||||
min_length = 0;
|
f_rewinddir(&dir);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
dirent = readdir(dir);
|
f_readdir(&dir, &fno);
|
||||||
if (dirent == RT_NULL)
|
if (fno.fname[0] == '\0')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* matched the prefix string */
|
/* matched the prefix string */
|
||||||
if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0) {
|
if (strncmp(index, fno.fname, strlen(index)) == 0) {
|
||||||
if (min_length == 0) {
|
if (min_length == 0) {
|
||||||
min_length = rt_strlen(dirent->d_name);
|
min_length = strlen(fno.fname);
|
||||||
/* save dirent name */
|
/* save dirent name */
|
||||||
strcpy(full_path, dirent->d_name);
|
strcpy(full_path, fno.fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
length = str_common(dirent->d_name, full_path);
|
length = str_common(fno.fname, full_path);
|
||||||
|
|
||||||
if (length < min_length) {
|
if (length < min_length) {
|
||||||
min_length = length;
|
min_length = length;
|
||||||
|
@ -225,17 +228,16 @@ void shell_auto_complete_path(char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min_length) {
|
if (min_length) {
|
||||||
if (min_length < rt_strlen(full_path)) {
|
if (min_length < strlen(full_path)) {
|
||||||
/* list the candidate */
|
/* list the candidate */
|
||||||
rewinddir(dir);
|
f_rewinddir(&dir);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
dirent = readdir(dir);
|
f_readdir(&dir, &fno);
|
||||||
if (dirent == RT_NULL)
|
if (fno.fname[0] == '\0')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
|
if (strncmp(index, fno.fname, strlen(index)) == 0)
|
||||||
SHELL_PRINTF("%s\n", dirent->d_name);
|
SHELL_PRINTF("%s%s%s\r\n", fno.fname, (fno.fattrib & AM_DIR) ? "/" : "", (fno.fattrib & AM_HID) ? "(Hidden)" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +247,7 @@ void shell_auto_complete_path(char *path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
f_closedir(&dir);
|
||||||
rt_free(full_path);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -529,11 +530,11 @@ int shell_exec(char *cmd, uint32_t length)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SHELL_USING_FS
|
#ifdef SHELL_USING_FS
|
||||||
extern int shell_exec_script(char *cmd, uint32_t length);
|
// extern int shell_exec_script(char *cmd, uint32_t length);
|
||||||
|
|
||||||
if (shell_exec_script(cmd, length) == 0) {
|
// if (shell_exec_script(cmd, length) == 0) {
|
||||||
return 0;
|
// return 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -633,7 +634,6 @@ void shell_handler(uint8_t data)
|
||||||
SHELL_PRINTF("%c", shell->line[shell->line_curpos]);
|
SHELL_PRINTF("%c", shell->line[shell->line_curpos]);
|
||||||
shell->line_curpos++;
|
shell->line_curpos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
198
components/shell/shell_fs.c
Normal file
198
components/shell/shell_fs.c
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
#include "shell.h"
|
||||||
|
#include "ff.h"
|
||||||
|
#include "fatfs_posix_api.h"
|
||||||
|
|
||||||
|
#if defined(SHELL_USING_FS)
|
||||||
|
/*
|
||||||
|
static void *(*shell_malloc)(size_t size) = mmheap_alloc;
|
||||||
|
static void (*shell_free)(void *ptr) = mmheap_free;
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *fatfs_table[] = {
|
||||||
|
"FR_OK:成功", /* (0) Succeeded */
|
||||||
|
"FR_DISK_ERR:底层硬件错误", /* (1) A hard error occurred in the low level disk I/O layer */
|
||||||
|
"FR_INT_ERR:断言失败", /* (2) Assertion failed */
|
||||||
|
"FR_NOT_READY:物理驱动没有工作", /* (3) The physical drive cannot work */
|
||||||
|
"FR_NO_FILE:文件不存在", /* (4) Could not find the file */
|
||||||
|
"FR_NO_PATH:路径不存在", /* (5) Could not find the path */
|
||||||
|
"FR_INVALID_NAME:无效文件名", /* (6) The path name format is invalid */
|
||||||
|
"FR_DENIED:由于禁止访问或者目录已满访问被拒绝", /* (7) Access denied due to prohibited access or directory full */
|
||||||
|
"FR_EXIST:文件已经存在", /* (8) Access denied due to prohibited access */
|
||||||
|
"FR_INVALID_OBJECT:文件或者目录对象无效", /* (9) The file/directory object is invalid */
|
||||||
|
"FR_WRITE_PROTECTED:物理驱动被写保护", /* (10) The physical drive is write protected */
|
||||||
|
"FR_INVALID_DRIVE:逻辑驱动号无效", /* (11) The logical drive number is invalid */
|
||||||
|
"FR_NOT_ENABLED:卷中无工作区", /* (12) The volume has no work area */
|
||||||
|
"FR_NO_FILESYSTEM:没有有效的FAT卷", /* (13) There is no valid FAT volume */
|
||||||
|
"FR_MKFS_ABORTED:由于参数错误f_mkfs()被终止", /* (14) The f_mkfs() aborted due to any parameter error */
|
||||||
|
"FR_TIMEOUT:在规定的时间内无法获得访问卷的许可", /* (15) Could not get a grant to access the volume within defined period */
|
||||||
|
"FR_LOCKED:由于文件共享策略操作被拒绝", /* (16) The operation is rejected according to the file sharing policy */
|
||||||
|
"FR_NOT_ENOUGH_CORE:无法分配长文件名工作区", /* (17) LFN working buffer could not be allocated */
|
||||||
|
"FR_TOO_MANY_OPEN_FILES:当前打开的文件数大于_FS_SHARE", /* (18) Number of open files > _FS_SHARE */
|
||||||
|
"FR_INVALID_PARAMETER:参数无效" /* (19) Given parameter is invalid */
|
||||||
|
};
|
||||||
|
|
||||||
|
static char path[SHELL_CONSOLEBUF_SIZE] = { 0 };
|
||||||
|
|
||||||
|
#ifdef DFS_USING_WORKDIR
|
||||||
|
extern char working_directory[];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int cmd_ls(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILINFO entry = { 0 };
|
||||||
|
DIR dir;
|
||||||
|
int err;
|
||||||
|
uint8_t flag = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 1; i < argc; i++) {
|
||||||
|
//cmd
|
||||||
|
if (argv[i][0] == '-') {
|
||||||
|
if (strcmp(argv[i], "-a") == 0) {
|
||||||
|
flag |= 0x01;
|
||||||
|
} else {
|
||||||
|
MSG("参数错误 %s\r\n", argv[i]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//path
|
||||||
|
else {
|
||||||
|
if ((flag & 0x80) == 0) {
|
||||||
|
strcpy(path, argv[i]);
|
||||||
|
flag |= 0x80;
|
||||||
|
} else {
|
||||||
|
MSG("参数错误 %s\r\n", argv[i]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flag & 0x80) == 0) {
|
||||||
|
strcpy(path, ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f_opendir(&dir, path);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
MSG("%s %s\r\n", fatfs_table[err], path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
err = f_readdir(&dir, &entry);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
MSG("%s %s\r\n", fatfs_table[err], path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for end of directory listing */
|
||||||
|
if (entry.fname[0] == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((entry.fattrib & AM_HID) && !(flag & 0x01)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MSG("%s%s%s\r\n", entry.fname, (entry.fattrib & AM_DIR) ? "/" : "", (entry.fattrib & AM_HID) ? "(Hidden)" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
f_closedir(&dir);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SHELL_CMD_EXPORT_ALIAS(cmd_ls, ls, List information about the FILEs.);
|
||||||
|
|
||||||
|
int cmd_rm(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
MSG("缺少参数\r\n");
|
||||||
|
MSG("rm <path> \r\n");
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
strcpy(path, argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f_unlink(path);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
MSG("%s %s\r\n", fatfs_table[err], path);
|
||||||
|
err = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
SHELL_CMD_EXPORT_ALIAS(cmd_rm, rm, Remove(unlink) the FILE(s).);
|
||||||
|
|
||||||
|
int cmd_cd(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
strcpy(path, ".");
|
||||||
|
} else {
|
||||||
|
strcpy(path, argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t i = strlen(path) - 1; i > 0; i--) {
|
||||||
|
if (path[i] == '/')
|
||||||
|
path[i] = '\0';
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f_chdir(path);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
MSG("%s %s\r\n", fatfs_table[err], path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SHELL_CMD_EXPORT_ALIAS(cmd_cd, cd, Change the shell working directory.);
|
||||||
|
|
||||||
|
int cmd_pwd(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
err = f_getcwd(path, SHELL_CONSOLEBUF_SIZE);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
MSG("%s\r\n", fatfs_table[err]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MSG("%s\r\n", path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SHELL_CMD_EXPORT_ALIAS(cmd_pwd, pwd, Print the name of the current working directory.);
|
||||||
|
|
||||||
|
int cmd_mkdir(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
strcpy(path, "new_dir");
|
||||||
|
} else {
|
||||||
|
strcpy(path, argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f_mkdir(path);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
MSG("%s %s\r\n", fatfs_table[err], path);
|
||||||
|
err = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
SHELL_CMD_EXPORT_ALIAS(cmd_mkdir, mkdir, Create the DIRECTORY.);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue