From 10b157a38d3fe353ece472f556b0cf8c97cea180 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Wed, 3 Jul 2024 22:04:39 +0800 Subject: [PATCH 1/5] Typo fix in logs - mhz - MHz (#4225) As reported by karamo, a few different places in our logs had incorrect capitalization of MHz. fixes meshtastic/firmware#4126 --- src/mesh/RadioInterface.cpp | 2 +- src/sleep.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index cdea33717..343b7f200 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -521,7 +521,7 @@ void RadioInterface::applyModemConfig() LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f\n", freq, loraConfig.frequency_offset); LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power); - LOG_INFO("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, + LOG_INFO("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f MHz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart); LOG_INFO("Radio myRegion->numChannels: %d x %.3fkHz\n", numChannels, bw); LOG_INFO("Radio channel_num: %d\n", channel_num + 1); diff --git a/src/sleep.cpp b/src/sleep.cpp index c9c45bf67..1c1a6e9ac 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -62,14 +62,14 @@ void setCPUFast(bool on) /* * * There's a newly introduced bug in the espressif framework where WiFi is - * unstable when the frequency is less than 240mhz. + * unstable when the frequency is less than 240MHz. * * This mostly impacts WiFi AP mode but we'll bump the frequency for * all WiFi use cases. * (Added: Dec 23, 2021 by Jm Casler) */ #ifndef CONFIG_IDF_TARGET_ESP32C3 - LOG_DEBUG("Setting CPU to 240mhz because WiFi is in use.\n"); + LOG_DEBUG("Setting CPU to 240MHz because WiFi is in use.\n"); setCpuFrequencyMhz(240); #endif return; From 9c46bdad1abca401ab51fe7b865436c6756bd71c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 3 Jul 2024 16:29:07 -0500 Subject: [PATCH 2/5] New new BLE logging characteristic with LogRecord protos (#4220) * New UUID * New log radio characteristic with LogRecord protobuf * LogRecord * Merge derp * How did you get there * Trunk * Fix length * Remove assert --- src/BluetoothCommon.cpp | 6 +++-- src/BluetoothCommon.h | 4 ++-- src/RedirectablePrint.cpp | 43 +++++++++++++++++++++++++++------- src/RedirectablePrint.h | 2 ++ src/mesh/Router.cpp | 6 +++-- src/nimble/NimbleBluetooth.cpp | 7 +++--- src/nimble/NimbleBluetooth.h | 2 +- 7 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/BluetoothCommon.cpp b/src/BluetoothCommon.cpp index 7ef1c39b4..d9502e4f5 100644 --- a/src/BluetoothCommon.cpp +++ b/src/BluetoothCommon.cpp @@ -11,5 +11,7 @@ const uint8_t FROMRADIO_UUID_16[16u] = {0x02, 0x00, 0x12, 0xac, 0x42, 0x02, 0x78 0xed, 0x11, 0x93, 0x49, 0x9e, 0xe6, 0x55, 0x2c}; const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; -const uint8_t LOGRADIO_UUID_16[16u] = {0xe2, 0xf2, 0x1e, 0xbe, 0xc5, 0x15, 0xcf, 0xaa, - 0x6b, 0x43, 0xfa, 0x78, 0x38, 0xd2, 0x6f, 0x6c}; \ No newline at end of file +const uint8_t LEGACY_LOGRADIO_UUID_16[16u] = {0xe2, 0xf2, 0x1e, 0xbe, 0xc5, 0x15, 0xcf, 0xaa, + 0x6b, 0x43, 0xfa, 0x78, 0x38, 0xd2, 0x6f, 0x6c}; +const uint8_t LOGRADIO_UUID_16[16u] = {0x47, 0x95, 0xDF, 0x8C, 0xDE, 0xE9, 0x44, 0x99, + 0x23, 0x44, 0xE6, 0x06, 0x49, 0x6E, 0x3D, 0x5A}; \ No newline at end of file diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h index 5497e1d6d..440d13844 100644 --- a/src/BluetoothCommon.h +++ b/src/BluetoothCommon.h @@ -11,7 +11,8 @@ #define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7" #define FROMRADIO_UUID "2c55e69e-4993-11ed-b878-0242ac120002" #define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453" -#define LOGRADIO_UUID "6c6fd238-78fa-436b-aacf-15c5be1ef2e2" +#define LEGACY_LOGRADIO_UUID "6c6fd238-78fa-436b-aacf-15c5be1ef2e2" +#define LOGRADIO_UUID "5a3d6e49-06e6-4423-9944-e9de8cdf9547" // NRF52 wants these constants as byte arrays // Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER @@ -28,5 +29,4 @@ class BluetoothApi virtual void clearBonds(); virtual bool isConnected(); virtual int getRssi() = 0; - virtual void sendLog(const char *logMessage); }; \ No newline at end of file diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 782febd75..555e45401 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -4,6 +4,7 @@ #include "concurrency/OSThread.h" #include "configuration.h" #include "main.h" +#include "mesh/generated/meshtastic/mesh.pb.h" #include #include #include @@ -192,22 +193,48 @@ void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_ vsnprintf(message, len + 1, format, arg); } auto thread = concurrency::OSThread::currentThread; + meshtastic_LogRecord logRecord = meshtastic_LogRecord_init_zero; + logRecord.level = getLogLevel(logLevel); + strcpy(logRecord.message, message); + if (thread) + strcpy(logRecord.source, thread->ThreadName.c_str()); + logRecord.time = getValidTime(RTCQuality::RTCQualityDevice, true); + + uint8_t *buffer = new uint8_t[meshtastic_LogRecord_size]; + size_t size = pb_encode_to_bytes(buffer, meshtastic_LogRecord_size, meshtastic_LogRecord_fields, &logRecord); #ifdef ARCH_ESP32 - if (thread) - nimbleBluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); - else - nimbleBluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); + nimbleBluetooth->sendLog(buffer, size); #elif defined(ARCH_NRF52) - if (thread) - nrf52Bluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); - else - nrf52Bluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); + nrf52Bluetooth->sendLog(reinterpret_cast(buffer)); #endif delete[] message; } } } +meshtastic_LogRecord_Level RedirectablePrint::getLogLevel(const char *logLevel) +{ + meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset + switch (logLevel[0]) { + case 'D': + ll = meshtastic_LogRecord_Level_DEBUG; + break; + case 'I': + ll = meshtastic_LogRecord_Level_INFO; + break; + case 'W': + ll = meshtastic_LogRecord_Level_WARNING; + break; + case 'E': + ll = meshtastic_LogRecord_Level_ERROR; + break; + case 'C': + ll = meshtastic_LogRecord_Level_CRITICAL; + break; + } + return ll; +} + void RedirectablePrint::log(const char *logLevel, const char *format, ...) { #ifdef ARCH_PORTDUINO diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index 3f20c894c..23ae3c44d 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -1,6 +1,7 @@ #pragma once #include "../freertosinc.h" +#include "mesh/generated/meshtastic/mesh.pb.h" #include #include #include @@ -57,4 +58,5 @@ class RedirectablePrint : public Print private: void log_to_syslog(const char *logLevel, const char *format, va_list arg); void log_to_ble(const char *logLevel, const char *format, va_list arg); + meshtastic_LogRecord_Level getLogLevel(const char *logLevel); }; \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 3141d986b..c8c18ae6d 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -244,8 +244,10 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) - assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || - p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now + if (!(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || + p->which_payload_variant == meshtastic_MeshPacket_decoded_tag)) { + return meshtastic_Routing_Error_BAD_REQUEST; + } // If the packet is not yet encrypted, do so now if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 78ef5a1d3..d959553a4 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -219,7 +219,6 @@ void NimbleBluetooth::setupService() logRadioCharacteristic = bleService->createCharacteristic( LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC, 512U); - logRadioCharacteristic->setValue("Init"); } bluetoothPhoneAPI = new BluetoothPhoneAPI(); @@ -268,12 +267,12 @@ void NimbleBluetooth::clearBonds() NimBLEDevice::deleteAllBonds(); } -void NimbleBluetooth::sendLog(const char *logMessage) +void NimbleBluetooth::sendLog(const uint8_t *logMessage, size_t length) { - if (!bleServer || !isConnected() || strlen(logMessage) > 512) { + if (!bleServer || !isConnected() || length > 512) { return; } - logRadioCharacteristic->notify(reinterpret_cast(logMessage), strlen(logMessage), true); + logRadioCharacteristic->notify(logMessage, length, true); } void clearNVS() diff --git a/src/nimble/NimbleBluetooth.h b/src/nimble/NimbleBluetooth.h index 39794779b..45602e088 100644 --- a/src/nimble/NimbleBluetooth.h +++ b/src/nimble/NimbleBluetooth.h @@ -11,7 +11,7 @@ class NimbleBluetooth : BluetoothApi bool isActive(); bool isConnected(); int getRssi(); - void sendLog(const char *logMessage); + void sendLog(const uint8_t *logMessage, size_t length); private: void setupService(); From 8785adf6e4f59df40bc686cebfbb4946b7816135 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 3 Jul 2024 15:39:09 -0700 Subject: [PATCH 3/5] minor cleanup proposal (#4169) * MESHTASTIC_EXCLUDE_WIFI and HAS_WIFI cleanup... Our code was checking HAS_WIFI and the new MESHTASTIC_EXCLUDE_WIFI flags in various places (even though EXCLUDE_WIFI forces HAS_WIFI to 0). Instead just check HAS_WIFI, only use EXCLUDE_WIFI inside configuration.h * cleanup: use HAS_NETWORKING instead of HAS_WIFI || HAS_ETHERNET We already had HAS_NETWORKING as flag in MQTT to mean 'we have tcpip'. Generallize that and move it into configuration.h so that we can use it elsewhere. * Use #pragma once, because supported by gcc and all modern compilers instead of #ifdef DOTHFILE_H etc... --------- Co-authored-by: Jonathan Bennett --- src/DebugConfiguration.cpp | 2 +- src/DebugConfiguration.h | 11 +++++------ src/Power.cpp | 2 +- src/RedirectablePrint.cpp | 4 ++-- src/configuration.h | 11 +++++++---- src/mesh/NodeDB.cpp | 2 +- src/mesh/http/ContentHandler.cpp | 2 +- src/mesh/wifi/WiFiAPClient.cpp | 2 +- src/modules/AdminModule.h | 2 +- src/mqtt/MQTT.cpp | 18 +++++++++--------- src/mqtt/MQTT.h | 6 ++---- src/platform/esp32/main-esp32.cpp | 29 ++++++++++++++--------------- src/sleep.cpp | 4 ++-- 13 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/DebugConfiguration.cpp b/src/DebugConfiguration.cpp index 9df402e77..d9ecd9fe3 100644 --- a/src/DebugConfiguration.cpp +++ b/src/DebugConfiguration.cpp @@ -26,7 +26,7 @@ SOFTWARE.*/ #include "DebugConfiguration.h" -#if HAS_WIFI || HAS_ETHERNET +#if HAS_NETWORKING Syslog::Syslog(UDP &client) { diff --git a/src/DebugConfiguration.h b/src/DebugConfiguration.h index 874d63bca..ebe9da8d4 100644 --- a/src/DebugConfiguration.h +++ b/src/DebugConfiguration.h @@ -1,5 +1,6 @@ -#ifndef SYSLOG_H -#define SYSLOG_H +#pragma once + +#include "configuration.h" // DEBUG LED #ifndef LED_INVERTED @@ -125,7 +126,7 @@ #include #endif // HAS_WIFI -#if HAS_WIFI || HAS_ETHERNET +#if HAS_NETWORKING class Syslog { @@ -160,6 +161,4 @@ class Syslog bool vlogf(uint16_t pri, const char *appName, const char *fmt, va_list args) __attribute__((format(printf, 3, 0))); }; -#endif // HAS_ETHERNET || HAS_WIFI - -#endif // SYSLOG_H \ No newline at end of file +#endif // HAS_ETHERNET || HAS_WIFI \ No newline at end of file diff --git a/src/Power.cpp b/src/Power.cpp index 18a527cee..cea373806 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -27,7 +27,7 @@ #if defined(DEBUG_HEAP_MQTT) && !MESHTASTIC_EXCLUDE_MQTT #include "mqtt/MQTT.h" #include "target_specific.h" -#if !MESTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include #endif #endif diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 555e45401..14264ba21 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -16,7 +16,7 @@ #include "platform/portduino/PortduinoGlue.h" #endif -#if HAS_WIFI || HAS_ETHERNET +#if HAS_NETWORKING extern Syslog syslog; #endif void RedirectablePrint::rpInit() @@ -138,7 +138,7 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, void RedirectablePrint::log_to_syslog(const char *logLevel, const char *format, va_list arg) { -#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO) +#if HAS_NETWORKING && !defined(ARCH_PORTDUINO) // if syslog is in use, collect the log messages and send them to syslog if (syslog.isEnabled()) { int ll = 0; diff --git a/src/configuration.h b/src/configuration.h index 3d10feeaa..854d3dadf 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -242,9 +242,6 @@ along with this program. If not, see . #define HAS_BLUETOOTH 0 #endif -#include "DebugConfiguration.h" -#include "RF95Configuration.h" - #ifndef HW_VENDOR #error HW_VENDOR must be defined #endif @@ -290,6 +287,9 @@ along with this program. If not, see . #define HAS_WIFI 0 #endif +// Allow code that needs internet to just check HAS_NETWORKING rather than HAS_WIFI || HAS_ETHERNET +#define HAS_NETWORKING (HAS_WIFI || HAS_ETHERNET) + // // Turn off Bluetooth #ifdef MESHTASTIC_EXCLUDE_BLUETOOTH #undef HAS_BLUETOOTH @@ -308,4 +308,7 @@ along with this program. If not, see . #ifdef MESHTASTIC_EXCLUDE_SCREEN #undef HAS_SCREEN #define HAS_SCREEN 0 -#endif \ No newline at end of file +#endif + +#include "DebugConfiguration.h" +#include "RF95Configuration.h" \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 1dc6d7883..84872e471 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -26,7 +26,7 @@ #include #ifdef ARCH_ESP32 -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "modules/esp32/StoreForwardModule.h" diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 7f9df058d..b309484e2 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -6,7 +6,7 @@ #include "main.h" #include "mesh/http/ContentHelper.h" #include "mesh/http/WebServer.h" -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "mqtt/JSON.h" diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index ffb16bd3e..e733d1801 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -1,5 +1,5 @@ #include "configuration.h" -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "NodeDB.h" #include "RTC.h" #include "concurrency/Periodic.h" diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index 32b32c253..6ecc88829 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -1,6 +1,6 @@ #pragma once #include "ProtobufModule.h" -#if HAS_WIFI && !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 74f3ca5a3..a64720c78 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -14,7 +14,7 @@ #endif #include "mesh/generated/meshtastic/remote_hardware.pb.h" #include "sleep.h" -#if HAS_WIFI && !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #include #endif @@ -175,7 +175,7 @@ void mqttInit() new MQTT(); } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE) #else MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) @@ -206,7 +206,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) moduleConfig.mqtt.map_report_settings.publish_interval_secs, default_map_publish_interval_secs); } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING if (!moduleConfig.mqtt.proxy_to_client_enabled) pubSub.setCallback(mqttCallback); #endif @@ -226,7 +226,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) bool MQTT::isConnectedDirectly() { -#ifdef HAS_NETWORKING +#if HAS_NETWORKING return pubSub.connected(); #else return false; @@ -244,7 +244,7 @@ bool MQTT::publish(const char *topic, const char *payload, bool retained) service.sendMqttMessageToClientProxy(msg); return true; } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING else if (isConnectedDirectly()) { return pubSub.publish(topic, payload, retained); } @@ -264,7 +264,7 @@ bool MQTT::publish(const char *topic, const uint8_t *payload, size_t length, boo service.sendMqttMessageToClientProxy(msg); return true; } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING else if (isConnectedDirectly()) { return pubSub.publish(topic, payload, length, retained); } @@ -284,7 +284,7 @@ void MQTT::reconnect() publishStatus(); return; // Don't try to connect directly to the server } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING // Defaults int serverPort = 1883; const char *serverAddr = default_mqtt_address; @@ -357,7 +357,7 @@ void MQTT::reconnect() void MQTT::sendSubscriptions() { -#ifdef HAS_NETWORKING +#if HAS_NETWORKING size_t numChan = channels.getNumChannels(); for (size_t i = 0; i < numChan; i++) { const auto &ch = channels.getByIndex(i); @@ -396,7 +396,7 @@ bool MQTT::wantsLink() const int32_t MQTT::runOnce() { -#ifdef HAS_NETWORKING +#if HAS_NETWORKING if (!moduleConfig.mqtt.enabled || !(moduleConfig.mqtt.map_reporting_enabled || channels.anyMqttEnabled())) return disable(); diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index f2eb6b120..1ebba4afe 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -8,17 +8,15 @@ #include "mqtt/JSON.h" #if HAS_WIFI #include -#define HAS_NETWORKING 1 #if !defined(ARCH_PORTDUINO) #include #endif #endif #if HAS_ETHERNET #include -#define HAS_NETWORKING 1 #endif -#ifdef HAS_NETWORKING +#if HAS_NETWORKING #include #endif @@ -43,7 +41,7 @@ class MQTT : private concurrency::OSThread #endif public: -#ifdef HAS_NETWORKING +#if HAS_NETWORKING PubSubClient pubSub; #endif MQTT(); diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 1dd7a389a..aa51e810a 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -8,7 +8,7 @@ #include "nimble/NimbleBluetooth.h" #endif -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif @@ -24,23 +24,22 @@ #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) { -#ifndef MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI if (!isWifiAvailable() && config.bluetooth.enabled == true) +#else + if (config.bluetooth.enabled == true) #endif -#ifdef MESHTASTIC_EXCLUDE_WIFI - if (config.bluetooth.enabled == true) -#endif - { - if (!nimbleBluetooth) { - nimbleBluetooth = new NimbleBluetooth(); - } - if (enable && !nimbleBluetooth->isActive()) { - nimbleBluetooth->setup(); - } - // For ESP32, no way to recover from bluetooth shutdown without reboot - // BLE advertising automatically stops when MCU enters light-sleep(?) - // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse + { + if (!nimbleBluetooth) { + nimbleBluetooth = new NimbleBluetooth(); } + if (enable && !nimbleBluetooth->isActive()) { + nimbleBluetooth->setup(); + } + // For ESP32, no way to recover from bluetooth shutdown without reboot + // BLE advertising automatically stops when MCU enters light-sleep(?) + // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse + } } #else void setBluetoothEnable(bool enable) {} diff --git a/src/sleep.cpp b/src/sleep.cpp index 1c1a6e9ac..735ebcf6a 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -17,7 +17,7 @@ #ifdef ARCH_ESP32 #include "esp32/pm.h" #include "esp_pm.h" -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "rom/rtc.h" @@ -56,7 +56,7 @@ RTC_DATA_ATTR int bootCount = 0; */ void setCPUFast(bool on) { -#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI +#if defined(ARCH_ESP32) && HAS_WIFI if (isWifiAvailable()) { /* From 8bca3e168d5f89ab3168937a1384c32bda27d0d9 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 3 Jul 2024 16:02:20 -0700 Subject: [PATCH 4/5] Add PowerMon support (#4155) * Turn off vscode cmake prompt - we don't use cmake on meshtastic * Add rak4631_dap variant for debugging with NanoDAP debug probe device. * The rak device can also run freertos (which is underneath nrf52 arduino) * Add semihosting support for nrf52840 devices Initial platformio.ini file only supports rak4630 Default to non TCP for the semihosting log output for now... Fixes https://github.com/meshtastic/firmware/issues/4135 * powermon WIP (for https://github.com/meshtastic/firmware/issues/4136 ) * oops - mean't to mark the _dbg variant as an 'extra' board. * powermon wip * Make serial port on wio-sdk-wm1110 board work By disabling the (inaccessible) adafruit USB * Instrument (radiolib only for now) lora for powermon per https://github.com/meshtastic/firmware/issues/4136 * powermon gps support https://github.com/meshtastic/firmware/issues/4136 * Add CPU deep and light sleep powermon states https://github.com/meshtastic/firmware/issues/4136 * Change the board/swversion bootstring so it is a new "structured" log msg. * powermon wip * add example script for getting esp S3 debugging working Not yet used but I didn't want these nasty tricks to get lost yet. * Add PowerMon reporting for screen and bluetooth pwr. * make power.powermon_enables config setting work. * update to latest protobufs * fix bogus shellcheck warning * make powermon optional (but default enabled because tiny and no runtime impact) * tell vscode, if formatting, use whatever our trunk formatter wants without this flag if the user has set some other formatter (clang) in their user level settings, it will be looking in the wrong directory for the clang options (we want the options in .trunk/clang) Note: formatOnSave is true in master, which means a bunch of our older files are non compliant and if you edit them it will generate lots of formatting related diffs. I guess I'll start letting that happen with my future commits ;-). * add PowerStress module * nrf52 arduino is built upon freertos, so let platformio debug it * don't accidentally try to Segger ICE if we are using another ICE * clean up RedirectablePrint::log so it doesn't have three very different implementations inline. * remove NoopPrint - it is no longer needed * when talking to API clients via serial, don't turn off log msgs instead encapsuate them * fix the build - would loop forever if there were no files to send * don't use Segger code if not talking to a Segger debugger * when encapsulating logs, make sure the strings always has nul terminators * nrf52 soft device will watchdog if you use ICE while BT on... so have debugger disable bluetooth. * Important to not print debug messages while writing to the toPhone scratch buffer * don't include newlines if encapsulating log records as protobufs * update to latest protobufs (needed for powermon goo) * PowerStress WIP * fix linter warning --- bin/setup-python-for-esp-debug.sh | 12 +++++ boards/wio-sdk-wm1110.json | 2 +- src/PowerFSM.cpp | 17 +++++++ src/PowerMon.cpp | 45 ++++++++++++++++++ src/PowerMon.h | 34 ++++++++++++++ src/configuration.h | 2 + src/gps/GPS.cpp | 4 ++ src/main.cpp | 12 ++++- src/mesh/LR11x0Interface.cpp | 3 +- src/mesh/RF95Interface.cpp | 31 +++++++------ src/mesh/RadioLibInterface.cpp | 21 +++++++++ src/mesh/RadioLibInterface.h | 13 ++++-- src/mesh/SX126xInterface.cpp | 3 +- src/mesh/SX128xInterface.cpp | 3 +- src/modules/Modules.cpp | 6 +++ src/modules/PowerStressModule.cpp | 77 +++++++++++++++++++++++++++++++ src/modules/PowerStressModule.h | 38 +++++++++++++++ src/sleep.cpp | 6 +++ 18 files changed, 306 insertions(+), 23 deletions(-) create mode 100644 bin/setup-python-for-esp-debug.sh create mode 100644 src/PowerMon.cpp create mode 100644 src/PowerMon.h create mode 100644 src/modules/PowerStressModule.cpp create mode 100644 src/modules/PowerStressModule.h diff --git a/bin/setup-python-for-esp-debug.sh b/bin/setup-python-for-esp-debug.sh new file mode 100644 index 000000000..edba43e72 --- /dev/null +++ b/bin/setup-python-for-esp-debug.sh @@ -0,0 +1,12 @@ +# shellcheck shell=bash +# (this minor script is actually shell agnostic, and is intended to be sourced rather than run in a subshell) + +# This is a little script you can source if you want to make ESP debugging work on a modern (24.04) ubuntu machine +# It assumes you have built and installed python 2.7 from source with: +# ./configure --enable-optimizations --enable-shared --enable-unicode=ucs4 +# sudo make clean +# make +# sudo make altinstall + +export LD_LIBRARY_PATH=$HOME/packages/python-2.7.18/ +export PYTHON_HOME=/usr/local/lib/python2.7/ diff --git a/boards/wio-sdk-wm1110.json b/boards/wio-sdk-wm1110.json index 882f4443e..18c87adde 100644 --- a/boards/wio-sdk-wm1110.json +++ b/boards/wio-sdk-wm1110.json @@ -27,7 +27,7 @@ "jlink_device": "nRF52840_xxAA", "svd_path": "nrf52840.svd" }, - "frameworks": ["arduino"], + "frameworks": ["arduino", "freertos"], "name": "Seeed WIO WM1110", "upload": { "maximum_ram_size": 248832, diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index a7bc18f1a..72e00810b 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -11,6 +11,7 @@ #include "Default.h" #include "MeshService.h" #include "NodeDB.h" +#include "PowerMon.h" #include "configuration.h" #include "graphics/Screen.h" #include "main.h" @@ -49,6 +50,7 @@ static bool isPowered() static void sdsEnter() { LOG_DEBUG("Enter state: SDS\n"); + powerMon->setState(meshtastic_PowerMon_State_CPU_DeepSleep); // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false); } @@ -68,6 +70,7 @@ static uint32_t secsSlept; static void lsEnter() { LOG_INFO("lsEnter begin, ls_secs=%u\n", config.power.ls_secs); + powerMon->clearState(meshtastic_PowerMon_State_Screen_On); screen->setOn(false); secsSlept = 0; // How long have we been sleeping this time @@ -87,8 +90,10 @@ static void lsIdle() // Briefly come out of sleep long enough to blink the led once every few seconds uint32_t sleepTime = SLEEP_TIME; + powerMon->setState(meshtastic_PowerMon_State_CPU_LightSleep); setLed(false); // Never leave led on while in light sleep esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL); + powerMon->clearState(meshtastic_PowerMon_State_CPU_LightSleep); switch (wakeCause2) { case ESP_SLEEP_WAKEUP_TIMER: @@ -144,6 +149,7 @@ static void lsExit() static void nbEnter() { LOG_DEBUG("Enter state: NB\n"); + powerMon->clearState(meshtastic_PowerMon_State_BT_On); screen->setOn(false); #ifdef ARCH_ESP32 // Only ESP32 should turn off bluetooth @@ -155,6 +161,8 @@ static void nbEnter() static void darkEnter() { + powerMon->clearState(meshtastic_PowerMon_State_BT_On); + powerMon->clearState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(true); screen->setOn(false); } @@ -162,6 +170,8 @@ static void darkEnter() static void serialEnter() { LOG_DEBUG("Enter state: SERIAL\n"); + powerMon->clearState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(false); screen->setOn(true); screen->print("Serial connected\n"); @@ -170,6 +180,7 @@ static void serialEnter() static void serialExit() { // Turn bluetooth back on when we leave serial stream API + powerMon->setState(meshtastic_PowerMon_State_BT_On); setBluetoothEnable(true); screen->print("Serial disconnected\n"); } @@ -182,6 +193,8 @@ static void powerEnter() LOG_INFO("Loss of power in Powered\n"); powerFSM.trigger(EVENT_POWER_DISCONNECTED); } else { + powerMon->setState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); // within enter() the function getState() returns the state we came from @@ -205,6 +218,8 @@ static void powerIdle() static void powerExit() { + powerMon->setState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); @@ -216,6 +231,8 @@ static void powerExit() static void onEnter() { LOG_DEBUG("Enter state: ON\n"); + powerMon->setState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); } diff --git a/src/PowerMon.cpp b/src/PowerMon.cpp new file mode 100644 index 000000000..3d28715e0 --- /dev/null +++ b/src/PowerMon.cpp @@ -0,0 +1,45 @@ +#include "PowerMon.h" +#include "NodeDB.h" + +// Use the 'live' config flag to figure out if we should be showing this message +static bool is_power_enabled(uint64_t m) +{ + return (m & config.power.powermon_enables) ? true : false; +} + +void PowerMon::setState(_meshtastic_PowerMon_State state, const char *reason) +{ +#ifdef USE_POWERMON + auto oldstates = states; + states |= state; + if (oldstates != states && is_power_enabled(state)) { + emitLog(reason); + } +#endif +} + +void PowerMon::clearState(_meshtastic_PowerMon_State state, const char *reason) +{ +#ifdef USE_POWERMON + auto oldstates = states; + states &= ~state; + if (oldstates != states && is_power_enabled(state)) { + emitLog(reason); + } +#endif +} + +void PowerMon::emitLog(const char *reason) +{ +#ifdef USE_POWERMON + // The nrf52 printf doesn't understand 64 bit ints, so if we ever reach that point this function will need to change. + LOG_INFO("S:PM:0x%08lx,%s\n", (uint32_t)states, reason); +#endif +} + +PowerMon *powerMon; + +void powerMonInit() +{ + powerMon = new PowerMon(); +} \ No newline at end of file diff --git a/src/PowerMon.h b/src/PowerMon.h new file mode 100644 index 000000000..e9f5dbd59 --- /dev/null +++ b/src/PowerMon.h @@ -0,0 +1,34 @@ +#pragma once +#include "configuration.h" + +#include "meshtastic/powermon.pb.h" + +#ifndef MESHTASTIC_EXCLUDE_POWERMON +#define USE_POWERMON // FIXME turn this only for certain builds +#endif + +/** + * The singleton class for monitoring power consumption of device + * subsystems/modes. + * + * For more information see the PowerMon docs. + */ +class PowerMon +{ + uint64_t states = 0UL; + + public: + PowerMon() {} + + // Mark entry/exit of a power consuming state + void setState(_meshtastic_PowerMon_State state, const char *reason = ""); + void clearState(_meshtastic_PowerMon_State state, const char *reason = ""); + + private: + // Emit the coded log message + void emitLog(const char *reason); +}; + +extern PowerMon *powerMon; + +void powerMonInit(); \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h index 854d3dadf..aad4ac457 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -258,6 +258,7 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_GPS 1 #define MESHTASTIC_EXCLUDE_SCREEN 1 #define MESHTASTIC_EXCLUDE_MQTT 1 +#define MESHTASTIC_EXCLUDE_POWERMON 1 #endif // Turn off all optional modules @@ -278,6 +279,7 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_WAYPOINT 1 #define MESHTASTIC_EXCLUDE_INPUTBROKER 1 #define MESHTASTIC_EXCLUDE_SERIAL 1 +#define MESHTASTIC_EXCLUDE_POWERSTRESS 1 #endif // // Turn off wifi even if HW supports wifi (webserver relies on wifi and is also disabled) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 5efe96251..ec7d725b8 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -3,6 +3,7 @@ #include "Default.h" #include "GPS.h" #include "NodeDB.h" +#include "PowerMon.h" #include "RTC.h" #include "main.h" // pmu_found @@ -815,9 +816,12 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) return; if (on) { + powerMon->setState(meshtastic_PowerMon_State_GPS_Active); clearBuffer(); // drop any old data waiting in the buffer before re-enabling if (en_gpio) digitalWrite(en_gpio, on ? GPS_EN_ACTIVE : !GPS_EN_ACTIVE); // turn this on if defined, every time + } else { + powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); } isInPowersave = !on; if (!standbyOnly && en_gpio != 0 && diff --git a/src/main.cpp b/src/main.cpp index 196eae525..1e0d998e1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" +#include "PowerMon.h" #include "ReliableRouter.h" #include "airtime.h" #include "buzz.h" @@ -214,6 +215,14 @@ __attribute__((weak, noinline)) bool loopCanSleep() return true; } +/** + * Print info as a structured log message (for automated log processing) + */ +void printInfo() +{ + LOG_INFO("S:B:%d,%s\n", HW_VENDOR, optstr(APP_VERSION)); +} + void setup() { concurrency::hasBeenSetup = true; @@ -234,6 +243,7 @@ void setup() #ifdef DEBUG_PORT consoleInit(); // Set serial baud rate and init our mesh console #endif + powerMonInit(); serialSinceMsec = millis(); @@ -553,7 +563,7 @@ void setup() #endif // Hello - LOG_INFO("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION)); + printInfo(); #ifdef ARCH_ESP32 esp32Setup(); diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index bffca0c44..fc059ec16 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -184,6 +184,7 @@ template void LR11x0Interface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** @@ -223,7 +224,7 @@ template void LR11x0Interface::startReceive() 0); // only RX_DONE IRQ is needed, we'll check for PREAMBLE_DETECTED and HEADER_VALID in isActivelyReceiving assert(err == RADIOLIB_ERR_NONE); - isReceiving = true; + RadioLibInterface::startReceive(); // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index c5356ad3b..bd1ebdb0e 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -25,7 +25,8 @@ typedef struct { } DACDB; // Interpolation function -DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val2) { +DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val2) +{ DACDB result; double fraction = (double)(dbm - dbm1) / (dbm2 - dbm1); result.dac = (uint8_t)(val1.dac + fraction * (val2.dac - val1.dac)); @@ -34,16 +35,17 @@ DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val } // Function to find the correct DAC and DB values based on dBm using interpolation -DACDB getDACandDB(uint8_t dbm) { +DACDB getDACandDB(uint8_t dbm) +{ // Predefined values static const struct { uint8_t dbm; DACDB values; } dbmToDACDB[] = { - {20, {168, 2}}, // 100mW - {24, {148, 6}}, // 250mW - {27, {128, 9}}, // 500mW - {30, {90, 12}} // 1000mW + {20, {168, 2}}, // 100mW + {24, {148, 6}}, // 250mW + {27, {128, 9}}, // 500mW + {30, {90, 12}} // 1000mW }; const int numValues = sizeof(dbmToDACDB) / sizeof(dbmToDACDB[0]); @@ -103,7 +105,7 @@ bool RF95Interface::init() if (power > RF95_MAX_POWER) // This chip has lower power limits than some power = RF95_MAX_POWER; - + limitPower(); iface = lora = new RadioLibRF95(&module); @@ -116,13 +118,13 @@ bool RF95Interface::init() // enable PA #ifdef RF95_PA_EN #if defined(RF95_PA_DAC_EN) - #ifdef RADIOMASTER_900_BANDIT_NANO - // Use calculated DAC value - dacWrite(RF95_PA_EN, powerDAC); - #else - // Use Value set in /*/variant.h - dacWrite(RF95_PA_EN, RF95_PA_LEVEL); - #endif +#ifdef RADIOMASTER_900_BANDIT_NANO + // Use calculated DAC value + dacWrite(RF95_PA_EN, powerDAC); +#else + // Use Value set in /*/variant.h + dacWrite(RF95_PA_EN, RF95_PA_LEVEL); +#endif #endif #endif @@ -254,6 +256,7 @@ void RF95Interface::setStandby() isReceiving = false; // If we were receiving, not any more disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** We override to turn on transmitter power as needed. diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index a4ceac9f1..f299ebff2 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -1,6 +1,7 @@ #include "RadioLibInterface.h" #include "MeshTypes.h" #include "NodeDB.h" +#include "PowerMon.h" #include "SPILock.h" #include "configuration.h" #include "error.h" @@ -317,6 +318,7 @@ void RadioLibInterface::handleTransmitInterrupt() // ignore the transmit interrupt if (sendingPacket) completeSending(); + powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // But our transmitter is deffinitely off now } void RadioLibInterface::completeSending() @@ -412,6 +414,24 @@ void RadioLibInterface::handleReceiveInterrupt() } } +void RadioLibInterface::startReceive() +{ + isReceiving = true; + powerMon->setState(meshtastic_PowerMon_State_Lora_RXOn); +} + +void RadioLibInterface::configHardwareForSend() +{ + powerMon->setState(meshtastic_PowerMon_State_Lora_TXOn); +} + +void RadioLibInterface::setStandby() +{ + // neither sending nor receiving + powerMon->clearState(meshtastic_PowerMon_State_Lora_RXOn); + powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); +} + /** start an immediate transmit */ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp) { @@ -431,6 +451,7 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp) // This send failed, but make sure to 'complete' it properly completeSending(); + powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // Transmitter off now startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode) } diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 2c841a19e..dd01d2037 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -126,8 +126,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified * Start waiting to receive a message * * External functions can call this method to wake the device from sleep. + * Subclasses must override and call this base method */ - virtual void startReceive() = 0; + virtual void startReceive(); /** can we detect a LoRa preamble on the current channel? */ virtual bool isChannelActive() = 0; @@ -166,8 +167,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified meshtastic_QueueStatus getQueueStatus(); protected: - /** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */ - virtual void configHardwareForSend() {} + /** Do any hardware setup needed on entry into send configuration for the radio. + * Subclasses can customize, but must also call this base method */ + virtual void configHardwareForSend(); /** Could we send right now (i.e. either not actively receiving or transmitting)? */ virtual bool canSendImmediately(); @@ -186,5 +188,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0; - virtual void setStandby() = 0; + /** + * Subclasses must override, implement and then call into this base class implementation + */ + virtual void setStandby(); }; \ No newline at end of file diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index afaa13b7f..b564ba287 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -231,6 +231,7 @@ template void SX126xInterface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** @@ -270,7 +271,7 @@ template void SX126xInterface::startReceive() LOG_ERROR("Radiolib error %d when attempting SX126X startReceiveDutyCycleAuto!\n", err); assert(err == RADIOLIB_ERR_NONE); - isReceiving = true; + RadioLibInterface::startReceive(); // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index 9e4fbfa77..fdb2b9a39 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -190,6 +190,7 @@ template void SX128xInterface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** @@ -263,7 +264,7 @@ template void SX128xInterface::startReceive() LOG_ERROR("Radiolib error %d when attempting SX128X startReceive!\n", err); assert(err == RADIOLIB_ERR_NONE); - isReceiving = true; + RadioLibInterface::startReceive(); // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index ba1f5c11e..300afc246 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -27,6 +27,9 @@ #if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE #include "modules/RemoteHardwareModule.h" #endif +#if !MESHTASTIC_EXCLUDE_POWERSTRESS +#include "modules/PowerStressModule.h" +#endif #include "modules/RoutingModule.h" #include "modules/TextMessageModule.h" #if !MESHTASTIC_EXCLUDE_TRACEROUTE @@ -115,6 +118,9 @@ void setupModules() #if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE new RemoteHardwareModule(); +#endif +#if !MESHTASTIC_EXCLUDE_POWERSTRESS + new PowerStressModule(); #endif // Example: Put your module here // new ReplyModule(); diff --git a/src/modules/PowerStressModule.cpp b/src/modules/PowerStressModule.cpp new file mode 100644 index 000000000..c86017ae2 --- /dev/null +++ b/src/modules/PowerStressModule.cpp @@ -0,0 +1,77 @@ +#include "PowerStressModule.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include "main.h" + +extern void printInfo(); + +PowerStressModule::PowerStressModule() + : ProtobufModule("powerstress", meshtastic_PortNum_POWERSTRESS_APP, &meshtastic_PowerStressMessage_msg), + concurrency::OSThread("PowerStressModule") +{ +} + +bool PowerStressModule::handleReceivedProtobuf(const meshtastic_MeshPacket &req, meshtastic_PowerStressMessage *pptr) +{ + // We only respond to messages if powermon debugging is already on + if (config.power.powermon_enables) { + auto p = *pptr; + LOG_INFO("Received PowerStress cmd=%d\n", p.cmd); + + // Some commands we can handle immediately, anything else gets deferred to be handled by our thread + switch (p.cmd) { + case meshtastic_PowerStressMessage_Opcode_UNSET: + LOG_ERROR("PowerStress operation unset\n"); + break; + + case meshtastic_PowerStressMessage_Opcode_PRINT_INFO: + printInfo(); + break; + + default: + if (currentMessage.cmd != meshtastic_PowerStressMessage_Opcode_UNSET) + LOG_ERROR("PowerStress operation %d already in progress! Can't start new command\n", currentMessage.cmd); + else + currentMessage = p; // copy for use by thread (the message provided to us will be getting freed) + break; + } + } + return true; +} + +int32_t PowerStressModule::runOnce() +{ + + if (!config.power.powermon_enables) { + // Powermon not enabled - stop using CPU/stop this thread + return disable(); + } + + int32_t sleep_msec = 10; // when not active check for new messages every 10ms + + auto &p = currentMessage; + + if (isRunningCommand) { + // Done with the previous command - our sleep must have finished + p.cmd = meshtastic_PowerStressMessage_Opcode_UNSET; + p.num_seconds = 0; + } else { + sleep_msec = (int32_t)(p.num_seconds * 1000); + isRunningCommand = !!sleep_msec; // if the command wants us to sleep, make sure to mark that we have something running + + switch (p.cmd) { + case meshtastic_PowerStressMessage_Opcode_UNSET: // No need to start a new command + break; + case meshtastic_PowerStressMessage_Opcode_LED_ON: + break; + default: + LOG_ERROR("PowerStress operation %d not yet implemented!\n", p.cmd); + sleep_msec = 0; // Don't do whatever sleep was requested... + break; + } + } + return sleep_msec; +} \ No newline at end of file diff --git a/src/modules/PowerStressModule.h b/src/modules/PowerStressModule.h new file mode 100644 index 000000000..2d449f690 --- /dev/null +++ b/src/modules/PowerStressModule.h @@ -0,0 +1,38 @@ +#pragma once +#include "ProtobufModule.h" +#include "concurrency/OSThread.h" +#include "mesh/generated/meshtastic/powermon.pb.h" + +/** + * A module that provides easy low-level remote access to device hardware. + */ +class PowerStressModule : public ProtobufModule, private concurrency::OSThread +{ + meshtastic_PowerStressMessage currentMessage = meshtastic_PowerStressMessage_init_default; + bool isRunningCommand = false; + + public: + /** Constructor + * name is for debugging output + */ + PowerStressModule(); + + protected: + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_PowerStressMessage *p) override; + + /** + * Periodically read the gpios we have been asked to WATCH, if they have changed, + * broadcast a message with the change information. + * + * The method that will be called each time our thread gets a chance to run + * + * Returns desired period for next invocation (or RUN_SAME for no change) + */ + virtual int32_t runOnce() override; +}; + +extern PowerStressModule powerStressModule; \ No newline at end of file diff --git a/src/sleep.cpp b/src/sleep.cpp index 735ebcf6a..e2c9549f3 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -8,6 +8,7 @@ #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" +#include "PowerMon.h" #include "detect/LoRaRadioType.h" #include "error.h" #include "main.h" @@ -85,6 +86,11 @@ void setCPUFast(bool on) void setLed(bool ledOn) { + if (ledOn) + powerMon->setState(meshtastic_PowerMon_State_LED_On); + else + powerMon->clearState(meshtastic_PowerMon_State_LED_On); + #ifdef LED_PIN // toggle the led so we can get some rough sense of how often loop is pausing digitalWrite(LED_PIN, ledOn ^ LED_INVERTED); From 4b82634d1a7951a4ab8b0c32615640c340bb2b3e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 3 Jul 2024 22:19:01 -0500 Subject: [PATCH 5/5] Cleanup buffer --- src/RedirectablePrint.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 14264ba21..1851ffbaa 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -208,6 +208,7 @@ void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_ nrf52Bluetooth->sendLog(reinterpret_cast(buffer)); #endif delete[] message; + delete[] buffer; } } }