Command System
Categories:
6 minute read
Command Structure
All XWSH commands are defined using the struct xwsh_cmd structure (xwmd/cli/xwsh/mi.h:21):
struct xwsh_cmd {
char * name; /**< Command name */
xwer_t (*func)(xwsz_t argc, char ** argv); /**< Command function */
char * desc; /**< Command description */
};
Field Descriptions
| Field | Type | Description |
|---|---|---|
name |
char * |
Command name string (case-sensitive) |
func |
Function pointer | Command handler function, accepts argument count and array |
desc |
char * |
Command description, displayed in help information |
Command Handler Function Signature
xwer_t cmd_handler(xwsz_t argc, char ** argv);
argc: Number of arguments (including the command name itself,argv[0])argv: Argument pointer array, each element points to a\0-terminated string- Return value:
XWOK(0) indicates success, negative value indicates error code
Built-in Commands
XWSH has four built-in basic commands, defined in xwmd/cli/xwsh/cmd.c.
1. help - Show Help Information
Function: Displays the names and descriptions of all available commands (built-in + external).
Usage:
help
Example Output:
--------------------------------------------
help show this help
clear clear screen
rd read memory
wr write memory
mycmd my custom command
Implementation (xwsh_cmd_help()):
xwer_t xwsh_cmd_help(xwsz_t argc, char ** argv)
{
XWOS_UNUSED(argc);
XWOS_UNUSED(argv);
xwsh_show_all_cmds(); // Call core function to display command list
return XWOK;
}
2. clear - Clear Screen
Function: Uses ANSI escape sequences to clear the terminal screen and move the cursor to the top-left corner.
Usage:
clear
ANSI Escape Sequences:
\e[2J: Clear entire screen\e[0;0H: Move cursor to row 0, column 0
Implementation (xwsh_cmd_clear()):
xwer_t xwsh_cmd_clear(xwsz_t argc, char ** argv)
{
XWOS_UNUSED(argc);
XWOS_UNUSED(argv);
printf("\e[2J"); // Clear screen
printf("\e[0;0H"); // Cursor home
return XWOK;
}
3. rd - Read Memory
Function: Displays the content of a specified memory area in hexadecimal and ASCII format.
Usage:
rd <address hex> [size decimal]
Parameters:
| Parameter | Format | Default | Description |
|---|---|---|---|
| Address | Hexadecimal | None | Starting address of the memory to read |
| Size | Decimal | 1 | Number of bytes to read |
Examples:
rd 0x90000000 # Read 1 byte at 0x90000000
rd 0x90000000 16 # Read 16 bytes at 0x90000000
rd 0x20000000 256 # Read 256 bytes at 0x20000000
Output Format:
origin address: 0x90000000
00000000: 12 34 56 78 9a bc de f0 11 22 33 44 55 66 77 88 |.4Vx....."3DUfw.|
00000010: aa bb cc dd ee ff 00 11 22 33 44 55 66 77 88 99 |........"3DUfw..|
Format Description:
- 16 bytes per line
- Left: Offset (hexadecimal)
- Middle: Hexadecimal values (extra space after every 8 bytes)
- Right: ASCII representation (non-printable characters shown as
.)
4. wr - Write Memory
Function: Writes data to a specified memory address.
Usage:
wr <address hex> <value hex> [b|w|l]
Parameters:
| Parameter | Format | Default | Description |
|---|---|---|---|
| Address | Hexadecimal | None | Memory address to write to |
| Value | Hexadecimal | None | Value to write |
| Size | Character | l |
Write size: b (byte), w (word), l (long word) |
Examples:
wr 0x90000000 0x1234 w # Write 0x1234 (2 bytes) to 0x90000000
wr 0x90000000 0x55 b # Write 0x55 (1 byte) to 0x90000000
wr 0x90000000 0xdeadbeef # Write 0xdeadbeef (4 bytes) to 0x90000000
Size Reference:
| Option | Size | Corresponding Type | Address Alignment |
|---|---|---|---|
b |
1 byte | xwu8_t |
Any |
w |
2 bytes | xwu16_t |
2-byte aligned |
l |
4 bytes | xwu32_t |
4-byte aligned |
Adding External Commands
Users can add custom commands via the xwsh_set_ext_cmd_table() function.
1. Define the Command Structure Array
#include "xwmd/cli/xwsh/mi.h"
xwer_t my_test_cmd(xwsz_t argc, char ** argv)
{
printf("My test command executed!\r\n");
printf("argc: %d\r\n", argc);
for (xwsz_t i = 0; i < argc; i++) {
printf("argv[%d]: %s\r\n", i, argv[i]);
}
return XWOK;
}
xwer_t my_calc_cmd(xwsz_t argc, char ** argv)
{
if (argc != 3) {
printf("Usage: calc <num1> <num2>\r\n");
return -EINVAL;
}
xws32_t a, b;
sscanf(argv[1], "%d", &a);
sscanf(argv[2], "%d", &b);
printf("%d + %d = %d\r\n", a, b, a + b);
return XWOK;
}
const struct xwsh_cmd my_cmds[] = {
{ .name = "test", .func = my_test_cmd, .desc = "my test command" },
{ .name = "calc", .func = my_calc_cmd, .desc = "simple calculator" },
};
2. Register the Command Table
Timing: Must be called before XWSH starts (xwsh_start() or xwsh_init()).
xwer_t rc = xwsh_set_ext_cmd_table(my_cmds,
sizeof(my_cmds) / sizeof(my_cmds[0]));
if (rc < 0) {
printf("Failed to set command table: %d\r\n", rc);
}
3. Clear the Command Table
To remove all external commands, pass NULL and 0:
xwsh_set_ext_cmd_table(NULL, 0); // Clear external command table
Duplicate Name Checking Mechanism
The xwsh_set_ext_cmd_table() function performs strict duplicate name checking to ensure command name uniqueness.
Checking Rules
-
External commands vs internal commands
for (j = 0; j < xwsh_cmd_table_size; j++) { if (!strcmp(cmd[i].name, xwsh_cmd_table[j].name)) { rc = -EEXIST; // Duplicate with built-in command goto err_duplicate; } } -
Between external commands
for (j = 0; j < i; j++) { if (!strcmp(cmd[i].name, cmd[j].name)) { rc = -EEXIST; // Duplicate among external commands goto err_duplicate; } }
Error Handling
| Error Code | Meaning | Handling Suggestion |
|---|---|---|
-EEXIST |
Command name already exists | Change command name or remove conflicting command |
-EINVAL |
Invalid parameter (cmd is NULL but num is not 0) |
Check parameter logic |
Naming Suggestions
- Use lowercase letters: Keep consistent with built-in commands
- Avoid special characters: Only use letters, numbers, underscores
- Be concise and clear: Command name should reflect functionality
- Moderate length: Recommended 2-10 characters
Command Execution Flow
1. Command Lookup (xwsh_find_cmd())
const struct xwsh_cmd * xwsh_find_cmd(char * name)
{
// 1. Check built-in command table
for (i = 0; i < xwsh_cmd_table_size; i++) {
if (!strcmp(name, xwsh_cmd_table[i].name)) {
return &xwsh_cmd_table[i];
}
}
// 2. Check external command table
if ((NULL != xwsh_ext_cmd_table) && (0 != xwsh_ext_cmd_table_size)) {
for (i = 0; i < xwsh_ext_cmd_table_size; i++) {
if (!strcmp(name, xwsh_ext_cmd_table[i].name)) {
return &xwsh_ext_cmd_table[i];
}
}
}
return NULL; // Command not found
}
2. Command Execution (xwsh_run_cmdline())
xwer_t xwsh_run_cmdline(char * line)
{
// 1. Split command line
rc = xwsh_split_cmdline(line, &argc, argv, XWSH_MAX_PARAM_NUM);
// 2. Find command
cmd = xwsh_find_cmd(argv[0]);
// 3. Execute command
if (cmd) {
if (cmd->func) {
rc = cmd->func(argc, argv); // Call command handler function
} else {
printf("cmd %s not implemented.\r\n", cmd->name);
}
} else if (argv[0]) {
printf("\r\ncan't find cmd %s.\r\n", argv[0]);
}
return rc;
}
Best Practices
1. Command Design Principles
- Single Responsibility: Each command should complete only one clear function
- Clear Help: Command descriptions should concisely explain functionality
- Parameter Validation: Validate parameter validity in the command handler function
- Error Feedback: Provide meaningful error messages
2. Memory Safety
xwer_t safe_memory_cmd(xwsz_t argc, char ** argv)
{
xwptr_t addr;
// Argument count check
if (argc != 2) {
printf("Usage: %s <address>\r\n", argv[0]);
return -EINVAL;
}
// Address format validation
if (sscanf(argv[1], "%lx", &addr) != 1) {
printf("Invalid address format\n");
return -EINVAL;
}
// Address range check (optional)
if (addr < 0x20000000 || addr >= 0x24000000) {
printf("Address out of valid range\n");
return -EACCES;
}
// Execute operation
// ...
return XWOK;
}
3. Performance Considerations
- Avoid long blocking: Command execution time should be as short as possible
- Minimize memory allocation: Use stack variables instead of heap allocation
- Optimize output: Avoid extensive string operations and formatting
Debugging Tips
1. Command Debug Output
xwer_t debug_cmd(xwsz_t argc, char ** argv)
{
#ifdef XWSH_DBG
xwsz_t i;
xwlogf(D, "XWSH.CMD", "argc: %d\r\n", argc);
for (i = 0; i < argc; i++) {
xwlogf(D, "XWSH.CMD", "argv[%d]: %s\r\n", i, argv[i]);
}
#endif
// Command logic
return XWOK;
}
2. Enable Debug Mode
Uncomment #define XWSH_DBG in core.c and readline.c to enable detailed debug output.