Essential Guide to Building a Lightweight Serial Command Line Shell from Scratch in Embedded Development https://mp.weixin.qq.com/s/H0x2QYkhyqoQChgEqm-MwQ
Implementation and Pitfall Guide for Lightweight Command Line Shell in Embedded Development In embedded development, the command line shell (CLI Shell) is the most common and direct way to interact with devices. Its simplicity, efficiency, and low resource consumption make it particularly suitable for resource-constrained scenarios such as MCUs. This article will explore how to build a lightweight shell based on serial communication from scratch and share practical experiences in development and maintenance.
1. Why Do We Need a Command Line Shell? Embedded devices rely on device interaction during development, debugging, testing, and mass production. Compared to complex protocols like Bluetooth and Wi-Fi, the combination of serial communication and command line shell has significant advantages: Simple and Reliable: Physical connections are stable, eliminating the need to handle wireless signal interference Low Resource Consumption: Text-based protocols require minimal memory and bandwidth Cross-Platform Support: Mainstream operating systems provide serial driver support
2. Typical Application Scenarios
1. Quick Debugging and Configuration device_name set KitchenTimer > OK wifi set MyHotSpot WPA2 mypassword > OK
2. Factory Mass Production Testing serial_number burn 12345678 > OK key_test button1 > PASS
3. Automated Testing Integration import serial ser = serial.Serial(“/dev/ttyACM0″, 115200) ser.write(b”factory_reset\n”) response = ser.readline().decode() assert “OK” in response
3. Implementing Command Line Shell from Scratch Hardware Preparation Taking the nRF52840 development board as an example, we need to implement a basic serial communication interface:
// Serial output encapsulation void console_putc(char c) { app_uart_put(c); } // Serial input encapsulation char console_getc(void) { uint8_t cr; while(app_uart_get(&cr) != NRF_SUCCESS); // Block until data is received return (char)cr; }
Main Loop Implementation
int main(void) { char buf[128]; while(1) { console_puts("$ "); int len = console_gets(buf, sizeof(buf)); console_putc('\n'); if(len) { console_puts("OK\n"); } } }
Open Source Solution Integration
It is recommended to use a lightweight open-source shell framework:
Adding Shell Core Module
shell/ ├── include/shell.h └── src/shell.c
Command Registration Example
// shell_commands.c int cli_cmd_hello(int argc, char *argv[]) { shell_put_line("Hello World!"); return 0; } static const sShellCommand s_shell_commands[] = { {"hello", cli_cmd_hello, "Print welcome message"}, {"help", shell_help_handler, "Show help"}, };
4. Advanced Functionality Implementation Parameter Parsing
int cli_cmd_kv_write(int argc, char *argv[]) { if(argc != 3) { shell_put_line("> FAIL,1"); return -1; } bool ret = kv_store_write(argv[1], argv[2]); shell_put_line(ret ? "> OK" : "> FAIL,2"); return ret ? 0 : -1; }
Automated Testing
Python automation script example:
import serial ser = serial.Serial("/dev/ttyACM0", 115200, timeout=1) ser.write(b"kv_read device_name\n") response = ser.readline().decode().strip() assert response == "KitchenTimer"
5. Development Considerations 1. Unified Output Format
void shell_result(int code) { char buf[32]; snprintf(buf, sizeof(buf), "> %s,%d", (code == 0) ? "OK" : "FAIL", abs(code)); shell_put_line(buf); }
2. Resource Optimization Strategies
Isolate debugging commands through conditional compilation
#if DEBUG_MODE {"mem_dump", debug_memdump, "Memory debugging"}, #endif
6. Scenarios Where Shell is Not Suitable High bandwidth data transmission is required Strict communication security requirements Extremely limited system resources (ROM < 8KB)
Conclusion The command line shell is a powerful tool in embedded development that can significantly enhance debugging efficiency. By designing command structures reasonably, standardizing output formats, and combining automated testing, a stable and reliable human-machine interaction system can be built. During development, it is essential to balance resource consumption and functional expansion, selecting the most suitable implementation scheme based on project requirements.
Finally
Today, I have shared so much with you. If you found it helpful, please remember to give a thumbs up.
A permanent, free platform for sharing embedded technology knowledge~