diff --git a/protobufs b/protobufs index 63621282..256f1195 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 636212824a446194b73b02ca5c6c15cd61d3e007 +Subproject commit 256f11954b7c8fcb9dc4481771c24559925bf32a diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 53405e75..601b83f9 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -97,7 +97,7 @@ static uint16_t displayWidth, displayHeight; #define SCREEN_WIDTH displayWidth #define SCREEN_HEIGHT displayHeight -#if defined(USE_EINK) || defined(ILI9341_DRIVER) +#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) // The screen is bigger so use bigger fonts #define FONT_SMALL ArialMT_Plain_16 #define FONT_MEDIUM ArialMT_Plain_24 diff --git a/src/main.cpp b/src/main.cpp index 95da0401..c3f892bc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -233,6 +233,8 @@ void setup() delay(1); #endif + // We need to scan here to decide if we have a screen for nodeDB.init() + scanI2Cdevice(); #ifdef RAK4630 // scanEInkDevice(); #endif @@ -273,10 +275,12 @@ void setup() power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration /* - * Move the scanning I2C device to the back of power initialization. - * Some boards need to be powered on to correctly scan to the device address, such as t-beam-s3-core + * Repeat the scanning for I2C devices after power initialization. + * Boards with an PMU need to be powered on to correctly scan to the device address, such as t-beam-s3-core */ - scanI2Cdevice(); + if ((HW_VENDOR == HardwareModel_LILYGO_TBEAM_S3_CORE) || (HW_VENDOR == HardwareModel_TBEAM)) { + scanI2Cdevice(); + } // Init our SPI controller (must be before screen and lora) initSPI(); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index fca3af30..92115d12 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -699,11 +699,23 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n) if (!info) { if (*numNodes >= MAX_NUM_NODES) { - screen->print("error: node_db full!\n"); - DEBUG_MSG("ERROR! could not create new node, node_db is full! (%d nodes)", *numNodes); - return NULL; + screen->print("warning: node_db full! erasing oldest entry\n"); + // look for oldest node and erase it + uint32_t oldest = UINT32_MAX; + int oldestIndex = -1; + for (int i = 0; i < *numNodes; i++) { + if (nodes[i].last_heard < oldest) { + oldest = nodes[i].last_heard; + oldestIndex = i; + } + } + // Shove the remaining nodes down the chain + for (int i = oldestIndex; i < *numNodes - 1; i++) { + nodes[i] = nodes[i + 1]; + } + (*numNodes)--; } - // add the node + // add the node at the end info = &nodes[(*numNodes)++]; // everything is missing except the nodenum diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h index bbc0380a..9392c19a 100644 --- a/src/mesh/generated/admin.pb.h +++ b/src/mesh/generated/admin.pb.h @@ -66,7 +66,7 @@ typedef struct _AdminMessage { /* Get the Canned Message Module messages in the response to this message. */ char get_canned_message_module_messages_response[201]; /* Request the node to send device metadata (firmware, protobuf version, etc) */ - uint32_t get_device_metadata_request; + bool get_device_metadata_request; /* Device metadata response */ DeviceMetadata get_device_metadata_response; /* Set the owner for this node */ @@ -94,6 +94,9 @@ typedef struct _AdminMessage { bool confirm_set_channel; /* TODO: REPLACE */ bool confirm_set_radio; + /* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) + Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. */ + int32_t reboot_ota_seconds; /* This message is only supported for the simulator porduino build. If received the simulator will exit successfully. */ bool exit_simulator; @@ -150,6 +153,7 @@ extern "C" { #define AdminMessage_confirm_set_module_config_tag 65 #define AdminMessage_confirm_set_channel_tag 66 #define AdminMessage_confirm_set_radio_tag 67 +#define AdminMessage_reboot_ota_seconds_tag 95 #define AdminMessage_exit_simulator_tag 96 #define AdminMessage_reboot_seconds_tag 97 #define AdminMessage_shutdown_seconds_tag 98 @@ -169,7 +173,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_module_config_response,g X(a, STATIC, ONEOF, BOOL, (payload_variant,get_all_channel_request,get_all_channel_request), 9) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,get_canned_message_module_messages_request,get_canned_message_module_messages_request), 10) \ X(a, STATIC, ONEOF, STRING, (payload_variant,get_canned_message_module_messages_response,get_canned_message_module_messages_response), 11) \ -X(a, STATIC, ONEOF, UINT32, (payload_variant,get_device_metadata_request,get_device_metadata_request), 12) \ +X(a, STATIC, ONEOF, BOOL, (payload_variant,get_device_metadata_request,get_device_metadata_request), 12) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_device_metadata_response,get_device_metadata_response), 13) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_owner,set_owner), 32) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 33) \ @@ -180,6 +184,7 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_config,confirm_s X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_module_config,confirm_set_module_config), 65) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_channel,confirm_set_channel), 66) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_radio,confirm_set_radio), 67) \ +X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,exit_simulator,exit_simulator), 96) \ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_seconds,reboot_seconds), 97) \ X(a, STATIC, ONEOF, INT32, (payload_variant,shutdown_seconds,shutdown_seconds), 98) \ diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index b2ed44a0..883ed0ac 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -2,6 +2,9 @@ #include "Channels.h" #include "MeshService.h" #include "NodeDB.h" +#ifdef ARCH_ESP32 +#include "BleOta.h" +#endif #include "Router.h" #include "configuration.h" #include "main.h" @@ -103,6 +106,21 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r) rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000); break; } + case AdminMessage_reboot_ota_seconds_tag: { + int32_t s = r->reboot_ota_seconds; +#ifdef ARCH_ESP32 + if (BleOta::getOtaAppVersion().isEmpty()) { + DEBUG_MSG("No OTA firmware available, scheduling regular reboot in %d seconds\n", s); + }else{ + BleOta::switchToOtaApp(); + DEBUG_MSG("Rebooting to OTA in %d seconds\n", s); + } +#else + DEBUG_MSG("Not on ESP32, scheduling regular reboot in %d seconds\n", s); +#endif + rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000); + break; + } case AdminMessage_shutdown_seconds_tag: { int32_t s = r->shutdown_seconds; DEBUG_MSG("Shutdown in %d seconds\n", s); diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index b62aa245..29ea2025 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -11,7 +11,7 @@ #include "graphics/fonts/OLEDDisplayFontsRU.h" #endif -#if defined(USE_EINK) || defined(ILI9341_DRIVER) +#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) // The screen is bigger so use bigger fonts #define FONT_SMALL ArialMT_Plain_16 #define FONT_MEDIUM ArialMT_Plain_24 @@ -292,7 +292,7 @@ int32_t CannedMessageModule::runOnce() if(this->dest == NODENUM_BROADCAST) { this->dest = nodeDB.getNodeNum(); } - for (int i = 0; i < numNodes; i++) { + for (unsigned int i = 0; i < numNodes; i++) { if (nodeDB.getNodeByIndex(i)->num == this->dest) { this->dest = (i > 0) ? nodeDB.getNodeByIndex(i-1)->num : nodeDB.getNodeByIndex(numNodes-1)->num; break; @@ -313,7 +313,7 @@ int32_t CannedMessageModule::runOnce() if(this->dest == NODENUM_BROADCAST) { this->dest = nodeDB.getNodeNum(); } - for (int i = 0; i < numNodes; i++) { + for (unsigned int i = 0; i < numNodes; i++) { if (nodeDB.getNodeByIndex(i)->num == this->dest) { this->dest = (i < numNodes-1) ? nodeDB.getNodeByIndex(i+1)->num : nodeDB.getNodeByIndex(0)->num; break; @@ -453,13 +453,15 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->setColor(WHITE); display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor)); } else { - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(FONT_SMALL); - display->drawString(0 + x, 0 + y, cannedMessageModule->getPrevMessage()); - display->setFont(FONT_MEDIUM); - display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getCurrentMessage()); - display->setFont(FONT_SMALL); - display->drawString(0 + x, 0 + y + FONT_HEIGHT_MEDIUM, cannedMessageModule->getNextMessage()); + if (this->messagesCount > 0) { + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(FONT_SMALL); + display->drawString(0 + x, 0 + y, cannedMessageModule->getPrevMessage()); + display->setFont(FONT_MEDIUM); + display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getCurrentMessage()); + display->setFont(FONT_SMALL); + display->drawString(0 + x, 0 + y + FONT_HEIGHT_MEDIUM, cannedMessageModule->getNextMessage()); + } } } diff --git a/src/platform/esp32/BleOta.cpp b/src/platform/esp32/BleOta.cpp new file mode 100644 index 00000000..8062eede --- /dev/null +++ b/src/platform/esp32/BleOta.cpp @@ -0,0 +1,46 @@ +#include "Arduino.h" +#include "BleOta.h" +#include + +static const String MESHTASTIC_OTA_APP_PROJECT_NAME("Meshtastic-OTA"); + +const esp_partition_t* BleOta::findEspOtaAppPartition() { + const esp_partition_t *part + = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, nullptr); + + esp_app_desc_t app_desc; + esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc)); + + if (ret != ESP_OK || MESHTASTIC_OTA_APP_PROJECT_NAME != app_desc.project_name) { + part + = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, + nullptr); + ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc)); + } + + if (ret == ESP_OK && MESHTASTIC_OTA_APP_PROJECT_NAME == app_desc.project_name) { + return part; + } else { + return nullptr; + } +} + +String BleOta::getOtaAppVersion() { + const esp_partition_t *part = findEspOtaAppPartition(); + esp_app_desc_t app_desc; + esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc)); + String version; + if (ret == ESP_OK) { + version = app_desc.version; + } + return version; +} + +bool BleOta::switchToOtaApp() { + bool success = false; + const esp_partition_t *part = findEspOtaAppPartition(); + if (part) { + success = (ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_set_boot_partition(part)) == ESP_OK); + } + return success; +} \ No newline at end of file diff --git a/src/platform/esp32/BleOta.h b/src/platform/esp32/BleOta.h new file mode 100644 index 00000000..4c598f36 --- /dev/null +++ b/src/platform/esp32/BleOta.h @@ -0,0 +1,18 @@ +#ifndef BLEOTA_H +#define BLEOTA_H + +#include + +class BleOta { + public: + explicit BleOta() {}; + + static String getOtaAppVersion(); + static bool switchToOtaApp(); + + private: + String mUserAgent; + static const esp_partition_t *findEspOtaAppPartition(); +}; + +#endif //BLEOTA_H \ No newline at end of file diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp index ccfaa3b0..b3af114e 100644 --- a/src/platform/portduino/SimRadio.cpp +++ b/src/platform/portduino/SimRadio.cpp @@ -171,6 +171,8 @@ void SimRadio::onNotify(uint32_t notification) // Packet has been sent, count it toward our TX airtime utilization. uint32_t xmitMsec = getPacketTime(txp); airTime->logAirtime(TX_LOG, xmitMsec); + + delay(xmitMsec); // Model the time it is busy sending completeSending(); } } @@ -207,6 +209,9 @@ void SimRadio::startSend(MeshPacket * txp) void SimRadio::startReceive(MeshPacket *p) { isReceiving = true; + size_t length = getPacketLength(p); + uint32_t xmitMsec = getPacketTime(length); + delay(xmitMsec); // Model the time it is busy receiving handleReceiveInterrupt(p); }