Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 88 additions & 21 deletions examples/Terminal-LED-Control/Terminal-LED-Control.ino
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
#include <Wire.h>
#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() {
Expand All @@ -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() {
Expand Down
64 changes: 61 additions & 3 deletions src/terminal_commander.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,16 +414,17 @@ 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;
}
}
}
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;
}
}
Expand Down Expand Up @@ -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;
}
}
16 changes: 15 additions & 1 deletion src/terminal_commander.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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.
*
Expand All @@ -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 <functional> which is not supported for AVR cores
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -535,6 +547,8 @@
* @returns void
*/
void printTwoWireRegister(uint8_t i2c_register);

int parseCmd(const char* input, struct cmd_param* result);
};
}
#endif