From f9a0f5459feea4352a030af33c05e54fa00164f0 Mon Sep 17 00:00:00 2001 From: Josh Marinacci Date: Sat, 19 Jul 2014 11:28:51 -0700 Subject: [PATCH 1/7] switch to using generic Streams instead of hard coded to Serial --- Cmd.cpp | 41 +++++++++++++++++++++-------------------- Cmd.h | 4 ++-- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Cmd.cpp b/Cmd.cpp index 4d4500e..33fb54b 100755 --- a/Cmd.cpp +++ b/Cmd.cpp @@ -35,7 +35,7 @@ \file Cmd.c This implements a simple command line interface for the Arduino so that - its possible to execute individual functions within the sketch. + its possible to execute individual functions within the sketch. */ /**************************************************************************/ #include @@ -59,6 +59,8 @@ const char cmd_banner[] PROGMEM = "*************** CMD *******************"; const char cmd_prompt[] PROGMEM = "CMD >> "; const char cmd_unrecog[] PROGMEM = "CMD: Command not recognized."; +static Stream* stream; + /**************************************************************************/ /*! Generate the main command prompt @@ -68,13 +70,13 @@ void cmd_display() { char buf[50]; - Serial.println(); + stream->println(); strcpy_P(buf, cmd_banner); - Serial.println(buf); + stream->println(buf); strcpy_P(buf, cmd_prompt); - Serial.print(buf); + stream->print(buf); } /**************************************************************************/ @@ -100,7 +102,7 @@ void cmd_parse(char *cmd) { argv[++i] = strtok(NULL, " "); } while ((i < 30) && (argv[i] != NULL)); - + // save off the number of arguments for the particular command. argc = i; @@ -118,7 +120,7 @@ void cmd_parse(char *cmd) // command not recognized. print message and re-generate prompt. strcpy_P(buf, cmd_unrecog); - Serial.println(buf); + stream->println(buf); cmd_display(); } @@ -127,12 +129,12 @@ void cmd_parse(char *cmd) /*! This function processes the individual characters typed into the command prompt. It saves them off into the message buffer unless its a "backspace" - or "enter" key. + or "enter" key. */ /**************************************************************************/ void cmd_handler() { - char c = Serial.read(); + char c = stream->read(); switch (c) { @@ -140,23 +142,23 @@ void cmd_handler() // terminate the msg and reset the msg ptr. then send // it to the handler for processing. *msg_ptr = '\0'; - Serial.print("\r\n"); + stream->print("\r\n"); cmd_parse((char *)msg); msg_ptr = msg; break; - + case '\b': - // backspace - Serial.print(c); + // backspace + stream->print(c); if (msg_ptr > msg) { msg_ptr--; } break; - + default: // normal character entered. add it to the buffer - Serial.print(c); + stream->print(c); *msg_ptr++ = c; break; } @@ -170,7 +172,7 @@ void cmd_handler() /**************************************************************************/ void cmdPoll() { - while (Serial.available()) + while (stream->available()) { cmd_handler(); } @@ -179,25 +181,24 @@ void cmdPoll() /**************************************************************************/ /*! Initialize the command line interface. This sets the terminal speed and - and initializes things. + and initializes things. */ /**************************************************************************/ -void cmdInit(uint32_t speed) +void cmdInit(Stream *str) { + stream = str; // init the msg ptr msg_ptr = msg; // init the command table cmd_tbl_list = NULL; - // set the serial speed - Serial.begin(speed); } /**************************************************************************/ /*! Add a command to the command table. The commands should be added in - at the setup() portion of the sketch. + at the setup() portion of the sketch. */ /**************************************************************************/ void cmdAdd(char *name, void (*func)(int argc, char **argv)) diff --git a/Cmd.h b/Cmd.h index db509d9..d1f9b8c 100755 --- a/Cmd.h +++ b/Cmd.h @@ -32,7 +32,7 @@ *******************************************************************/ /*! - \file + \file \ingroup @@ -52,7 +52,7 @@ typedef struct _cmd_t struct _cmd_t *next; } cmd_t; -void cmdInit(uint32_t speed); +void cmdInit(Stream *); void cmdPoll(); void cmdAdd(char *name, void (*func)(int argc, char **argv)); uint32_t cmdStr2Num(char *str, uint8_t base); From 7dd421e575a62ac4ec8545d44d896d7c49f20238 Mon Sep 17 00:00:00 2001 From: Josh Marinacci Date: Sun, 20 Jul 2014 21:50:23 -0700 Subject: [PATCH 2/7] added support for using . as a line delimiter --- Cmd.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Cmd.cpp b/Cmd.cpp index 33fb54b..b4b14a5 100755 --- a/Cmd.cpp +++ b/Cmd.cpp @@ -138,6 +138,7 @@ void cmd_handler() switch (c) { + case '.': case '\r': // terminate the msg and reset the msg ptr. then send // it to the handler for processing. From 1a07df2049aa8914c0f9965279bb8bf5b83d18f6 Mon Sep 17 00:00:00 2001 From: Joshua Marinacci Date: Thu, 31 Jul 2014 13:48:04 -0700 Subject: [PATCH 3/7] moved the readme, updated it --- README | 12 --------- README.md | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 12 deletions(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index 2e2a83c..0000000 --- a/README +++ /dev/null @@ -1,12 +0,0 @@ -## CmdArduino - -by Akiba at Freaklabs.org - -The Arduino Command Line Interface, aka CmdArduino, is a simple shell that can -be run on an Arduino. It's nothing fancy and its main purpose is to allow users -to easily call their functions on a running Arduino via a simple serial -terminal. It also allows users to pass in arguments from the command line into -the functions they wrote so they can easily toggle pins, set blinking speed, -set pwm duty cycles, or whatever else might need command line user input. Using -it is fairly simple and just requires unzipping the files into the -"Arduino/libraries" sub-directory in the Arduino program folder. diff --git a/README.md b/README.md new file mode 100644 index 0000000..fee5fb5 --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +== CmdArduino + + +CmdArduino is a small library to parse commands from the Serial port +or anything else which implements the Stream API. It is based on the +original by Akiba at Freaklabs.org + +To use it create your command functions, then wire them up in your setup function. +All command functions must take `int arg_cnt, char ** args` as it's parameters +and return `void`. +Here's an example from a simple robot: + +``` +void left(int arg_cnt, char **args) { + LeftMotor->run(FORWARD); + delay(200); + LeftMotor->run(RELEASE); +} + +void right(int arg_cnt, char **args) { + RightMotor->run(FORWARD); + delay(200); + RightMotor->run(RELEASE); +} + +void setup() { + Serial.begin(9600); + cmdInit(&Serial); + cmdAdd('left',left); + cmdAdd('right',right); +} +``` + +Call `cmdInit` with a pointer to the stream you are using. Call `cmdAdd` +to attach a string command to the command function. Now you can type `left` +or `right` into your serial port to command the robot. The serial port +will be parsed using newline, `\n`, as the delimiter. The command name should +be the first item and any arguments after that. For example, to tell the robot +to turn left for three seconds, type in: + +``` +left 3000\n +``` + +Then the left function becomes + +``` +void left(int arg_cnt, char **args) { + int time = 200; + if(arg_cnt > 0) { + time = parseNum(args[0]); + } + LeftMotor->run(FORWARD); + delay(time); + LeftMotor->run(RELEASE); +} +``` + + + + + + + +== original readme + +The Arduino Command Line Interface, aka CmdArduino, is a simple shell that can +be run on an Arduino. It's nothing fancy and its main purpose is to allow users +to easily call their functions on a running Arduino via a simple serial +terminal. It also allows users to pass in arguments from the command line into +the functions they wrote so they can easily toggle pins, set blinking speed, +set pwm duty cycles, or whatever else might need command line user input. Using +it is fairly simple and just requires unzipping the files into the +"Arduino/libraries" sub-directory in the Arduino program folder. From 5c4110b80903fc1a77c520b3dc0a6dc21986f303 Mon Sep 17 00:00:00 2001 From: Slowhand_47 Date: Thu, 25 May 2017 10:01:02 +0200 Subject: [PATCH 4/7] Fix prototype of cmdAdd to remove Compiler warning New versions of the Arduino IDE throw a compiler warning if you pass a const char * aka string literal ("hello world") to a char * function argument. This commit changes the prototype to take a const char *. --- Cmd.cpp | 2 +- Cmd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cmd.cpp b/Cmd.cpp index b4b14a5..64b2f54 100755 --- a/Cmd.cpp +++ b/Cmd.cpp @@ -202,7 +202,7 @@ void cmdInit(Stream *str) at the setup() portion of the sketch. */ /**************************************************************************/ -void cmdAdd(char *name, void (*func)(int argc, char **argv)) +void cmdAdd(const char *name, void (*func)(int argc, char **argv)) { // alloc memory for command struct cmd_tbl = (cmd_t *)malloc(sizeof(cmd_t)); diff --git a/Cmd.h b/Cmd.h index d1f9b8c..3688a8c 100755 --- a/Cmd.h +++ b/Cmd.h @@ -54,7 +54,7 @@ typedef struct _cmd_t void cmdInit(Stream *); void cmdPoll(); -void cmdAdd(char *name, void (*func)(int argc, char **argv)); +void cmdAdd(const char *name, void (*func)(int argc, char **argv)); uint32_t cmdStr2Num(char *str, uint8_t base); #endif //CMD_H From 2e3d49bac46828182f4d1b143f67948d9e4b8285 Mon Sep 17 00:00:00 2001 From: Slowhand_47 Date: Thu, 25 May 2017 10:50:10 +0200 Subject: [PATCH 5/7] Fix examples The examples did not compile since cmdInit was changed to accept a Stream reference instead of a serial port speed. This change fixes all examples. It also adds a new function cmdGetStream(). This allows command functions to get access to the same stream that is used by the command interpreter itself. If you change a sketch from using the serial port to using a different stream, you can simply change the initialisation of the cmd module and all command functions can remain unchanged. The commit also contains a fix to ignore \n characters as they are usually not part of a valid command. This way, the code works with all terminals, no matter if they send \r or \r\n line endings. --- Cmd.cpp | 17 +++++++++++++++++ Cmd.h | 1 + ...ine_ex1_hello.pde => cmd_line_ex1_hello.ino} | 8 +++++--- ..._line_ex2_args.pde => cmd_line_ex2_args.ino} | 15 +++++++++------ ...led_blink.pde => cmd_line_ex3_led_blink.ino} | 5 +++-- ...md_line_ex4_pwm.pde => cmd_line_ex4_pwm.ino} | 7 ++++--- ...ons.pde => cmd_line_ex5_multi_functions.ino} | 16 +++++++++------- 7 files changed, 48 insertions(+), 21 deletions(-) rename examples/cmd_line_ex1_hello/{cmd_line_ex1_hello.pde => cmd_line_ex1_hello.ino} (91%) mode change 100755 => 100644 rename examples/cmd_line_ex2_args/{cmd_line_ex2_args.pde => cmd_line_ex2_args.ino} (90%) mode change 100755 => 100644 rename examples/cmd_line_ex3_led_blink/{cmd_line_ex3_led_blink.pde => cmd_line_ex3_led_blink.ino} (98%) mode change 100755 => 100644 rename examples/cmd_line_ex4_pwm/{cmd_line_ex4_pwm.pde => cmd_line_ex4_pwm.ino} (95%) mode change 100755 => 100644 rename examples/cmd_line_ex5_multi_functions/{cmd_line_ex5_multi_functions.pde => cmd_line_ex5_multi_functions.ino} (93%) mode change 100755 => 100644 diff --git a/Cmd.cpp b/Cmd.cpp index 64b2f54..05a9c5e 100755 --- a/Cmd.cpp +++ b/Cmd.cpp @@ -148,6 +148,11 @@ void cmd_handler() msg_ptr = msg; break; + case '\n': + // ignore newline characters. they usually come in pairs + // with the \r characters we use for newline detection. + break; + case '\b': // backspace stream->print(c); @@ -223,6 +228,18 @@ void cmdAdd(const char *name, void (*func)(int argc, char **argv)) cmd_tbl_list = cmd_tbl; } +/**************************************************************************/ +/*! + Get a pointer to the stream used by the interpreter. This allows + commands to use the same communication channel as the interpreter + without tracking it in the main program. +*/ +/**************************************************************************/ +Stream* cmdGetStream(void) +{ + return stream; +} + /**************************************************************************/ /*! Convert a string to a number. The base must be specified, ie: "32" is a diff --git a/Cmd.h b/Cmd.h index 3688a8c..d8818fb 100755 --- a/Cmd.h +++ b/Cmd.h @@ -55,6 +55,7 @@ typedef struct _cmd_t void cmdInit(Stream *); void cmdPoll(); void cmdAdd(const char *name, void (*func)(int argc, char **argv)); +Stream* cmdGetStream(void); uint32_t cmdStr2Num(char *str, uint8_t base); #endif //CMD_H diff --git a/examples/cmd_line_ex1_hello/cmd_line_ex1_hello.pde b/examples/cmd_line_ex1_hello/cmd_line_ex1_hello.ino old mode 100755 new mode 100644 similarity index 91% rename from examples/cmd_line_ex1_hello/cmd_line_ex1_hello.pde rename to examples/cmd_line_ex1_hello/cmd_line_ex1_hello.ino index abae6b5..1f8c95e --- a/examples/cmd_line_ex1_hello/cmd_line_ex1_hello.pde +++ b/examples/cmd_line_ex1_hello/cmd_line_ex1_hello.ino @@ -9,7 +9,8 @@ to them. void setup() { // init the command line and set it for a speed of 57600 - cmdInit(57600); + Serial.begin(57600); + cmdInit(&Serial); // add the commands to the command table. These functions must // already exist in the sketch. See the functions below. @@ -34,5 +35,6 @@ void loop() // That's it. void hello(int arg_cnt, char **args) { - Serial.println("Hello world."); -} + cmdGetStream()->println("Hello world."); +} + diff --git a/examples/cmd_line_ex2_args/cmd_line_ex2_args.pde b/examples/cmd_line_ex2_args/cmd_line_ex2_args.ino old mode 100755 new mode 100644 similarity index 90% rename from examples/cmd_line_ex2_args/cmd_line_ex2_args.pde rename to examples/cmd_line_ex2_args/cmd_line_ex2_args.ino index d837348..f405b91 --- a/examples/cmd_line_ex2_args/cmd_line_ex2_args.pde +++ b/examples/cmd_line_ex2_args/cmd_line_ex2_args.ino @@ -9,7 +9,8 @@ to them. void setup() { // init the command line and set it for a speed of 57600 - cmdInit(57600); + Serial.begin(57600); + cmdInit(&Serial); // add the commands to the command table. These functions must // already exist in the sketch. See the functions below. @@ -49,11 +50,13 @@ void loop() // Arg 9: yay void arg_display(int arg_cnt, char **args) { + Stream *s = cmdGetStream(); + for (int i=0; iprint("Arg "); + s->print(i); + s->print(": "); + s->println(args[i]); } -} +} diff --git a/examples/cmd_line_ex3_led_blink/cmd_line_ex3_led_blink.pde b/examples/cmd_line_ex3_led_blink/cmd_line_ex3_led_blink.ino old mode 100755 new mode 100644 similarity index 98% rename from examples/cmd_line_ex3_led_blink/cmd_line_ex3_led_blink.pde rename to examples/cmd_line_ex3_led_blink/cmd_line_ex3_led_blink.ino index 38ec070..b341869 --- a/examples/cmd_line_ex3_led_blink/cmd_line_ex3_led_blink.pde +++ b/examples/cmd_line_ex3_led_blink/cmd_line_ex3_led_blink.ino @@ -16,7 +16,8 @@ void setup() pinMode(led_pin, OUTPUT); // init the command line and set it for a speed of 57600 - cmdInit(57600); + Serial.begin(57600); + cmdInit(&Serial); // add the commands to the command table. These functions must // already exist in the sketch. See the functions below. @@ -82,4 +83,4 @@ void led_blink(int arg_cnt, char **args) } } - + diff --git a/examples/cmd_line_ex4_pwm/cmd_line_ex4_pwm.pde b/examples/cmd_line_ex4_pwm/cmd_line_ex4_pwm.ino old mode 100755 new mode 100644 similarity index 95% rename from examples/cmd_line_ex4_pwm/cmd_line_ex4_pwm.pde rename to examples/cmd_line_ex4_pwm/cmd_line_ex4_pwm.ino index 1b09cb8..b988dd9 --- a/examples/cmd_line_ex4_pwm/cmd_line_ex4_pwm.pde +++ b/examples/cmd_line_ex4_pwm/cmd_line_ex4_pwm.ino @@ -10,11 +10,12 @@ int pwm_pin = 10; void setup() { - // set the led pin as an output. its part of the demo. + // set the PWM pin as an output. its part of the demo. pinMode(pwm_pin, OUTPUT); // init the command line and set it for a speed of 57600 - cmdInit(57600); + Serial.begin(57600); + cmdInit(&Serial); // add the commands to the command table. These functions must // already exist in the sketch. See the functions below. @@ -66,4 +67,4 @@ void led_pwm(int arg_cnt, char **args) // if no args, turn off the LED analogWrite(pwm_pin, 0); } -} +} diff --git a/examples/cmd_line_ex5_multi_functions/cmd_line_ex5_multi_functions.pde b/examples/cmd_line_ex5_multi_functions/cmd_line_ex5_multi_functions.ino old mode 100755 new mode 100644 similarity index 93% rename from examples/cmd_line_ex5_multi_functions/cmd_line_ex5_multi_functions.pde rename to examples/cmd_line_ex5_multi_functions/cmd_line_ex5_multi_functions.ino index 9dedf17..4eedd2a --- a/examples/cmd_line_ex5_multi_functions/cmd_line_ex5_multi_functions.pde +++ b/examples/cmd_line_ex5_multi_functions/cmd_line_ex5_multi_functions.ino @@ -18,7 +18,8 @@ void setup() pinMode(pwm_pin, OUTPUT); // init the command line and set it for a speed of 57600 - cmdInit(57600); + Serial.begin(57600); + cmdInit(&Serial); // add the commands to the command table. These functions must // already exist in the sketch. See the functions below. @@ -54,7 +55,7 @@ void loop() // hello void hello(int arg_cnt, char **args) { - Serial.println("Hello world."); + cmdGetStream()->println("Hello world."); } // Display the contents of the args string array. @@ -73,12 +74,13 @@ void hello(int arg_cnt, char **args) // Arg 6: baby void arg_display(int arg_cnt, char **args) { + Stream *s = cmdGetStream(); for (int i=0; iprint("Arg "); + s->print(i); + s->print(": "); + s->println(args[i]); } } @@ -133,4 +135,4 @@ void led_pwm(int arg_cnt, char **args) // if no args, turn off the LED analogWrite(pwm_pin, 0); } -} +} From 81bdc22aa778181cdddfa740615da6340fcfb06f Mon Sep 17 00:00:00 2001 From: Rodrigo Alvarez Date: Tue, 5 Jan 2021 17:29:23 -0600 Subject: [PATCH 6/7] Fixed compilation issue for Arm-based systems (at least Arduino NANO 33 IOT) --- Cmd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Cmd.h b/Cmd.h index d8818fb..296f28a 100755 --- a/Cmd.h +++ b/Cmd.h @@ -43,6 +43,7 @@ #define MAX_MSG_SIZE 60 #include +#include // command line structure typedef struct _cmd_t From 0f3135d1a294a267656f670530ce4c11f0aeefc3 Mon Sep 17 00:00:00 2001 From: Rodrigo Alvarez Date: Fri, 8 Jan 2021 00:26:29 -0600 Subject: [PATCH 7/7] Removed '.' delimiter because it prevents using float numbers as arguments. --- Cmd.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Cmd.cpp b/Cmd.cpp index 05a9c5e..6a97855 100755 --- a/Cmd.cpp +++ b/Cmd.cpp @@ -138,7 +138,6 @@ void cmd_handler() switch (c) { - case '.': case '\r': // terminate the msg and reset the msg ptr. then send // it to the handler for processing.