Integration Guide
Categories:
9 minute read
Integration Mode Overview
XWSH provides two integration modes to suit different application scenarios and resource constraints. The choice depends on thread management requirements, resource availability, and system architecture.
Mode Comparison Matrix
| Feature | Standalone Thread Mode (xwsh_start()) |
Embedded Mode (xwsh_init() + xwsh_loop()) |
|---|---|---|
| Thread Resources | Requires dedicated stack space (1-2 KB) | Uses caller’s thread stack |
| Thread Management | XWSH internally creates and manages thread | User controls the loop call |
| Priority | XWSH_THD_PRIORITY (realtime priority downgrade) |
Same as caller’s thread |
| Blocking Mode | Thread blocks in xwsh_loop() |
Blocks in user’s loop |
| Freeze Support | Automatic thread freeze support | User needs to handle manually |
| Use Case | Standalone CLI task, system debugging | Integration into existing tasks, resource-constrained environments |
| Code Complexity | Low (automatic management) | Medium (user manages the loop) |
Standalone Thread Mode
Working Principle
Standalone thread mode creates a dedicated thread to run XWSH, managed internally by the XWSH module.
// xwmd/cli/xwsh/mi.c:24
#define XWSH_THD_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 0)
Priority Description:
XWOS_SKD_PRIORITY_RT_MAX: System maximum realtime priorityXWOS_SKD_PRIORITY_DROP(max, n): Downgradenlevels frommaxXWSH_THD_PRIORITY: Realtime priority downgraded 0 levels, ensuring CLI responsiveness
Usage Steps
1. Include Header File
#include "xwmd/cli/xwsh/mi.h"
2. Define Thread Stack
// Recommended stack size: 1-2 KB, depends on command complexity and recursion depth
xwstk_t xwsh_stack[1024]; // 1024 * sizeof(xwstk_t) bytes
3. Add External Commands (Optional)
// Must be called before xwsh_start()
const struct xwsh_cmd my_cmds[] = {
{ .name = "test", .func = my_test_cmd, .desc = "test command" },
};
xwsh_set_ext_cmd_table(my_cmds, 1);
4. Start XWSH
xwer_t rc = xwsh_start(xwsh_stack, sizeof(xwsh_stack));
if (rc < 0) {
// Error handling
printf("Failed to start XWSH: %d\r\n", rc);
}
Thread Main Function
// xwmd/cli/xwsh/mi.c:59
xwer_t xwsh_thd_mainfunc(void * arg)
{
char buf[XWSH_MAXINPUT];
XWOS_UNUSED(arg);
xwsh_init(); // Display logo, initialize readline
while (!xwos_cthd_shld_stop()) {
if (xwos_cthd_shld_frz()) {
xwos_cthd_freeze(); // Support thread freeze
}
xwsh_loop(buf); // Read and execute commands
}
return XWOK;
}
Thread Lifecycle:
- Create thread with priority
XWSH_THD_PRIORITY - Display system logo and version information
- Initialize CherryRL readline library
- Enter main loop, waiting for user input
- Support thread freeze/resume
- Thread stop condition:
xwos_cthd_shld_stop()returns true
Complete Example
#include <xwos/standard.h>
#include "xwmd/cli/xwsh/mi.h"
/* Custom commands */
xwer_t my_info_cmd(xwsz_t argc, char ** argv)
{
XWOS_UNUSED(argc);
XWOS_UNUSED(argv);
printf("System information:\r\n");
printf(" XWSH version: 1.0\r\n");
printf(" Build time: %s %s\r\n", __DATE__, __TIME__);
return XWOK;
}
xwer_t my_echo_cmd(xwsz_t argc, char ** argv)
{
for (xwsz_t i = 1; i < argc; i++) {
printf("%s ", argv[i]);
}
printf("\r\n");
return XWOK;
}
/* Command table */
const struct xwsh_cmd my_cmds[] = {
{ .name = "info", .func = my_info_cmd, .desc = "show system info" },
{ .name = "echo", .func = my_echo_cmd, .desc = "echo arguments" },
};
int main(void)
{
xwstk_t xwsh_stack[1024];
xwer_t rc;
/* Set external command table (must be called before startup) */
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);
return rc;
}
/* Start XWSH */
rc = xwsh_start(xwsh_stack, sizeof(xwsh_stack));
if (rc < 0) {
printf("Failed to start XWSH: %d\r\n", rc);
return rc;
}
/* Main thread executes other tasks */
while (1) {
// Other application logic
xwos_cthd_sleep_ms(1000);
}
return 0;
}
Embedded Mode
Working Principle
Embedded mode integrates XWSH into an existing thread, where user code controls the execution of the command loop.
Usage Steps
1. Include Header File
#include "xwmd/cli/xwsh/mi.h"
2. Add External Commands (Optional)
// Must be called before xwsh_init()
const struct xwsh_cmd my_cmds[] = {
{ .name = "test", .func = my_test_cmd, .desc = "test command" },
};
xwsh_set_ext_cmd_table(my_cmds, 1);
3. Initialize XWSH
xwsh_init(); // Display logo, initialize readline
4. Run Main Loop
char buf[XWSH_MAXINPUT];
while (!exit_condition) {
xwsh_loop(buf);
// Other task logic can be added here
}
Complete Example
#include <xwos/standard.h>
#include "xwmd/cli/xwsh/mi.h"
/* Custom command */
xwer_t my_status_cmd(xwsz_t argc, char ** argv)
{
XWOS_UNUSED(argc);
XWOS_UNUSED(argv);
printf("System status: OK\r\n");
printf("Free memory: %d bytes\r\n", get_free_memory());
return XWOK;
}
/* Command table */
const struct xwsh_cmd my_cmds[] = {
{ .name = "status", .func = my_status_cmd, .desc = "show system status" },
};
/* Main task function */
xwer_t main_task(void * arg)
{
char buf[XWSH_MAXINPUT];
xwer_t rc;
XWOS_UNUSED(arg);
/* Set external command table */
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);
return rc;
}
/* Initialize XWSH */
xwsh_init();
/* Main loop */
while (!xwos_cthd_shld_stop()) {
/* Handle CLI input */
xwsh_loop(buf);
/* Execute other tasks (non-blocking) */
process_background_tasks();
/* Brief sleep to avoid busy-waiting */
xwos_cthd_sleep_ms(10);
}
return XWOK;
}
/* Version with timeout */
xwer_t main_task_with_timeout(void * arg)
{
char buf[XWSH_MAXINPUT];
xwtm_t timeout = 100; // 100ms timeout
XWOS_UNUSED(arg);
xwsh_init();
while (!xwos_cthd_shld_stop()) {
/* Set stdin non-blocking mode (if supported) */
set_stdin_nonblocking();
/* Command loop with timeout */
xwtm_t start = xwos_cthd_get_timestamp();
while ((xwos_cthd_get_timestamp() - start) < timeout) {
xwsh_loop(buf);
}
/* Execute other periodic tasks */
periodic_task();
}
return XWOK;
}
Best Practices
1. Mode Selection Guide
Choose standalone thread mode when:
- You need an independent CLI thread that does not affect the main task’s real-time performance
- System resources are sufficient (extra stack space available)
- CLI requires a specific priority setting
- You want automatic handling of thread freeze/resume
Choose embedded mode when:
- System resources are tight (cannot allocate extra stack space)
- You need to integrate CLI into an existing task loop
- You need finer control over command execution timing
- The application already has a main loop architecture
2. Priority Settings
Standalone Thread Mode Priority Recommendations
// High responsiveness (debugging use)
#define XWSH_HIGH_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 0)
// Medium priority (general use)
#define XWSH_MEDIUM_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 5)
// Low priority (background task)
#define XWSH_LOW_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 10)
Modification Method (edit mi.c:22):
#define XWSH_THD_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 5)
Embedded Mode Priority
The priority of embedded mode depends on the caller’s thread. Recommendations:
- Debug thread: Higher priority, ensures fast response
- Background thread: Lower priority, does not interfere with critical tasks
- Main thread: Set according to application needs
3. Resource Planning
Stack Size Estimation
| Use Case | Recommended Stack Size | Description |
|---|---|---|
| Simple commands | 512-1024 bytes | Basic commands, no recursion |
| Complex commands | 1024-2048 bytes | Formatted output, string operations |
| Recursive commands | 2048+ bytes | Command handler functions may recurse |
Stack Usage Analysis:
// Add stack check in xwsh_thd_mainfunc
xwsz_t stack_used = xwos_cthd_get_stackused();
xwsz_t stack_size = xwos_cthd_get_stacksize();
printf("Stack usage: %d/%d bytes (%.1f%%)\r\n",
stack_used, stack_size,
(stack_used * 100.0) / stack_size);
Memory Footprint Statistics
| Component | Size | Notes |
|---|---|---|
| XWSH code | ~3-5 KB | Depends on compilation optimization |
| Static buffers | ~1.2 KB | Prompt + history |
| Thread stack | 1-2 KB | Required in standalone mode |
| CherryRL | ~1 KB | Library code size |
4. Error Handling
Startup Failure Handling
xwer_t rc = xwsh_start(stack, stack_size);
if (rc < 0) {
switch (rc) {
case -ENOMEM:
printf("Insufficient memory for XWSH thread\r\n");
break;
case -EINVAL:
printf("Invalid stack parameters\r\n");
break;
default:
printf("Failed to start XWSH: %d\r\n", rc);
break;
}
// Fallback to embedded mode or disable CLI
fallback_to_embedded_mode();
}
Command Execution Error Handling
xwer_t safe_cmd_handler(xwsz_t argc, char ** argv)
{
xwer_t rc = XWOK;
// Parameter validation
if (argc < 2) {
printf("Usage: %s <param>\r\n", argv[0]);
rc = -EINVAL;
goto err_param;
}
// Resource availability check
if (!check_resource_available()) {
rc = -ENOMEM;
goto err_resource;
}
// Main logic (may fail)
rc = perform_operation(argv[1]);
if (rc < 0) {
printf("Operation failed: %d\r\n", rc);
goto err_operation;
}
printf("Success\r\n");
return XWOK;
err_operation:
cleanup_operation();
err_resource:
err_param:
return rc;
}
5. Performance Optimization
Reducing Blocking Time
// Non-blocking input check (if platform supports it)
if (stdin_has_data()) {
char buf[XWSH_MAXINPUT];
xwsh_loop(buf);
} else {
// Execute other tasks
process_other_tasks();
}
Command Response Time Optimization
// Step-wise execution for complex commands
xwer_t long_running_cmd(xwsz_t argc, char ** argv)
{
static xwsz_t step = 0;
static xwsz_t total = 100;
if (argc > 1 && strcmp(argv[1], "reset") == 0) {
step = 0;
printf("Reset progress\r\n");
return XWOK;
}
if (step < total) {
printf("Progress: %d/%d\r\n", step + 1, total);
perform_step(step);
step++;
if (step == total) {
printf("Completed\r\n");
}
} else {
printf("Already completed. Use 'cmd reset' to restart.\r\n");
}
return XWOK;
}
Output Buffer Optimization
// Batch output to reduce system calls
void batch_printf(const char *format, ...)
{
static char buffer[256];
va_list args;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
// Actual output
printf("%s", buffer);
}
6. Security Considerations
Input Validation
xwer_t secure_cmd(xwsz_t argc, char ** argv)
{
// Length check
for (xwsz_t i = 0; i < argc; i++) {
if (strlen(argv[i]) > MAX_ARG_LEN) {
printf("Argument %d too long\r\n", i);
return -E2BIG;
}
}
// Content check (injection prevention)
for (xwsz_t i = 0; i < argc; i++) {
if (!is_valid_input(argv[i])) {
printf("Invalid characters in argument %d\r\n", i);
return -EINVAL;
}
}
// Execute safe operation
return XWOK;
}
Permission Control
// Role-based command access control
xwer_t privileged_cmd(xwsz_t argc, char ** argv)
{
if (!current_user_is_admin()) {
printf("Permission denied. Admin required.\r\n");
return -EACCES;
}
// Privileged operation
return XWOK;
}
Debugging and Testing
1. Unit Test Framework
#include "xwmd/cli/xwsh/mi.h"
void test_command_parsing(void)
{
char line[] = "test arg1 arg2 arg3";
xwsz_t argc;
char *argv[XWSH_MAX_PARAM_NUM];
xwer_t rc;
rc = xwsh_split_cmdline(line, &argc, argv, XWSH_MAX_PARAM_NUM);
assert(rc == XWOK);
assert(argc == 4);
assert(strcmp(argv[0], "test") == 0);
assert(strcmp(argv[1], "arg1") == 0);
assert(strcmp(argv[2], "arg2") == 0);
assert(strcmp(argv[3], "arg3") == 0);
printf("Command parsing test passed\r\n");
}
2. Integration Test
void test_xwsh_integration(void)
{
xwstk_t stack[1024];
xwer_t rc;
// Test standalone thread mode
rc = xwsh_start(stack, sizeof(stack));
assert(rc == XWOK);
// Wait for thread to start
xwos_cthd_sleep_ms(100);
// Test command execution (via actual input or mock)
// ...
printf("Integration test passed\r\n");
}
3. Performance Test
void benchmark_command_execution(void)
{
xwtm_t start, end;
xwer_t rc;
char *test_cmds[] = {
"help",
"rd 0x20000000 16",
"wr 0x20000000 0x1234 w",
};
for (xwsz_t i = 0; i < sizeof(test_cmds)/sizeof(test_cmds[0]); i++) {
start = xwos_cthd_get_timestamp();
for (xwsz_t j = 0; j < 1000; j++) {
rc = xwsh_run_cmdline(test_cmds[i]);
assert(rc == XWOK);
}
end = xwos_cthd_get_timestamp();
printf("Command '%s': %lld us per execution\r\n",
test_cmds[i], (end - start) / 1000);
}
}
Frequently Asked Questions
Q1: How to change the prompt?
A: Modify the chry_readline_prompt_edit() calls in readline.c, or implement a custom prompt generation function.
Q2: Are multi-line commands supported?
A: The current version does not support them. You would need to extend the CherryRL configuration or modify the command parsing logic.
Q3: How to increase the history size?
A: Modify XWSH_RL_HISTORY_MAXSIZE in readline.c:33. It must remain a power of 2.
Q4: How to implement command execution timeout?
A: In embedded mode, you can add a timeout check in the loop or use an input function with a timeout.
Q5: How to disable colored output?
A: Modify the chry_readline_prompt_edit() calls and remove SGR (Select Graphic Rendition) attributes.
Q6: Are command aliases supported?
A: Not currently supported, but you can implement them in command handler functions or extend the command lookup logic.
Q7: How to log all executed commands?
A: Add logging after xwsh_run_cmdline() execution, or modify the command execution flow.