[feat] add shell component and example
This commit is contained in:
parent
3e9132d402
commit
c82f593dd9
21
component/shell/CMakeLists.txt
Executable file
21
component/shell/CMakeLists.txt
Executable file
@ -0,0 +1,21 @@
|
||||
file(GLOB FILELIST
|
||||
shell.c
|
||||
)
|
||||
|
||||
set(TARGET shell)
|
||||
add_library(${TARGET} STATIC ${FILELIST})
|
||||
|
||||
target_include_directories(${TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
if(CONFIG_FREERTOS)
|
||||
target_sources(${TARGET} PRIVATE shell_freertos.c)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${TARGET} PRIVATE -DCONFIG_SHELL)
|
||||
if(CONFIG_SHELL_EXEC_THREAD)
|
||||
target_compile_definitions(${TARGET} PRIVATE -DCONFIG_SHELL_EXEC_THREAD)
|
||||
endif()
|
||||
|
||||
if(CONFIG_SHELL_CMD_SIZE)
|
||||
target_compile_definitions(${TARGET} PRIVATE -DSHELL_CMD_SIZE=${CONFIG_SHELL_CMD_SIZE})
|
||||
endif()
|
||||
927
component/shell/shell.c
Executable file
927
component/shell/shell.c
Executable file
@ -0,0 +1,927 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-04-30 Bernard the first version for FinSH
|
||||
* 2006-05-08 Bernard change finsh thread stack to 2048
|
||||
* 2006-06-03 Bernard add support for skyeye
|
||||
* 2006-09-24 Bernard remove the code related with hardware
|
||||
* 2010-01-18 Bernard fix down then up key bug.
|
||||
* 2010-03-19 Bernard fix backspace issue and fix device read in shell.
|
||||
* 2010-04-01 Bernard add prompt output when start and remove the empty history
|
||||
* 2011-02-23 Bernard fix variable section end issue of finsh shell
|
||||
* initialization when use GNU GCC compiler.
|
||||
* 2016-11-26 armink add password authentication
|
||||
* 2018-07-02 aozima add custom prompt support.
|
||||
*/
|
||||
|
||||
#include "shell.h"
|
||||
#if defined(SHELL_USING_FS)
|
||||
#include "ff.h"
|
||||
#endif
|
||||
|
||||
struct shell_syscall *_syscall_table_begin = NULL;
|
||||
struct shell_syscall *_syscall_table_end = NULL;
|
||||
struct shell_sysvar *_sysvar_table_begin = NULL;
|
||||
struct shell_sysvar *_sysvar_table_end = NULL;
|
||||
|
||||
struct shell _shell;
|
||||
static struct shell *shell;
|
||||
static char *shell_prompt_custom = NULL;
|
||||
|
||||
extern void shell_abort_exec(int sig);
|
||||
extern int shell_start_exec(cmd_function_t func, int argc, char *argv[]);
|
||||
extern void shell_dup_line(char *cmd, uint32_t length);
|
||||
static volatile shell_sig_func_ptr shell_sig_func;
|
||||
|
||||
int shell_help(int argc, char **argv)
|
||||
{
|
||||
SHELL_DGB("shell commands list:\r\n");
|
||||
{
|
||||
struct shell_syscall *index;
|
||||
|
||||
for (index = _syscall_table_begin; index < _syscall_table_end; index++) {
|
||||
// if (strncmp(index->name, "__cmd_", 6) != 0) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
#if defined(SHELL_USING_DESCRIPTION)
|
||||
SHELL_DGB("%-16s - %s\r\n", &index->name[0], index->desc);
|
||||
#else
|
||||
SHELL_DGB("%s\r\n", &index->name[0]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
SHELL_DGB("\r\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
SHELL_CMD_EXPORT_ALIAS(shell_help, help, shell help.);
|
||||
|
||||
static int shell_memtrace(int argc, char **argv)
|
||||
{
|
||||
uint32_t addr, value;
|
||||
int i, j;
|
||||
|
||||
/* check args */
|
||||
if (argc < 2) {
|
||||
SHELL_DGB("write memory: 0x42000000 0xabcd 10\r\n");
|
||||
SHELL_DGB("read memory: 0x42000000 10\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get address */
|
||||
addr = strtoll(argv[1], NULL, 16);
|
||||
|
||||
if (argc < 3) {
|
||||
/* read word */
|
||||
SHELL_DGB("0x%08x\r\n", *(volatile uint32_t *)(uintptr_t)addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc < 4) {
|
||||
uint16_t count = atoi(argv[2]);
|
||||
for (i = 0; i < count;) {
|
||||
SHELL_DGB("0x%08x ", (addr + sizeof(uintptr_t) * i));
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (i < count) {
|
||||
/* read word */
|
||||
SHELL_DGB("0x%08x ", *(volatile uint32_t *)(uintptr_t)(addr + sizeof(uintptr_t) * i));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
SHELL_DGB("\r\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc < 5) {
|
||||
uint16_t count = atoi(argv[3]);
|
||||
/* write value */
|
||||
value = strtoll(argv[2], NULL, 16);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
*(volatile uint32_t *)(uintptr_t)(addr + sizeof(uintptr_t) * i) = (uint32_t)value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
SHELL_CMD_EXPORT_ALIAS(shell_memtrace, memtrace, memory trace.);
|
||||
|
||||
static char *shell_get_prompt(void)
|
||||
{
|
||||
static char shell_prompt[SHELL_CONSOLEBUF_SIZE + 1] = { 0 };
|
||||
|
||||
if (shell_prompt_custom) {
|
||||
if(strlcpy(shell_prompt, shell_prompt_custom, sizeof(shell_prompt)) >= sizeof(shell_prompt))
|
||||
printf("[OS]: strlcpy truncated \r\n");
|
||||
} else {
|
||||
if(strlcpy(shell_prompt, SHELL_DEFAULT_NAME, sizeof(shell_prompt)) >= sizeof(shell_prompt))
|
||||
printf("[OS]: strlcpy truncated \r\n");
|
||||
}
|
||||
#if defined(SHELL_USING_FS)
|
||||
/* get current working directory */
|
||||
f_getcwd(&shell_prompt[strlen(shell_prompt)],
|
||||
SHELL_CONSOLEBUF_SIZE - strlen(shell_prompt));
|
||||
#endif
|
||||
|
||||
if(strlcat(shell_prompt, "/>", sizeof(shell_prompt)) >= sizeof(shell_prompt))
|
||||
printf("[OS]: strlcat truncated \r\n");
|
||||
|
||||
return shell_prompt;
|
||||
}
|
||||
|
||||
static int str_common(const char *str1, const char *str2)
|
||||
{
|
||||
const char *str = str1;
|
||||
|
||||
while ((*str != 0) && (*str2 != 0) && (*str == *str2)) {
|
||||
str++;
|
||||
str2++;
|
||||
}
|
||||
|
||||
return (str - str1);
|
||||
}
|
||||
|
||||
static void shell_handle_history(struct shell *shell)
|
||||
{
|
||||
SHELL_PRINTF("\033[2K\r");
|
||||
SHELL_PROMPT("%s", shell_get_prompt());
|
||||
SHELL_PRINTF("%s", shell->line);
|
||||
}
|
||||
|
||||
static void shell_push_history(struct shell *shell)
|
||||
{
|
||||
if (shell->line_position != 0) {
|
||||
/* push history */
|
||||
if (shell->history_count >= SHELL_HISTORY_LINES) {
|
||||
/* if current cmd is same as last cmd, don't push */
|
||||
if (memcmp(&shell->cmd_history[SHELL_HISTORY_LINES - 1], shell->line,
|
||||
SHELL_CMD_SIZE)) {
|
||||
/* move history */
|
||||
int index;
|
||||
|
||||
for (index = 0; index < SHELL_HISTORY_LINES - 1; index++) {
|
||||
memcpy(&shell->cmd_history[index][0],
|
||||
&shell->cmd_history[index + 1][0], SHELL_CMD_SIZE);
|
||||
}
|
||||
|
||||
memset(&shell->cmd_history[index][0], 0, SHELL_CMD_SIZE);
|
||||
memcpy(&shell->cmd_history[index][0], shell->line,
|
||||
shell->line_position);
|
||||
|
||||
/* it's the maximum history */
|
||||
shell->history_count = SHELL_HISTORY_LINES;
|
||||
}
|
||||
} else {
|
||||
/* if current cmd is same as last cmd, don't push */
|
||||
if (shell->history_count == 0 ||
|
||||
memcmp(&shell->cmd_history[shell->history_count - 1], shell->line,
|
||||
SHELL_CMD_SIZE)) {
|
||||
shell->current_history = shell->history_count;
|
||||
memset(&shell->cmd_history[shell->history_count][0], 0, SHELL_CMD_SIZE);
|
||||
memcpy(&shell->cmd_history[shell->history_count][0], shell->line,
|
||||
shell->line_position);
|
||||
|
||||
/* increase count and set current history position */
|
||||
shell->history_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shell->current_history = shell->history_count;
|
||||
}
|
||||
|
||||
#ifdef SHELL_USING_FS
|
||||
|
||||
void shell_auto_complete_path(char *path)
|
||||
{
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
char *full_path, *ptr, *index;
|
||||
char str_buff[256];
|
||||
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
full_path = str_buff;
|
||||
|
||||
// if (*path != '/') {
|
||||
// f_getcwd(full_path, 256);
|
||||
// if (full_path[strlen(full_path) - 1] != '/')
|
||||
// strlcat(full_path, "/");
|
||||
// } else
|
||||
*full_path = '\0';
|
||||
|
||||
index = NULL;
|
||||
ptr = path;
|
||||
for (;;) {
|
||||
if (*ptr == '/')
|
||||
index = ptr + 1;
|
||||
if (!*ptr)
|
||||
break;
|
||||
|
||||
ptr++;
|
||||
}
|
||||
if (index == NULL)
|
||||
index = path;
|
||||
|
||||
if (index != NULL) {
|
||||
char *dest = index;
|
||||
|
||||
/* fill the parent path */
|
||||
ptr = full_path;
|
||||
while (*ptr)
|
||||
ptr++;
|
||||
|
||||
for (index = path; index != dest;)
|
||||
*ptr++ = *index++;
|
||||
*(ptr - 1) = '\0';
|
||||
|
||||
if (f_opendir(&dir, full_path)) /* open directory failed! */
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* restore the index position */
|
||||
index = dest;
|
||||
}
|
||||
|
||||
/* auto complete the file or directory name */
|
||||
if (*index == '\0') /* display all of files and directories */
|
||||
{
|
||||
f_rewinddir(&dir);
|
||||
for (;;) {
|
||||
f_readdir(&dir, &fno);
|
||||
if (fno.fname[0] == '\0')
|
||||
break;
|
||||
|
||||
SHELL_PRINTF("%s%s%s\r\n", fno.fname, (fno.fattrib & AM_DIR) ? "/" : "", (fno.fattrib & AM_HID) ? "(Hidden)" : "");
|
||||
}
|
||||
} else {
|
||||
uint32_t length, min_length = 0;
|
||||
|
||||
f_rewinddir(&dir);
|
||||
for (;;) {
|
||||
f_readdir(&dir, &fno);
|
||||
if (fno.fname[0] == '\0')
|
||||
break;
|
||||
|
||||
/* matched the prefix string */
|
||||
if (strncmp(index, fno.fname, strlen(index)) == 0) {
|
||||
if (min_length == 0) {
|
||||
min_length = strlen(fno.fname);
|
||||
/* save dirent name */
|
||||
if(strlcpy(full_path, fno.fname, sizeof(str_buff)) >= sizeof(str_buff))
|
||||
printf("[OS]: strlcpy truncated \r\n");
|
||||
}
|
||||
|
||||
length = str_common(fno.fname, full_path);
|
||||
|
||||
if (length < min_length) {
|
||||
min_length = length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (min_length) {
|
||||
if (min_length < strlen(full_path)) {
|
||||
/* list the candidate */
|
||||
f_rewinddir(&dir);
|
||||
for (;;) {
|
||||
f_readdir(&dir, &fno);
|
||||
if (fno.fname[0] == '\0')
|
||||
break;
|
||||
|
||||
if (strncmp(index, fno.fname, strlen(index)) == 0)
|
||||
SHELL_PRINTF("%s%s%s\r\n", fno.fname, (fno.fattrib & AM_DIR) ? "/" : "", (fno.fattrib & AM_HID) ? "(Hidden)" : "");
|
||||
}
|
||||
}
|
||||
|
||||
length = index - path;
|
||||
memcpy(index, full_path, min_length);
|
||||
path[length + min_length] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void shell_auto_complete(char *prefix)
|
||||
{
|
||||
int length, min_length;
|
||||
const char *name_ptr, *cmd_name;
|
||||
struct shell_syscall *index;
|
||||
|
||||
min_length = 0;
|
||||
name_ptr = NULL;
|
||||
|
||||
SHELL_PRINTF("\r\n");
|
||||
|
||||
if (*prefix == '\0') {
|
||||
shell_help(0, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SHELL_USING_FS
|
||||
/* check whether a spare in the command */
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr = prefix + strlen(prefix);
|
||||
|
||||
while (ptr != prefix) {
|
||||
if (*ptr == ' ') {
|
||||
shell_auto_complete_path(ptr + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
ptr--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* checks in internal command */
|
||||
{
|
||||
for (index = _syscall_table_begin; index < _syscall_table_end; index++) {
|
||||
/* skip finsh shell function */
|
||||
// if (strncmp(index->name, "__cmd_", 6) != 0) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
cmd_name = (const char *)&index->name[0];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
SHELL_CMD("%s\r\n", cmd_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* auto complete string */
|
||||
if (name_ptr != NULL) {
|
||||
strlcpy(prefix, name_ptr, min_length + 1);
|
||||
}
|
||||
|
||||
SHELL_PROMPT("%s", shell_get_prompt());
|
||||
SHELL_PRINTF("%s", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
static int shell_split(char *cmd, uint32_t length, char *argv[SHELL_ARG_NUM])
|
||||
{
|
||||
char *ptr;
|
||||
uint32_t position;
|
||||
uint32_t argc;
|
||||
uint32_t i;
|
||||
|
||||
ptr = cmd;
|
||||
position = 0;
|
||||
argc = 0;
|
||||
|
||||
while (position < length) {
|
||||
/* strip bank and tab */
|
||||
while ((*ptr == ' ' || *ptr == '\t') && position < length) {
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
position++;
|
||||
}
|
||||
|
||||
if (argc >= SHELL_ARG_NUM) {
|
||||
SHELL_E("Too many args ! We only Use:\r\n");
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
SHELL_E("%s ", argv[i]);
|
||||
}
|
||||
|
||||
SHELL_E("\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (position >= length) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* handle string */
|
||||
if (*ptr == '"') {
|
||||
ptr++;
|
||||
position++;
|
||||
argv[argc] = ptr;
|
||||
argc++;
|
||||
|
||||
/* skip this string */
|
||||
while (*ptr != '"' && position < length) {
|
||||
if (*ptr == '\\') {
|
||||
if (*(ptr + 1) == '"') {
|
||||
ptr++;
|
||||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
ptr++;
|
||||
position++;
|
||||
}
|
||||
|
||||
if (position >= length) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* skip '"' */
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
position++;
|
||||
} else {
|
||||
argv[argc] = ptr;
|
||||
argc++;
|
||||
|
||||
while ((*ptr != ' ' && *ptr != '\t') && position < length) {
|
||||
ptr++;
|
||||
position++;
|
||||
}
|
||||
|
||||
if (position >= length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return argc;
|
||||
}
|
||||
|
||||
static cmd_function_t shell_get_cmd(char *cmd, int size)
|
||||
{
|
||||
struct shell_syscall *index;
|
||||
cmd_function_t cmd_func = NULL;
|
||||
|
||||
for (index = _syscall_table_begin; index < _syscall_table_end; index++) {
|
||||
// if (strncmp(index->name, "__cmd_", 6) != 0) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if (strncmp(&index->name[0], cmd, size) == 0 &&
|
||||
index->name[0 + size] == '\0') {
|
||||
cmd_func = (cmd_function_t)index->func;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cmd_func;
|
||||
}
|
||||
|
||||
static int shell_exec_cmd(char *cmd, uint32_t length, int *retp)
|
||||
{
|
||||
int argc;
|
||||
uint32_t cmd0_size = 0;
|
||||
cmd_function_t cmd_func;
|
||||
char *argv[SHELL_ARG_NUM];
|
||||
|
||||
// ASSERT(cmd);
|
||||
// ASSERT(retp);
|
||||
|
||||
/* find the size of first command */
|
||||
while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') &&
|
||||
cmd0_size < length) {
|
||||
cmd0_size++;
|
||||
}
|
||||
|
||||
if (cmd0_size == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd_func = shell_get_cmd(cmd, cmd0_size);
|
||||
|
||||
if (cmd_func == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* split arguments */
|
||||
memset(argv, 0x00, sizeof(argv));
|
||||
argc = shell_split(cmd, length, argv);
|
||||
|
||||
if (argc == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* exec this command */
|
||||
shell_signal(SHELL_SIGINT, SHELL_SIG_DFL);
|
||||
shell_dup_line(cmd, length);
|
||||
*retp = shell_start_exec(cmd_func, argc, argv);
|
||||
// *retp = cmd_func(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(SHELL_USING_LWIP) && defined(SHELL_USING_FS)
|
||||
static int shell_exec_lwp(char *cmd, uint32_t length)
|
||||
{
|
||||
int argc;
|
||||
int cmd0_size = 0;
|
||||
char *argv[SHELL_ARG_NUM];
|
||||
int fd = -1;
|
||||
char *pg_name;
|
||||
|
||||
extern int exec(char *, int, char **);
|
||||
|
||||
/* find the size of first command */
|
||||
while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') &&
|
||||
cmd0_size < length) {
|
||||
cmd0_size++;
|
||||
}
|
||||
|
||||
if (cmd0_size == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* split arguments */
|
||||
rt_memset(argv, 0x00, sizeof(argv));
|
||||
argc = msh_split(cmd, length, argv);
|
||||
|
||||
if (argc == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pg_name = argv[0];
|
||||
/* try to open program */
|
||||
fd = open(pg_name, O_RDONLY, 0);
|
||||
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* found program */
|
||||
close(fd);
|
||||
exec(pg_name, argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int shell_exec(char *cmd, uint32_t length)
|
||||
{
|
||||
int cmd_ret;
|
||||
|
||||
/* strim the beginning of command */
|
||||
while (*cmd == ' ' || *cmd == '\t') {
|
||||
cmd++;
|
||||
length--;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Exec sequence:
|
||||
* 1. built-in command
|
||||
* 2. module(if enabled)
|
||||
*/
|
||||
if (shell_exec_cmd(cmd, length, &cmd_ret) == 0) {
|
||||
return cmd_ret;
|
||||
}
|
||||
|
||||
#ifdef SHELL_USING_FS
|
||||
// extern int shell_exec_script(char *cmd, uint32_t length);
|
||||
|
||||
// if (shell_exec_script(cmd, length) == 0) {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SHELL_USING_LWIP
|
||||
|
||||
if (shell_exec_lwp(cmd, length) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* truncate the cmd at the first space. */
|
||||
{
|
||||
char *tcmd;
|
||||
tcmd = cmd;
|
||||
|
||||
while (*tcmd != ' ' && *tcmd != '\0') {
|
||||
tcmd++;
|
||||
}
|
||||
|
||||
*tcmd = '\0';
|
||||
}
|
||||
SHELL_E("%s: command not found.\r\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void shell_handler(uint8_t data)
|
||||
{
|
||||
/*
|
||||
* handle control key
|
||||
* up key : 0x1b 0x5b 0x41
|
||||
* down key: 0x1b 0x5b 0x42
|
||||
* right key:0x1b 0x5b 0x43
|
||||
* left key: 0x1b 0x5b 0x44
|
||||
*/
|
||||
|
||||
if (data == 0x03) {
|
||||
/*!< ctrl + c */
|
||||
if (shell_sig_func) {
|
||||
shell_sig_func(SHELL_SIGINT);
|
||||
shell_sig_func = NULL;
|
||||
}
|
||||
SHELL_PRINTF("^C");
|
||||
data = '\r';
|
||||
}
|
||||
|
||||
if (data == 0x1b) {
|
||||
shell->stat = WAIT_SPEC_KEY;
|
||||
return;
|
||||
} else if (shell->stat == WAIT_SPEC_KEY) {
|
||||
if (data == 0x5b) {
|
||||
shell->stat = WAIT_FUNC_KEY;
|
||||
return;
|
||||
}
|
||||
|
||||
shell->stat = WAIT_NORMAL;
|
||||
} else if (shell->stat == WAIT_FUNC_KEY) {
|
||||
shell->stat = WAIT_NORMAL;
|
||||
|
||||
if (data == 0x41) /* up key */
|
||||
{
|
||||
/* prev history */
|
||||
if (shell->current_history > 0) {
|
||||
shell->current_history--;
|
||||
} else {
|
||||
shell->current_history = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* copy the history command */
|
||||
memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
|
||||
SHELL_CMD_SIZE);
|
||||
shell->line_curpos = shell->line_position = strlen(shell->line);
|
||||
shell_handle_history(shell);
|
||||
|
||||
return;
|
||||
} else if (data == 0x42) /* down key */
|
||||
{
|
||||
/* next history */
|
||||
if (shell->current_history < shell->history_count - 1) {
|
||||
shell->current_history++;
|
||||
} else {
|
||||
/* set to the end of history */
|
||||
if (shell->history_count != 0) {
|
||||
shell->current_history = shell->history_count - 1;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
|
||||
SHELL_CMD_SIZE);
|
||||
shell->line_curpos = shell->line_position = strlen(shell->line);
|
||||
shell_handle_history(shell);
|
||||
|
||||
return;
|
||||
} else if (data == 0x44) /* left key */
|
||||
{
|
||||
if (shell->line_curpos) {
|
||||
SHELL_PRINTF("\b");
|
||||
shell->line_curpos--;
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (data == 0x43) /* right key */
|
||||
{
|
||||
if (shell->line_curpos < shell->line_position) {
|
||||
SHELL_PRINTF("%c", shell->line[shell->line_curpos]);
|
||||
shell->line_curpos++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* received null or error */
|
||||
if ((data == '\0') || (data == 0xFF)) {
|
||||
return;
|
||||
}
|
||||
/* handle tab key */
|
||||
else if (data == '\t') {
|
||||
int i;
|
||||
|
||||
/* move the cursor to the beginning of line */
|
||||
for (i = 0; i < shell->line_curpos; i++) {
|
||||
SHELL_PRINTF("\b");
|
||||
}
|
||||
|
||||
/* auto complete */
|
||||
shell_auto_complete(&shell->line[0]);
|
||||
/* re-calculate position */
|
||||
shell->line_curpos = shell->line_position = strlen(shell->line);
|
||||
|
||||
return;
|
||||
}
|
||||
/* handle backspace key */
|
||||
else if (data == 0x7f || data == 0x08) {
|
||||
/* note that shell->line_curpos >= 0 */
|
||||
if (shell->line_curpos == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
shell->line_position--;
|
||||
shell->line_curpos--;
|
||||
|
||||
if (shell->line_position > shell->line_curpos) {
|
||||
int i;
|
||||
|
||||
memmove(&shell->line[shell->line_curpos],
|
||||
&shell->line[shell->line_curpos + 1],
|
||||
shell->line_position - shell->line_curpos);
|
||||
shell->line[shell->line_position] = 0;
|
||||
|
||||
SHELL_PRINTF("\b%s \b", &shell->line[shell->line_curpos]);
|
||||
|
||||
/* move the cursor to the origin position */
|
||||
for (i = shell->line_curpos; i <= shell->line_position; i++) {
|
||||
SHELL_PRINTF("\b");
|
||||
}
|
||||
} else {
|
||||
SHELL_PRINTF("\b \b");
|
||||
shell->line[shell->line_position] = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* handle end of line, break */
|
||||
if (data == '\r' || data == '\n') {
|
||||
shell_push_history(shell);
|
||||
|
||||
SHELL_PRINTF("\r\n");
|
||||
shell_exec(shell->line, shell->line_position);
|
||||
|
||||
SHELL_PROMPT(shell_get_prompt());
|
||||
memset(shell->line, 0, sizeof(shell->line));
|
||||
shell->line_curpos = shell->line_position = 0;
|
||||
return;
|
||||
}
|
||||
/* return not display character */
|
||||
if((data < 0x20) || (data >= 0x80))
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* it's a large line, discard it */
|
||||
if (shell->line_position >= SHELL_CMD_SIZE) {
|
||||
shell->line_position = 0;
|
||||
}
|
||||
|
||||
/* normal character */
|
||||
if (shell->line_curpos < shell->line_position) {
|
||||
int i;
|
||||
|
||||
memmove(&shell->line[shell->line_curpos + 1],
|
||||
&shell->line[shell->line_curpos],
|
||||
shell->line_position - shell->line_curpos);
|
||||
shell->line[shell->line_curpos] = data;
|
||||
|
||||
SHELL_PRINTF("%s", &shell->line[shell->line_curpos]);
|
||||
|
||||
/* move the cursor to new position */
|
||||
for (i = shell->line_curpos; i < shell->line_position; i++) {
|
||||
SHELL_PRINTF("\b");
|
||||
}
|
||||
} else {
|
||||
shell->line[shell->line_position] = data;
|
||||
SHELL_PRINTF("%c", data);
|
||||
}
|
||||
|
||||
data = 0;
|
||||
shell->line_position++;
|
||||
shell->line_curpos++;
|
||||
|
||||
if (shell->line_position >= SHELL_CMD_SIZE) {
|
||||
/* clear command line */
|
||||
shell->line_position = 0;
|
||||
shell->line_curpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void shell_function_init(const void *begin, const void *end)
|
||||
{
|
||||
_syscall_table_begin = (struct shell_syscall *)begin;
|
||||
_syscall_table_end = (struct shell_syscall *)end;
|
||||
}
|
||||
|
||||
static void shell_var_init(const void *begin, const void *end)
|
||||
{
|
||||
_sysvar_table_begin = (struct shell_sysvar *)begin;
|
||||
_sysvar_table_end = (struct shell_sysvar *)end;
|
||||
}
|
||||
|
||||
int shell_set_prompt(const char *prompt)
|
||||
{
|
||||
if (shell_prompt_custom) {
|
||||
SHELL_FREE(shell_prompt_custom);
|
||||
shell_prompt_custom = NULL;
|
||||
}
|
||||
|
||||
/* strdup */
|
||||
if (prompt) {
|
||||
shell_prompt_custom = (char *)SHELL_MALLOC(strlen(prompt) + 1);
|
||||
if (shell_prompt_custom) {
|
||||
if(strlcpy(shell_prompt_custom, prompt, strlen(prompt) + 1) >= strlen(prompt) + 1)
|
||||
printf("[OS]: strlcpy truncated \r\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shell_set_print(void (*shell_printf)(char *fmt, ...))
|
||||
{
|
||||
if (shell_printf) {
|
||||
shell->shell_printf = shell_printf;
|
||||
return 0;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* @ingroup shell
|
||||
*
|
||||
* This function will initialize shell
|
||||
*/
|
||||
void shell_init(void)
|
||||
{
|
||||
#if defined(__CC_ARM) || defined(__CLANG_ARM) /* ARM C Compiler */
|
||||
extern const int FSymTab$$Base;
|
||||
extern const int FSymTab$$Limit;
|
||||
extern const int VSymTab$$Base;
|
||||
extern const int VSymTab$$Limit;
|
||||
shell_function_init(&FSymTab$$Base, &FSymTab$$Limit);
|
||||
shell_var_init(&VSymTab$$Base, &VSymTab$$Limit);
|
||||
#elif defined(__ICCARM__) || defined(__ICCRX__) /* for IAR Compiler */
|
||||
shell_function_init(__section_begin("FSymTab"), __section_end("FSymTab"));
|
||||
shell_var_init(__section_begin("VSymTab"), __section_end("VSymTab"));
|
||||
#elif defined(__GNUC__)
|
||||
/* GNU GCC Compiler and TI CCS */
|
||||
extern const int __fsymtab_start;
|
||||
extern const int __fsymtab_end;
|
||||
extern const int __vsymtab_start;
|
||||
extern const int __vsymtab_end;
|
||||
shell_function_init(&__fsymtab_start, &__fsymtab_end);
|
||||
shell_var_init(&__vsymtab_start, &__vsymtab_end);
|
||||
#endif
|
||||
shell = &_shell;
|
||||
shell_set_prompt(SHELL_DEFAULT_NAME);
|
||||
shell_set_print((void (*)(char *fmt, ...))printf);
|
||||
SHELL_PRINTF(shell_get_prompt());
|
||||
}
|
||||
|
||||
shell_sig_func_ptr shell_signal(int sig, shell_sig_func_ptr func)
|
||||
{
|
||||
shell_sig_func_ptr shell_sig_func_prev = shell_sig_func;
|
||||
|
||||
if (sig == SHELL_SIGINT) {
|
||||
if (func == SHELL_SIG_DFL) {
|
||||
shell_sig_func = shell_abort_exec;
|
||||
} else if (func == SHELL_SIG_IGN) {
|
||||
shell_sig_func = NULL;
|
||||
} else {
|
||||
shell_sig_func = func;
|
||||
}
|
||||
return shell_sig_func_prev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void shell_abort_exec(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
}
|
||||
__attribute__((weak)) int shell_start_exec(cmd_function_t func, int argc, char *argv[])
|
||||
{
|
||||
return func(argc, argv);
|
||||
}
|
||||
__attribute__((weak)) void shell_dup_line(char *cmd, uint32_t length)
|
||||
{
|
||||
(void)cmd;
|
||||
(void)length;
|
||||
}
|
||||
167
component/shell/shell.h
Executable file
167
component/shell/shell.h
Executable file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-06-02 Bernard Add finsh_get_prompt function declaration
|
||||
*/
|
||||
#ifndef __SHELL_H__
|
||||
#define __SHELL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "shell_config.h"
|
||||
|
||||
#ifdef SHELL_USING_COLOR
|
||||
/*
|
||||
* The color for terminal (foreground)
|
||||
* BLACK 30
|
||||
* RED 31
|
||||
* GREEN 32
|
||||
* YELLOW 33
|
||||
* BLUE 34
|
||||
* PURPLE 35
|
||||
* CYAN 36
|
||||
* WHITE 37
|
||||
*/
|
||||
#define _SHELL_COLOR_HDR(n) shell->shell_printf("\033[" #n "m")
|
||||
#define _SHELL_COLOR_END shell->shell_printf("\033[0m")
|
||||
|
||||
#define shell_print(color_n, fmt, ...) \
|
||||
do { \
|
||||
_SHELL_COLOR_HDR(color_n); \
|
||||
shell->shell_printf(fmt, ##__VA_ARGS__); \
|
||||
_SHELL_COLOR_END; \
|
||||
} while (0)
|
||||
|
||||
#define SHELL_PRINTF(fmt, ...) shell_print(0, fmt, ##__VA_ARGS__)
|
||||
#define SHELL_PROMPT(fmt, ...) shell_print(36, fmt, ##__VA_ARGS__)
|
||||
#define SHELL_DGB(fmt, ...) shell_print(32, fmt, ##__VA_ARGS__)
|
||||
#define SHELL_CMD(fmt, ...) shell_print(33, fmt, ##__VA_ARGS__)
|
||||
#define SHELL_E(fmt, ...) shell_print(31, fmt, ##__VA_ARGS__)
|
||||
|
||||
#else
|
||||
#define SHELL_PRINTF(fmt, ...) shell->shell_printf(fmt, ##__VA_ARGS__)
|
||||
#define SHELL_PROMPT(fmt, ...) shell->shell_printf(fmt, ##__VA_ARGS__)
|
||||
#define SHELL_DGB(fmt, ...) shell->shell_printf(fmt, ##__VA_ARGS__)
|
||||
#define SHELL_CMD(fmt, ...) shell->shell_printf(fmt, ##__VA_ARGS__)
|
||||
#define SHELL_E(fmt, ...) shell->shell_printf(fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define SHELL_MALLOC malloc
|
||||
#define SHELL_FREE free
|
||||
|
||||
#define SHELL_SIGINT 1
|
||||
#define SHELL_SIG_DFL ((shell_sig_func_ptr)0) /* Default action */
|
||||
#define SHELL_SIG_IGN ((shell_sig_func_ptr)1) /* Ignore action */
|
||||
|
||||
typedef void (*shell_sig_func_ptr)(int);
|
||||
typedef int (*syscall_func)(void);
|
||||
typedef int (*cmd_function_t)(int argc, char **argv);
|
||||
|
||||
enum input_stat {
|
||||
WAIT_NORMAL,
|
||||
WAIT_SPEC_KEY,
|
||||
WAIT_FUNC_KEY,
|
||||
};
|
||||
|
||||
struct shell {
|
||||
enum input_stat stat;
|
||||
|
||||
uint16_t current_history;
|
||||
uint16_t history_count;
|
||||
char cmd_history[SHELL_HISTORY_LINES][SHELL_CMD_SIZE];
|
||||
|
||||
char line[SHELL_CMD_SIZE];
|
||||
uint16_t line_position;
|
||||
uint16_t line_curpos;
|
||||
|
||||
#ifdef SHELL_USING_AUTH
|
||||
char password[SHELL_PASSWORD_MAX];
|
||||
#endif
|
||||
|
||||
#if defined(SHELL_USING_FS)
|
||||
|
||||
#endif
|
||||
void (*shell_printf)(char *fmt, ...);
|
||||
};
|
||||
|
||||
/* system call table */
|
||||
struct shell_syscall {
|
||||
const char *name; /* the name of system call */
|
||||
#if defined(SHELL_USING_DESCRIPTION)
|
||||
const char *desc; /* description of system call */
|
||||
#endif
|
||||
syscall_func func; /* the function address of system call */
|
||||
};
|
||||
|
||||
/* system variable table */
|
||||
struct shell_sysvar {
|
||||
const char *name; /* the name of variable */
|
||||
#if defined(SHELL_USING_DESCRIPTION)
|
||||
const char *desc; /* description of system variable */
|
||||
#endif
|
||||
uint8_t type; /* the type of variable */
|
||||
void *var; /* the address of variable */
|
||||
};
|
||||
|
||||
#ifdef SHELL_USING_DESCRIPTION
|
||||
#define SHELL_FUNCTION_EXPORT_CMD(name, cmd, desc) \
|
||||
const char __fsym_##cmd##_name[] __attribute__((section(".rodata.name"))) = #cmd; \
|
||||
const char __fsym_##cmd##_desc[] __attribute__((section(".rodata.name"))) = #desc; \
|
||||
__attribute__((used)) const struct shell_syscall __fsym_##cmd __attribute__((section("FSymTab"))) = { \
|
||||
__fsym_##cmd##_name, \
|
||||
__fsym_##cmd##_desc, \
|
||||
(syscall_func)&name \
|
||||
};
|
||||
|
||||
#define SHELL_VAR_EXPORT(name, type, desc) \
|
||||
const char __vsym_##name##_name[] __attribute__((section(".rodata.name"))) = #name; \
|
||||
const char __vsym_##name##_desc[] __attribute__((section(".rodata.name"))) = #desc; \
|
||||
__attribute__((used)) const struct shell_sysvar __vsym_##name __attribute__((section("VSymTab"))) = { \
|
||||
__vsym_##name##_name, \
|
||||
__vsym_##name##_desc, \
|
||||
type, \
|
||||
(void *)&name \
|
||||
};
|
||||
#else
|
||||
#define SHELL_FUNCTION_EXPORT_CMD(name, cmd, desc) \
|
||||
const char __fsym_##cmd##_name[] = #cmd; \
|
||||
__attribute__((used)) const struct shell_syscall __fsym_##cmd __attribute__((section("FSymTab"))) = { \
|
||||
__fsym_##cmd##_name, \
|
||||
(syscall_func)&name \
|
||||
};
|
||||
|
||||
#define SHELL_VAR_EXPORT(name, type, desc) \
|
||||
const char __vsym_##name##_name[] = #name; \
|
||||
__attribute__((used)) const struct shell_sysvar __vsym_##name __attribute__((section("VSymTab"))) = { \
|
||||
__vsym_##name##_name, \
|
||||
type, \
|
||||
(void *)&name \
|
||||
};
|
||||
#endif /* end of SHELL_USING_DESCRIPTION */
|
||||
|
||||
/**
|
||||
* @ingroup shell
|
||||
*
|
||||
* This macro exports a command to module shell.
|
||||
*
|
||||
* @param command the name of command.
|
||||
* @param desc the description of command, which will show in help.
|
||||
*/
|
||||
#define SHELL_CMD_EXPORT(command, desc) \
|
||||
SHELL_FUNCTION_EXPORT_CMD(command, command, desc)
|
||||
#define SHELL_CMD_EXPORT_ALIAS(command, alias, desc) \
|
||||
SHELL_FUNCTION_EXPORT_CMD(command, alias, desc)
|
||||
|
||||
void shell_handler(uint8_t data);
|
||||
int shell_set_prompt(const char *prompt);
|
||||
int shell_set_print(void (*shell_printf)(char *fmt, ...));
|
||||
void shell_init(void);
|
||||
void shell_exe_cmd(uint8_t *cmd, uint16_t len);
|
||||
shell_sig_func_ptr shell_signal(int sig, shell_sig_func_ptr func);
|
||||
#endif
|
||||
47
component/shell/shell_config.h
Executable file
47
component/shell/shell_config.h
Executable file
@ -0,0 +1,47 @@
|
||||
#ifndef __SHELL_CONFIG_H__
|
||||
#define __SHELL_CONFIG_H__
|
||||
|
||||
#ifndef SHELL_DEFAULT_NAME
|
||||
#define SHELL_DEFAULT_NAME "jzhgonha"
|
||||
#endif
|
||||
|
||||
#ifndef SHELL_CONSOLEBUF_SIZE
|
||||
#define SHELL_CONSOLEBUF_SIZE 128
|
||||
#endif
|
||||
|
||||
#ifndef SHELL_PROMPT_SIZE
|
||||
#define SHELL_PROMPT_SIZE 20
|
||||
#endif
|
||||
|
||||
#ifndef SHELL_HISTORY_LINES
|
||||
#define SHELL_HISTORY_LINES 5
|
||||
#endif
|
||||
|
||||
#ifndef SHELL_CMD_SIZE
|
||||
#define SHELL_CMD_SIZE 120
|
||||
#endif
|
||||
|
||||
#ifndef SHELL_ARG_NUM
|
||||
#define SHELL_ARG_NUM 16
|
||||
#endif
|
||||
|
||||
//#define SHELL_USING_FS
|
||||
#define SHELL_USING_COLOR
|
||||
|
||||
#ifndef SHELL_THREAD_STACK_SIZE
|
||||
#define SHELL_THREAD_STACK_SIZE 1024
|
||||
#endif
|
||||
|
||||
#ifndef SHELL_THREAD_PRIO
|
||||
#define SHELL_THREAD_PRIO 5
|
||||
#endif
|
||||
|
||||
#ifndef SHELL_EXEC_THREAD_STACK_SIZE
|
||||
#define SHELL_EXEC_THREAD_STACK_SIZE 1024
|
||||
#endif
|
||||
|
||||
#ifndef SHELL_EXEC_THREAD_PRIO
|
||||
#define SHELL_EXEC_THREAD_PRIO 4
|
||||
#endif
|
||||
|
||||
#endif
|
||||
183
component/shell/shell_freertos.c
Executable file
183
component/shell/shell_freertos.c
Executable file
@ -0,0 +1,183 @@
|
||||
#include "shell.h"
|
||||
#include <FreeRTOS.h>
|
||||
#include "semphr.h"
|
||||
#include "ring_buffer.h"
|
||||
#include "bflb_uart.h"
|
||||
#include "mem.h"
|
||||
|
||||
#if defined(CONFIG_SHELL_EXEC_THREAD) && CONFIG_SHELL_EXEC_THREAD
|
||||
static int shell_exec_argc;
|
||||
static char *shell_exec_argv[SHELL_ARG_NUM + 1];
|
||||
static char shell_exec_line[SHELL_CMD_SIZE];
|
||||
static ptrdiff_t shell_exec_line_diff;
|
||||
TaskHandle_t shell_exec_handle;
|
||||
static ATTR_NOCACHE_RAM_SECTION volatile bool shell_exec_end = true;
|
||||
|
||||
static void shell_exec_task(void *pvParameters)
|
||||
{
|
||||
shell_exec_end = false;
|
||||
__ASM volatile("fence");
|
||||
((cmd_function_t)(pvParameters))(shell_exec_argc, shell_exec_argv);
|
||||
shell_exec_end = true;
|
||||
__ASM volatile("fence");
|
||||
vTaskDelete(shell_exec_handle);
|
||||
shell_exec_handle = NULL;
|
||||
}
|
||||
|
||||
void shell_dup_line(char *cmd, uint32_t length)
|
||||
{
|
||||
memcpy(shell_exec_line, cmd, length + 1);
|
||||
shell_exec_line_diff = shell_exec_line - cmd;
|
||||
}
|
||||
|
||||
void shell_abort_exec(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
if (shell_exec_end == false) {
|
||||
shell_exec_end = true;
|
||||
__ASM volatile("fence");
|
||||
vTaskDelete(shell_exec_handle);
|
||||
shell_exec_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int shell_start_exec(cmd_function_t func, int argc, char *argv[])
|
||||
{
|
||||
BaseType_t xReturned;
|
||||
shell_abort_exec(SHELL_SIGINT);
|
||||
shell_exec_argc = argc;
|
||||
|
||||
for (uint8_t i = 0; i < argc; i++) {
|
||||
shell_exec_argv[i] = argv[i] + shell_exec_line_diff;
|
||||
}
|
||||
shell_exec_argv[argc] = NULL;
|
||||
|
||||
__ASM volatile("fence");
|
||||
xReturned = xTaskCreate(shell_exec_task, (char *)"shell_exec_task", SHELL_EXEC_THREAD_STACK_SIZE, func, SHELL_EXEC_THREAD_PRIO, &shell_exec_handle);
|
||||
|
||||
if (xReturned == pdPASS) {
|
||||
return 0;
|
||||
} else {
|
||||
shell_exec_end = true;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static TaskHandle_t shell_handle;
|
||||
SemaphoreHandle_t sem_shell = NULL;
|
||||
|
||||
Ring_Buffer_Type shell_rb;
|
||||
|
||||
uint8_t shell_buffer[512];
|
||||
|
||||
void shell_release_sem(void)
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
if (xPortIsInsideInterrupt()) {
|
||||
int ret = xSemaphoreGiveFromISR(sem_shell, &xHigherPriorityTaskWoken);
|
||||
if (ret == pdPASS) {
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
} else {
|
||||
xSemaphoreGive(sem_shell);
|
||||
}
|
||||
}
|
||||
|
||||
struct bflb_device_s *uart_shell = NULL;
|
||||
|
||||
void uart_shell_isr(int irq, void *arg)
|
||||
{
|
||||
uint32_t intstatus = bflb_uart_get_intstatus(uart_shell);
|
||||
if (intstatus & UART_INTSTS_RX_FIFO) {
|
||||
while (bflb_uart_rxavailable(uart_shell)) {
|
||||
Ring_Buffer_Write_Byte(&shell_rb, bflb_uart_getchar(uart_shell));
|
||||
}
|
||||
shell_release_sem();
|
||||
}
|
||||
if (intstatus & UART_INTSTS_RTO) {
|
||||
while (bflb_uart_rxavailable(uart_shell)) {
|
||||
Ring_Buffer_Write_Byte(&shell_rb, bflb_uart_getchar(uart_shell));
|
||||
}
|
||||
shell_release_sem();
|
||||
bflb_uart_int_clear(uart_shell, UART_INTCLR_RTO);
|
||||
}
|
||||
}
|
||||
|
||||
static void shell_task(void *pvParameters)
|
||||
{
|
||||
uint8_t data;
|
||||
uint32_t len;
|
||||
|
||||
bflb_uart_feature_control(uart_shell, UART_CMD_CLR_RX_FIFO, 0);
|
||||
bflb_uart_rxint_mask(uart_shell, false);
|
||||
bflb_irq_attach(uart_shell->irq_num, uart_shell_isr, NULL);
|
||||
bflb_irq_enable(uart_shell->irq_num);
|
||||
|
||||
while (1) {
|
||||
if (xSemaphoreTake(sem_shell, portMAX_DELAY) == pdTRUE) {
|
||||
len = Ring_Buffer_Get_Length(&shell_rb);
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
Ring_Buffer_Read_Byte(&shell_rb, &data);
|
||||
shell_handler(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void shell_init_with_task(struct bflb_device_s *shell)
|
||||
{
|
||||
vSemaphoreCreateBinary(sem_shell);
|
||||
uart_shell = shell;
|
||||
|
||||
Ring_Buffer_Init(&shell_rb, shell_buffer, sizeof(shell_buffer), NULL, NULL);
|
||||
|
||||
shell_init();
|
||||
xTaskCreate(shell_task, (char *)"shell_task", SHELL_THREAD_STACK_SIZE, NULL, SHELL_THREAD_PRIO, &shell_handle);
|
||||
}
|
||||
|
||||
void shell_exe_cmd(uint8_t *cmd, uint16_t len)
|
||||
{
|
||||
Ring_Buffer_Write(&shell_rb, cmd, len);
|
||||
shell_release_sem();
|
||||
}
|
||||
|
||||
static void ps_cmd(int argc, char **argv)
|
||||
{
|
||||
char *pcWriteBuffer, *info;
|
||||
const char *const pcHeader = "State Priority Stack # Base\r\n********************************************************\r\n";
|
||||
BaseType_t xSpacePadding;
|
||||
|
||||
info = malloc(1536);
|
||||
if (NULL == info) {
|
||||
return;
|
||||
}
|
||||
pcWriteBuffer = info;
|
||||
|
||||
/* Generate a table of task stats. */
|
||||
if (strlcpy(pcWriteBuffer, "Task", 1536) >= 1536)
|
||||
printf("[OS]: strlcpy truncated \r\n");
|
||||
pcWriteBuffer += strlen(pcWriteBuffer);
|
||||
|
||||
/* Minus three for the null terminator and half the number of characters in
|
||||
"Task" so the column lines up with the centre of the heading. */
|
||||
for (xSpacePadding = strlen("Task"); xSpacePadding < (configMAX_TASK_NAME_LEN - 3); xSpacePadding++) {
|
||||
/* Add a space to align columns after the task's name. */
|
||||
*pcWriteBuffer = ' ';
|
||||
pcWriteBuffer++;
|
||||
|
||||
/* Ensure always terminated. */
|
||||
*pcWriteBuffer = 0x00;
|
||||
}
|
||||
if (strlcpy(pcWriteBuffer, pcHeader, 1536 - (pcWriteBuffer - info)) >=
|
||||
1536 - (pcWriteBuffer - info))
|
||||
printf("[OS]: strlcpy truncated \r\n");
|
||||
vTaskList(pcWriteBuffer + strlen(pcHeader));
|
||||
printf("\r\n");
|
||||
printf(info);
|
||||
|
||||
free(info);
|
||||
}
|
||||
SHELL_CMD_EXPORT_ALIAS(ps_cmd, ps, shell ps);
|
||||
11
example/shell/shell_no_os/CMakeLists.txt
Normal file
11
example/shell/shell_no_os/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
include(proj.conf)
|
||||
|
||||
project(${EXAMPLE_NAME} VERSION 0.1)
|
||||
add_executable(${EXAMPLE_NAME}.elf main.c)
|
||||
|
||||
include_directories(.)
|
||||
|
||||
add_subdirectory(${SDK_BASE_DIR} sdk)
|
||||
target_link_libraries(${EXAMPLE_NAME}.elf sdk)
|
||||
18
example/shell/shell_no_os/Makefile
Normal file
18
example/shell/shell_no_os/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
EXAMPLE_BASE_DIR ?= $(shell realpath .)
|
||||
EXAMPLE_NAME := $(notdir $(patsubst %/,%,$(CURDIR)))
|
||||
SDK_BASE_DIR ?= $(shell realpath ./../../..)
|
||||
|
||||
export SDK_BASE_DIR
|
||||
export EXAMPLE_NAME
|
||||
export EXAMPLE_BASE_DIR
|
||||
|
||||
GCC_PATH := $(shell which arm-none-eabi-gcc)
|
||||
CROSS_COMPILE := $(patsubst %gcc,%,$(GCC_PATH))
|
||||
ifeq ($(GCC_PATH),)
|
||||
$(error arm-none-eabi-gcc not found in PATH. Please install the ARM toolchain.)
|
||||
endif
|
||||
|
||||
# add custom cmake definition
|
||||
#cmake_definition+=-Dxxx=sss
|
||||
|
||||
include $(SDK_BASE_DIR)/project.build
|
||||
42
example/shell/shell_no_os/main.c
Normal file
42
example/shell/shell_no_os/main.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include "resets.h"
|
||||
#include "timer.h"
|
||||
#include "gpio.h"
|
||||
#include "uart.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "mem.h"
|
||||
#include "shell.h"
|
||||
|
||||
#define LED_PIN (25)
|
||||
#define LED_TIME (500 * 1000) /* 500ms */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
reset_unreset_blocks_wait(RESETS_BLOCK_IO_BANK0 | RESETS_BLOCK_UART0 | RESETS_BLOCK_TIMER);
|
||||
gpio_init(0, GPIO_FUNC_UART | GPIO_PULL_UP | GPIO_DRIVE_4MA); /* UART_TX pin */
|
||||
gpio_init(1, GPIO_FUNC_UART | GPIO_PULL_UP | GPIO_SCHMITT | GPIO_PAD_IE | GPIO_PAD_OD); /* UART_RX pin */
|
||||
uart_init(uart0_hw, 6 * 1000 * 1000, UART_DATABITS_8 | UART_PARITY_NONE | UART_STOPBITS_1);
|
||||
printf("shell example\r\n");
|
||||
|
||||
kmem_init((void *)0x20030000, 64 * 1024);
|
||||
shell_init();
|
||||
while(1) {
|
||||
int c = uart_get_char(uart0_hw);
|
||||
if (c >= 0) {
|
||||
shell_handler((char)c);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shell_test(int argc, char **argv)
|
||||
{
|
||||
printf("shell test, argc=%d:\r\n", argc);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
printf("argv[%d] = %s\r\n", i, argv[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
return 0;
|
||||
}
|
||||
SHELL_CMD_EXPORT_ALIAS(shell_test, test, shell test.);
|
||||
1
example/shell/shell_no_os/proj.conf
Normal file
1
example/shell/shell_no_os/proj.conf
Normal file
@ -0,0 +1 @@
|
||||
set(CONFIG_TLSF 1)
|
||||
14
flash.ld
14
flash.ld
@ -15,6 +15,7 @@ PHDRS
|
||||
isr_reset PT_LOAD FLAGS(6); /* R + X */
|
||||
text PT_LOAD FLAGS(5); /* R + X */
|
||||
rodata PT_LOAD FLAGS(6); /* R + W */
|
||||
shell PT_LOAD FLAGS(6); /* R + W */
|
||||
data PT_LOAD FLAGS(6); /* R + W */
|
||||
bss PT_LOAD FLAGS(6); /* R + W */
|
||||
}
|
||||
@ -49,6 +50,19 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
} >FLASH :rodata
|
||||
|
||||
.shell :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__fsymtab_start = .;
|
||||
KEEP(*(FSymTab))
|
||||
__fsymtab_end = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
__vsymtab_start = .;
|
||||
KEEP(*(VSymTab))
|
||||
__vsymtab_end = .;
|
||||
} >FLASH :shell
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user