From a8e2446f000e32b66e4808e974c059f7b84f7c60 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sat, 28 Dec 2024 18:05:25 -0600 Subject: [PATCH 01/25] Initialize array to 0s (#5688) --- src/platform/portduino/PortduinoGlue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 4fadc3ca9..fd489829b 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -90,7 +90,7 @@ void getMacAddr(uint8_t *dmac) if (strlen(optionMac) >= 12) { MAC_from_string(optionMac, dmac); } else { - uint32_t hwId; + uint32_t hwId = {0}; sscanf(optionMac, "%u", &hwId); dmac[0] = 0x80; dmac[1] = 0; From 6749367a73134d9b0e524bb12701105e7d254064 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 28 Dec 2024 18:23:56 -0600 Subject: [PATCH 02/25] [create-pull-request] automated change (#5686) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index ba7d7fe6f..800529e39 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 5 -build = 18 +build = 19 From 57a9a5ca21a3e148151d60a33a111570f4795b89 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sat, 28 Dec 2024 18:48:54 -0600 Subject: [PATCH 03/25] Another Valgrind fix (#5690) --- src/platform/portduino/PortduinoGlue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index fd489829b..0c981bf16 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -104,7 +104,7 @@ void getMacAddr(uint8_t *dmac) exit; } else { - struct hci_dev_info di; + struct hci_dev_info di = {0}; di.dev_id = 0; bdaddr_t bdaddr; int btsock; From e45c0e4d4082e3e78f9124381de01583314ecd59 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Sun, 29 Dec 2024 11:56:05 +1100 Subject: [PATCH 04/25] Minor cppcheck fixes (#5689) * In graphics/Screen.cpp, a copy/paste error to do with hearts * In mesh/http/ContentHandler.cpp, an unused variable * in mqtt/MQTT.cpp, remove unneded logic " '!A || (A && B)' is equivalent to '!A || B'" --- src/graphics/Screen.cpp | 4 ++-- src/mesh/http/ContentHandler.cpp | 1 - src/mqtt/MQTT.cpp | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 4cfb8701e..31647c92d 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1015,7 +1015,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - devil_height) / 2 + 2 + 5, devil_width, devil_height, devil); } else if (strcmp(msg, "♥️") == 0 || strcmp(msg, "\U0001F9E1") == 0 || strcmp(msg, "\U00002763") == 0 || strcmp(msg, "\U00002764") == 0 || strcmp(msg, "\U0001F495") == 0 || strcmp(msg, "\U0001F496") == 0 || - strcmp(msg, "\U0001F497") == 0 || strcmp(msg, "\U0001F496") == 0) { + strcmp(msg, "\U0001F497") == 0 || strcmp(msg, "\U0001F498") == 0) { display->drawXbm(x + (SCREEN_WIDTH - heart_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - heart_height) / 2 + 2 + 5, heart_width, heart_height, heart); } else { @@ -2756,4 +2756,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN +#endif // HAS_SCREEN \ No newline at end of file diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 2b88702ed..aa8a68f91 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -725,7 +725,6 @@ void handleNodes(HTTPRequest *req, HTTPResponse *res) node["position"] = new JSONValue(position); } - JSONObject user; node["long_name"] = new JSONValue(tempNodeInfo->user.long_name); node["short_name"] = new JSONValue(tempNodeInfo->user.short_name); char macStr[18]; diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index c91252231..4260ae201 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -627,8 +627,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_Me // mp_decoded will not be decoded when it's PKI encrypted and not directed to us if (mp_decoded.which_payload_variant == meshtastic_MeshPacket_decoded_tag) { // For uplinking other's packets, check if it's not OK to MQTT or if it's an older packet without the bitfield - bool dontUplink = !mp_decoded.decoded.has_bitfield || - (mp_decoded.decoded.has_bitfield && !(mp_decoded.decoded.bitfield & BITFIELD_OK_TO_MQTT_MASK)); + bool dontUplink = !mp_decoded.decoded.has_bitfield || !(mp_decoded.decoded.bitfield & BITFIELD_OK_TO_MQTT_MASK); // check for the lowest bit of the data bitfield set false, and the use of one of the default keys. if (!isFromUs(&mp_decoded) && !isMqttServerAddressPrivate && dontUplink && (ch.settings.psk.size < 2 || (ch.settings.psk.size == 16 && memcmp(ch.settings.psk.bytes, defaultpsk, 16)) || From 3c7053c66a16bdc6ee024d8cafffc8838e873417 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Sun, 29 Dec 2024 15:23:46 +1100 Subject: [PATCH 05/25] reference seeed indicator fix commit arduino-esp32 (#5692) Co-authored-by: mverch67 --- variants/seeed-sensecap-indicator/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/seeed-sensecap-indicator/platformio.ini b/variants/seeed-sensecap-indicator/platformio.ini index e6bb2145e..86d6d0412 100644 --- a/variants/seeed-sensecap-indicator/platformio.ini +++ b/variants/seeed-sensecap-indicator/platformio.ini @@ -2,7 +2,7 @@ [env:seeed-sensecap-indicator] extends = esp32s3_base platform_packages = - platformio/framework-arduinoespressif32 @ https://github.com/mverch67/arduino-esp32.git#add_tca9535 ; based on 2.0.16 + platformio/framework-arduinoespressif32 @ https://github.com/mverch67/arduino-esp32.git#aef7fef6de3329ed6f75512d46d63bba12b09bb5 ; add_tca9535 (based on 2.0.16) board = seeed-sensecap-indicator board_check = true From a2a6b236b719cf8d5a34dad6d826ad1224325c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 30 Dec 2024 21:28:31 +0100 Subject: [PATCH 06/25] support indicator sensors through Rp2040 serial (#5696) * support indicator sensors through Rp2040 serial * disable excessive debug printing --- .../Telemetry/EnvironmentTelemetry.cpp | 12 +- .../Telemetry/Sensor/IndicatorSensor.cpp | 167 ++++++++++++++++++ .../Telemetry/Sensor/IndicatorSensor.h | 19 ++ src/serialization/cobs.cpp | 131 ++++++++++++++ src/serialization/cobs.h | 75 ++++++++ variants/seeed-sensecap-indicator/variant.h | 6 + 6 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 src/modules/Telemetry/Sensor/IndicatorSensor.cpp create mode 100644 src/modules/Telemetry/Sensor/IndicatorSensor.h create mode 100644 src/serialization/cobs.cpp create mode 100644 src/serialization/cobs.h diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 008da5c71..e72b03bd4 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -64,6 +64,10 @@ CGRadSensSensor cgRadSens; #include "Sensor/T1000xSensor.h" T1000xSensor t1000xSensor; #endif +#ifdef SENSECAP_INDICATOR +#include "Sensor/IndicatorSensor.h" +IndicatorSensor indicatorSensor; +#endif #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true @@ -103,6 +107,9 @@ int32_t EnvironmentTelemetryModule::runOnce() LOG_INFO("Environment Telemetry: init"); // it's possible to have this module enabled, only for displaying values on the screen. // therefore, we should only enable the sensor loop if measurement is also enabled +#ifdef SENSECAP_INDICATOR + result = indicatorSensor.runOnce(); +#endif #ifdef T1000X_SENSOR_EN result = t1000xSensor.runOnce(); #elif !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL @@ -298,6 +305,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m m->which_variant = meshtastic_Telemetry_environment_metrics_tag; m->variant.environment_metrics = meshtastic_EnvironmentMetrics_init_zero; +#ifdef SENSECAP_INDICATOR + valid = valid && indicatorSensor.getMetrics(m); + hasSensor = true; +#endif #ifdef T1000X_SENSOR_EN // add by WayenWeng valid = valid && t1000xSensor.getMetrics(m); hasSensor = true; @@ -410,7 +421,6 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m valid = valid && cgRadSens.getMetrics(m); hasSensor = true; } - #endif return valid && hasSensor; } diff --git a/src/modules/Telemetry/Sensor/IndicatorSensor.cpp b/src/modules/Telemetry/Sensor/IndicatorSensor.cpp new file mode 100644 index 000000000..f3dcd1727 --- /dev/null +++ b/src/modules/Telemetry/Sensor/IndicatorSensor.cpp @@ -0,0 +1,167 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(SENSECAP_INDICATOR) + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "IndicatorSensor.h" +#include "TelemetrySensor.h" +#include "serialization/cobs.h" +#include +#include + +IndicatorSensor::IndicatorSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "Indicator") {} + +#define SENSOR_BUF_SIZE (512) + +uint8_t buf[SENSOR_BUF_SIZE]; // recv +uint8_t data[SENSOR_BUF_SIZE]; // decode + +#define ACK_PKT_PARA "ACK" + +enum sensor_pkt_type { + PKT_TYPE_ACK = 0x00, // uin32_t + PKT_TYPE_CMD_COLLECT_INTERVAL = 0xA0, // uin32_t + PKT_TYPE_CMD_BEEP_ON = 0xA1, // uin32_t ms: on time + PKT_TYPE_CMD_BEEP_OFF = 0xA2, + PKT_TYPE_CMD_SHUTDOWN = 0xA3, // uin32_t + PKT_TYPE_CMD_POWER_ON = 0xA4, + PKT_TYPE_SENSOR_SCD41_TEMP = 0xB0, // float + PKT_TYPE_SENSOR_SCD41_HUMIDITY = 0xB1, // float + PKT_TYPE_SENSOR_SCD41_CO2 = 0xB2, // float + PKT_TYPE_SENSOR_AHT20_TEMP = 0xB3, // float + PKT_TYPE_SENSOR_AHT20_HUMIDITY = 0xB4, // float + PKT_TYPE_SENSOR_TVOC_INDEX = 0xB5, // float +}; + +static int cmd_send(uint8_t cmd, const char *p_data, uint8_t len) +{ + uint8_t buf[32] = {0}; + uint8_t data[32] = {0}; + + if (len > 31) { + return -1; + } + + uint8_t index = 1; + + data[0] = cmd; + + if (len > 0 && p_data != NULL) { + memcpy(&data[1], p_data, len); + index += len; + } + cobs_encode_result ret = cobs_encode(buf, sizeof(buf), data, index); + + // LOG_DEBUG("cobs TX status:%d, len:%d, type 0x%x", ret.status, ret.out_len, cmd); + + if (ret.status == COBS_ENCODE_OK) { + return uart_write_bytes(SENSOR_PORT_NUM, buf, ret.out_len + 1); + } + + return -1; +} + +int32_t IndicatorSensor::runOnce() +{ + LOG_INFO("%s: init", sensorName); + setup(); + return 2 * DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; // give it some time to start up +} + +void IndicatorSensor::setup() +{ + uart_config_t uart_config = { + .baud_rate = SENSOR_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, + }; + int intr_alloc_flags = 0; + char buffer[11]; + + uart_driver_install(SENSOR_PORT_NUM, SENSOR_BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags); + uart_param_config(SENSOR_PORT_NUM, &uart_config); + uart_set_pin(SENSOR_PORT_NUM, SENSOR_RP2040_TXD, SENSOR_RP2040_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + cmd_send(PKT_TYPE_CMD_POWER_ON, NULL, 0); + // measure and send only once every minute, for the phone API + const char *interval = ultoa(60000, buffer, 10); + cmd_send(PKT_TYPE_CMD_COLLECT_INTERVAL, interval, strlen(interval) + 1); +} + +bool IndicatorSensor::getMetrics(meshtastic_Telemetry *measurement) +{ + cobs_decode_result ret; + int len = uart_read_bytes(SENSOR_PORT_NUM, buf, (SENSOR_BUF_SIZE - 1), 100 / portTICK_PERIOD_MS); + + float value = 0.0; + uint8_t pkt_type = 0; + uint8_t *p_buf_start = buf; + uint8_t *p_buf_end = buf; + if (len > 0) { + while (p_buf_start < (buf + len)) { + p_buf_end = p_buf_start; + while (p_buf_end < (buf + len)) { + if (*p_buf_end == 0x00) { + break; + } + p_buf_end++; + } + // decode buf + memset(data, 0, sizeof(data)); + ret = cobs_decode(data, sizeof(data), p_buf_start, p_buf_end - p_buf_start); + + // LOG_DEBUG("cobs RX status:%d, len:%d, type:0x%x ", ret.status, ret.out_len, data[0]); + + if (ret.out_len > 1 && ret.status == COBS_DECODE_OK) { + + value = 0.0; + pkt_type = data[0]; + switch (pkt_type) { + case PKT_TYPE_SENSOR_SCD41_CO2: { + memcpy(&value, &data[1], sizeof(value)); + // LOG_DEBUG("CO2: %.1f", value); + cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4); + break; + } + + case PKT_TYPE_SENSOR_AHT20_TEMP: { + memcpy(&value, &data[1], sizeof(value)); + // LOG_DEBUG("Temp: %.1f", value); + cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4); + measurement->variant.environment_metrics.has_temperature = true; + measurement->variant.environment_metrics.temperature = value; + break; + } + + case PKT_TYPE_SENSOR_AHT20_HUMIDITY: { + memcpy(&value, &data[1], sizeof(value)); + // LOG_DEBUG("Humidity: %.1f", value); + cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4); + measurement->variant.environment_metrics.has_relative_humidity = true; + measurement->variant.environment_metrics.relative_humidity = value; + break; + } + + case PKT_TYPE_SENSOR_TVOC_INDEX: { + memcpy(&value, &data[1], sizeof(value)); + // LOG_DEBUG("Tvoc: %.1f", value); + cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4); + measurement->variant.environment_metrics.has_iaq = true; + measurement->variant.environment_metrics.iaq = value; + break; + } + default: + break; + } + } + + p_buf_start = p_buf_end + 1; // next message + } + return true; + } + return false; +} + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/IndicatorSensor.h b/src/modules/Telemetry/Sensor/IndicatorSensor.h new file mode 100644 index 000000000..48ecef8de --- /dev/null +++ b/src/modules/Telemetry/Sensor/IndicatorSensor.h @@ -0,0 +1,19 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" + +class IndicatorSensor : public TelemetrySensor +{ + protected: + virtual void setup() override; + + public: + IndicatorSensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; +}; + +#endif \ No newline at end of file diff --git a/src/serialization/cobs.cpp b/src/serialization/cobs.cpp new file mode 100644 index 000000000..39ea019fd --- /dev/null +++ b/src/serialization/cobs.cpp @@ -0,0 +1,131 @@ +#include "cobs.h" +#include + +#ifdef SENSECAP_INDICATOR + +cobs_encode_result cobs_encode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len) +{ + cobs_encode_result result = {0, COBS_ENCODE_OK}; + const uint8_t *src_read_ptr = src_ptr; + const uint8_t *src_end_ptr = src_read_ptr + src_len; + uint8_t *dst_buf_start_ptr = dst_buf_ptr; + uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len; + uint8_t *dst_code_write_ptr = dst_buf_ptr; + uint8_t *dst_write_ptr = dst_code_write_ptr + 1; + uint8_t src_byte = 0; + uint8_t search_len = 1; + + if ((dst_buf_ptr == NULL) || (src_ptr == NULL)) { + result.status = COBS_ENCODE_NULL_POINTER; + return result; + } + + if (src_len != 0) { + for (;;) { + if (dst_write_ptr >= dst_buf_end_ptr) { + result.status = (cobs_encode_status)(result.status | (cobs_encode_status)COBS_ENCODE_OUT_BUFFER_OVERFLOW); + break; + } + + src_byte = *src_read_ptr++; + if (src_byte == 0) { + *dst_code_write_ptr = search_len; + dst_code_write_ptr = dst_write_ptr++; + search_len = 1; + if (src_read_ptr >= src_end_ptr) { + break; + } + } else { + *dst_write_ptr++ = src_byte; + search_len++; + if (src_read_ptr >= src_end_ptr) { + break; + } + if (search_len == 0xFF) { + *dst_code_write_ptr = search_len; + dst_code_write_ptr = dst_write_ptr++; + search_len = 1; + } + } + } + } + + if (dst_code_write_ptr >= dst_buf_end_ptr) { + result.status = (cobs_encode_status)(result.status | (cobs_encode_status)COBS_ENCODE_OUT_BUFFER_OVERFLOW); + dst_write_ptr = dst_buf_end_ptr; + } else { + *dst_code_write_ptr = search_len; + } + + result.out_len = dst_write_ptr - dst_buf_start_ptr; + + return result; +} + +cobs_decode_result cobs_decode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len) +{ + cobs_decode_result result = {0, COBS_DECODE_OK}; + const uint8_t *src_read_ptr = src_ptr; + const uint8_t *src_end_ptr = src_read_ptr + src_len; + uint8_t *dst_buf_start_ptr = dst_buf_ptr; + uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len; + uint8_t *dst_write_ptr = dst_buf_ptr; + size_t remaining_bytes; + uint8_t src_byte; + uint8_t i; + uint8_t len_code; + + if ((dst_buf_ptr == NULL) || (src_ptr == NULL)) { + result.status = COBS_DECODE_NULL_POINTER; + return result; + } + + if (src_len != 0) { + for (;;) { + len_code = *src_read_ptr++; + if (len_code == 0) { + result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT); + break; + } + len_code--; + + remaining_bytes = src_end_ptr - src_read_ptr; + if (len_code > remaining_bytes) { + result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_INPUT_TOO_SHORT); + len_code = remaining_bytes; + } + + remaining_bytes = dst_buf_end_ptr - dst_write_ptr; + if (len_code > remaining_bytes) { + result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_OUT_BUFFER_OVERFLOW); + len_code = remaining_bytes; + } + + for (i = len_code; i != 0; i--) { + src_byte = *src_read_ptr++; + if (src_byte == 0) { + result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT); + } + *dst_write_ptr++ = src_byte; + } + + if (src_read_ptr >= src_end_ptr) { + break; + } + + if (len_code != 0xFE) { + if (dst_write_ptr >= dst_buf_end_ptr) { + result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_OUT_BUFFER_OVERFLOW); + break; + } + *dst_write_ptr++ = 0; + } + } + } + + result.out_len = dst_write_ptr - dst_buf_start_ptr; + + return result; +} + +#endif \ No newline at end of file diff --git a/src/serialization/cobs.h b/src/serialization/cobs.h new file mode 100644 index 000000000..f95e61f62 --- /dev/null +++ b/src/serialization/cobs.h @@ -0,0 +1,75 @@ +#ifndef COBS_H_ +#define COBS_H_ + +#include "configuration.h" + +#ifdef SENSECAP_INDICATOR + +#include +#include + +#define COBS_ENCODE_DST_BUF_LEN_MAX(SRC_LEN) ((SRC_LEN) + (((SRC_LEN) + 253u) / 254u)) +#define COBS_DECODE_DST_BUF_LEN_MAX(SRC_LEN) (((SRC_LEN) == 0) ? 0u : ((SRC_LEN)-1u)) +#define COBS_ENCODE_SRC_OFFSET(SRC_LEN) (((SRC_LEN) + 253u) / 254u) + +typedef enum { + COBS_ENCODE_OK = 0x00, + COBS_ENCODE_NULL_POINTER = 0x01, + COBS_ENCODE_OUT_BUFFER_OVERFLOW = 0x02 +} cobs_encode_status; + +typedef struct { + size_t out_len; + cobs_encode_status status; +} cobs_encode_result; + +typedef enum { + COBS_DECODE_OK = 0x00, + COBS_DECODE_NULL_POINTER = 0x01, + COBS_DECODE_OUT_BUFFER_OVERFLOW = 0x02, + COBS_DECODE_ZERO_BYTE_IN_INPUT = 0x04, + COBS_DECODE_INPUT_TOO_SHORT = 0x08 +} cobs_decode_status; + +typedef struct { + size_t out_len; + cobs_decode_status status; +} cobs_decode_result; + +#ifdef __cplusplus +extern "C" { +#endif + +/* COBS-encode a string of input bytes. + * + * dst_buf_ptr: The buffer into which the result will be written + * dst_buf_len: Length of the buffer into which the result will be written + * src_ptr: The byte string to be encoded + * src_len Length of the byte string to be encoded + * + * returns: A struct containing the success status of the encoding + * operation and the length of the result (that was written to + * dst_buf_ptr) + */ +cobs_encode_result cobs_encode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len); + +/* Decode a COBS byte string. + * + * dst_buf_ptr: The buffer into which the result will be written + * dst_buf_len: Length of the buffer into which the result will be written + * src_ptr: The byte string to be decoded + * src_len Length of the byte string to be decoded + * + * returns: A struct containing the success status of the decoding + * operation and the length of the result (that was written to + * dst_buf_ptr) + */ +cobs_decode_result cobs_decode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SENSECAP_INDICATOR */ + +#endif /* COBS_H_ */ diff --git a/variants/seeed-sensecap-indicator/variant.h b/variants/seeed-sensecap-indicator/variant.h index 6028a3ffa..289fea55b 100644 --- a/variants/seeed-sensecap-indicator/variant.h +++ b/variants/seeed-sensecap-indicator/variant.h @@ -1,6 +1,12 @@ #define I2C_SDA 39 #define I2C_SCL 40 +// This board has a serial coprocessor for sensor readings +#define SENSOR_RP2040_TXD 19 +#define SENSOR_RP2040_RXD 20 +#define SENSOR_PORT_NUM 2 +#define SENSOR_BAUD_RATE 115200 + #define BUTTON_PIN 38 // #define BUTTON_NEED_PULLUP From bfcfca2e462aa238d1c09e1afec73d41e28cb275 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 31 Dec 2024 11:18:29 +1100 Subject: [PATCH 07/25] add spi_host + missing rotation (#5691) Co-authored-by: mverch67 --- src/graphics/TFTDisplay.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 4f2af670b..4d6c016ed 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -352,7 +352,7 @@ static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h class LGFX : public lgfx::LGFX_Device { - lgfx::Panel_LCD *_panel_instance; + lgfx::Panel_Device *_panel_instance; lgfx::Bus_SPI _bus_instance; lgfx::ITouch *_touch_instance; @@ -366,10 +366,21 @@ class LGFX : public lgfx::LGFX_Device _panel_instance = new lgfx::Panel_ST7735; else if (settingsMap[displayPanel] == st7735s) _panel_instance = new lgfx::Panel_ST7735S; + else if (settingsMap[displayPanel] == st7796) + _panel_instance = new lgfx::Panel_ST7796; else if (settingsMap[displayPanel] == ili9341) _panel_instance = new lgfx::Panel_ILI9341; else if (settingsMap[displayPanel] == ili9342) _panel_instance = new lgfx::Panel_ILI9342; + else if (settingsMap[displayPanel] == ili9488) + _panel_instance = new lgfx::Panel_ILI9488; + else if (settingsMap[displayPanel] == hx8357d) + _panel_instance = new lgfx::Panel_HX8357D; + else { + _panel_instance = new lgfx::Panel_NULL; + LOG_ERROR("Unknown display panel configured!\n"); + } + auto buscfg = _bus_instance.config(); buscfg.spi_mode = 0; buscfg.spi_host = settingsMap[displayspidev]; @@ -383,12 +394,12 @@ class LGFX : public lgfx::LGFX_Device LOG_DEBUG("Height: %d, Width: %d ", settingsMap[displayHeight], settingsMap[displayWidth]); cfg.pin_cs = settingsMap[displayCS]; // Pin number where CS is connected (-1 = disable) cfg.pin_rst = settingsMap[displayReset]; - cfg.panel_width = settingsMap[displayWidth]; // actual displayable width - cfg.panel_height = settingsMap[displayHeight]; // actual displayable height - cfg.offset_x = settingsMap[displayOffsetX]; // Panel offset amount in X direction - cfg.offset_y = settingsMap[displayOffsetY]; // Panel offset amount in Y direction - cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored) - cfg.invert = settingsMap[displayInvert]; // Set to true if the light/darkness of the panel is reversed + cfg.panel_width = settingsMap[displayWidth]; // actual displayable width + cfg.panel_height = settingsMap[displayHeight]; // actual displayable height + cfg.offset_x = settingsMap[displayOffsetX]; // Panel offset amount in X direction + cfg.offset_y = settingsMap[displayOffsetY]; // Panel offset amount in Y direction + cfg.offset_rotation = settingsMap[displayOffsetRotate]; // Rotation direction value offset 0~7 (4~7 is mirrored) + cfg.invert = settingsMap[displayInvert]; // Set to true if the light/darkness of the panel is reversed _panel_instance->config(cfg); @@ -410,7 +421,7 @@ class LGFX : public lgfx::LGFX_Device touch_cfg.y_max = settingsMap[displayWidth] - 1; touch_cfg.pin_int = settingsMap[touchscreenIRQ]; touch_cfg.bus_shared = true; - touch_cfg.offset_rotation = 1; + touch_cfg.offset_rotation = settingsMap[touchscreenRotate]; if (settingsMap[touchscreenI2CAddr] != -1) { touch_cfg.i2c_addr = settingsMap[touchscreenI2CAddr]; } else { From f9e71c3fb9ea5afc5bfe62494803e0177c32c369 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 31 Dec 2024 12:01:21 +1100 Subject: [PATCH 08/25] Remove an \n (#5703) --- src/graphics/TFTDisplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 4d6c016ed..c5187cffc 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -378,7 +378,7 @@ class LGFX : public lgfx::LGFX_Device _panel_instance = new lgfx::Panel_HX8357D; else { _panel_instance = new lgfx::Panel_NULL; - LOG_ERROR("Unknown display panel configured!\n"); + LOG_ERROR("Unknown display panel configured!"); } auto buscfg = _bus_instance.config(); From d1e5be515a63ea16dc21a690070d699ded3f61e1 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 31 Dec 2024 13:00:37 +1100 Subject: [PATCH 09/25] cherry-pick: disable BT when TFT in use (#5705) * disable BT when TFT in use * add comment BT disable --------- Co-authored-by: mverch67 --- src/mesh/NodeDB.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 9dbe92b7c..994e59d35 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -409,6 +409,13 @@ bool NodeDB::resetRadioConfig(bool factory_reset) rebootAtMsec = millis() + (5 * 1000); } +#if (defined(T_DECK) || defined(T_WATCH_S3) || defined(UNPHONE) || defined(PICOMPUTER_S3)) && defined(HAS_TFT) + // as long as PhoneAPI shares BT and TFT app switch BT off + config.bluetooth.enabled = false; + if (moduleConfig.external_notification.nag_timeout == 60) + moduleConfig.external_notification.nag_timeout = 0; +#endif + return didFactoryReset; } From 58ebd5bcdb02a1935238f6005d3c65a32209549d Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 31 Dec 2024 00:46:03 -0600 Subject: [PATCH 10/25] Actually use the MAC address from a ch341 (#5704) Co-authored-by: Tom Fifield --- src/platform/portduino/PortduinoGlue.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 0c981bf16..b020f5991 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -231,6 +232,9 @@ void portduinoSetup() dmac[3] = hash[3]; dmac[4] = hash[4]; dmac[5] = hash[5]; + std::stringstream mactmp; + mactmp << std::hex << +dmac[0] << +dmac[1] << +dmac[2] << +dmac[3] << +dmac[4] << +dmac[5]; + settingsStrings[mac_address] = mactmp.str(); } } From 9af8c58c4075ab0d9d1342c4a87c8ebd11b81c1b Mon Sep 17 00:00:00 2001 From: Bernd Giesecke Date: Tue, 31 Dec 2024 20:36:49 +0800 Subject: [PATCH 11/25] Add Ethernet RAK13800 support to RAK11310 (#5707) --- platformio.ini | 3 ++- src/mesh/eth/ethClient.cpp | 11 +++++++++++ variants/rak11310/pins_arduino.h | 18 +++++++++--------- variants/rak11310/platformio.ini | 5 ++++- variants/rak11310/variant.h | 15 +++++++++++---- 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/platformio.ini b/platformio.ini index bf50b7646..3129decaa 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,6 +30,7 @@ default_envs = tbeam ;default_envs = rak4631 ;default_envs = rak4631_eth_gw ;default_envs = rak2560 +;default_envs = rak11310 ;default_envs = rak_wismeshtap ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano @@ -164,4 +165,4 @@ lib_deps = robtillaart/INA226@0.6.0 ; Health Sensor Libraries - sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2 \ No newline at end of file + sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2 diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 3b4d716f5..08ecb7ce8 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -107,6 +107,11 @@ static int32_t reconnectETH() bool initEthernet() { if (config.network.eth_enabled) { +#ifdef PIN_ETH_POWER_EN + pinMode(PIN_ETH_POWER_EN, OUTPUT); + digitalWrite(PIN_ETH_POWER_EN, HIGH); // Power up. + delay(100); +#endif #ifdef PIN_ETHERNET_RESET pinMode(PIN_ETHERNET_RESET, OUTPUT); @@ -115,6 +120,12 @@ bool initEthernet() digitalWrite(PIN_ETHERNET_RESET, HIGH); // Reset Time. #endif +#ifdef RAK11310 // Initialize the SPI port + ETH_SPI_PORT.setSCK(PIN_SPI0_SCK); + ETH_SPI_PORT.setTX(PIN_SPI0_MOSI); + ETH_SPI_PORT.setRX(PIN_SPI0_MISO); + ETH_SPI_PORT.begin(); +#endif Ethernet.init(ETH_SPI_PORT, PIN_ETHERNET_SS); uint8_t mac[6]; diff --git a/variants/rak11310/pins_arduino.h b/variants/rak11310/pins_arduino.h index 626bed1da..0e2808b19 100644 --- a/variants/rak11310/pins_arduino.h +++ b/variants/rak11310/pins_arduino.h @@ -38,15 +38,15 @@ static const uint8_t A3 = PIN_A3; #define PIN_SERIAL2_RX (5ul) // SPI -#define PIN_SPI0_MISO (12u) -#define PIN_SPI0_MOSI (11u) -#define PIN_SPI0_SCK (10u) -#define PIN_SPI0_SS (13u) +#define PIN_SPI1_MISO (12u) +#define PIN_SPI1_MOSI (11u) +#define PIN_SPI1_SCK (10u) +#define PIN_SPI1_SS (13u) -#define PIN_SPI1_MISO (16u) -#define PIN_SPI1_MOSI (19u) -#define PIN_SPI1_SCK (18u) -#define PIN_SPI1_SS (17u) +#define PIN_SPI0_MISO (16u) +#define PIN_SPI0_MOSI (19u) +#define PIN_SPI0_SCK (18u) +#define PIN_SPI0_SS (17u) // Wire #define PIN_WIRE0_SDA (2u) @@ -65,4 +65,4 @@ static const uint8_t MISO = PIN_SPI0_MISO; static const uint8_t SCK = PIN_SPI0_SCK; static const uint8_t SDA = PIN_WIRE0_SDA; -static const uint8_t SCL = PIN_WIRE0_SCL; \ No newline at end of file +static const uint8_t SCL = PIN_WIRE0_SCL; diff --git a/variants/rak11310/platformio.ini b/variants/rak11310/platformio.ini index 923cedaa3..0cc60bc7c 100644 --- a/variants/rak11310/platformio.ini +++ b/variants/rak11310/platformio.ini @@ -12,7 +12,10 @@ build_flags = ${rp2040_base.build_flags} -Ivariants/rak11310 -DDEBUG_RP2040_PORT=Serial -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus" +build_src_filter = ${rp2040_base.build_src_filter} +<../variants/rak11310> + + + lib_deps = ${rp2040_base.lib_deps} + ${networking_base.lib_deps} + https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2 debug_build_flags = ${rp2040_base.build_flags}, -g -debug_tool = cmsis-dap ; for e.g. Picotool \ No newline at end of file +debug_tool = cmsis-dap ; for e.g. Picotool diff --git a/variants/rak11310/variant.h b/variants/rak11310/variant.h index 54e403ee7..bc8d2d71b 100644 --- a/variants/rak11310/variant.h +++ b/variants/rak11310/variant.h @@ -28,10 +28,10 @@ // RAK BSP somehow uses SPI1 instead of SPI0 #define HW_SPI1_DEVICE -#define LORA_SCK PIN_SPI0_SCK -#define LORA_MOSI PIN_SPI0_MOSI -#define LORA_MISO PIN_SPI0_MISO -#define LORA_CS PIN_SPI0_SS +#define LORA_SCK (10u) +#define LORA_MOSI (11u) +#define LORA_MISO (12u) +#define LORA_CS (13u) #define LORA_DIO0 RADIOLIB_NC #define LORA_RESET 14 @@ -49,3 +49,10 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 #endif + +#define HAS_ETHERNET 1 +#define PIN_ETHERNET_RESET 7 // IO3 +#define PIN_ETHERNET_SS 17 +#define ETH_SPI_PORT SPI + +#define PIN_ETH_POWER_EN 22 From 8b34c4ff05eb5ce63e95a2dee671bfacc45bbca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Tue, 31 Dec 2024 15:58:59 +0100 Subject: [PATCH 12/25] fix misc cppcheck things and compile time warnings (#5710) --- src/mesh/NodeDB.cpp | 13 +++--- .../Telemetry/Sensor/CGRadSensSensor.cpp | 3 +- .../Telemetry/Sensor/IndicatorSensor.cpp | 15 ++++--- src/platform/portduino/USBHal.h | 2 +- src/serialization/MeshPacketSerializer.cpp | 2 + src/serialization/MeshPacketSerializer.h | 1 - src/serialization/cobs.cpp | 40 +++++++++---------- src/sleep.cpp | 7 ++++ 8 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 994e59d35..bbc9eb1ea 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -992,8 +992,11 @@ void NodeDB::loadFromDisk() // Make sure we load hard coded admin keys even when the configuration file has none. // Initialize admin_key_count to zero byte numAdminKeys = 0; +#if defined(USERPREFS_USE_ADMIN_KEY_0) || defined(USERPREFS_USE_ADMIN_KEY_1) || defined(USERPREFS_USE_ADMIN_KEY_2) uint16_t sum = 0; +#endif #ifdef USERPREFS_USE_ADMIN_KEY_0 + for (uint8_t b = 0; b < 32; b++) { sum += config.security.admin_key[0].bytes[b]; } @@ -1002,8 +1005,6 @@ void NodeDB::loadFromDisk() LOG_INFO("Admin 0 key zero. Loading hard coded key from user preferences."); memcpy(config.security.admin_key[0].bytes, userprefs_admin_key_0, 32); config.security.admin_key[0].size = 32; - config.security.admin_key_count = numAdminKeys; - saveToDisk(SEGMENT_CONFIG); } #endif @@ -1017,8 +1018,6 @@ void NodeDB::loadFromDisk() LOG_INFO("Admin 1 key zero. Loading hard coded key from user preferences."); memcpy(config.security.admin_key[1].bytes, userprefs_admin_key_1, 32); config.security.admin_key[1].size = 32; - config.security.admin_key_count = numAdminKeys; - saveToDisk(SEGMENT_CONFIG); } #endif @@ -1032,10 +1031,14 @@ void NodeDB::loadFromDisk() LOG_INFO("Admin 2 key zero. Loading hard coded key from user preferences."); memcpy(config.security.admin_key[2].bytes, userprefs_admin_key_2, 32); config.security.admin_key[2].size = 32; + } +#endif + + if (numAdminKeys > 0) { + LOG_INFO("Saving %d hard coded admin keys.", numAdminKeys); config.security.admin_key_count = numAdminKeys; saveToDisk(SEGMENT_CONFIG); } -#endif state = loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig), &meshtastic_LocalModuleConfig_msg, &moduleConfig); diff --git a/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp index 5e69cc22f..ac5df1b81 100644 --- a/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp +++ b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp @@ -41,13 +41,12 @@ void CGRadSensSensor::begin(TwoWire *wire, uint8_t addr) float CGRadSensSensor::getStaticRadiation() { // Read a register, following the same pattern as the RCWL9620Sensor - uint32_t data; _wire->beginTransmission(_addr); // Transfer data to addr. _wire->write(0x06); // Radiation intensity (static period T = 500 sec) if (_wire->endTransmission() == 0) { if (_wire->requestFrom(_addr, (uint8_t)3)) { ; // Request 3 bytes - data = _wire->read(); + uint32_t data = _wire->read(); data <<= 8; data |= _wire->read(); data <<= 8; diff --git a/src/modules/Telemetry/Sensor/IndicatorSensor.cpp b/src/modules/Telemetry/Sensor/IndicatorSensor.cpp index f3dcd1727..317357137 100644 --- a/src/modules/Telemetry/Sensor/IndicatorSensor.cpp +++ b/src/modules/Telemetry/Sensor/IndicatorSensor.cpp @@ -35,8 +35,8 @@ enum sensor_pkt_type { static int cmd_send(uint8_t cmd, const char *p_data, uint8_t len) { - uint8_t buf[32] = {0}; - uint8_t data[32] = {0}; + uint8_t send_buf[32] = {0}; + uint8_t send_data[32] = {0}; if (len > 31) { return -1; @@ -44,18 +44,18 @@ static int cmd_send(uint8_t cmd, const char *p_data, uint8_t len) uint8_t index = 1; - data[0] = cmd; + send_data[0] = cmd; if (len > 0 && p_data != NULL) { - memcpy(&data[1], p_data, len); + memcpy(&send_data[1], p_data, len); index += len; } - cobs_encode_result ret = cobs_encode(buf, sizeof(buf), data, index); + cobs_encode_result ret = cobs_encode(send_buf, sizeof(send_buf), send_data, index); // LOG_DEBUG("cobs TX status:%d, len:%d, type 0x%x", ret.status, ret.out_len, cmd); if (ret.status == COBS_ENCODE_OK) { - return uart_write_bytes(SENSOR_PORT_NUM, buf, ret.out_len + 1); + return uart_write_bytes(SENSOR_PORT_NUM, send_buf, ret.out_len + 1); } return -1; @@ -96,7 +96,6 @@ bool IndicatorSensor::getMetrics(meshtastic_Telemetry *measurement) int len = uart_read_bytes(SENSOR_PORT_NUM, buf, (SENSOR_BUF_SIZE - 1), 100 / portTICK_PERIOD_MS); float value = 0.0; - uint8_t pkt_type = 0; uint8_t *p_buf_start = buf; uint8_t *p_buf_end = buf; if (len > 0) { @@ -117,7 +116,7 @@ bool IndicatorSensor::getMetrics(meshtastic_Telemetry *measurement) if (ret.out_len > 1 && ret.status == COBS_DECODE_OK) { value = 0.0; - pkt_type = data[0]; + uint8_t pkt_type = data[0]; switch (pkt_type) { case PKT_TYPE_SENSOR_SCD41_CO2: { memcpy(&value, &data[1], sizeof(value)); diff --git a/src/platform/portduino/USBHal.h b/src/platform/portduino/USBHal.h index 2b0302ced..064f7ae36 100644 --- a/src/platform/portduino/USBHal.h +++ b/src/platform/portduino/USBHal.h @@ -26,7 +26,7 @@ class Ch341Hal : public RadioLibHal { public: // default constructor - initializes the base HAL and any needed private members - Ch341Hal(uint8_t spiChannel, uint32_t spiSpeed = 2000000, uint8_t spiDevice = 0, uint8_t gpioDevice = 0) + explicit Ch341Hal(uint8_t spiChannel, uint32_t spiSpeed = 2000000, uint8_t spiDevice = 0, uint8_t gpioDevice = 0) : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING) { } diff --git a/src/serialization/MeshPacketSerializer.cpp b/src/serialization/MeshPacketSerializer.cpp index b4603186b..2f0d881f2 100644 --- a/src/serialization/MeshPacketSerializer.cpp +++ b/src/serialization/MeshPacketSerializer.cpp @@ -13,6 +13,8 @@ #include "mesh/generated/meshtastic/remote_hardware.pb.h" #include +static const char *errStr = "Error decoding proto for %s message!"; + std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog) { // the created jsonObj is immutable after creation, so diff --git a/src/serialization/MeshPacketSerializer.h b/src/serialization/MeshPacketSerializer.h index 12efccb43..03860ab35 100644 --- a/src/serialization/MeshPacketSerializer.h +++ b/src/serialization/MeshPacketSerializer.h @@ -2,7 +2,6 @@ #include static const char hexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; -static const char *errStr = "Error decoding proto for %s message!"; class MeshPacketSerializer { diff --git a/src/serialization/cobs.cpp b/src/serialization/cobs.cpp index 39ea019fd..afb868f50 100644 --- a/src/serialization/cobs.cpp +++ b/src/serialization/cobs.cpp @@ -5,21 +5,22 @@ cobs_encode_result cobs_encode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len) { + cobs_encode_result result = {0, COBS_ENCODE_OK}; + + if (!dst_buf_ptr || !src_ptr) { + result.status = COBS_ENCODE_NULL_POINTER; + return result; + } + const uint8_t *src_read_ptr = src_ptr; const uint8_t *src_end_ptr = src_read_ptr + src_len; uint8_t *dst_buf_start_ptr = dst_buf_ptr; uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len; uint8_t *dst_code_write_ptr = dst_buf_ptr; uint8_t *dst_write_ptr = dst_code_write_ptr + 1; - uint8_t src_byte = 0; uint8_t search_len = 1; - if ((dst_buf_ptr == NULL) || (src_ptr == NULL)) { - result.status = COBS_ENCODE_NULL_POINTER; - return result; - } - if (src_len != 0) { for (;;) { if (dst_write_ptr >= dst_buf_end_ptr) { @@ -27,7 +28,7 @@ cobs_encode_result cobs_encode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const u break; } - src_byte = *src_read_ptr++; + uint8_t src_byte = *src_read_ptr++; if (src_byte == 0) { *dst_code_write_ptr = search_len; dst_code_write_ptr = dst_write_ptr++; @@ -65,31 +66,28 @@ cobs_encode_result cobs_encode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const u cobs_decode_result cobs_decode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len) { cobs_decode_result result = {0, COBS_DECODE_OK}; - const uint8_t *src_read_ptr = src_ptr; - const uint8_t *src_end_ptr = src_read_ptr + src_len; - uint8_t *dst_buf_start_ptr = dst_buf_ptr; - uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len; - uint8_t *dst_write_ptr = dst_buf_ptr; - size_t remaining_bytes; - uint8_t src_byte; - uint8_t i; - uint8_t len_code; - if ((dst_buf_ptr == NULL) || (src_ptr == NULL)) { + if (!dst_buf_ptr || !src_ptr) { result.status = COBS_DECODE_NULL_POINTER; return result; } + const uint8_t *src_read_ptr = src_ptr; + const uint8_t *src_end_ptr = src_read_ptr + src_len; + uint8_t *dst_buf_start_ptr = dst_buf_ptr; + const uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len; + uint8_t *dst_write_ptr = dst_buf_ptr; + if (src_len != 0) { for (;;) { - len_code = *src_read_ptr++; + uint8_t len_code = *src_read_ptr++; if (len_code == 0) { result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT); break; } len_code--; - remaining_bytes = src_end_ptr - src_read_ptr; + size_t remaining_bytes = src_end_ptr - src_read_ptr; if (len_code > remaining_bytes) { result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_INPUT_TOO_SHORT); len_code = remaining_bytes; @@ -101,8 +99,8 @@ cobs_decode_result cobs_decode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const u len_code = remaining_bytes; } - for (i = len_code; i != 0; i--) { - src_byte = *src_read_ptr++; + for (uint8_t i = len_code; i != 0; i--) { + uint8_t src_byte = *src_read_ptr++; if (src_byte == 0) { result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT); } diff --git a/src/sleep.cpp b/src/sleep.cpp index 69eb0349a..5f1909a77 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -271,6 +271,12 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false, bool skipSaveN gpio_hold_en((gpio_num_t)BUTTON_PIN); } #endif +#ifdef SENSECAP_INDICATOR + // Portexpander definition does not pass GPIO_IS_VALID_OUTPUT_GPIO + pinMode(LORA_CS, OUTPUT); + digitalWrite(LORA_CS, HIGH); + gpio_hold_en((gpio_num_t)LORA_CS); +#else if (GPIO_IS_VALID_OUTPUT_GPIO(LORA_CS)) { // LoRa CS (RADIO_NSS) needs to stay HIGH, even during deep sleep pinMode(LORA_CS, OUTPUT); @@ -278,6 +284,7 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false, bool skipSaveN gpio_hold_en((gpio_num_t)LORA_CS); } #endif +#endif #ifdef HAS_PMU if (pmu_found && PMU) { From fdcc0e12aa17673d7f2838c22ee8faab0a530f31 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Wed, 1 Jan 2025 03:15:01 +1100 Subject: [PATCH 13/25] Minor TFT branch synch (#5706) --- src/graphics/Screen.cpp | 4 ++-- src/modules/CannedMessageModule.cpp | 2 ++ src/sleep.cpp | 5 ++++- variants/seeed-sensecap-indicator/platformio.ini | 4 ++-- variants/seeed-sensecap-indicator/variant.h | 3 +-- variants/t-deck/platformio.ini | 4 ++-- variants/t-deck/variant.h | 6 ++++-- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 31647c92d..198dcc235 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1506,7 +1506,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O #elif defined(USE_ST7567) dispdev = new ST7567Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); -#elif ARCH_PORTDUINO +#elif ARCH_PORTDUINO && !HAS_TFT if (settingsMap[displayPanel] != no_screen) { LOG_DEBUG("Make TFTDisplay!"); dispdev = new TFTDisplay(address.address, -1, -1, geometry, @@ -2756,4 +2756,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN \ No newline at end of file +#endif // HAS_SCREEN diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index a96fcc080..c20b7b56e 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -982,6 +982,7 @@ bool CannedMessageModule::interceptingKeyboardInput() } } +#if !HAS_TFT void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { char buffer[50]; @@ -1140,6 +1141,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st } } } +#endif //! HAS_TFT ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp) { diff --git a/src/sleep.cpp b/src/sleep.cpp index 5f1909a77..161b6e107 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -58,7 +58,7 @@ RTC_DATA_ATTR int bootCount = 0; */ void setCPUFast(bool on) { -#if defined(ARCH_ESP32) && HAS_WIFI +#if defined(ARCH_ESP32) && HAS_WIFI && !HAS_TFT if (isWifiAvailable()) { /* @@ -391,6 +391,9 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r gpio_wakeup_enable(pin, GPIO_INTR_LOW_LEVEL); esp_sleep_enable_gpio_wakeup(); #endif +#ifdef INPUTDRIVER_ENCODER_BTN + gpio_wakeup_enable((gpio_num_t)INPUTDRIVER_ENCODER_BTN, GPIO_INTR_LOW_LEVEL); +#endif #ifdef T_WATCH_S3 gpio_wakeup_enable((gpio_num_t)SCREEN_TOUCH_INT, GPIO_INTR_LOW_LEVEL); #endif diff --git a/variants/seeed-sensecap-indicator/platformio.ini b/variants/seeed-sensecap-indicator/platformio.ini index 86d6d0412..1b64ed6e1 100644 --- a/variants/seeed-sensecap-indicator/platformio.ini +++ b/variants/seeed-sensecap-indicator/platformio.ini @@ -24,5 +24,5 @@ build_flags = ${esp32_base.build_flags} lib_deps = ${esp32s3_base.lib_deps} https://github.com/mverch67/LovyanGFX#develop - earlephilhower/ESP8266Audio@^1.9.7 - earlephilhower/ESP8266SAM@^1.0.1 \ No newline at end of file + earlephilhower/ESP8266Audio@^1.9.9 + earlephilhower/ESP8266SAM@^1.0.1 diff --git a/variants/seeed-sensecap-indicator/variant.h b/variants/seeed-sensecap-indicator/variant.h index 289fea55b..29d547be3 100644 --- a/variants/seeed-sensecap-indicator/variant.h +++ b/variants/seeed-sensecap-indicator/variant.h @@ -25,8 +25,7 @@ #define ST7701_BL 45 #define ST7701_SPI_HOST SPI2_HOST #define ST7701_BACKLIGHT_EN 45 -#define SPI_FREQUENCY 20000000 -#define SPI_READ_FREQUENCY 16000000 +#define SPI_FREQUENCY 12000000 #define TFT_HEIGHT 480 #define TFT_WIDTH 480 #define TFT_OFFSET_X 0 diff --git a/variants/t-deck/platformio.ini b/variants/t-deck/platformio.ini index 16769e2f2..d2f09f50b 100644 --- a/variants/t-deck/platformio.ini +++ b/variants/t-deck/platformio.ini @@ -6,7 +6,7 @@ board_check = true upload_protocol = esptool #upload_port = COM29 -build_flags = ${esp32_base.build_flags} +build_flags = ${esp32s3_base.build_flags} -DT_DECK -DBOARD_HAS_PSRAM -DMAX_THREADS=40 @@ -16,4 +16,4 @@ build_flags = ${esp32_base.build_flags} lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX@^1.1.9 earlephilhower/ESP8266Audio@^1.9.9 - earlephilhower/ESP8266SAM@^1.0.1 \ No newline at end of file + earlephilhower/ESP8266SAM@^1.0.1 diff --git a/variants/t-deck/variant.h b/variants/t-deck/variant.h index 91c12ab3d..4aeeb7ca8 100644 --- a/variants/t-deck/variant.h +++ b/variants/t-deck/variant.h @@ -27,8 +27,10 @@ #define SLEEP_TIME 120 +#ifndef HAS_TFT #define BUTTON_PIN 0 // #define BUTTON_NEED_PULLUP +#endif #define GPS_DEFAULT_NOT_PRESENT 1 #define GPS_RX_PIN 44 #define GPS_TX_PIN 43 @@ -60,7 +62,7 @@ #define TB_DOWN 15 #define TB_LEFT 1 #define TB_RIGHT 2 -#define TB_PRESS BUTTON_PIN +#define TB_PRESS 0 // BUTTON_PIN // microphone #define ES7210_SCK 47 @@ -98,4 +100,4 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 // Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface -// code) \ No newline at end of file +// code) From 9abd07bb0535d67ad807800aba854f11aaf61395 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 31 Dec 2024 16:06:38 -0600 Subject: [PATCH 14/25] Set ch341 MAD Address via sprintf formatting (#5713) --- src/platform/portduino/PortduinoGlue.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index b020f5991..b042510f5 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -232,9 +231,9 @@ void portduinoSetup() dmac[3] = hash[3]; dmac[4] = hash[4]; dmac[5] = hash[5]; - std::stringstream mactmp; - mactmp << std::hex << +dmac[0] << +dmac[1] << +dmac[2] << +dmac[3] << +dmac[4] << +dmac[5]; - settingsStrings[mac_address] = mactmp.str(); + char macBuf[13] = {0}; + sprintf(macBuf, "%02X%02X%02X%02X%02X%02X", dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]); + settingsStrings[mac_address] = macBuf; } } @@ -244,7 +243,7 @@ void portduinoSetup() std::cout << "Please set a MAC Address in config.yaml using either MACAddress or MACAddressSource." << std::endl; exit(EXIT_FAILURE); } - std::cout << "MAC Address: " << std::hex << +dmac[0] << +dmac[1] << +dmac[2] << +dmac[3] << +dmac[4] << +dmac[5] << std::endl; + printf("MAC ADDRESS: %02X:%02X:%02X:%02X:%02X:%02X\n", dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]); // Rather important to set this, if not running simulated. randomSeed(time(NULL)); From c2c06ed0adb3f779d88ab6f812a380d848c72c75 Mon Sep 17 00:00:00 2001 From: Eric Severance Date: Wed, 1 Jan 2025 16:40:14 -0800 Subject: [PATCH 15/25] Move DecodedServiceEnvelope into its own file (#5715) --- src/mqtt/MQTT.cpp | 19 +------------------ src/mqtt/ServiceEnvelope.cpp | 23 +++++++++++++++++++++++ src/mqtt/ServiceEnvelope.h | 13 +++++++++++++ 3 files changed, 37 insertions(+), 18 deletions(-) create mode 100644 src/mqtt/ServiceEnvelope.cpp create mode 100644 src/mqtt/ServiceEnvelope.h diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 4260ae201..5141af560 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -2,6 +2,7 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" +#include "ServiceEnvelope.h" #include "configuration.h" #include "main.h" #include "mesh/Channels.h" @@ -25,7 +26,6 @@ #endif #include #include -#include #include #include @@ -47,23 +47,6 @@ static uint8_t bytes[meshtastic_MqttClientProxyMessage_size + 30]; // 12 for cha static bool isMqttServerAddressPrivate = false; -// meshtastic_ServiceEnvelope that automatically releases dynamically allocated memory when it goes out of scope. -struct DecodedServiceEnvelope : public meshtastic_ServiceEnvelope { - DecodedServiceEnvelope() = delete; - DecodedServiceEnvelope(const uint8_t *payload, size_t length) - : meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_default), - validDecode(pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, this)) - { - } - ~DecodedServiceEnvelope() - { - if (validDecode) - pb_release(&meshtastic_ServiceEnvelope_msg, this); - } - // Clients must check that this is true before using. - const bool validDecode; -}; - inline void onReceiveProto(char *topic, byte *payload, size_t length) { const DecodedServiceEnvelope e(payload, length); diff --git a/src/mqtt/ServiceEnvelope.cpp b/src/mqtt/ServiceEnvelope.cpp new file mode 100644 index 000000000..ee55f22f6 --- /dev/null +++ b/src/mqtt/ServiceEnvelope.cpp @@ -0,0 +1,23 @@ +#include "ServiceEnvelope.h" +#include "mesh-pb-constants.h" +#include + +DecodedServiceEnvelope::DecodedServiceEnvelope(const uint8_t *payload, size_t length) + : meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_default), + validDecode(pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, this)) +{ +} + +DecodedServiceEnvelope::DecodedServiceEnvelope(DecodedServiceEnvelope &&other) + : meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_zero), validDecode(other.validDecode) +{ + std::swap(packet, other.packet); + std::swap(channel_id, other.channel_id); + std::swap(gateway_id, other.gateway_id); +} + +DecodedServiceEnvelope::~DecodedServiceEnvelope() +{ + if (validDecode) + pb_release(&meshtastic_ServiceEnvelope_msg, this); +} \ No newline at end of file diff --git a/src/mqtt/ServiceEnvelope.h b/src/mqtt/ServiceEnvelope.h new file mode 100644 index 000000000..6ab0695db --- /dev/null +++ b/src/mqtt/ServiceEnvelope.h @@ -0,0 +1,13 @@ +#pragma once + +#include "mesh/generated/meshtastic/mqtt.pb.h" + +// meshtastic_ServiceEnvelope that automatically releases dynamically allocated memory when it goes out of scope. +struct DecodedServiceEnvelope : public meshtastic_ServiceEnvelope { + DecodedServiceEnvelope(const uint8_t *payload, size_t length); + DecodedServiceEnvelope(DecodedServiceEnvelope &) = delete; + DecodedServiceEnvelope(DecodedServiceEnvelope &&); + ~DecodedServiceEnvelope(); + // Clients must check that this is true before using. + const bool validDecode; +}; \ No newline at end of file From 9f32995d7fcf96384dc01b5b953772327a600e97 Mon Sep 17 00:00:00 2001 From: Eric Severance Date: Wed, 1 Jan 2025 17:25:01 -0800 Subject: [PATCH 16/25] Implement MeshModule destructor (#5714) --- src/mesh/MeshModule.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp index 9de54ade5..2f2863fa5 100644 --- a/src/mesh/MeshModule.cpp +++ b/src/mesh/MeshModule.cpp @@ -4,6 +4,7 @@ #include "NodeDB.h" #include "configuration.h" #include "modules/RoutingModule.h" +#include #include std::vector *MeshModule::modules; @@ -29,7 +30,9 @@ void MeshModule::setup() {} MeshModule::~MeshModule() { - assert(0); // FIXME - remove from list of modules once someone needs this feature + auto it = std::find(modules->begin(), modules->end(), this); + assert(it != modules->end()); + modules->erase(it); } meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, From 183f68ba0005e9bfeb4423681693b225d28a5f6d Mon Sep 17 00:00:00 2001 From: Eric Severance Date: Wed, 1 Jan 2025 17:26:12 -0800 Subject: [PATCH 17/25] Run tests as part of the main CI (#5712) * Create an shared action to install native dependecies * Create a workflow for running native tests * Artifact names contain version * Add test-native to main_matrix.yml * No permission are required for test_native.yml * Add permissions for dorny/test-reporter * No permissions when running tests * s/Generate Reports/Generate Test Reports/ --- .github/actions/setup-native/action.yml | 14 +++ .github/workflows/build_native.yml | 20 +--- .github/workflows/main_matrix.yml | 3 + .github/workflows/test_native.yml | 153 ++++++++++++++++++++++++ .github/workflows/tests.yml | 75 +----------- 5 files changed, 175 insertions(+), 90 deletions(-) create mode 100644 .github/actions/setup-native/action.yml create mode 100644 .github/workflows/test_native.yml diff --git a/.github/actions/setup-native/action.yml b/.github/actions/setup-native/action.yml new file mode 100644 index 000000000..36c95d943 --- /dev/null +++ b/.github/actions/setup-native/action.yml @@ -0,0 +1,14 @@ +name: Setup native build +description: Install libraries needed for building the Native/Portduino build + +runs: + using: composite + steps: + - name: Setup base + id: base + uses: ./.github/actions/setup-base + + - name: Install libs needed for native build + shell: bash + run: | + sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml index 74bc074aa..11ba09ad7 100644 --- a/.github/workflows/build_native.yml +++ b/.github/workflows/build_native.yml @@ -10,12 +10,6 @@ jobs: build-native: runs-on: ubuntu-latest steps: - - name: Install libs needed for native build - shell: bash - run: | - sudo apt-get update --fix-missing - sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev - - name: Checkout code uses: actions/checkout@v4 with: @@ -23,17 +17,9 @@ jobs: ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} - - name: Upgrade python tools - shell: bash - run: | - python -m pip install --upgrade pip - pip install -U platformio adafruit-nrfutil - pip install -U meshtastic --pre - - - name: Upgrade platformio - shell: bash - run: | - pio upgrade + - name: Setup native build + id: base + uses: ./.github/actions/setup-native - name: Build Native run: bin/build-native.sh diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 0109bef1a..a437411b5 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -137,6 +137,9 @@ jobs: package-native: uses: ./.github/workflows/package_amd64.yml + test-native: + uses: ./.github/workflows/test_native.yml + build-docker: if: ${{ github.event_name == 'workflow_dispatch' }} uses: ./.github/workflows/build_docker.yml diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml new file mode 100644 index 000000000..8fe4e1c03 --- /dev/null +++ b/.github/workflows/test_native.yml @@ -0,0 +1,153 @@ +name: Run Tests on Native platform + +on: + workflow_call: + workflow_dispatch: + +permissions: {} + +env: + LCOV_CAPTURE_FLAGS: --quiet --capture --include "${PWD}/src/*" --exclude '*/src/mesh/generated/*' --directory .pio/build/coverage/src --base-directory "${PWD}" + +jobs: + simulator-tests: + name: Native Simulator Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup native build + id: base + uses: ./.github/actions/setup-native + + - name: Install simulator dependencies + run: pip install -U dotmap + + # We now run integration test before other build steps (to quickly see runtime failures) + - name: Build for native/coverage + run: platformio run -e coverage + + - name: Capture initial coverage information + shell: bash + run: | + sudo apt-get install -y lcov + lcov ${{ env.LCOV_CAPTURE_FLAGS }} --initial --output-file coverage_base.info + + - name: Integration test + run: | + .pio/build/coverage/program & + PID=$! + timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done" + echo "Simulator started, launching python test..." + python3 -c 'from meshtastic.test import testSimulator; testSimulator()' + wait + + - name: Capture coverage information + if: always() # run this step even if previous step failed + run: lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info + + - name: Get release version string + if: always() # run this step even if previous step failed + run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + + - name: Save coverage information + uses: actions/upload-artifact@v4 + if: always() # run this step even if previous step failed + with: + name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.version }}.zip + overwrite: true + path: ./coverage_*.info + + platformio-tests: + name: Native PlatformIO Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup native build + id: base + uses: ./.github/actions/setup-native + + - name: Get release version string + run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + + - name: PlatformIO Tests + run: platformio test -e coverage --junit-output-path testreport.xml + + - name: Save test results + if: always() # run this step even if previous step failed + uses: actions/upload-artifact@v4 + with: + name: platformio-test-report-${{ steps.version.outputs.version }}.zip + overwrite: true + path: ./testreport.xml + + - name: Capture coverage information + if: always() # run this step even if previous step failed + run: | + sudo apt-get install -y lcov + lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name tests --output-file coverage_tests.info + + - name: Save coverage information + uses: actions/upload-artifact@v4 + if: always() # run this step even if previous step failed + with: + name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.version }}.zip + overwrite: true + path: ./coverage_*.info + + generate-reports: + name: Generate Test Reports + runs-on: ubuntu-latest + permissions: # Needed for dorny/test-reporter. + contents: read + actions: read + checks: write + needs: + - simulator-tests + - platformio-tests + if: always() + steps: + - uses: actions/checkout@v4 + + - name: Get release version string + run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + + - name: Download test artifacts + uses: actions/download-artifact@v4 + with: + name: platformio-test-report-${{ steps.version.outputs.version }}.zip + merge-multiple: true + + - name: Test Report + uses: dorny/test-reporter@v1.9.1 + with: + name: PlatformIO Tests + path: testreport.xml + reporter: java-junit + + - name: Download coverage artifacts + uses: actions/download-artifact@v4 + with: + pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.version }}.zip + path: code-coverage-report + merge-multiple: true + + - name: Generate Code Coverage Report + run: | + sudo apt-get install -y lcov + lcov --quiet --add-tracefile code-coverage-report/coverage_base.info --add-tracefile code-coverage-report/coverage_integration.info --add-tracefile code-coverage-report/coverage_tests.info --output-file code-coverage-report/coverage_src.info + genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report + + - name: Save Code Coverage Report + uses: actions/upload-artifact@v4 + with: + name: code-coverage-report-${{ steps.version.outputs.version }}.zip + path: code-coverage-report diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ae9f82543..c9489db1a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,79 +6,8 @@ on: workflow_dispatch: {} jobs: - test-simulator: - runs-on: ubuntu-latest - env: - LCOV_CAPTURE_FLAGS: --quiet --capture --include "${PWD}/src/*" --exclude '*/src/mesh/generated/*' --directory .pio/build/coverage/src --base-directory "${PWD}" - steps: - - name: Install libs needed for native build - shell: bash - run: | - sudo apt-get update --fix-missing - sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev - sudo apt-get install -y lcov - - - name: Checkout code - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Upgrade python tools - shell: bash - run: | - python -m pip install --upgrade pip - pip install -U platformio adafruit-nrfutil dotmap - pip install -U meshtastic --pre - - - name: Upgrade platformio - shell: bash - run: | - pio upgrade - - - name: Build Native - run: bin/build-native.sh - - # We now run integration test before other build steps (to quickly see runtime failures) - - name: Build for native/coverage - run: | - platformio run -e coverage - lcov ${{ env.LCOV_CAPTURE_FLAGS }} --initial --output-file coverage_base.info - - - name: Integration test - run: | - .pio/build/coverage/program & - PID=$! - timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done" - echo "Simulator started, launching python test..." - python3 -c 'from meshtastic.test import testSimulator; testSimulator()' - wait - lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info - - - name: PlatformIO Tests - run: | - platformio test -e coverage --junit-output-path testreport.xml - lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name tests --output-file coverage_tests.info - - - name: Test Report - uses: dorny/test-reporter@v1.9.1 - if: success() || failure() # run this step even if previous step failed - with: - name: PlatformIO Tests - path: testreport.xml - reporter: java-junit - - - name: Generate Code Coverage Report - run: | - lcov --quiet --add-tracefile coverage_base.info --add-tracefile coverage_integration.info --add-tracefile coverage_tests.info --output-file coverage_src.info - mkdir code-coverage-report - genhtml --quiet --legend --prefix "${PWD}" coverage_src.info --output-directory code-coverage-report - mv coverage_*.info code-coverage-report - - - name: Save Code Coverage Report - uses: actions/upload-artifact@v4 - with: - name: code-coverage-report - path: code-coverage-report + native-tests: + uses: ./.github/workflows/test_native.yml hardware-tests: runs-on: test-runner From 88d8ab53c8fba2830a71c9c0131b990d0f0f4e64 Mon Sep 17 00:00:00 2001 From: Eric Severance Date: Wed, 1 Jan 2025 19:37:11 -0800 Subject: [PATCH 18/25] Disable coverage generation (#5719) * Disable coverage generation * Comment a bit more of the report generation --- .github/workflows/test_native.yml | 54 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 8fe4e1c03..9de3b34a6 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -120,34 +120,34 @@ jobs: run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT id: version - - name: Download test artifacts - uses: actions/download-artifact@v4 - with: - name: platformio-test-report-${{ steps.version.outputs.version }}.zip - merge-multiple: true + # - name: Download test artifacts + # uses: actions/download-artifact@v4 + # with: + # name: platformio-test-report-${{ steps.version.outputs.version }}.zip + # merge-multiple: true - - name: Test Report - uses: dorny/test-reporter@v1.9.1 - with: - name: PlatformIO Tests - path: testreport.xml - reporter: java-junit + # - name: Test Report + # uses: dorny/test-reporter@v1.9.1 + # with: + # name: PlatformIO Tests + # path: testreport.xml + # reporter: java-junit - - name: Download coverage artifacts - uses: actions/download-artifact@v4 - with: - pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.version }}.zip - path: code-coverage-report - merge-multiple: true + # - name: Download coverage artifacts + # uses: actions/download-artifact@v4 + # with: + # pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.version }}.zip + # path: code-coverage-report + # merge-multiple: true - - name: Generate Code Coverage Report - run: | - sudo apt-get install -y lcov - lcov --quiet --add-tracefile code-coverage-report/coverage_base.info --add-tracefile code-coverage-report/coverage_integration.info --add-tracefile code-coverage-report/coverage_tests.info --output-file code-coverage-report/coverage_src.info - genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report + # - name: Generate Code Coverage Report + # run: | + # sudo apt-get install -y lcov + # lcov --quiet --add-tracefile code-coverage-report/coverage_base.info --add-tracefile code-coverage-report/coverage_integration.info --add-tracefile code-coverage-report/coverage_tests.info --output-file code-coverage-report/coverage_src.info + # genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report - - name: Save Code Coverage Report - uses: actions/upload-artifact@v4 - with: - name: code-coverage-report-${{ steps.version.outputs.version }}.zip - path: code-coverage-report + # - name: Save Code Coverage Report + # uses: actions/upload-artifact@v4 + # with: + # name: code-coverage-report-${{ steps.version.outputs.version }}.zip + # path: code-coverage-report From 7a1c32b89aa348871ff2e97ebf7a618f8274309e Mon Sep 17 00:00:00 2001 From: Eric Severance Date: Wed, 1 Jan 2025 20:41:13 -0800 Subject: [PATCH 19/25] test_native.yaml checks out code for the PR. (#5720) --- .github/workflows/test_native.yml | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 9de3b34a6..1cc1f7c40 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -16,6 +16,8 @@ jobs: steps: - uses: actions/checkout@v4 with: + ref: ${{github.event.pull_request.head.ref}} + repository: ${{github.event.pull_request.head.repo.full_name}} submodules: recursive - name: Setup native build @@ -67,6 +69,8 @@ jobs: steps: - uses: actions/checkout@v4 with: + ref: ${{github.event.pull_request.head.ref}} + repository: ${{github.event.pull_request.head.repo.full_name}} submodules: recursive - name: Setup native build @@ -115,23 +119,26 @@ jobs: if: always() steps: - uses: actions/checkout@v4 + with: + ref: ${{github.event.pull_request.head.ref}} + repository: ${{github.event.pull_request.head.repo.full_name}} - name: Get release version string run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT id: version - # - name: Download test artifacts - # uses: actions/download-artifact@v4 - # with: - # name: platformio-test-report-${{ steps.version.outputs.version }}.zip - # merge-multiple: true + - name: Download test artifacts + uses: actions/download-artifact@v4 + with: + name: platformio-test-report-${{ steps.version.outputs.version }}.zip + merge-multiple: true - # - name: Test Report - # uses: dorny/test-reporter@v1.9.1 - # with: - # name: PlatformIO Tests - # path: testreport.xml - # reporter: java-junit + - name: Test Report + uses: dorny/test-reporter@v1.9.1 + with: + name: PlatformIO Tests + path: testreport.xml + reporter: java-junit # - name: Download coverage artifacts # uses: actions/download-artifact@v4 From 93e2bc7058ba0d0b7b3936590b5c185bc418fba9 Mon Sep 17 00:00:00 2001 From: Eric Severance Date: Wed, 1 Jan 2025 22:53:07 -0800 Subject: [PATCH 20/25] Use relative paths in coverage info files (#5721) --- .github/workflows/test_native.yml | 38 +++++++++++++++++-------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 1cc1f7c40..8c1527279 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -36,6 +36,7 @@ jobs: run: | sudo apt-get install -y lcov lcov ${{ env.LCOV_CAPTURE_FLAGS }} --initial --output-file coverage_base.info + sed -i -e "s#${PWD}#.#" coverage_base.info # Make paths relative. - name: Integration test run: | @@ -48,7 +49,9 @@ jobs: - name: Capture coverage information if: always() # run this step even if previous step failed - run: lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info + run: | + lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info + sed -i -e "s#${PWD}#.#" coverage_integration.info # Make paths relative. - name: Get release version string if: always() # run this step even if previous step failed @@ -97,6 +100,7 @@ jobs: run: | sudo apt-get install -y lcov lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name tests --output-file coverage_tests.info + sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative. - name: Save coverage information uses: actions/upload-artifact@v4 @@ -140,21 +144,21 @@ jobs: path: testreport.xml reporter: java-junit - # - name: Download coverage artifacts - # uses: actions/download-artifact@v4 - # with: - # pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.version }}.zip - # path: code-coverage-report - # merge-multiple: true + - name: Download coverage artifacts + uses: actions/download-artifact@v4 + with: + pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.version }}.zip + path: code-coverage-report + merge-multiple: true - # - name: Generate Code Coverage Report - # run: | - # sudo apt-get install -y lcov - # lcov --quiet --add-tracefile code-coverage-report/coverage_base.info --add-tracefile code-coverage-report/coverage_integration.info --add-tracefile code-coverage-report/coverage_tests.info --output-file code-coverage-report/coverage_src.info - # genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report + - name: Generate Code Coverage Report + run: | + sudo apt-get install -y lcov + lcov --quiet --add-tracefile code-coverage-report/coverage_base.info --add-tracefile code-coverage-report/coverage_integration.info --add-tracefile code-coverage-report/coverage_tests.info --output-file code-coverage-report/coverage_src.info + genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report - # - name: Save Code Coverage Report - # uses: actions/upload-artifact@v4 - # with: - # name: code-coverage-report-${{ steps.version.outputs.version }}.zip - # path: code-coverage-report + - name: Save Code Coverage Report + uses: actions/upload-artifact@v4 + with: + name: code-coverage-report-${{ steps.version.outputs.version }}.zip + path: code-coverage-report From 9f7cbf1b4fe61979c5e98f9affb1d801af7147c8 Mon Sep 17 00:00:00 2001 From: Eric Severance Date: Thu, 2 Jan 2025 03:32:39 -0800 Subject: [PATCH 21/25] MQTT unit test can inject WiFiClient (#5716) --- src/mqtt/MQTT.cpp | 12 +++++++----- src/mqtt/MQTT.h | 40 +++++++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 5141af560..46fb607b5 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -282,7 +282,9 @@ void mqttInit() } #if HAS_NETWORKING -MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE) +MQTT::MQTT() : MQTT(std::unique_ptr(new MQTTClient())) {} +MQTT::MQTT(std::unique_ptr _mqttClient) + : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE), mqttClient(std::move(_mqttClient)), pubSub(*mqttClient) #else MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) #endif @@ -420,13 +422,13 @@ void MQTT::reconnect() } } else { LOG_INFO("Use non-TLS-encrypted session"); - pubSub.setClient(mqttClient); + pubSub.setClient(*mqttClient); } #else - pubSub.setClient(mqttClient); + pubSub.setClient(*mqttClient); #endif #elif HAS_NETWORKING - pubSub.setClient(mqttClient); + pubSub.setClient(*mqttClient); #endif std::pair hostAndPort = parseHostAndPort(serverAddr, serverPort); @@ -444,7 +446,7 @@ void MQTT::reconnect() enabled = true; // Start running background process again runASAP = true; reconnectCount = 0; - isMqttServerAddressPrivate = isPrivateIpAddress(mqttClient.remoteIP()); + isMqttServerAddressPrivate = isPrivateIpAddress(mqttClient->remoteIP()); publishNodeInfo(); sendSubscriptions(); diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index cb1fffcc9..cf52ad877 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -22,6 +22,7 @@ #if HAS_NETWORKING #include +#include #endif #define MAX_MQTT_QUEUE 16 @@ -32,24 +33,7 @@ */ class MQTT : private concurrency::OSThread { - // supposedly the current version is busted: - // http://www.iotsharing.com/2017/08/how-to-use-esp32-mqtts-with-mqtts-mosquitto-broker-tls-ssl.html -#if HAS_WIFI - WiFiClient mqttClient; -#if !defined(ARCH_PORTDUINO) -#if (defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3) || defined(RPI_PICO) - WiFiClientSecure wifiSecureClient; -#endif -#endif -#endif -#if HAS_ETHERNET - EthernetClient mqttClient; -#endif - public: -#if HAS_NETWORKING - PubSubClient pubSub; -#endif MQTT(); /** @@ -93,7 +77,29 @@ class MQTT : private concurrency::OSThread virtual int32_t runOnce() override; +#ifndef PIO_UNIT_TESTING private: +#endif + // supposedly the current version is busted: + // http://www.iotsharing.com/2017/08/how-to-use-esp32-mqtts-with-mqtts-mosquitto-broker-tls-ssl.html +#if HAS_WIFI + using MQTTClient = WiFiClient; +#if !defined(ARCH_PORTDUINO) +#if (defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3) || defined(RPI_PICO) + WiFiClientSecure wifiSecureClient; +#endif +#endif +#endif +#if HAS_ETHERNET + using MQTTClient = EthernetClient; +#endif + +#if HAS_NETWORKING + std::unique_ptr mqttClient; + PubSubClient pubSub; + explicit MQTT(std::unique_ptr mqttClient); +#endif + std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID std::string mapTopic = "/2/map/"; // For protobuf-encoded MapReport messages From 9bda080e3d0be0f025f88d36bb4a9aa605954fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 2 Jan 2025 16:05:12 +0100 Subject: [PATCH 22/25] evaluate GPS_THREAD_INTERVAL after variant file (#5722) --- src/configuration.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index 994f1e72e..2c77b55e3 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -178,13 +178,6 @@ along with this program. If not, see . #define TCA9535_ADDR 0x20 #define TCA9555_ADDR 0x26 -// ----------------------------------------------------------------------------- -// GPS -// ----------------------------------------------------------------------------- -#ifndef GPS_THREAD_INTERVAL -#define GPS_THREAD_INTERVAL 200 -#endif - // ----------------------------------------------------------------------------- // Touchscreen // ----------------------------------------------------------------------------- @@ -206,6 +199,10 @@ along with this program. If not, see . #define VEXT_ON_VALUE LOW #endif +// ----------------------------------------------------------------------------- +// GPS +// ----------------------------------------------------------------------------- + #ifndef GPS_BAUDRATE #define GPS_BAUDRATE 9600 #define GPS_BAUDRATE_FIXED 0 @@ -213,6 +210,10 @@ along with this program. If not, see . #define GPS_BAUDRATE_FIXED 1 #endif +#ifndef GPS_THREAD_INTERVAL +#define GPS_THREAD_INTERVAL 200 +#endif + /* Step #2: follow with defines common to the architecture; also enable HAS_ option not specifically disabled by variant.h */ #include "architecture.h" From b41efc17ba60a0f4b93cf85fe0c1b08070aeb67e Mon Sep 17 00:00:00 2001 From: Eric Severance Date: Thu, 2 Jan 2025 08:32:38 -0800 Subject: [PATCH 23/25] Disable BUILD_EPOCH for unit tests (#5723) --- .github/workflows/test_native.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 8c1527279..d016635ef 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -84,6 +84,11 @@ jobs: run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT id: version + # Disable (comment-out) BUILD_EPOCH. It causes a full rebuild between tests and resets the + # coverage information each time. + - name: Disable BUILD_EPOCH + run: sed -i 's/-DBUILD_EPOCH=$UNIX_TIME/#-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini + - name: PlatformIO Tests run: platformio test -e coverage --junit-output-path testreport.xml From 9d710041c43af266dc0e32703e39775bb1f4929e Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Fri, 3 Jan 2025 09:01:10 +0800 Subject: [PATCH 24/25] Add MESHTASTIC_EXCLUDE_SOCKETAPI (#5729) MESHTASTIC_EXCLUDE_SOCKETAPI disables the API Server when set. Co-authored-by: mverch67 Co-authored-by: GUVWAF --- src/mesh/eth/ethClient.cpp | 3 ++- src/mesh/wifi/WiFiAPClient.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 08ecb7ce8..24c4f0db1 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -66,8 +66,9 @@ static int32_t reconnectETH() syslog.enable(); } - // initWebServer(); +#if !MESHTASTIC_EXCLUDE_SOCKETAPI initApiServer(); +#endif ethStartupComplete = true; } diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index 38aa2e2a2..2f8138921 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -106,7 +106,9 @@ static void onNetworkConnected() #if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WEBSERVER initWebServer(); #endif +#if !MESHTASTIC_EXCLUDE_SOCKETAPI initApiServer(); +#endif APStartupComplete = true; } From e1aaafb77a9f6e0bc159242de24b9b3cbb9e1782 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Fri, 3 Jan 2025 10:05:26 +0800 Subject: [PATCH 25/25] Cherrypick "add more locking for shared SPI devices (#5595) " (#5728) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add more locking for shared SPI devices (#5595) * add more locking for shared SPI devices * call initSPI before the lock is used * remove old one * don't double lock * Add missing unlock * More missing unlocks * Add locks to SafeFile, remove from `readcb`, introduce some LockGuards * fix lock in setupSDCard() * pull radiolib trunk with SPI-CS fixes * change ContentHandler to Constructor type locks, where applicable --------- Co-authored-by: mverch67 Co-authored-by: GUVWAF Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com> * mesh-tab: lower I2C touch frequency --------- Co-authored-by: Thomas Göttgens Co-authored-by: mverch67 Co-authored-by: GUVWAF Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com> --- platformio.ini | 3 ++- src/FSCommon.cpp | 21 ++++++++++++++-- src/SafeFile.cpp | 15 ++++++++---- src/SafeFile.h | 1 + src/main.cpp | 4 ++-- src/mesh/NodeDB.cpp | 22 +++++++++++++---- src/mesh/PhoneAPI.cpp | 3 +++ src/mesh/http/ContentHandler.cpp | 15 ++++++++++++ src/mesh/mesh-pb-constants.cpp | 8 +++++-- src/modules/AdminModule.cpp | 4 ++++ src/modules/CannedMessageModule.cpp | 7 ++++-- src/modules/RangeTestModule.cpp | 2 ++ src/modules/Telemetry/Sensor/BME680Sensor.cpp | 5 ++++ .../Telemetry/Sensor/NAU7802Sensor.cpp | 7 +++++- src/xmodem.cpp | 24 +++++++++++++++++++ variants/mesh-tab/platformio.ini | 6 ++--- 16 files changed, 125 insertions(+), 22 deletions(-) diff --git a/platformio.ini b/platformio.ini index 3129decaa..cd32ed179 100644 --- a/platformio.ini +++ b/platformio.ini @@ -124,7 +124,8 @@ lib_deps = [radiolib_base] lib_deps = - jgromes/RadioLib@7.1.0 + ; jgromes/RadioLib@7.1.0 + https://github.com/jgromes/RadioLib.git#92b687821ff4e6c358d866f84566f66672ab02b8 ; Common libs for environmental measurements in telemetry module ; (not included in native / portduino) diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index df46c1941..6d8ff835c 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -9,6 +9,7 @@ * */ #include "FSCommon.h" +#include "SPILock.h" #include "configuration.h" #ifdef HAS_SDCARD @@ -102,6 +103,8 @@ bool copyFile(const char *from, const char *to) return true; #elif defined(FSCom) + // take SPI Lock + concurrency::LockGuard g(spiLock); unsigned char cbuffer[16]; File f1 = FSCom.open(from, FILE_O_READ); @@ -145,16 +148,23 @@ bool renameFile(const char *pathFrom, const char *pathTo) return false; } #elif defined(FSCom) + #ifdef ARCH_ESP32 + // take SPI Lock + spiLock->lock(); // rename was fixed for ESP32 IDF LittleFS in April - return FSCom.rename(pathFrom, pathTo); + bool result = FSCom.rename(pathFrom, pathTo); + spiLock->unlock(); + return result; #else + // copyFile does its own locking. if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom)) { return true; } else { return false; } #endif + #endif } @@ -164,6 +174,7 @@ bool renameFile(const char *pathFrom, const char *pathTo) * @brief Get the list of files in a directory. * * This function returns a list of files in a directory. The list includes the full path of each file. + * We can't use SPILOCK here because of recursion. Callers of this function should use SPILOCK. * * @param dirname The name of the directory. * @param levels The number of levels of subdirectories to list. @@ -212,6 +223,7 @@ std::vector getFiles(const char *dirname, uint8_t levels) /** * Lists the contents of a directory. + * We can't use SPILOCK here because of recursion. Callers of this function should use SPILOCK. * * @param dirname The name of the directory to list. * @param levels The number of levels of subdirectories to list. @@ -325,18 +337,21 @@ void listDir(const char *dirname, uint8_t levels, bool del) void rmDir(const char *dirname) { #ifdef FSCom + #if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)) listDir(dirname, 10, true); #elif defined(ARCH_NRF52) // nRF52 implementation of LittleFS has a recursive delete function FSCom.rmdir_r(dirname); #endif + #endif } void fsInit() { #ifdef FSCom + spiLock->lock(); if (!FSBegin()) { LOG_ERROR("Filesystem mount failed"); // assert(0); This auto-formats the partition, so no need to fail here. @@ -347,6 +362,7 @@ void fsInit() LOG_DEBUG("Filesystem files:"); #endif listDir("/", 10); + spiLock->unlock(); #endif } @@ -356,6 +372,7 @@ void fsInit() void setupSDCard() { #ifdef HAS_SDCARD + concurrency::LockGuard g(spiLock); SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI); if (!SD.begin(SDCARD_CS, SDHandler)) { @@ -383,4 +400,4 @@ void setupSDCard() LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024))); LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024))); #endif -} \ No newline at end of file +} diff --git a/src/SafeFile.cpp b/src/SafeFile.cpp index c76ff8054..c5d7b335e 100644 --- a/src/SafeFile.cpp +++ b/src/SafeFile.cpp @@ -5,6 +5,7 @@ // Only way to work on both esp32 and nrf52 static File openFile(const char *filename, bool fullAtomic) { + concurrency::LockGuard g(spiLock); if (!fullAtomic) FSCom.remove(filename); // Nuke the old file to make space (ignore if it !exists) @@ -53,14 +54,19 @@ bool SafeFile::close() if (!f) return false; + spiLock->lock(); f.close(); + spiLock->unlock(); if (!testReadback()) return false; - // brief window of risk here ;-) - if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) { - LOG_ERROR("Can't remove old pref file"); - return false; + { // Scope for lock + concurrency::LockGuard g(spiLock); + // brief window of risk here ;-) + if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) { + LOG_ERROR("Can't remove old pref file"); + return false; + } } String filenameTmp = filename; @@ -76,6 +82,7 @@ bool SafeFile::close() /// Read our (closed) tempfile back in and compare the hash bool SafeFile::testReadback() { + concurrency::LockGuard g(spiLock); bool lfs_failed = lfs_assert_failed; lfs_assert_failed = false; diff --git a/src/SafeFile.h b/src/SafeFile.h index 61361d312..3d0f81cad 100644 --- a/src/SafeFile.h +++ b/src/SafeFile.h @@ -1,6 +1,7 @@ #pragma once #include "FSCommon.h" +#include "SPILock.h" #include "configuration.h" #ifdef FSCom diff --git a/src/main.cpp b/src/main.cpp index 5982e709d..c2b20b1c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -364,6 +364,8 @@ void setup() #endif #endif + initSPI(); + OSThread::setup(); ledPeriodic = new Periodic("Blink", ledBlinker); @@ -640,8 +642,6 @@ void setup() rp2040Setup(); #endif - initSPI(); // needed here before reading from littleFS - // We do this as early as possible because this loads preferences from flash // but we need to do this after main cpu init (esp32setup), because we need the random seed set nodeDB = new NodeDB; diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index bbc9eb1ea..8e084c99d 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -13,6 +13,7 @@ #include "PowerFSM.h" #include "RTC.h" #include "Router.h" +#include "SPILock.h" #include "SafeFile.h" #include "TypeConversions.h" #include "error.h" @@ -423,12 +424,15 @@ bool NodeDB::factoryReset(bool eraseBleBonds) { LOG_INFO("Perform factory reset!"); // first, remove the "/prefs" (this removes most prefs) - rmDir("/prefs"); + spiLock->lock(); + rmDir("/prefs"); // this uses spilock internally... + #ifdef FSCom if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) { LOG_ERROR("Could not remove rangetest.csv file"); } #endif + spiLock->unlock(); // second, install default state (this will deal with the duplicate mac address issue) installDefaultDeviceState(); installDefaultConfig(!eraseBleBonds); // Also preserve the private key if we're not erasing BLE bonds @@ -913,6 +917,7 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t { LoadFileResult state = LoadFileResult::OTHER_FAILURE; #ifdef FSCom + concurrency::LockGuard g(spiLock); auto f = FSCom.open(filename, FILE_O_READ); @@ -946,8 +951,10 @@ void NodeDB::loadFromDisk() // disk we will still factoryReset to restore things. #ifdef ARCH_ESP32 + spiLock->lock(); if (FSCom.exists("/static/static")) rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release + spiLock->unlock(); #endif // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM @@ -1097,9 +1104,6 @@ void NodeDB::loadFromDisk() bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct, bool fullAtomic) { -#ifdef ARCH_ESP32 - concurrency::LockGuard g(spiLock); -#endif bool okay = false; #ifdef FSCom auto f = SafeFile(filename, fullAtomic); @@ -1127,7 +1131,9 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_ bool NodeDB::saveChannelsToDisk() { #ifdef FSCom + spiLock->lock(); FSCom.mkdir("/prefs"); + spiLock->unlock(); #endif return saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile); } @@ -1135,7 +1141,9 @@ bool NodeDB::saveChannelsToDisk() bool NodeDB::saveDeviceStateToDisk() { #ifdef FSCom + spiLock->lock(); FSCom.mkdir("/prefs"); + spiLock->unlock(); #endif // Note: if MAX_NUM_NODES=100 and meshtastic_NodeInfoLite_size=166, so will be approximately 17KB // Because so huge we _must_ not use fullAtomic, because the filesystem is probably too small to hold two copies of this @@ -1148,7 +1156,9 @@ bool NodeDB::saveToDiskNoRetry(int saveWhat) bool success = true; #ifdef FSCom + spiLock->lock(); FSCom.mkdir("/prefs"); + spiLock->unlock(); #endif if (saveWhat & SEGMENT_CONFIG) { config.has_device = true; @@ -1199,7 +1209,9 @@ bool NodeDB::saveToDisk(int saveWhat) if (!success) { LOG_ERROR("Failed to save to disk, retrying"); #ifdef ARCH_NRF52 // @geeksville is not ready yet to say we should do this on other platforms. See bug #4184 discussion + spiLock->lock(); FSCom.format(); + spiLock->unlock(); #endif success = saveToDiskNoRetry(saveWhat); @@ -1518,4 +1530,4 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co LOG_ERROR("A critical failure occurred, portduino is exiting"); exit(2); #endif -} +} \ No newline at end of file diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 8c1ba74c7..6789acbb3 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -12,6 +12,7 @@ #include "PhoneAPI.h" #include "PowerFSM.h" #include "RadioInterface.h" +#include "SPILock.h" #include "TypeConversions.h" #include "main.h" #include "xmodem.h" @@ -54,7 +55,9 @@ void PhoneAPI::handleStartConfig() // even if we were already connected - restart our state machine state = STATE_SEND_MY_INFO; pauseBluetoothLogging = true; + spiLock->lock(); filesManifest = getFiles("/", 10); + spiLock->unlock(); LOG_DEBUG("Got %d files in manifest", filesManifest.size()); LOG_INFO("Start API client config"); diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index aa8a68f91..5841fe478 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -10,6 +10,7 @@ #include "mesh/wifi/WiFiAPClient.h" #endif #include "Led.h" +#include "SPILock.h" #include "power.h" #include "serialization/JSON.h" #include @@ -236,6 +237,7 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res) void htmlDeleteDir(const char *dirname) { + File root = FSCom.open(dirname); if (!root) { return; @@ -318,6 +320,7 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res) res->setHeader("Access-Control-Allow-Origin", "*"); res->setHeader("Access-Control-Allow-Methods", "GET"); + concurrency::LockGuard g(spiLock); auto fileList = htmlListDir("/static", 10); // create json output structure @@ -349,9 +352,12 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res) res->setHeader("Content-Type", "application/json"); res->setHeader("Access-Control-Allow-Origin", "*"); res->setHeader("Access-Control-Allow-Methods", "DELETE"); + if (params->getQueryParameter("delete", paramValDelete)) { std::string pathDelete = "/" + paramValDelete; + concurrency::LockGuard g(spiLock); if (FSCom.remove(pathDelete.c_str())) { + LOG_INFO("%s", pathDelete.c_str()); JSONObject jsonObjOuter; jsonObjOuter["status"] = new JSONValue("ok"); @@ -360,6 +366,7 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res) delete value; return; } else { + LOG_INFO("%s", pathDelete.c_str()); JSONObject jsonObjOuter; jsonObjOuter["status"] = new JSONValue("Error"); @@ -393,6 +400,8 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res) filenameGzip = "/static/index.html.gz"; } + concurrency::LockGuard g(spiLock); + if (FSCom.exists(filename.c_str())) { file = FSCom.open(filename.c_str()); if (!file.available()) { @@ -410,6 +419,7 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res) file = FSCom.open(filenameGzip.c_str()); res->setHeader("Content-Type", "text/html"); if (!file.available()) { + LOG_WARN("File not available - %s", filenameGzip.c_str()); res->println("Web server is running.

The content you are looking for can't be found. Please see: FAQ.

printf("

Saved %d bytes to %s

", (int)fileLength, pathname.c_str()); } if (!didwrite) { @@ -642,9 +654,11 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) jsonObjMemory["heap_free"] = new JSONValue((int)memGet.getFreeHeap()); jsonObjMemory["psram_total"] = new JSONValue((int)memGet.getPsramSize()); jsonObjMemory["psram_free"] = new JSONValue((int)memGet.getFreePsram()); + spiLock->lock(); jsonObjMemory["fs_total"] = new JSONValue((int)FSCom.totalBytes()); jsonObjMemory["fs_used"] = new JSONValue((int)FSCom.usedBytes()); jsonObjMemory["fs_free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes())); + spiLock->unlock(); // data->power JSONObject jsonObjPower; @@ -786,6 +800,7 @@ void handleDeleteFsContent(HTTPRequest *req, HTTPResponse *res) LOG_INFO("Delete files from /static/* : "); + concurrency::LockGuard g(spiLock); htmlDeleteDir("/static"); res->println("


Back to admin"); diff --git a/src/mesh/mesh-pb-constants.cpp b/src/mesh/mesh-pb-constants.cpp index deb93d0a6..a8f4fd6d8 100644 --- a/src/mesh/mesh-pb-constants.cpp +++ b/src/mesh/mesh-pb-constants.cpp @@ -1,6 +1,7 @@ #include "configuration.h" #include "FSCommon.h" +#include "SPILock.h" #include "mesh-pb-constants.h" #include #include @@ -55,9 +56,12 @@ bool readcb(pb_istream_t *stream, uint8_t *buf, size_t count) /// Write to an arduino file bool writecb(pb_ostream_t *stream, const uint8_t *buf, size_t count) { + spiLock->lock(); auto file = (Print *)stream->state; // LOG_DEBUG("writing %d bytes to protobuf file", count); - return file->write(buf, count) == count; + bool status = file->write(buf, count) == count; + spiLock->unlock(); + return status; } #endif @@ -68,4 +72,4 @@ bool is_in_helper(uint32_t n, const uint32_t *array, pb_size_t count) return true; return false; -} +} \ No newline at end of file diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index fc3b914e5..7906b410b 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -4,6 +4,7 @@ #include "NodeDB.h" #include "PowerFSM.h" #include "RTC.h" +#include "SPILock.h" #include "meshUtils.h" #include #if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH @@ -358,12 +359,15 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta } case meshtastic_AdminMessage_delete_file_request_tag: { LOG_DEBUG("Client requesting to delete file: %s", r->delete_file_request); + #ifdef FSCom + spiLock->lock(); if (FSCom.remove(r->delete_file_request)) { LOG_DEBUG("Successfully deleted file"); } else { LOG_DEBUG("Failed to delete file"); } + spiLock->unlock(); #endif break; } diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index c20b7b56e..5fb32fff5 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -9,6 +9,7 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" // needed for button bypass +#include "SPILock.h" #include "detect/ScanI2C.h" #include "input/ScanAndSelect.h" #include "mesh/generated/meshtastic/cannedmessages.pb.h" @@ -1184,8 +1185,10 @@ bool CannedMessageModule::saveProtoForModule() { bool okay = true; -#ifdef FS - FS.mkdir("/prefs"); +#ifdef FSCom + spiLock->lock(); + FSCom.mkdir("/prefs"); + spiLock->unlock(); #endif okay &= nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, diff --git a/src/modules/RangeTestModule.cpp b/src/modules/RangeTestModule.cpp index c42839d97..cad1d51f1 100644 --- a/src/modules/RangeTestModule.cpp +++ b/src/modules/RangeTestModule.cpp @@ -15,6 +15,7 @@ #include "PowerFSM.h" #include "RTC.h" #include "Router.h" +#include "SPILock.h" #include "airtime.h" #include "configuration.h" #include "gps/GeoCoord.h" @@ -205,6 +206,7 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp) LOG_DEBUG("gpsStatus->getDOP() %d", gpsStatus->getDOP()); LOG_DEBUG("-----------------------------------------"); */ + concurrency::LockGuard g(spiLock); if (!FSBegin()) { LOG_DEBUG("An Error has occurred while mounting the filesystem"); return 0; diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.cpp b/src/modules/Telemetry/Sensor/BME680Sensor.cpp index 18515d0a8..9237cf0c9 100644 --- a/src/modules/Telemetry/Sensor/BME680Sensor.cpp +++ b/src/modules/Telemetry/Sensor/BME680Sensor.cpp @@ -5,6 +5,7 @@ #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "BME680Sensor.h" #include "FSCommon.h" +#include "SPILock.h" #include "TelemetrySensor.h" BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {} @@ -75,6 +76,7 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement) void BME680Sensor::loadState() { #ifdef FSCom + spiLock->lock(); auto file = FSCom.open(bsecConfigFileName, FILE_O_READ); if (file) { file.read((uint8_t *)&bsecState, BSEC_MAX_STATE_BLOB_SIZE); @@ -84,6 +86,7 @@ void BME680Sensor::loadState() } else { LOG_INFO("No %s state found (File: %s)", sensorName, bsecConfigFileName); } + spiLock->unlock(); #else LOG_ERROR("ERROR: Filesystem not implemented"); #endif @@ -92,6 +95,7 @@ void BME680Sensor::loadState() void BME680Sensor::updateState() { #ifdef FSCom + spiLock->lock(); bool update = false; if (stateUpdateCounter == 0) { /* First state update when IAQ accuracy is >= 3 */ @@ -127,6 +131,7 @@ void BME680Sensor::updateState() LOG_INFO("Can't write %s state (File: %s)", sensorName, bsecConfigFileName); } } + spiLock->unlock(); #else LOG_ERROR("ERROR: Filesystem not implemented"); #endif diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp index 65f616686..1329c8d90 100644 --- a/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp +++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp @@ -5,6 +5,7 @@ #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "FSCommon.h" #include "NAU7802Sensor.h" +#include "SPILock.h" #include "SafeFile.h" #include "TelemetrySensor.h" #include @@ -111,13 +112,16 @@ bool NAU7802Sensor::saveCalibrationData() } else { okay = true; } + spiLock->lock(); okay &= file.close(); + spiLock->unlock(); return okay; } bool NAU7802Sensor::loadCalibrationData() { + spiLock->lock(); auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ); bool okay = false; if (file) { @@ -134,7 +138,8 @@ bool NAU7802Sensor::loadCalibrationData() } else { LOG_INFO("No %s state found (File: %s)", sensorName, nau7802ConfigFileName); } + spiLock->unlock(); return okay; } -#endif +#endif \ No newline at end of file diff --git a/src/xmodem.cpp b/src/xmodem.cpp index bf25e2da7..1d8c77760 100644 --- a/src/xmodem.cpp +++ b/src/xmodem.cpp @@ -49,6 +49,7 @@ **********************************************************************************************************************/ #include "xmodem.h" +#include "SPILock.h" #ifdef FSCom @@ -119,8 +120,11 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket) if ((xmodemPacket.seq == 0) && !isReceiving && !isTransmitting) { // NULL packet has the destination filename memcpy(filename, &xmodemPacket.buffer.bytes, xmodemPacket.buffer.size); + if (xmodemPacket.control == meshtastic_XModem_Control_SOH) { // Receive this file and put to Flash + spiLock->lock(); file = FSCom.open(filename, FILE_O_WRITE); + spiLock->unlock(); if (file) { sendControl(meshtastic_XModem_Control_ACK); isReceiving = true; @@ -132,14 +136,18 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket) break; } else { // Transmit this file from Flash LOG_INFO("XModem: Transmit file %s", filename); + spiLock->lock(); file = FSCom.open(filename, FILE_O_READ); + spiLock->unlock(); if (file) { packetno = 1; isTransmitting = true; xmodemStore = meshtastic_XModem_init_zero; xmodemStore.control = meshtastic_XModem_Control_SOH; xmodemStore.seq = packetno; + spiLock->lock(); xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes)); + spiLock->unlock(); xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size); LOG_DEBUG("XModem: STX Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size); if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) { @@ -159,7 +167,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket) if ((xmodemPacket.seq == packetno) && check(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size, xmodemPacket.crc16)) { // valid packet + spiLock->lock(); file.write(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size); + spiLock->unlock(); sendControl(meshtastic_XModem_Control_ACK); packetno++; break; @@ -178,16 +188,21 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket) case meshtastic_XModem_Control_EOT: // End of transmission sendControl(meshtastic_XModem_Control_ACK); + spiLock->lock(); file.flush(); file.close(); + spiLock->unlock(); isReceiving = false; break; case meshtastic_XModem_Control_CAN: // Cancel transmission and remove file sendControl(meshtastic_XModem_Control_ACK); + spiLock->lock(); file.flush(); file.close(); + FSCom.remove(filename); + spiLock->unlock(); isReceiving = false; break; case meshtastic_XModem_Control_ACK: @@ -195,7 +210,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket) if (isTransmitting) { if (isEOT) { sendControl(meshtastic_XModem_Control_EOT); + spiLock->lock(); file.close(); + spiLock->unlock(); LOG_INFO("XModem: Finished send file %s", filename); isTransmitting = false; isEOT = false; @@ -206,7 +223,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket) xmodemStore = meshtastic_XModem_init_zero; xmodemStore.control = meshtastic_XModem_Control_SOH; xmodemStore.seq = packetno; + spiLock->lock(); xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes)); + spiLock->unlock(); xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size); LOG_DEBUG("XModem: ACK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size); if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) { @@ -224,7 +243,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket) if (isTransmitting) { if (--retrans <= 0) { sendControl(meshtastic_XModem_Control_CAN); + spiLock->lock(); file.close(); + spiLock->unlock(); LOG_INFO("XModem: Retransmit timeout, cancel file %s", filename); isTransmitting = false; break; @@ -232,8 +253,11 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket) xmodemStore = meshtastic_XModem_init_zero; xmodemStore.control = meshtastic_XModem_Control_SOH; xmodemStore.seq = packetno; + spiLock->lock(); file.seek((packetno - 1) * sizeof(meshtastic_XModem_buffer_t::bytes)); + xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes)); + spiLock->unlock(); xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size); LOG_DEBUG("XModem: NAK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size); if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) { diff --git a/variants/mesh-tab/platformio.ini b/variants/mesh-tab/platformio.ini index 26b072cde..a1007a7f4 100644 --- a/variants/mesh-tab/platformio.ini +++ b/variants/mesh-tab/platformio.ini @@ -178,7 +178,7 @@ build_flags = ${mesh_tab_base.build_flags} -D LGFX_TOUCH_Y_MIN=0 -D LGFX_TOUCH_Y_MAX=479 -D LGFX_TOUCH_ROTATION=0 - -D LGFX_TOUCH_I2C_FREQ=1000000 + -D LGFX_TOUCH_I2C_FREQ=400000 ; 3.5" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005006893699919.html [env:mesh-tab-3-5-IPS-capacitive] @@ -204,7 +204,7 @@ build_flags = ${mesh_tab_base.build_flags} -D LGFX_TOUCH_Y_MIN=0 -D LGFX_TOUCH_Y_MAX=479 -D LGFX_TOUCH_ROTATION=1 - -D LGFX_TOUCH_I2C_FREQ=1000000 + -D LGFX_TOUCH_I2C_FREQ=400000 ; 4.0" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005007082906950.html [env:mesh-tab-4-0-IPS-capacitive] @@ -230,4 +230,4 @@ build_flags = ${mesh_tab_base.build_flags} -D LGFX_TOUCH_Y_MIN=0 -D LGFX_TOUCH_Y_MAX=479 -D LGFX_TOUCH_ROTATION=1 - -D LGFX_TOUCH_I2C_FREQ=1000000 \ No newline at end of file + -D LGFX_TOUCH_I2C_FREQ=400000 \ No newline at end of file