From c431946efc8891c333a5f01917dc509f4dab8eff Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:48:27 -0700 Subject: [PATCH 01/14] style: add missing this-> --- terminal_commander.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index 60e49ca..a76d8d8 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -100,7 +100,7 @@ namespace TerminalCommander { break; } } - writeErrorMsgToSerialBuffer(this->lastError.set(InvalidSerialCmdLength), this->lastError.message); + this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidSerialCmdLength), this->lastError.message); this->pSerial->println(this->lastError.message); this->lastError.clear(); this->command.reset(); @@ -139,7 +139,7 @@ namespace TerminalCommander { // end of serial input data has been reached if (data_index == 0) { // input serial buffer is empty - writeErrorMsgToSerialBuffer(this->lastError.set(NoInput), this->lastError.message); + this->writeErrorMsgToSerialBuffer(this->lastError.set(NoInput), this->lastError.message); return; } @@ -297,7 +297,7 @@ namespace TerminalCommander { // Scan TwoWire bus to explore and query available devices case I2C_SCAN: { if (this->command.argsLength != 0) { - writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); + this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); return; } @@ -348,7 +348,7 @@ namespace TerminalCommander { } // no terminal commander or user-defined command was identified - writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); + this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); } break; } @@ -388,14 +388,14 @@ namespace TerminalCommander { } else { // an input buffer value was unrecognized - writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedInput), this->lastError.message); + this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedInput), this->lastError.message); return false; } } if (idx == 0) { // input serial buffer is empty - writeErrorMsgToSerialBuffer(this->lastError.set(NoInput), this->lastError.message); + this->writeErrorMsgToSerialBuffer(this->lastError.set(NoInput), this->lastError.message); return false; } @@ -511,6 +511,6 @@ namespace TerminalCommander { /// TODO: move as much of this as possible into an error_t member void TerminalCommander::writeErrorMsgToSerialBuffer(error_type_t error, char *message) { memset(message, '\0', TERM_ERROR_MESSAGE_SIZE); - strcpy_P(message, (char *)pgm_read_word(&(string_error_table[error]))); + strcpy_P(message, (char *)pgm_read_word(&(this->string_error_table[error]))); } } From f61574540513a4f8704103ca028b70688b5c411e Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:44:50 -0700 Subject: [PATCH 02/14] fix: cannot root str with different return types --- terminal_commander.cpp | 2 +- terminal_commander.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index a76d8d8..dd17c39 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -7,7 +7,7 @@ #include "terminal_commander.h" -int16_t strcmp(const char *s1, const char *s2) { +int strcmp(const char *s1, const char *s2) { const unsigned char *p1 = (const unsigned char *)s1; const unsigned char *p2 = (const unsigned char *)s2; diff --git a/terminal_commander.h b/terminal_commander.h index 9956997..12101ff 100644 --- a/terminal_commander.h +++ b/terminal_commander.h @@ -43,7 +43,7 @@ * @param s2 Null-terminated byte string. * @return int */ - extern int16_t strcmp(const char *s1, const char *s2) __attribute__((weak)); + extern int strcmp(const char *s1, const char *s2) __attribute__((weak)); namespace TerminalCommander { namespace TerminalCommanderTypes { From 54db1dc88cb5e47ec91eb5f7a7e90867f6a50e77 Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:56:13 -0700 Subject: [PATCH 03/14] feat: strncasecmp --- terminal_commander.cpp | 29 ++++++++++++++++++++++------- terminal_commander.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index dd17c39..3732588 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -25,6 +25,26 @@ int strcmp(const char *s1, const char *s2) { return 0; } +int tolower(int c) { + return c >= 'A' && c <= 'Z' ? c + 32 : c; +} + +int strncasecmp(const char *s1, const char *s2, size_t num) { + const unsigned char *p1 = (const unsigned char *)s1; + const unsigned char *p2 = (const unsigned char *)s2; + + if (num == 0) return 0; + + while (num-- != 0 && tolower(*p1) == tolower(*p2)) { + if (num == 0 || *p1 == '\0' || *p2 == '\0') + break; + p1++; + p2++; + } + + return tolower(*p1) - tolower(*p2); +} + namespace TerminalCommander { using namespace TerminalCommanderTypes; @@ -169,9 +189,7 @@ namespace TerminalCommander { } this->command.argsLength = data_index - this->command.cmdLength; - if ((this->command.data[0] == 'i' || this->command.data[0] == 'I') && - (this->command.data[1] == '2' || this->command.data[1] == '@') && - (this->command.data[2] == 'c' || this->command.data[2] == 'C')) { + if (strncasecmp(this->command.data, "I2C", 3)) { // test if buffer represents hex value pairs and convert these from ASCII to hex if (!this->parseTwoWireData()) { @@ -199,10 +217,7 @@ namespace TerminalCommander { return; } } - else if ((this->command.data[0] == 's' || this->command.data[0] == 'S') && - (this->command.data[1] == 'c' || this->command.data[1] == 'C') && - (this->command.data[2] == 'a' || this->command.data[2] == 'A') && - (this->command.data[3] == 'n' || this->command.data[3] == 'N')) { + if (strncasecmp(this->command.data, "SCAN", 4)) { this->command.protocol = I2C_SCAN; } diff --git a/terminal_commander.h b/terminal_commander.h index 12101ff..ae8c388 100644 --- a/terminal_commander.h +++ b/terminal_commander.h @@ -45,6 +45,34 @@ */ extern int strcmp(const char *s1, const char *s2) __attribute__((weak)); + /** + * @brief Convert a single ASCII character to its lowercase counterpart. + * + * @details Ignores characters outsize of A-Z. + * + * @param c ASCII Character + * @return int + */ + extern int tolower(int c) __attribute__((weak)); + + /** + * @brief Compares two null-terminated byte strings lexicographically, + * limited to a maximum `num` characters. Case-insensitive. + * + * @details Returns: + * Negative Value: If s1 appears before s2 in lexicographical order. Or, + * the first not-matching character in s1 has a greater + * ASCII value than the corresponding character in s2. + * Zero: If s1 and s2 compare equal. + * Positive Value: If s1 appears after s2 in lexicographical order. + * + * @param s1 Null-terminated byte string. + * @param s2 Null-terminated byte string. + * @param num Maximum number of characters to compare. + * @return int + */ + extern int strncasecmp(const char *s1, const char *s2, size_t num) __attribute__((weak)); + namespace TerminalCommander { namespace TerminalCommanderTypes { // the following only works for lambda expressions that do NOT capture local variables, e.g. [](){} From a3eaba453209f0535f696cd50df391332766de8b Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:58:46 -0700 Subject: [PATCH 04/14] fix: missing else --- terminal_commander.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index 3732588..17b995b 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -217,7 +217,7 @@ namespace TerminalCommander { return; } } - if (strncasecmp(this->command.data, "SCAN", 4)) { + else if (strncasecmp(this->command.data, "SCAN", 4)) { this->command.protocol = I2C_SCAN; } From 50c420fc469c476d41247cfd61a611bfff2935a5 Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:07:16 -0700 Subject: [PATCH 05/14] refactor: split command types into individual functions --- terminal_commander.cpp | 300 +++++++++++++++++++++-------------------- terminal_commander.h | 6 + 2 files changed, 163 insertions(+), 143 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index 17b995b..29ed3a2 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -123,7 +123,6 @@ namespace TerminalCommander { this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidSerialCmdLength), this->lastError.message); this->pSerial->println(this->lastError.message); this->lastError.clear(); - this->command.reset(); } else if (this->command.complete) { this->serialCommandProcessor(); @@ -133,10 +132,10 @@ namespace TerminalCommander { this->lastError.clear(); } this->pSerial->print(F(">> ")); - - // clear the input buffer array and reset serial logic - this->command.reset(); } + + // clear the input buffer array and reset serial logic + this->command.reset(); } void TerminalCommander::onCommand(const char* command, user_callback_char_fn_t callback) { @@ -222,150 +221,25 @@ namespace TerminalCommander { } switch (command.protocol) { - case I2C_READ: { - this->pSerial->println(F("I2C Read")); - const uint8_t i2c_address = - (uint8_t)((this->command.twowire[0] << 4) + this->command.twowire[1]); - this->printTwoWireAddress(i2c_address); - const uint8_t i2c_register = - (uint8_t)((this->command.twowire[2] << 4) + this->command.twowire[3]); - this->printTwoWireRegister(i2c_register); - - uint8_t twi_read_index = 0; // start at zero so we can use the entire buffer for read - this->command.flushTwoWire(); // flush the existing twowire buffer of all data - - this->pWire->beginTransmission(i2c_address); - this->pWire->write(i2c_register); - twi_error_type_t error = (twi_error_type_t)(this->pWire->endTransmission()); - if (error == NACK_ADDRESS) { - this->pSerial->println(F("Error: I2C read attempt recieved NACK")); - return; - } - delayMicroseconds(50); - this->pWire->requestFrom(i2c_address, (uint8_t)((this->command.argsLength >> 1) - 1)); - delayMicroseconds(50); - while(this->pWire->available()) { - if (twi_read_index >= TERM_TWOWIRE_BUFFER_SIZE) { - this->writeErrorMsgToSerialBuffer(this->lastError.set(IncomingTwoWireReadLength), this->lastError.message); - return; - } - this->command.twowire[twi_read_index] = (uint8_t)this->pWire->read(); - twi_read_index++; - } - - this->pSerial->print(F("Read Data:")); - if (twi_read_index == 0) { - this->pSerial->print(F(" No Data Received")); - } - else { - for(uint8_t k = 0; k < twi_read_index; k++) { - if (this->command.twowire[k] < 0x10) { - this->pSerial->print(F(" 0x0")); - } - else { - this->pSerial->print(F(" 0x")); - } - this->pSerial->print(this->command.twowire[k], HEX); - } - } - this->pSerial->print('\n'); - - } - break; - - case I2C_WRITE: { - this->pSerial->println(F("I2C Write")); - const uint8_t i2c_address = - (uint8_t)((this->command.twowire[0] << 4) + this->command.twowire[1]); - this->printTwoWireAddress(i2c_address); - const uint8_t i2c_register = - (uint8_t)((this->command.twowire[2] << 4) + this->command.twowire[3]); - this->printTwoWireRegister(i2c_register); + case I2C_READ: + i2cRead(); + break; - this->pWire->beginTransmission(i2c_address); - this->pWire->write(i2c_register); - for (uint8_t k = 4; k < this->command.argsLength; k += 2) { - this->pWire->write((16 * this->command.twowire[k]) + this->command.twowire[k+1]); - } - twi_error_type_t error = (twi_error_type_t)(this->pWire->endTransmission()); - if (error == NACK_ADDRESS) { - this->pSerial->println(F("Error: I2C write attempt recieved NACK")); - return; - } - else { - this->pSerial->print(F("Write Data:")); - for(uint8_t k = 4; k < this->command.argsLength; k += 2) { - uint8_t write_data = (16 * this->command.twowire[k]) + this->command.twowire[k+1]; - if (write_data < 0x01) { - this->pSerial->print(F(" 0x0")); - } - else { - this->pSerial->print(F(" 0x")); - } - this->pSerial->print(write_data, HEX); - } - this->pSerial->print('\n'); - } - } - break; + case I2C_WRITE: + i2cWrite(); + break; // Scan TwoWire bus to explore and query available devices - case I2C_SCAN: { - if (this->command.argsLength != 0) { - this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); - return; - } + case I2C_SCAN: + i2cScan(); + break; - this->pSerial->println(F("Scan I2C Bus for Available Devices")); - this->scanTwoWireBus(); - } - break; - - default: { - // Check for user-defined functions for GPIO, configurations, reinitialization, etc. - if (this->command.pArgs != nullptr) { - char user_command[this->command.cmdLength + 1] = {'\0'}; - memcpy(user_command, this->command.data, (size_t)(this->command.cmdLength)); - for (uint8_t k = 0; k < this->numUserCharCallbacks; k++) { - if (strcmp(user_command, this->userCharCallbacks[k].command) == 0) { - // remove leading whitespace - while (*this->command.pArgs != '\0'){ - if (isSpace(this->command.pArgs[0])) { - this->command.pArgs++; - this->command.iArgs++; - } - else { - break; - } - } - - // get char count for user args not including trailing whitespace/terminators - uint8_t user_args_length = 0; - for (uint8_t k = TERM_CHAR_BUFFER_SIZE; k > this->command.iArgs; k--) { - if ((this->command.serialRx[k] != '\0') && !isSpace(this->command.serialRx[k])) { - user_args_length = k - this->command.iArgs; - break; - } - } - - this->userCharCallbacks[k].callback(this->command.pArgs, (size_t)(user_args_length)); - return; - } - } - } - 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); - return; - } - } + default: + if (!runUserCallbacks()) { + // no terminal commander or user-defined command was identified + this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); } - - // no terminal commander or user-defined command was identified - this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); - } - break; + break; } } @@ -523,6 +397,146 @@ namespace TerminalCommander { } } + void TerminalCommander::i2cRead(void) { + this->pSerial->println(F("I2C Read")); + const uint8_t i2c_address = + (uint8_t)((this->command.twowire[0] << 4) + this->command.twowire[1]); + this->printTwoWireAddress(i2c_address); + const uint8_t i2c_register = + (uint8_t)((this->command.twowire[2] << 4) + this->command.twowire[3]); + this->printTwoWireRegister(i2c_register); + + uint8_t twi_read_index = 0; // start at zero so we can use the entire buffer for read + this->command.flushTwoWire(); // flush the existing twowire buffer of all data + + this->pWire->beginTransmission(i2c_address); + this->pWire->write(i2c_register); + twi_error_type_t error = (twi_error_type_t)(this->pWire->endTransmission()); + if (error == NACK_ADDRESS) { + this->pSerial->println(F("Error: I2C read attempt recieved NACK")); + return; + } + + delayMicroseconds(50); + this->pWire->requestFrom(i2c_address, (uint8_t)((this->command.argsLength >> 1) - 1)); + delayMicroseconds(50); + + while(this->pWire->available()) { + if (twi_read_index >= TERM_TWOWIRE_BUFFER_SIZE) { + this->writeErrorMsgToSerialBuffer(this->lastError.set(IncomingTwoWireReadLength), this->lastError.message); + return; + } + this->command.twowire[twi_read_index] = (uint8_t)this->pWire->read(); + twi_read_index++; + } + + if (twi_read_index == 0) { + this->pSerial->println(F("No Data Received")); + return; + } + + this->pSerial->print(F("Read Data:")); + for(uint8_t k = 0; k < twi_read_index; k++) { + if (this->command.twowire[k] < 0x10) { + this->pSerial->print(F(" 0x0")); + } + else { + this->pSerial->print(F(" 0x")); + } + this->pSerial->print(this->command.twowire[k], HEX); + } + this->pSerial->print('\n'); + } + + void TerminalCommander::i2cWrite(void) { + this->pSerial->println(F("I2C Write")); + const uint8_t i2c_address = + (uint8_t)((this->command.twowire[0] << 4) + this->command.twowire[1]); + this->printTwoWireAddress(i2c_address); + const uint8_t i2c_register = + (uint8_t)((this->command.twowire[2] << 4) + this->command.twowire[3]); + this->printTwoWireRegister(i2c_register); + + this->pWire->beginTransmission(i2c_address); + this->pWire->write(i2c_register); + for (uint8_t k = 4; k < this->command.argsLength; k += 2) { + this->pWire->write((16 * this->command.twowire[k]) + this->command.twowire[k+1]); + } + twi_error_type_t error = (twi_error_type_t)(this->pWire->endTransmission()); + if (error == NACK_ADDRESS) { + this->pSerial->println(F("Error: I2C write attempt recieved NACK")); + return; + } + else { + this->pSerial->print(F("Write Data:")); + for(uint8_t k = 4; k < this->command.argsLength; k += 2) { + uint8_t write_data = (16 * this->command.twowire[k]) + this->command.twowire[k+1]; + if (write_data < 0x01) { + this->pSerial->print(F(" 0x0")); + } + else { + this->pSerial->print(F(" 0x")); + } + this->pSerial->print(write_data, HEX); + } + this->pSerial->print('\n'); + } + } + } + + void TerminalCommander::i2cScan(void) { + if (this->command.argsLength != 0) { + this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); + return; + } + + this->pSerial->println(F("Scan I2C Bus for Available Devices")); + this->scanTwoWireBus(); + } + + bool TerminalCommander::runUserCallbacks(void) { + // Check for user-defined functions for GPIO, configurations, reinitialization, etc. + if (this->command.pArgs != nullptr) { + char user_command[this->command.cmdLength + 1] = {'\0'}; + memcpy(user_command, this->command.data, (size_t)(this->command.cmdLength)); + for (uint8_t k = 0; k < this->numUserCharCallbacks; k++) { + if (strcmp(user_command, this->userCharCallbacks[k].command) == 0) { + // remove leading whitespace + while (*this->command.pArgs != '\0'){ + if (isSpace(this->command.pArgs[0])) { + this->command.pArgs++; + this->command.iArgs++; + } + else { + break; + } + } + + // get char count for user args not including trailing whitespace/terminators + uint8_t user_args_length = 0; + for (uint8_t k = TERM_CHAR_BUFFER_SIZE; k > this->command.iArgs; k--) { + if ((this->command.serialRx[k] != '\0') && !isSpace(this->command.serialRx[k])) { + user_args_length = k - this->command.iArgs; + break; + } + } + + this->userCharCallbacks[k].callback(this->command.pArgs, (size_t)(user_args_length)); + 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); + return true; + } + } + } + return false; + } + /// TODO: move as much of this as possible into an error_t member void TerminalCommander::writeErrorMsgToSerialBuffer(error_type_t error, char *message) { memset(message, '\0', TERM_ERROR_MESSAGE_SIZE); diff --git a/terminal_commander.h b/terminal_commander.h index ae8c388..2b0a23f 100644 --- a/terminal_commander.h +++ b/terminal_commander.h @@ -424,6 +424,12 @@ */ void scanTwoWireBus(void); + + void i2cRead(void); + void i2cWrite(void); + void i2cScan(void); + bool runUserCallbacks(void); + /*! @brief Error-check the incoming ASCII command string * * @details Detailed description here. From 238a2e16ec49f1e2ac5a376a3b7434df8d249892 Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 15:52:23 -0700 Subject: [PATCH 06/14] refactor: while loop in runUserCallbacks --- terminal_commander.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index 29ed3a2..c2cbaa2 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -502,14 +502,9 @@ namespace TerminalCommander { for (uint8_t k = 0; k < this->numUserCharCallbacks; k++) { if (strcmp(user_command, this->userCharCallbacks[k].command) == 0) { // remove leading whitespace - while (*this->command.pArgs != '\0'){ - if (isSpace(this->command.pArgs[0])) { - this->command.pArgs++; - this->command.iArgs++; - } - else { - break; - } + while (*this->command.pArgs != '\0' && isSpace(this->command.pArgs[0])) { + this->command.pArgs++; + this->command.iArgs++; } // get char count for user args not including trailing whitespace/terminators From f330558ac80c97fda09fa02d1d4c612fa437c261 Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:09:05 -0700 Subject: [PATCH 07/14] refactor: rm protocol filtering, unnecessary --- terminal_commander.cpp | 32 +++++++++----------------------- terminal_commander.h | 12 ------------ 2 files changed, 9 insertions(+), 35 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index c2cbaa2..d78d787 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -202,14 +202,16 @@ namespace TerminalCommander { } if (this->command.data[3] == 'r' || this->command.data[3] == 'R') { - this->command.protocol = I2C_READ; + this->i2cRead(); + return; } else if (this->command.data[3] == 'w' || this->command.data[3] == 'W') { if (command.argsLength < 6U) { this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidTwoWireWriteData), this->lastError.message); return; } - this->command.protocol = I2C_WRITE; + this->i2cWrite(); + return; } else { this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedI2CTransType), this->lastError.message); @@ -217,29 +219,13 @@ namespace TerminalCommander { } } else if (strncasecmp(this->command.data, "SCAN", 4)) { - this->command.protocol = I2C_SCAN; + this->i2cScan(); + return; } - switch (command.protocol) { - case I2C_READ: - i2cRead(); - break; - - case I2C_WRITE: - i2cWrite(); - break; - - // Scan TwoWire bus to explore and query available devices - case I2C_SCAN: - i2cScan(); - break; - - default: - if (!runUserCallbacks()) { - // no terminal commander or user-defined command was identified - this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); - } - break; + if (!this->runUserCallbacks()) { + // no terminal commander or user-defined command was identified + this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); } } diff --git a/terminal_commander.h b/terminal_commander.h index 2b0a23f..0e3c690 100644 --- a/terminal_commander.h +++ b/terminal_commander.h @@ -82,13 +82,6 @@ // e.g. [&](){}, but requires #include which is not supported for AVR cores // typedef std::function cmd_callback_t - enum terminal_protocols_t { - UNDEFINED = 0, - I2C_READ, - I2C_WRITE, - I2C_SCAN, - }; - enum error_type_t { NoError = 0, NoInput, @@ -196,9 +189,6 @@ /** Fixed array for holding hex values to be sent/received via TwoWire/I2C */ uint8_t twowire[TERM_TWOWIRE_BUFFER_SIZE] = {0}; - /** Protocol type identified for */ - terminal_protocols_t protocol; - /** Pointer to first non-space character following a space char in the incoming buffer */ char *pArgs; @@ -229,7 +219,6 @@ * @returns Description of the returned parameter */ terminal_command_t() : - protocol(UNDEFINED), pArgs(nullptr), iArgs(0U), cmdLength(0U), @@ -309,7 +298,6 @@ * @returns void */ void initialize(void) { - this->protocol = UNDEFINED; this->pArgs = nullptr; this->iArgs = 0U; this->cmdLength = 0U; From 94092ae77a05c1fcba409337230e8eb42cc0f53b Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:12:38 -0700 Subject: [PATCH 08/14] refactor: move i2c read validation to its fn --- terminal_commander.cpp | 68 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index d78d787..42fb5d9 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -206,10 +206,6 @@ namespace TerminalCommander { return; } else if (this->command.data[3] == 'w' || this->command.data[3] == 'W') { - if (command.argsLength < 6U) { - this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidTwoWireWriteData), this->lastError.message); - return; - } this->i2cWrite(); return; } @@ -435,38 +431,42 @@ namespace TerminalCommander { } void TerminalCommander::i2cWrite(void) { - this->pSerial->println(F("I2C Write")); - const uint8_t i2c_address = - (uint8_t)((this->command.twowire[0] << 4) + this->command.twowire[1]); - this->printTwoWireAddress(i2c_address); - const uint8_t i2c_register = - (uint8_t)((this->command.twowire[2] << 4) + this->command.twowire[3]); - this->printTwoWireRegister(i2c_register); - - this->pWire->beginTransmission(i2c_address); - this->pWire->write(i2c_register); - for (uint8_t k = 4; k < this->command.argsLength; k += 2) { - this->pWire->write((16 * this->command.twowire[k]) + this->command.twowire[k+1]); - } - twi_error_type_t error = (twi_error_type_t)(this->pWire->endTransmission()); - if (error == NACK_ADDRESS) { - this->pSerial->println(F("Error: I2C write attempt recieved NACK")); - return; - } - else { - this->pSerial->print(F("Write Data:")); - for(uint8_t k = 4; k < this->command.argsLength; k += 2) { - uint8_t write_data = (16 * this->command.twowire[k]) + this->command.twowire[k+1]; - if (write_data < 0x01) { - this->pSerial->print(F(" 0x0")); - } - else { - this->pSerial->print(F(" 0x")); - } - this->pSerial->print(write_data, HEX); + if (this->command.argsLength < 6U) { + this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidTwoWireWriteData), this->lastError.message); + return; + } + + this->pSerial->println(F("I2C Write")); + const uint8_t i2c_address = + (uint8_t)((this->command.twowire[0] << 4) + this->command.twowire[1]); + this->printTwoWireAddress(i2c_address); + const uint8_t i2c_register = + (uint8_t)((this->command.twowire[2] << 4) + this->command.twowire[3]); + this->printTwoWireRegister(i2c_register); + + this->pWire->beginTransmission(i2c_address); + this->pWire->write(i2c_register); + for (uint8_t k = 4; k < this->command.argsLength; k += 2) { + this->pWire->write((16 * this->command.twowire[k]) + this->command.twowire[k+1]); + } + twi_error_type_t error = (twi_error_type_t)(this->pWire->endTransmission()); + if (error == NACK_ADDRESS) { + this->pSerial->println(F("Error: I2C write attempt recieved NACK")); + return; + } + else { + this->pSerial->print(F("Write Data:")); + for(uint8_t k = 4; k < this->command.argsLength; k += 2) { + uint8_t write_data = (16 * this->command.twowire[k]) + this->command.twowire[k+1]; + if (write_data < 0x01) { + this->pSerial->print(F(" 0x0")); + } + else { + this->pSerial->print(F(" 0x")); } - this->pSerial->print('\n'); + this->pSerial->print(write_data, HEX); } + this->pSerial->print('\n'); } } From ef9665f904ea7ea6af742abe5b2e7f362fd64cf2 Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:24:16 -0700 Subject: [PATCH 09/14] refactor: struct to class - removeSpaces to Command --- terminal_commander.cpp | 199 ++++++++++++++++++++++++++++++++--------- terminal_commander.h | 85 ++++++------------ 2 files changed, 186 insertions(+), 98 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index 42fb5d9..f379621 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -78,6 +78,160 @@ namespace TerminalCommander { strErrUnrecognizedI2CTransType }; + /** + * @brief Use this struct to build and config terminal command data. + * + * @details A more elaborate description of the constructor. + * + * @param void + * @returns Description of the returned parameter + */ + Command::Command() : + pArgs(nullptr), + iArgs(0U), + cmdLength(0U), + argsLength(0U), + index(0U), + complete(false), + overflow(false) {} + + /** + * @brief Use this struct to build and config terminal command data. + * + * @details A more elaborate description of the constructor. + * + * @param param Description of the input parameter + * @returns void + */ + void Command::next(char character) { + if (character == TERM_LINE_ENDING) { + this->complete = true; + return; + } + + if (index >= TERM_CHAR_BUFFER_SIZE) { + this->overflow = true; + return; + } + + serialRx[this->index++] = character; + } + + /** + * @brief Use this struct to build and config terminal command data. + * + * @details A more elaborate description of the constructor. + * + * @param param Description of the input parameter + * @returns void + */ + void Command::previous(void) { + if (this->index > 0) { + serialRx[--this->index] = '\0'; + } + } + + /** + * @brief Use this struct to build and config terminal command data. + * + * @details A more elaborate description of the constructor. + * + * @param void + * @returns void + */ + void Command::flushInput(void) { + memset(this->serialRx, '\0', sizeof(this->serialRx)); + this->complete = false; + this->overflow = false; + } + + /** + * @brief Use this struct to build and config terminal command data. + * + * @details A more elaborate description of the constructor. + * + * @param param Description of the input parameter + * @returns void + */ + void Command::flushTwoWire(void) { + memset(this->twowire, 0, sizeof(this->twowire)); + } + + /** + * @brief Use this struct to build and config terminal command data. + * + * @details A more elaborate description of the constructor. + * + * @param void + * @returns void + */ + void Command::initialize(void) { + this->pArgs = nullptr; + this->iArgs = 0U; + this->cmdLength = 0U; + this->argsLength = 0U; + this->index = 0U; + this->flushTwoWire(); + memset(this->data, '\0', sizeof(this->data)); + } + + /** + * @brief Use this struct to build and config terminal command data. + * + * @details A more elaborate description of the constructor. + * + * @param void + * @returns void + */ + void Command::reset(void) { + this->flushInput(); + this->initialize(); + } + + /** + * @brief Remove spaces from incoming serial command. + */ + bool Command::removeSpaces(void) { + uint8_t data_index = 0; + for (uint8_t serialrx_index = 0; serialrx_index < TERM_CHAR_BUFFER_SIZE; serialrx_index++) { + // remove whitespace from input character string + if (!isSpace(this->serialRx[serialrx_index])) { + if (this->serialRx[serialrx_index] == '\0') { + // end of serial input data has been reached + if (data_index == 0) { + // input serial buffer is empty + return false; + } + + if (this->cmdLength == 0) { + // serial buffer is not empty but command did not have any spaces + this->cmdLength = data_index; + } + break; + } + else { + this->data[data_index] = this->serialRx[serialrx_index]; + } + data_index++; + } + else if ((this->pArgs == nullptr) && + (data_index != 0) && + (serialrx_index != (TERM_CHAR_BUFFER_SIZE - 1U))) { + // Store pointer to next char character after the 1st space to enable passing user args + this->pArgs = (char*)(&this->serialRx[serialrx_index]) + 1; + + // Store index corresponding to pointer location since it is start index of user args + this->iArgs = serialrx_index; + + // Space character is treated as delimiter for commands even if not a user command + this->cmdLength = data_index; + } + } + this->argsLength = data_index - this->cmdLength; + + return true; + } + TerminalCommander::TerminalCommander(Stream* pSerial, TwoWire* pWire) { this->pSerial = pSerial; this->pWire = pWire; @@ -88,7 +242,7 @@ namespace TerminalCommander { // check for buffer overflow if (this->command.overflow) { break; - } + } // get the new byte char c = (char)this->pSerial->read(); @@ -143,53 +297,16 @@ namespace TerminalCommander { this->numUserCharCallbacks++; } - /// TODO: break this up into smaller methods void TerminalCommander::serialCommandProcessor(void) { if (!this->isRxBufferDataValid()) { return; } - - // remove spaces from incoming serial command - uint8_t data_index = 0; - for (uint8_t serialrx_index = 0; serialrx_index < TERM_CHAR_BUFFER_SIZE; serialrx_index++) { - // remove whitespace from input character string - if (!isSpace(this->command.serialRx[serialrx_index])) { - if (this->command.serialRx[serialrx_index] == '\0') { - // end of serial input data has been reached - if (data_index == 0) { - // input serial buffer is empty - this->writeErrorMsgToSerialBuffer(this->lastError.set(NoInput), this->lastError.message); - return; - } - - if (this->command.cmdLength == 0) { - // serial buffer is not empty but command did not have any spaces - this->command.cmdLength = data_index; - } - break; - } - else { - this->command.data[data_index] = this->command.serialRx[serialrx_index]; - } - data_index++; - } - else if ((this->command.pArgs == nullptr) && - (data_index != 0) && - (serialrx_index != (TERM_CHAR_BUFFER_SIZE - 1U))) { - // Store pointer to next char character after the 1st space to enable passing user args - this->command.pArgs = (char*)(&this->command.serialRx[serialrx_index]) + 1; - - // Store index corresponding to pointer location since it is start index of user args - this->command.iArgs = serialrx_index; - - // Space character is treated as delimiter for commands even if not a user command - this->command.cmdLength = data_index; - } + if (!this->command.removeSpaces()) { + this->writeErrorMsgToSerialBuffer(this->lastError.set(NoInput), this->lastError.message); + return; } - this->command.argsLength = data_index - this->command.cmdLength; if (strncasecmp(this->command.data, "I2C", 3)) { - // test if buffer represents hex value pairs and convert these from ASCII to hex if (!this->parseTwoWireData()) { return; diff --git a/terminal_commander.h b/terminal_commander.h index 0e3c690..bf6b0d3 100644 --- a/terminal_commander.h +++ b/terminal_commander.h @@ -173,13 +173,10 @@ memset(this->message, '\0', sizeof(this->message)); } }; + }; - /** - * @brief Use this struct to build and config terminal command data. - * - * @details A more elaborate description of the constructor. - */ - struct terminal_command_t { + class Command { + public: /** Fixed array for raw incoming serial rx data */ char serialRx[TERM_CHAR_BUFFER_SIZE + 1] = {'\0'}; @@ -218,14 +215,7 @@ * @param void * @returns Description of the returned parameter */ - terminal_command_t() : - pArgs(nullptr), - iArgs(0U), - cmdLength(0U), - argsLength(0U), - index(0U), - complete(false), - overflow(false) {} + Command(); /** * @brief Use this struct to build and config terminal command data. @@ -235,19 +225,7 @@ * @param param Description of the input parameter * @returns void */ - void next(char character) { - if (character == TERM_LINE_ENDING) { - this->complete = true; - return; - } - - if (index >= TERM_CHAR_BUFFER_SIZE) { - this->overflow = true; - return; - } - - serialRx[this->index++] = character; - } + void next(char character); /** * @brief Use this struct to build and config terminal command data. @@ -257,11 +235,7 @@ * @param param Description of the input parameter * @returns void */ - void previous(void) { - if (this->index > 0) { - serialRx[--this->index] = '\0'; - } - } + void previous(void); /** * @brief Use this struct to build and config terminal command data. @@ -271,11 +245,7 @@ * @param void * @returns void */ - void flushInput(void) { - memset(this->serialRx, '\0', sizeof(this->serialRx)); - this->complete = false; - this->overflow = false; - } + void flushInput(void); /** * @brief Use this struct to build and config terminal command data. @@ -285,9 +255,7 @@ * @param param Description of the input parameter * @returns void */ - void flushTwoWire(void) { - memset(this->twowire, 0, sizeof(this->twowire)); - } + void flushTwoWire(void); /** * @brief Use this struct to build and config terminal command data. @@ -297,15 +265,7 @@ * @param void * @returns void */ - void initialize(void) { - this->pArgs = nullptr; - this->iArgs = 0U; - this->cmdLength = 0U; - this->argsLength = 0U; - this->index = 0U; - this->flushTwoWire(); - memset(this->data, '\0', sizeof(this->data)); - } + void initialize(void); /** * @brief Use this struct to build and config terminal command data. @@ -315,12 +275,15 @@ * @param void * @returns void */ - void reset(void) { - this->flushInput(); - this->initialize(); - } - }; - } + void reset(void); + + /** + * @brief Remove spaces from incoming serial command. + */ + bool removeSpaces(void); + + private: + }; class TerminalCommander { public: @@ -353,8 +316,16 @@ uint8_t numUserCharCallbacks = 0; TerminalCommanderTypes::error_t lastError; - TerminalCommanderTypes::terminal_command_t command; + + /** + * @brief Use this struct to build and config terminal command data. + * + * @details A more elaborate description of the constructor. + */ + Command command; + Stream *pSerial; + TwoWire *pWire; /*! @brief Execute incoming serial string by command or protocol type @@ -427,5 +398,5 @@ */ void writeErrorMsgToSerialBuffer(TerminalCommanderTypes::error_type_t error, char *message); }; - } + }; #endif From 6ff7669fa9b2f83782ff51f5aa032b02f80e72a9 Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 15:35:14 -0700 Subject: [PATCH 10/14] fix: I2C cmd length --- terminal_commander.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index f379621..d498b48 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -313,9 +313,11 @@ namespace TerminalCommander { } // if command was sent without spaces then set correct length for command and args - if (this->command.cmdLength == 0) { + // cmdLength will be length of command and args, e.g. I2CWffffff, and should be + // set to 4 and argsLength to (cmd+args).length - cmd. + if (this->command.cmdLength > 4U) { + this->command.argsLength = this->command.cmdLength - 4U; this->command.cmdLength = 4U; - this->command.argsLength = data_index - 4U; } if (this->command.data[3] == 'r' || this->command.data[3] == 'R') { From 4c96628848a49ad734d4866a66e837f910225124 Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:59:38 -0700 Subject: [PATCH 11/14] fix: missing ln --- terminal_commander.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index d498b48..09f7a24 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -282,7 +282,7 @@ namespace TerminalCommander { this->serialCommandProcessor(); if (this->lastError.flag) { - this->pSerial->print(this->lastError.message); + this->pSerial->println(this->lastError.message); this->lastError.clear(); } this->pSerial->print(F(">> ")); From 75f997e54f9feec13572f3ec78a33b51ac290460 Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:01:15 -0700 Subject: [PATCH 12/14] refactor: simplify while loop --- terminal_commander.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index 09f7a24..3308416 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -263,14 +263,8 @@ namespace TerminalCommander { if (this->command.overflow) { // discard incoming data until the serial line ending is received - while(1) { - if (this->pSerial->available() > 0) { - char character = (char)this->pSerial->read(); - if (character == TERM_LINE_ENDING) { - break; - } - } - else { + while (this->pSerial->available() > 0) { + if ((char)this->pSerial->read() == TERM_LINE_ENDING) { break; } } From b761015b8c7fffb148f78d8cb478f5be3dded6cb Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:09:28 -0700 Subject: [PATCH 13/14] refactor: rm unnecessary else --- terminal_commander.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index 3308416..34c8716 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -322,10 +322,9 @@ namespace TerminalCommander { this->i2cWrite(); return; } - else { - this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedI2CTransType), this->lastError.message); - return; - } + + this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedI2CTransType), this->lastError.message); + return; } else if (strncasecmp(this->command.data, "SCAN", 4)) { this->i2cScan(); From 6afb05275ccbe5de49b1d8341cc4f574aae2d2db Mon Sep 17 00:00:00 2001 From: Emma Litwa-Vulcu <80431903+reiniiriarios@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:57:36 -0700 Subject: [PATCH 14/14] refactor: simplify error setting --- terminal_commander.cpp | 60 +++++++++--------------------------------- terminal_commander.h | 41 ++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 57 deletions(-) diff --git a/terminal_commander.cpp b/terminal_commander.cpp index 34c8716..f654c1e 100644 --- a/terminal_commander.cpp +++ b/terminal_commander.cpp @@ -48,36 +48,6 @@ int strncasecmp(const char *s1, const char *s2, size_t num) { namespace TerminalCommander { using namespace TerminalCommanderTypes; - // put common error messages into Program memory to save SRAM space - static const char strErrNoError[] PROGMEM = "No Error\n"; - static const char strErrNoInput[] PROGMEM = "Error: No Input\n"; - static const char strErrUndefinedUserFunctionPtr[] PROGMEM = "Error: USER function is not defined (null pointer)\n"; - static const char strErrUnrecognizedInput[] PROGMEM = "Error: Unrecognized Input Character\n"; - static const char strErrInvalidSerialCmdLength[] PROGMEM = "\nError: Serial Command Length Exceeds Limit\n"; - static const char strErrIncomingTwoWireReadLength[] PROGMEM = "Error: Incoming TwoWire Data Exceeds Read Buffer\n"; - static const char strErrInvalidTwoWireCharacter[] PROGMEM = "Error: Invalid TwoWire Command Character\n"; - static const char strErrInvalidTwoWireCmdLength[] PROGMEM = "Error: TwoWire Command requires Address and Register\n"; - static const char strErrInvalidTwoWireWriteData[] PROGMEM = "Error: No data provided for write to I2C registers\n"; - static const char strErrInvalidHexValuePair[] PROGMEM = "Error: Commands must be in hex value pairs\n"; - static const char strErrUnrecognizedProtocol[] PROGMEM = "Error: Unrecognized Protocol\n"; - static const char strErrUnrecognizedI2CTransType[] PROGMEM = "Error: Unrecognized I2C transaction type\n"; - - static const char *const string_error_table[] PROGMEM = - { - strErrNoError, - strErrNoInput, - strErrUndefinedUserFunctionPtr, - strErrUnrecognizedInput, - strErrInvalidSerialCmdLength, - strErrIncomingTwoWireReadLength, - strErrInvalidTwoWireCharacter, - strErrInvalidTwoWireCmdLength, - strErrInvalidTwoWireWriteData, - strErrInvalidHexValuePair, - strErrUnrecognizedProtocol, - strErrUnrecognizedI2CTransType - }; - /** * @brief Use this struct to build and config terminal command data. * @@ -268,7 +238,7 @@ namespace TerminalCommander { break; } } - this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidSerialCmdLength), this->lastError.message); + this->lastError.set(InvalidSerialCmdLength); this->pSerial->println(this->lastError.message); this->lastError.clear(); } @@ -296,7 +266,7 @@ namespace TerminalCommander { return; } if (!this->command.removeSpaces()) { - this->writeErrorMsgToSerialBuffer(this->lastError.set(NoInput), this->lastError.message); + this->lastError.set(NoInput); return; } @@ -323,7 +293,7 @@ namespace TerminalCommander { return; } - this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedI2CTransType), this->lastError.message); + this->lastError.set(UnrecognizedI2CTransType); return; } else if (strncasecmp(this->command.data, "SCAN", 4)) { @@ -333,7 +303,7 @@ namespace TerminalCommander { if (!this->runUserCallbacks()) { // no terminal commander or user-defined command was identified - this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); + this->lastError.set(UnrecognizedProtocol); } } @@ -371,14 +341,14 @@ namespace TerminalCommander { } else { // an input buffer value was unrecognized - this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedInput), this->lastError.message); + this->lastError.set(UnrecognizedInput); return false; } } if (idx == 0) { // input serial buffer is empty - this->writeErrorMsgToSerialBuffer(this->lastError.set(NoInput), this->lastError.message); + this->lastError.set(NoInput); return false; } @@ -412,19 +382,19 @@ namespace TerminalCommander { } else { // an command character is invalid or unrecognized - this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidTwoWireCharacter), this->lastError.message); + this->lastError.set(InvalidTwoWireCharacter); return false; } } if (idx < 7) { // command buffer is empty - this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidTwoWireCmdLength), this->lastError.message); + this->lastError.set(InvalidTwoWireCmdLength); return false; } else if ((idx >> 1) != ((idx + 1) >> 1)) { // command buffer does not specify hex values in multiples of 8 bits - this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidHexValuePair), this->lastError.message); + this->lastError.set(InvalidHexValuePair); return false; } @@ -517,7 +487,7 @@ namespace TerminalCommander { while(this->pWire->available()) { if (twi_read_index >= TERM_TWOWIRE_BUFFER_SIZE) { - this->writeErrorMsgToSerialBuffer(this->lastError.set(IncomingTwoWireReadLength), this->lastError.message); + this->lastError.set(IncomingTwoWireReadLength); return; } this->command.twowire[twi_read_index] = (uint8_t)this->pWire->read(); @@ -544,7 +514,7 @@ namespace TerminalCommander { void TerminalCommander::i2cWrite(void) { if (this->command.argsLength < 6U) { - this->writeErrorMsgToSerialBuffer(this->lastError.set(InvalidTwoWireWriteData), this->lastError.message); + this->lastError.set(InvalidTwoWireWriteData); return; } @@ -584,7 +554,7 @@ namespace TerminalCommander { void TerminalCommander::i2cScan(void) { if (this->command.argsLength != 0) { - this->writeErrorMsgToSerialBuffer(this->lastError.set(UnrecognizedProtocol), this->lastError.message); + this->lastError.set(UnrecognizedProtocol); return; } @@ -629,10 +599,4 @@ namespace TerminalCommander { } return false; } - - /// TODO: move as much of this as possible into an error_t member - void TerminalCommander::writeErrorMsgToSerialBuffer(error_type_t error, char *message) { - memset(message, '\0', TERM_ERROR_MESSAGE_SIZE); - strcpy_P(message, (char *)pgm_read_word(&(this->string_error_table[error]))); - } } diff --git a/terminal_commander.h b/terminal_commander.h index bf6b0d3..b2f4dfd 100644 --- a/terminal_commander.h +++ b/terminal_commander.h @@ -82,6 +82,36 @@ // e.g. [&](){}, but requires #include which is not supported for AVR cores // typedef std::function cmd_callback_t + // put common error messages into Program memory to save SRAM space + static const char strErrNoError[] PROGMEM = "No Error\n"; + static const char strErrNoInput[] PROGMEM = "Error: No Input\n"; + static const char strErrUndefinedUserFunctionPtr[] PROGMEM = "Error: USER function is not defined (null pointer)\n"; + static const char strErrUnrecognizedInput[] PROGMEM = "Error: Unrecognized Input Character\n"; + static const char strErrInvalidSerialCmdLength[] PROGMEM = "\nError: Serial Command Length Exceeds Limit\n"; + static const char strErrIncomingTwoWireReadLength[] PROGMEM = "Error: Incoming TwoWire Data Exceeds Read Buffer\n"; + static const char strErrInvalidTwoWireCharacter[] PROGMEM = "Error: Invalid TwoWire Command Character\n"; + static const char strErrInvalidTwoWireCmdLength[] PROGMEM = "Error: TwoWire Command requires Address and Register\n"; + static const char strErrInvalidTwoWireWriteData[] PROGMEM = "Error: No data provided for write to I2C registers\n"; + static const char strErrInvalidHexValuePair[] PROGMEM = "Error: Commands must be in hex value pairs\n"; + static const char strErrUnrecognizedProtocol[] PROGMEM = "Error: Unrecognized Protocol\n"; + static const char strErrUnrecognizedI2CTransType[] PROGMEM = "Error: Unrecognized I2C transaction type\n"; + + static const char *const string_error_table[] PROGMEM = + { + strErrNoError, + strErrNoInput, + strErrUndefinedUserFunctionPtr, + strErrUnrecognizedInput, + strErrInvalidSerialCmdLength, + strErrIncomingTwoWireReadLength, + strErrInvalidTwoWireCharacter, + strErrInvalidTwoWireCmdLength, + strErrInvalidTwoWireWriteData, + strErrInvalidHexValuePair, + strErrUnrecognizedProtocol, + strErrUnrecognizedI2CTransType + }; + enum error_type_t { NoError = 0, NoInput, @@ -143,6 +173,8 @@ error_type_t set(error_type_t error_type) { this->flag = true; this->type = error_type; + memset(this->message, '\0', TERM_ERROR_MESSAGE_SIZE); + strcpy_P(this->message, (char *)pgm_read_word(&(string_error_table[error_type]))); return this->type; } @@ -388,15 +420,6 @@ void i2cWrite(void); void i2cScan(void); bool runUserCallbacks(void); - - /*! @brief Error-check the incoming ASCII command string - * - * @details Detailed description here. - * - * @param param Description of the input parameter - * @returns void - */ - void writeErrorMsgToSerialBuffer(TerminalCommanderTypes::error_type_t error, char *message); }; }; #endif