Command System

XWSH Command System: Built-in command details, external command adding methods, and duplicate name checking mechanism.

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

  1. 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;
            }
    }
    
  2. 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.