1.新增msh组件(类Shell工具)。
This commit is contained in:
73
Kconfig
73
Kconfig
@@ -1,26 +1,52 @@
|
||||
mainmenu "mr-library"
|
||||
|
||||
menu "Device configure"
|
||||
# Heap
|
||||
config MR_CFG_HEAP_SIZE
|
||||
int "Heap size (Bytes)"
|
||||
default 4096
|
||||
range 32 2147483647
|
||||
help
|
||||
"Size of dynamic memory for system."
|
||||
|
||||
config MR_CFG_PRINTF_BUFSZ
|
||||
int "Printf buffer size"
|
||||
default 128
|
||||
range 32 2147483647
|
||||
help
|
||||
"Size of the buffer used by the printf function."
|
||||
"This option sets the size of the heap used by the library."
|
||||
|
||||
# Assert
|
||||
config MR_USING_ASSERT
|
||||
bool "Use assert"
|
||||
default y
|
||||
help
|
||||
"Use this option allows the use of assert statements in the code."
|
||||
|
||||
# Console
|
||||
config MR_USING_CONSOLE
|
||||
bool "Use console"
|
||||
default y
|
||||
help
|
||||
"Use this option allows for the use of the console."
|
||||
|
||||
menu "Console configure"
|
||||
depends on MR_USING_CONSOLE
|
||||
|
||||
config MR_CFG_PRINTF_BUFSZ
|
||||
int "Printf buffer size"
|
||||
default 128
|
||||
range 32 2147483647
|
||||
help
|
||||
"This option sets the buffer size used by the printf function."
|
||||
|
||||
config MR_CFG_CONSOLE_NAME
|
||||
string "Console device name"
|
||||
default "serial1"
|
||||
help
|
||||
"This option sets the name of the console device."
|
||||
|
||||
config MR_USING_CONSOLE_NONBLOCK
|
||||
bool "Use console non-blocking"
|
||||
default n
|
||||
help
|
||||
"Use this option allows for the use of the console device in non-blocking mode."
|
||||
endmenu
|
||||
|
||||
# Log
|
||||
config MR_USING_LOG
|
||||
bool "Use log"
|
||||
default y
|
||||
@@ -67,19 +93,20 @@ menu "Device configure"
|
||||
"Use this option allows for the use of success log."
|
||||
endmenu
|
||||
|
||||
# Device
|
||||
config MR_CFG_NAME_MAX
|
||||
int "Name max length"
|
||||
default 8
|
||||
range 4 1024
|
||||
help
|
||||
"Maximum length of device name."
|
||||
"This option sets the max length of the name."
|
||||
|
||||
config MR_CFG_DESC_MAX
|
||||
int "Descriptors max number"
|
||||
default 64
|
||||
range 16 1024
|
||||
help
|
||||
"Maximum number of descriptors."
|
||||
"This option sets the max number of descriptors."
|
||||
|
||||
config MR_USING_RDWR_CTL
|
||||
bool "Use read/write control"
|
||||
@@ -87,28 +114,6 @@ menu "Device configure"
|
||||
help
|
||||
"Use this option allows for read and write control of devices."
|
||||
|
||||
config MR_USING_CONSOLE
|
||||
bool "Use console"
|
||||
default y
|
||||
help
|
||||
"Use this option allows for the use of the console device."
|
||||
|
||||
menu "Console configure"
|
||||
depends on MR_USING_CONSOLE
|
||||
|
||||
config MR_CFG_CONSOLE_NAME
|
||||
string "Console name"
|
||||
default "serial1"
|
||||
help
|
||||
"Name of the console device."
|
||||
|
||||
config MR_USING_CONSOLE_NONBLOCK
|
||||
bool "Use console non-blocking"
|
||||
default n
|
||||
help
|
||||
"Use this option allows for the use of the console device in non-blocking mode."
|
||||
endmenu
|
||||
|
||||
config MR_USING_ADC
|
||||
bool "Use ADC device"
|
||||
default n
|
||||
@@ -222,6 +227,8 @@ menu "Device configure"
|
||||
"Use this option allows for the use of Timer devices."
|
||||
endmenu
|
||||
|
||||
# Driver
|
||||
source "driver/Kconfig"
|
||||
|
||||
source "components/Kconfig"
|
||||
# Components
|
||||
source "components/Kconfig"
|
||||
|
||||
@@ -1,3 +1,46 @@
|
||||
menu "No components configure"
|
||||
menu "Components configure"
|
||||
|
||||
# Msh
|
||||
config MR_USING_MSH
|
||||
bool "Use msh"
|
||||
default y
|
||||
help
|
||||
"Use this option allows for the use of the shell."
|
||||
|
||||
menu "Msh configure"
|
||||
depends on MR_USING_MSH
|
||||
config MR_CFG_MSH_BUFSZ
|
||||
int "Msh buffer size"
|
||||
default 32
|
||||
range 16 1024
|
||||
help
|
||||
"This option sets the buffer size used by the shell."
|
||||
|
||||
config MR_CFG_MSH_NAME_MAX
|
||||
int "Msh command name max length"
|
||||
default 8
|
||||
range 8 64
|
||||
help
|
||||
"This option sets the max length of the command name."
|
||||
|
||||
config MR_CFG_MSH_ARGS_MAX
|
||||
int "Msh argument max number"
|
||||
default 4
|
||||
range 1 16
|
||||
help
|
||||
"This option sets the max number of arguments."
|
||||
|
||||
config MR_CFG_MSH_PROMPT
|
||||
string "Msh prompt"
|
||||
default "msh>"
|
||||
help
|
||||
"This option sets the prompt of the shell."
|
||||
|
||||
config MR_USING_MSH_ECHO
|
||||
bool "Use msh echo"
|
||||
default y
|
||||
help
|
||||
"Use this option allows for the use of the echo in the msh."
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
338
components/msh.c
Normal file
338
components/msh.c
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* @copyright (c) 2023, MR Development Team
|
||||
*
|
||||
* @license SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* @date 2023-12-25 MacRsh First version
|
||||
*/
|
||||
|
||||
#include "include/components/msh.h"
|
||||
|
||||
#ifdef MR_USING_MSH
|
||||
|
||||
/**
|
||||
* @brief MSH structure.
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
#ifndef MR_CFG_MSH_BUFSZ
|
||||
#define MR_CFG_MSH_BUFSZ (32)
|
||||
#endif /* MR_CFG_MSHELL_BUFSZ */
|
||||
char buf[MR_CFG_MSH_BUFSZ]; /**< Buffer for reading */
|
||||
#ifndef MR_CFG_MSH_ARGS_MAX
|
||||
#define MR_CFG_MSH_ARGS_MAX (8)
|
||||
#endif /* MR_CFG_MSH_ARGS_MAX */
|
||||
char *args[MR_CFG_MSH_ARGS_MAX]; /**< Arguments for the msh */
|
||||
size_t cursor; /**< Cursor position */
|
||||
size_t bytes; /**< Bytes in the buffer */
|
||||
char key_buf[8]; /**< Buffer for keys */
|
||||
size_t key_bytes; /**< Bytes in the key buffer */
|
||||
int echo; /**< Echo or not */
|
||||
} msh;
|
||||
|
||||
MR_MSH_EXPORT(start, MR_NULL, MR_NULL, "0");
|
||||
MR_MSH_EXPORT(end, MR_NULL, MR_NULL, "1.end");
|
||||
|
||||
#define MSH_CURSOR_FORWARD(x) "\x1b["#x"D"
|
||||
#define MSH_CURSOR_BACKWARD(x) "\x1b["#x"C"
|
||||
#define MSH_DELETE_CHAR(x) "\x1b["#x"P"
|
||||
#define MSH_INSERT_CHAR(x) "\x1b["#x"@"
|
||||
|
||||
static void msh_new_line(void)
|
||||
{
|
||||
/* Move the cursor to the beginning of the line and print a new line */
|
||||
if (msh.echo == MR_ENABLE)
|
||||
{
|
||||
#ifndef MR_CFG_MSH_PROMPT
|
||||
#define MR_CFG_MSH_PROMPT "msh>"
|
||||
#endif /* MR_CFG_MSH_PROMPT */
|
||||
mr_printf("\r\n"MR_CFG_MSH_PROMPT" ");
|
||||
}
|
||||
msh.cursor = 0;
|
||||
msh.bytes = 0;
|
||||
msh.key_bytes = 0;
|
||||
}
|
||||
|
||||
static void msh_move_cursor_left(void)
|
||||
{
|
||||
if (msh.cursor > 0)
|
||||
{
|
||||
msh.cursor--;
|
||||
mr_printf(MSH_CURSOR_FORWARD(1));
|
||||
}
|
||||
}
|
||||
|
||||
static void msh_move_cursor_right(void)
|
||||
{
|
||||
if (msh.cursor < msh.bytes)
|
||||
{
|
||||
msh.cursor++;
|
||||
mr_printf(MSH_CURSOR_BACKWARD(1));
|
||||
}
|
||||
}
|
||||
|
||||
static void msh_delete_char(void)
|
||||
{
|
||||
if (msh.cursor > 0)
|
||||
{
|
||||
/* Move the cursor forward and delete the character */
|
||||
mr_printf(MSH_CURSOR_FORWARD(1)MSH_DELETE_CHAR(1));
|
||||
|
||||
/* Check if you need to remove characters from the middle */
|
||||
if (msh.cursor != msh.bytes)
|
||||
{
|
||||
/* Readjust string */
|
||||
for (size_t i = msh.cursor; i < msh.bytes; i++)
|
||||
{
|
||||
msh.buf[i - 1] = msh.buf[i];
|
||||
}
|
||||
}
|
||||
msh.cursor--;
|
||||
msh.bytes--;
|
||||
}
|
||||
}
|
||||
|
||||
static void msh_insert_char(char c)
|
||||
{
|
||||
/* Check if there is enough space */
|
||||
if ((msh.bytes + 1) == MR_CFG_MSH_BUFSZ)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check whether the cursor is at the end of the buffer */
|
||||
if (msh.cursor == msh.bytes)
|
||||
{
|
||||
msh.buf[msh.bytes] = c;
|
||||
} else
|
||||
{
|
||||
/* Insert the character */
|
||||
mr_printf(MSH_INSERT_CHAR(1));
|
||||
|
||||
/* Readjust string */
|
||||
for (size_t i = msh.cursor; i < msh.bytes; i++)
|
||||
{
|
||||
msh.buf[i + 1] = msh.buf[i];
|
||||
}
|
||||
msh.buf[msh.cursor] = c;
|
||||
}
|
||||
msh.cursor++;
|
||||
msh.bytes++;
|
||||
msh.buf[msh.bytes] = '\0';
|
||||
|
||||
/* Echo the character */
|
||||
if (msh.echo == MR_ENABLE)
|
||||
{
|
||||
mr_printf("%c", c);
|
||||
}
|
||||
}
|
||||
|
||||
static void msh_parse_cmd(void)
|
||||
{
|
||||
/* Check whether the buffer is empty */
|
||||
if (msh.bytes == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find the command */
|
||||
char *cmd = strchr(msh.buf, ' ');
|
||||
if (cmd != MR_NULL)
|
||||
{
|
||||
*cmd = '\0';
|
||||
}
|
||||
|
||||
/* Execute the command */
|
||||
for (const struct mr_msh_cmd *msh_cmd = ((&_mr_msh_cmd_start) + 1); msh_cmd < &_mr_msh_cmd_end; msh_cmd++)
|
||||
{
|
||||
if (strcmp(msh_cmd->name, msh.buf) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Restore the command */
|
||||
if (cmd != MR_NULL)
|
||||
{
|
||||
*cmd = ' ';
|
||||
}
|
||||
|
||||
/* Parse the arguments */
|
||||
char *old_arg = msh.buf;
|
||||
int args_num = 0;
|
||||
for (args_num = 0; args_num < MR_ARRAY_SIZE(msh.args); args_num++)
|
||||
{
|
||||
char *arg = strchr(old_arg, ' ');
|
||||
if (arg == MR_NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
*arg = '\0';
|
||||
msh.args[args_num] = ++arg;
|
||||
old_arg = arg;
|
||||
}
|
||||
|
||||
mr_printf("\r\n");
|
||||
msh_cmd->call(args_num, msh.args);
|
||||
}
|
||||
}
|
||||
|
||||
#define KEY_BACKSPACE "\x7f"
|
||||
#define KEY_ENTER "\r"
|
||||
#define KEY_LEFT "\x1b[D"
|
||||
#define KEY_RIGHT "\x1b[C"
|
||||
#define KEY_DELETE "\x1B[3~"
|
||||
|
||||
#define MSH_IS_PRINTABLE(c) ((c) >= 0x20 && (c) <= 0x7e)
|
||||
#define MSH_IS_ESC_KEY(c) ((c) == 0x1b)
|
||||
#define MSH_IS_END_KEY(c) \
|
||||
((((c) >= 'A') && ((c) <= 'D')) || (((c) >= 'P') && ((c) <= 'S')) || ((c) >= '~') || ((c) == 'H') || ((c) == 'F'))
|
||||
|
||||
static void msh_key_enter(void)
|
||||
{
|
||||
msh_parse_cmd();
|
||||
msh_new_line();
|
||||
}
|
||||
|
||||
static void msh_key_backspace(void)
|
||||
{
|
||||
msh_delete_char();
|
||||
}
|
||||
|
||||
static void msh_key_left(void)
|
||||
{
|
||||
msh_move_cursor_left();
|
||||
}
|
||||
|
||||
static void msh_key_right(void)
|
||||
{
|
||||
msh_move_cursor_right();
|
||||
}
|
||||
|
||||
static void msh_key_delete(void)
|
||||
{
|
||||
msh_move_cursor_right();
|
||||
msh_delete_char();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Msh long character key map structure.
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *key;
|
||||
void (*exec)(void);
|
||||
} msh_key_map[] =
|
||||
{
|
||||
{KEY_ENTER, msh_key_enter},
|
||||
{KEY_BACKSPACE, msh_key_backspace},
|
||||
{KEY_LEFT, msh_key_left},
|
||||
{KEY_RIGHT, msh_key_right},
|
||||
{KEY_DELETE, msh_key_delete},
|
||||
};
|
||||
|
||||
static void msh_parse_key(char c)
|
||||
{
|
||||
int parse_flag = MR_DISABLE;
|
||||
|
||||
/* key-bytes: 0 -> short character key, 1 -> long character key */
|
||||
if (msh.key_bytes == 0)
|
||||
{
|
||||
if (MSH_IS_ESC_KEY(c))
|
||||
{
|
||||
msh.key_buf[msh.key_bytes++] = c;
|
||||
} else
|
||||
{
|
||||
msh.key_buf[msh.key_bytes++] = c;
|
||||
msh.key_buf[msh.key_bytes] = '\0';
|
||||
parse_flag = MR_ENABLE;
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (MSH_IS_END_KEY(c))
|
||||
{
|
||||
msh.key_buf[msh.key_bytes++] = c;
|
||||
msh.key_buf[msh.key_bytes] = '\0';
|
||||
parse_flag = MR_ENABLE;
|
||||
} else
|
||||
{
|
||||
msh.key_buf[msh.key_bytes++] = c;
|
||||
/* Check whether the key-buffer is full */
|
||||
if (msh.key_bytes >= sizeof(msh.key_buf) - 1)
|
||||
{
|
||||
msh.key_bytes = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the long character key */
|
||||
if (parse_flag == MR_ENABLE)
|
||||
{
|
||||
for (size_t i = 0; i < MR_ARRAY_SIZE(msh_key_map); i++)
|
||||
{
|
||||
if (strncmp(msh.key_buf, msh_key_map[i].key, msh.key_bytes) == 0)
|
||||
{
|
||||
msh_key_map[i].exec();
|
||||
break;
|
||||
}
|
||||
}
|
||||
msh.key_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int msh_cmd_help(int argc, void *args)
|
||||
{
|
||||
/* Print the help */
|
||||
for (const struct mr_msh_cmd *msh_cmd = ((&_mr_msh_cmd_start) + 1); msh_cmd < &_mr_msh_cmd_end; msh_cmd++)
|
||||
{
|
||||
mr_printf("%-*s - %s\r\n", MR_CFG_MSH_NAME_MAX, msh_cmd->name, msh_cmd->help);
|
||||
}
|
||||
return MR_EOK;
|
||||
}
|
||||
|
||||
static int msh_cmd_clear(int argc, void *args)
|
||||
{
|
||||
mr_printf("\033c");
|
||||
msh_new_line();
|
||||
return MR_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function receives a character for the msh.
|
||||
*
|
||||
* @param c The character to receive.
|
||||
*/
|
||||
void mr_msh_recv_char(char c)
|
||||
{
|
||||
/* Judgments are characters and keys */
|
||||
if (MSH_IS_PRINTABLE(c) && (msh.key_bytes == 0))
|
||||
{
|
||||
msh_insert_char(c);
|
||||
} else
|
||||
{
|
||||
msh_parse_key(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function initialize the msh.
|
||||
*
|
||||
* @return MR_ERR_OK on success, otherwise an error code.
|
||||
*/
|
||||
int mr_msh_init(void)
|
||||
{
|
||||
#ifdef MR_USING_MSH_ECHO
|
||||
msh.echo = MR_ENABLE;
|
||||
#endif /* MR_USING_MSH_ECHO */
|
||||
/* Print the prompt */
|
||||
msh_new_line();
|
||||
return MR_EOK;
|
||||
}
|
||||
MR_INIT_DEV_EXPORT(mr_msh_init);
|
||||
|
||||
/**
|
||||
* @brief Exports default MSH commands.
|
||||
*/
|
||||
MR_MSH_CMD_EXPORT(help, msh_cmd_help, "Show help information.");
|
||||
MR_MSH_CMD_EXPORT(clear, msh_cmd_clear, "Clear the screen.");
|
||||
|
||||
#endif /* MR_USING_MSH */
|
||||
77
include/components/msh.h
Normal file
77
include/components/msh.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* @copyright (c) 2023, MR Development Team
|
||||
*
|
||||
* @license SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* @date 2023-12-25 MacRsh First version
|
||||
*/
|
||||
|
||||
#ifndef _MSH_H_
|
||||
#define _MSH_H_
|
||||
|
||||
#include "include/mr_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef MR_USING_MSH
|
||||
|
||||
/**
|
||||
* @brief MSH command structure.
|
||||
*/
|
||||
struct mr_msh_cmd
|
||||
{
|
||||
const char *name; /**< Name */
|
||||
int (*call)(int argc, void *args); /**< Callback function */
|
||||
const char *help; /**< Help information */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Exports a MSH command with level.
|
||||
*
|
||||
* @param name The name of the command.
|
||||
* @param fn The callback function.
|
||||
* @param help The help information.
|
||||
* @param level The level of the command.
|
||||
*/
|
||||
#define MR_MSH_EXPORT(name, fn, help, level) \
|
||||
MR_USED const struct mr_msh_cmd _mr_msh_cmd_##name MR_SECTION(".msh_cmd."level) = {#name, fn, help};
|
||||
|
||||
/**
|
||||
* @brief Exports a MSH command.
|
||||
*
|
||||
* @param name The name of the command.
|
||||
* @param fn The callback function.
|
||||
* @param help The help information.
|
||||
*/
|
||||
#define MR_MSH_CMD_EXPORT(name, fn, help) \
|
||||
MR_MSH_EXPORT(name, fn, help, "1")
|
||||
|
||||
/**
|
||||
* @brief Parses the arguments for the MSH command.
|
||||
*
|
||||
* @param index The index of the argument.
|
||||
*
|
||||
* @note This macro must be called from a function where the first parameter is argc and the second parameter is args.
|
||||
* 1 -> argc, 2 -> args.
|
||||
*/
|
||||
#define MR_MSH_PARSE_ARGS(index) \
|
||||
(((index) < (argc)) ? (((const char **)(args))[index]) : MR_NULL)
|
||||
|
||||
/**
|
||||
* @addtogroup Msh.
|
||||
* @{
|
||||
*/
|
||||
void mr_msh_recv_char(char c);
|
||||
/** @} */
|
||||
#else
|
||||
#define MR_MSH_EXPORT(name, fn, help, level)
|
||||
#define MR_MSH_CMD_EXPORT(name, fn, help)
|
||||
#endif /* MR_USING_MSH */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _MSH_H_ */
|
||||
@@ -15,40 +15,17 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef MR_USING_ADC
|
||||
#include "device/adc.h"
|
||||
#endif
|
||||
|
||||
#ifdef MR_USING_CAN
|
||||
#include "device/can.h"
|
||||
#endif
|
||||
|
||||
#ifdef MR_USING_DAC
|
||||
#include "device/dac.h"
|
||||
#endif
|
||||
|
||||
#ifdef MR_USING_I2C
|
||||
#include "device/i2c.h"
|
||||
#ifdef MR_USING_SOFT_I2C
|
||||
#include "device/soft_i2c.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MR_USING_PIN
|
||||
#include "device/pin.h"
|
||||
#endif
|
||||
|
||||
#ifdef MR_USING_SERIAL
|
||||
#include "device/serial.h"
|
||||
#endif
|
||||
|
||||
#ifdef MR_USING_SPI
|
||||
#include "device/spi.h"
|
||||
#endif
|
||||
|
||||
#ifdef MR_USING_TIMER
|
||||
#include "device/timer.h"
|
||||
#endif
|
||||
|
||||
#include "components/msh.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user