diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index c049ced..3c2f32d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,5 +1,9 @@ name: Build Firmware -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 40418c3..78901bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### 0.4.0 (2024/01/04) + +* Provide EEPROM commands. +* Provide a method for the Teensy to read it's own USB Serial Number back to + the device through the USB interface. + ### 0.3.0 (2023/11/06) * Increase the maximum analog pulse duration to 3 minutes. diff --git a/platformio.ini b/platformio.ini index 1862407..acede48 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,6 +13,7 @@ platform = teensy board = teensy31 framework = arduino board_build.f_cpu = 96000000L +upload_protocol = teensy-cli lib_deps = https://github.com/nox771/i2c_t3.git build_flags = diff --git a/src/commandconstants.hpp b/src/commandconstants.hpp index eb61733..77b1f79 100644 --- a/src/commandconstants.hpp +++ b/src/commandconstants.hpp @@ -6,6 +6,7 @@ int info_func(CommandRouter *cmd, int argc, const char **argv); int reboot_func(CommandRouter *cmd, int argc, const char **argv); int version_func(CommandRouter *cmd, int argc, const char **argv); int mcu_func(CommandRouter *cmd, int argc, const char **argv); +int serialnumber_func(CommandRouter *cmd, int argc, const char **argv); int command_license_func(CommandRouter *cmd, int argc, const char **argv); // Digital GPIO @@ -58,12 +59,21 @@ int register_read_uint16(CommandRouter *cmd, int argc, const char **argv); int register_write_uint16(CommandRouter *cmd, int argc, const char **argv); int register_read_uint32(CommandRouter *cmd, int argc, const char **argv); int register_write_uint32(CommandRouter *cmd, int argc, const char **argv); + +int eeprom_length(CommandRouter *cmd, int argc, const char **argv); +int eeprom_read_uint8(CommandRouter *cmd, int argc, const char **argv); +int eeprom_write_uint8(CommandRouter *cmd, int argc, const char **argv); +int eeprom_update_uint8(CommandRouter *cmd, int argc, const char **argv); +int eeprom_read_string(CommandRouter *cmd, int argc, const char **argv); +int eeprom_write_string(CommandRouter *cmd, int argc, const char **argv); + // Syntax is: {short command, description, syntax} const command_item_t command_list[] = { {"?", "Display help info", "?", command_help_func}, {"info", "Displays information about this TeensyToAny device", "about", info_func}, {"reboot", "Runs setup routine again, for this device.", "reboot", reboot_func}, {"mcu", "Displays information about the microcontroller board.", "mcu", mcu_func}, + {"serialnumber", "Displays the serial number of the board.", "serialnumber", serialnumber_func}, {"license", "Display the license information for the source code running on the " "teensy", @@ -162,5 +172,17 @@ const command_item_t command_list[] = { "register_read_uint32 address", register_read_uint32}, {"register_write_uint32", "Write to an arbitrary hardware register.", "register_write_uint32 address data", register_write_uint32}, + {"eeprom_length", "Return the size of the of the EEPROM in bytes.", + "eeprom_length", eeprom_length}, + {"eeprom_read_uint8", "Read data from a given EEPROM address.", + "eeprom_read_uint8 address", eeprom_read_uint8}, + {"eeprom_write_uint8", "Write to an EEPROM address.", + "eeprom_write_uint8 address data", eeprom_write_uint8}, + {"eeprom_update_uint8", "Write to an EEPROM address if the value has changed.", + "eeprom_update_uint8 address data", eeprom_update_uint8}, + {"eeprom_read_string", "Read data from a given EEPROM address.", + "eeprom_read_string address", eeprom_read_string}, + {"eeprom_write_string", "Write to an EEPROM address.", + "eeprom_write_string address data", eeprom_write_string}, {nullptr, nullptr, nullptr, nullptr}, }; diff --git a/src/main.cpp b/src/main.cpp index 1c8f6eb..4cc0441 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include // TODO: this isn't exactly correct since this main file won't get // regenerated if it wasn't touched. @@ -73,6 +75,23 @@ int version_func(CommandRouter *cmd, int argc, const char **argv) { return 0; } +int serialnumber_func(CommandRouter *cmd, int argc, const char **argv) { + (void)argc; + (void)argv; + uint8_t i; + // https://github.com/PaulStoffregen/cores/pull/722 +#pragma GCC diagnostic push + // https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html +#pragma GCC diagnostic ignored "-Warray-bounds" + for (i=0; i < (usb_string_serial_number.bLength - 2) / sizeof(uint16_t); i++) { + cmd->buffer[i] = (char)usb_string_serial_number.wString[i]; + } +#pragma GCC diagnostic pop + cmd->buffer[i] = '\0'; + return 0; +} + + int mcu_func(CommandRouter *cmd, int argc, const char **argv) { (void)argc; (void)argv; @@ -859,6 +878,157 @@ int register_read_uint32(CommandRouter *cmd, int argc, const char **argv) { return 0; } +int eeprom_length(CommandRouter *cmd, int argc, const char **argv) { + if (argc != 1) { + return EINVAL; + } + + uint16_t length = EEPROM.length(); + + snprintf(cmd->buffer, cmd->buffer_size, "0x%04X", length); + + return 0; +} + +int eeprom_read_uint8(CommandRouter *cmd, int argc, const char **argv) { + if (argc != 2) { + return EINVAL; + } + int index; + uint8_t data; + + index = strtol(argv[1], nullptr, 0); + if (index > EEPROM.length()) { + return EINVAL; + } + + data = EEPROM.read(index); + + snprintf(cmd->buffer, cmd->buffer_size, "0x%02X", data); + + return 0; +} + +int eeprom_write_uint8(CommandRouter *cmd, int argc, const char **argv) { + if (argc != 3) { + return EINVAL; + } + int index; + uint8_t data; + + index = strtol(argv[1], nullptr, 0); + data = strtol(argv[2], nullptr, 0); + if (index > EEPROM.length()) { + return EINVAL; + } + + EEPROM.write(index, data); + + return 0; +} + +int eeprom_update_uint8(CommandRouter *cmd, int argc, const char **argv) { + if (argc != 3) { + return EINVAL; + } + int index; + uint8_t data; + + index = strtol(argv[1], nullptr, 0); + data = strtol(argv[2], nullptr, 0); + if (index > EEPROM.length()) { + return EINVAL; + } + + /* + The function EEPROM.update(address, val) is equivalent to the following: + + if( EEPROM.read(address) != val ){ + EEPROM.write(address, val); + } + */ + EEPROM.update(index, data); + + return 0; +} + +int eeprom_read_string(CommandRouter *cmd, int argc, const char **argv) { + if (argc < 2 || argc > 3) { + return EINVAL; + } + int index, i; + int n_read; + char data; + + index = strtol(argv[1], nullptr, 0); + if (index > EEPROM.length()) { + return EINVAL; + } + if (argc >= 3) { + n_read = strtol(argv[2], nullptr, 0); + } else { + n_read = EEPROM.length() - index; + } + + if (index + n_read > EEPROM.length()) { + return EINVAL; + } + + for(i=0; i < n_read; i++, index++){ + data = (char) EEPROM.read(index); + + if (data == '\0') { + break; + } + + cmd->buffer[i] = data; + } + // Terminate, always, even if we "got to the end of EEPROM's length + cmd->buffer[i] = '\0'; + + return 0; +} + +int eeprom_write_string(CommandRouter *cmd, int argc, const char **argv) { + if (argc < 3) { + return EINVAL; + } + int index, i; + int data_length; + const char* data; + + index = strtol(argv[1], nullptr, 0); + if (index > EEPROM.length()) { + return EINVAL; + } + + // We compute the length of the string "joined" by spaces + data_length = argc - 3; + for (i=2; i < argc; i++) { + data = argv[2]; + data_length += strlen(data); + } + + if (index + data_length >= EEPROM.length()) { + return EINVAL; + } + + for (int j=2; j < argc; j++) { + data = argv[j]; + if (j != 2) { + EEPROM.update(index, ' '); + ++index; + } + for(i=0; data[i] != '\0'; i++, index++){ + EEPROM.update(index, data[i]); + } + } + EEPROM.update(index, '\0'); + + return 0; +} + + void loop() { // TODO: remove this check on if Serial is available. diff --git a/versioneer.py b/versioneer.py index 8b5749e..8ff1e54 100644 --- a/versioneer.py +++ b/versioneer.py @@ -2,8 +2,8 @@ revision = subprocess.check_output(["git", "describe", "--tags", "--dirty"]).strip() revision = revision.decode() -revision = revision.replace('-dirty', '+dirty', 1) -revision = revision.replace('-', '.post', 1) +revision = revision.replace('-dirty', '.dirty', 1) +revision = revision.replace('-', '.dev', 1) revision = revision.replace('-g', '+g', 1) print('-DGIT_DESCRIBE=\'"%s"\'' % revision)