diff --git a/examples/Terminal-LED-Control/Terminal-LED-Control.ino b/examples/Terminal-LED-Control/Terminal-LED-Control.ino index 672a834..a82330a 100644 --- a/examples/Terminal-LED-Control/Terminal-LED-Control.ino +++ b/examples/Terminal-LED-Control/Terminal-LED-Control.ino @@ -1,12 +1,17 @@ #include #include "terminal_commander.h" + +/* BEGIN: FEATURE enable/disable */ // I2C communication bus speed #define I2C_CLK_RATE (400000L) // UART serial console communication baud rate #define TERM_BAUD_RATE (115200L) +#define FEATURE_ECHO +/* END: FEATURE enable/disable */ + TerminalCommander::Terminal Terminal(&Serial, &Wire); void setup() { @@ -25,33 +30,95 @@ void setup() { // Option1: using a lambda expression that matches // type TerminalCommander::user_callback_char_fn_t - Terminal.onCommand("led", [](char* args, size_t size) { - if (args == nullptr || size == 0) { - Serial.println(F("Error: No LED state provided")); - return; - } - - // type 'led on' or 'led off' in terminal turn built-in LED on/off - char cmd[size + 1] = {'\0'}; - memcpy(cmd, args, size); - if (strcmp(cmd, "on") == 0) { - digitalWrite(LED_BUILTIN, HIGH); - } - else if (strcmp(cmd, "off") == 0) { - digitalWrite(LED_BUILTIN, LOW); - } - else { - Serial.println(F("Error: Unrecognized LED state")); - } - }); + Terminal.onCommand("led", &led_function); + // Option2: using a pointer to a function that matches // type TerminalCommander::user_callback_char_fn_t - Terminal.onCommand("MyCommand", &my_function); + Terminal.onCommand("MyCommand", &my_function); + Terminal.onCommand("digitalWrite", &digitalWrite_function); + Terminal.onCommand("help", &help_function); +#ifdef FEATURE_ECHO + Terminal.echo(true); +#endif +} + + +int keyword2value(const char *str) { + if (strcmp(str, "HIGH") == 0) return 1; + if (strcmp(str, "LOW") == 0) return 0; + if (strcmp(str, "1") == 0) return 1; + if (strcmp(str, "0") == 0) return 0; + if (strcmp(str, "on") == 0) return 1; + if (strcmp(str, "off") == 0) return 0; + if (strcmp(str, "OUTPUT") == 0) return 1; + if (strcmp(str, "INPUT") == 0) return 0; + if (strcmp(str, "INPUT_PULLUP") == 0) return 2; + return -1; +} + + + +void led_function(struct cmd_param param) { + int val = 0; + + val = keyword2value(param.argv[0]); + + if ((param.argc != 1)||(val < 0)) + { + Serial.println(F("Bad parameter,Example: led off")); + return; + } + + digitalWrite(LED_BUILTIN, val); } -void my_function(char* args, size_t size) { + +void my_function(struct cmd_param param) { // your code goes here + //list all the command parameters + Serial.println(param.argc); + Serial.println(param.argv[0]); + Serial.println(param.argv[1]); + Serial.println(param.argv[2]); + Serial.println(param.argv[3]); + Serial.println(param.argv[4]); +} + + +void digitalWrite_function(struct cmd_param param) { + int val = 0; + + val = keyword2value(param.argv[1]); + + if ((param.argc != 2) ||(val < 0)) + { + Serial.println(F("Bad parameter,Example: digitalWrite 13 HIGH")); + return; + } + + digitalWrite(atoi(param.argv[0]), val); +} + + +void help_function(struct cmd_param param) { + Serial.println("help:\n" + "led on - led on\n" + "led off - led off\n" + "scan - i2c scan\n" + "i2c r - i2c read\n" + "i2c w - i2c write\n" + "digitalWrite - digitalWrite pin, HIGH/LOW \n" + "help - list command\n" + "MyCommand - your test command\n" + "\n" + "Example:\n" + "* read four registers of some device with address 0x31 and starting at register address 0x02\n" + " >>i2c r 31 02 00 00 00\n" + "* test your command\n" + " >>MyCommand P1 P2 P3 P4 P5\n" + "* GPIO13 to HIGH\n" + " >>digitalWrite 13 HIGH\n"); } void loop() { diff --git a/src/terminal_commander.cpp b/src/terminal_commander.cpp index fc3c367..b095d8e 100644 --- a/src/terminal_commander.cpp +++ b/src/terminal_commander.cpp @@ -414,8 +414,8 @@ namespace TerminalCommander { break; } } - - this->userCharCallbacks[k].callback(this->command.pArgs, (size_t)(user_args_length)); + this->parseCmd(this->command.pArgs,&(this->command.cmd_param_value)); + this->userCharCallbacks[k].callback((struct cmd_param)this->command.cmd_param_value); return true; } } @@ -423,7 +423,8 @@ namespace TerminalCommander { else { for (uint8_t k = 0; k < this->numUserCharCallbacks; k++) { if (strcmp(this->command.data, this->userCharCallbacks[k].command) == 0) { - this->userCharCallbacks[k].callback((char*)nullptr, (size_t)0U); + this->command.cmd_param_value = {0}; + this->userCharCallbacks[k].callback((struct cmd_param)this->command.cmd_param_value); return true; } } @@ -644,4 +645,61 @@ namespace TerminalCommander { } this->pSerial->println(i2c_register, HEX); } + + +int Terminal::parseCmd(const char* input, struct cmd_param* result) { + int i = 0; + char buffer[MAX_CMD_ARGC_NUM * MAX_CMD_ARGV_STR_LENGTH] = {0}; + + if((result == NULL)||(input == NULL)) + { + return -1; + } + result->argc = 0; + memset(result->argv, 0, sizeof(result->argv)); + + strncpy(buffer, input, sizeof(buffer) - 1); + buffer[sizeof(buffer) - 1] = '\0'; + + // remove '\n' of string end + i = MAX_CMD_ARGC_NUM * MAX_CMD_ARGV_STR_LENGTH -1; + for( ; i > 0 ;i--) + { + if(buffer[i] == '\n') + { + buffer[i] = 0; + break; + } + else + if(buffer[i] != 0) + { + break; + } + } + + // remove '\r' of string end + for( ;i > 0 ;i--) + { + if(buffer[i] == '\r') + { + buffer[i] = 0; + break; + } + else + if(buffer[i] != 0) + { + break; + } + } + + char* token = strtok(buffer, " "); + while (token != NULL && result->argc < MAX_CMD_ARGC_NUM) { + strncpy(result->argv[result->argc], token, (MAX_CMD_ARGV_STR_LENGTH -1)); + result->argv[result->argc][MAX_CMD_ARGV_STR_LENGTH -1] = '\0'; + + result->argc++; + token = strtok(NULL, " "); + } + return 0; + } } diff --git a/src/terminal_commander.h b/src/terminal_commander.h index 319e8cc..39dc1ea 100644 --- a/src/terminal_commander.h +++ b/src/terminal_commander.h @@ -22,6 +22,10 @@ // Maximum number of unique user-defined commands #define MAX_USER_COMMANDS ( 10U) + + #define MAX_CMD_ARGC_NUM (5) + #define MAX_CMD_ARGV_STR_LENGTH (10 + 1) //each parameter max 10 char with '\0' + #if (TERM_TWOWIRE_BUFFER_SIZE > TERM_CHAR_BUFFER_SIZE) #error "TwoWire buffer size must not exceed terminal character buffer size" @@ -30,6 +34,11 @@ #warning "Wire library does not support transactions exceeding 32 bytes" #endif +struct cmd_param { + int argc; //parsed cmd parameter_cnt(max MAX_CMD_ARGC_NUM) + char argv[MAX_CMD_ARGC_NUM][MAX_CMD_ARGV_STR_LENGTH]; //parsed cmd parameter +}; + /** * @brief Compares two null-terminated byte strings lexicographically. * @@ -49,7 +58,7 @@ namespace TerminalCommander { namespace TerminalCommanderTypes { /** @brief User char* callback lambda expression that does not capture local variables */ - typedef void (user_callback_char_fn_t)(char*, size_t); + typedef void (user_callback_char_fn_t)(struct cmd_param); // alt: the following works for lambda expressions that capture local variables // e.g. [&](){}, but requires #include which is not supported for AVR cores @@ -222,6 +231,9 @@ /** Total length in char and without spaces of buffer after command delimiter character*/ uint8_t argsLength; + + /* after parsed command parameters */ + struct cmd_param cmd_param_value; /** Index of current character in incoming serial rx data array */ uint8_t index; @@ -535,6 +547,8 @@ * @returns void */ void printTwoWireRegister(uint8_t i2c_register); + + int parseCmd(const char* input, struct cmd_param* result); }; } #endif