├── .gitignore ├── LICENSE ├── examples └── main.c ├── cli_defs.h ├── .clang-format ├── cli.h ├── .pre-commit-config.yaml ├── README.md └── cli.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | venv 3 | .venv 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Sean Farrelly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/main.c: -------------------------------------------------------------------------------- 1 | #include "cli.h" 2 | 3 | static cli_status_t help_func(int argc, char **argv); 4 | static cli_status_t blink_func(int argc, char **argv); 5 | 6 | cmd_t cmd_tbl[] = {{.cmd = "help", .func = help_func}, {.cmd = "blink", .func = blink_func}}; 7 | 8 | cli_t cli; 9 | 10 | int main(void) 11 | { 12 | cli.println = user_uart_println; 13 | cli.cmd_tbl = cmd_tbl; 14 | cli.cmd_cnt = sizeof(cmd_tbl) / sizeof(cmd_t); 15 | cli_init(&cli); 16 | 17 | // enable UART receive-data interrupts here, so that UART_Rx_IrqHandler() gets 18 | // called when data is received 19 | 20 | while(1) { 21 | cli_process(&cli); 22 | } 23 | 24 | return 0; 25 | } 26 | 27 | /* For example.. */ 28 | void UART_Rx_IrqHandler() 29 | { 30 | char c = UART->RxData; 31 | cli_put(&cli, c); 32 | } 33 | 34 | void user_uart_println(char *string) 35 | { 36 | /* For example.. */ 37 | HAL_UART_Transmit_IT(&huart, string, strlen(string)); 38 | } 39 | 40 | cli_status_t help_func(int argc, char **argv) 41 | { 42 | cli.println("HELP function executed"); 43 | return CLI_OK; 44 | } 45 | 46 | cli_status_t blink_func(int argc, char **argv) 47 | { 48 | if(argc > 0) { 49 | if(strcmp(argv[1], "-help") == 0) { 50 | cli.println("BLINK help menu"); 51 | } else { 52 | return CLI_E_INVALID_ARGS; 53 | } 54 | } else { 55 | cli.println("BLINK function executed"); 56 | } 57 | return CLI_OK; 58 | } 59 | -------------------------------------------------------------------------------- /cli_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef _CLI_DEFS_H_ 2 | #define _CLI_DEFS_H_ 3 | 4 | #include 5 | 6 | #ifndef MAX_BUF_SIZE 7 | #define MAX_BUF_SIZE 128 /* Maximum size of CLI Rx buffer */ 8 | #endif 9 | 10 | #ifndef CMD_TERMINATOR 11 | #define CMD_TERMINATOR '\r' /* Delimiter denoting end of cmd from user */ 12 | #endif 13 | 14 | typedef enum { 15 | CLI_OK, /* API execution successful. */ 16 | CLI_E_NULL_PTR, /* Null pointer error. */ 17 | CLI_E_IO, 18 | CLI_E_CMD_NOT_FOUND, /* Command name not found in command table. */ 19 | CLI_E_INVALID_ARGS, /* Invalid function parameters/arguments. */ 20 | CLI_E_BUF_FULL, /* CLI buffer full. */ 21 | CLI_IDLE /* No command to execute at the moment */ 22 | } cli_status_t; 23 | 24 | /*! 25 | * @brief Function type declarations. 26 | */ 27 | typedef cli_status_t (*cmd_func_ptr_t)(int argc, char **argv); 28 | typedef void (*println_func_ptr_t)(char *string); 29 | 30 | /*! 31 | * @brief Command structure, consisting of a name and function pointer. 32 | */ 33 | typedef struct { 34 | char *cmd; /* Command name. */ 35 | cmd_func_ptr_t func; /* Function pointer to associated function. */ 36 | } cmd_t; 37 | 38 | /*! 39 | * @brief Command-line interface handle structure. 40 | */ 41 | typedef struct { 42 | println_func_ptr_t println; /* Function pointer to user defined println function. */ 43 | cmd_t *cmd_tbl; /* Pointer to series of commands which are to be accepted. */ 44 | size_t cmd_cnt; /* Number of commands in cmd_tbl. */ 45 | } cli_t; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # 3 | # Note: The list of ForEachMacros can be obtained using: 4 | # 5 | # git grep -h '^#define [^[:space:]]*FOR_EACH[^[:space:]]*(' include/ \ 6 | # | sed "s,^#define \([^[:space:]]*FOR_EACH[^[:space:]]*\)(.*$, - '\1'," \ 7 | # | sort | uniq 8 | # 9 | # References: 10 | # - https://clang.llvm.org/docs/ClangFormatStyleOptions.html 11 | 12 | --- 13 | BasedOnStyle: LLVM 14 | AlignConsecutiveMacros: AcrossComments 15 | AllowShortBlocksOnASingleLine: false 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortEnumsOnASingleLine: false 18 | AllowShortFunctionsOnASingleLine: None 19 | AllowShortIfStatementsOnASingleLine: false 20 | AllowShortLoopsOnASingleLine: false 21 | AttributeMacros: 22 | - __aligned 23 | - __deprecated 24 | - __packed 25 | - __printf_like 26 | - __syscall 27 | - __subsystem 28 | BreakBeforeBraces: Linux 29 | ColumnLimit: 100 30 | ConstructorInitializerIndentWidth: 8 31 | ContinuationIndentWidth: 8 32 | ForEachMacros: 33 | - 'FOR_EACH' 34 | - 'FOR_EACH_FIXED_ARG' 35 | - 'FOR_EACH_IDX' 36 | - 'FOR_EACH_IDX_FIXED_ARG' 37 | - 'FOR_EACH_NONEMPTY_TERM' 38 | - 'RB_FOR_EACH' 39 | - 'RB_FOR_EACH_CONTAINER' 40 | - 'SYS_DLIST_FOR_EACH_CONTAINER' 41 | - 'SYS_DLIST_FOR_EACH_CONTAINER_SAFE' 42 | - 'SYS_DLIST_FOR_EACH_NODE' 43 | - 'SYS_DLIST_FOR_EACH_NODE_SAFE' 44 | - 'SYS_SFLIST_FOR_EACH_CONTAINER' 45 | - 'SYS_SFLIST_FOR_EACH_CONTAINER_SAFE' 46 | - 'SYS_SFLIST_FOR_EACH_NODE' 47 | - 'SYS_SFLIST_FOR_EACH_NODE_SAFE' 48 | - 'SYS_SLIST_FOR_EACH_CONTAINER' 49 | - 'SYS_SLIST_FOR_EACH_CONTAINER_SAFE' 50 | - 'SYS_SLIST_FOR_EACH_NODE' 51 | - 'SYS_SLIST_FOR_EACH_NODE_SAFE' 52 | - '_WAIT_Q_FOR_EACH' 53 | - 'Z_FOR_EACH' 54 | - 'Z_FOR_EACH_ENGINE' 55 | - 'Z_FOR_EACH_EXEC' 56 | - 'Z_FOR_EACH_FIXED_ARG' 57 | - 'Z_FOR_EACH_FIXED_ARG_EXEC' 58 | - 'Z_FOR_EACH_IDX' 59 | - 'Z_FOR_EACH_IDX_EXEC' 60 | - 'Z_FOR_EACH_IDX_FIXED_ARG' 61 | - 'Z_FOR_EACH_IDX_FIXED_ARG_EXEC' 62 | - 'Z_GENLIST_FOR_EACH_CONTAINER' 63 | - 'Z_GENLIST_FOR_EACH_CONTAINER_SAFE' 64 | - 'Z_GENLIST_FOR_EACH_NODE' 65 | - 'Z_GENLIST_FOR_EACH_NODE_SAFE' 66 | IncludeBlocks: Regroup 67 | IncludeCategories: 68 | - Regex: '^".*\.h"$' 69 | Priority: 0 70 | - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|limits|locale|math|setjmp|signal|stdarg|stdbool|stddef|stdint|stdio|stdlib|string|tgmath|time|wchar|wctype)\.h>$' 71 | Priority: 1 72 | - Regex: '^\$' 73 | Priority: 2 74 | - Regex: '.*' 75 | Priority: 3 76 | IndentCaseLabels: false 77 | IndentWidth: 8 78 | # SpaceBeforeParens: ControlStatementsExceptControlMacros # clang-format >= 13.0 79 | UseTab: Always 80 | WhitespaceSensitiveMacros: 81 | - STRINGIFY 82 | - Z_STRINGIFY 83 | 84 | 85 | SpaceBeforeParens: false 86 | -------------------------------------------------------------------------------- /cli.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2019 Sean Farrelly 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | * File cli.h 25 | * Created by Sean Farrelly 26 | * Version 1.0 27 | * 28 | */ 29 | 30 | /*! @file cli.h 31 | * @brief Command-line interface API definitions. 32 | */ 33 | 34 | /*! 35 | * @defgroup CLI API 36 | */ 37 | #ifndef _CLI_H_ 38 | #define _CLI_H_ 39 | 40 | /*! CPP guard */ 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | 45 | #include "cli_defs.h" 46 | 47 | /*! 48 | * @brief This API initialises the command-line interface. 49 | * 50 | * @param[in] cli : Pointer to cli handle struct. 51 | * 52 | * @return cli_status_t 53 | */ 54 | cli_status_t cli_init(cli_t *cli); 55 | 56 | /*! 57 | * @brief This API deinitialises the command-line interface. 58 | * 59 | * @param[in] cli : Pointer to cli handle struct. 60 | * 61 | * @return cli_status_t 62 | */ 63 | cli_status_t cli_deinit(cli_t *cli); 64 | 65 | /*! 66 | * @brief This API must be periodically called by the user to process and 67 | * execute any commands received. 68 | * 69 | * @param[in] cli : Pointer to cli handle struct. 70 | * 71 | * @return cli_status_t 72 | */ 73 | cli_status_t cli_process(cli_t *cli); 74 | 75 | /*! 76 | * @brief This API should be called from the devices interrupt handler whenever 77 | * a character is received over the input stream. 78 | * 79 | * @param[in] cli : Pointer to cli handle struct. 80 | * @param[in] c : The character received. 81 | * 82 | * @return cli_status_t 83 | */ 84 | cli_status_t cli_put(cli_t *cli, char c); 85 | 86 | #ifdef __cplusplus 87 | } 88 | #endif /* End of CPP guard */ 89 | #endif /* CLI_H_ */ 90 | /** @}*/ 91 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.4.0 4 | hooks: 5 | - id: check-added-large-files # prevents giant files from being committed. 6 | - id: check-ast # simply checks whether the files parse as valid python. 7 | - id: check-byte-order-marker # forbids files which have a utf-8 byte-order marker. 8 | - id: check-builtin-literals # requires literal syntax when initializing empty or zero python builtin types. 9 | - id: check-case-conflict # checks for files that would conflict in case-insensitive filesystems. 10 | - id: check-docstring-first # checks a common error of defining a docstring after code. 11 | - id: check-executables-have-shebangs # ensures that (non-binary) executables have a shebang. 12 | - id: check-json # checks json files for parseable syntax. 13 | - id: check-shebang-scripts-are-executable # ensures that (non-binary) files with a shebang are executable. 14 | - id: check-merge-conflict # checks for files that contain merge conflict strings. 15 | - id: check-symlinks # checks for symlinks which do not point to anything. 16 | - id: check-toml # checks toml files for parseable syntax. 17 | - id: check-xml # checks xml files for parseable syntax. 18 | - id: check-yaml # checks yaml files for parseable syntax. 19 | - id: debug-statements # checks for debugger imports and py37+ `breakpoint()` calls in python source. 20 | - id: destroyed-symlinks # detects symlinks which are changed to regular files with a content of a path which that symlink was pointing to. 21 | - id: detect-private-key # detects the presence of private keys. 22 | # - id: double-quote-string-fixer # replaces double quoted strings with single quoted strings. 23 | - id: end-of-file-fixer # ensures that a file is either empty, or ends with one newline. 24 | - id: file-contents-sorter # sorts the lines in specified files (defaults to alphabetical). you must provide list of target files as input in your .pre-commit-config.yaml file. 25 | - id: fix-byte-order-marker # removes utf-8 byte order marker. 26 | - id: mixed-line-ending # replaces or checks mixed line ending. 27 | - id: name-tests-test # this verifies that test files are named correctly. 28 | # - id: no-commit-to-branch # don't commit to branch 29 | - id: requirements-txt-fixer # sorts entries in requirements.txt. 30 | - id: sort-simple-yaml # sorts simple yaml files which consist only of top-level keys, preserving comments and blocks. 31 | - id: trailing-whitespace # trims trailing whitespace. 32 | 33 | - repo: https://github.com/pre-commit/mirrors-prettier 34 | rev: v2.7.1 35 | hooks: 36 | - id: prettier 37 | files: \.(js|ts|jsx|tsx|css|less|html|markdown|md|yaml|yml|rst)$ 38 | 39 | - repo: https://github.com/pre-commit/mirrors-clang-format 40 | rev: v16.0.6 41 | hooks: 42 | - id: clang-format 43 | 44 | - repo: https://github.com/jorisroovers/gitlint 45 | rev: v0.18.0 46 | hooks: 47 | - id: gitlint 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cli-embedded 2 | 3 | A simple command-line interface for use in embedded systems. 4 | This useful tool allows a user to remotely invoke functions on their device by specifing commands (and parameters) over a byte stream protocol. 5 | 6 | ## Features 7 | 8 | - Remotely invoke functions on device. 9 | - Ability to process function parameters. 10 | - Statically allocated memory. 11 | - Backspace to remove unintentional keypresses. 12 | 13 | ## Introduction 14 | 15 | This package contains files to implement a simple command-line interface. 16 | The package includes cli.h, and cli.c. 17 | 18 | ## Integration details 19 | 20 | - Integrate cli.h and cli.c files into your project. 21 | - Include the cli.h header file in your code like below. 22 | 23 | ```c 24 | #include "cli.h" 25 | ``` 26 | 27 | ## File information 28 | 29 | - cli.h : This header file contains the definitions of the cli user API. 30 | - cli.c : This source file contains the implementation of the CLI. 31 | 32 | ## Supported interfaces 33 | 34 | - Typically, UART. 35 | - .. Any byte-stream based interface. 36 | 37 | ## Integration Guide 38 | 39 | ### Initialising the CLI 40 | 41 | To correctly set up the CLI, the user must do four things: 42 | 43 | 1. Create a table of commands which are to be accepted by the CLI, using the cmd_t structure. 44 | 45 | **Note**: Command functions must use the `cli_status_t (*func)(int argc, char **argv)` definition. 46 | 47 | ```c 48 | cmd_t cmds[2] = { 49 | { 50 | .cmd = "help", 51 | .func = help_func 52 | }, 53 | { 54 | .cmd = "echo", 55 | .func = echo_func 56 | } 57 | }; 58 | ``` 59 | 60 | 2. Place the cli_put() function within the devices interrupt handler responsible for receiving 1 byte over the communication protocol. 61 | 62 | ```c 63 | void UART_Rx_IrqHandler() 64 | { 65 | char c = UART->RxData; 66 | cli_put(&cli, c); 67 | } 68 | ``` 69 | 70 | 3. Create an instance of the CLI handle structure, and fill in the required parameters. 71 | 72 | ```c 73 | cli_status_t rslt = CLI_OK; 74 | 75 | cli_t cli = { 76 | .println = user_uart_println, 77 | .cmd_tbl = cmds, 78 | .cmd_cnt = sizeof(cmds) / sizeof(cmd_t) 79 | }; 80 | 81 | if((rslt = cli_init(&cli)) != CLI_OK) 82 | { 83 | printf("CLI: Failed to initialise"); 84 | } 85 | ``` 86 | 87 | 4. Periodically call the `cli_process()` function in order to process incoming commands. 88 | 89 | ## User Guide 90 | 91 | To interface with the CLI, the user must open a communication stream on their chosen protocol (typically UART). 92 | The default end-of-delimiter used by the application is '\r', however this can be changed. 93 | The user can invoke their functions by sending: 94 | `echo \r` 95 | 96 | - echo, the name of the command 97 | - , first parameter (if required). 98 | 99 | ## Function templates 100 | 101 | ```c 102 | void user_uart_println(char *string) 103 | { 104 | /* For example.. */ 105 | HAL_UART_Transmit_IT(&huart, string, strlen(string)); 106 | } 107 | 108 | cli_status_t help_func(int argc, char **argv) 109 | { 110 | cli_status_t rslt = CLI_OK; 111 | 112 | /* Code executed when 'help' is entered */ 113 | 114 | return rslt; 115 | } 116 | 117 | cli_status_t echo_func(int argc, char **argv) 118 | { 119 | cli_status_t rslt = CLI_OK; 120 | 121 | /* Code executed when 'echo' is entered */ 122 | 123 | return rslt; 124 | } 125 | ``` 126 | -------------------------------------------------------------------------------- /cli.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2019 Sean Farrelly 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | * File cli.c 25 | * Created by Sean Farrelly 26 | * Version 1.0 27 | * 28 | */ 29 | 30 | /*! @file cli.c 31 | * @brief Implementation of command-line interface. 32 | */ 33 | #include "cli.h" 34 | 35 | #include 36 | #include 37 | 38 | static volatile uint8_t buf[MAX_BUF_SIZE]; /* CLI Rx byte-buffer */ 39 | static volatile uint8_t *buf_ptr; /* Pointer to Rx byte-buffer */ 40 | 41 | static uint8_t cmd_buf[MAX_BUF_SIZE]; /* CLI command buffer */ 42 | static volatile uint8_t cmd_pending; 43 | 44 | const char cli_prompt[] = ">> "; /* CLI prompt displayed to the user */ 45 | const char cli_unrecog[] = "CMD: Command not recognised\r\n"; 46 | 47 | /*! 48 | * @brief This internal API prints a message to the user on the CLI. 49 | */ 50 | static void cli_print(cli_t *cli, const char *msg); 51 | 52 | /*! 53 | * @brief This API initialises the command-line interface. 54 | */ 55 | cli_status_t cli_init(cli_t *cli) 56 | { 57 | /* Set buffer ptr to beginning of buf */ 58 | buf_ptr = buf; 59 | 60 | cmd_pending = 0; 61 | 62 | /* Print the CLI prompt. */ 63 | cli_print(cli, cli_prompt); 64 | 65 | return CLI_OK; 66 | } 67 | 68 | /*! 69 | * @brief This API deinitialises the command-line interface. 70 | */ 71 | cli_status_t cli_deinit(cli_t *cli) 72 | { 73 | return CLI_OK; 74 | } 75 | 76 | /*! @brief This API must be periodically called by the user to process and 77 | * execute any commands received. 78 | */ 79 | cli_status_t cli_process(cli_t *cli) 80 | { 81 | if(!cmd_pending) 82 | return CLI_IDLE; 83 | 84 | uint8_t argc = 0; 85 | char *argv[30]; 86 | 87 | /* Get the first token (cmd name) */ 88 | argv[argc] = strtok(cmd_buf, " "); 89 | 90 | /* Walk through the other tokens (parameters) */ 91 | while((argv[argc] != NULL) && (argc < 30)) { 92 | argv[++argc] = strtok(NULL, " "); 93 | } 94 | 95 | /* Search the command table for a matching command, using argv[0] 96 | * which is the command name. */ 97 | for(size_t i = 0; i < cli->cmd_cnt; i++) { 98 | if(strcmp(argv[0], cli->cmd_tbl[i].cmd) == 0) { 99 | /* Found a match, execute the associated function. */ 100 | cli_status_t return_value = cli->cmd_tbl[i].func(argc, argv); 101 | cli_print(cli, cli_prompt); /* Print the CLI prompt to the user. */ 102 | cmd_pending = 0; 103 | return return_value; 104 | } 105 | } 106 | 107 | /* Command not found */ 108 | cli_print(cli, cli_unrecog); 109 | 110 | cli_print(cli, cli_prompt); /* Print the CLI prompt to the user. */ 111 | 112 | cmd_pending = 0; 113 | return CLI_E_CMD_NOT_FOUND; 114 | } 115 | 116 | /*! 117 | * @brief This API should be called from the devices interrupt handler whenever 118 | * a character is received over the input stream. 119 | */ 120 | cli_status_t cli_put(cli_t *cli, char c) 121 | { 122 | switch(c) { 123 | case CMD_TERMINATOR: 124 | 125 | if(!cmd_pending) { 126 | *buf_ptr = '\0'; /* Terminate the msg and reset the msg ptr. */ 127 | strcpy(cmd_buf, buf); /* Copy string to command buffer for processing. */ 128 | cmd_pending = 1; 129 | buf_ptr = buf; /* Reset buf_ptr to beginning. */ 130 | } 131 | break; 132 | 133 | case '\b': 134 | /* Backspace. Delete character. */ 135 | if(buf_ptr > buf) 136 | buf_ptr--; 137 | break; 138 | 139 | default: 140 | /* Normal character received, add to buffer. */ 141 | if((buf_ptr - buf) < MAX_BUF_SIZE) 142 | *buf_ptr++ = c; 143 | else 144 | return CLI_E_BUF_FULL; 145 | break; 146 | } 147 | } 148 | 149 | /*! 150 | * @brief Print a message on the command-line interface. 151 | */ 152 | static void cli_print(cli_t *cli, const char *msg) 153 | { 154 | /* Temp buffer to store text in ram first */ 155 | char buf[50]; 156 | 157 | strcpy(buf, msg); 158 | cli->println(buf); 159 | } 160 | --------------------------------------------------------------------------------