Embedded Command Line Interfaces and Why You Need Them

Throughout the development process, from hardware prototyping to manufacturing, the need to run test code repeatedly arises. This is crucial for verifying functionality and performing system-level testing. 

However, relying on debuggers or restarting the device to trigger events can lead to delays during boot-up and initialization. Moreover, it assumes that manufacturers and non-developers possess the necessary knowledge and tools to navigate these complexities. Thus, it becomes essential for embedded systems to offer a straightforward method for executing commands repeatedly through an accessible interface during both development and manufacturing.

Enter the solution: a command-line interface (CLI). This tool empowers users to exercise various features and functions without requiring expertise in debugging or software intricacies. Testing can be efficiently conducted via the CLI using the most suitable communication interface for the scenario, such as UART, USB, RTT, or Bluetooth.

While custom CLI implementations are certainly an option, a wealth of open-source solutions exists. Our team opted to explore these open-source alternatives first, aiming to identify one that could meet our needs with minimal adjustments. The initial phase of this implementation involves reviewing the available open-source CLI solutions and comparing their features. Once we find a suitable option, we can establish a standard solution to integrate into our template projects for broad adoption.

Why Use a CLI?

A CLI allows developers and manufacturers to exercise various features and functions without the need for debuggers or deep software knowledge. Testing can be performed using the communication interface most convenient to the situation, such as UART, USB, RTT, or Bluetooth.

While it’s possible to write a custom CLI, open-source solutions are available that can often meet your needs with minimal modification. Before embarking on an internal project, it’s worth reviewing available open-source CLI solutions to find one that fits your requirements. Here, we outline the key features to consider when choosing or implementing a CLI for embedded systems.

Requirements

Based on experience with closed-source and internally developed CLIs, here are the key features to prioritize.

Must Haves

Feature Description
Open Source with Permissive License The solution should be easily redistributable, ideally under an MIT license.
Communication Interface Agnostic The CLI should abstract input/output, supporting protocols like UART, USB, Bluetooth, etc.
Bare Metal Support The CLI should not rely on any RTOS or other dependencies.
Basic Shell Functionality Includes echoing input, backspace support, and help messages.
C or C++ Implementation Preferably a small, lightweight library in C or C++, with minimal files.
Static Memory Allocation Avoids dynamic allocation, a best practice for embedded systems.

Nice to Haves

Feature Description
Autocomplete and History Allows easier interaction through tab completion and command history recall.
Parameter Validation Ensures correct command arguments, improving usability.
Multiple Instances Support Enables serving multiple CLIs over different interfaces or protocols.
Built-in Help Native support for printing help messages and available commands.
Runtime Command Registration Commands can be registered at runtime, enabling dynamic updates.

Additional Considerations

Security Considerations

Securing embedded CLIs is crucial, especially in production environments. Best practices include implementing user authentication, encrypting communication interfaces, and restricting access to sensitive commands. For example, you can secure CLI access via password protection or encryption keys, ensuring only authorized users can interact with the system.

Example: A CLI secured with a password protects the system from unauthorized tampering during manufacturing or field use.

Performance Impact

When integrating a CLI into resource-constrained embedded systems. Large command sets and strings, for instance, can increase the footprint and slow down system response times. Reducing string sizes by using a more compact, manual format for commands can help mitigate this. Keeping the CLI lightweight and trimming unnecessary features will also minimize the impact on system resources.

Tip: Slimming down shell commands and minimizing string processing overhead will help keep your system responsive.

Interchangeable CLI Output Formats

A flexible CLI should support both human-readable and machine-readable formats, making it suitable for automated testing and interaction. This feature allows you to toggle between different output formats depending on the situation. For example, you might configure the CLI to output structured data like JSON or XML for machines while retaining plain text for human operators.

USB-CDC Support Example

A practical example would be adding USB-CDC support to your system, enabling two separate USB-CDC classes for different CLI instances—one for human operators and one for automated systems. This setup allows different users or processes to interact with the CLI simultaneously over the same hardware interface.

Hardware-Enabled CLI

In some systems, you might want to control when the CLI is available. For instance, external hardware could be used to determine whether the CLI is enabled at boot. If the hardware (such as a specific jumper) is absent, the CLI module would never load. This method ensures that the CLI isn’t exposed unnecessarily during operation, adding another layer of security.

Binary Protocols as an Alternative

In some cases, the full functionality of a CLI may not be necessary, or the nature of the deployment might not permit its use. A binary protocol could be a viable alternative for applications where you only need basic interaction with the device (e.g., for simple commands or status updates). This reduces the code size and execution overhead while still allowing communication.

Reduced Functionality CLI

Sometimes a more lightweight, reduced functionality CLI is preferable. For example, a CLI that only exposes essential commands and omits advanced features (such as autocomplete and history) might be appropriate for a system with strict resource constraints.

Multiple CLI Instances

Some applications may require multiple CLIs or separate instances of a CLI. For instance, you may need one CLI for handling RX and TX over different protocols or need to create a distinction between userland and kernel interactions. In such cases, a system with support for multiple shells or CLI instances, each managing its own state, would be beneficial.

By considering these additional aspects, you can create a flexible and powerful CLI that suits both your development needs and deployment scenarios, ensuring that testing, manufacturing, and troubleshooting are smooth and efficient.

Conclusion

Based on the analysis we plan to use Funbiscuit’s embedded-cli, the gif included in the repo speaks volumes so we include it here.

The embedded-cli by Funbiscuit ticks every box except for parameter validation but that was only a “nice to have” feature. We even discovered some additional features while integrating this into a template project. There is a hook function pointer that can be set up to be called whenever a command is about to be executed by the CLI library. It lets you print out the command and its arguments. What a great feature for debugging and logging!

Below is a table comparing the size of a project built before and after adding the CLI.

filename text data bss dec hex
with_cli.elf 40000 664 52520 93184 16c00
without_cli.elf 36048 664 50968 87680 15680

Some of that will be the FreeRTOS task that was added to interface with the CLI library. Some optimization could be done to trim buffers and the task’s stack size, but ultimately the increase is worth the benefits – and if the CLI is not needed in production, it can be easily removed.

The Funbiscuit embedded-cli project includes everything we were looking for, and should make a great addition to our projects.DojoFive brings modern tools, techniques, and best practices from the web and mobile development environments, paired with leading-edge innovations in firmware to our customers to help them build successful products and successful clients. We have talented engineers on hand ready to help you with all aspects of your EmbedOps journey. Bring your interesting problems that need solving – we are always happy to help out. You can reach out at any time on LinkedIn or through email!

Sign up to get our content updates!

Unlock the full potential of your embedded projects with our expert insights! Dive into our comprehensive resources to stay ahead in firmware development. Subscribe now to get the latest best practices and guides delivered straight to your inbox.

Sign Up for Updates

Discover why Dojo Five EmbedOps is the embedded enterprise choice for build tool and test management.

Sign up to receive a free account to the EmbedOps platform and start building with confidence..

  • Connect a repo
  • Use Dev Containers with your Continuous Integration (CI) provider
  • Analyze memory usage
  • Integrate and visualize static analysis results
  • Perform Hardware-in-the-Loop (HIL) tests
  • Install the Command Line Interface for a developer-friendly experience

Subscribe to our Monthly Newsletter

Subscribe to our monthly newsletter for development insights delivered straight to your inbox.

Interested in learning more?

Best-in-class embedded firmware content, resources and best practices

Laptop with some code on screen

I want to write my first embedded program. Where do I start?

The boom in the Internet of Things (IoT) commercial devices and hobbyist platforms like the Raspberry Pi and Arduino have created a lot of options, offering inexpensive platforms with easy to use development tools for creating embedded projects. You have a lot of options to choose from. An embedded development platform is typically a microcontroller chip mounted on a circuit board designed to show off its features. There are typically two types out there: there are inexpensive versions, sometimes called

Read More »
Medical device monitoring vitals

IEC-62304 Medical Device Software – Software Life Cycle Processes Primer – Part 1

IEC-62304 Software Lifecycle requires a lot of self-reflection to scrutinize and document your development processes. There is an endless pursuit of perfection when it comes to heavily regulated industries. How can you guarantee something will have zero defects? That’s a pretty hefty task. The regulatory approach for the medical device industry is process control. The concept essentially states that if you document how every step must be completed, and provide checks to show every step has been completed properly, you

Read More »
Operating room filled with medical devices

IEC-62304 Medical Device Software – Software Life Cycle Processes Primer – Part II

Part I provides some background to IEC-62304. Part II provides a slightly more in-depth look at some of the specifics. The IEC 62304 Medical Device Software – Software Lifecycle Processes looks into your development processes for creating and maintaining your software. The standard is available for purchase here. So what activities does the standard look at? Here are some of the major topics. For any given topic, there will be a lot more specifics. This will look at a few

Read More »