{"id":10250,"date":"2024-03-18T21:17:00","date_gmt":"2024-03-18T20:17:00","guid":{"rendered":"https:\/\/playembedded.org\/?p=10250"},"modified":"2025-01-13T10:28:28","modified_gmt":"2025-01-13T09:28:28","slug":"cli-chibios-shell","status":"publish","type":"post","link":"https:\/\/playembedded.org\/blog\/cli-chibios-shell\/","title":{"rendered":"Build your Command Line Interface: a Guide to ChibiOS\/Shell"},"content":{"rendered":"<h2 class=\"wp-block-heading level_1\" id=\"1_Introduction\">Introduction<\/h2>\n\n\n\n<p>In this article, we explore the ChibiOS\/Shell, a fully configurable Command Line Interface (CLI) provided by ChibiOS. This tool allows users to interact with the operating system, execute tasks, and access system features through available serial drivers, utilizing either USB or UART connections.<\/p>\n\n\n\n<p>Embedded systems face a unique challenge because they are closed systems operating on an integrated chip without the interactive interfaces like a mouse or keyboard found on PCs. Programming on these microcontrollers typically creates a system that responds to specific events by generating outputs. These events usually come from external hardware and result in actions on other hardware components. For example, consider a smart miniature greenhouse with a temperature sensor. Positioned to receive sunlight, the greenhouse includes a small window operated by a servo. When the microcontroller reads the temperature sensor and detects that the temperature has exceeded a predetermined threshold, it opens the window to cool down the environment.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2800\" height=\"1840\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/Greenhouse-closed-system.png\" alt=\"\" class=\"wp-image-10485\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-closed-system.png 2800w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-closed-system-300x197.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-closed-system-1024x673.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-closed-system-150x99.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-closed-system-1536x1009.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-closed-system-2048x1346.png 2048w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-closed-system-1200x789.png 1200w\" sizes=\"auto, (max-width: 2800px) 100vw, 2800px\"><figcaption class=\"wp-element-caption\">Smart greenhouse control system with temperature-triggered window mechanism.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The system described operates in a closed loop, meaning we cannot directly influence its programmed behavior. Now, imagine if the microcontroller could accept commands with parameters through one of its serial ports. Upon receiving these commands, it would perform specific internal operations and provide feedback via the serial output. For instance, it might allow for the adjustment of the temperature threshold that triggers the window to open. Alternatively, it could enable manual control over the window, allowing it to be opened or closed on command.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2800\" height=\"1840\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/Greenhouse-with-shell.png\" alt=\"\" class=\"wp-image-10484\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-with-shell.png 2800w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-with-shell-300x197.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-with-shell-1024x673.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-with-shell-150x99.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-with-shell-1536x1009.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-with-shell-2048x1346.png 2048w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Greenhouse-with-shell-1200x789.png 1200w\" sizes=\"auto, (max-width: 2800px) 100vw, 2800px\"><figcaption class=\"wp-element-caption\">Enhanced smart greenhouse system with Shell integration for command input and control.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Furthermore, this command line can be used to display sensor data upon request, transforming it into a powerful tool. This capability is precisely what the Shell offers. At its core, a Shell is a Command Line Interface that operates on one of the microcontroller&rsquo;s COM ports. It is engineered to accept commands and return responses. A command consists of a sequence of human-readable characters, potentially accompanied by optional parameters. Consider the command below, followed by two parameters:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">set threshold 35<\/pre>\n\n\n\n<p>In this example, the command is <code>set<\/code>, with <code>threshold<\/code> and <code>35<\/code> serving as the parameters. When a command is executed, it is linked to a specific function that receives these parameters as arguments. The action taken by the function then depends on how it is programmed by the user.<\/p>\n\n\n\n<p>Reflecting on our smart greenhouse scenario, such a command could adjust the temperature level that triggers the greenhouse door to open. The command might carry out verifications before setting a global variable, and if the command is processed successfully, the response might be:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">set threshold OK<\/pre>\n\n\n\n<p>This capability illustrates how commands can dynamically interact with the system&rsquo;s settings, enabling users to tailor the system&rsquo;s behavior according to specific needs or conditions.<\/p>\n\n\n\n<h2 class=\"wp-block-heading level_1\" id=\"2_Setting_up_and_running_the_Shell\">Setting up and running the Shell<\/h2>\n\n\n\n<p>The best way to really get to know what the Shell can do is by starting a test project that uses it. This gives us a hands-on chance to see how it works. A good starting point is using  <a href=\"https:\/\/playembedded.org\/simplest-project-chibios\/\" data-type=\"post\" data-id=\"7838\">The simplest project ever with ChibiOS<\/a>, chosen for an evaluation kit we like. From there we can expand the project using one of the many demo based on ChibiOS\/Shell that ChibiOS offers.<\/p>\n\n\n\n<p>This method helps us get familiar with the Shell quickly and shows us how we can adjust it for our own projects. By doing this, we can learn about the Shell&rsquo;s capabilities and how to make the most of them in our embedded systems.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"3_Preliminary_information\">Preliminary information<\/h3>\n\n\n\n<p>The best reference about how to use the Shell is the demo USB-CDC demo available under<em> [ChibiOS Root]\\testhal\\STM32\\multi\\USB_CDC<\/em>. This demo shows the application of the Shell using the Serial Driver over USB. The SoUSB is a Complex Device Driver that programs a microcontroller native USB peripheral into into a virtual COM port, which the PC can recognize as such. However, doing so requires to deal with USB descriptors and some other complexities related to the USB standard: diving into this while still trying to understand the Shell&rsquo;s workings might be overly complex because it involves managing several advanced features at once.<\/p>\n\n\n\n<p>Luckily, the Shell is modeled around an abstract interface called <code>BaseSequentialStream<\/code>. The underlying principle of adopting an interface such as <code>BaseSequentialStream<\/code> is that it acts as a contract between the application layer and the driver, defining four common methods: <code>write<\/code>, <code>read<\/code>, <code>put<\/code>, and <code>get<\/code>. Both SerialDriver and SerialDriver over USB adhere to this contract, extending it, which enables their use in any context requiring a <code>BaseSequentialStream<\/code>. Now, as the Shell relies on these four common methods, it can be interoperable with both drivers.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2800\" height=\"960\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/BaseSequentialStream-for-shell.png\" alt=\"\" class=\"wp-image-10482\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/BaseSequentialStream-for-shell.png 2800w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/BaseSequentialStream-for-shell-300x103.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/BaseSequentialStream-for-shell-1024x351.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/BaseSequentialStream-for-shell-150x51.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/BaseSequentialStream-for-shell-1536x527.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/BaseSequentialStream-for-shell-2048x702.png 2048w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/BaseSequentialStream-for-shell-1200x411.png 1200w\" sizes=\"auto, (max-width: 2800px) 100vw, 2800px\"><figcaption class=\"wp-element-caption\">Diagram illustrating the Shell interaction with UART and USB-specific implementations of BaseSequentialStream, highlighting the common API and device-specific extensions.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>For those looking for more details,  <a href=\"https:\/\/playembedded.org\/formatting-strings-with-chprintf-in-chibios\/#10_Appendix_A_Casting_mechanism_of_a_SerialDriver_to_BaseSequentialStream_in_ChibiOS\">Appendic A<\/a> of the article about the <code>chprintf<\/code> in the article is a good reference. But right now, we are focusing on running the Shell with a Serial Driver to make our first steps with this library easier. If you are not familiar with the Serial Driver, it might be helpful to check out <a href=\"https:\/\/playembedded.org\/chibios-hal-serial-driver-explained\/\" data-type=\"post\" data-id=\"10246\">ChibiOS\/HAL&rsquo;s Serial Driver Explained<\/a>.<\/p>\n\n\n\n<p>In the example I will show next, I am using the SDP-K1 evaluation kit, specifically the Serial Driver 5. This driver is selected because UART5 on this evaluation kit can be directly connected to the PC through the Debugger. Thus, when we connect our kit to the PC, we immediately gain access to a COM port that is linked to UART5 on the microcontroller, making it ready to use right away.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2480\" height=\"1200\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/SDP-K1-debugger-port-bridge-connection.png\" alt=\"\" class=\"wp-image-10494\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/SDP-K1-debugger-port-bridge-connection.png 2480w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/SDP-K1-debugger-port-bridge-connection-300x145.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/SDP-K1-debugger-port-bridge-connection-1024x495.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/SDP-K1-debugger-port-bridge-connection-150x73.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/SDP-K1-debugger-port-bridge-connection-1536x743.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/SDP-K1-debugger-port-bridge-connection-2048x991.png 2048w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/SDP-K1-debugger-port-bridge-connection-1200x581.png 1200w\" sizes=\"auto, (max-width: 2480px) 100vw, 2480px\"><figcaption class=\"wp-element-caption\">The debugger COM port bridge of the SDP-K1<\/figcaption><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"4_Integrating_the_Shell_in_our_project\">Integrating the Shell in our project<\/h3>\n\n\n\n<p>The Shell is an optional library that must be explicitly integrated into your project to be utilized. This process typically involves adding specific files and configuring the makefile, which aids in minimizing the compiled code size by including only what is necessary. This strategy ensures that if the Shell is not needed, the codebase remains streamlined without unnecessary additions.<\/p>\n\n\n\n<p>To activate the Shell, we need to incorporate certain dependencies into our makefile under &ldquo;<code>Project, target, sources and paths<\/code>&ldquo;. There are primarily three groups of dependencies to be added:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The Shell itself, being a separate module, must be integrated into the project for usage. It can be located under <em>[ChibiOS root]\/os\/various\/shell\/shell.mk<\/em><\/li>\n\n\n\n<li>The <code>chprintf<\/code>, which is extensively utilized internally by the Shell, can be included via <em>[ChibiOS root]\/os\/hal\/lib\/streams\/streams.mk<\/em><\/li>\n\n\n\n<li>The ChibiOS Test Suite, necessitating multiple inclusions, as shown in the makefile of any standard demo.<\/li>\n<\/ul>\n\n\n\n<p>Examining my makefile, the subsequent additions would be necessary:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">##############################################################################\n# Project, target, sources and paths\n#\n\n...\n\n# Other files (optional).\ninclude $(CHIBIOS)\/os\/test\/test.mk\ninclude $(CHIBIOS)\/test\/rt\/rt_test.mk\ninclude $(CHIBIOS)\/test\/oslib\/oslib_test.mk\ninclude $(CHIBIOS)\/os\/hal\/lib\/streams\/streams.mk\ninclude $(CHIBIOS)\/os\/various\/shell\/shell.mk\n\n<\/pre>\n\n\n\n<p>Before we proceed, it is important to mention why the test suite is included. The Shell includes several default commands, among which is one that executes the test suite. Omitting this suite from our project would result in build errors. Later on, we will explore how to disable this specific command through the makefile, effectively removing the test suite if it is unnecessary for our purposes. For the time being, however, we will adhere to the standard demonstration setup.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"5_A_minimalistic_application_with_the_Shell\">A minimalistic application with the Shell<\/h3>\n\n\n\n<p>The main function below illustrates a minimal application that uses the Shell. This code has been inspired by the demo at <em>[ChibiOS Root]\/testhal\/STM32\/multi\/USB_CDC<\/em> and brings together all necessary elements to run the Shell on the debugger&rsquo;s serial connection.<\/p>\n\n\n\n<p>Let us examine the entire main function to gain a full understanding before going into the specifics.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/*\n    PLAY Embedded demos - Copyright (C) 2014...2024 Rocco Marco Guglielmi\n\n    This file is part of PLAY Embedded demos.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n*\/\n\n#include \"ch.h\"\n#include \"hal.h\"\n\n#include \"chprintf.h\"\n#include \"shell.h\"\n\n\/*===========================================================================*\/\n\/* Command line related.                                                     *\/\n\/*===========================================================================*\/\n\n\/*\n * Working area of the Shell Thread.\n *\/\nstatic THD_WORKING_AREA(waShell, 2048);\n\n\/* Can be measured using dd if=\/dev\/xxxx of=\/dev\/null bs=512 count=10000.*\/\nstatic void cmd_write(BaseSequentialStream *chp, int argc, char *argv[]) {\n  static uint8_t buf[] =\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\";\n\n  (void)argv;\n  if (argc &gt; 0) {\n    chprintf(chp, \"Usage: write\\r\\n\");\n    return;\n  }\n\n  while (chnGetTimeout((BaseChannel *)&amp;SD5, TIME_IMMEDIATE) == MSG_TIMEOUT) {\n    streamWrite(chp, buf, sizeof buf - 1);\n  }\n  chprintf(chp, \"\\r\\n\\nstopped\\r\\n\");\n}\n\nstatic const ShellCommand commands[] = {\n  {\"write\", cmd_write},\n  {NULL, NULL}\n};\n\nstatic const ShellConfig shell_cfg = {\n  .sc_channel  = (BaseSequentialStream *)&amp;SD5,\n  .sc_commands = commands\n};\n\n\/*===========================================================================*\/\n\/* Generic code.                                                             *\/\n\/*===========================================================================*\/\n\n\/*\n * This is a periodic thread that does absolutely nothing except flashing\n * a LED.\n *\/\nstatic THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"blinker\");\n  while (true) {\n    palToggleLine(LINE_LED_GREEN);\n    chThdSleepMilliseconds(250);\n  }\n}\n\n\/*\n * Application entry point.\n *\/\nint main(void) {\n\n  \/*\n   * System initializations.\n   * - HAL initialization, this also initializes the configured device drivers\n   *   and performs the board-specific initializations.\n   * - Kernel initialization, the main() function becomes a thread and the\n   *   RTOS is active.\n   *\/\n  halInit();\n  chSysInit();\n\n  \/* Creates the LED blinker thread. *\/\n  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 1, Thread1, NULL);\n\n  \/* Activating the debugger COM port with default configuration (8-N-1, 38400bps). *\/\n  sdStart(&amp;SD5, NULL);\n\n  \/* Initializing the Shell. *\/\n  shellInit();\n\n  \/* The main spawn the Shell and if terminates it respawns it. *\/\n  while (true) {\n\n    thread_t *shelltp = chThdCreateStatic(waShell, sizeof(waShell),\n                                          NORMALPRIO + 1, shellThread,\n                                          (void *)&amp;shell_cfg);\n    chThdWait(shelltp);\n    chThdSleepMilliseconds(1000);\n  }\n}<\/pre>\n\n\n\n<p>The analysis of the code reveals two primary components:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The declaration of all functions and structures necessary for initializing the Shell, positioned outside the main function.<\/li>\n\n\n\n<li>The instantiation of the Shell itself, executed within the main function.<\/li>\n<\/ol>\n\n\n\n<p>Essentially, the Shell is a <a href=\"https:\/\/playembedded.org\/parametric-threads-with-chibios\/\" data-type=\"post\" data-id=\"8523\">parametric thread<\/a> predefined within the library as <code>shellThread<\/code>. To activate the Shell, one must initiate this thread by providing it with a suitable working area and its configuration as parameters. The choice between using a static working area or allocating memory from the heap depends on specific project requirements or preferences.<\/p>\n\n\n\n<p>For allocating memory from the heap:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">define SHELL_WA_SIZE   THD_WORKING_AREA_SIZE(2048)\nthread_t *shelltp = chThdCreateFromHeap(NULL, SHELL_WA_SIZE,\n                                        \"shell\", NORMALPRIO + 1,\n                                        shellThread, (void *)&amp;shell_cfg);<\/pre>\n\n\n\n<p>For using a static working area:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static THD_WORKING_AREA(waShell, 2048);\nthread_t *shelltp = chThdCreateStatic(waShell, sizeof(waShell),\n                                      NORMALPRIO + 1, shellThread,\n                                      (void *)&amp;shell_cfg);<\/pre>\n\n\n\n<p>This arrangement allows for flexibility in how the Shell&rsquo;s thread is deployed, catering to diverse application scenarios and system resource management strategies.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/* Thread instantiation allocating memory from the heap. *\/\n#define SHELL_WA_SIZE   THD_WORKING_AREA_SIZE(2048)\nthread_t *shelltp = chThdCreateFromHeap(NULL, SHELL_WA_SIZE,\n                                        \"shell\", NORMALPRIO + 1,\n                                        shellThread, (void *)&amp;shell_cfg);\n\n\/* Thread instantiation using a static working area. *\/\nstatic THD_WORKING_AREA(waShell, 2048);\nthread_t *shelltp = chThdCreateStatic(waShell, sizeof(waShell),\n                                      NORMALPRIO + 1, shellThread,\n                                      (void *)&amp;shell_cfg);<\/pre>\n\n\n\n<p>In our scenario, I opted for a static thread. However, there&rsquo;s a crucial aspect to consider: the Shell thread can terminate upon a certain keystroke (CTRL+D) or if the &lsquo;exit&rsquo; command is executed. To accommodate this, we prepare by storing the Shell thread&rsquo;s pointer in a variable named <code>shelltp<\/code>. Subsequently, invoking <code>chThdWait<\/code> puts the main thread on hold indefinitely, awaiting the Shell thread&rsquo;s termination. Upon such an event, the main thread pauses for an additional 1000 milliseconds before respawning the Shell.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/* The main thread spawns the Shell and respawns it upon termination. *\/\nwhile (true) {\n\n  thread_t *shelltp = chThdCreateStatic(waShell, sizeof(waShell),\n                                        NORMALPRIO + 1, shellThread,\n                                        (void *)&amp;shell_cfg);\n  chThdWait(shelltp);\n  chThdSleepMilliseconds(1000);\n}<\/pre>\n\n\n\n<p>This serves as a demonstration of the flexibility available, yet it is also feasible to configure the Shell so that its thread does not terminate. It is crucial to initialize the communication channel the Shell will use (in this instance, Serial Driver 5) before starting the Shell thread. Additionally, invoking <code>shellInit()<\/code> is necessary to set up certain internal aspects of the Shell. This preparation occurs just before we enter the main loop:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/* Activating the debugger COM port with default configuration (8-N-1, 38400bps). *\/\nsdStart(&amp;SD5, NULL);\n\n\/* Initializing the Shell. *\/\nshellInit();<\/pre>\n\n\n\n<p>With this setup complete, we turn our attention to the configuration structure of the Shell. This structure typically has two key fields:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>sc_channel<\/code>, which points to the <code>BaseSequentialStream<\/code> utilized for spawning the Shell.<\/li>\n\n\n\n<li><code>sc_commands<\/code>, a pointer to an array defining additional, user-specified commands that can be executed via the Shell.<\/li>\n<\/ul>\n\n\n\n<p>The <code>sc_channel<\/code> field connects the Shell to our serial driver, ensuring communication flows through the intended channel. Meanwhile, the <code>sc_commands<\/code> field facilitates the extension of the Shell&rsquo;s functionality, allowing for the integration of custom commands tailored to our project&rsquo;s needs. The configuration for our project is specified as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static const ShellConfig shell_cfg = {\n  .sc_channel  = (BaseSequentialStream *)&amp;SD5,\n  .sc_commands = commands\n};<\/pre>\n\n\n\n<p>The commands list is defined within our main function:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static const ShellCommand commands[] = {\n  {\"write\", cmd_write},\n  {NULL, NULL}\n};<\/pre>\n\n\n\n<p>This array links a string to a function, enabling the expansion of the Shell&rsquo;s command set beyond the default commands. It is important to note that since the array&rsquo;s size is not predefined, it must conclude with a <code>{NULL, NULL}<\/code> entry. This serves as a marker to indicate the end of the command list.<\/p>\n\n\n\n<p>In this instance, we have defined a single user-created command, &ldquo;write&rdquo;. Typing &ldquo;write&rdquo; in the Shell triggers the execution of the <code>cmd_write<\/code> function, also detailed in our main application:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/* Can be measured using dd if=\/dev\/xxxx of=\/dev\/null bs=512 count=10000.*\/\nstatic void cmd_write(BaseSequentialStream *chp, int argc, char *argv[]) {\n  static uint8_t buf[] =\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n      \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\";\n\n  (void)argv;\n  if (argc &gt; 0) {\n    chprintf(chp, \"Usage: write\\r\\n\");\n    return;\n  }\n\n  while (chnGetTimeout((BaseChannel *)&amp;SD5, TIME_IMMEDIATE) == MSG_TIMEOUT) {\n    streamWrite(chp, buf, sizeof buf - 1);\n  }\n  chprintf(chp, \"\\r\\n\\nstopped\\r\\n\");\n} <\/pre>\n\n\n\n<p>This function continuously prints a predefined buffer until any key is pressed by the user, demonstrating a simple, yet practical application of custom Shell commands.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"6_Experiencing_the_Shell_in_action\">Experiencing the Shell in action<\/h3>\n\n\n\n<p>When we open the COM port linked to our evaluation kit after flashing our firmware, we have the opportunity to explore this shell demonstration. Initially, if we press &ldquo;Enter&rdquo; in the terminal, the shell responds, indicating it is operational.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1318\" height=\"781\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/Verifying-Shell-presence.png\" alt=\"\" class=\"wp-image-10490\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Verifying-Shell-presence.png 1318w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Verifying-Shell-presence-300x178.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Verifying-Shell-presence-1024x607.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Verifying-Shell-presence-150x89.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Verifying-Shell-presence-1200x711.png 1200w\" sizes=\"auto, (max-width: 1318px) 100vw, 1318px\"><figcaption class=\"wp-element-caption\">Initial response from the Shell: verifying its presence.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The first command we should try is &ldquo;help,&rdquo; which displays a list of all available commands:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1414\" height=\"1081\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/Help-command.png\" alt=\"\" class=\"wp-image-10497\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-command.png 1414w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-command-300x229.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-command-1024x783.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-command-150x115.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-command-1200x917.png 1200w\" sizes=\"auto, (max-width: 1414px) 100vw, 1414px\"><figcaption class=\"wp-element-caption\">Exploring Shell commands: output of the &lsquo;help&rsquo; command.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>This list includes several built-in commands and our custom command, &ldquo;write.&rdquo; Executing the &ldquo;write&rdquo; command triggers the corresponding function, <code>cmd_write<\/code>, which outputs a predefined string repeatedly until any key is pressed, halting the process with a &ldquo;stopped&rdquo; message.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1414\" height=\"1081\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/Write-command.png\" alt=\"\" class=\"wp-image-10492\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Write-command.png 1414w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Write-command-300x229.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Write-command-1024x783.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Write-command-150x115.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Write-command-1200x917.png 1200w\" sizes=\"auto, (max-width: 1414px) 100vw, 1414px\"><figcaption class=\"wp-element-caption\">The custom command &lsquo;write&rsquo; in action.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>As mentioned, the command continuously outputs the buffer until any key is pressed in the shell. When this happens, the loop is interrupted, and the function displays &ldquo;stopped&rdquo; before returning to the main shell loop.<\/p>\n\n\n\n<h2 class=\"wp-block-heading level_1\" id=\"7_Command_Handling\">Command Handling<\/h2>\n\n\n\n<p>The shell is fully customizable, enabling the addition of new commands, linking them to specific functions, and even disabling built-in commands. Initially, the shell handles the input by separating the command from its parameters. However, once we execute our custom-defined function, managing the input and performing error checks becomes our responsibility.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"8_Creating_and_managing_command_handlers\">Creating and managing command handlers<\/h3>\n\n\n\n<p>The shell operates by taking input from the user in the form of characters. These characters are not immediately processed. Instead, the shell waits until the user presses the &lsquo;Enter&rsquo; key. Upon doing so, the shell interprets the entire input string. It separates the string into multiple parts using spaces as the dividing factor. The first word is recognized as the command, which tells the shell which action should be executed. The subsequent words are considered parameters, which provide additional information or specifics about how the command should be executed.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1922\" height=\"402\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/Command-and-parameters.png\" alt=\"\" class=\"wp-image-10495\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Command-and-parameters.png 1922w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Command-and-parameters-300x63.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Command-and-parameters-1024x214.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Command-and-parameters-150x31.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Command-and-parameters-1536x321.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Command-and-parameters-1200x251.png 1200w\" sizes=\"auto, (max-width: 1922px) 100vw, 1922px\"><figcaption class=\"wp-element-caption\">Illustration of command and parameter separation in the shell.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>A command is linked to a function: if the command is either a built-in command or one specified in our custom command list, then the corresponding function is invoked. The handling of parameters is important here.<\/p>\n\n\n\n<p>The function associated with a command is defined as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/**\n * @brief   Command handler function type.\n *\/\ntypedef void (*shellcmd_t)(BaseSequentialStream *chp, int argc, char *argv[]);<\/pre>\n\n\n\n<p>This function takes the <code>BaseSequentialStream<\/code> used by the shell, an integer representing the number of arguments entered in the shell following the command, and an array of strings that are the parameters themselves.<\/p>\n\n\n\n<p>To clarify this concept, let&rsquo;s introduce a new command and add it to our list of user-defined commands:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static void cmd_argcount(BaseSequentialStream *chp, int argc, char *argv[]) {\n\n  chprintf(chp, \"Command argcount received with %d arguments\\r\\n\", argc);\n\n  if(argc &gt; 0) {\n    for(int i = 0; i &lt; argc; i++) {\n      chprintf(chp, \"Argument %d: %s\\r\\n\", i + 1, argv[i]);\n    }\n  }\n}\n\nstatic const ShellCommand commands[] = {\n  {\"write\", cmd_write},\n  {\"argcount\", cmd_argcount},\n  {NULL, NULL}\n};<\/pre>\n\n\n\n<p>Next, we will test these commands in the shell to observe their responses.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1414\" height=\"1081\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/Argcount-command.png\" alt=\"\" class=\"wp-image-10496\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Argcount-command.png 1414w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Argcount-command-300x229.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Argcount-command-1024x783.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Argcount-command-150x115.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Argcount-command-1200x917.png 1200w\" sizes=\"auto, (max-width: 1414px) 100vw, 1414px\"><figcaption class=\"wp-element-caption\">Demonstrating the &lsquo;argcount&rsquo; command in action.<\/figcaption><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"9_Argument_checks_and_validation\">Argument checks and validation<\/h3>\n\n\n\n<p>From our previous examples, it is clear that the arguments for a command, along with their count, are passed directly to the function as anticipated. This enables us to perform checks on these arguments and tailor the function&rsquo;s behavior based on the command&rsquo;s parameters.<\/p>\n\n\n\n<p>For instance, if a function is not designed to accept any arguments, we could structure it as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static void cmd_example(BaseSequentialStream *chp, int argc, char *argv[]) {\n  \n  \/* Ignoring argv to avoid unused variable warning *\/\n  (void) argv;\n  \n  if(argc &gt; 0) {\n    chprintf(chp, \"Usage: example\\r\\n\",);\n  }\n  else {\n    \/* Implement the command's functionality here.. *\/\n  }\n}<\/pre>\n\n\n\n<p>If a function requires a more complex set of arguments, we can extend our validation accordingly. Revisiting the greenhouse example with the command to set a temperature threshold:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">set threshold 35<\/pre>\n\n\n\n<p>Imagine this command always requires two parameters: the first must be &ldquo;threshold,&rdquo; and the second, a number between 25 and 40. A potential implementation could look like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static void cmd_set(BaseSequentialStream *chp, int argc, char *argv[]) {\n  \n  msg_t msg = MSG_OK;\n  \n  \/* Check if the command received exactly two arguments *\/\n  if(argc != 2) {\n    msg = MSG_RESET;\n  }\n  else {\n    \/* Check if the first argument is \"threshold\" *\/\n    if(strcmp(argv[0], \"threshold\") == 0) {\n\n      \/* Convert the second argument to an integer *\/\n      int tmp = atoi(argv[1]);\n      \n      \/* Check if the number is outside the valid range *\/\n      if((tmp &lt; 25) || (tmp &gt; 40)) {\n        msg = MSG_RESET;\n      }\n      else {\n        \/* Your action here: for example, setting a threshold variable *\/\n        \/\/ threshold = tmp;\n      }\n    }\n    else {\n      msg = MSG_RESET;\n    }\n  }\n  \n  \/* Provide usage feedback if command format is incorrect *\/\n  if(msg == MSG_RESET) {\n    chprintf(chp, \"set threshold ERR\\r\\n\");\n    chprintf(chp, \"Usage: set threshold [temp] where temp is a number between 25 and 40\\r\\n\");\n  }\n  else {\n    chprintf(chp, \"set threshold OK\\r\\n\");\n  }\n}<\/pre>\n\n\n\n<p>This method allows for precise control over the command inputs and provides clear feedback to the user on how to correctly use the command<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"10_Implementing_breakable_loops\">Implementing breakable loops<\/h3>\n\n\n\n<p>A common requirement in shell functionality is creating functions that run in a loop until interrupted by a key press. This allows for tasks, such as printing sensor data to the shell indefinitely, to be executed until the user decides to stop. We illustrated this concept with the &ldquo;write&rdquo; command example, showcasing the importance of understanding how to implement such breakable loops effectively.<\/p>\n\n\n\n<p>The core functionality is encapsulated in the following loop:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  while (chnGetTimeout((BaseChannel *)&amp;SD5, TIME_IMMEDIATE) == MSG_TIMEOUT) {\n    streamWrite(chp, buf, sizeof buf - 1);\n  }\n  chprintf(chp, \"\\r\\n\\nstopped\\r\\n\");<\/pre>\n\n\n\n<p>The key to this functionality is the <code>chnGetTimeout<\/code> function, a method of the <code>BaseChannel<\/code> abstract interface, which extends <code>BaseSequentialStream<\/code> by adding four additional methods with timeouts (<code>gett<\/code>, <code>putt<\/code>, <code>writet<\/code>, and <code>readt<\/code>). The <code>SerialDriver<\/code> implements both interfaces, therefore, it is possible to use <code>chnGetTimeout<\/code> on the <code>SerialDriver<\/code>.<\/p>\n\n\n\n<p>This function, similarly to <code>sdGetTimeout<\/code>, is designed for reading a single byte from a <code>SerialDriver<\/code> within a specified timeout period. When set to <code>TIME_IMMEDIATE<\/code>, this function returns immediately.<\/p>\n\n\n\n<p>If the function returns a character, it indicates a key press by the user. Otherwise, it returns <code>MSG_TIMEOUT<\/code>, indicating no key press.<\/p>\n\n\n\n<p>As a result, the loop continues indefinitely as long as <code>chnGetTimeout<\/code> returns <code>MSG_TIMEOUT<\/code>. Once a key is pressed, <code>chnGetTimeout<\/code> will return a character different from <code>MSG_TIMEOUT<\/code>, breaking the loop.<\/p>\n\n\n\n<p>While this method effectively prints data upon command, it comes with a significant limitation: data printing must be halted each time the user wishes to enter commands. In situations where continuous data streaming is desired alongside command input capability, a viable solution could be to employ a second <code>BaseSequentialStream<\/code> exclusively for data streaming, while reserving the Shell for command execution.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"11_Disabling_native_commands\">Disabling native commands<\/h3>\n\n\n\n<p>The shell is equipped with several built-in commands, all of which, except for &ldquo;help,&rdquo; can be disabled. These commands are specified in the <em>[ChibiOS Root]\\os\\various\\shell\\shell_cmd.h<\/em> file. Disabling them involves setting certain flags to false:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/*===========================================================================*\/\n\/* Module pre-compile time settings.                                         *\/\n\/*===========================================================================*\/\n\n#if !defined(SHELL_CMD_EXIT_ENABLED) || defined(__DOXYGEN__)\n#define SHELL_CMD_EXIT_ENABLED              TRUE\n#endif\n\n#if !defined(SHELL_CMD_INFO_ENABLED) || defined(__DOXYGEN__)\n#define SHELL_CMD_INFO_ENABLED              TRUE\n#endif\n\n#if !defined(SHELL_CMD_ECHO_ENABLED) || defined(__DOXYGEN__)\n#define SHELL_CMD_ECHO_ENABLED              TRUE\n#endif\n\n#if !defined(SHELL_CMD_SYSTIME_ENABLED) || defined(__DOXYGEN__)\n#define SHELL_CMD_SYSTIME_ENABLED           TRUE\n#endif\n\n#if !defined(SHELL_CMD_MEM_ENABLED) || defined(__DOXYGEN__)\n#define SHELL_CMD_MEM_ENABLED               TRUE\n#endif\n\n#if !defined(SHELL_CMD_THREADS_ENABLED) || defined(__DOXYGEN__)\n#define SHELL_CMD_THREADS_ENABLED           TRUE\n#endif\n\n#if !defined(SHELL_CMD_TEST_ENABLED) || defined(__DOXYGEN__)\n#define SHELL_CMD_TEST_ENABLED              TRUE\n#endif\n\n#if !defined(SHELL_CMD_FILES_ENABLED) || defined(__DOXYGEN__)\n#define SHELL_CMD_FILES_ENABLED             FALSE\n#endif<\/pre>\n\n\n\n<p>However this configuration is common to all the projects using the shell, and it could be subject to changes if we update our ChibiOS repository. Therefore, instead of modifying these flags directly in the header, a more manageable approach is to modify them through the project&rsquo;s makefile. This allows for project-specific customization without altering the shared codebase. For instance, to disable the &ldquo;systime&rdquo; and &ldquo;test&rdquo; commands, you can modify the <code>UDEFS<\/code> variable in your makefile as shown:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">##############################################################################\n# Start of user section\n#\n\n# List all user C define here, like -D_DEBUG=1\nUDEFS = -DSHELL_CMD_SYSTIME_ENABLED=0 \\\n        -DSHELL_CMD_TEST_ENABLED=0<\/pre>\n\n\n\n<p>With this adjustment, executing the &ldquo;help&rdquo; command will reflect the absence of the &ldquo;systime&rdquo; and &ldquo;test&rdquo; commands.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1414\" height=\"1081\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/03\/Help-without-some-commands.png\" alt=\"\" class=\"wp-image-10499\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-without-some-commands.png 1414w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-without-some-commands-300x229.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-without-some-commands-1024x783.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-without-some-commands-150x115.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Help-without-some-commands-1200x917.png 1200w\" sizes=\"auto, (max-width: 1414px) 100vw, 1414px\"><figcaption class=\"wp-element-caption\">The result of the &ldquo;help&rdquo; command after disabling certain commands.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Among the native commands, special attention should be given to &ldquo;exit&rdquo; and &ldquo;test&rdquo;:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The command &ldquo;exit&rdquo; terminates the shell session. Its disablement is crucial if you intend for the shell thread to run indefinitely without user termination. This setup requires the shell thread to be initialized prior to entering the main application loop, allowing the main loop to serve other purposes.<\/li>\n\n\n\n<li>The command &ldquo;test&rdquo; launches the test suite, primarily used to verify ChibiOS functionality on new microcontroller ports or for benchmarking. Although valuable for development, it consumes significant memory, making it desirable to disable for deployed applications. Disabling the &ldquo;test&rdquo; command in the makefile and commenting out or removing related includes can free up resources.<\/li>\n<\/ul>\n\n\n\n<p>The code snippet below demonstrates how to exclude the &ldquo;test&rdquo; command and the test suite from our project<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">##############################################################################\n# Project, target, sources and paths\n#\n\n...\n\ninclude $(CHIBIOS)\/tools\/mk\/autobuild.mk\n# Other files (optional).\n#include $(CHIBIOS)\/os\/test\/test.mk\n#include $(CHIBIOS)\/test\/rt\/rt_test.mk\n#include $(CHIBIOS)\/test\/oslib\/oslib_test.mk\ninclude $(CHIBIOS)\/os\/hal\/lib\/streams\/streams.mk\ninclude $(CHIBIOS)\/os\/various\/shell\/shell.mk\n\n...\n\n##############################################################################\n# Start of user section\n#\n\n# List all user C define here, like -D_DEBUG=1\nUDEFS = -DSHELL_CMD_TEST_ENABLED=0\n\n...\n<\/pre>\n\n\n\n<p>This approach allows for efficient management and customization of shell commands, tailoring the shell&rsquo;s functionality to specific project requirements.<\/p>\n\n\n\n<h2 class=\"wp-block-heading level_1\" id=\"12_Advanced_Shell_configurations\">Advanced Shell configurations<\/h2>\n\n\n\n<p>The shell provides further customization options, detailed in the file <em>[ChibiOS Root]\\os\\various\\shell\\shell.h<\/em>. At this time, we will focus on two significant settings:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/**\n * @brief   Shell maximum input line length.\n *\/\n#if !defined(SHELL_MAX_LINE_LENGTH) || defined(__DOXYGEN__)\n#define SHELL_MAX_LINE_LENGTH       64\n#endif\n\n\/**\n * @brief   Shell maximum arguments per command.\n *\/\n#if !defined(SHELL_MAX_ARGUMENTS) || defined(__DOXYGEN__)\n#define SHELL_MAX_ARGUMENTS         4\n#endif<\/pre>\n\n\n\n<p>These configurations set limits on the maximum characters per input line and the maximum number of arguments a command can accept. Adjusting these limits is possible through the project&rsquo;s makefile, but caution is advised. Increasing these values directly impacts the shell&rsquo;s memory requirements. If system crashes occur after adjustments, you may need to allocate more memory to the shell&rsquo;s working area.<\/p>\n\n\n\n<p>Other configurable features, such as shell history and autocompletion, are also available but less critical for beginners. These advanced topics will be covered in a future article.<\/p>\n\n\n\n<h2 class=\"wp-block-heading level_1\" id=\"13_Conclusions\">Conclusions<\/h2>\n\n\n\n<p>In conclusion, this article provides a solid foundation for anyone looking to start building a customized Command Line Interface (CLI) using ChibiOS\/Shell. From setting up and running the Shell to managing command handlers and configuring advanced shell properties, we have covered essential aspects to get you underway. Whether it is implementing breakable loops, disabling native commands, or adjusting shell parameters for memory efficiency, these guidelines equip you with the knowledge to tailor the CLI to your project&rsquo;s needs. With this introduction, you are well on your way to creating a CLI that enhances the interaction with your embedded systems, making development and debugging more efficient and user-friendly.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>Introduction In this article, we explore the ChibiOS\/Shell, a fully configurable Command Line Interface (CLI) provided by ChibiOS. This tool allows users to interact with the operating system, execute tasks, and access system features through available serial drivers, utilizing either USB or UART connections. Embedded systems face a unique challenge because they are closed systems [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":10502,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1221],"tags":[1303,1301],"coauthors":[241],"class_list":["post-10250","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-further-readings","tag-chibios-hal","tag-uart","pumpkin"],"views":3172,"jetpack_featured_media_url":"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/03\/Build-your-CLI.jpg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts\/10250","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/comments?post=10250"}],"version-history":[{"count":0,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts\/10250\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/media\/10502"}],"wp:attachment":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/media?parent=10250"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/categories?post=10250"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/tags?post=10250"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/coauthors?post=10250"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}