Adding Shell Commands

The official Shell documentation can be seen here: https://mynewt.apache.org/latest/os/modules/shell/shell/

Mynewt includes a 'Shell' library that allows you to add an extensible command-line style interface to your applications. You can implement custom commands that users can execute over a simple serial connection, and display formatted text back to the end users.

Adding shell support

To add shell support to your app, make sure the following pkg.deps are defined in your pkg.yml file:

pkg.deps:
    - "@apache-mynewt-core/sys/console/full"
    - "@apache-mynewt-core/sys/shell"
    - "@apache-mynewt-core/sys/sysinit"

And in the syscfg.vals section of syscfg.yml  add the following:

syscfg.vals:
    # Enable the shell task.
    SHELL_TASK: 1

Adding a custom command handler

To add a new command handler use the following code snippets, placing the different sections at an appropriate place in your code:

#include "console/console.h"
#include "shell/shell.h"

...

// Command handler prototype declaration
static int shell_test_cmd(int argc, char **argv);

// Shell command struct
static struct shell_cmd shell_test_cmd_struct = {
    .sc_cmd = "test",
    .sc_cmd_func = shell_test_cmd
};

...

// Implement your command handler
static int
shell_test_cmd(int argc, char **argv)
{
    console_printf("Test!\n");
    return 0;
}

...

// Call this before sysinit to register the command
#if MYNEWT_VAL(SHELL_TASK)
    shell_cmd_register(&shell_test_cmd_struct);
#endif

Example: Updating apps/first/src/main.c

You can update apps/first with a custom shell command using the following code in main.c:

#include <assert.h>
#include <string.h>

#include "os/os.h"
#include "bsp/bsp.h"
#include "hal/hal_gpio.h"
#include "sysinit/sysinit.h"
#include "console/console.h"
#include "shell/shell.h"

/* Define task stack and task object */
#define LED_TASK_PRIO        (100)  /* 1 = highest, 255 = lowest */
#define LED_STACK_SIZE       OS_STACK_ALIGN(64)
struct os_task led_task;
os_stack_t led_task_stack[LED_STACK_SIZE];

/* LED task handler prototype declaration */
static void led_task_func(void *arg);

/* Command handler prototype declaration */
static int shell_test_cmd(int argc, char **argv);

/* Shell command struct */
static struct shell_cmd shell_test_cmd_struct = {
    .sc_cmd = "test",
    .sc_cmd_func = shell_test_cmd
};

int
main(int argc, char **argv)
{
    int rc;

    /* Initialize the task */
    os_task_init(&led_task, "blinky", led_task_func, NULL,
                 LED_TASK_PRIO, OS_WAIT_FOREVER, led_task_stack,
                 LED_STACK_SIZE);

    /* Call this before sysinit to register the command */
    #if MYNEWT_VAL(SHELL_TASK)
        shell_cmd_register(&shell_test_cmd_struct);
    #endif

    /* Initialize the OS */
    sysinit();

    while (1) {
        /* Run the event queue to process background events */
        os_eventq_run(os_eventq_dflt_get());
    }

    return rc;
}

/* Implement the 'test' command handler */
static int
shell_test_cmd(int argc, char **argv)
{
    console_printf("Test!\n");
    return 0;
}

static void
led_task_func(void *arg)
{
    /* Configure the LED GPIO as an output and HIGH (On) */
    hal_gpio_init_out(LED_BLINK_PIN, 1);

    while (1) {
        /* Wait one second */
        os_time_delay(OS_TICKS_PER_SEC * 1);

        /* Toggle the LED */
        hal_gpio_toggle(LED_BLINK_PIN);
    }
}

Testing the Shell Command

You can test the new 'test' shell command by connecting over serial:

$ minicom -D /dev/tty.SLAB_USBtoUART

Once connected you can send the 'help' command to get a list of valid shell commands, and then then 'test' command which should display 'Test!' in the shell:

Last updated on 2017-08-18 at 04.04.39 AM Published on 2017-08-18 at 03.37.04 PM