A tiny and flexible shell implementation to be used on embedded devices.

shimatta 306e66f535 Merge branch 'bugfix/sequence_counter_exceeds_limit' of shimatta/shellmatta into develop 2 days ago
.vscode 95de370e94 refactoring transport layer implementation 3 months ago
api 6531e17eb8 fixed documentation issues 3 months ago
cfg 373f7dea24 fixed some documentation issues 3 months ago
doc 6531e17eb8 fixed documentation issues 3 months ago
example 6531e17eb8 fixed documentation issues 3 months ago
python_driver 2d216259e4 sequence_counter_h2s/sequence_h2s could get bigger as 256 2 days ago
src f84d0a8c1c replaced forgotten direct write calls - would have bypassed the transport layer 3 months ago
test 6531e17eb8 fixed documentation issues 3 months ago
.gitignore 4578f6293c added output to gitignore 3 months ago
LICENSE 1b7cdb1acc replaced the LICENSE.md file with a plain text file with the standard convention for LICENSE files... 4 years ago
README.md 6531e17eb8 fixed documentation issues 3 months ago
makefile 373f7dea24 fixed some documentation issues 3 months ago

README.md

Shellmatta

A tiny and flexible shell implementation to be used on embedded devices.

Name

The name shellmatta is the combination of shell and shimatta.

What the hell is shimatta you might ask.

...well if you really wanna know you might reach out to these nerds that are running domains like shimatta.net or shimatta.de.

Do not pretend i didn't warn you.

Intention

The intention is to enable a software project of nearly any size to have a runtime command line interface to simplify debugging or configuration/calibration of any kind of device.

The shellmatta is designed to fit in most tiny microcontroller.

It is based on a simple character based interface and can work with for example network sockets or simple uarts. Some features are removable at build time to save ressources on really tiny platforms.

Features

The shellmatta piled up some features over time:

  1. history buffer (configurable)
  2. auto complete
  3. heredoc like interface to pass multiline data
  4. option parser (getopt like)
  5. simple authentication mechanism

Documentation

Besides this readme most documentation is integrated directly in the sourcecode as doxygen parsable comments.

To build the doxygen documentation just run make doc.

The html and latex documentation will be exported to output/doc

Integration into your project

The basic integration into a softwareproject is quite easy.

  1. add all *.c files from the src to your build
  2. include the api/shellmatta.h file
  3. implement a write function to output the data from the shell
  4. initialize the shell providing static buffers
  5. implement and add commands
  6. pass data into the shellmatta and watch the magic happen
  7. static constant command list (if you do not like dynamic lists)

Code example:

#include "shellmatta.h"
#include <unistd.h>

shellmatta_retCode_t writeFct(const char* data, uint32_t length)
{
    write(1, data, length);
    return SHELLMATTA_OK;
}

static shellmatta_retCode_t exampleCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length)
{
    shellmatta_retCode_t ret;
    char option;

    static const shellmatta_opt_long_t options[] = 
    {
        {"version",  'v',   SHELLMATTA_OPT_ARG_NONE},
        {NULL,      '\0',   SHELLMATTA_OPT_ARG_NONE}
    };

    ret = shellmatta_opt_long(handle, options, &option, NULL, NULL);
    while(SHELLMATTA_OK == ret)
    {
        switch(option)
        {
            case 'v':
                shellmatta_printf(handle, "This should represent the version of this command");
                break;
            default:
                shellmatta_printf(handle, "Unknown option: %c\r\n", option);
                break;
        }
        ret = shellmatta_opt_long(handle, options, &option, NULL, NULL);
    }

    (void)arguments;
    (void)length;
    return SHELLMATTA_OK;
}
shellmatta_cmd_t exampleCmd = { "example",                                              /**< command name       */
                                "e",                                                    /**< command alias      */
                                "example command",                                      /**< command help       */
                                "example [options]\n"                                   /**< command usage text */
                                "\t-v, --version - print the version of the command",
                                exampleCmdFct,                                          /**< command function   */
                                NULL};                                                  /**< intenally used     */

int main(void)
{
    static char buffer[1024];               /**< memory for inptu buffer    */
    static char historyBuffer[4096];        /**< memory for history buffer  */
    static shellmatta_instance_t instance;  /**< instance variable          */
    shellmatta_handle_t handle;             /**< handle used for accessing  */

    /** -# initialize the shellmatta instance */
    shellmatta_doInit(  &instance,
                        &handle,
                        buffer,
                        sizeof(buffer),
                        historyBuffer,
                        sizeof(historyBuffer),
                        "shellmatta->",         /**< prompt text                    */
                        NULL,                   /**< optional static command list   */
                        writeFct);              /**< write function                 */

    /** -# add the command - one command can only be added to one instance */
    shellmatta_addCmd(handle, &exampleCmd);

    /** -# ready to put some data in there */
    shellmatta_processData(handle, "example --version\r", 18u);

    return 0;
}

Compile time configuration

There are some defines you can use to change the behaviour of the shellmatta:

Define Description
SHELLMATTA_STRIP_PRINTF removes stdio dependencies to reduce footprint
SHELLMATTA_HELP_COMMAND string to overwrite the help command name
SHELLMATTA_HELP_ALIAS string to overwrite the help command alias
SHELLMATTA_HELP_HELP_TEXT string to overwrite the help command help
SHELLMATTA_HELP_USAGE_TEXT string to overwrite the help command usage
SHELLMATTA_AUTHENTICATION if defined this enables the authentication
SHELLMATTA_TRANSPORT if defined this enables the transport layer
SHELLMATTA_TRANSPORT_CRC_NO_LOOKUP disables lookup for transport layer crc32
SHELLMATTA_YMODEM_CRC_NO_LOOKUP disables lookup for ymodem crc16

Example

There is a quite confusing example in this repo to show and test some features.

To build it just rum make example. The binary will be built to output/example/example

It requires a serial device as parameter to run e.g. /dev/tty0

To be able to play around a bit you can create a local serial loopback using socat.

socat -d -d pty,raw,echo=0 pty,raw,echo=0

This will create two serial devices which are connected with a loopback. The device numbers in this example might change on your system.

You can use one of them starting the example e.g.

./output/example/example /dev/pts2

And use the other one to connect using the terminal tool of your choice e.g.

minicom -D /dev/pts3

Running tests

There are some tests implemented using catch2 and the function fake framework.

To run the tests just do:

make test

To be able to build the coverage report you need an installation of (gcovr)[https://pypi.org/project/gcovr].