A command line interpreter and script engine for embedded systems.

Version License CI Coverage RISC-V code size

xelp is an interactive command line interpreter, script engine, and single-key menu system for embedded C projects. It compiles to under 4 KB with all features enabled and runs on targets from 8-bit microcontrollers to 64-bit hosts. Register your own C functions as commands and call them from the prompt or from scripts stored in ROM. No OS, no dynamic memory, no standard library dependencies.

Features

CLI in action

Key functions [?] show help [l] toggle LED CLI functions help show help echo echo args back led led <0|1> status system status config config <key> <value> xelp> echo "hello world" hello world xelp> led 1 LED on xelp> config gain 50; config mode 2 # inline script gain = 50 mode = 2 xelp> _

Every command above is a plain C function registered with a one-line table entry:

XELPCLIFuncMapEntry commands[] = {
    { &cmd_echo,   "echo",   "echo args back"          },
    { &cmd_led,    "led",    "led <0|1>"               },
    { &cmd_config, "config", "config <key> <value>"    },
    XELP_FUNC_ENTRY_LAST
};

Modes

ModeDescriptionCompile flag
CLICommand line with prompt, backspace, command dispatch. Type commands, press ENTER.XELP_ENABLE_CLI
KEYSingle key press → immediate action. For menus and quick toggles, no ENTER needed.XELP_ENABLE_KEY
THRPass-through to another peripheral (modem, debug port). All keys forwarded.XELP_ENABLE_THR

Quick start

Add three files to your project: xelp.c, xelp.h, xelpcfg.h. Then:

#include "xelp.h"

void uart_putc(char c) { UART_TX = c; }

XELPRESULT cmd_hello(const char *args, int len) {
    XELPOut(&cli, "Hello!\n", 0);
    return XELP_S_OK;
}

XELPCLIFuncMapEntry commands[] = {
    { &cmd_hello, "hello", "say hello" },
    XELP_FUNC_ENTRY_LAST
};

XELP cli;

void main(void) {
    XELPInit(&cli, "My Device v1.0");
    XELP_SET_FN_OUT(cli, &uart_putc);
    XELP_SET_FN_CLI(cli, commands);

    for (;;) {
        if (uart_rx_ready())
            XELPParseKey(&cli, uart_getc());
    }
}

Platform support and build sizes

Compiled with -Os, all features enabled:

ArchitectureCompilerWord sizeCode size (bytes)
ARM32 Thumbarm-none-eabi-gcc32-bit1488
MSP430msp430-gcc16-bit1804
RISC-V (rv64)riscv64-linux-gnu-gcc64-bit1960
ARM32arm-none-eabi-gcc32-bit2372
AVR (ATtiny85)avr-gcc8-bit2420
AVR (ATmega328P)avr-gcc8-bit2452
x86-64GCC64-bit2775
x86-32GCC32-bit2826
x86-64Clang64-bit3003
ARM64aarch64-linux-gnu-gcc64-bit3148
PowerPCpowerpc-linux-gnu-gcc32-bit3778
68HC11m68hc11-gcc8-bit4247

Sizes measured via Docker cross-compilation (bash tools/crossbuild.sh). KEY-only mode: 900 bytes.

Building and testing

make tests        # build and run unit tests + coverage
make coverage     # tests + coverage summary
make example      # build and run the posix ncurses example
make clean        # remove build artifacts

19 test units, 207 test cases, 100% line coverage of xelp.c.

Documentation

License

BSD 2-Clause — see LICENSE.txt. © 2005–2025 M. A. Chatterjee