From 9da92626e51466b328b1d5aba1de5abf7886c2ea Mon Sep 17 00:00:00 2001 From: ford-jones Date: Thu, 11 Sep 2025 14:16:48 +1200 Subject: [PATCH 001/166] Create channel-mute toggle function --- src/mesh/Channels.cpp | 10 ++++++++++ src/mesh/Channels.h | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 70e4127d8..3ada5fa0c 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -343,6 +343,16 @@ void Channels::setChannel(const meshtastic_Channel &c) old = c; // slam in the new settings/role } +void Channels::setMute(ChannelIndex chIndex) +{ + if (chIndex < channelFile.channels_count) { + meshtastic_Channel *ch = channelFile.channels + chIndex; + ch->settings.mute = !ch->settings.mute; + } else { + LOG_ERROR("Failed to mute. Invalid channel index %d > %d", chIndex, channelFile.channels_count); + }; +}; + bool Channels::anyMqttEnabled() { #if USERPREFS_EVENT_MODE && !MESHTASTIC_EXCLUDE_MQTT diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 7873a306a..e7c6ddb78 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -47,6 +47,12 @@ class Channels */ void setChannel(const meshtastic_Channel &c); + /** + * Toggles the mute state of the channel associated with the channel index. + * I.e. if it's off turn it on and vice-versa. + */ + void setMute(ChannelIndex chIndex); + /** Return a human friendly name for this channel (and expand any short strings as needed) */ const char *getName(size_t chIndex); From 67ecb60bcd0bec5061b1d5129f92b33e6e811124 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Thu, 11 Sep 2025 14:18:00 +1200 Subject: [PATCH 002/166] Added mute state to channel settings --- protobufs | 2 +- src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/channel.pb.h | 14 +++++++++----- src/mesh/generated/meshtastic/deviceonly.pb.h | 4 ++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/protobufs b/protobufs index 8985852d7..550702a69 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 8985852d752de3f7210f9a4a3e0923120ec438b3 +Subproject commit 550702a695bc31651c758757ccf70f0fbe9cc43c diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index f4c33bd79..db9dedaaf 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 679 +#define meshtastic_ChannelSet_size 695 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index ca4310bf1..594d15929 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -97,6 +97,8 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; + /* Whether or not we should receive notifactions / alerts from this channel */ + bool mute; } meshtastic_ChannelSettings; /* A pair of a channel number, mode and the (sharable) settings for that channel */ @@ -128,10 +130,10 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default} +#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0} #define meshtastic_ModuleSettings_init_default {0, 0} #define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN} -#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero} +#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0} #define meshtastic_ModuleSettings_init_zero {0, 0} #define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN} @@ -145,6 +147,7 @@ extern "C" { #define meshtastic_ChannelSettings_uplink_enabled_tag 5 #define meshtastic_ChannelSettings_downlink_enabled_tag 6 #define meshtastic_ChannelSettings_module_settings_tag 7 +#define meshtastic_ChannelSettings_mute_tag 8 #define meshtastic_Channel_index_tag 1 #define meshtastic_Channel_settings_tag 2 #define meshtastic_Channel_role_tag 3 @@ -157,7 +160,8 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \ X(a, STATIC, SINGULAR, FIXED32, id, 4) \ X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \ -X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) +X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \ +X(a, STATIC, SINGULAR, BOOL, mute, 8) #define meshtastic_ChannelSettings_CALLBACK NULL #define meshtastic_ChannelSettings_DEFAULT NULL #define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings @@ -187,8 +191,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size -#define meshtastic_ChannelSettings_size 72 -#define meshtastic_Channel_size 87 +#define meshtastic_ChannelSettings_size 74 +#define meshtastic_Channel_size 89 #define meshtastic_ModuleSettings_size 8 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index f47091384..59c70cc9e 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -360,8 +360,8 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_NodeDatabase_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size -#define meshtastic_BackupPreferences_size 2271 -#define meshtastic_ChannelFile_size 718 +#define meshtastic_BackupPreferences_size 2287 +#define meshtastic_ChannelFile_size 734 #define meshtastic_DeviceState_size 1737 #define meshtastic_NodeInfoLite_size 196 #define meshtastic_PositionLite_size 28 From fa1ccf477989afaaef74eaa0ad3a0ce9795a391e Mon Sep 17 00:00:00 2001 From: ford-jones Date: Thu, 11 Sep 2025 17:30:59 +1200 Subject: [PATCH 003/166] Create node-mute toggle functions --- src/modules/AdminModule.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 4014e1c36..5cfdd2063 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -365,6 +365,24 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta } break; } + case meshtastic_AdminMessage_set_muted_node_tag: { + LOG_INFO("Client received set_muted_node command"); + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->set_muted_node); + if (node != NULL) { + node->is_muted = true; + saveChanges(SEGMENT_NODEDATABASE, false); + } + break; + } + case meshtastic_AdminMessage_remove_muted_node_tag: { + LOG_INFO("Client received remove_muted_node command"); + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->remove_muted_node); + if (node != NULL) { + node->is_muted = false; + saveChanges(SEGMENT_NODEDATABASE, false); + } + break; + } case meshtastic_AdminMessage_set_fixed_position_tag: { LOG_INFO("Client received set_fixed_position command"); meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum()); From 6b7ad9c4e187180fb46e319a1510972fbf08e636 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Thu, 11 Sep 2025 17:32:12 +1200 Subject: [PATCH 004/166] Added mute state to nodedb entries --- protobufs | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 8 ++++++++ src/mesh/generated/meshtastic/deviceonly.pb.h | 19 ++++++++++++------- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/protobufs b/protobufs index 550702a69..638917dea 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 550702a695bc31651c758757ccf70f0fbe9cc43c +Subproject commit 638917dea8bb36b2823261c9fbc87430c859b3c3 diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index bc0b780b9..616b7e8ee 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -247,6 +247,10 @@ typedef struct _meshtastic_AdminMessage { uint32_t set_ignored_node; /* Set specified node-num to be un-ignored on the NodeDB on the device */ uint32_t remove_ignored_node; + /* Set specified node-num to be muted */ + uint32_t set_muted_node; + /* Set specified node-num to be heard / not-muted */ + uint32_t remove_muted_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -388,6 +392,8 @@ extern "C" { #define meshtastic_AdminMessage_store_ui_config_tag 46 #define meshtastic_AdminMessage_set_ignored_node_tag 47 #define meshtastic_AdminMessage_remove_ignored_node_tag 48 +#define meshtastic_AdminMessage_set_muted_node_tag 49 +#define meshtastic_AdminMessage_remove_muted_node_tag 50 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 @@ -446,6 +452,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,set_muted_node,set_muted_node), 49) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_muted_node,remove_muted_node), 50) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 59c70cc9e..55c433699 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -94,6 +94,9 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; + /* True if node has been muted + Persists between NodeDB internal clean ups */ + bool is_muted; /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ uint8_t next_hop; /* Bitfield for storing booleans. @@ -190,14 +193,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_NodeDatabase_init_default {0, {0}} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_BackupPreferences_init_default {0, 0, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default, false, meshtastic_ChannelFile_init_default, false, meshtastic_User_init_default} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_NodeDatabase_init_zero {0, {0}} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} @@ -228,8 +231,9 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 -#define meshtastic_NodeInfoLite_next_hop_tag 12 -#define meshtastic_NodeInfoLite_bitfield_tag 13 +#define meshtastic_NodeInfoLite_is_muted_tag 12 +#define meshtastic_NodeInfoLite_next_hop_tag 13 +#define meshtastic_NodeInfoLite_bitfield_tag 14 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -284,8 +288,9 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 12) \ -X(a, STATIC, SINGULAR, UINT32, bitfield, 13) +X(a, STATIC, SINGULAR, BOOL, is_muted, 12) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 13) \ +X(a, STATIC, SINGULAR, UINT32, bitfield, 14) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -363,7 +368,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; #define meshtastic_BackupPreferences_size 2287 #define meshtastic_ChannelFile_size 734 #define meshtastic_DeviceState_size 1737 -#define meshtastic_NodeInfoLite_size 196 +#define meshtastic_NodeInfoLite_size 198 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 98 From 1594421214cf287ad9cc3672966e4567a5129ded Mon Sep 17 00:00:00 2001 From: ford-jones Date: Thu, 11 Sep 2025 21:49:25 +1200 Subject: [PATCH 005/166] Rebase protos --- protobufs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 638917dea..a8f3ee5b0 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 638917dea8bb36b2823261c9fbc87430c859b3c3 +Subproject commit a8f3ee5b016688fc9a4ac5e11cf317feab9718bf From a31fdf01ced293ac4077e388f353a75e2d36c068 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Thu, 11 Sep 2025 22:23:42 +1200 Subject: [PATCH 006/166] Decouple protobuf changes --- protobufs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protobufs b/protobufs index a8f3ee5b0..4c4427c4a 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit a8f3ee5b016688fc9a4ac5e11cf317feab9718bf +Subproject commit 4c4427c4a73c86fed7dc8632188bb8be95349d81 From d5300a11410f220f2068ab80b1ec6f9c6b394926 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Fri, 12 Sep 2025 13:54:52 +1200 Subject: [PATCH 007/166] Disable bell-invoked ext notifs for muted nodes --- src/modules/ExternalNotificationModule.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 2f2934984..b73547c02 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -506,8 +506,9 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } } + meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from); - if (moduleConfig.external_notification.alert_message) { + if (moduleConfig.external_notification.alert_message && !sender->is_muted) { LOG_INFO("externalNotificationModule - Notification Module"); isNagging = true; setExternalState(0, true); @@ -518,7 +519,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_vibra) { + if (moduleConfig.external_notification.alert_message_vibra && !sender->is_muted) { LOG_INFO("externalNotificationModule - Notification Module (Vibra)"); isNagging = true; setExternalState(1, true); @@ -529,7 +530,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_buzzer) { + if (moduleConfig.external_notification.alert_message_buzzer && !sender->is_muted) { LOG_INFO("externalNotificationModule - Notification Module (Buzzer)"); isNagging = true; if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) { From 8c9c00172cdf5f7bb2d78f4f370198a95f5843d9 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Fri, 12 Sep 2025 14:12:22 +1200 Subject: [PATCH 008/166] Clearly dilineate module mute from sender or channel mute --- src/modules/ExternalNotificationModule.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/ExternalNotificationModule.h b/src/modules/ExternalNotificationModule.h index 19cf9eb7b..f667f7be9 100644 --- a/src/modules/ExternalNotificationModule.h +++ b/src/modules/ExternalNotificationModule.h @@ -43,8 +43,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency: void setExternalState(uint8_t index = 0, bool on = false); bool getExternal(uint8_t index = 0); - void setMute(bool mute) { isMuted = mute; } - bool getMute() { return isMuted; } + void setMute(bool mute) { isSilenced = mute; } + bool getMute() { return isSilenced; } bool canBuzz(); bool nagging(); @@ -67,7 +67,7 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency: bool isNagging = false; - bool isMuted = false; + bool isSilenced = false; virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, From 4e879a7b261e38fc6ef3f0bc9286229aa7e82f0a Mon Sep 17 00:00:00 2001 From: ford-jones Date: Fri, 12 Sep 2025 14:12:55 +1200 Subject: [PATCH 009/166] Disable bell-invoked ext notifs for muted channels --- src/modules/ExternalNotificationModule.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index b73547c02..c54306ffd 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -440,7 +440,7 @@ ExternalNotificationModule::ExternalNotificationModule() ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshPacket &mp) { - if (moduleConfig.external_notification.enabled && !isMuted) { + if (moduleConfig.external_notification.enabled && !isSilenced) { #ifdef T_WATCH_S3 drv.setWaveform(0, 75); drv.setWaveform(1, 56); @@ -506,9 +506,11 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } } - meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from); - if (moduleConfig.external_notification.alert_message && !sender->is_muted) { + meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from); + meshtastic_Channel ch = channels.getByIndex(sender->channel ? sender->channel : channels.getPrimaryIndex()); + + if (moduleConfig.external_notification.alert_message && !sender->is_muted && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module"); isNagging = true; setExternalState(0, true); @@ -519,7 +521,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_vibra && !sender->is_muted) { + if (moduleConfig.external_notification.alert_message_vibra && !sender->is_muted && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module (Vibra)"); isNagging = true; setExternalState(1, true); @@ -530,7 +532,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_buzzer && !sender->is_muted) { + if (moduleConfig.external_notification.alert_message_buzzer && !sender->is_muted && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module (Buzzer)"); isNagging = true; if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) { From 71f659cba6c26503a6881a54b98910cfc0dbb4f8 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Fri, 12 Sep 2025 14:15:06 +1200 Subject: [PATCH 010/166] Trunk fmt --- src/SerialConsole.cpp | 7 +++---- src/mesh/StreamAPI.h | 6 +++--- variants/esp32s3/t-deck-pro/variant.h | 15 +++++++------ .../nrf52840/heltec_mesh_solar/variant.cpp | 2 +- variants/nrf52840/heltec_mesh_solar/variant.h | 21 +++++++++---------- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 093a24678..2e6ae68a5 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -65,10 +65,9 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con int32_t SerialConsole::runOnce() { #ifdef HELTEC_MESH_SOLAR - //After enabling the mesh solar serial port module configuration, command processing is handled by the serial port module. - if(moduleConfig.serial.enabled && moduleConfig.serial.override_console_serial_port - && moduleConfig.serial.mode==meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG) - { + // After enabling the mesh solar serial port module configuration, command processing is handled by the serial port module. + if (moduleConfig.serial.enabled && moduleConfig.serial.override_console_serial_port && + moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG) { return 250; } #endif diff --git a/src/mesh/StreamAPI.h b/src/mesh/StreamAPI.h index 547dd0175..4ca2c197f 100644 --- a/src/mesh/StreamAPI.h +++ b/src/mesh/StreamAPI.h @@ -50,15 +50,15 @@ class StreamAPI : public PhoneAPI * phone. */ virtual int32_t runOncePart(); - virtual int32_t runOncePart(char *buf,uint16_t bufLen); + virtual int32_t runOncePart(char *buf, uint16_t bufLen); private: /** * Read any rx chars from the link and call handleToRadio */ int32_t readStream(); - int32_t readStream(char *buf,uint16_t bufLen); - int32_t handleRecStream(char *buf,uint16_t bufLen); + int32_t readStream(char *buf, uint16_t bufLen); + int32_t handleRecStream(char *buf, uint16_t bufLen); /** * call getFromRadio() and deliver encapsulated packets to the Stream diff --git a/variants/esp32s3/t-deck-pro/variant.h b/variants/esp32s3/t-deck-pro/variant.h index abe0a772a..35cb99435 100644 --- a/variants/esp32s3/t-deck-pro/variant.h +++ b/variants/esp32s3/t-deck-pro/variant.h @@ -93,11 +93,10 @@ // Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface // code) -#define MODEM_POWER_EN 41 -#define MODEM_PWRKEY 40 -#define MODEM_RST 9 -#define MODEM_RI 7 -#define MODEM_DTR 8 -#define MODEM_RX 10 -#define MODEM_TX 11 - +#define MODEM_POWER_EN 41 +#define MODEM_PWRKEY 40 +#define MODEM_RST 9 +#define MODEM_RI 7 +#define MODEM_DTR 8 +#define MODEM_RX 10 +#define MODEM_TX 11 diff --git a/variants/nrf52840/heltec_mesh_solar/variant.cpp b/variants/nrf52840/heltec_mesh_solar/variant.cpp index 8236d7cf4..05d7a32e2 100644 --- a/variants/nrf52840/heltec_mesh_solar/variant.cpp +++ b/variants/nrf52840/heltec_mesh_solar/variant.cpp @@ -32,5 +32,5 @@ const uint32_t g_ADigitalPinMap[] = { void initVariant() { - pinMode(BQ4050_EMERGENCY_SHUTDOWN_PIN, INPUT); + pinMode(BQ4050_EMERGENCY_SHUTDOWN_PIN, INPUT); } diff --git a/variants/nrf52840/heltec_mesh_solar/variant.h b/variants/nrf52840/heltec_mesh_solar/variant.h index 33c2b2556..4165bc349 100644 --- a/variants/nrf52840/heltec_mesh_solar/variant.h +++ b/variants/nrf52840/heltec_mesh_solar/variant.h @@ -39,16 +39,15 @@ extern "C" { #define NUM_ANALOG_INPUTS (1) #define NUM_ANALOG_OUTPUTS (0) - #define PIN_LED1 (0 + 12) // green (confirmed on 1.0 board) #define LED_BLUE PIN_LED1 // fake for bluefruit library #define LED_GREEN PIN_LED1 #define LED_BUILTIN LED_GREEN -#define LED_STATE_ON 0 // State when LED is lit +#define LED_STATE_ON 0 // State when LED is lit #define HAS_NEOPIXEL // Enable the use of neopixels #define NEOPIXEL_COUNT 1 // How many neopixels are connected -#define NEOPIXEL_DATA (32+15) // gpio pin used to send data to the neopixels +#define NEOPIXEL_DATA (32 + 15) // gpio pin used to send data to the neopixels #define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use /* @@ -74,13 +73,13 @@ No longer populated on PCB // I2C bus 0 // Routed to footprint for PCF8563TS RTC // Not populated on T114 V1, maybe in future? -#define PIN_WIRE_SDA (0 + 6) // P0.26 +#define PIN_WIRE_SDA (0 + 6) // P0.26 #define PIN_WIRE_SCL (0 + 26) // P0.26 // I2C bus 1 // Available on header pins, for general use #define PIN_WIRE1_SDA (0 + 30) // P0.30 -#define PIN_WIRE1_SCL (0 + 5) // P0.13 +#define PIN_WIRE1_SCL (0 + 5) // P0.13 /* * Lora radio @@ -89,14 +88,14 @@ No longer populated on PCB #define USE_SX1262 // #define USE_SX1268 #define SX126X_CS (0 + 24) // FIXME - we really should define LORA_CS instead -#define LORA_CS (0 + 24) +#define LORA_CS (0 + 24) #define SX126X_DIO1 (0 + 20) // Note DIO2 is attached internally to the module to an analog switch for TX/RX switching // #define SX1262_DIO3 (0 + 21) // This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the // main // CPU? -#define SX126X_BUSY (0 + 17) +#define SX126X_BUSY (0 + 17) #define SX126X_RESET (0 + 25) // Not really an E22 but TTGO seems to be trying to clone that #define SX126X_DIO2_AS_RF_SWITCH @@ -134,16 +133,16 @@ No longer populated on PCB // For LORA, spi 0 #define PIN_SPI_MISO (0 + 23) #define PIN_SPI_MOSI (0 + 22) -#define PIN_SPI_SCK (0 + 19) +#define PIN_SPI_SCK (0 + 19) // #define PIN_PWR_EN (0 + 6) // To debug via the segger JLINK console rather than the CDC-ACM serial device // #define USE_SEGGER -#define BQ4050_SDA_PIN (32+1) // I2C data line pin -#define BQ4050_SCL_PIN (32+0) // I2C clock line pin -#define BQ4050_EMERGENCY_SHUTDOWN_PIN (32+3) // Emergency shutdown pin +#define BQ4050_SDA_PIN (32 + 1) // I2C data line pin +#define BQ4050_SCL_PIN (32 + 0) // I2C clock line pin +#define BQ4050_EMERGENCY_SHUTDOWN_PIN (32 + 3) // Emergency shutdown pin #define HAS_RTC 0 #ifdef __cplusplus From 693181b2be40a2280f4a1984313aeb7394bf068a Mon Sep 17 00:00:00 2001 From: ford-jones Date: Fri, 12 Sep 2025 15:44:37 +1200 Subject: [PATCH 011/166] Disable message-invoked ext notifs for muted channels and nodes --- src/modules/ExternalNotificationModule.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index c54306ffd..4dd8811ec 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -457,7 +457,10 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_bell) { + meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from); + meshtastic_Channel ch = channels.getByIndex(sender->channel ? sender->channel : channels.getPrimaryIndex()); + + if (moduleConfig.external_notification.alert_bell && !sender->is_muted && !ch.settings.mute) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell"); isNagging = true; @@ -470,7 +473,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_bell_vibra) { + if (moduleConfig.external_notification.alert_bell_vibra && !sender->is_muted && !ch.settings.mute) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell (Vibra)"); isNagging = true; @@ -483,7 +486,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_bell_buzzer && canBuzz()) { + if (moduleConfig.external_notification.alert_bell_buzzer && canBuzz() && !sender->is_muted && !ch.settings.mute) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell (Buzzer)"); isNagging = true; @@ -507,9 +510,6 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from); - meshtastic_Channel ch = channels.getByIndex(sender->channel ? sender->channel : channels.getPrimaryIndex()); - if (moduleConfig.external_notification.alert_message && !sender->is_muted && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module"); isNagging = true; From 5579d87845f0063af1e50daf8d81ebd231a3f0ce Mon Sep 17 00:00:00 2001 From: ford-jones Date: Fri, 12 Sep 2025 19:52:34 +1200 Subject: [PATCH 012/166] Disable on-screen 'new message' popup for muted nodes and channels --- src/graphics/Screen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index eb8093947..e688b2ccc 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1419,6 +1419,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) } // === Prepare banner content === const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from); + const meshtastic_Channel channel = channels.getByIndex(node->channel ? node->channel : channels.getPrimaryIndex()); const char *longName = (node && node->has_user) ? node->user.long_name : nullptr; const char *msgRaw = reinterpret_cast(packet->decoded.payload.bytes); @@ -1440,15 +1441,14 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) } else { strcpy(banner, "Alert Received"); } - } else { + } else if (!node->is_muted && !channel.settings.mute) { if (longName && longName[0]) { snprintf(banner, sizeof(banner), "New Message from\n%s", longName); } else { strcpy(banner, "New Message"); } + screen->showSimpleBanner(banner, 3000); } - - screen->showSimpleBanner(banner, 3000); } } From e0890b2a1328321d7728179d3e891d9f64f37ff5 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Fri, 12 Sep 2025 23:01:42 +1200 Subject: [PATCH 013/166] Don't mute alerts --- src/graphics/Screen.cpp | 22 ++++++++++++++-------- src/modules/ExternalNotificationModule.cpp | 8 ++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index e688b2ccc..9a82d572a 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -95,7 +95,7 @@ namespace graphics #define NUM_EXTRA_FRAMES 3 // text message and debug frame // if defined a pixel will blink to show redraws // #define SHOW_REDRAWS - +#define ASCII_BELL '\x07' // A text message frame + debug frame + all the node infos FrameCallback *normalFrames; static uint32_t targetFramerate = IDLE_FRAMERATE; @@ -1426,21 +1426,27 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) char banner[256]; - // Check for bell character in message to determine alert type bool isAlert = false; - for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) { - if (msgRaw[i] == '\x07') { - isAlert = true; - break; - } - } + if (moduleConfig.external_notification.alert_bell || moduleConfig.external_notification.alert_bell_vibra || + moduleConfig.external_notification.alert_bell_buzzer) + // Check for bell character to determine if this message is an alert + for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) { + if (msgRaw[i] == ASCII_BELL) { + isAlert = true; + break; + } + } + + // Unlike generic messages, alerts (when enabled via the ext notif module) ignore any + // 'mute' preferences set to any specific node or channel. if (isAlert) { if (longName && longName[0]) { snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName); } else { strcpy(banner, "Alert Received"); } + screen->showSimpleBanner(banner, 3000); } else if (!node->is_muted && !channel.settings.mute) { if (longName && longName[0]) { snprintf(banner, sizeof(banner), "New Message from\n%s", longName); diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 4dd8811ec..92590f149 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -451,7 +451,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP // Check if the message contains a bell character. Don't do this loop for every pin, just once. auto &p = mp.decoded; bool containsBell = false; - for (int i = 0; i < p.payload.size; i++) { + for (size_t i = 0; i < p.payload.size; i++) { if (p.payload.bytes[i] == ASCII_BELL) { containsBell = true; } @@ -460,7 +460,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from); meshtastic_Channel ch = channels.getByIndex(sender->channel ? sender->channel : channels.getPrimaryIndex()); - if (moduleConfig.external_notification.alert_bell && !sender->is_muted && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_bell) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell"); isNagging = true; @@ -473,7 +473,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_bell_vibra && !sender->is_muted && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_bell_vibra) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell (Vibra)"); isNagging = true; @@ -486,7 +486,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_bell_buzzer && canBuzz() && !sender->is_muted && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_bell_buzzer && canBuzz()) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell (Buzzer)"); isNagging = true; From ccff2769fedac1d43056c41ef29721946ee1bf5d Mon Sep 17 00:00:00 2001 From: ford-jones Date: Sat, 13 Sep 2025 13:39:32 +1200 Subject: [PATCH 014/166] Make use of pre-existing channel_settings.module_settings.is_client_muted setting --- src/graphics/Screen.cpp | 2 +- src/mesh/Channels.cpp | 2 +- src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/channel.pb.h | 14 +++++--------- src/mesh/generated/meshtastic/deviceonly.pb.h | 4 ++-- src/modules/ExternalNotificationModule.cpp | 9 ++++++--- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 9a82d572a..5150a19ee 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1447,7 +1447,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) strcpy(banner, "Alert Received"); } screen->showSimpleBanner(banner, 3000); - } else if (!node->is_muted && !channel.settings.mute) { + } else if (!node->is_muted && !channel.settings.module_settings.is_client_muted) { if (longName && longName[0]) { snprintf(banner, sizeof(banner), "New Message from\n%s", longName); } else { diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index affe05285..2eaafe39c 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -347,7 +347,7 @@ void Channels::setMute(ChannelIndex chIndex) { if (chIndex < channelFile.channels_count) { meshtastic_Channel *ch = channelFile.channels + chIndex; - ch->settings.mute = !ch->settings.mute; + ch->settings.module_settings.is_client_muted = !ch->settings.module_settings.is_client_muted; } else { LOG_ERROR("Failed to mute. Invalid channel index %d > %d", chIndex, channelFile.channels_count); }; diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index db9dedaaf..f4c33bd79 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 695 +#define meshtastic_ChannelSet_size 679 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index 594d15929..ca4310bf1 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -97,8 +97,6 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; - /* Whether or not we should receive notifactions / alerts from this channel */ - bool mute; } meshtastic_ChannelSettings; /* A pair of a channel number, mode and the (sharable) settings for that channel */ @@ -130,10 +128,10 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0} +#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default} #define meshtastic_ModuleSettings_init_default {0, 0} #define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN} -#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0} +#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero} #define meshtastic_ModuleSettings_init_zero {0, 0} #define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN} @@ -147,7 +145,6 @@ extern "C" { #define meshtastic_ChannelSettings_uplink_enabled_tag 5 #define meshtastic_ChannelSettings_downlink_enabled_tag 6 #define meshtastic_ChannelSettings_module_settings_tag 7 -#define meshtastic_ChannelSettings_mute_tag 8 #define meshtastic_Channel_index_tag 1 #define meshtastic_Channel_settings_tag 2 #define meshtastic_Channel_role_tag 3 @@ -160,8 +157,7 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \ X(a, STATIC, SINGULAR, FIXED32, id, 4) \ X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \ -X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \ -X(a, STATIC, SINGULAR, BOOL, mute, 8) +X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) #define meshtastic_ChannelSettings_CALLBACK NULL #define meshtastic_ChannelSettings_DEFAULT NULL #define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings @@ -191,8 +187,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size -#define meshtastic_ChannelSettings_size 74 -#define meshtastic_Channel_size 89 +#define meshtastic_ChannelSettings_size 72 +#define meshtastic_Channel_size 87 #define meshtastic_ModuleSettings_size 8 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 55c433699..4f6e6a106 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -365,8 +365,8 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_NodeDatabase_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size -#define meshtastic_BackupPreferences_size 2287 -#define meshtastic_ChannelFile_size 734 +#define meshtastic_BackupPreferences_size 2271 +#define meshtastic_ChannelFile_size 718 #define meshtastic_DeviceState_size 1737 #define meshtastic_NodeInfoLite_size 198 #define meshtastic_PositionLite_size 28 diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 92590f149..28e451f49 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -510,7 +510,8 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message && !sender->is_muted && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_message && !sender->is_muted && + !ch.settings.module_settings.is_client_muted) { LOG_INFO("externalNotificationModule - Notification Module"); isNagging = true; setExternalState(0, true); @@ -521,7 +522,8 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_vibra && !sender->is_muted && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_message_vibra && !sender->is_muted && + !ch.settings.module_settings.is_client_muted) { LOG_INFO("externalNotificationModule - Notification Module (Vibra)"); isNagging = true; setExternalState(1, true); @@ -532,7 +534,8 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_buzzer && !sender->is_muted && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_message_buzzer && !sender->is_muted && + !ch.settings.module_settings.is_client_muted) { LOG_INFO("externalNotificationModule - Notification Module (Buzzer)"); isNagging = true; if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) { From f8d44f8f6cd79c9c443cebd72bdd9f4be1b2c9e0 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Sat, 13 Sep 2025 17:45:07 +1200 Subject: [PATCH 015/166] Revert previous commit - this needs it's own proto --- src/graphics/Screen.cpp | 2 +- src/mesh/Channels.cpp | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 8 ------- src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/channel.pb.h | 16 +++++++++---- src/mesh/generated/meshtastic/deviceonly.pb.h | 23 ++++++++----------- src/modules/ExternalNotificationModule.cpp | 9 +++----- 7 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 5150a19ee..9a82d572a 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1447,7 +1447,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) strcpy(banner, "Alert Received"); } screen->showSimpleBanner(banner, 3000); - } else if (!node->is_muted && !channel.settings.module_settings.is_client_muted) { + } else if (!node->is_muted && !channel.settings.mute) { if (longName && longName[0]) { snprintf(banner, sizeof(banner), "New Message from\n%s", longName); } else { diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 2eaafe39c..affe05285 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -347,7 +347,7 @@ void Channels::setMute(ChannelIndex chIndex) { if (chIndex < channelFile.channels_count) { meshtastic_Channel *ch = channelFile.channels + chIndex; - ch->settings.module_settings.is_client_muted = !ch->settings.module_settings.is_client_muted; + ch->settings.mute = !ch->settings.mute; } else { LOG_ERROR("Failed to mute. Invalid channel index %d > %d", chIndex, channelFile.channels_count); }; diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index 616b7e8ee..bc0b780b9 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -247,10 +247,6 @@ typedef struct _meshtastic_AdminMessage { uint32_t set_ignored_node; /* Set specified node-num to be un-ignored on the NodeDB on the device */ uint32_t remove_ignored_node; - /* Set specified node-num to be muted */ - uint32_t set_muted_node; - /* Set specified node-num to be heard / not-muted */ - uint32_t remove_muted_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -392,8 +388,6 @@ extern "C" { #define meshtastic_AdminMessage_store_ui_config_tag 46 #define meshtastic_AdminMessage_set_ignored_node_tag 47 #define meshtastic_AdminMessage_remove_ignored_node_tag 48 -#define meshtastic_AdminMessage_set_muted_node_tag 49 -#define meshtastic_AdminMessage_remove_muted_node_tag 50 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 @@ -452,8 +446,6 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ -X(a, STATIC, ONEOF, UINT32, (payload_variant,set_muted_node,set_muted_node), 49) \ -X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_muted_node,remove_muted_node), 50) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index f4c33bd79..db9dedaaf 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 679 +#define meshtastic_ChannelSet_size 695 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index ca4310bf1..7331109a3 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -97,6 +97,10 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; + /* Whether or not we should receive notifactions / alerts through this channel + Note: This is NOT the same as module_settings.is_client_mute which pertains + to the device role. */ + bool mute; } meshtastic_ChannelSettings; /* A pair of a channel number, mode and the (sharable) settings for that channel */ @@ -128,10 +132,10 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default} +#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0} #define meshtastic_ModuleSettings_init_default {0, 0} #define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN} -#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero} +#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0} #define meshtastic_ModuleSettings_init_zero {0, 0} #define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN} @@ -145,6 +149,7 @@ extern "C" { #define meshtastic_ChannelSettings_uplink_enabled_tag 5 #define meshtastic_ChannelSettings_downlink_enabled_tag 6 #define meshtastic_ChannelSettings_module_settings_tag 7 +#define meshtastic_ChannelSettings_mute_tag 8 #define meshtastic_Channel_index_tag 1 #define meshtastic_Channel_settings_tag 2 #define meshtastic_Channel_role_tag 3 @@ -157,7 +162,8 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \ X(a, STATIC, SINGULAR, FIXED32, id, 4) \ X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \ -X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) +X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \ +X(a, STATIC, SINGULAR, BOOL, mute, 8) #define meshtastic_ChannelSettings_CALLBACK NULL #define meshtastic_ChannelSettings_DEFAULT NULL #define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings @@ -187,8 +193,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size -#define meshtastic_ChannelSettings_size 72 -#define meshtastic_Channel_size 87 +#define meshtastic_ChannelSettings_size 74 +#define meshtastic_Channel_size 89 #define meshtastic_ModuleSettings_size 8 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 4f6e6a106..59c70cc9e 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -94,9 +94,6 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; - /* True if node has been muted - Persists between NodeDB internal clean ups */ - bool is_muted; /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ uint8_t next_hop; /* Bitfield for storing booleans. @@ -193,14 +190,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_NodeDatabase_init_default {0, {0}} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_BackupPreferences_init_default {0, 0, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default, false, meshtastic_ChannelFile_init_default, false, meshtastic_User_init_default} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_NodeDatabase_init_zero {0, {0}} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} @@ -231,9 +228,8 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 -#define meshtastic_NodeInfoLite_is_muted_tag 12 -#define meshtastic_NodeInfoLite_next_hop_tag 13 -#define meshtastic_NodeInfoLite_bitfield_tag 14 +#define meshtastic_NodeInfoLite_next_hop_tag 12 +#define meshtastic_NodeInfoLite_bitfield_tag 13 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -288,9 +284,8 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, BOOL, is_muted, 12) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 13) \ -X(a, STATIC, SINGULAR, UINT32, bitfield, 14) +X(a, STATIC, SINGULAR, UINT32, next_hop, 12) \ +X(a, STATIC, SINGULAR, UINT32, bitfield, 13) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -365,10 +360,10 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_NodeDatabase_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size -#define meshtastic_BackupPreferences_size 2271 -#define meshtastic_ChannelFile_size 718 +#define meshtastic_BackupPreferences_size 2287 +#define meshtastic_ChannelFile_size 734 #define meshtastic_DeviceState_size 1737 -#define meshtastic_NodeInfoLite_size 198 +#define meshtastic_NodeInfoLite_size 196 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 98 diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 28e451f49..92590f149 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -510,8 +510,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message && !sender->is_muted && - !ch.settings.module_settings.is_client_muted) { + if (moduleConfig.external_notification.alert_message && !sender->is_muted && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module"); isNagging = true; setExternalState(0, true); @@ -522,8 +521,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_vibra && !sender->is_muted && - !ch.settings.module_settings.is_client_muted) { + if (moduleConfig.external_notification.alert_message_vibra && !sender->is_muted && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module (Vibra)"); isNagging = true; setExternalState(1, true); @@ -534,8 +532,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_buzzer && !sender->is_muted && - !ch.settings.module_settings.is_client_muted) { + if (moduleConfig.external_notification.alert_message_buzzer && !sender->is_muted && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module (Buzzer)"); isNagging = true; if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) { From bfadd9c866fa60f4cd5bf1eeea2fc273502b21ec Mon Sep 17 00:00:00 2001 From: ford-jones Date: Sat, 13 Sep 2025 17:51:52 +1200 Subject: [PATCH 016/166] Regen protos --- src/mesh/generated/meshtastic/admin.pb.h | 8 ++++++++ src/mesh/generated/meshtastic/channel.pb.h | 2 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 19 ++++++++++++------- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index bc0b780b9..616b7e8ee 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -247,6 +247,10 @@ typedef struct _meshtastic_AdminMessage { uint32_t set_ignored_node; /* Set specified node-num to be un-ignored on the NodeDB on the device */ uint32_t remove_ignored_node; + /* Set specified node-num to be muted */ + uint32_t set_muted_node; + /* Set specified node-num to be heard / not-muted */ + uint32_t remove_muted_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -388,6 +392,8 @@ extern "C" { #define meshtastic_AdminMessage_store_ui_config_tag 46 #define meshtastic_AdminMessage_set_ignored_node_tag 47 #define meshtastic_AdminMessage_remove_ignored_node_tag 48 +#define meshtastic_AdminMessage_set_muted_node_tag 49 +#define meshtastic_AdminMessage_remove_muted_node_tag 50 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 @@ -446,6 +452,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,set_muted_node,set_muted_node), 49) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_muted_node,remove_muted_node), 50) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index 7331109a3..1e1b95df7 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -98,7 +98,7 @@ typedef struct _meshtastic_ChannelSettings { bool has_module_settings; meshtastic_ModuleSettings module_settings; /* Whether or not we should receive notifactions / alerts through this channel - Note: This is NOT the same as module_settings.is_client_mute which pertains + Note: This is NOT the same as module_settings.is_client_mute which pertains to the device role. */ bool mute; } meshtastic_ChannelSettings; diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 59c70cc9e..55c433699 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -94,6 +94,9 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; + /* True if node has been muted + Persists between NodeDB internal clean ups */ + bool is_muted; /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ uint8_t next_hop; /* Bitfield for storing booleans. @@ -190,14 +193,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_NodeDatabase_init_default {0, {0}} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_BackupPreferences_init_default {0, 0, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default, false, meshtastic_ChannelFile_init_default, false, meshtastic_User_init_default} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_NodeDatabase_init_zero {0, {0}} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} @@ -228,8 +231,9 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 -#define meshtastic_NodeInfoLite_next_hop_tag 12 -#define meshtastic_NodeInfoLite_bitfield_tag 13 +#define meshtastic_NodeInfoLite_is_muted_tag 12 +#define meshtastic_NodeInfoLite_next_hop_tag 13 +#define meshtastic_NodeInfoLite_bitfield_tag 14 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -284,8 +288,9 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 12) \ -X(a, STATIC, SINGULAR, UINT32, bitfield, 13) +X(a, STATIC, SINGULAR, BOOL, is_muted, 12) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 13) \ +X(a, STATIC, SINGULAR, UINT32, bitfield, 14) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -363,7 +368,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; #define meshtastic_BackupPreferences_size 2287 #define meshtastic_ChannelFile_size 734 #define meshtastic_DeviceState_size 1737 -#define meshtastic_NodeInfoLite_size 196 +#define meshtastic_NodeInfoLite_size 198 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 98 From 3d86c99c259a91da4c32d832b8f290a9ee6534b8 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Fri, 12 Sep 2025 05:53:35 +0200 Subject: [PATCH 017/166] T-Lora Pager: Interrupt based rotary encoder --- src/input/RotaryEncoderImpl.cpp | 65 +++++++++++++++------ src/input/RotaryEncoderImpl.h | 7 +++ variants/esp32s3/tlora-pager/platformio.ini | 4 +- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/input/RotaryEncoderImpl.cpp b/src/input/RotaryEncoderImpl.cpp index 7d638dd71..cede1b87c 100644 --- a/src/input/RotaryEncoderImpl.cpp +++ b/src/input/RotaryEncoderImpl.cpp @@ -6,6 +6,8 @@ #define ORIGIN_NAME "RotaryEncoder" +#define ROTARY_INTERRUPT_FLAG _BV(0) + RotaryEncoderImpl *rotaryEncoderImpl; RotaryEncoderImpl::RotaryEncoderImpl() : concurrency::OSThread(ORIGIN_NAME), originName(ORIGIN_NAME) @@ -30,6 +32,17 @@ bool RotaryEncoderImpl::init() moduleConfig.canned_message.inputbroker_pin_press); rotary->resetButton(); + inputQueue = xQueueCreate(5, sizeof(input_broker_event)); + interruptFlag = xEventGroupCreate(); + interruptInstance = this; + auto interruptHandler = []() { + xEventGroupSetBits(interruptInstance->interruptFlag, ROTARY_INTERRUPT_FLAG); + }; + attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE); + attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE); + attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE); + xTaskCreate(inputWorker, "rotary", 2 * 1024, this, 10, &inputWorkerTask); + inputBroker->registerSource(this); LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a, @@ -38,35 +51,49 @@ bool RotaryEncoderImpl::init() return true; } -int32_t RotaryEncoderImpl::runOnce() +void RotaryEncoderImpl::dispatchInputs() { - InputEvent e{originName, INPUT_BROKER_NONE, 0, 0, 0}; static uint32_t lastPressed = millis(); if (rotary->readButton() == RotaryEncoder::ButtonState::BUTTON_PRESSED) { if (lastPressed + 200 < millis()) { - LOG_DEBUG("Rotary event Press"); + // LOG_DEBUG("Rotary event Press"); lastPressed = millis(); - e.inputEvent = this->eventPressed; - } - } else { - switch (rotary->process()) { - case RotaryEncoder::DIRECTION_CW: - LOG_DEBUG("Rotary event CW"); - e.inputEvent = this->eventCw; - break; - case RotaryEncoder::DIRECTION_CCW: - LOG_DEBUG("Rotary event CCW"); - e.inputEvent = this->eventCcw; - break; - default: - break; + xQueueSend(inputQueue, &this->eventPressed, portMAX_DELAY); } } - if (e.inputEvent != INPUT_BROKER_NONE) { + switch (rotary->process()) { + case RotaryEncoder::DIRECTION_CW: + // LOG_DEBUG("Rotary event CW"); + xQueueSend(inputQueue, &this->eventCw, portMAX_DELAY); + break; + case RotaryEncoder::DIRECTION_CCW: + // LOG_DEBUG("Rotary event CCW"); + xQueueSend(inputQueue, &this->eventCcw, portMAX_DELAY); + break; + default: + break; + } +} + +void RotaryEncoderImpl::inputWorker(void *p) +{ + RotaryEncoderImpl* instance = (RotaryEncoderImpl*)p; + while (true) { + xEventGroupWaitBits(instance->interruptFlag, ROTARY_INTERRUPT_FLAG, pdTRUE, pdTRUE, portMAX_DELAY); + instance->dispatchInputs(); + } + vTaskDelete(NULL); +} + +RotaryEncoderImpl* RotaryEncoderImpl::interruptInstance; + +int32_t RotaryEncoderImpl::runOnce() +{ + InputEvent e{originName, INPUT_BROKER_NONE, 0, 0, 0}; + while(xQueueReceive(inputQueue, &e.inputEvent, 0) == pdPASS) { this->notifyObservers(&e); } - return 10; } diff --git a/src/input/RotaryEncoderImpl.h b/src/input/RotaryEncoderImpl.h index ae2a7c6fd..1d92617d5 100644 --- a/src/input/RotaryEncoderImpl.h +++ b/src/input/RotaryEncoderImpl.h @@ -17,6 +17,13 @@ class RotaryEncoderImpl : public Observable, public concurre protected: virtual int32_t runOnce() override; + QueueHandle_t inputQueue; + void dispatchInputs(void); + TaskHandle_t inputWorkerTask; + static void inputWorker(void *p); + EventGroupHandle_t interruptFlag; + static RotaryEncoderImpl* interruptInstance; + input_broker_event eventCw = INPUT_BROKER_NONE; input_broker_event eventCcw = INPUT_BROKER_NONE; input_broker_event eventPressed = INPUT_BROKER_NONE; diff --git a/variants/esp32s3/tlora-pager/platformio.ini b/variants/esp32s3/tlora-pager/platformio.ini index 312d46259..9800161bb 100644 --- a/variants/esp32s3/tlora-pager/platformio.ini +++ b/variants/esp32s3/tlora-pager/platformio.ini @@ -15,7 +15,7 @@ build_flags = ${esp32s3_base.build_flags} -D SDCARD_USE_SPI1 -D ENABLE_ROTARY_PULLUP -D ENABLE_BUTTON_PULLUP - -D HALF_STEP + -D ROTARY_BUXTRONICS lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX@1.2.7 @@ -26,7 +26,7 @@ lib_deps = ${esp32s3_base.lib_deps} lewisxhe/SensorLib@0.3.1 https://github.com/pschatzmann/arduino-audio-driver/archive/refs/tags/v0.1.3.zip https://github.com/mverch67/BQ27220/archive/07d92be846abd8a0258a50c23198dac0858b22ed.zip - https://github.com/mverch67/RotaryEncoder/archive/25a59d5745a6645536f921427d80b08e78f886d4.zip + https://github.com/mverch67/RotaryEncoder/archive/da958a21389cbcd485989705df602a33e092dd88.zip [env:tlora-pager-tft] board_level = extra From 42e4759634c88b5429d69e02c6a630976362a077 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 14 Sep 2025 04:22:01 +0200 Subject: [PATCH 018/166] T-Lora Pager: Fix amplifier fuzzing/popping --- src/AudioThread.h | 17 +++++++++++++++++ src/main.cpp | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/AudioThread.h b/src/AudioThread.h index 286729909..f794d3a79 100644 --- a/src/AudioThread.h +++ b/src/AudioThread.h @@ -11,6 +11,11 @@ #include #include +#ifdef USE_XL9555 +#include "ExtensionIOXL9555.hpp" +extern ExtensionIOXL9555 io; +#endif + #define AUDIO_THREAD_INTERVAL_MS 100 class AudioThread : public concurrency::OSThread @@ -20,6 +25,9 @@ class AudioThread : public concurrency::OSThread void beginRttl(const void *data, uint32_t len) { +#ifdef USE_XL9555 + io.digitalWrite(EXPANDS_AMP_EN, HIGH); +#endif setCPUFast(true); rtttlFile = new AudioFileSourcePROGMEM(data, len); i2sRtttl = new AudioGeneratorRTTTL(); @@ -45,6 +53,9 @@ class AudioThread : public concurrency::OSThread rtttlFile = nullptr; setCPUFast(false); +#ifdef USE_XL9555 + io.digitalWrite(EXPANDS_AMP_EN, LOW); +#endif } void readAloud(const char *text) @@ -55,10 +66,16 @@ class AudioThread : public concurrency::OSThread i2sRtttl = nullptr; } +#ifdef USE_XL9555 + io.digitalWrite(EXPANDS_AMP_EN, HIGH); +#endif ESP8266SAM *sam = new ESP8266SAM; sam->Say(audioOut, text); delete sam; setCPUFast(false); +#ifdef USE_XL9555 + io.digitalWrite(EXPANDS_AMP_EN, LOW); +#endif } protected: diff --git a/src/main.cpp b/src/main.cpp index 8d576f008..b821310ce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -374,7 +374,7 @@ void setup() io.pinMode(EXPANDS_DRV_EN, OUTPUT); io.digitalWrite(EXPANDS_DRV_EN, HIGH); io.pinMode(EXPANDS_AMP_EN, OUTPUT); - io.digitalWrite(EXPANDS_AMP_EN, HIGH); + io.digitalWrite(EXPANDS_AMP_EN, LOW); io.pinMode(EXPANDS_LORA_EN, OUTPUT); io.digitalWrite(EXPANDS_LORA_EN, HIGH); io.pinMode(EXPANDS_GPS_EN, OUTPUT); From 20f68929c8b6da3f8f3fc797149437c2012fc687 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 14 Sep 2025 20:17:24 +0200 Subject: [PATCH 019/166] Fix build for other variants --- src/input/RotaryEncoderImpl.h | 6 +++++- src/modules/Modules.cpp | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/input/RotaryEncoderImpl.h b/src/input/RotaryEncoderImpl.h index 1d92617d5..4922b4333 100644 --- a/src/input/RotaryEncoderImpl.h +++ b/src/input/RotaryEncoderImpl.h @@ -1,6 +1,8 @@ #pragma once -// This is a non-interrupt version of RotaryEncoder which is based on a debounce inherent FSM table (see RotaryEncoder library) +#ifdef T_LORA_PAGER + +// This is a version of RotaryEncoder which is based on a debounce inherent FSM table (see RotaryEncoder library) #include "InputBroker.h" #include "concurrency/OSThread.h" @@ -33,3 +35,5 @@ class RotaryEncoderImpl : public Observable, public concurre }; extern RotaryEncoderImpl *rotaryEncoderImpl; + +#endif diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index d4beb6824..65139fb6c 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -3,7 +3,9 @@ #include "buzz/BuzzerFeedbackThread.h" #include "input/ExpressLRSFiveWay.h" #include "input/InputBroker.h" +#ifdef T_LORA_PAGER #include "input/RotaryEncoderImpl.h" +#endif #include "input/RotaryEncoderInterruptImpl1.h" #include "input/SerialKeyboardImpl.h" #include "input/UpDownInterruptImpl1.h" From a76f59123197bdd7acfef8d6dc816d33bc7e3262 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Mon, 15 Sep 2025 15:08:02 +1200 Subject: [PATCH 020/166] Fix - reference actual channel when changing settings --- src/mesh/Channels.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index affe05285..bc1d5ab20 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -346,7 +346,7 @@ void Channels::setChannel(const meshtastic_Channel &c) void Channels::setMute(ChannelIndex chIndex) { if (chIndex < channelFile.channels_count) { - meshtastic_Channel *ch = channelFile.channels + chIndex; + meshtastic_Channel *ch = &getByIndex(chIndex); ch->settings.mute = !ch->settings.mute; } else { LOG_ERROR("Failed to mute. Invalid channel index %d > %d", chIndex, channelFile.channels_count); From 5fca3a30ecefd33ad472c0b04c1b29188e9c3155 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Mon, 15 Sep 2025 15:13:25 +1200 Subject: [PATCH 021/166] Update protos --- protobufs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 4c4427c4a..8caf42396 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 4c4427c4a73c86fed7dc8632188bb8be95349d81 +Subproject commit 8caf42396438f0d8a0305143485fd671c1fc7126 From f0b7aab03081494932bb5c773ae45bc6e4d578ab Mon Sep 17 00:00:00 2001 From: ford-jones Date: Mon, 15 Sep 2025 15:21:40 +1200 Subject: [PATCH 022/166] Refactor ref syntax --- src/mesh/Channels.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index bc1d5ab20..1c2bfdcfb 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -346,8 +346,8 @@ void Channels::setChannel(const meshtastic_Channel &c) void Channels::setMute(ChannelIndex chIndex) { if (chIndex < channelFile.channels_count) { - meshtastic_Channel *ch = &getByIndex(chIndex); - ch->settings.mute = !ch->settings.mute; + meshtastic_Channel &ch = getByIndex(chIndex); + ch.settings.mute = !ch.settings.mute; } else { LOG_ERROR("Failed to mute. Invalid channel index %d > %d", chIndex, channelFile.channels_count); }; From 6c932d51ec1288eeba38805f64103169f1f2144a Mon Sep 17 00:00:00 2001 From: WillyJL Date: Mon, 15 Sep 2025 17:49:03 +0200 Subject: [PATCH 023/166] Fix defines --- src/AudioThread.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AudioThread.h b/src/AudioThread.h index f794d3a79..8073ee51b 100644 --- a/src/AudioThread.h +++ b/src/AudioThread.h @@ -25,7 +25,7 @@ class AudioThread : public concurrency::OSThread void beginRttl(const void *data, uint32_t len) { -#ifdef USE_XL9555 +#ifdef T_LORA_PAGER io.digitalWrite(EXPANDS_AMP_EN, HIGH); #endif setCPUFast(true); @@ -53,7 +53,7 @@ class AudioThread : public concurrency::OSThread rtttlFile = nullptr; setCPUFast(false); -#ifdef USE_XL9555 +#ifdef T_LORA_PAGER io.digitalWrite(EXPANDS_AMP_EN, LOW); #endif } @@ -66,14 +66,14 @@ class AudioThread : public concurrency::OSThread i2sRtttl = nullptr; } -#ifdef USE_XL9555 +#ifdef T_LORA_PAGER io.digitalWrite(EXPANDS_AMP_EN, HIGH); #endif ESP8266SAM *sam = new ESP8266SAM; sam->Say(audioOut, text); delete sam; setCPUFast(false); -#ifdef USE_XL9555 +#ifdef T_LORA_PAGER io.digitalWrite(EXPANDS_AMP_EN, LOW); #endif } From 1c256ccfd79b4908ea794b503e5e4b58559590cb Mon Sep 17 00:00:00 2001 From: ford-jones Date: Tue, 16 Sep 2025 15:43:13 +1200 Subject: [PATCH 024/166] Update comments and remove unused function --- src/mesh/Channels.cpp | 10 ---------- src/mesh/Channels.h | 6 ------ src/mesh/generated/meshtastic/channel.pb.h | 4 +--- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 1c2bfdcfb..4ef41ddfb 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -343,16 +343,6 @@ void Channels::setChannel(const meshtastic_Channel &c) old = c; // slam in the new settings/role } -void Channels::setMute(ChannelIndex chIndex) -{ - if (chIndex < channelFile.channels_count) { - meshtastic_Channel &ch = getByIndex(chIndex); - ch.settings.mute = !ch.settings.mute; - } else { - LOG_ERROR("Failed to mute. Invalid channel index %d > %d", chIndex, channelFile.channels_count); - }; -}; - bool Channels::anyMqttEnabled() { #if USERPREFS_EVENT_MODE && !MESHTASTIC_EXCLUDE_MQTT diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index e7c6ddb78..7873a306a 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -47,12 +47,6 @@ class Channels */ void setChannel(const meshtastic_Channel &c); - /** - * Toggles the mute state of the channel associated with the channel index. - * I.e. if it's off turn it on and vice-versa. - */ - void setMute(ChannelIndex chIndex); - /** Return a human friendly name for this channel (and expand any short strings as needed) */ const char *getName(size_t chIndex); diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index 1e1b95df7..594d15929 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -97,9 +97,7 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; - /* Whether or not we should receive notifactions / alerts through this channel - Note: This is NOT the same as module_settings.is_client_mute which pertains - to the device role. */ + /* Whether or not we should receive notifactions / alerts from this channel */ bool mute; } meshtastic_ChannelSettings; From c9702fe4d011c7a6b6ad20ec946865b86b7c4f47 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Tue, 16 Sep 2025 19:21:53 +1200 Subject: [PATCH 025/166] Regen protos --- src/mesh/generated/meshtastic/admin.pb.h | 8 ------- src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/channel.pb.h | 14 ++++------- src/mesh/generated/meshtastic/config.pb.h | 11 ++++++--- src/mesh/generated/meshtastic/deviceonly.pb.h | 23 ++++++++----------- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 2 ++ .../generated/meshtastic/module_config.pb.h | 13 +++++++---- 8 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index 616b7e8ee..bc0b780b9 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -247,10 +247,6 @@ typedef struct _meshtastic_AdminMessage { uint32_t set_ignored_node; /* Set specified node-num to be un-ignored on the NodeDB on the device */ uint32_t remove_ignored_node; - /* Set specified node-num to be muted */ - uint32_t set_muted_node; - /* Set specified node-num to be heard / not-muted */ - uint32_t remove_muted_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -392,8 +388,6 @@ extern "C" { #define meshtastic_AdminMessage_store_ui_config_tag 46 #define meshtastic_AdminMessage_set_ignored_node_tag 47 #define meshtastic_AdminMessage_remove_ignored_node_tag 48 -#define meshtastic_AdminMessage_set_muted_node_tag 49 -#define meshtastic_AdminMessage_remove_muted_node_tag 50 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 @@ -452,8 +446,6 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ -X(a, STATIC, ONEOF, UINT32, (payload_variant,set_muted_node,set_muted_node), 49) \ -X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_muted_node,remove_muted_node), 50) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index db9dedaaf..f4c33bd79 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 695 +#define meshtastic_ChannelSet_size 679 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index 594d15929..ca4310bf1 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -97,8 +97,6 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; - /* Whether or not we should receive notifactions / alerts from this channel */ - bool mute; } meshtastic_ChannelSettings; /* A pair of a channel number, mode and the (sharable) settings for that channel */ @@ -130,10 +128,10 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0} +#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default} #define meshtastic_ModuleSettings_init_default {0, 0} #define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN} -#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0} +#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero} #define meshtastic_ModuleSettings_init_zero {0, 0} #define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN} @@ -147,7 +145,6 @@ extern "C" { #define meshtastic_ChannelSettings_uplink_enabled_tag 5 #define meshtastic_ChannelSettings_downlink_enabled_tag 6 #define meshtastic_ChannelSettings_module_settings_tag 7 -#define meshtastic_ChannelSettings_mute_tag 8 #define meshtastic_Channel_index_tag 1 #define meshtastic_Channel_settings_tag 2 #define meshtastic_Channel_role_tag 3 @@ -160,8 +157,7 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \ X(a, STATIC, SINGULAR, FIXED32, id, 4) \ X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \ -X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \ -X(a, STATIC, SINGULAR, BOOL, mute, 8) +X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) #define meshtastic_ChannelSettings_CALLBACK NULL #define meshtastic_ChannelSettings_DEFAULT NULL #define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings @@ -191,8 +187,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size -#define meshtastic_ChannelSettings_size 74 -#define meshtastic_Channel_size 89 +#define meshtastic_ChannelSettings_size 72 +#define meshtastic_Channel_size 87 #define meshtastic_ModuleSettings_size 8 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 67d461611..59e55db3f 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -64,7 +64,12 @@ typedef enum _meshtastic_Config_DeviceConfig_Role { in areas not already covered by other routers, or to bridge around problematic terrain, but should not be given priority over other routers in order to avoid unnecessaraily consuming hops. */ - meshtastic_Config_DeviceConfig_Role_ROUTER_LATE = 11 + meshtastic_Config_DeviceConfig_Role_ROUTER_LATE = 11, + /* Description: Treats packets from or to favorited nodes as ROUTER, and all other packets as CLIENT. + Technical Details: Used for stronger attic/roof nodes to distribute messages more widely + from weaker, indoor, or less-well-positioned nodes. Recommended for users with multiple nodes + where one CLIENT_BASE acts as a more powerful base station, such as an attic/roof node. */ + meshtastic_Config_DeviceConfig_Role_CLIENT_BASE = 12 } meshtastic_Config_DeviceConfig_Role; /* Defines the device's behavior for how messages are rebroadcast */ @@ -646,8 +651,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT -#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_ROUTER_LATE -#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_ROUTER_LATE+1)) +#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_CLIENT_BASE +#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_CLIENT_BASE+1)) #define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL #define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 55c433699..9b6330596 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -94,9 +94,6 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; - /* True if node has been muted - Persists between NodeDB internal clean ups */ - bool is_muted; /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ uint8_t next_hop; /* Bitfield for storing booleans. @@ -193,14 +190,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_NodeDatabase_init_default {0, {0}} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_BackupPreferences_init_default {0, 0, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default, false, meshtastic_ChannelFile_init_default, false, meshtastic_User_init_default} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_NodeDatabase_init_zero {0, {0}} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} @@ -231,9 +228,8 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 -#define meshtastic_NodeInfoLite_is_muted_tag 12 -#define meshtastic_NodeInfoLite_next_hop_tag 13 -#define meshtastic_NodeInfoLite_bitfield_tag 14 +#define meshtastic_NodeInfoLite_next_hop_tag 12 +#define meshtastic_NodeInfoLite_bitfield_tag 13 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -288,9 +284,8 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, BOOL, is_muted, 12) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 13) \ -X(a, STATIC, SINGULAR, UINT32, bitfield, 14) +X(a, STATIC, SINGULAR, UINT32, next_hop, 12) \ +X(a, STATIC, SINGULAR, UINT32, bitfield, 13) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -365,10 +360,10 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_NodeDatabase_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size -#define meshtastic_BackupPreferences_size 2287 -#define meshtastic_ChannelFile_size 734 +#define meshtastic_BackupPreferences_size 2273 +#define meshtastic_ChannelFile_size 718 #define meshtastic_DeviceState_size 1737 -#define meshtastic_NodeInfoLite_size 198 +#define meshtastic_NodeInfoLite_size 196 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 98 diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index ca8dcd5fb..da224fb94 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -188,7 +188,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size #define meshtastic_LocalConfig_size 747 -#define meshtastic_LocalModuleConfig_size 669 +#define meshtastic_LocalModuleConfig_size 671 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index ce3722aa7..2a4e77870 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -272,6 +272,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_HELTEC_MESH_SOLAR = 108, /* Lilygo T-Echo Lite */ meshtastic_HardwareModel_T_ECHO_LITE = 109, + /* New Heltec LoRA32 with ESP32-S3 CPU */ + meshtastic_HardwareModel_HELTEC_V4 = 110, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index b27f5f515..16c4c230c 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -317,6 +317,9 @@ typedef struct _meshtastic_ModuleConfig_RangeTestConfig { /* Bool value indicating that this node should save a RangeTest.csv file. ESP32 Only */ bool save; + /* Bool indicating that the node should cleanup / destroy it's RangeTest.csv file. + ESP32 Only */ + bool clear_on_reboot; } meshtastic_ModuleConfig_RangeTestConfig; /* Configuration for both device and environment metrics */ @@ -519,7 +522,7 @@ extern "C" { #define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0, 0} -#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0} +#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0} @@ -535,7 +538,7 @@ extern "C" { #define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0, 0} -#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0} +#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0} @@ -610,6 +613,7 @@ extern "C" { #define meshtastic_ModuleConfig_RangeTestConfig_enabled_tag 1 #define meshtastic_ModuleConfig_RangeTestConfig_sender_tag 2 #define meshtastic_ModuleConfig_RangeTestConfig_save_tag 3 +#define meshtastic_ModuleConfig_RangeTestConfig_clear_on_reboot_tag 4 #define meshtastic_ModuleConfig_TelemetryConfig_device_update_interval_tag 1 #define meshtastic_ModuleConfig_TelemetryConfig_environment_update_interval_tag 2 #define meshtastic_ModuleConfig_TelemetryConfig_environment_measurement_enabled_tag 3 @@ -803,7 +807,8 @@ X(a, STATIC, SINGULAR, BOOL, is_server, 6) #define meshtastic_ModuleConfig_RangeTestConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ X(a, STATIC, SINGULAR, UINT32, sender, 2) \ -X(a, STATIC, SINGULAR, BOOL, save, 3) +X(a, STATIC, SINGULAR, BOOL, save, 3) \ +X(a, STATIC, SINGULAR, BOOL, clear_on_reboot, 4) #define meshtastic_ModuleConfig_RangeTestConfig_CALLBACK NULL #define meshtastic_ModuleConfig_RangeTestConfig_DEFAULT NULL @@ -901,7 +906,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_MapReportSettings_size 14 #define meshtastic_ModuleConfig_NeighborInfoConfig_size 10 #define meshtastic_ModuleConfig_PaxcounterConfig_size 30 -#define meshtastic_ModuleConfig_RangeTestConfig_size 10 +#define meshtastic_ModuleConfig_RangeTestConfig_size 12 #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_SerialConfig_size 28 #define meshtastic_ModuleConfig_StoreForwardConfig_size 24 From 4ac99c5df1278e2c506e3b5e3d5b7078744cdc26 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Tue, 16 Sep 2025 19:26:22 +1200 Subject: [PATCH 026/166] Regen protobuffs again --- src/mesh/generated/meshtastic/admin.pb.h | 8 +++++++ src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/channel.pb.h | 14 +++++++---- src/mesh/generated/meshtastic/deviceonly.pb.h | 23 +++++++++++-------- src/mesh/generated/meshtastic/mesh.pb.h | 6 +++-- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index bc0b780b9..616b7e8ee 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -247,6 +247,10 @@ typedef struct _meshtastic_AdminMessage { uint32_t set_ignored_node; /* Set specified node-num to be un-ignored on the NodeDB on the device */ uint32_t remove_ignored_node; + /* Set specified node-num to be muted */ + uint32_t set_muted_node; + /* Set specified node-num to be heard / not-muted */ + uint32_t remove_muted_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -388,6 +392,8 @@ extern "C" { #define meshtastic_AdminMessage_store_ui_config_tag 46 #define meshtastic_AdminMessage_set_ignored_node_tag 47 #define meshtastic_AdminMessage_remove_ignored_node_tag 48 +#define meshtastic_AdminMessage_set_muted_node_tag 49 +#define meshtastic_AdminMessage_remove_muted_node_tag 50 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 @@ -446,6 +452,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,set_muted_node,set_muted_node), 49) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_muted_node,remove_muted_node), 50) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index f4c33bd79..db9dedaaf 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 679 +#define meshtastic_ChannelSet_size 695 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index ca4310bf1..594d15929 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -97,6 +97,8 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; + /* Whether or not we should receive notifactions / alerts from this channel */ + bool mute; } meshtastic_ChannelSettings; /* A pair of a channel number, mode and the (sharable) settings for that channel */ @@ -128,10 +130,10 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default} +#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0} #define meshtastic_ModuleSettings_init_default {0, 0} #define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN} -#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero} +#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0} #define meshtastic_ModuleSettings_init_zero {0, 0} #define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN} @@ -145,6 +147,7 @@ extern "C" { #define meshtastic_ChannelSettings_uplink_enabled_tag 5 #define meshtastic_ChannelSettings_downlink_enabled_tag 6 #define meshtastic_ChannelSettings_module_settings_tag 7 +#define meshtastic_ChannelSettings_mute_tag 8 #define meshtastic_Channel_index_tag 1 #define meshtastic_Channel_settings_tag 2 #define meshtastic_Channel_role_tag 3 @@ -157,7 +160,8 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \ X(a, STATIC, SINGULAR, FIXED32, id, 4) \ X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \ -X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) +X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \ +X(a, STATIC, SINGULAR, BOOL, mute, 8) #define meshtastic_ChannelSettings_CALLBACK NULL #define meshtastic_ChannelSettings_DEFAULT NULL #define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings @@ -187,8 +191,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size -#define meshtastic_ChannelSettings_size 72 -#define meshtastic_Channel_size 87 +#define meshtastic_ChannelSettings_size 74 +#define meshtastic_Channel_size 89 #define meshtastic_ModuleSettings_size 8 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 9b6330596..148261fc8 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -94,6 +94,9 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; + /* True if node has been muted + Persists between NodeDB internal clean ups */ + bool is_muted; /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ uint8_t next_hop; /* Bitfield for storing booleans. @@ -190,14 +193,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_NodeDatabase_init_default {0, {0}} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_BackupPreferences_init_default {0, 0, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default, false, meshtastic_ChannelFile_init_default, false, meshtastic_User_init_default} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_NodeDatabase_init_zero {0, {0}} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} @@ -228,8 +231,9 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 -#define meshtastic_NodeInfoLite_next_hop_tag 12 -#define meshtastic_NodeInfoLite_bitfield_tag 13 +#define meshtastic_NodeInfoLite_is_muted_tag 12 +#define meshtastic_NodeInfoLite_next_hop_tag 13 +#define meshtastic_NodeInfoLite_bitfield_tag 14 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -284,8 +288,9 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 12) \ -X(a, STATIC, SINGULAR, UINT32, bitfield, 13) +X(a, STATIC, SINGULAR, BOOL, is_muted, 12) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 13) \ +X(a, STATIC, SINGULAR, UINT32, bitfield, 14) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -360,10 +365,10 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_NodeDatabase_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size -#define meshtastic_BackupPreferences_size 2273 -#define meshtastic_ChannelFile_size 718 +#define meshtastic_BackupPreferences_size 2289 +#define meshtastic_ChannelFile_size 734 #define meshtastic_DeviceState_size 1737 -#define meshtastic_NodeInfoLite_size 196 +#define meshtastic_NodeInfoLite_size 198 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 98 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 2a4e77870..294f0beac 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -259,8 +259,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_T_DECK_PRO = 102, /* Lilygo TLora Pager */ meshtastic_HardwareModel_T_LORA_PAGER = 103, - /* GAT562 Mesh Trial Tracker */ - meshtastic_HardwareModel_GAT562_MESH_TRIAL_TRACKER = 104, + /* M5Stack Reserved */ + meshtastic_HardwareModel_M5STACK_RESERVED = 104, /* 0x68 */ /* RAKwireless WisMesh Tag */ meshtastic_HardwareModel_WISMESH_TAG = 105, /* RAKwireless WisBlock Core RAK3312 https://docs.rakwireless.com/product-categories/wisduo/rak3112-module/overview/ */ @@ -274,6 +274,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_T_ECHO_LITE = 109, /* New Heltec LoRA32 with ESP32-S3 CPU */ meshtastic_HardwareModel_HELTEC_V4 = 110, + /* M5Stack C6L */ + meshtastic_HardwareModel_M5STACK_C6L = 111, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ From 43078a40ebe6e42e34e83f29c80afba9f62298cc Mon Sep 17 00:00:00 2001 From: ford-jones Date: Tue, 16 Sep 2025 21:57:51 +1200 Subject: [PATCH 027/166] Fix build failure in ci, add missing argument --- src/mesh/Channels.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 4c0a0edad..50e51261e 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -428,7 +428,8 @@ bool Channels::setDefaultPresetCryptoForHash(ChannelHash channelHash) // Iterate all known presets for (int preset = _meshtastic_Config_LoRaConfig_ModemPreset_MIN; preset <= _meshtastic_Config_LoRaConfig_ModemPreset_MAX; ++preset) { - const char *name = DisplayFormatters::getModemPresetDisplayName((meshtastic_Config_LoRaConfig_ModemPreset)preset, false); + const char *name = + DisplayFormatters::getModemPresetDisplayName((meshtastic_Config_LoRaConfig_ModemPreset)preset, false, true); if (!name) continue; if (strcmp(name, "Invalid") == 0) From d427b477e39f77434e08b6d7b9f1199b995c9d62 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Wed, 17 Sep 2025 02:07:24 +0200 Subject: [PATCH 028/166] Format --- src/input/RotaryEncoderImpl.cpp | 10 ++++------ src/input/RotaryEncoderImpl.h | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/input/RotaryEncoderImpl.cpp b/src/input/RotaryEncoderImpl.cpp index cede1b87c..216e92382 100644 --- a/src/input/RotaryEncoderImpl.cpp +++ b/src/input/RotaryEncoderImpl.cpp @@ -35,9 +35,7 @@ bool RotaryEncoderImpl::init() inputQueue = xQueueCreate(5, sizeof(input_broker_event)); interruptFlag = xEventGroupCreate(); interruptInstance = this; - auto interruptHandler = []() { - xEventGroupSetBits(interruptInstance->interruptFlag, ROTARY_INTERRUPT_FLAG); - }; + auto interruptHandler = []() { xEventGroupSetBits(interruptInstance->interruptFlag, ROTARY_INTERRUPT_FLAG); }; attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE); attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE); attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE); @@ -78,7 +76,7 @@ void RotaryEncoderImpl::dispatchInputs() void RotaryEncoderImpl::inputWorker(void *p) { - RotaryEncoderImpl* instance = (RotaryEncoderImpl*)p; + RotaryEncoderImpl *instance = (RotaryEncoderImpl *)p; while (true) { xEventGroupWaitBits(instance->interruptFlag, ROTARY_INTERRUPT_FLAG, pdTRUE, pdTRUE, portMAX_DELAY); instance->dispatchInputs(); @@ -86,12 +84,12 @@ void RotaryEncoderImpl::inputWorker(void *p) vTaskDelete(NULL); } -RotaryEncoderImpl* RotaryEncoderImpl::interruptInstance; +RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance; int32_t RotaryEncoderImpl::runOnce() { InputEvent e{originName, INPUT_BROKER_NONE, 0, 0, 0}; - while(xQueueReceive(inputQueue, &e.inputEvent, 0) == pdPASS) { + while (xQueueReceive(inputQueue, &e.inputEvent, 0) == pdPASS) { this->notifyObservers(&e); } return 10; diff --git a/src/input/RotaryEncoderImpl.h b/src/input/RotaryEncoderImpl.h index 4922b4333..e5ff251e8 100644 --- a/src/input/RotaryEncoderImpl.h +++ b/src/input/RotaryEncoderImpl.h @@ -23,8 +23,8 @@ class RotaryEncoderImpl : public Observable, public concurre void dispatchInputs(void); TaskHandle_t inputWorkerTask; static void inputWorker(void *p); - EventGroupHandle_t interruptFlag; - static RotaryEncoderImpl* interruptInstance; + EventGroupHandle_t interruptFlag; + static RotaryEncoderImpl *interruptInstance; input_broker_event eventCw = INPUT_BROKER_NONE; input_broker_event eventCcw = INPUT_BROKER_NONE; From 0e26702c4600a4c39e9ef2249e09e35c9763fd73 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Fri, 19 Sep 2025 19:08:38 +0200 Subject: [PATCH 029/166] InputPollable: System for polling after interrupts --- src/input/InputBroker.cpp | 46 +++++++++++++++++++++++++++++++++++++-- src/input/InputBroker.h | 22 +++++++++++++++++++ src/main.cpp | 3 +++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/input/InputBroker.cpp b/src/input/InputBroker.cpp index ef6d8df91..5ca890b43 100644 --- a/src/input/InputBroker.cpp +++ b/src/input/InputBroker.cpp @@ -3,16 +3,58 @@ InputBroker *inputBroker = nullptr; -InputBroker::InputBroker(){}; +InputBroker::InputBroker() +{ +#ifdef HAS_FREE_RTOS + inputEventQueue = xQueueCreate(5, sizeof(InputEvent)); + pollSoonQueue = xQueueCreate(5, sizeof(InputPollable *)); + xTaskCreate(pollSoonWorker, "input-pollSoon", 2 * 1024, this, 10, &pollSoonTask); +#endif +} void InputBroker::registerSource(Observable *source) { this->inputEventObserver.observe(source); } +#ifdef HAS_FREE_RTOS +void InputBroker::pollSoonRequestFromIsr(InputPollable *pollable) +{ + xQueueSendFromISR(pollSoonQueue, &pollable, NULL); +} + +void InputBroker::queueInputEvent(const InputEvent *event) +{ + xQueueSend(inputEventQueue, event, portMAX_DELAY); +} + +void InputBroker::processInputEventQueue() +{ + InputEvent event; + while (xQueueReceive(inputEventQueue, &event, 0)) { + handleInputEvent(&event); + } +} +#endif + int InputBroker::handleInputEvent(const InputEvent *event) { powerFSM.trigger(EVENT_INPUT); // todo: not every input should wake, like long hold release this->notifyObservers(event); return 0; -} \ No newline at end of file +} + +#ifdef HAS_FREE_RTOS +void InputBroker::pollSoonWorker(void *p) +{ + InputBroker *instance = (InputBroker *)p; + while (true) { + InputPollable *pollable = NULL; + xQueueReceive(instance->pollSoonQueue, &pollable, portMAX_DELAY); + if (pollable) { + pollable->pollOnce(); + } + } + vTaskDelete(NULL); +} +#endif diff --git a/src/input/InputBroker.h b/src/input/InputBroker.h index 2cdfa2ae2..82af184f3 100644 --- a/src/input/InputBroker.h +++ b/src/input/InputBroker.h @@ -1,5 +1,7 @@ #pragma once + #include "Observer.h" +#include "freertosinc.h" enum input_broker_event { INPUT_BROKER_NONE = 0, @@ -41,6 +43,13 @@ typedef struct _InputEvent { uint16_t touchX; uint16_t touchY; } InputEvent; + +class InputPollable +{ + public: + virtual void pollOnce() = 0; +}; + class InputBroker : public Observable { CallbackObserver inputEventObserver = @@ -50,9 +59,22 @@ class InputBroker : public Observable InputBroker(); void registerSource(Observable *source); void injectInputEvent(const InputEvent *event) { handleInputEvent(event); } +#ifdef HAS_FREE_RTOS + void pollSoonRequestFromIsr(InputPollable *pollable); + void queueInputEvent(const InputEvent *event); + void processInputEventQueue(); +#endif protected: int handleInputEvent(const InputEvent *event); + + private: +#ifdef HAS_FREE_RTOS + QueueHandle_t inputEventQueue; + QueueHandle_t pollSoonQueue; + TaskHandle_t pollSoonTask; + static void pollSoonWorker(void *p); +#endif }; extern InputBroker *inputBroker; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b821310ce..510d2b898 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1602,6 +1602,9 @@ void loop() #endif service->loop(); +#if !MESHTASTIC_EXCLUDE_INPUTBROKER + inputBroker->processInputEventQueue(); +#endif #if defined(LGFX_SDL) if (screen) { auto dispdev = screen->getDisplayDevice(); From 54f9f7a5917711adf9971bcd44dcdddd8f40812d Mon Sep 17 00:00:00 2001 From: WillyJL Date: Fri, 19 Sep 2025 22:05:18 +0200 Subject: [PATCH 030/166] T-Lora Pager: Use InputPollable for RotaryEncoderImpl --- src/input/RotaryEncoderImpl.cpp | 50 +++++++++------------------------ src/input/RotaryEncoderImpl.h | 11 ++------ 2 files changed, 16 insertions(+), 45 deletions(-) diff --git a/src/input/RotaryEncoderImpl.cpp b/src/input/RotaryEncoderImpl.cpp index 216e92382..213dd4faa 100644 --- a/src/input/RotaryEncoderImpl.cpp +++ b/src/input/RotaryEncoderImpl.cpp @@ -6,11 +6,9 @@ #define ORIGIN_NAME "RotaryEncoder" -#define ROTARY_INTERRUPT_FLAG _BV(0) - RotaryEncoderImpl *rotaryEncoderImpl; -RotaryEncoderImpl::RotaryEncoderImpl() : concurrency::OSThread(ORIGIN_NAME), originName(ORIGIN_NAME) +RotaryEncoderImpl::RotaryEncoderImpl() { rotary = nullptr; } @@ -20,7 +18,6 @@ bool RotaryEncoderImpl::init() if (!moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.inputbroker_pin_a == 0 || moduleConfig.canned_message.inputbroker_pin_b == 0) { // Input device is disabled. - disable(); return false; } @@ -32,16 +29,11 @@ bool RotaryEncoderImpl::init() moduleConfig.canned_message.inputbroker_pin_press); rotary->resetButton(); - inputQueue = xQueueCreate(5, sizeof(input_broker_event)); - interruptFlag = xEventGroupCreate(); interruptInstance = this; - auto interruptHandler = []() { xEventGroupSetBits(interruptInstance->interruptFlag, ROTARY_INTERRUPT_FLAG); }; + auto interruptHandler = []() { inputBroker->pollSoonRequestFromIsr(interruptInstance); }; attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE); attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE); attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE); - xTaskCreate(inputWorker, "rotary", 2 * 1024, this, 10, &inputWorkerTask); - - inputBroker->registerSource(this); LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw, @@ -49,50 +41,36 @@ bool RotaryEncoderImpl::init() return true; } -void RotaryEncoderImpl::dispatchInputs() +void RotaryEncoderImpl::pollOnce() { + InputEvent e{ORIGIN_NAME, INPUT_BROKER_NONE, 0, 0, 0}; + static uint32_t lastPressed = millis(); if (rotary->readButton() == RotaryEncoder::ButtonState::BUTTON_PRESSED) { if (lastPressed + 200 < millis()) { - // LOG_DEBUG("Rotary event Press"); + LOG_DEBUG("Rotary event Press"); lastPressed = millis(); - xQueueSend(inputQueue, &this->eventPressed, portMAX_DELAY); + e.inputEvent = this->eventPressed; + inputBroker->queueInputEvent(&e); } } switch (rotary->process()) { case RotaryEncoder::DIRECTION_CW: - // LOG_DEBUG("Rotary event CW"); - xQueueSend(inputQueue, &this->eventCw, portMAX_DELAY); + LOG_DEBUG("Rotary event CW"); + e.inputEvent = this->eventCw; + inputBroker->queueInputEvent(&e); break; case RotaryEncoder::DIRECTION_CCW: - // LOG_DEBUG("Rotary event CCW"); - xQueueSend(inputQueue, &this->eventCcw, portMAX_DELAY); + LOG_DEBUG("Rotary event CCW"); + e.inputEvent = this->eventCcw; + inputBroker->queueInputEvent(&e); break; default: break; } } -void RotaryEncoderImpl::inputWorker(void *p) -{ - RotaryEncoderImpl *instance = (RotaryEncoderImpl *)p; - while (true) { - xEventGroupWaitBits(instance->interruptFlag, ROTARY_INTERRUPT_FLAG, pdTRUE, pdTRUE, portMAX_DELAY); - instance->dispatchInputs(); - } - vTaskDelete(NULL); -} - RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance; -int32_t RotaryEncoderImpl::runOnce() -{ - InputEvent e{originName, INPUT_BROKER_NONE, 0, 0, 0}; - while (xQueueReceive(inputQueue, &e.inputEvent, 0) == pdPASS) { - this->notifyObservers(&e); - } - return 10; -} - #endif \ No newline at end of file diff --git a/src/input/RotaryEncoderImpl.h b/src/input/RotaryEncoderImpl.h index e5ff251e8..af70d1bf4 100644 --- a/src/input/RotaryEncoderImpl.h +++ b/src/input/RotaryEncoderImpl.h @@ -10,20 +10,14 @@ class RotaryEncoder; -class RotaryEncoderImpl : public Observable, public concurrency::OSThread +class RotaryEncoderImpl : public InputPollable { public: RotaryEncoderImpl(); bool init(void); + virtual void pollOnce() override; protected: - virtual int32_t runOnce() override; - - QueueHandle_t inputQueue; - void dispatchInputs(void); - TaskHandle_t inputWorkerTask; - static void inputWorker(void *p); - EventGroupHandle_t interruptFlag; static RotaryEncoderImpl *interruptInstance; input_broker_event eventCw = INPUT_BROKER_NONE; @@ -31,7 +25,6 @@ class RotaryEncoderImpl : public Observable, public concurre input_broker_event eventPressed = INPUT_BROKER_NONE; RotaryEncoder *rotary; - const char *originName; }; extern RotaryEncoderImpl *rotaryEncoderImpl; From a76cc88dc2cae630eb7793eb7b14cb223f9ddd8d Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sat, 20 Sep 2025 18:53:30 +0200 Subject: [PATCH 031/166] Rename RotaryEncoderImpl to TLoraPagerRotaryEncoder --- ...ryEncoderImpl.cpp => TLoraPagerRotaryEncoder.cpp} | 12 ++++++------ ...RotaryEncoderImpl.h => TLoraPagerRotaryEncoder.h} | 8 ++++---- src/modules/Modules.cpp | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) rename src/input/{RotaryEncoderImpl.cpp => TLoraPagerRotaryEncoder.cpp} (89%) rename src/input/{RotaryEncoderImpl.h => TLoraPagerRotaryEncoder.h} (73%) diff --git a/src/input/RotaryEncoderImpl.cpp b/src/input/TLoraPagerRotaryEncoder.cpp similarity index 89% rename from src/input/RotaryEncoderImpl.cpp rename to src/input/TLoraPagerRotaryEncoder.cpp index 213dd4faa..1b99defee 100644 --- a/src/input/RotaryEncoderImpl.cpp +++ b/src/input/TLoraPagerRotaryEncoder.cpp @@ -1,19 +1,19 @@ #ifdef T_LORA_PAGER -#include "RotaryEncoderImpl.h" +#include "TLoraPagerRotaryEncoder.h" #include "InputBroker.h" #include "RotaryEncoder.h" #define ORIGIN_NAME "RotaryEncoder" -RotaryEncoderImpl *rotaryEncoderImpl; +TLoraPagerRotaryEncoder *tLoraPagerRotaryEncoder; -RotaryEncoderImpl::RotaryEncoderImpl() +TLoraPagerRotaryEncoder::TLoraPagerRotaryEncoder() { rotary = nullptr; } -bool RotaryEncoderImpl::init() +bool TLoraPagerRotaryEncoder::init() { if (!moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.inputbroker_pin_a == 0 || moduleConfig.canned_message.inputbroker_pin_b == 0) { @@ -41,7 +41,7 @@ bool RotaryEncoderImpl::init() return true; } -void RotaryEncoderImpl::pollOnce() +void TLoraPagerRotaryEncoder::pollOnce() { InputEvent e{ORIGIN_NAME, INPUT_BROKER_NONE, 0, 0, 0}; @@ -71,6 +71,6 @@ void RotaryEncoderImpl::pollOnce() } } -RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance; +TLoraPagerRotaryEncoder *TLoraPagerRotaryEncoder::interruptInstance; #endif \ No newline at end of file diff --git a/src/input/RotaryEncoderImpl.h b/src/input/TLoraPagerRotaryEncoder.h similarity index 73% rename from src/input/RotaryEncoderImpl.h rename to src/input/TLoraPagerRotaryEncoder.h index af70d1bf4..d5e2edf4e 100644 --- a/src/input/RotaryEncoderImpl.h +++ b/src/input/TLoraPagerRotaryEncoder.h @@ -10,15 +10,15 @@ class RotaryEncoder; -class RotaryEncoderImpl : public InputPollable +class TLoraPagerRotaryEncoder : public InputPollable { public: - RotaryEncoderImpl(); + TLoraPagerRotaryEncoder(); bool init(void); virtual void pollOnce() override; protected: - static RotaryEncoderImpl *interruptInstance; + static TLoraPagerRotaryEncoder *interruptInstance; input_broker_event eventCw = INPUT_BROKER_NONE; input_broker_event eventCcw = INPUT_BROKER_NONE; @@ -27,6 +27,6 @@ class RotaryEncoderImpl : public InputPollable RotaryEncoder *rotary; }; -extern RotaryEncoderImpl *rotaryEncoderImpl; +extern TLoraPagerRotaryEncoder *tLoraPagerRotaryEncoder; #endif diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index abafce070..35e509b83 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -4,7 +4,7 @@ #include "input/ExpressLRSFiveWay.h" #include "input/InputBroker.h" #ifdef T_LORA_PAGER -#include "input/RotaryEncoderImpl.h" +#include "input/TLoraPagerRotaryEncoder.h" #endif #include "input/RotaryEncoderInterruptImpl1.h" #include "input/SerialKeyboardImpl.h" @@ -185,10 +185,10 @@ void setupModules() } #ifdef T_LORA_PAGER // use a special FSM based rotary encoder version for T-LoRa Pager - rotaryEncoderImpl = new RotaryEncoderImpl(); - if (!rotaryEncoderImpl->init()) { - delete rotaryEncoderImpl; - rotaryEncoderImpl = nullptr; + tLoraPagerRotaryEncoder = new TLoraPagerRotaryEncoder(); + if (!tLoraPagerRotaryEncoder->init()) { + delete tLoraPagerRotaryEncoder; + tLoraPagerRotaryEncoder = nullptr; } #else upDownInterruptImpl1 = new UpDownInterruptImpl1(); From 4100ba83a365be2a3edba673d0d2e6da0b192e5f Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 21 Sep 2025 03:23:16 +0200 Subject: [PATCH 032/166] Revert "Rename RotaryEncoderImpl to TLoraPagerRotaryEncoder" This reverts commit a76cc88dc2cae630eb7793eb7b14cb223f9ddd8d. --- ...aPagerRotaryEncoder.cpp => RotaryEncoderImpl.cpp} | 12 ++++++------ ...TLoraPagerRotaryEncoder.h => RotaryEncoderImpl.h} | 8 ++++---- src/modules/Modules.cpp | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) rename src/input/{TLoraPagerRotaryEncoder.cpp => RotaryEncoderImpl.cpp} (89%) rename src/input/{TLoraPagerRotaryEncoder.h => RotaryEncoderImpl.h} (73%) diff --git a/src/input/TLoraPagerRotaryEncoder.cpp b/src/input/RotaryEncoderImpl.cpp similarity index 89% rename from src/input/TLoraPagerRotaryEncoder.cpp rename to src/input/RotaryEncoderImpl.cpp index 1b99defee..213dd4faa 100644 --- a/src/input/TLoraPagerRotaryEncoder.cpp +++ b/src/input/RotaryEncoderImpl.cpp @@ -1,19 +1,19 @@ #ifdef T_LORA_PAGER -#include "TLoraPagerRotaryEncoder.h" +#include "RotaryEncoderImpl.h" #include "InputBroker.h" #include "RotaryEncoder.h" #define ORIGIN_NAME "RotaryEncoder" -TLoraPagerRotaryEncoder *tLoraPagerRotaryEncoder; +RotaryEncoderImpl *rotaryEncoderImpl; -TLoraPagerRotaryEncoder::TLoraPagerRotaryEncoder() +RotaryEncoderImpl::RotaryEncoderImpl() { rotary = nullptr; } -bool TLoraPagerRotaryEncoder::init() +bool RotaryEncoderImpl::init() { if (!moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.inputbroker_pin_a == 0 || moduleConfig.canned_message.inputbroker_pin_b == 0) { @@ -41,7 +41,7 @@ bool TLoraPagerRotaryEncoder::init() return true; } -void TLoraPagerRotaryEncoder::pollOnce() +void RotaryEncoderImpl::pollOnce() { InputEvent e{ORIGIN_NAME, INPUT_BROKER_NONE, 0, 0, 0}; @@ -71,6 +71,6 @@ void TLoraPagerRotaryEncoder::pollOnce() } } -TLoraPagerRotaryEncoder *TLoraPagerRotaryEncoder::interruptInstance; +RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance; #endif \ No newline at end of file diff --git a/src/input/TLoraPagerRotaryEncoder.h b/src/input/RotaryEncoderImpl.h similarity index 73% rename from src/input/TLoraPagerRotaryEncoder.h rename to src/input/RotaryEncoderImpl.h index d5e2edf4e..af70d1bf4 100644 --- a/src/input/TLoraPagerRotaryEncoder.h +++ b/src/input/RotaryEncoderImpl.h @@ -10,15 +10,15 @@ class RotaryEncoder; -class TLoraPagerRotaryEncoder : public InputPollable +class RotaryEncoderImpl : public InputPollable { public: - TLoraPagerRotaryEncoder(); + RotaryEncoderImpl(); bool init(void); virtual void pollOnce() override; protected: - static TLoraPagerRotaryEncoder *interruptInstance; + static RotaryEncoderImpl *interruptInstance; input_broker_event eventCw = INPUT_BROKER_NONE; input_broker_event eventCcw = INPUT_BROKER_NONE; @@ -27,6 +27,6 @@ class TLoraPagerRotaryEncoder : public InputPollable RotaryEncoder *rotary; }; -extern TLoraPagerRotaryEncoder *tLoraPagerRotaryEncoder; +extern RotaryEncoderImpl *rotaryEncoderImpl; #endif diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 35e509b83..abafce070 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -4,7 +4,7 @@ #include "input/ExpressLRSFiveWay.h" #include "input/InputBroker.h" #ifdef T_LORA_PAGER -#include "input/TLoraPagerRotaryEncoder.h" +#include "input/RotaryEncoderImpl.h" #endif #include "input/RotaryEncoderInterruptImpl1.h" #include "input/SerialKeyboardImpl.h" @@ -185,10 +185,10 @@ void setupModules() } #ifdef T_LORA_PAGER // use a special FSM based rotary encoder version for T-LoRa Pager - tLoraPagerRotaryEncoder = new TLoraPagerRotaryEncoder(); - if (!tLoraPagerRotaryEncoder->init()) { - delete tLoraPagerRotaryEncoder; - tLoraPagerRotaryEncoder = nullptr; + rotaryEncoderImpl = new RotaryEncoderImpl(); + if (!rotaryEncoderImpl->init()) { + delete rotaryEncoderImpl; + rotaryEncoderImpl = nullptr; } #else upDownInterruptImpl1 = new UpDownInterruptImpl1(); From d558df8a3a57d93fa8d358cabf05884b296bb2af Mon Sep 17 00:00:00 2001 From: WillyJL Date: Sun, 21 Sep 2025 03:29:52 +0200 Subject: [PATCH 033/166] Revert unnecessary ifdefs --- src/input/RotaryEncoderImpl.h | 4 ---- src/modules/Modules.cpp | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/input/RotaryEncoderImpl.h b/src/input/RotaryEncoderImpl.h index af70d1bf4..6f8e9fe5f 100644 --- a/src/input/RotaryEncoderImpl.h +++ b/src/input/RotaryEncoderImpl.h @@ -1,7 +1,5 @@ #pragma once -#ifdef T_LORA_PAGER - // This is a version of RotaryEncoder which is based on a debounce inherent FSM table (see RotaryEncoder library) #include "InputBroker.h" @@ -28,5 +26,3 @@ class RotaryEncoderImpl : public InputPollable }; extern RotaryEncoderImpl *rotaryEncoderImpl; - -#endif diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index abafce070..757753d45 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -3,9 +3,7 @@ #include "buzz/BuzzerFeedbackThread.h" #include "input/ExpressLRSFiveWay.h" #include "input/InputBroker.h" -#ifdef T_LORA_PAGER #include "input/RotaryEncoderImpl.h" -#endif #include "input/RotaryEncoderInterruptImpl1.h" #include "input/SerialKeyboardImpl.h" #include "input/UpDownInterruptImpl1.h" From 59f9e2a00b730971097975e690aed463660218db Mon Sep 17 00:00:00 2001 From: ford-jones Date: Mon, 22 Sep 2025 14:59:45 +1200 Subject: [PATCH 034/166] Regen protos --- src/mesh/generated/meshtastic/admin.pb.h | 8 --- src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/channel.pb.h | 14 ++---- src/mesh/generated/meshtastic/config.pb.h | 49 ++++++++++++------- .../generated/meshtastic/device_ui.pb.cpp | 2 - src/mesh/generated/meshtastic/device_ui.pb.h | 43 ++-------------- src/mesh/generated/meshtastic/deviceonly.pb.h | 23 ++++----- src/mesh/generated/meshtastic/localonly.pb.h | 4 +- src/mesh/generated/meshtastic/mesh.pb.h | 8 +-- .../generated/meshtastic/module_config.pb.h | 13 ++--- 10 files changed, 58 insertions(+), 108 deletions(-) diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index 616b7e8ee..bc0b780b9 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -247,10 +247,6 @@ typedef struct _meshtastic_AdminMessage { uint32_t set_ignored_node; /* Set specified node-num to be un-ignored on the NodeDB on the device */ uint32_t remove_ignored_node; - /* Set specified node-num to be muted */ - uint32_t set_muted_node; - /* Set specified node-num to be heard / not-muted */ - uint32_t remove_muted_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -392,8 +388,6 @@ extern "C" { #define meshtastic_AdminMessage_store_ui_config_tag 46 #define meshtastic_AdminMessage_set_ignored_node_tag 47 #define meshtastic_AdminMessage_remove_ignored_node_tag 48 -#define meshtastic_AdminMessage_set_muted_node_tag 49 -#define meshtastic_AdminMessage_remove_muted_node_tag 50 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 @@ -452,8 +446,6 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ -X(a, STATIC, ONEOF, UINT32, (payload_variant,set_muted_node,set_muted_node), 49) \ -X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_muted_node,remove_muted_node), 50) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index db9dedaaf..f4c33bd79 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 695 +#define meshtastic_ChannelSet_size 679 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index 594d15929..ca4310bf1 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -97,8 +97,6 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; - /* Whether or not we should receive notifactions / alerts from this channel */ - bool mute; } meshtastic_ChannelSettings; /* A pair of a channel number, mode and the (sharable) settings for that channel */ @@ -130,10 +128,10 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0} +#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default} #define meshtastic_ModuleSettings_init_default {0, 0} #define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN} -#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0} +#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero} #define meshtastic_ModuleSettings_init_zero {0, 0} #define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN} @@ -147,7 +145,6 @@ extern "C" { #define meshtastic_ChannelSettings_uplink_enabled_tag 5 #define meshtastic_ChannelSettings_downlink_enabled_tag 6 #define meshtastic_ChannelSettings_module_settings_tag 7 -#define meshtastic_ChannelSettings_mute_tag 8 #define meshtastic_Channel_index_tag 1 #define meshtastic_Channel_settings_tag 2 #define meshtastic_Channel_role_tag 3 @@ -160,8 +157,7 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \ X(a, STATIC, SINGULAR, FIXED32, id, 4) \ X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \ -X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \ -X(a, STATIC, SINGULAR, BOOL, mute, 8) +X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) #define meshtastic_ChannelSettings_CALLBACK NULL #define meshtastic_ChannelSettings_DEFAULT NULL #define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings @@ -191,8 +187,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size -#define meshtastic_ChannelSettings_size 74 -#define meshtastic_Channel_size 89 +#define meshtastic_ChannelSettings_size 72 +#define meshtastic_Channel_size 87 #define meshtastic_ModuleSettings_size 8 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 0453ecad2..59e55db3f 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -173,10 +173,28 @@ typedef enum _meshtastic_Config_NetworkConfig_ProtocolFlags { meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST = 1 } meshtastic_Config_NetworkConfig_ProtocolFlags; -/* Deprecated in 2.7.4: Unused */ -typedef enum _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat { - meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_UNUSED = 0 -} meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat; +/* How the GPS coordinates are displayed on the OLED screen. */ +typedef enum _meshtastic_Config_DisplayConfig_GpsCoordinateFormat { + /* GPS coordinates are displayed in the normal decimal degrees format: + DD.DDDDDD DDD.DDDDDD */ + meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DEC = 0, + /* GPS coordinates are displayed in the degrees minutes seconds format: + DD°MM'SS"C DDD°MM'SS"C, where C is the compass point representing the locations quadrant */ + meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS = 1, + /* Universal Transverse Mercator format: + ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing */ + meshtastic_Config_DisplayConfig_GpsCoordinateFormat_UTM = 2, + /* Military Grid Reference System format: + ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square, + E is easting, N is northing */ + meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MGRS = 3, + /* Open Location Code (aka Plus Codes). */ + meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OLC = 4, + /* Ordnance Survey Grid Reference (the National Grid System of the UK). + Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square, + E is the easting, N is the northing */ + meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR = 5 +} meshtastic_Config_DisplayConfig_GpsCoordinateFormat; /* Unit display preference */ typedef enum _meshtastic_Config_DisplayConfig_DisplayUnits { @@ -473,7 +491,7 @@ typedef struct _meshtastic_Config_DisplayConfig { uint32_t screen_on_secs; /* Deprecated in 2.7.4: Unused How the GPS coordinates are formatted on the OLED screen. */ - meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat gps_format; + meshtastic_Config_DisplayConfig_GpsCoordinateFormat gps_format; /* Automatically toggles to the next page on the screen like a carousel, based the specified interval in seconds. Potentially useful for devices without user buttons. */ uint32_t auto_screen_carousel_secs; @@ -497,9 +515,6 @@ typedef struct _meshtastic_Config_DisplayConfig { /* If false (default), the device will display the time in 24-hour format on screen. If true, the device will display the time in 12-hour format on screen. */ bool use_12h_clock; - /* If false (default), the device will use short names for various display screens. - If true, node names will show in long format */ - bool use_long_node_name; } meshtastic_Config_DisplayConfig; /* Lora Config */ @@ -663,9 +678,9 @@ extern "C" { #define _meshtastic_Config_NetworkConfig_ProtocolFlags_MAX meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST #define _meshtastic_Config_NetworkConfig_ProtocolFlags_ARRAYSIZE ((meshtastic_Config_NetworkConfig_ProtocolFlags)(meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST+1)) -#define _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_MIN meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_UNUSED -#define _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_MAX meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_UNUSED -#define _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat)(meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_UNUSED+1)) +#define _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DEC +#define _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MAX meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR +#define _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_ARRAYSIZE ((meshtastic_Config_DisplayConfig_GpsCoordinateFormat)(meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR+1)) #define _meshtastic_Config_DisplayConfig_DisplayUnits_MIN meshtastic_Config_DisplayConfig_DisplayUnits_METRIC #define _meshtastic_Config_DisplayConfig_DisplayUnits_MAX meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL @@ -706,7 +721,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_address_mode_ENUMTYPE meshtastic_Config_NetworkConfig_AddressMode -#define meshtastic_Config_DisplayConfig_gps_format_ENUMTYPE meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat +#define meshtastic_Config_DisplayConfig_gps_format_ENUMTYPE meshtastic_Config_DisplayConfig_GpsCoordinateFormat #define meshtastic_Config_DisplayConfig_units_ENUMTYPE meshtastic_Config_DisplayConfig_DisplayUnits #define meshtastic_Config_DisplayConfig_oled_ENUMTYPE meshtastic_Config_DisplayConfig_OledType #define meshtastic_Config_DisplayConfig_displaymode_ENUMTYPE meshtastic_Config_DisplayConfig_DisplayMode @@ -727,7 +742,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, "", 0, 0} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} -#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN, 0, 0} +#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN, 0} #define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} #define meshtastic_Config_SecurityConfig_init_default {{0, {0}}, {0, {0}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}}, 0, 0, 0, 0} @@ -738,7 +753,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, "", 0, 0} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} -#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN, 0, 0} +#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN, 0} #define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0} #define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} #define meshtastic_Config_SecurityConfig_init_zero {{0, {0}}, {0, {0}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}}, 0, 0, 0, 0} @@ -805,7 +820,6 @@ extern "C" { #define meshtastic_Config_DisplayConfig_wake_on_tap_or_motion_tag 10 #define meshtastic_Config_DisplayConfig_compass_orientation_tag 11 #define meshtastic_Config_DisplayConfig_use_12h_clock_tag 12 -#define meshtastic_Config_DisplayConfig_use_long_node_name_tag 13 #define meshtastic_Config_LoRaConfig_use_preset_tag 1 #define meshtastic_Config_LoRaConfig_modem_preset_tag 2 #define meshtastic_Config_LoRaConfig_bandwidth_tag 3 @@ -951,8 +965,7 @@ X(a, STATIC, SINGULAR, UENUM, displaymode, 8) \ X(a, STATIC, SINGULAR, BOOL, heading_bold, 9) \ X(a, STATIC, SINGULAR, BOOL, wake_on_tap_or_motion, 10) \ X(a, STATIC, SINGULAR, UENUM, compass_orientation, 11) \ -X(a, STATIC, SINGULAR, BOOL, use_12h_clock, 12) \ -X(a, STATIC, SINGULAR, BOOL, use_long_node_name, 13) +X(a, STATIC, SINGULAR, BOOL, use_12h_clock, 12) #define meshtastic_Config_DisplayConfig_CALLBACK NULL #define meshtastic_Config_DisplayConfig_DEFAULT NULL @@ -1030,7 +1043,7 @@ extern const pb_msgdesc_t meshtastic_Config_SessionkeyConfig_msg; #define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size #define meshtastic_Config_BluetoothConfig_size 10 #define meshtastic_Config_DeviceConfig_size 100 -#define meshtastic_Config_DisplayConfig_size 34 +#define meshtastic_Config_DisplayConfig_size 32 #define meshtastic_Config_LoRaConfig_size 85 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 204 diff --git a/src/mesh/generated/meshtastic/device_ui.pb.cpp b/src/mesh/generated/meshtastic/device_ui.pb.cpp index 01940265f..2fc8d9461 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.cpp +++ b/src/mesh/generated/meshtastic/device_ui.pb.cpp @@ -28,5 +28,3 @@ PB_BIND(meshtastic_Map, meshtastic_Map, AUTO) - - diff --git a/src/mesh/generated/meshtastic/device_ui.pb.h b/src/mesh/generated/meshtastic/device_ui.pb.h index d9eb90773..8f693e570 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.h +++ b/src/mesh/generated/meshtastic/device_ui.pb.h @@ -74,32 +74,6 @@ typedef enum _meshtastic_Language { meshtastic_Language_TRADITIONAL_CHINESE = 31 } meshtastic_Language; -/* How the GPS coordinates are displayed on the OLED screen. */ -typedef enum _meshtastic_DeviceUIConfig_GpsCoordinateFormat { - /* GPS coordinates are displayed in the normal decimal degrees format: - DD.DDDDDD DDD.DDDDDD */ - meshtastic_DeviceUIConfig_GpsCoordinateFormat_DEC = 0, - /* GPS coordinates are displayed in the degrees minutes seconds format: - DD°MM'SS"C DDD°MM'SS"C, where C is the compass point representing the locations quadrant */ - meshtastic_DeviceUIConfig_GpsCoordinateFormat_DMS = 1, - /* Universal Transverse Mercator format: - ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing */ - meshtastic_DeviceUIConfig_GpsCoordinateFormat_UTM = 2, - /* Military Grid Reference System format: - ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square, - E is easting, N is northing */ - meshtastic_DeviceUIConfig_GpsCoordinateFormat_MGRS = 3, - /* Open Location Code (aka Plus Codes). */ - meshtastic_DeviceUIConfig_GpsCoordinateFormat_OLC = 4, - /* Ordnance Survey Grid Reference (the National Grid System of the UK). - Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square, - E is the easting, N is the northing */ - meshtastic_DeviceUIConfig_GpsCoordinateFormat_OSGR = 5, - /* Maidenhead Locator System - Described here: https://en.wikipedia.org/wiki/Maidenhead_Locator_System */ - meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS = 6 -} meshtastic_DeviceUIConfig_GpsCoordinateFormat; - /* Struct definitions */ typedef struct _meshtastic_NodeFilter { /* Filter unknown nodes */ @@ -189,8 +163,6 @@ typedef struct _meshtastic_DeviceUIConfig { /* Clockface analog style true for analog clockface, false for digital clockface */ bool is_clockface_analog; - /* How the GPS coordinates are formatted on the OLED screen. */ - meshtastic_DeviceUIConfig_GpsCoordinateFormat gps_format; } meshtastic_DeviceUIConfig; @@ -211,14 +183,9 @@ extern "C" { #define _meshtastic_Language_MAX meshtastic_Language_TRADITIONAL_CHINESE #define _meshtastic_Language_ARRAYSIZE ((meshtastic_Language)(meshtastic_Language_TRADITIONAL_CHINESE+1)) -#define _meshtastic_DeviceUIConfig_GpsCoordinateFormat_MIN meshtastic_DeviceUIConfig_GpsCoordinateFormat_DEC -#define _meshtastic_DeviceUIConfig_GpsCoordinateFormat_MAX meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS -#define _meshtastic_DeviceUIConfig_GpsCoordinateFormat_ARRAYSIZE ((meshtastic_DeviceUIConfig_GpsCoordinateFormat)(meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS+1)) - #define meshtastic_DeviceUIConfig_theme_ENUMTYPE meshtastic_Theme #define meshtastic_DeviceUIConfig_language_ENUMTYPE meshtastic_Language #define meshtastic_DeviceUIConfig_compass_mode_ENUMTYPE meshtastic_CompassMode -#define meshtastic_DeviceUIConfig_gps_format_ENUMTYPE meshtastic_DeviceUIConfig_GpsCoordinateFormat @@ -226,12 +193,12 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default, {0, {0}}, false, meshtastic_Map_init_default, _meshtastic_CompassMode_MIN, 0, 0, _meshtastic_DeviceUIConfig_GpsCoordinateFormat_MIN} +#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default, {0, {0}}, false, meshtastic_Map_init_default, _meshtastic_CompassMode_MIN, 0, 0} #define meshtastic_NodeFilter_init_default {0, 0, 0, 0, 0, "", 0} #define meshtastic_NodeHighlight_init_default {0, 0, 0, 0, ""} #define meshtastic_GeoPoint_init_default {0, 0, 0} #define meshtastic_Map_init_default {false, meshtastic_GeoPoint_init_default, "", 0} -#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero, {0, {0}}, false, meshtastic_Map_init_zero, _meshtastic_CompassMode_MIN, 0, 0, _meshtastic_DeviceUIConfig_GpsCoordinateFormat_MIN} +#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero, {0, {0}}, false, meshtastic_Map_init_zero, _meshtastic_CompassMode_MIN, 0, 0} #define meshtastic_NodeFilter_init_zero {0, 0, 0, 0, 0, "", 0} #define meshtastic_NodeHighlight_init_zero {0, 0, 0, 0, ""} #define meshtastic_GeoPoint_init_zero {0, 0, 0} @@ -274,7 +241,6 @@ extern "C" { #define meshtastic_DeviceUIConfig_compass_mode_tag 16 #define meshtastic_DeviceUIConfig_screen_rgb_color_tag 17 #define meshtastic_DeviceUIConfig_is_clockface_analog_tag 18 -#define meshtastic_DeviceUIConfig_gps_format_tag 19 /* Struct field encoding specification for nanopb */ #define meshtastic_DeviceUIConfig_FIELDLIST(X, a) \ @@ -295,8 +261,7 @@ X(a, STATIC, SINGULAR, BYTES, calibration_data, 14) \ X(a, STATIC, OPTIONAL, MESSAGE, map_data, 15) \ X(a, STATIC, SINGULAR, UENUM, compass_mode, 16) \ X(a, STATIC, SINGULAR, UINT32, screen_rgb_color, 17) \ -X(a, STATIC, SINGULAR, BOOL, is_clockface_analog, 18) \ -X(a, STATIC, SINGULAR, UENUM, gps_format, 19) +X(a, STATIC, SINGULAR, BOOL, is_clockface_analog, 18) #define meshtastic_DeviceUIConfig_CALLBACK NULL #define meshtastic_DeviceUIConfig_DEFAULT NULL #define meshtastic_DeviceUIConfig_node_filter_MSGTYPE meshtastic_NodeFilter @@ -353,7 +318,7 @@ extern const pb_msgdesc_t meshtastic_Map_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_DEVICE_UI_PB_H_MAX_SIZE meshtastic_DeviceUIConfig_size -#define meshtastic_DeviceUIConfig_size 204 +#define meshtastic_DeviceUIConfig_size 201 #define meshtastic_GeoPoint_size 33 #define meshtastic_Map_size 58 #define meshtastic_NodeFilter_size 47 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 148261fc8..9b6330596 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -94,9 +94,6 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; - /* True if node has been muted - Persists between NodeDB internal clean ups */ - bool is_muted; /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ uint8_t next_hop; /* Bitfield for storing booleans. @@ -193,14 +190,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_NodeDatabase_init_default {0, {0}} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_BackupPreferences_init_default {0, 0, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default, false, meshtastic_ChannelFile_init_default, false, meshtastic_User_init_default} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_NodeDatabase_init_zero {0, {0}} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} @@ -231,9 +228,8 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 -#define meshtastic_NodeInfoLite_is_muted_tag 12 -#define meshtastic_NodeInfoLite_next_hop_tag 13 -#define meshtastic_NodeInfoLite_bitfield_tag 14 +#define meshtastic_NodeInfoLite_next_hop_tag 12 +#define meshtastic_NodeInfoLite_bitfield_tag 13 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -288,9 +284,8 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, BOOL, is_muted, 12) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 13) \ -X(a, STATIC, SINGULAR, UINT32, bitfield, 14) +X(a, STATIC, SINGULAR, UINT32, next_hop, 12) \ +X(a, STATIC, SINGULAR, UINT32, bitfield, 13) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -365,10 +360,10 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_NodeDatabase_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size -#define meshtastic_BackupPreferences_size 2289 -#define meshtastic_ChannelFile_size 734 +#define meshtastic_BackupPreferences_size 2273 +#define meshtastic_ChannelFile_size 718 #define meshtastic_DeviceState_size 1737 -#define meshtastic_NodeInfoLite_size 198 +#define meshtastic_NodeInfoLite_size 196 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 98 diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 3ab6f02c1..da224fb94 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -187,8 +187,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size -#define meshtastic_LocalConfig_size 749 -#define meshtastic_LocalModuleConfig_size 673 +#define meshtastic_LocalConfig_size 747 +#define meshtastic_LocalModuleConfig_size 671 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 6292ce070..2a4e77870 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -259,8 +259,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_T_DECK_PRO = 102, /* Lilygo TLora Pager */ meshtastic_HardwareModel_T_LORA_PAGER = 103, - /* M5Stack Reserved */ - meshtastic_HardwareModel_M5STACK_RESERVED = 104, /* 0x68 */ + /* GAT562 Mesh Trial Tracker */ + meshtastic_HardwareModel_GAT562_MESH_TRIAL_TRACKER = 104, /* RAKwireless WisMesh Tag */ meshtastic_HardwareModel_WISMESH_TAG = 105, /* RAKwireless WisBlock Core RAK3312 https://docs.rakwireless.com/product-categories/wisduo/rak3112-module/overview/ */ @@ -274,10 +274,6 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_T_ECHO_LITE = 109, /* New Heltec LoRA32 with ESP32-S3 CPU */ meshtastic_HardwareModel_HELTEC_V4 = 110, - /* M5Stack C6L */ - meshtastic_HardwareModel_M5STACK_C6L = 111, - /* M5Stack Cardputer Adv */ - meshtastic_HardwareModel_M5STACK_CARDPUTER_ADV = 112, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 47d3b5baa..16c4c230c 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -356,9 +356,6 @@ typedef struct _meshtastic_ModuleConfig_TelemetryConfig { uint32_t health_update_interval; /* Enable/Disable the health telemetry module on-device display */ bool health_screen_enabled; - /* Enable/Disable the device telemetry module to send metrics to the mesh - Note: We will still send telemtry to the connected phone / client every minute over the API */ - bool device_telemetry_enabled; } meshtastic_ModuleConfig_TelemetryConfig; /* Canned Messages Module Config */ @@ -526,7 +523,7 @@ extern "C" { #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0, 0} -#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0} #define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN} @@ -542,7 +539,7 @@ extern "C" { #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0, 0} -#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0} #define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN} @@ -630,7 +627,6 @@ extern "C" { #define meshtastic_ModuleConfig_TelemetryConfig_health_measurement_enabled_tag 11 #define meshtastic_ModuleConfig_TelemetryConfig_health_update_interval_tag 12 #define meshtastic_ModuleConfig_TelemetryConfig_health_screen_enabled_tag 13 -#define meshtastic_ModuleConfig_TelemetryConfig_device_telemetry_enabled_tag 14 #define meshtastic_ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1 #define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2 #define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3 @@ -829,8 +825,7 @@ X(a, STATIC, SINGULAR, UINT32, power_update_interval, 9) \ X(a, STATIC, SINGULAR, BOOL, power_screen_enabled, 10) \ X(a, STATIC, SINGULAR, BOOL, health_measurement_enabled, 11) \ X(a, STATIC, SINGULAR, UINT32, health_update_interval, 12) \ -X(a, STATIC, SINGULAR, BOOL, health_screen_enabled, 13) \ -X(a, STATIC, SINGULAR, BOOL, device_telemetry_enabled, 14) +X(a, STATIC, SINGULAR, BOOL, health_screen_enabled, 13) #define meshtastic_ModuleConfig_TelemetryConfig_CALLBACK NULL #define meshtastic_ModuleConfig_TelemetryConfig_DEFAULT NULL @@ -915,7 +910,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_SerialConfig_size 28 #define meshtastic_ModuleConfig_StoreForwardConfig_size 24 -#define meshtastic_ModuleConfig_TelemetryConfig_size 48 +#define meshtastic_ModuleConfig_TelemetryConfig_size 46 #define meshtastic_ModuleConfig_size 227 #define meshtastic_RemoteHardwarePin_size 21 From 0db2e40ee356c02203b5e91963d4b5cd5ac14032 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Mon, 22 Sep 2025 15:05:53 +1200 Subject: [PATCH 035/166] Use latest protos --- src/mesh/generated/meshtastic/config.pb.h | 49 +++++++------------ .../generated/meshtastic/device_ui.pb.cpp | 2 + src/mesh/generated/meshtastic/device_ui.pb.h | 43 ++++++++++++++-- src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 4 +- src/mesh/generated/meshtastic/mesh.pb.h | 8 ++- .../generated/meshtastic/module_config.pb.h | 13 +++-- 7 files changed, 77 insertions(+), 44 deletions(-) diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 59e55db3f..0453ecad2 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -173,28 +173,10 @@ typedef enum _meshtastic_Config_NetworkConfig_ProtocolFlags { meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST = 1 } meshtastic_Config_NetworkConfig_ProtocolFlags; -/* How the GPS coordinates are displayed on the OLED screen. */ -typedef enum _meshtastic_Config_DisplayConfig_GpsCoordinateFormat { - /* GPS coordinates are displayed in the normal decimal degrees format: - DD.DDDDDD DDD.DDDDDD */ - meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DEC = 0, - /* GPS coordinates are displayed in the degrees minutes seconds format: - DD°MM'SS"C DDD°MM'SS"C, where C is the compass point representing the locations quadrant */ - meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS = 1, - /* Universal Transverse Mercator format: - ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing */ - meshtastic_Config_DisplayConfig_GpsCoordinateFormat_UTM = 2, - /* Military Grid Reference System format: - ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square, - E is easting, N is northing */ - meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MGRS = 3, - /* Open Location Code (aka Plus Codes). */ - meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OLC = 4, - /* Ordnance Survey Grid Reference (the National Grid System of the UK). - Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square, - E is the easting, N is the northing */ - meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR = 5 -} meshtastic_Config_DisplayConfig_GpsCoordinateFormat; +/* Deprecated in 2.7.4: Unused */ +typedef enum _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat { + meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_UNUSED = 0 +} meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat; /* Unit display preference */ typedef enum _meshtastic_Config_DisplayConfig_DisplayUnits { @@ -491,7 +473,7 @@ typedef struct _meshtastic_Config_DisplayConfig { uint32_t screen_on_secs; /* Deprecated in 2.7.4: Unused How the GPS coordinates are formatted on the OLED screen. */ - meshtastic_Config_DisplayConfig_GpsCoordinateFormat gps_format; + meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat gps_format; /* Automatically toggles to the next page on the screen like a carousel, based the specified interval in seconds. Potentially useful for devices without user buttons. */ uint32_t auto_screen_carousel_secs; @@ -515,6 +497,9 @@ typedef struct _meshtastic_Config_DisplayConfig { /* If false (default), the device will display the time in 24-hour format on screen. If true, the device will display the time in 12-hour format on screen. */ bool use_12h_clock; + /* If false (default), the device will use short names for various display screens. + If true, node names will show in long format */ + bool use_long_node_name; } meshtastic_Config_DisplayConfig; /* Lora Config */ @@ -678,9 +663,9 @@ extern "C" { #define _meshtastic_Config_NetworkConfig_ProtocolFlags_MAX meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST #define _meshtastic_Config_NetworkConfig_ProtocolFlags_ARRAYSIZE ((meshtastic_Config_NetworkConfig_ProtocolFlags)(meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST+1)) -#define _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DEC -#define _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MAX meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR -#define _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_ARRAYSIZE ((meshtastic_Config_DisplayConfig_GpsCoordinateFormat)(meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR+1)) +#define _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_MIN meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_UNUSED +#define _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_MAX meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_UNUSED +#define _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat)(meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_UNUSED+1)) #define _meshtastic_Config_DisplayConfig_DisplayUnits_MIN meshtastic_Config_DisplayConfig_DisplayUnits_METRIC #define _meshtastic_Config_DisplayConfig_DisplayUnits_MAX meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL @@ -721,7 +706,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_address_mode_ENUMTYPE meshtastic_Config_NetworkConfig_AddressMode -#define meshtastic_Config_DisplayConfig_gps_format_ENUMTYPE meshtastic_Config_DisplayConfig_GpsCoordinateFormat +#define meshtastic_Config_DisplayConfig_gps_format_ENUMTYPE meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat #define meshtastic_Config_DisplayConfig_units_ENUMTYPE meshtastic_Config_DisplayConfig_DisplayUnits #define meshtastic_Config_DisplayConfig_oled_ENUMTYPE meshtastic_Config_DisplayConfig_OledType #define meshtastic_Config_DisplayConfig_displaymode_ENUMTYPE meshtastic_Config_DisplayConfig_DisplayMode @@ -742,7 +727,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, "", 0, 0} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} -#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN, 0} +#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN, 0, 0} #define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} #define meshtastic_Config_SecurityConfig_init_default {{0, {0}}, {0, {0}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}}, 0, 0, 0, 0} @@ -753,7 +738,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, "", 0, 0} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} -#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN, 0} +#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_DeprecatedGpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN, 0, 0} #define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0} #define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} #define meshtastic_Config_SecurityConfig_init_zero {{0, {0}}, {0, {0}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}}, 0, 0, 0, 0} @@ -820,6 +805,7 @@ extern "C" { #define meshtastic_Config_DisplayConfig_wake_on_tap_or_motion_tag 10 #define meshtastic_Config_DisplayConfig_compass_orientation_tag 11 #define meshtastic_Config_DisplayConfig_use_12h_clock_tag 12 +#define meshtastic_Config_DisplayConfig_use_long_node_name_tag 13 #define meshtastic_Config_LoRaConfig_use_preset_tag 1 #define meshtastic_Config_LoRaConfig_modem_preset_tag 2 #define meshtastic_Config_LoRaConfig_bandwidth_tag 3 @@ -965,7 +951,8 @@ X(a, STATIC, SINGULAR, UENUM, displaymode, 8) \ X(a, STATIC, SINGULAR, BOOL, heading_bold, 9) \ X(a, STATIC, SINGULAR, BOOL, wake_on_tap_or_motion, 10) \ X(a, STATIC, SINGULAR, UENUM, compass_orientation, 11) \ -X(a, STATIC, SINGULAR, BOOL, use_12h_clock, 12) +X(a, STATIC, SINGULAR, BOOL, use_12h_clock, 12) \ +X(a, STATIC, SINGULAR, BOOL, use_long_node_name, 13) #define meshtastic_Config_DisplayConfig_CALLBACK NULL #define meshtastic_Config_DisplayConfig_DEFAULT NULL @@ -1043,7 +1030,7 @@ extern const pb_msgdesc_t meshtastic_Config_SessionkeyConfig_msg; #define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size #define meshtastic_Config_BluetoothConfig_size 10 #define meshtastic_Config_DeviceConfig_size 100 -#define meshtastic_Config_DisplayConfig_size 32 +#define meshtastic_Config_DisplayConfig_size 34 #define meshtastic_Config_LoRaConfig_size 85 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 204 diff --git a/src/mesh/generated/meshtastic/device_ui.pb.cpp b/src/mesh/generated/meshtastic/device_ui.pb.cpp index 2fc8d9461..01940265f 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.cpp +++ b/src/mesh/generated/meshtastic/device_ui.pb.cpp @@ -28,3 +28,5 @@ PB_BIND(meshtastic_Map, meshtastic_Map, AUTO) + + diff --git a/src/mesh/generated/meshtastic/device_ui.pb.h b/src/mesh/generated/meshtastic/device_ui.pb.h index 8f693e570..d9eb90773 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.h +++ b/src/mesh/generated/meshtastic/device_ui.pb.h @@ -74,6 +74,32 @@ typedef enum _meshtastic_Language { meshtastic_Language_TRADITIONAL_CHINESE = 31 } meshtastic_Language; +/* How the GPS coordinates are displayed on the OLED screen. */ +typedef enum _meshtastic_DeviceUIConfig_GpsCoordinateFormat { + /* GPS coordinates are displayed in the normal decimal degrees format: + DD.DDDDDD DDD.DDDDDD */ + meshtastic_DeviceUIConfig_GpsCoordinateFormat_DEC = 0, + /* GPS coordinates are displayed in the degrees minutes seconds format: + DD°MM'SS"C DDD°MM'SS"C, where C is the compass point representing the locations quadrant */ + meshtastic_DeviceUIConfig_GpsCoordinateFormat_DMS = 1, + /* Universal Transverse Mercator format: + ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing */ + meshtastic_DeviceUIConfig_GpsCoordinateFormat_UTM = 2, + /* Military Grid Reference System format: + ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square, + E is easting, N is northing */ + meshtastic_DeviceUIConfig_GpsCoordinateFormat_MGRS = 3, + /* Open Location Code (aka Plus Codes). */ + meshtastic_DeviceUIConfig_GpsCoordinateFormat_OLC = 4, + /* Ordnance Survey Grid Reference (the National Grid System of the UK). + Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square, + E is the easting, N is the northing */ + meshtastic_DeviceUIConfig_GpsCoordinateFormat_OSGR = 5, + /* Maidenhead Locator System + Described here: https://en.wikipedia.org/wiki/Maidenhead_Locator_System */ + meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS = 6 +} meshtastic_DeviceUIConfig_GpsCoordinateFormat; + /* Struct definitions */ typedef struct _meshtastic_NodeFilter { /* Filter unknown nodes */ @@ -163,6 +189,8 @@ typedef struct _meshtastic_DeviceUIConfig { /* Clockface analog style true for analog clockface, false for digital clockface */ bool is_clockface_analog; + /* How the GPS coordinates are formatted on the OLED screen. */ + meshtastic_DeviceUIConfig_GpsCoordinateFormat gps_format; } meshtastic_DeviceUIConfig; @@ -183,9 +211,14 @@ extern "C" { #define _meshtastic_Language_MAX meshtastic_Language_TRADITIONAL_CHINESE #define _meshtastic_Language_ARRAYSIZE ((meshtastic_Language)(meshtastic_Language_TRADITIONAL_CHINESE+1)) +#define _meshtastic_DeviceUIConfig_GpsCoordinateFormat_MIN meshtastic_DeviceUIConfig_GpsCoordinateFormat_DEC +#define _meshtastic_DeviceUIConfig_GpsCoordinateFormat_MAX meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS +#define _meshtastic_DeviceUIConfig_GpsCoordinateFormat_ARRAYSIZE ((meshtastic_DeviceUIConfig_GpsCoordinateFormat)(meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS+1)) + #define meshtastic_DeviceUIConfig_theme_ENUMTYPE meshtastic_Theme #define meshtastic_DeviceUIConfig_language_ENUMTYPE meshtastic_Language #define meshtastic_DeviceUIConfig_compass_mode_ENUMTYPE meshtastic_CompassMode +#define meshtastic_DeviceUIConfig_gps_format_ENUMTYPE meshtastic_DeviceUIConfig_GpsCoordinateFormat @@ -193,12 +226,12 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default, {0, {0}}, false, meshtastic_Map_init_default, _meshtastic_CompassMode_MIN, 0, 0} +#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default, {0, {0}}, false, meshtastic_Map_init_default, _meshtastic_CompassMode_MIN, 0, 0, _meshtastic_DeviceUIConfig_GpsCoordinateFormat_MIN} #define meshtastic_NodeFilter_init_default {0, 0, 0, 0, 0, "", 0} #define meshtastic_NodeHighlight_init_default {0, 0, 0, 0, ""} #define meshtastic_GeoPoint_init_default {0, 0, 0} #define meshtastic_Map_init_default {false, meshtastic_GeoPoint_init_default, "", 0} -#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero, {0, {0}}, false, meshtastic_Map_init_zero, _meshtastic_CompassMode_MIN, 0, 0} +#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero, {0, {0}}, false, meshtastic_Map_init_zero, _meshtastic_CompassMode_MIN, 0, 0, _meshtastic_DeviceUIConfig_GpsCoordinateFormat_MIN} #define meshtastic_NodeFilter_init_zero {0, 0, 0, 0, 0, "", 0} #define meshtastic_NodeHighlight_init_zero {0, 0, 0, 0, ""} #define meshtastic_GeoPoint_init_zero {0, 0, 0} @@ -241,6 +274,7 @@ extern "C" { #define meshtastic_DeviceUIConfig_compass_mode_tag 16 #define meshtastic_DeviceUIConfig_screen_rgb_color_tag 17 #define meshtastic_DeviceUIConfig_is_clockface_analog_tag 18 +#define meshtastic_DeviceUIConfig_gps_format_tag 19 /* Struct field encoding specification for nanopb */ #define meshtastic_DeviceUIConfig_FIELDLIST(X, a) \ @@ -261,7 +295,8 @@ X(a, STATIC, SINGULAR, BYTES, calibration_data, 14) \ X(a, STATIC, OPTIONAL, MESSAGE, map_data, 15) \ X(a, STATIC, SINGULAR, UENUM, compass_mode, 16) \ X(a, STATIC, SINGULAR, UINT32, screen_rgb_color, 17) \ -X(a, STATIC, SINGULAR, BOOL, is_clockface_analog, 18) +X(a, STATIC, SINGULAR, BOOL, is_clockface_analog, 18) \ +X(a, STATIC, SINGULAR, UENUM, gps_format, 19) #define meshtastic_DeviceUIConfig_CALLBACK NULL #define meshtastic_DeviceUIConfig_DEFAULT NULL #define meshtastic_DeviceUIConfig_node_filter_MSGTYPE meshtastic_NodeFilter @@ -318,7 +353,7 @@ extern const pb_msgdesc_t meshtastic_Map_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_DEVICE_UI_PB_H_MAX_SIZE meshtastic_DeviceUIConfig_size -#define meshtastic_DeviceUIConfig_size 201 +#define meshtastic_DeviceUIConfig_size 204 #define meshtastic_GeoPoint_size 33 #define meshtastic_Map_size 58 #define meshtastic_NodeFilter_size 47 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 9b6330596..7fab82ff7 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -360,7 +360,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_NodeDatabase_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size -#define meshtastic_BackupPreferences_size 2273 +#define meshtastic_BackupPreferences_size 2277 #define meshtastic_ChannelFile_size 718 #define meshtastic_DeviceState_size 1737 #define meshtastic_NodeInfoLite_size 196 diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index da224fb94..3ab6f02c1 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -187,8 +187,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size -#define meshtastic_LocalConfig_size 747 -#define meshtastic_LocalModuleConfig_size 671 +#define meshtastic_LocalConfig_size 749 +#define meshtastic_LocalModuleConfig_size 673 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 2a4e77870..6292ce070 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -259,8 +259,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_T_DECK_PRO = 102, /* Lilygo TLora Pager */ meshtastic_HardwareModel_T_LORA_PAGER = 103, - /* GAT562 Mesh Trial Tracker */ - meshtastic_HardwareModel_GAT562_MESH_TRIAL_TRACKER = 104, + /* M5Stack Reserved */ + meshtastic_HardwareModel_M5STACK_RESERVED = 104, /* 0x68 */ /* RAKwireless WisMesh Tag */ meshtastic_HardwareModel_WISMESH_TAG = 105, /* RAKwireless WisBlock Core RAK3312 https://docs.rakwireless.com/product-categories/wisduo/rak3112-module/overview/ */ @@ -274,6 +274,10 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_T_ECHO_LITE = 109, /* New Heltec LoRA32 with ESP32-S3 CPU */ meshtastic_HardwareModel_HELTEC_V4 = 110, + /* M5Stack C6L */ + meshtastic_HardwareModel_M5STACK_C6L = 111, + /* M5Stack Cardputer Adv */ + meshtastic_HardwareModel_M5STACK_CARDPUTER_ADV = 112, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 16c4c230c..47d3b5baa 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -356,6 +356,9 @@ typedef struct _meshtastic_ModuleConfig_TelemetryConfig { uint32_t health_update_interval; /* Enable/Disable the health telemetry module on-device display */ bool health_screen_enabled; + /* Enable/Disable the device telemetry module to send metrics to the mesh + Note: We will still send telemtry to the connected phone / client every minute over the API */ + bool device_telemetry_enabled; } meshtastic_ModuleConfig_TelemetryConfig; /* Canned Messages Module Config */ @@ -523,7 +526,7 @@ extern "C" { #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0, 0} -#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0} #define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN} @@ -539,7 +542,7 @@ extern "C" { #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0, 0} -#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0} #define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN} @@ -627,6 +630,7 @@ extern "C" { #define meshtastic_ModuleConfig_TelemetryConfig_health_measurement_enabled_tag 11 #define meshtastic_ModuleConfig_TelemetryConfig_health_update_interval_tag 12 #define meshtastic_ModuleConfig_TelemetryConfig_health_screen_enabled_tag 13 +#define meshtastic_ModuleConfig_TelemetryConfig_device_telemetry_enabled_tag 14 #define meshtastic_ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1 #define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2 #define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3 @@ -825,7 +829,8 @@ X(a, STATIC, SINGULAR, UINT32, power_update_interval, 9) \ X(a, STATIC, SINGULAR, BOOL, power_screen_enabled, 10) \ X(a, STATIC, SINGULAR, BOOL, health_measurement_enabled, 11) \ X(a, STATIC, SINGULAR, UINT32, health_update_interval, 12) \ -X(a, STATIC, SINGULAR, BOOL, health_screen_enabled, 13) +X(a, STATIC, SINGULAR, BOOL, health_screen_enabled, 13) \ +X(a, STATIC, SINGULAR, BOOL, device_telemetry_enabled, 14) #define meshtastic_ModuleConfig_TelemetryConfig_CALLBACK NULL #define meshtastic_ModuleConfig_TelemetryConfig_DEFAULT NULL @@ -910,7 +915,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_SerialConfig_size 28 #define meshtastic_ModuleConfig_StoreForwardConfig_size 24 -#define meshtastic_ModuleConfig_TelemetryConfig_size 46 +#define meshtastic_ModuleConfig_TelemetryConfig_size 48 #define meshtastic_ModuleConfig_size 227 #define meshtastic_RemoteHardwarePin_size 21 From 319cd6fa7bf50a2c409874b3438efef68c64712f Mon Sep 17 00:00:00 2001 From: ford-jones Date: Mon, 22 Sep 2025 15:14:31 +1200 Subject: [PATCH 036/166] Regen protos for latest changes --- src/mesh/generated/meshtastic/admin.pb.h | 8 +++++++ src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/channel.pb.h | 14 +++++++---- src/mesh/generated/meshtastic/deviceonly.pb.h | 23 +++++++++++-------- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index bc0b780b9..616b7e8ee 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -247,6 +247,10 @@ typedef struct _meshtastic_AdminMessage { uint32_t set_ignored_node; /* Set specified node-num to be un-ignored on the NodeDB on the device */ uint32_t remove_ignored_node; + /* Set specified node-num to be muted */ + uint32_t set_muted_node; + /* Set specified node-num to be heard / not-muted */ + uint32_t remove_muted_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -388,6 +392,8 @@ extern "C" { #define meshtastic_AdminMessage_store_ui_config_tag 46 #define meshtastic_AdminMessage_set_ignored_node_tag 47 #define meshtastic_AdminMessage_remove_ignored_node_tag 48 +#define meshtastic_AdminMessage_set_muted_node_tag 49 +#define meshtastic_AdminMessage_remove_muted_node_tag 50 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 @@ -446,6 +452,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,set_muted_node,set_muted_node), 49) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_muted_node,remove_muted_node), 50) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index f4c33bd79..db9dedaaf 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 679 +#define meshtastic_ChannelSet_size 695 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index ca4310bf1..594d15929 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -97,6 +97,8 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; + /* Whether or not we should receive notifactions / alerts from this channel */ + bool mute; } meshtastic_ChannelSettings; /* A pair of a channel number, mode and the (sharable) settings for that channel */ @@ -128,10 +130,10 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default} +#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0} #define meshtastic_ModuleSettings_init_default {0, 0} #define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN} -#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero} +#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0} #define meshtastic_ModuleSettings_init_zero {0, 0} #define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN} @@ -145,6 +147,7 @@ extern "C" { #define meshtastic_ChannelSettings_uplink_enabled_tag 5 #define meshtastic_ChannelSettings_downlink_enabled_tag 6 #define meshtastic_ChannelSettings_module_settings_tag 7 +#define meshtastic_ChannelSettings_mute_tag 8 #define meshtastic_Channel_index_tag 1 #define meshtastic_Channel_settings_tag 2 #define meshtastic_Channel_role_tag 3 @@ -157,7 +160,8 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \ X(a, STATIC, SINGULAR, FIXED32, id, 4) \ X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \ -X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) +X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \ +X(a, STATIC, SINGULAR, BOOL, mute, 8) #define meshtastic_ChannelSettings_CALLBACK NULL #define meshtastic_ChannelSettings_DEFAULT NULL #define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings @@ -187,8 +191,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size -#define meshtastic_ChannelSettings_size 72 -#define meshtastic_Channel_size 87 +#define meshtastic_ChannelSettings_size 74 +#define meshtastic_Channel_size 89 #define meshtastic_ModuleSettings_size 8 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 7fab82ff7..04264ae76 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -94,6 +94,9 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; + /* True if node has been muted + Persists between NodeDB internal clean ups */ + bool is_muted; /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ uint8_t next_hop; /* Bitfield for storing booleans. @@ -190,14 +193,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_NodeDatabase_init_default {0, {0}} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_BackupPreferences_init_default {0, 0, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default, false, meshtastic_ChannelFile_init_default, false, meshtastic_User_init_default} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_NodeDatabase_init_zero {0, {0}} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} @@ -228,8 +231,9 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 -#define meshtastic_NodeInfoLite_next_hop_tag 12 -#define meshtastic_NodeInfoLite_bitfield_tag 13 +#define meshtastic_NodeInfoLite_is_muted_tag 12 +#define meshtastic_NodeInfoLite_next_hop_tag 13 +#define meshtastic_NodeInfoLite_bitfield_tag 14 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -284,8 +288,9 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 12) \ -X(a, STATIC, SINGULAR, UINT32, bitfield, 13) +X(a, STATIC, SINGULAR, BOOL, is_muted, 12) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 13) \ +X(a, STATIC, SINGULAR, UINT32, bitfield, 14) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -360,10 +365,10 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_NodeDatabase_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size -#define meshtastic_BackupPreferences_size 2277 -#define meshtastic_ChannelFile_size 718 +#define meshtastic_BackupPreferences_size 2293 +#define meshtastic_ChannelFile_size 734 #define meshtastic_DeviceState_size 1737 -#define meshtastic_NodeInfoLite_size 196 +#define meshtastic_NodeInfoLite_size 198 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 98 From e7840122e8f1622a4ea36d58873bd63f81f3e3a3 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Tue, 23 Sep 2025 11:40:45 +1200 Subject: [PATCH 037/166] Decouple node-mute from channel-mute --- src/graphics/Screen.cpp | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 8 -------- src/mesh/generated/meshtastic/deviceonly.pb.h | 11 +++-------- src/modules/AdminModule.cpp | 18 ------------------ src/modules/ExternalNotificationModule.cpp | 6 +++--- 5 files changed, 7 insertions(+), 38 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index df0b2a1cc..c8381db36 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1468,7 +1468,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) strcpy(banner, "Alert Received"); } screen->showSimpleBanner(banner, 3000); - } else if (!node->is_muted && !channel.settings.mute) { + } else if (!channel.settings.mute) { if (longName && longName[0]) { #if defined(M5STACK_UNITC6L) strcpy(banner, "New Message"); diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index 616b7e8ee..bc0b780b9 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -247,10 +247,6 @@ typedef struct _meshtastic_AdminMessage { uint32_t set_ignored_node; /* Set specified node-num to be un-ignored on the NodeDB on the device */ uint32_t remove_ignored_node; - /* Set specified node-num to be muted */ - uint32_t set_muted_node; - /* Set specified node-num to be heard / not-muted */ - uint32_t remove_muted_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -392,8 +388,6 @@ extern "C" { #define meshtastic_AdminMessage_store_ui_config_tag 46 #define meshtastic_AdminMessage_set_ignored_node_tag 47 #define meshtastic_AdminMessage_remove_ignored_node_tag 48 -#define meshtastic_AdminMessage_set_muted_node_tag 49 -#define meshtastic_AdminMessage_remove_muted_node_tag 50 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 @@ -452,8 +446,6 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ -X(a, STATIC, ONEOF, UINT32, (payload_variant,set_muted_node,set_muted_node), 49) \ -X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_muted_node,remove_muted_node), 50) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 04264ae76..a7a6b81d9 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -94,9 +94,6 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; - /* True if node has been muted - Persists between NodeDB internal clean ups */ - bool is_muted; /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ uint8_t next_hop; /* Bitfield for storing booleans. @@ -193,14 +190,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_NodeDatabase_init_default {0, {0}} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_BackupPreferences_init_default {0, 0, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default, false, meshtastic_ChannelFile_init_default, false, meshtastic_User_init_default} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_NodeDatabase_init_zero {0, {0}} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} @@ -231,7 +228,6 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 -#define meshtastic_NodeInfoLite_is_muted_tag 12 #define meshtastic_NodeInfoLite_next_hop_tag 13 #define meshtastic_NodeInfoLite_bitfield_tag 14 #define meshtastic_DeviceState_my_node_tag 2 @@ -288,7 +284,6 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, BOOL, is_muted, 12) \ X(a, STATIC, SINGULAR, UINT32, next_hop, 13) \ X(a, STATIC, SINGULAR, UINT32, bitfield, 14) #define meshtastic_NodeInfoLite_CALLBACK NULL @@ -368,7 +363,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; #define meshtastic_BackupPreferences_size 2293 #define meshtastic_ChannelFile_size 734 #define meshtastic_DeviceState_size 1737 -#define meshtastic_NodeInfoLite_size 198 +#define meshtastic_NodeInfoLite_size 196 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 98 diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 0877c969b..79ea7bc0c 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -369,24 +369,6 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta } break; } - case meshtastic_AdminMessage_set_muted_node_tag: { - LOG_INFO("Client received set_muted_node command"); - meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->set_muted_node); - if (node != NULL) { - node->is_muted = true; - saveChanges(SEGMENT_NODEDATABASE, false); - } - break; - } - case meshtastic_AdminMessage_remove_muted_node_tag: { - LOG_INFO("Client received remove_muted_node command"); - meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->remove_muted_node); - if (node != NULL) { - node->is_muted = false; - saveChanges(SEGMENT_NODEDATABASE, false); - } - break; - } case meshtastic_AdminMessage_set_fixed_position_tag: { LOG_INFO("Client received set_fixed_position command"); meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum()); diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 92590f149..5ee7834db 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -510,7 +510,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message && !sender->is_muted && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_message && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module"); isNagging = true; setExternalState(0, true); @@ -521,7 +521,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_vibra && !sender->is_muted && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_message_vibra && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module (Vibra)"); isNagging = true; setExternalState(1, true); @@ -532,7 +532,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_buzzer && !sender->is_muted && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_message_buzzer && !ch.settings.mute) { LOG_INFO("externalNotificationModule - Notification Module (Buzzer)"); isNagging = true; if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) { From 2fbfb193049639d5128f5bafe76d04c84985dfb6 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Tue, 23 Sep 2025 12:40:48 +1200 Subject: [PATCH 038/166] Regen protos --- src/mesh/generated/meshtastic/channel.pb.h | 2 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index 594d15929..d5573a1e2 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -97,7 +97,7 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; - /* Whether or not we should receive notifactions / alerts from this channel */ + /* Whether or not we should receive notifactions / alerts through this channel */ bool mute; } meshtastic_ChannelSettings; diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index a7a6b81d9..b5b116137 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -228,8 +228,8 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 -#define meshtastic_NodeInfoLite_next_hop_tag 13 -#define meshtastic_NodeInfoLite_bitfield_tag 14 +#define meshtastic_NodeInfoLite_next_hop_tag 12 +#define meshtastic_NodeInfoLite_bitfield_tag 13 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -284,8 +284,8 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 13) \ -X(a, STATIC, SINGULAR, UINT32, bitfield, 14) +X(a, STATIC, SINGULAR, UINT32, next_hop, 12) \ +X(a, STATIC, SINGULAR, UINT32, bitfield, 13) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite From a1ca553bc0ac5695d512879ac2bffe1c858cbb1d Mon Sep 17 00:00:00 2001 From: WillyJL Date: Tue, 23 Sep 2025 22:30:01 +0200 Subject: [PATCH 039/166] Fix desktop build --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 5f2501cc8..48ecc14c7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1596,7 +1596,7 @@ void loop() #endif service->loop(); -#if !MESHTASTIC_EXCLUDE_INPUTBROKER +#if !MESHTASTIC_EXCLUDE_INPUTBROKER && defined(HAS_FREE_RTOS) inputBroker->processInputEventQueue(); #endif #if defined(LGFX_SDL) From 060a1299953166c77414f759ddba2558ae23a175 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Wed, 24 Sep 2025 03:05:26 +0200 Subject: [PATCH 040/166] More flexible InputPollable paradigm --- src/input/InputBroker.cpp | 14 +++++++++++--- src/input/InputBroker.h | 2 +- src/input/RotaryEncoderImpl.cpp | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/input/InputBroker.cpp b/src/input/InputBroker.cpp index 5ca890b43..c588a9a0f 100644 --- a/src/input/InputBroker.cpp +++ b/src/input/InputBroker.cpp @@ -18,14 +18,22 @@ void InputBroker::registerSource(Observable *source) } #ifdef HAS_FREE_RTOS -void InputBroker::pollSoonRequestFromIsr(InputPollable *pollable) +void InputBroker::requestPollSoon(InputPollable *pollable) { - xQueueSendFromISR(pollSoonQueue, &pollable, NULL); + if (xPortInIsrContext() == pdTRUE) { + xQueueSendFromISR(pollSoonQueue, &pollable, NULL); + } else { + xQueueSend(pollSoonQueue, &pollable, 0); + } } void InputBroker::queueInputEvent(const InputEvent *event) { - xQueueSend(inputEventQueue, event, portMAX_DELAY); + if (xPortInIsrContext() == pdTRUE) { + xQueueSendFromISR(inputEventQueue, event, NULL); + } else { + xQueueSend(inputEventQueue, event, portMAX_DELAY); + } } void InputBroker::processInputEventQueue() diff --git a/src/input/InputBroker.h b/src/input/InputBroker.h index 82af184f3..192bd7e8b 100644 --- a/src/input/InputBroker.h +++ b/src/input/InputBroker.h @@ -60,7 +60,7 @@ class InputBroker : public Observable void registerSource(Observable *source); void injectInputEvent(const InputEvent *event) { handleInputEvent(event); } #ifdef HAS_FREE_RTOS - void pollSoonRequestFromIsr(InputPollable *pollable); + void requestPollSoon(InputPollable *pollable); void queueInputEvent(const InputEvent *event); void processInputEventQueue(); #endif diff --git a/src/input/RotaryEncoderImpl.cpp b/src/input/RotaryEncoderImpl.cpp index 213dd4faa..7b43fa256 100644 --- a/src/input/RotaryEncoderImpl.cpp +++ b/src/input/RotaryEncoderImpl.cpp @@ -30,7 +30,7 @@ bool RotaryEncoderImpl::init() rotary->resetButton(); interruptInstance = this; - auto interruptHandler = []() { inputBroker->pollSoonRequestFromIsr(interruptInstance); }; + auto interruptHandler = []() { inputBroker->requestPollSoon(interruptInstance); }; attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE); attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE); attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE); From edb5c0f88ed9adbf0d0b30bdbc89f69046d6ce26 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Wed, 24 Sep 2025 04:19:11 +0200 Subject: [PATCH 041/166] Custom xPortInIsrContext() for nRF52/RP2xx0 --- src/platform/nrf52/architecture.h | 3 +++ src/platform/rp2xx0/architecture.h | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index c9938062e..56b46088a 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -149,3 +149,6 @@ // No serial ports on this board - ONLY use segger in memory console #define USE_SEGGER #endif + +// Detect if running in ISR context (ARM Cortex-M4) +#define xPortInIsrContext() ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) == 0 ? pdFALSE : pdTRUE) diff --git a/src/platform/rp2xx0/architecture.h b/src/platform/rp2xx0/architecture.h index 506c19c83..0c168ceee 100644 --- a/src/platform/rp2xx0/architecture.h +++ b/src/platform/rp2xx0/architecture.h @@ -35,4 +35,7 @@ #define HW_VENDOR meshtastic_HardwareModel_RP2040_FEATHER_RFM95 #elif defined(PRIVATE_HW) #define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW -#endif \ No newline at end of file +#endif + +// Detect if running in ISR context (ARM Cortex-M33 / RISC-V) +#define xPortInIsrContext() (__get_current_exception() == 0 ? pdFALSE : pdTRUE) From 6448f069f84a0732026d192a37fa99a1a430711f Mon Sep 17 00:00:00 2001 From: ford-jones Date: Sun, 28 Sep 2025 13:17:57 +1300 Subject: [PATCH 042/166] Use channel as specified in the received packet --- src/modules/ExternalNotificationModule.cpp | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 5ee7834db..97d51fbd2 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -69,7 +69,7 @@ bool ascending = true; #endif #define EXT_NOTIFICATION_MODULE_OUTPUT_MS 1000 -#define EXT_NOTIFICATION_DEFAULT_THREAD_MS 25 +#define EXT_NOTIFICATION_FAST_THREAD_MS 25 #define ASCII_BELL 0x07 @@ -88,12 +88,13 @@ int32_t ExternalNotificationModule::runOnce() if (!moduleConfig.external_notification.enabled) { return INT32_MAX; // we don't need this thread here... } else { - - bool isPlaying = rtttl::isPlaying(); + uint32_t delay = EXT_NOTIFICATION_MODULE_OUTPUT_MS; + bool isRtttlPlaying = rtttl::isPlaying(); #ifdef HAS_I2S - isPlaying = rtttl::isPlaying() || audioThread->isPlaying(); + // audioThread->isPlaying() also handles actually playing the RTTTL, needs to be called in loop + isRtttlPlaying = isRtttlPlaying || audioThread->isPlaying(); #endif - if ((nagCycleCutoff < millis()) && !isPlaying) { + if ((nagCycleCutoff < millis()) && !isRtttlPlaying) { // let the song finish if we reach timeout nagCycleCutoff = UINT32_MAX; LOG_INFO("Turning off external notification: "); @@ -116,21 +117,16 @@ int32_t ExternalNotificationModule::runOnce() // If the output is turned on, turn it back off after the given period of time. if (isNagging) { - if (externalTurnedOn[0] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms - : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < - millis()) { + delay = (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms + : EXT_NOTIFICATION_MODULE_OUTPUT_MS); + if (externalTurnedOn[0] + delay < millis()) { setExternalState(0, !getExternal(0)); } - if (externalTurnedOn[1] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms - : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < - millis()) { + if (externalTurnedOn[1] + delay < millis()) { setExternalState(1, !getExternal(1)); } // Only toggle buzzer output if not using PWM mode (to avoid conflict with RTTTL) - if (!moduleConfig.external_notification.use_pwm && - externalTurnedOn[2] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms - : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < - millis()) { + if (!moduleConfig.external_notification.use_pwm && externalTurnedOn[2] + delay < millis()) { LOG_DEBUG("EXTERNAL 2 %d compared to %d", externalTurnedOn[2] + moduleConfig.external_notification.output_ms, millis()); setExternalState(2, !getExternal(2)); @@ -181,6 +177,8 @@ int32_t ExternalNotificationModule::runOnce() colorState = 1; } } + // we need fast updates for the color change + delay = EXT_NOTIFICATION_FAST_THREAD_MS; #endif #ifdef T_WATCH_S3 @@ -190,12 +188,14 @@ int32_t ExternalNotificationModule::runOnce() // Play RTTTL over i2s audio interface if enabled as buzzer #ifdef HAS_I2S - if (moduleConfig.external_notification.use_i2s_as_buzzer && canBuzz()) { + if (moduleConfig.external_notification.use_i2s_as_buzzer) { if (audioThread->isPlaying()) { // Continue playing } else if (isNagging && (nagCycleCutoff >= millis())) { audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone)); } + // we need fast updates to play the RTTTL + delay = EXT_NOTIFICATION_FAST_THREAD_MS; } #endif // now let the PWM buzzer play @@ -206,9 +206,11 @@ int32_t ExternalNotificationModule::runOnce() // start the song again if we have time left rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); } + // we need fast updates to play the RTTTL + delay = EXT_NOTIFICATION_FAST_THREAD_MS; } - return EXT_NOTIFICATION_DEFAULT_THREAD_MS; + return delay; } } @@ -457,9 +459,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from); - meshtastic_Channel ch = channels.getByIndex(sender->channel ? sender->channel : channels.getPrimaryIndex()); - + meshtastic_Channel ch = channels.getByIndex(mp.channel ? mp.channel : channels.getPrimaryIndex()); if (moduleConfig.external_notification.alert_bell) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell"); From abc011aeb974d24e905cdf9babf38bcdbc99451b Mon Sep 17 00:00:00 2001 From: ford-jones Date: Sun, 28 Sep 2025 16:26:45 +1300 Subject: [PATCH 043/166] Use channel as specified in the received packet for OLED screen notifications --- src/graphics/Screen.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 44421e8fa..e6cee1824 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1458,7 +1458,8 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) } // === Prepare banner content === const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from); - const meshtastic_Channel channel = channels.getByIndex(node->channel ? node->channel : channels.getPrimaryIndex()); + const meshtastic_Channel channel = + channels.getByIndex(packet->channel ? packet->channel : channels.getPrimaryIndex()); const char *longName = (node && node->has_user) ? node->user.long_name : nullptr; const char *msgRaw = reinterpret_cast(packet->decoded.payload.bytes); From 033fc0c8f392d203194cbb8d5a93fea03977db64 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 28 Sep 2025 13:13:07 -0500 Subject: [PATCH 044/166] Validate CR and SF lora config (#8146) * Validate CR and SF lora config * No zero-bw * Update src/modules/AdminModule.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix braces --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/modules/AdminModule.cpp | 45 +++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 79ea7bc0c..1e2d4ebe8 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -707,20 +707,40 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) #endif config.display = c.payload_variant.display; break; - case meshtastic_Config_lora_tag: + + case meshtastic_Config_lora_tag: { + // Wrap the entire case in a block to scope variables and avoid crossing initialization + auto oldLoraConfig = config.lora; + auto validatedLora = c.payload_variant.lora; + LOG_INFO("Set config: LoRa"); config.has_lora = true; + + if (validatedLora.coding_rate < 4 || validatedLora.coding_rate > 8) { + LOG_WARN("Invalid coding_rate %d, setting to 5", validatedLora.coding_rate); + validatedLora.coding_rate = 5; + } + + if (validatedLora.spread_factor < 7 || validatedLora.spread_factor > 12) { + LOG_WARN("Invalid spread_factor %d, setting to 11", validatedLora.spread_factor); + validatedLora.spread_factor = 11; + } + + if (validatedLora.bandwidth == 0) { + int originalBandwidth = validatedLora.bandwidth; + validatedLora.bandwidth = myRegion->wideLora ? 800 : 250; + LOG_WARN("Invalid bandwidth %d, setting to default", originalBandwidth); + } + // If no lora radio parameters change, don't need to reboot - if (config.lora.use_preset == c.payload_variant.lora.use_preset && config.lora.region == c.payload_variant.lora.region && - config.lora.modem_preset == c.payload_variant.lora.modem_preset && - config.lora.bandwidth == c.payload_variant.lora.bandwidth && - config.lora.spread_factor == c.payload_variant.lora.spread_factor && - config.lora.coding_rate == c.payload_variant.lora.coding_rate && - config.lora.tx_power == c.payload_variant.lora.tx_power && - config.lora.frequency_offset == c.payload_variant.lora.frequency_offset && - config.lora.override_frequency == c.payload_variant.lora.override_frequency && - config.lora.channel_num == c.payload_variant.lora.channel_num && - config.lora.sx126x_rx_boosted_gain == c.payload_variant.lora.sx126x_rx_boosted_gain) { + if (oldLoraConfig.use_preset == validatedLora.use_preset && oldLoraConfig.region == validatedLora.region && + oldLoraConfig.modem_preset == validatedLora.modem_preset && oldLoraConfig.bandwidth == validatedLora.bandwidth && + oldLoraConfig.spread_factor == validatedLora.spread_factor && + oldLoraConfig.coding_rate == validatedLora.coding_rate && oldLoraConfig.tx_power == validatedLora.tx_power && + oldLoraConfig.frequency_offset == validatedLora.frequency_offset && + oldLoraConfig.override_frequency == validatedLora.override_frequency && + oldLoraConfig.channel_num == validatedLora.channel_num && + oldLoraConfig.sx126x_rx_boosted_gain == validatedLora.sx126x_rx_boosted_gain) { requiresReboot = false; } @@ -739,7 +759,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) digitalWrite(RF95_FAN_EN, HIGH ^ 0); } #endif - config.lora = c.payload_variant.lora; + config.lora = validatedLora; // If we're setting region for the first time, init the region and regenerate the keys if (isRegionUnset && config.lora.region > meshtastic_Config_LoRaConfig_RegionCode_UNSET) { if (!owner.is_licensed) { @@ -771,6 +791,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) } } break; + } case meshtastic_Config_bluetooth_tag: LOG_INFO("Set config: Bluetooth"); config.has_bluetooth = true; From a15d6547678272726f5338f232183411008a1844 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 28 Sep 2025 15:30:53 -0500 Subject: [PATCH 045/166] Finish deprecating the Repeater role behavior (#8144) * Finish deprecating the Repeater role behavior * Validate * Fixed bad if/else block * Get your crap together! --- src/DisplayFormatters.cpp | 3 - src/gps/GPS.cpp | 5 - src/main.cpp | 12 +- src/mesh/FloodingRouter.cpp | 5 +- src/mesh/FloodingRouter.h | 2 +- src/mesh/MeshService.cpp | 7 +- src/mesh/NextHopRouter.cpp | 5 +- src/mesh/NodeDB.cpp | 10 +- src/mesh/RadioInterface.cpp | 5 +- src/mesh/Router.cpp | 4 - src/modules/AdminModule.cpp | 15 +- src/modules/Modules.cpp | 219 ++++++++++------------ src/modules/NodeInfoModule.cpp | 5 - src/modules/RoutingModule.cpp | 2 - src/modules/Telemetry/DeviceTelemetry.cpp | 5 - src/modules/Telemetry/HostMetrics.cpp | 4 - src/sleep.cpp | 3 +- userPrefs.jsonc | 2 +- 18 files changed, 126 insertions(+), 187 deletions(-) diff --git a/src/DisplayFormatters.cpp b/src/DisplayFormatters.cpp index 5193e1cb4..246cf0022 100644 --- a/src/DisplayFormatters.cpp +++ b/src/DisplayFormatters.cpp @@ -76,9 +76,6 @@ const char *DisplayFormatters::getDeviceRole(meshtastic_Config_DeviceConfig_Role case meshtastic_Config_DeviceConfig_Role_ROUTER_LATE: return "Router Late"; break; - case meshtastic_Config_DeviceConfig_Role_REPEATER: - return "Repeater"; - break; default: return "Unknown"; break; diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 3bf2710fe..0487d1fea 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1104,11 +1104,6 @@ int32_t GPS::runOnce() publishUpdate(); } - // Repeaters have no need for GPS - if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { - return disable(); - } - if (whileActive()) { // if we have received valid NMEA claim we are connected setConnected(); diff --git a/src/main.cpp b/src/main.cpp index 38c8e8ca5..29a608dfe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -793,14 +793,7 @@ void setup() } #endif - // If we're taking on the repeater role, use NextHopRouter and turn off 3V3_S rail because peripherals are not needed - if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { - router = new NextHopRouter(); -#ifdef PIN_3V3_EN - digitalWrite(PIN_3V3_EN, LOW); -#endif - } else - router = new ReliableRouter(); + router = new ReliableRouter(); // only play start melody when role is not tracker or sensor if (config.power.is_power_saving == true && @@ -926,8 +919,7 @@ void setup() if (sensor_detected == false) { #endif if (HAS_GPS) { - if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && - config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) { + if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) { gps = GPS::createGps(); if (gps) { gpsStatus->observe(&gps->newStatus); diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 3caee78f8..5d2d7653a 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -81,9 +81,8 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) bool FloodingRouter::roleAllowsCancelingDupe(const meshtastic_MeshPacket *p) { if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || - config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER || config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE) { - // ROUTER, REPEATER, ROUTER_LATE should never cancel relaying a packet (i.e. we should always rebroadcast), + // ROUTER, ROUTER_LATE should never cancel relaying a packet (i.e. we should always rebroadcast), // even if we've heard another station rebroadcast it already. return false; } @@ -102,7 +101,7 @@ bool FloodingRouter::roleAllowsCancelingDupe(const meshtastic_MeshPacket *p) void FloodingRouter::perhapsCancelDupe(const meshtastic_MeshPacket *p) { if (p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA && roleAllowsCancelingDupe(p)) { - // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! + // cancel rebroadcast of this message *if* there was already one, unless we're a router! // But only LoRa packets should be able to trigger this. if (Router::cancelSending(p->from, p->id)) txRelayCanceled++; diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index 30ad5945b..eaf71d294 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -59,7 +59,7 @@ class FloodingRouter : public Router */ virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; - // Return false for roles like ROUTER or REPEATER which should always rebroadcast even when we've heard another rebroadcast of + // Return false for roles like ROUTER which should always rebroadcast even when we've heard another rebroadcast of // the same packet bool roleAllowsCancelingDupe(const meshtastic_MeshPacket *p); diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index a138ad1d1..1b2af082d 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -85,12 +85,11 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp) powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping nodeDB->updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio - bool isPreferredRebroadcaster = - IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER, meshtastic_Config_DeviceConfig_Role_REPEATER); + bool isPreferredRebroadcaster = config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER; if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp->decoded.portnum == meshtastic_PortNum_TELEMETRY_APP && mp->decoded.request_id > 0) { - LOG_DEBUG("Received telemetry response. Skip sending our NodeInfo"); // because this potentially a Repeater which will - // ignore our request for its NodeInfo + LOG_DEBUG("Received telemetry response. Skip sending our NodeInfo"); + // ignore our request for its NodeInfo } else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user && nodeInfoModule && !isPreferredRebroadcaster && !nodeDB->isFull()) { if (airTime->isTxAllowedChannelUtil(true)) { diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 4ae0a818e..cb483bc97 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -170,7 +170,6 @@ bool NextHopRouter::perhapsRelay(const meshtastic_MeshPacket *p) */ uint8_t NextHopRouter::getNextHop(NodeNum to, uint8_t relay_node) { - // When we're a repeater router->sniffReceived will call NextHopRouter directly without checking for broadcast if (isBroadcast(to)) return NO_NEXT_HOP_PREFERENCE; @@ -208,7 +207,7 @@ bool NextHopRouter::roleAllowsCancelingFromTxQueue(const meshtastic_MeshPacket * { // Return true if we're allowed to cancel a packet in the txQueue (so we may never transmit it even once) - // Return false for roles like ROUTER, REPEATER, ROUTER_LATE which should always transmit the packet at least once. + // Return false for roles like ROUTER, ROUTER_LATE which should always transmit the packet at least once. return roleAllowsCancelingDupe(p); // same logic as FloodingRouter::roleAllowsCancelingDupe } @@ -221,7 +220,7 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key) /* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue to avoid canceling a transmission if it was ACKed super fast via MQTT */ if (old->numRetransmissions < NUM_RELIABLE_RETX - 1) { - // We only cancel it if we are the original sender or if we're not a router(_late)/repeater + // We only cancel it if we are the original sender or if we're not a router(_late) if (isFromUs(p) || roleAllowsCancelingFromTxQueue(p)) { // remove the 'original' (identified by originator and packet->id) from the txqueue and free it cancelSending(getFrom(p), p->id); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index b512ae675..a32ee37f9 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -554,10 +554,9 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) #endif #ifdef USERPREFS_CONFIG_DEVICE_ROLE - // Restrict ROUTER*, LOST AND FOUND, and REPEATER roles for security reasons + // Restrict ROUTER*, LOST AND FOUND roles for security reasons if (IS_ONE_OF(USERPREFS_CONFIG_DEVICE_ROLE, meshtastic_Config_DeviceConfig_Role_ROUTER, - meshtastic_Config_DeviceConfig_Role_ROUTER_LATE, meshtastic_Config_DeviceConfig_Role_REPEATER, - meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND)) { + meshtastic_Config_DeviceConfig_Role_ROUTER_LATE, meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND)) { LOG_WARN("ROUTER roles are restricted, falling back to CLIENT role"); config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; } else { @@ -906,11 +905,6 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) moduleConfig.telemetry.device_update_interval = ONE_DAY; owner.has_is_unmessagable = true; owner.is_unmessagable = true; - } else if (role == meshtastic_Config_DeviceConfig_Role_REPEATER) { - owner.has_is_unmessagable = true; - owner.is_unmessagable = true; - config.display.screen_on_secs = 1; - config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY; } else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) { owner.has_is_unmessagable = true; owner.is_unmessagable = true; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 31c68c302..5233b8698 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -317,9 +317,8 @@ uint32_t RadioInterface::getTxDelayMsecWeightedWorst(float snr) /** Returns true if we should rebroadcast early like a ROUTER */ bool RadioInterface::shouldRebroadcastEarlyLikeRouter(meshtastic_MeshPacket *p) { - // If we are a ROUTER or REPEATER, we always rebroadcast early - if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || - config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { + // If we are a ROUTER, we always rebroadcast early + if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) { return true; } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 7f17737e5..8f9fb28f9 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -399,10 +399,6 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p) { concurrency::LockGuard g(cryptLock); - if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER && - config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_ALL_SKIP_DECODING) - return DecodeState::DECODE_FAILURE; - if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY && (nodeDB->getMeshNode(p->from) == NULL || !nodeDB->getMeshNode(p->from)->has_user)) { LOG_DEBUG("Node 0x%x not in nodeDB-> Rebroadcast mode KNOWN_ONLY will ignore packet", p->from); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 1e2d4ebe8..7544db121 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -611,10 +611,9 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) } config.device = c.payload_variant.device; if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_NONE && - IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER, - meshtastic_Config_DeviceConfig_Role_REPEATER)) { + config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) { config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_ALL; - const char *warning = "Rebroadcast mode can't be set to NONE for a router or repeater"; + const char *warning = "Rebroadcast mode can't be set to NONE for a router"; LOG_WARN(warning); sendWarning(warning); } @@ -627,8 +626,9 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) LOG_DEBUG("Tried to set node_info_broadcast_secs too low, setting to %d", min_node_info_broadcast_secs); config.device.node_info_broadcast_secs = min_node_info_broadcast_secs; } - // Router Client is deprecated; Set it to client - if (c.payload_variant.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT) { + // Router Client and Repeater deprecated; Set it to client + if (IS_ONE_OF(c.payload_variant.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT, + meshtastic_Config_DeviceConfig_Role_REPEATER)) { config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; if (moduleConfig.store_forward.enabled && !moduleConfig.store_forward.is_server) { moduleConfig.store_forward.is_server = true; @@ -637,10 +637,9 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) } } #if USERPREFS_EVENT_MODE - // If we're in event mode, nobody is a Router or Repeater + // If we're in event mode, nobody is a Router or Router Late if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || - config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE || - config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { + config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE) { config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; } #endif diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index bd8997493..02962dd59 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -112,204 +112,191 @@ */ void setupModules() { - if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { #if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { - inputBroker = new InputBroker(); - systemCommandsModule = new SystemCommandsModule(); - buzzerFeedbackThread = new BuzzerFeedbackThread(); - } + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + inputBroker = new InputBroker(); + systemCommandsModule = new SystemCommandsModule(); + buzzerFeedbackThread = new BuzzerFeedbackThread(); + } #endif #if !MESHTASTIC_EXCLUDE_ADMIN - adminModule = new AdminModule(); + adminModule = new AdminModule(); #endif #if !MESHTASTIC_EXCLUDE_NODEINFO - nodeInfoModule = new NodeInfoModule(); + nodeInfoModule = new NodeInfoModule(); #endif #if !MESHTASTIC_EXCLUDE_GPS - positionModule = new PositionModule(); + positionModule = new PositionModule(); #endif #if !MESHTASTIC_EXCLUDE_WAYPOINT - waypointModule = new WaypointModule(); + waypointModule = new WaypointModule(); #endif #if !MESHTASTIC_EXCLUDE_TEXTMESSAGE - textMessageModule = new TextMessageModule(); + textMessageModule = new TextMessageModule(); #endif #if !MESHTASTIC_EXCLUDE_TRACEROUTE - traceRouteModule = new TraceRouteModule(); + traceRouteModule = new TraceRouteModule(); #endif #if !MESHTASTIC_EXCLUDE_NEIGHBORINFO - if (moduleConfig.has_neighbor_info && moduleConfig.neighbor_info.enabled) { - neighborInfoModule = new NeighborInfoModule(); - } + if (moduleConfig.has_neighbor_info && moduleConfig.neighbor_info.enabled) { + neighborInfoModule = new NeighborInfoModule(); + } #endif #if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR - if (moduleConfig.has_detection_sensor && moduleConfig.detection_sensor.enabled) { - detectionSensorModule = new DetectionSensorModule(); - } + if (moduleConfig.has_detection_sensor && moduleConfig.detection_sensor.enabled) { + detectionSensorModule = new DetectionSensorModule(); + } #endif #if !MESHTASTIC_EXCLUDE_ATAK - if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TAK, - meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)) { - atakPluginModule = new AtakPluginModule(); - } + if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TAK, meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)) { + atakPluginModule = new AtakPluginModule(); + } #endif #if !MESHTASTIC_EXCLUDE_PKI - keyVerificationModule = new KeyVerificationModule(); + keyVerificationModule = new KeyVerificationModule(); #endif #if !MESHTASTIC_EXCLUDE_DROPZONE - dropzoneModule = new DropzoneModule(); + dropzoneModule = new DropzoneModule(); #endif #if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE - new GenericThreadModule(); + new GenericThreadModule(); #endif - // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance - // to a global variable. + // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance + // to a global variable. #if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE - new RemoteHardwareModule(); + new RemoteHardwareModule(); #endif #if !MESHTASTIC_EXCLUDE_POWERSTRESS - new PowerStressModule(); + new PowerStressModule(); #endif - // Example: Put your module here - // new ReplyModule(); + // Example: Put your module here + // new ReplyModule(); #if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { - rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); - if (!rotaryEncoderInterruptImpl1->init()) { - delete rotaryEncoderInterruptImpl1; - rotaryEncoderInterruptImpl1 = nullptr; - } + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); + if (!rotaryEncoderInterruptImpl1->init()) { + delete rotaryEncoderInterruptImpl1; + rotaryEncoderInterruptImpl1 = nullptr; + } #ifdef T_LORA_PAGER - // use a special FSM based rotary encoder version for T-LoRa Pager - rotaryEncoderImpl = new RotaryEncoderImpl(); - if (!rotaryEncoderImpl->init()) { - delete rotaryEncoderImpl; - rotaryEncoderImpl = nullptr; - } + // use a special FSM based rotary encoder version for T-LoRa Pager + rotaryEncoderImpl = new RotaryEncoderImpl(); + if (!rotaryEncoderImpl->init()) { + delete rotaryEncoderImpl; + rotaryEncoderImpl = nullptr; + } #else - upDownInterruptImpl1 = new UpDownInterruptImpl1(); - if (!upDownInterruptImpl1->init()) { - delete upDownInterruptImpl1; - upDownInterruptImpl1 = nullptr; - } + upDownInterruptImpl1 = new UpDownInterruptImpl1(); + if (!upDownInterruptImpl1->init()) { + delete upDownInterruptImpl1; + upDownInterruptImpl1 = nullptr; + } #endif - cardKbI2cImpl = new CardKbI2cImpl(); - cardKbI2cImpl->init(); + cardKbI2cImpl = new CardKbI2cImpl(); + cardKbI2cImpl->init(); #if defined(M5STACK_UNITC6L) - i2cButton = new i2cButtonThread("i2cButtonThread"); + i2cButton = new i2cButtonThread("i2cButtonThread"); #endif #ifdef INPUTBROKER_MATRIX_TYPE - kbMatrixImpl = new KbMatrixImpl(); - kbMatrixImpl->init(); + kbMatrixImpl = new KbMatrixImpl(); + kbMatrixImpl->init(); #endif // INPUTBROKER_MATRIX_TYPE #ifdef INPUTBROKER_SERIAL_TYPE - aSerialKeyboardImpl = new SerialKeyboardImpl(); - aSerialKeyboardImpl->init(); + aSerialKeyboardImpl = new SerialKeyboardImpl(); + aSerialKeyboardImpl->init(); #endif // INPUTBROKER_MATRIX_TYPE - } + } #endif // HAS_BUTTON #if ARCH_PORTDUINO - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { - seesawRotary = new SeesawRotary("SeesawRotary"); - if (!seesawRotary->init()) { - delete seesawRotary; - seesawRotary = nullptr; - } - aLinuxInputImpl = new LinuxInputImpl(); - aLinuxInputImpl->init(); + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + seesawRotary = new SeesawRotary("SeesawRotary"); + if (!seesawRotary->init()) { + delete seesawRotary; + seesawRotary = nullptr; } + aLinuxInputImpl = new LinuxInputImpl(); + aLinuxInputImpl->init(); + } #endif #if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { - trackballInterruptImpl1 = new TrackballInterruptImpl1(); - trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS); - } + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + trackballInterruptImpl1 = new TrackballInterruptImpl1(); + trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS); + } #endif #ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE - expressLRSFiveWayInput = new ExpressLRSFiveWay(); + expressLRSFiveWayInput = new ExpressLRSFiveWay(); #endif #if HAS_SCREEN && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { - cannedMessageModule = new CannedMessageModule(); - } + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + cannedMessageModule = new CannedMessageModule(); + } #endif #if ARCH_PORTDUINO - new HostMetricsModule(); + new HostMetricsModule(); #endif #if HAS_TELEMETRY - new DeviceTelemetryModule(); + new DeviceTelemetryModule(); #endif #if HAS_TELEMETRY && HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR - if (moduleConfig.has_telemetry && - (moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled)) { - new EnvironmentTelemetryModule(); - } + if (moduleConfig.has_telemetry && + (moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled)) { + new EnvironmentTelemetryModule(); + } #if __has_include("Adafruit_PM25AQI.h") - if (moduleConfig.has_telemetry && moduleConfig.telemetry.air_quality_enabled && - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) { - new AirQualityTelemetryModule(); - } + if (moduleConfig.has_telemetry && moduleConfig.telemetry.air_quality_enabled && + nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) { + new AirQualityTelemetryModule(); + } #endif #if !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY - if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MAX30102].first > 0 || - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MLX90614].first > 0) { - new HealthTelemetryModule(); - } + if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MAX30102].first > 0 || + nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MLX90614].first > 0) { + new HealthTelemetryModule(); + } #endif #endif #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR - if (moduleConfig.has_telemetry && - (moduleConfig.telemetry.power_measurement_enabled || moduleConfig.telemetry.power_screen_enabled)) { - new PowerTelemetryModule(); - } + if (moduleConfig.has_telemetry && + (moduleConfig.telemetry.power_measurement_enabled || moduleConfig.telemetry.power_screen_enabled)) { + new PowerTelemetryModule(); + } #endif #if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \ !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) #if !MESHTASTIC_EXCLUDE_SERIAL - if (moduleConfig.has_serial && moduleConfig.serial.enabled && - config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { - new SerialModule(); - } + if (moduleConfig.has_serial && moduleConfig.serial.enabled && + config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + new SerialModule(); + } #endif #endif #ifdef ARCH_ESP32 - // Only run on an esp32 based device. + // Only run on an esp32 based device. #if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO - audioModule = new AudioModule(); + audioModule = new AudioModule(); #endif #if !MESHTASTIC_EXCLUDE_PAXCOUNTER - if (moduleConfig.has_paxcounter && moduleConfig.paxcounter.enabled) { - paxcounterModule = new PaxcounterModule(); - } + if (moduleConfig.has_paxcounter && moduleConfig.paxcounter.enabled) { + paxcounterModule = new PaxcounterModule(); + } #endif #endif #if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) #if !MESHTASTIC_EXCLUDE_STOREFORWARD - if (moduleConfig.has_store_forward && moduleConfig.store_forward.enabled) { - storeForwardModule = new StoreForwardModule(); - } + if (moduleConfig.has_store_forward && moduleConfig.store_forward.enabled) { + storeForwardModule = new StoreForwardModule(); + } #endif #endif #if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION - externalNotificationModule = new ExternalNotificationModule(); + externalNotificationModule = new ExternalNotificationModule(); #endif #if !MESHTASTIC_EXCLUDE_RANGETEST && !MESHTASTIC_EXCLUDE_GPS - if (moduleConfig.has_range_test && moduleConfig.range_test.enabled) - new RangeTestModule(); + if (moduleConfig.has_range_test && moduleConfig.range_test.enabled) + new RangeTestModule(); #endif - } else { -#if !MESHTASTIC_EXCLUDE_ADMIN - adminModule = new AdminModule(); -#endif -#if HAS_TELEMETRY - new DeviceTelemetryModule(); -#endif -#if !MESHTASTIC_EXCLUDE_TRACEROUTE - traceRouteModule = new TraceRouteModule(); -#endif - } // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra // acks routingModule = new RoutingModule(); diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 276a11b3a..2c3c274d2 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -94,11 +94,6 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply() u.public_key.bytes[0] = 0; u.public_key.size = 0; } - // Coerce unmessagable for Repeater role - if (u.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { - u.has_is_unmessagable = true; - u.is_unmessagable = true; - } LOG_INFO("Send owner %s/%s/%s", u.id, u.long_name, u.short_name); lastSentToMesh = millis(); diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp index e7e92c79a..fbe3a9cee 100644 --- a/src/modules/RoutingModule.cpp +++ b/src/modules/RoutingModule.cpp @@ -42,8 +42,6 @@ bool RoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mesh meshtastic_MeshPacket *RoutingModule::allocReply() { - if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) - return NULL; assert(currentRequest); return NULL; diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 98d5b19d0..ad148b759 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -26,7 +26,6 @@ int32_t DeviceTelemetryModule::runOnce() Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval, default_telemetry_broadcast_interval_secs, numOnlineNodes))) && airTime->isTxAllowedChannelUtil(!isImpoliteRole) && airTime->isTxAllowedAirUtil() && - config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) { sendTelemetry(); lastSentToMesh = uptimeLastMs; @@ -44,10 +43,6 @@ int32_t DeviceTelemetryModule::runOnce() bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t) { - // Don't worry about storing telemetry in NodeDB if we're a repeater - if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) - return false; - if (t->which_variant == meshtastic_Telemetry_device_metrics_tag) { #if defined(DEBUG_PORT) && !defined(DEBUG_MUTE) const char *sender = getSenderShortName(mp); diff --git a/src/modules/Telemetry/HostMetrics.cpp b/src/modules/Telemetry/HostMetrics.cpp index dcde495a2..577132006 100644 --- a/src/modules/Telemetry/HostMetrics.cpp +++ b/src/modules/Telemetry/HostMetrics.cpp @@ -22,10 +22,6 @@ int32_t HostMetricsModule::runOnce() bool HostMetricsModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t) { - // Don't worry about storing telemetry in NodeDB if we're a repeater - if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) - return false; - if (t->which_variant == meshtastic_Telemetry_host_metrics_tag) { #if defined(DEBUG_PORT) && !defined(DEBUG_MUTE) const char *sender = getSenderShortName(mp); diff --git a/src/sleep.cpp b/src/sleep.cpp index 0f8931292..ec560cb90 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -532,8 +532,7 @@ void enableModemSleep() bool shouldLoraWake(uint32_t msecToWake) { - return msecToWake < portMAX_DELAY && (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || - config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER); + return msecToWake < portMAX_DELAY && (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER); } void enableLoraInterrupt() diff --git a/userPrefs.jsonc b/userPrefs.jsonc index f6f3ef995..464eb968c 100644 --- a/userPrefs.jsonc +++ b/userPrefs.jsonc @@ -21,7 +21,7 @@ // "USERPREFS_CONFIG_LORA_REGION": "meshtastic_Config_LoRaConfig_RegionCode_US", // "USERPREFS_CONFIG_OWNER_LONG_NAME": "My Long Name", // "USERPREFS_CONFIG_OWNER_SHORT_NAME": "MLN", - // "USERPREFS_CONFIG_DEVICE_ROLE": "meshtastic_Config_DeviceConfig_Role_CLIENT", // Defaults to CLIENT. ROUTER*, LOST AND FOUND, and REPEATER roles are restricted. + // "USERPREFS_CONFIG_DEVICE_ROLE": "meshtastic_Config_DeviceConfig_Role_CLIENT", // Defaults to CLIENT. ROUTER*, and LOST AND FOUND roles are restricted. // "USERPREFS_EVENT_MODE": "1", // "USERPREFS_FIRMWARE_EDITION": "meshtastic_FirmwareEdition_BURNING_MAN", // "USERPREFS_FIXED_BLUETOOTH": "121212", From a1c658a467ee802b1fb64f8d82c6d335a379d986 Mon Sep 17 00:00:00 2001 From: Clive Blackledge Date: Sun, 28 Sep 2025 14:42:51 -0700 Subject: [PATCH 046/166] Bug / Send upgraded (duplicate) packets to phone if the queue removal failed. (#8148) * Add seenRecently = true if wasUpgraded is true but unable to remove from queue (i.e. already sent/processed). * Consistent comment between FloodingRouter and HopRouter --- src/mesh/FloodingRouter.cpp | 4 ++++ src/mesh/NextHopRouter.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 5d2d7653a..1d8ac247f 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -54,6 +54,10 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) // We already enqueued the improved copy, so make sure the incoming packet stops here. return true; } + + // No queue entry was replaced by this upgraded copy, so treat it as a duplicate to avoid + // delivering the same packet to applications/phone twice with different hop limits. + seenRecently = true; } if (seenRecently) { diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index cb483bc97..0461d7eb6 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -64,6 +64,10 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) // We already enqueued the improved copy, so make sure the incoming packet stops here. return true; } + + // No queue entry was replaced by this upgraded copy, so treat it as a duplicate to avoid + // delivering the same packet to applications/phone twice with different hop limits. + seenRecently = true; } if (seenRecently) { From a3e6f16378bfd89bcae91191dfd734278dd9cc6b Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 30 Sep 2025 08:20:39 +1000 Subject: [PATCH 047/166] Introduce non-linear TX_GAIN_LORA (#8107) * Introduce non-linear TX_GAIN_LORA Previously, our TX_GAIN_LORA setting was a single number, intended to represent the signal gain going through a power amp (plus or minus antenna, attenuator, and other parts of the RF chain). It turns out the relationship between the input power (i.e. from an SX1262) and total output power is often non-linear. While we fudged a 1dBm difference here and there with existing chips, the Heltec v4 has a 5dBm difference in gain depending on which end of the input power (and frequency) you are at. To allow people to run their Heltec v4 at max power when legal, and future proof our code, this patch introduced an optional array-based TX_GAIN_LORA. Define NUM_PA_POINTS and set TX_GAIN_LORA to gain values for a given input power in 1dBm increments, and all will work. For linear systems, just continue to define TX_GAIN_LORA as a number. Fixes https://github.com/meshtastic/firmware/issues/8070 * Remove temporary power limit on heltec v4 * Add function RadioLibInterface::checkOutputPower * Ensure SX126x reaches minimum supported power. * Keep it simple, instead. --- src/configuration.h | 6 ++++++ src/mesh/RadioInterface.cpp | 14 ++++++++++++++ src/mesh/SX126xInterface.cpp | 7 +++++-- variants/esp32s3/heltec_v4/platformio.ini | 1 - 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index 1b386ec17..91181890b 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -117,6 +117,12 @@ along with this program. If not, see . #define SX126X_MAX_POWER 22 #endif +#ifdef HELTEC_V4 +// Power Amps are often non-linear, so we can use an array of values for the power curve +#define NUM_PA_POINTS 22 +#define TX_GAIN_LORA 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7 +#endif + // Default system gain to 0 if not defined #ifndef TX_GAIN_LORA #define TX_GAIN_LORA 0 diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 31c68c302..b891ec89c 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -674,11 +674,25 @@ void RadioInterface::limitPower(int8_t loraMaxPower) power = maxPower; } +#ifndef NUM_PA_POINTS if (TX_GAIN_LORA > 0) { LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, TX_GAIN_LORA); power -= TX_GAIN_LORA; } +#else + // we have an array of PA gain values. Find the highest power setting that works. + const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA}; + for (int radio_dbm = 0; radio_dbm < NUM_PA_POINTS; radio_dbm++) { + if (((radio_dbm + tx_gain[radio_dbm]) > power) || + ((radio_dbm == (NUM_PA_POINTS - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) { + // we've exceeded the power limit, or hit the max we can do + LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]); + power -= tx_gain[radio_dbm]; + break; + } + } +#endif if (power > loraMaxPower) // Clamp power to maximum defined level power = loraMaxPower; diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index 3fc2562b3..785338483 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -80,6 +80,9 @@ template bool SX126xInterface::init() RadioLibInterface::init(); limitPower(SX126X_MAX_POWER); + // Make sure we reach the minimum power supported to turn the chip on (-9dBm) + if (power < -9) + power = -9; int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO); // \todo Display actual typename of the adapter, not just `SX126x` @@ -118,8 +121,8 @@ template bool SX126xInterface::init() LOG_DEBUG("Set DIO2 as %sRF switch, result: %d", dio2AsRfSwitch ? "" : "not ", res); } - // If a pin isn't defined, we set it to RADIOLIB_NC, it is safe to always do external RF switching with RADIOLIB_NC as it has - // no effect +// If a pin isn't defined, we set it to RADIOLIB_NC, it is safe to always do external RF switching with RADIOLIB_NC as it has +// no effect #if ARCH_PORTDUINO if (res == RADIOLIB_ERR_NONE) { LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", portduino_config.lora_rxen_pin.pin, diff --git a/variants/esp32s3/heltec_v4/platformio.ini b/variants/esp32s3/heltec_v4/platformio.ini index 1a448bc99..d0a250ad3 100644 --- a/variants/esp32s3/heltec_v4/platformio.ini +++ b/variants/esp32s3/heltec_v4/platformio.ini @@ -8,4 +8,3 @@ build_flags = -D HELTEC_V4 -I variants/esp32s3/heltec_v4 -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. - -D SX126X_MAX_POWER=11 From 8d323a1cf1e0570a31f1cb9499b8bb552b8bb72e Mon Sep 17 00:00:00 2001 From: Quency-D Date: Mon, 29 Sep 2025 17:49:31 +0800 Subject: [PATCH 048/166] add heltec tracker v2 board. --- boards/heltec_wireless_tracker_v2.json | 37 +++++++++ src/graphics/Screen.cpp | 2 +- src/mesh/SX126xInterface.cpp | 6 +- src/platform/esp32/architecture.h | 2 + src/sleep.cpp | 2 +- .../heltec_wireless_tracker_v2/pins_arduino.h | 71 +++++++++++++++++ .../heltec_wireless_tracker_v2/platformio.ini | 15 ++++ .../heltec_wireless_tracker_v2/variant.h | 78 +++++++++++++++++++ 8 files changed, 208 insertions(+), 5 deletions(-) create mode 100644 boards/heltec_wireless_tracker_v2.json create mode 100644 variants/esp32s3/heltec_wireless_tracker_v2/pins_arduino.h create mode 100644 variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini create mode 100644 variants/esp32s3/heltec_wireless_tracker_v2/variant.h diff --git a/boards/heltec_wireless_tracker_v2.json b/boards/heltec_wireless_tracker_v2.json new file mode 100644 index 000000000..502954e69 --- /dev/null +++ b/boards/heltec_wireless_tracker_v2.json @@ -0,0 +1,37 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "partitions": "default_8MB.csv" + }, + "core": "esp32", + "extra_flags": [ + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_USB_MODE=0", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "hwids": [["0x303A", "0x1001"]], + "mcu": "esp32s3", + "variant": "heltec_wireless_tracker_v2" + }, + "connectivity": ["wifi", "bluetooth", "lora"], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": ["arduino", "espidf"], + "name": "Heltec Wireless Tracker V2", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608, + "wait_for_upload_port": true, + "require_upload_port": true, + "speed": 921600 + }, + "url": "https://heltec.org", + "vendor": "Heltec" +} diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 1a9cf484b..5b585e485 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -453,7 +453,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) #endif dispdev->displayOn(); -#ifdef HELTEC_TRACKER_V1_X +#if defined(HELTEC_TRACKER_V1_X) || defined(HELTEC_WIRELESS_TRACKER_V2) ui->init(); #endif #ifdef USE_ST7789 diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index 785338483..a858c5e3b 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -52,7 +52,7 @@ template bool SX126xInterface::init() pinMode(SX126X_POWER_EN, OUTPUT); #endif -#ifdef HELTEC_V4 +#if defined(HELTEC_V4)||defined(HELTEC_WIRELESS_TRACKER_V2) pinMode(LORA_PA_POWER, OUTPUT); digitalWrite(LORA_PA_POWER, HIGH); @@ -352,7 +352,7 @@ template bool SX126xInterface::sleep() digitalWrite(SX126X_POWER_EN, LOW); #endif -#ifdef HELTEC_V4 +#if defined(HELTEC_V4)||defined(HELTEC_WIRELESS_TRACKER_V2) /* * Do not switch the power on and off frequently. * After turning off LORA_PA_EN, the power consumption has dropped to the uA level. @@ -367,7 +367,7 @@ template bool SX126xInterface::sleep() /** Some boards require GPIO control of tx vs rx paths */ template void SX126xInterface::setTransmitEnable(bool txon) { -#ifdef HELTEC_V4 +#if defined(HELTEC_V4)||defined(HELTEC_WIRELESS_TRACKER_V2) digitalWrite(LORA_PA_POWER, HIGH); digitalWrite(LORA_PA_EN, HIGH); digitalWrite(LORA_PA_TX_EN, txon ? 1 : 0); diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 6b658c2a3..53b23124d 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -201,6 +201,8 @@ #define HW_VENDOR meshtastic_HardwareModel_HELTEC_V4 #elif defined(M5STACK_UNITC6L) #define HW_VENDOR meshtastic_HardwareModel_M5STACK_C6L +#elif defined(HELTEC_WIRELESS_TRACKER_V2) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER_V2 #endif // ----------------------------------------------------------------------------- diff --git a/src/sleep.cpp b/src/sleep.cpp index 0f8931292..cfc8fbcd6 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -554,7 +554,7 @@ void enableLoraInterrupt() gpio_pullup_en((gpio_num_t)LORA_CS); #endif -#ifdef HELTEC_V4 +#if defined(HELTEC_V4)||defined(HELTEC_WIRELESS_TRACKER_V2) gpio_pullup_en((gpio_num_t)LORA_PA_POWER); gpio_pullup_en((gpio_num_t)LORA_PA_EN); gpio_pulldown_en((gpio_num_t)LORA_PA_TX_EN); diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/pins_arduino.h b/variants/esp32s3/heltec_wireless_tracker_v2/pins_arduino.h new file mode 100644 index 000000000..61c319109 --- /dev/null +++ b/variants/esp32s3/heltec_wireless_tracker_v2/pins_arduino.h @@ -0,0 +1,71 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include "soc/soc_caps.h" +#include + +#define DISPLAY_HEIGHT 80 +#define DISPLAY_WIDTH 160 + +#define USB_VID 0x303a +#define USB_PID 0x1001 + +static const uint8_t LED_BUILTIN = 18; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 5; +static const uint8_t SCL = 6; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 10; +static const uint8_t MISO = 11; +static const uint8_t SCK = 9; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +static const uint8_t Vext = 3; +static const uint8_t LED = 18; + +static const uint8_t RST_LoRa = 12; +static const uint8_t BUSY_LoRa = 13; +static const uint8_t DIO0 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini b/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini new file mode 100644 index 000000000..41952bf78 --- /dev/null +++ b/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini @@ -0,0 +1,15 @@ +[env:heltec-wireless-tracker-v2] +extends = esp32s3_base +board = heltec_wireless_tracker_v2 +board_build.partitions = default_8MB.csv +upload_protocol = esptool + +build_flags = + ${esp32s3_base.build_flags} + -I variants/esp32s3/heltec_wireless_tracker_v2 + -D HELTEC_WIRELESS_TRACKER_V2 + -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + -D SX126X_MAX_POWER=11 ;The latter limit is the largest, and will be updated after the V4 update. +lib_deps = + ${esp32s3_base.lib_deps} + lovyan03/LovyanGFX@^1.2.0 diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h new file mode 100644 index 000000000..39769f1e0 --- /dev/null +++ b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h @@ -0,0 +1,78 @@ +#define LED_PIN 18 + +#define _VARIANT_HELTEC_WIRELESS_TRACKER + +// I2C +#define I2C_SDA SDA +#define I2C_SCL SCL + +// ST7735S TFT LCD +#define ST7735S 1 // there are different (sub-)versions of ST7735 +#define ST7735_CS 38 +#define ST7735_RS 40 // DC +#define ST7735_SDA 42 // MOSI +#define ST7735_SCK 41 +#define ST7735_RESET 39 +#define ST7735_MISO -1 +#define ST7735_BUSY -1 +#define TFT_BL 21 +#define ST7735_SPI_HOST SPI3_HOST +#define SPI_FREQUENCY 40000000 +#define SPI_READ_FREQUENCY 16000000 +#define SCREEN_ROTATE +#define TFT_HEIGHT DISPLAY_WIDTH +#define TFT_WIDTH DISPLAY_HEIGHT +#define TFT_OFFSET_X 24 +#define TFT_OFFSET_Y 0 +#define TFT_INVERT false +#define SCREEN_TRANSITION_FRAMERATE 3 // fps +#define DISPLAY_FORCE_SMALL_FONTS + + +#define VEXT_ENABLE 3 // active HIGH - powers the GPS, GPS LNA and OLED +#define VEXT_ON_VALUE HIGH +#define BUTTON_PIN 0 + +#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO1_CHANNEL +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider +#define ADC_MULTIPLIER 4.9 * 1.045 +#define ADC_CTRL 2 // active HIGH, powers the voltage divider. +#define ADC_USE_PULLUP // Use internal pullup/pulldown instead of actively driving the output + +#undef GPS_RX_PIN +#undef GPS_TX_PIN +#define GPS_RX_PIN 33 +#define GPS_TX_PIN 34 +#define PIN_GPS_RESET 35 +#define PIN_GPS_PPS 36 +// #define PIN_GPS_EN 3 // Uncomment to power off the GPS with triple-click on Tracker v2, though we'll also lose the +// display. + +#define GPS_RESET_MODE LOW +#define GPS_UC6580 +#define GPS_BAUDRATE 115200 + +#define USE_SX1262 +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +#define LORA_PA_POWER 7 // power en +#define LORA_PA_EN 4 +#define LORA_PA_TX_EN 46 // enable tx \ No newline at end of file From 0f6131d2c86beae9e2fe91884b6bcbcd86834938 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 30 Sep 2025 08:30:18 +1000 Subject: [PATCH 049/166] Use common power amp definition for Heltec v4 and Heltec Tracker v2 --- src/configuration.h | 2 +- src/mesh/SX126xInterface.cpp | 6 +++--- src/sleep.cpp | 2 +- variants/esp32s3/heltec_v4/variant.h | 1 + variants/esp32s3/heltec_wireless_tracker_v2/variant.h | 8 ++++---- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index 91181890b..e67f0b8e5 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -117,7 +117,7 @@ along with this program. If not, see . #define SX126X_MAX_POWER 22 #endif -#ifdef HELTEC_V4 +#ifdef USE_GC1109_PA // Power Amps are often non-linear, so we can use an array of values for the power curve #define NUM_PA_POINTS 22 #define TX_GAIN_LORA 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7 diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index a858c5e3b..c60ef3a80 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -52,7 +52,7 @@ template bool SX126xInterface::init() pinMode(SX126X_POWER_EN, OUTPUT); #endif -#if defined(HELTEC_V4)||defined(HELTEC_WIRELESS_TRACKER_V2) +#if defined(USE_GC1109_PA) pinMode(LORA_PA_POWER, OUTPUT); digitalWrite(LORA_PA_POWER, HIGH); @@ -352,7 +352,7 @@ template bool SX126xInterface::sleep() digitalWrite(SX126X_POWER_EN, LOW); #endif -#if defined(HELTEC_V4)||defined(HELTEC_WIRELESS_TRACKER_V2) +#if defined(USE_GC1109_PA) /* * Do not switch the power on and off frequently. * After turning off LORA_PA_EN, the power consumption has dropped to the uA level. @@ -367,7 +367,7 @@ template bool SX126xInterface::sleep() /** Some boards require GPIO control of tx vs rx paths */ template void SX126xInterface::setTransmitEnable(bool txon) { -#if defined(HELTEC_V4)||defined(HELTEC_WIRELESS_TRACKER_V2) +#if defined(USE_GC1109_PA) digitalWrite(LORA_PA_POWER, HIGH); digitalWrite(LORA_PA_EN, HIGH); digitalWrite(LORA_PA_TX_EN, txon ? 1 : 0); diff --git a/src/sleep.cpp b/src/sleep.cpp index cfc8fbcd6..68867e0d0 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -554,7 +554,7 @@ void enableLoraInterrupt() gpio_pullup_en((gpio_num_t)LORA_CS); #endif -#if defined(HELTEC_V4)||defined(HELTEC_WIRELESS_TRACKER_V2) +#if defined(USE_GC1109_PA) gpio_pullup_en((gpio_num_t)LORA_PA_POWER); gpio_pullup_en((gpio_num_t)LORA_PA_EN); gpio_pulldown_en((gpio_num_t)LORA_PA_TX_EN); diff --git a/variants/esp32s3/heltec_v4/variant.h b/variants/esp32s3/heltec_v4/variant.h index 2b6b7af3d..1c9516e39 100644 --- a/variants/esp32s3/heltec_v4/variant.h +++ b/variants/esp32s3/heltec_v4/variant.h @@ -37,6 +37,7 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator #define LORA_PA_POWER 7 // power en #define LORA_PA_EN 2 #define LORA_PA_TX_EN 46 // enable tx diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h index 39769f1e0..aec31bba2 100644 --- a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h +++ b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h @@ -15,7 +15,7 @@ #define ST7735_RESET 39 #define ST7735_MISO -1 #define ST7735_BUSY -1 -#define TFT_BL 21 +#define TFT_BL 21 #define ST7735_SPI_HOST SPI3_HOST #define SPI_FREQUENCY 40000000 #define SPI_READ_FREQUENCY 16000000 @@ -28,7 +28,6 @@ #define SCREEN_TRANSITION_FRAMERATE 3 // fps #define DISPLAY_FORCE_SMALL_FONTS - #define VEXT_ENABLE 3 // active HIGH - powers the GPS, GPS LNA and OLED #define VEXT_ON_VALUE HIGH #define BUTTON_PIN 0 @@ -37,7 +36,7 @@ #define ADC_CHANNEL ADC1_GPIO1_CHANNEL #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider #define ADC_MULTIPLIER 4.9 * 1.045 -#define ADC_CTRL 2 // active HIGH, powers the voltage divider. +#define ADC_CTRL 2 // active HIGH, powers the voltage divider. #define ADC_USE_PULLUP // Use internal pullup/pulldown instead of actively driving the output #undef GPS_RX_PIN @@ -73,6 +72,7 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator #define LORA_PA_POWER 7 // power en -#define LORA_PA_EN 4 +#define LORA_PA_EN 4 #define LORA_PA_TX_EN 46 // enable tx \ No newline at end of file From 02efef3aaf7895353172bc541cc044ebc01b4e14 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Tue, 30 Sep 2025 16:36:52 +1300 Subject: [PATCH 050/166] Set appropriate mqtt root upon lora region change --- src/modules/AdminModule.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 79ea7bc0c..1cea85d7a 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -770,6 +770,15 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG; } } + if (config.lora.region != myRegion->code) { + // Region has changed so check whether there is a regulatory one we should be using instead. + // Additionally as a side-effect, assume a new value under myRegion + initRegion(); + + // subscribe to appropriate MQTT root topic for this region + sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name); + changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG; + } break; case meshtastic_Config_bluetooth_tag: LOG_INFO("Set config: Bluetooth"); From ee8fa9f328665233827d2cd220cd29c6f91c8cfd Mon Sep 17 00:00:00 2001 From: ford-jones Date: Tue, 30 Sep 2025 18:04:42 +1300 Subject: [PATCH 051/166] Use user preferences root topic if present --- src/modules/AdminModule.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 1cea85d7a..8421e3bea 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -776,7 +776,11 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) initRegion(); // subscribe to appropriate MQTT root topic for this region +#ifdef USERPREFS_MQTT_ROOT_TOPIC + sprintf(moduleConfig.mqtt.root, "%s/%s", USERPREFS_MQTT_ROOT_TOPIC, myRegion->name); +#else sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name); +#endif changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG; } break; From 500e7920ae9c2ae47e4fe4b22be2e3440bdc7f85 Mon Sep 17 00:00:00 2001 From: Quency-D <55523105+Quency-D@users.noreply.github.com> Date: Tue, 30 Sep 2025 14:06:46 +0800 Subject: [PATCH 052/166] delete SX126X_MAX_POWER=11 --- variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini b/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini index 41952bf78..4872561db 100644 --- a/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini +++ b/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini @@ -9,7 +9,6 @@ build_flags = -I variants/esp32s3/heltec_wireless_tracker_v2 -D HELTEC_WIRELESS_TRACKER_V2 -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. - -D SX126X_MAX_POWER=11 ;The latter limit is the largest, and will be updated after the V4 update. lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX@^1.2.0 From ee6857511a159f1127e6344db17e35a7e7cfa7bf Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 30 Sep 2025 08:05:00 -0500 Subject: [PATCH 053/166] Fix Heltec V3 missed button presses (#8167) --- src/input/ButtonThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/ButtonThread.cpp b/src/input/ButtonThread.cpp index 1d26e0758..9f53b06f4 100644 --- a/src/input/ButtonThread.cpp +++ b/src/input/ButtonThread.cpp @@ -279,7 +279,7 @@ int32_t ButtonThread::runOnce() if (!userButton.isIdle() || waitingForLongPress) { return 50; } - return INT32_MAX; + return 100; // FIXME: Why can't we rely on interrupts and use INT32_MAX here? } /* From b08e4efb78b7fd98063101bd1931754788654cbb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:34:40 -0500 Subject: [PATCH 054/166] Update protobufs (#8172) Co-authored-by: jp-bennett <5630967+jp-bennett@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/protobufs b/protobufs index 082bb7cfe..5fa4c44d9 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 082bb7cfeb2cba9d41be139cd324c4b43a14b3f9 +Subproject commit 5fa4c44d914aba67971ba15ace22e4b21af64ae5 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 6292ce070..601d52007 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -253,8 +253,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1 = 99, /* Seeed Tracker L1 EINK driver */ meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK = 100, - /* Reserved ID for future and past use */ - meshtastic_HardwareModel_QWANTZ_TINY_ARMS = 101, + /* Muzi Works R1 Neo */ + meshtastic_HardwareModel_MUZI_R1_NEO = 101, /* Lilygo T-Deck Pro */ meshtastic_HardwareModel_T_DECK_PRO = 102, /* Lilygo TLora Pager */ From 69c61f82479eb35186ab77a567ccbe824cf1e52a Mon Sep 17 00:00:00 2001 From: ford-jones Date: Wed, 1 Oct 2025 11:14:27 +1300 Subject: [PATCH 055/166] Assume previous root on topic change --- src/modules/AdminModule.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 8421e3bea..db31ea852 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -775,12 +775,17 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) // Additionally as a side-effect, assume a new value under myRegion initRegion(); - // subscribe to appropriate MQTT root topic for this region -#ifdef USERPREFS_MQTT_ROOT_TOPIC - sprintf(moduleConfig.mqtt.root, "%s/%s", USERPREFS_MQTT_ROOT_TOPIC, myRegion->name); -#else - sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name); -#endif + std::string current = moduleConfig.mqtt.root; + size_t location = current.find_first_of('/'); + + char root[location + 1]; + memset(root, 0, location); + memcpy(root, moduleConfig.mqtt.root, location); + root[location] = '\0'; + + // subscribe to the appropriate MQTT root topic for this region + sprintf(moduleConfig.mqtt.root, "%s/%s", root, myRegion->name); + changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG; } break; From 34a595b88e7d8a1703d3de48b2adfc37c663ad1e Mon Sep 17 00:00:00 2001 From: ford-jones Date: Wed, 1 Oct 2025 16:14:21 +1300 Subject: [PATCH 056/166] update mqtt root when region is changed via OLED menu handler --- src/graphics/draw/MenuHandler.cpp | 12 +++++++++++- src/modules/AdminModule.cpp | 15 +++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index 43b3fb8ab..f131bc298 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -116,6 +116,8 @@ void menuHandler::LoraRegionPicker(uint32_t duration) bannerOptions.bannerCallback = [](int selected) -> void { if (selected != 0 && config.lora.region != _meshtastic_Config_LoRaConfig_RegionCode(selected)) { config.lora.region = _meshtastic_Config_LoRaConfig_RegionCode(selected); + auto changes = SEGMENT_CONFIG; + // This is needed as we wait til picking the LoRa region to generate keys for the first time. if (!owner.is_licensed) { bool keygenSuccess = false; @@ -124,6 +126,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration) if (crypto->regeneratePublicKey(config.security.public_key.bytes, config.security.private_key.bytes)) { keygenSuccess = true; } + } else { LOG_INFO("Generate new PKI keys"); crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes); @@ -141,7 +144,14 @@ void menuHandler::LoraRegionPicker(uint32_t duration) if (myRegion->dutyCycle < 100) { config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit } - service->reloadConfig(SEGMENT_CONFIG); + + if (strncmp(moduleConfig.mqtt.root, default_mqtt_root, 3) == 0) { + // Default broker is in use, so subscribe to the appropriate MQTT root topic for this region + sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name); + changes |= SEGMENT_MODULECONFIG; + }; + + service->reloadConfig(changes); rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); } }; diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index db31ea852..367a0f617 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -765,6 +765,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) if (myRegion->dutyCycle < 100) { config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit } + // Compare the entire string, we are sure of the length as a topic has never been set if (strcmp(moduleConfig.mqtt.root, default_mqtt_root) == 0) { sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name); changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG; @@ -775,16 +776,10 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) // Additionally as a side-effect, assume a new value under myRegion initRegion(); - std::string current = moduleConfig.mqtt.root; - size_t location = current.find_first_of('/'); - - char root[location + 1]; - memset(root, 0, location); - memcpy(root, moduleConfig.mqtt.root, location); - root[location] = '\0'; - - // subscribe to the appropriate MQTT root topic for this region - sprintf(moduleConfig.mqtt.root, "%s/%s", root, myRegion->name); + if (strncmp(moduleConfig.mqtt.root, default_mqtt_root, 3) == 0) { + // Default broker is in use, so subscribe to the appropriate MQTT root topic for this region + sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name); + } changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG; } From dae9b1c024bcdd205cc154b644f09cf05bae7c5d Mon Sep 17 00:00:00 2001 From: ford-jones Date: Wed, 1 Oct 2025 17:58:14 +1300 Subject: [PATCH 057/166] Regen protos --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/protobufs b/protobufs index 082bb7cfe..394268b02 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 082bb7cfeb2cba9d41be139cd324c4b43a14b3f9 +Subproject commit 394268b02ebbc7797de31b09fe72fe2a7bdbbcab diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 6292ce070..d8d2f2e8a 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -253,8 +253,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1 = 99, /* Seeed Tracker L1 EINK driver */ meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK = 100, - /* Reserved ID for future and past use */ - meshtastic_HardwareModel_QWANTZ_TINY_ARMS = 101, + /* Muzi Works R1 Neo */ + meshtastic_HardwareModel_MUZI_R1_NEO = 101, /* Lilygo T-Deck Pro */ meshtastic_HardwareModel_T_DECK_PRO = 102, /* Lilygo TLora Pager */ @@ -278,6 +278,10 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_M5STACK_C6L = 111, /* M5Stack Cardputer Adv */ meshtastic_HardwareModel_M5STACK_CARDPUTER_ADV = 112, + /* ESP32S3 main controller with GPS and TFT screen. */ + meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER_V2 = 113, + /* LilyGo T-Watch Ultra */ + meshtastic_HardwareModel_T_WATCH_ULTRA = 114, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ From 4fd568f38429fae506a52daab9009bf6438ab254 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 30 Sep 2025 13:00:01 -0500 Subject: [PATCH 058/166] Initial support for T-Rex --- boards/t-rex.json | 52 +++++++++ src/detect/ScanI2C.cpp | 4 +- src/detect/ScanI2C.h | 1 + src/detect/ScanI2CTwoWire.cpp | 3 + src/gps/RTC.cpp | 30 ++++++ src/gps/RTC.h | 4 + src/main.cpp | 6 ++ src/platform/nrf52/NRF52Bluetooth.cpp | 3 +- src/power.h | 2 + variants/t-rex/platformio.ini | 17 +++ variants/t-rex/variant.cpp | 45 ++++++++ variants/t-rex/variant.h | 148 ++++++++++++++++++++++++++ 12 files changed, 312 insertions(+), 3 deletions(-) create mode 100644 boards/t-rex.json create mode 100644 variants/t-rex/platformio.ini create mode 100644 variants/t-rex/variant.cpp create mode 100644 variants/t-rex/variant.h diff --git a/boards/t-rex.json b/boards/t-rex.json new file mode 100644 index 000000000..d827c55dd --- /dev/null +++ b/boards/t-rex.json @@ -0,0 +1,52 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x8029"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"], + ["0x239A", "0x802A"] + ], + "usb_product": "Muzi T-REX", + "mcu": "nrf52840", + "variant": "t-rex", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "6.1.1", + "sd_fwid": "0x00B6" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "svd_path": "nrf52840.svd", + "openocd_target": "nrf52840-mdk-rs" + }, + "frameworks": ["arduino", "freertos"], + "name": "WisCore RAK4631 Board", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://muzi.works/", + "vendor": "Muzi Works" +} diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 170bef3a6..8ac503b83 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -25,8 +25,8 @@ ScanI2C::FoundDevice ScanI2C::firstScreen() const ScanI2C::FoundDevice ScanI2C::firstRTC() const { - ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; - return firstOfOrNONE(2, types); + ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563, RTC_RX8130CE}; + return firstOfOrNONE(3, types); } ScanI2C::FoundDevice ScanI2C::firstKeyboard() const diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 470a416c0..2e602338c 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -14,6 +14,7 @@ class ScanI2C SCREEN_ST7567, RTC_RV3028, RTC_PCF8563, + RTC_RX8130CE, CARDKB, TDECKKB, BBQ10KB, diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 01a630b52..6df3f8be1 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -197,6 +197,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) #ifdef PCF8563_RTC SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563", (uint8_t)addr.address) #endif +#ifdef RX8130CE_RTC + SCAN_SIMPLE_CASE(RX8130CE_RTC, RTC_RX8130CE, "RX8130CE", (uint8_t)addr.address) +#endif case CARDKB_ADDR: // Do we have the RAK14006 instead? diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index da20e28eb..97590c6a8 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -109,6 +109,25 @@ RTCSetResult readFromRTC() } return RTCSetResultSuccess; } +#elif defined(RX8130CE_RTC) + if (rtc_found.address == RX8130CE_RTC) { + uint32_t now = millis(); + ArtronShop_RX8130CE rtc(&Wire); + tm t; + if (rtc.getTime(&t)) { + tv.tv_sec = gm_mktime(&t); + tv.tv_usec = 0; + + uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms + LOG_DEBUG("Read RTC time from RX8130CE getDateTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900, + t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch); + timeStartMsec = now; + zeroOffsetSecs = tv.tv_sec; + if (currentQuality == RTCQualityNone) { + currentQuality = RTCQualityDevice; + } + } + } #else if (!gettimeofday(&tv, NULL)) { uint32_t now = millis(); @@ -214,6 +233,17 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, printableEpoch); } +#elif defined(RX8130CE_RTC) + if (rtc_found.address == RX8130CE_RTC) { + ArtronShop_RX8130CE rtc(&Wire); + tm *t = gmtime(&tv->tv_sec); + if (rtc.setTime(*t)) { + LOG_DEBUG("RX8130CE setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1, + t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, printableEpoch); + } else { + LOG_WARN("Failed to set time for RX8130CE"); + } + } #elif defined(ARCH_ESP32) settimeofday(tv, NULL); #endif diff --git a/src/gps/RTC.h b/src/gps/RTC.h index eca17bf35..06dd34c16 100644 --- a/src/gps/RTC.h +++ b/src/gps/RTC.h @@ -4,6 +4,10 @@ #include "sys/time.h" #include +#ifdef RX8130CE_RTC +#include +#endif + enum RTCQuality { /// We haven't had our RTC set yet diff --git a/src/main.cpp b/src/main.cpp index 29a608dfe..1df4ebe3b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -297,6 +297,12 @@ void printInfo() #ifndef PIO_UNIT_TESTING void setup() { +#if defined(T_REX) // XXX + pinMode(DCDC_EN_HOLD, OUTPUT); + digitalWrite(DCDC_EN_HOLD, HIGH); + pinMode(NRF_ON, OUTPUT); + digitalWrite(NRF_ON, HIGH); +#endif #if defined(PIN_POWER_EN) pinMode(PIN_POWER_EN, OUTPUT); diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index b457c35b7..79eef8f76 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -335,7 +335,8 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke meshtastic::BluetoothStatus newStatus(textkey); bluetoothStatus->updateStatus(&newStatus); -#if !defined(MESHTASTIC_EXCLUDE_SCREEN) // Todo: migrate this display code back into Screen class, and observe bluetoothStatus +#if HAS_SCREEN && \ + !defined(MESHTASTIC_EXCLUDE_SCREEN) // Todo: migrate this display code back into Screen class, and observe bluetoothStatus if (screen) { screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { char btPIN[16] = "888888"; diff --git a/src/power.h b/src/power.h index e96f5b022..10ec07a30 100644 --- a/src/power.h +++ b/src/power.h @@ -34,6 +34,8 @@ #define OCV_ARRAY 4200, 3876, 3826, 3763, 3713, 3660, 3573, 3485, 3422, 3359, 3300 #elif defined(SEEED_SOLAR_NODE) #define OCV_ARRAY 4200, 3986, 3922, 3812, 3734, 3645, 3527, 3420, 3281, 3087, 2786 +#elif defined(T_REX) +#define OCV_ARRAY 4330, 4292, 4254, 4216, 4178, 4140, 4102, 4064, 4026, 3988, 3950 #else // LiIon #define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100 #endif diff --git a/variants/t-rex/platformio.ini b/variants/t-rex/platformio.ini new file mode 100644 index 000000000..c2b72e7d3 --- /dev/null +++ b/variants/t-rex/platformio.ini @@ -0,0 +1,17 @@ +; The t-rex Muzi board +[env:t-rex] +extends = nrf52840_base +board = t-rex +board_check = true +build_flags = ${nrf52840_base.build_flags} -Ivariants/t-rex -D T_REX + -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + -DRADIOLIB_EXCLUDE_SX128X=1 + -DRADIOLIB_EXCLUDE_SX127X=1 + -DRADIOLIB_EXCLUDE_LR11X0=1 +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-rex> + + +lib_deps = + ${nrf52840_base.lib_deps} + ${networking_base.lib_deps} + https://github.com/RAKWireless/RAK13800-W5100S/archive/1.0.2.zip + rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 + artronshop/ArtronShop_RX8130CE@1.0.0 diff --git a/variants/t-rex/variant.cpp b/variants/t-rex/variant.cpp new file mode 100644 index 000000000..f87c041aa --- /dev/null +++ b/variants/t-rex/variant.cpp @@ -0,0 +1,45 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); + + // 3V3 Power Rail + // pinMode(PIN_3V3_EN, OUTPUT); + // digitalWrite(PIN_3V3_EN, HIGH); +} diff --git a/variants/t-rex/variant.h b/variants/t-rex/variant.h new file mode 100644 index 000000000..33bf7093a --- /dev/null +++ b/variants/t-rex/variant.h @@ -0,0 +1,148 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_TREX_ +#define _VARIANT_TREX_ + +#define RAK4630 + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) // ??? +#define NUM_DIGITAL_PINS (48) // ??? +#define NUM_ANALOG_INPUTS (1) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (32 + 4) // P1.04 Controls Green LED +#define PIN_LED2 (28) // P0.28 Controls Blue LED + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_GREEN PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 1 // State when LED is litted + +// Button +#define PIN_BUTTON1 (26) +#define BUTTON_ACTIVE_LOW 0 +#define BUTTON_ACTIVE_PULLUP 0 + +#define ADC_RESOLUTION 14 // ??? + +// Serial for GPS +#define PIN_SERIAL1_RX (25) +#define PIN_SERIAL1_TX (24) + +// Connected to Jlink CDC +#define PIN_SERIAL2_RX (8) // ??? +#define PIN_SERIAL2_TX (6) // ??? + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (45) +#define PIN_SPI_MOSI (44) +#define PIN_SPI_SCK (43) + +static const uint8_t SS = 42; +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +// T-Rex Extras +#define DCDC_EN_HOLD (13) // P0.13 Keeps DCDC alive after user button is pressed +#define NRF_ON (29) // P0.29 Tells IO controller device is on + +// RAKRGB +#define HAS_NCP5623 // ??? + +#define HAS_SCREEN 0 + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (19) // P0.19 RTC_SDA +#define PIN_WIRE_SCL (20) // P0.20 RTC_SDA + +#define PIN_BUZZER (0 + 3) // P0.03 + +#define USE_SX1262 +#define SX126X_CS (42) +#define SX126X_DIO1 (47) +#define SX126X_BUSY (46) +#define SX126X_RESET (38) +#define SX126X_POWER_EN (37) + +// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3 +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +// Testing USB detection +#define NRF_APM + +#define PIN_GPS_EN (32 + 1) // P1.01 +#define PIN_GPS_PPS (2) // P0.02 Pulse per second input from the GPS + +#define GPS_RX_PIN PIN_SERIAL1_RX +#define GPS_TX_PIN PIN_SERIAL1_TX + +// Battery +#define BATTERY_PIN (0 + 31) // P0.31 ADC_VBAT +// and has 12 bit resolution +#define BATTERY_SENSE_RESOLUTION_BITS 12 // ??? +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER 1.73 // ??? + +#define HAS_RTC 1 + +#define RX8130CE_RTC 0x32 + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif From f9937967fa9b21eb85f6fdfb2e79bcada012db46 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 30 Sep 2025 15:56:01 -0500 Subject: [PATCH 059/166] Add HardwareModel and correct directories --- src/platform/nrf52/architecture.h | 2 ++ variants/{ => nrf52840}/t-rex/platformio.ini | 6 ++++-- variants/{ => nrf52840}/t-rex/variant.cpp | 0 variants/{ => nrf52840}/t-rex/variant.h | 0 4 files changed, 6 insertions(+), 2 deletions(-) rename variants/{ => nrf52840}/t-rex/platformio.ini (83%) rename variants/{ => nrf52840}/t-rex/variant.cpp (100%) rename variants/{ => nrf52840}/t-rex/variant.h (100%) diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index c9938062e..9d0447067 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -98,6 +98,8 @@ #define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK #elif defined(SEEED_WIO_TRACKER_L1) #define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1 +#elif defined(T_REX) +#define HW_VENDOR meshtastic_HardwareModel_MUZI_R1_NEO #elif defined(HELTEC_MESH_SOLAR) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_SOLAR #else diff --git a/variants/t-rex/platformio.ini b/variants/nrf52840/t-rex/platformio.ini similarity index 83% rename from variants/t-rex/platformio.ini rename to variants/nrf52840/t-rex/platformio.ini index c2b72e7d3..33b8f96f5 100644 --- a/variants/t-rex/platformio.ini +++ b/variants/nrf52840/t-rex/platformio.ini @@ -3,12 +3,14 @@ extends = nrf52840_base board = t-rex board_check = true -build_flags = ${nrf52840_base.build_flags} -Ivariants/t-rex -D T_REX +build_flags = ${nrf52840_base.build_flags} + -Ivariants/nrf52840/t-rex + -D T_REX -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-rex> + + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/t-rex> + + lib_deps = ${nrf52840_base.lib_deps} ${networking_base.lib_deps} diff --git a/variants/t-rex/variant.cpp b/variants/nrf52840/t-rex/variant.cpp similarity index 100% rename from variants/t-rex/variant.cpp rename to variants/nrf52840/t-rex/variant.cpp diff --git a/variants/t-rex/variant.h b/variants/nrf52840/t-rex/variant.h similarity index 100% rename from variants/t-rex/variant.h rename to variants/nrf52840/t-rex/variant.h From 8b466b1db3cd9941a328f956308476adc688bb9f Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 30 Sep 2025 18:00:29 -0500 Subject: [PATCH 060/166] T-rex comment cleanup --- src/main.cpp | 2 +- variants/nrf52840/t-rex/variant.h | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1df4ebe3b..382f35065 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -297,7 +297,7 @@ void printInfo() #ifndef PIO_UNIT_TESTING void setup() { -#if defined(T_REX) // XXX +#if defined(T_REX) pinMode(DCDC_EN_HOLD, OUTPUT); digitalWrite(DCDC_EN_HOLD, HIGH); pinMode(NRF_ON, OUTPUT); diff --git a/variants/nrf52840/t-rex/variant.h b/variants/nrf52840/t-rex/variant.h index 33bf7093a..9ab0cadf8 100644 --- a/variants/nrf52840/t-rex/variant.h +++ b/variants/nrf52840/t-rex/variant.h @@ -38,8 +38,8 @@ extern "C" { #endif // __cplusplus // Number of pins defined in PinDescription array -#define PINS_COUNT (48) // ??? -#define NUM_DIGITAL_PINS (48) // ??? +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) #define NUM_ANALOG_INPUTS (1) #define NUM_ANALOG_OUTPUTS (0) @@ -60,15 +60,15 @@ extern "C" { #define BUTTON_ACTIVE_LOW 0 #define BUTTON_ACTIVE_PULLUP 0 -#define ADC_RESOLUTION 14 // ??? +#define ADC_RESOLUTION 14 // Serial for GPS #define PIN_SERIAL1_RX (25) #define PIN_SERIAL1_TX (24) // Connected to Jlink CDC -#define PIN_SERIAL2_RX (8) // ??? -#define PIN_SERIAL2_TX (6) // ??? +#define PIN_SERIAL2_RX (8) +#define PIN_SERIAL2_TX (6) /* * SPI Interfaces @@ -89,7 +89,7 @@ static const uint8_t SCK = PIN_SPI_SCK; #define NRF_ON (29) // P0.29 Tells IO controller device is on // RAKRGB -#define HAS_NCP5623 // ??? +#define HAS_NCP5623 #define HAS_SCREEN 0 @@ -99,7 +99,7 @@ static const uint8_t SCK = PIN_SPI_SCK; #define WIRE_INTERFACES_COUNT 1 #define PIN_WIRE_SDA (19) // P0.19 RTC_SDA -#define PIN_WIRE_SCL (20) // P0.20 RTC_SDA +#define PIN_WIRE_SCL (20) // P0.20 RTC_SCL #define PIN_BUZZER (0 + 3) // P0.03 @@ -126,12 +126,12 @@ static const uint8_t SCK = PIN_SPI_SCK; // Battery #define BATTERY_PIN (0 + 31) // P0.31 ADC_VBAT // and has 12 bit resolution -#define BATTERY_SENSE_RESOLUTION_BITS 12 // ??? +#define BATTERY_SENSE_RESOLUTION_BITS 12 #define BATTERY_SENSE_RESOLUTION 4096.0 #undef AREF_VOLTAGE #define AREF_VOLTAGE 3.0 #define VBAT_AR_INTERNAL AR_INTERNAL_3_0 -#define ADC_MULTIPLIER 1.73 // ??? +#define ADC_MULTIPLIER 1.73 #define HAS_RTC 1 From ad44940732b4f7bb1f664e399cf53f405fba4b0a Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 30 Sep 2025 20:46:38 -0500 Subject: [PATCH 061/166] Put the GPIO in the right state for wake from sleep --- variants/nrf52840/t-rex/variant.h | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/nrf52840/t-rex/variant.h b/variants/nrf52840/t-rex/variant.h index 9ab0cadf8..4735e340d 100644 --- a/variants/nrf52840/t-rex/variant.h +++ b/variants/nrf52840/t-rex/variant.h @@ -59,6 +59,7 @@ extern "C" { #define PIN_BUTTON1 (26) #define BUTTON_ACTIVE_LOW 0 #define BUTTON_ACTIVE_PULLUP 0 +#define BUTTON_SENSE_TYPE INPUT_SENSE_HIGH #define ADC_RESOLUTION 14 From d5164b4fbfe6b75328e90497e73d785faadcf85d Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 30 Sep 2025 21:38:32 -0500 Subject: [PATCH 062/166] Check the BUILD_EPOCH if defined --- src/gps/RTC.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index 97590c6a8..665a9aaa3 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -121,11 +121,21 @@ RTCSetResult readFromRTC() uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms LOG_DEBUG("Read RTC time from RX8130CE getDateTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch); - timeStartMsec = now; - zeroOffsetSecs = tv.tv_sec; +#ifdef BUILD_EPOCH + if (tv.tv_sec < BUILD_EPOCH) { + if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) { + LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH); + lastTimeValidationWarning = millis(); + } + return RTCSetResultInvalidTime; + } +#endif if (currentQuality == RTCQualityNone) { + timeStartMsec = now; + zeroOffsetSecs = tv.tv_sec; currentQuality = RTCQualityDevice; } + return RTCSetResultSuccess; } } #else From 17afdb9ccf9f89334b5087c99b47c7a469ef53f3 Mon Sep 17 00:00:00 2001 From: rcarteraz Date: Wed, 1 Oct 2025 08:21:20 -0700 Subject: [PATCH 063/166] no more t-rex --- variants/nrf52840/{t-rex => r1-neo}/platformio.ini | 12 ++++++------ variants/nrf52840/{t-rex => r1-neo}/variant.cpp | 0 variants/nrf52840/{t-rex => r1-neo}/variant.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) rename variants/nrf52840/{t-rex => r1-neo}/platformio.ini (82%) rename variants/nrf52840/{t-rex => r1-neo}/variant.cpp (100%) rename variants/nrf52840/{t-rex => r1-neo}/variant.h (98%) diff --git a/variants/nrf52840/t-rex/platformio.ini b/variants/nrf52840/r1-neo/platformio.ini similarity index 82% rename from variants/nrf52840/t-rex/platformio.ini rename to variants/nrf52840/r1-neo/platformio.ini index 33b8f96f5..6feb55dc9 100644 --- a/variants/nrf52840/t-rex/platformio.ini +++ b/variants/nrf52840/r1-neo/platformio.ini @@ -1,16 +1,16 @@ -; The t-rex Muzi board -[env:t-rex] +; The R1 Neo board +[env:r1-neo] extends = nrf52840_base -board = t-rex +board = r1-neo board_check = true build_flags = ${nrf52840_base.build_flags} - -Ivariants/nrf52840/t-rex - -D T_REX + -Ivariants/nrf52840/r1-neo + -D R1_NEO -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/t-rex> + + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/r1-neo> + + lib_deps = ${nrf52840_base.lib_deps} ${networking_base.lib_deps} diff --git a/variants/nrf52840/t-rex/variant.cpp b/variants/nrf52840/r1-neo/variant.cpp similarity index 100% rename from variants/nrf52840/t-rex/variant.cpp rename to variants/nrf52840/r1-neo/variant.cpp diff --git a/variants/nrf52840/t-rex/variant.h b/variants/nrf52840/r1-neo/variant.h similarity index 98% rename from variants/nrf52840/t-rex/variant.h rename to variants/nrf52840/r1-neo/variant.h index 4735e340d..901e993e3 100644 --- a/variants/nrf52840/t-rex/variant.h +++ b/variants/nrf52840/r1-neo/variant.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _VARIANT_TREX_ -#define _VARIANT_TREX_ +#ifndef _VARIANT_R1NEO_ +#define _VARIANT_R1NEO_ #define RAK4630 @@ -85,7 +85,7 @@ static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; -// T-Rex Extras +// R1 Neo Extras #define DCDC_EN_HOLD (13) // P0.13 Keeps DCDC alive after user button is pressed #define NRF_ON (29) // P0.29 Tells IO controller device is on From b28d09509676c8edd66fae0051562354655119dd Mon Sep 17 00:00:00 2001 From: rcarteraz Date: Wed, 1 Oct 2025 09:30:46 -0700 Subject: [PATCH 064/166] missed t-rexes --- boards/{t-rex.json => r1-neo.json} | 4 ++-- src/main.cpp | 2 +- src/platform/nrf52/architecture.h | 2 +- src/power.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename boards/{t-rex.json => r1-neo.json} (95%) diff --git a/boards/t-rex.json b/boards/r1-neo.json similarity index 95% rename from boards/t-rex.json rename to boards/r1-neo.json index d827c55dd..0383a2f48 100644 --- a/boards/t-rex.json +++ b/boards/r1-neo.json @@ -13,9 +13,9 @@ ["0x239A", "0x002A"], ["0x239A", "0x802A"] ], - "usb_product": "Muzi T-REX", + "usb_product": "Muzi R1 Neo", "mcu": "nrf52840", - "variant": "t-rex", + "variant": "r1-neo", "bsp": { "name": "adafruit" }, diff --git a/src/main.cpp b/src/main.cpp index 382f35065..d49111414 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -297,7 +297,7 @@ void printInfo() #ifndef PIO_UNIT_TESTING void setup() { -#if defined(T_REX) +#if defined(R1_NEO) pinMode(DCDC_EN_HOLD, OUTPUT); digitalWrite(DCDC_EN_HOLD, HIGH); pinMode(NRF_ON, OUTPUT); diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index 9d0447067..8212bcbc3 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -98,7 +98,7 @@ #define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK #elif defined(SEEED_WIO_TRACKER_L1) #define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1 -#elif defined(T_REX) +#elif defined(R1_NEO) #define HW_VENDOR meshtastic_HardwareModel_MUZI_R1_NEO #elif defined(HELTEC_MESH_SOLAR) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_SOLAR diff --git a/src/power.h b/src/power.h index 10ec07a30..23eb95064 100644 --- a/src/power.h +++ b/src/power.h @@ -34,7 +34,7 @@ #define OCV_ARRAY 4200, 3876, 3826, 3763, 3713, 3660, 3573, 3485, 3422, 3359, 3300 #elif defined(SEEED_SOLAR_NODE) #define OCV_ARRAY 4200, 3986, 3922, 3812, 3734, 3645, 3527, 3420, 3281, 3087, 2786 -#elif defined(T_REX) +#elif defined(R1_NEO) #define OCV_ARRAY 4330, 4292, 4254, 4216, 4178, 4140, 4102, 4064, 4026, 3988, 3950 #else // LiIon #define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100 From 849bbad2798900ab1b1a5f153de8fca1122c7369 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:13:28 -0500 Subject: [PATCH 065/166] Automated version bumps (#8177) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- bin/org.meshtastic.meshtasticd.metainfo.xml | 3 +++ debian/changelog | 7 +++++-- version.properties | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/org.meshtastic.meshtasticd.metainfo.xml b/bin/org.meshtastic.meshtasticd.metainfo.xml index 0d03dd349..3505f1940 100644 --- a/bin/org.meshtastic.meshtasticd.metainfo.xml +++ b/bin/org.meshtastic.meshtasticd.metainfo.xml @@ -87,6 +87,9 @@ + + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.12 + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.11 diff --git a/debian/changelog b/debian/changelog index 15c8604f6..8bd053b25 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -meshtasticd (2.7.11.0) UNRELEASED; urgency=medium +meshtasticd (2.7.12.0) unstable; urgency=medium [ Austin Lane ] * Initial packaging @@ -7,4 +7,7 @@ meshtasticd (2.7.11.0) UNRELEASED; urgency=medium [ ] * GitHub Actions Automatic version bump - -- Wed, 24 Sep 2025 11:01:13 +0000 + [ GitHub Actions ] + * Version 2.7.12 + + -- GitHub Actions Wed, 01 Oct 2025 19:51:41 +0000 diff --git a/version.properties b/version.properties index ce1205f2b..5c84a8e65 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 7 -build = 11 +build = 12 From f7469159cf8c992f9869fc67ca04531edab4479a Mon Sep 17 00:00:00 2001 From: Mike Robbins Date: Wed, 1 Oct 2025 16:31:53 -0400 Subject: [PATCH 066/166] Reliable ACKs for DMs (#8165) * RoutingModule::sendAckNak takes ackWantsAck arg to set want_ack on the ACK itself * Use reliable delivery for traceroute requests (which will be copied to traceroute responses by setReplyTo) * Update ReliableRouter::sniffReceived to use ReliableRouter::shouldSuccessAckWithWantAck * Use isFromUs * Update MockRoutingModule::sendAckNak to include ackWantsAck argument (currently ignored) --------- Co-authored-by: Ben Meadors --- src/mesh/PhoneAPI.cpp | 7 +++++ src/mesh/ReliableRouter.cpp | 44 +++++++++++++++++++++++++++++++- src/mesh/ReliableRouter.h | 6 +++++ src/mesh/Router.cpp | 5 ++-- src/mesh/Router.h | 3 ++- src/modules/RoutingModule.cpp | 6 ++++- src/modules/RoutingModule.h | 4 +-- src/modules/TraceRouteModule.cpp | 6 +++++ test/test_mqtt/MQTT.cpp | 4 +-- 9 files changed, 76 insertions(+), 9 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index f6f1bc027..07f314415 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -710,6 +710,13 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p) // sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Text messages can only be sent once every 2 seconds"); return false; } + + // Upgrade traceroute requests from phone to use reliable delivery, matching TraceRouteModule + if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && !isBroadcast(p.to)) { + // Use reliable delivery for traceroute requests (which will be copied to traceroute responses by setReplyTo) + p.want_ack = true; + } + lastPortNumToRadio[p.decoded.portnum] = millis(); service->handleToRadio(p); return true; diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index cca838ff0..b31c352fe 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -103,10 +103,20 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas /* A response may be set to want_ack for retransmissions, but we don't need to ACK a response if it received an implicit ACK already. If we received it directly or via NextHopRouter, only ACK with a hop limit of 0 to make sure the other side stops retransmitting. */ - if (!p->decoded.request_id && !p->decoded.reply_id) { + + if (shouldSuccessAckWithWantAck(p)) { + // If this packet should always be ACKed reliably with want_ack back to the original sender, make sure we + // do that unconditionally. + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, + routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit), true); + } else if (!p->decoded.request_id && !p->decoded.reply_id) { + // If it's not an ACK or a reply, send an ACK. sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit)); } else if ((p->hop_start > 0 && p->hop_start == p->hop_limit) || p->next_hop != NO_NEXT_HOP_PREFERENCE) { + // If we received the packet directly from the original sender, send a 0-hop ACK since the original sender + // won't overhear any implicit ACKs. If we received the packet via NextHopRouter, also send a 0-hop ACK to + // stop the immediate relayer's retransmissions. sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); } } else if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag && p->channel == 0 && @@ -152,4 +162,36 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas // handle the packet as normal isBroadcast(p->to) ? FloodingRouter::sniffReceived(p, c) : NextHopRouter::sniffReceived(p, c); +} + +/** + * If we ACK this packet, should we set want_ack=true on the ACK for reliable delivery of the ACK packet? + */ +bool ReliableRouter::shouldSuccessAckWithWantAck(const meshtastic_MeshPacket *p) +{ + // Don't ACK-with-want-ACK outgoing packets + if (isFromUs(p)) + return false; + + // Only ACK-with-want-ACK if the original packet asked for want_ack + if (!p->want_ack) + return false; + + // Only ACK-with-want-ACK packets to us (not broadcast) + if (!isToUs(p)) + return false; + + // Special case for text message DMs: + bool isTextMessage = + (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && + IS_ONE_OF(p->decoded.portnum, meshtastic_PortNum_TEXT_MESSAGE_APP, meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP); + + if (isTextMessage) { + // If it's a non-broadcast text message, and the original asked for want_ack, + // let's send an ACK that is itself want_ack to improve reliability of confirming delivery back to the sender. + // This should include all DMs regardless of whether or not reply_id is set. + return true; + } + + return false; } \ No newline at end of file diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index 2cf10fb99..33121de6b 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -31,4 +31,10 @@ class ReliableRouter : public NextHopRouter * We hook this method so we can see packets before FloodingRouter says they should be discarded */ virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override; + + private: + /** + * Should this packet be ACKed with a want_ack for reliable delivery? + */ + bool shouldSuccessAckWithWantAck(const meshtastic_MeshPacket *p); }; \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 8f9fb28f9..60637cbd1 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -198,9 +198,10 @@ meshtastic_MeshPacket *Router::allocForSending() /** * Send an ack or a nak packet back towards whoever sent idFrom */ -void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit) +void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit, + bool ackWantsAck) { - routingModule->sendAckNak(err, to, idFrom, chIndex, hopLimit); + routingModule->sendAckNak(err, to, idFrom, chIndex, hopLimit, ackWantsAck); } void Router::abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p) diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 92a5a06e5..10a3771a7 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -125,7 +125,8 @@ class Router : protected concurrency::OSThread, protected PacketHistory /** * Send an ack or a nak packet back towards whoever sent idFrom */ - void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0); + void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0, + bool ackWantsAck = false); private: /** diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp index fbe3a9cee..05173983c 100644 --- a/src/modules/RoutingModule.cpp +++ b/src/modules/RoutingModule.cpp @@ -47,10 +47,14 @@ meshtastic_MeshPacket *RoutingModule::allocReply() return NULL; } -void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit) +void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit, + bool ackWantsAck) { auto p = allocAckNak(err, to, idFrom, chIndex, hopLimit); + // Allow the caller to set want_ack on this ACK packet if it's important that the ACK be delivered reliably + p->want_ack = ackWantsAck; + router->sendLocal(p); // we sometimes send directly to the local node } diff --git a/src/modules/RoutingModule.h b/src/modules/RoutingModule.h index c047f6e29..a4e0679d0 100644 --- a/src/modules/RoutingModule.h +++ b/src/modules/RoutingModule.h @@ -13,8 +13,8 @@ class RoutingModule : public ProtobufModule */ RoutingModule(); - virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, - uint8_t hopLimit = 0); + virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0, + bool ackWantsAck = false); // Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit); diff --git a/src/modules/TraceRouteModule.cpp b/src/modules/TraceRouteModule.cpp index 8f69c504a..fc2cc232b 100644 --- a/src/modules/TraceRouteModule.cpp +++ b/src/modules/TraceRouteModule.cpp @@ -419,6 +419,9 @@ bool TraceRouteModule::startTraceRoute(NodeNum node) p->decoded.portnum = meshtastic_PortNum_TRACEROUTE_APP; p->decoded.want_response = true; + // Use reliable delivery for traceroute requests (which will be copied to traceroute responses by setReplyTo) + p->want_ack = true; + // Manually encode the RouteDiscovery payload p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_RouteDiscovery_msg, &req); @@ -532,6 +535,9 @@ void TraceRouteModule::launch(NodeNum node) p->decoded.portnum = meshtastic_PortNum_TRACEROUTE_APP; p->decoded.want_response = true; + // Use reliable delivery for traceroute requests (which will be copied to traceroute responses by setReplyTo) + p->want_ack = true; + p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_RouteDiscovery_msg, &req); diff --git a/test/test_mqtt/MQTT.cpp b/test/test_mqtt/MQTT.cpp index 32d81f6b4..ede3d22b7 100644 --- a/test/test_mqtt/MQTT.cpp +++ b/test/test_mqtt/MQTT.cpp @@ -83,8 +83,8 @@ class MockNodeDB : public NodeDB class MockRoutingModule : public RoutingModule { public: - void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, - uint8_t hopLimit = 0) override + void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0, + bool ackWantsAck = false) override { ackNacks_.emplace_back(err, to, idFrom, chIndex, hopLimit); } From 641a2fc63d1e412ff1326f00e63e7fa5964d17d0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:32:06 -0500 Subject: [PATCH 067/166] Update protobufs (#8178) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 12 ++++++++---- src/mesh/generated/meshtastic/mesh.pb.h | 4 ++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/protobufs b/protobufs index 5fa4c44d9..60c3e6600 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 5fa4c44d914aba67971ba15ace22e4b21af64ae5 +Subproject commit 60c3e6600a2f4e6f49e45aeb47aafd8291a0015c diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index bc0b780b9..7cc896292 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -132,6 +132,8 @@ typedef struct _meshtastic_SharedContact { meshtastic_User user; /* Add this contact to the blocked / ignored list */ bool should_ignore; + /* Set the IS_KEY_MANUALLY_VERIFIED bit */ + bool manually_verified; } meshtastic_SharedContact; /* This message is used by a client to initiate or complete a key verification */ @@ -319,13 +321,13 @@ extern "C" { #define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0} #define meshtastic_HamParameters_init_default {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} -#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0} +#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0} #define meshtastic_KeyVerificationAdmin_init_default {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0} #define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}} #define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0} #define meshtastic_HamParameters_init_zero {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} -#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0} +#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0} #define meshtastic_KeyVerificationAdmin_init_zero {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0} /* Field tags (for use in manual encoding/decoding) */ @@ -341,6 +343,7 @@ extern "C" { #define meshtastic_SharedContact_node_num_tag 1 #define meshtastic_SharedContact_user_tag 2 #define meshtastic_SharedContact_should_ignore_tag 3 +#define meshtastic_SharedContact_manually_verified_tag 4 #define meshtastic_KeyVerificationAdmin_message_type_tag 1 #define meshtastic_KeyVerificationAdmin_remote_nodenum_tag 2 #define meshtastic_KeyVerificationAdmin_nonce_tag 3 @@ -504,7 +507,8 @@ X(a, STATIC, REPEATED, MESSAGE, node_remote_hardware_pins, 1) #define meshtastic_SharedContact_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, node_num, 1) \ X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \ -X(a, STATIC, SINGULAR, BOOL, should_ignore, 3) +X(a, STATIC, SINGULAR, BOOL, should_ignore, 3) \ +X(a, STATIC, SINGULAR, BOOL, manually_verified, 4) #define meshtastic_SharedContact_CALLBACK NULL #define meshtastic_SharedContact_DEFAULT NULL #define meshtastic_SharedContact_user_MSGTYPE meshtastic_User @@ -539,7 +543,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg; #define meshtastic_HamParameters_size 31 #define meshtastic_KeyVerificationAdmin_size 25 #define meshtastic_NodeRemoteHardwarePinsResponse_size 496 -#define meshtastic_SharedContact_size 125 +#define meshtastic_SharedContact_size 127 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 601d52007..d8d2f2e8a 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -278,6 +278,10 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_M5STACK_C6L = 111, /* M5Stack Cardputer Adv */ meshtastic_HardwareModel_M5STACK_CARDPUTER_ADV = 112, + /* ESP32S3 main controller with GPS and TFT screen. */ + meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER_V2 = 113, + /* LilyGo T-Watch Ultra */ + meshtastic_HardwareModel_T_WATCH_ULTRA = 114, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ From ec28c383af11cd24afd6b9fd72235789c38c43ad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:32:25 -0500 Subject: [PATCH 068/166] Upgrade trunk (#8159) Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com> --- .trunk/trunk.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 4e9de6a02..fa6fa6d7d 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -8,15 +8,15 @@ plugins: uri: https://github.com/trunk-io/plugins lint: enabled: - - checkov@3.2.471 - - renovate@41.130.1 + - checkov@3.2.473 + - renovate@41.132.2 - prettier@3.6.2 - trufflehog@3.90.8 - yamllint@1.37.1 - bandit@1.8.6 - - trivy@0.66.0 + - trivy@0.67.0 - taplo@0.10.0 - - ruff@0.13.1 + - ruff@0.13.2 - isort@6.0.1 - markdownlint@0.45.0 - oxipng@9.1.5 From f82667d71e151398327c678af5bc2326b94ee17f Mon Sep 17 00:00:00 2001 From: ford-jones Date: Thu, 2 Oct 2025 10:24:32 +1300 Subject: [PATCH 069/166] Removed magic numbers --- src/graphics/draw/MenuHandler.cpp | 4 ++-- src/modules/AdminModule.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index f131bc298..c064866ca 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -145,11 +145,11 @@ void menuHandler::LoraRegionPicker(uint32_t duration) config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit } - if (strncmp(moduleConfig.mqtt.root, default_mqtt_root, 3) == 0) { + if (strncmp(moduleConfig.mqtt.root, default_mqtt_root, strlen(default_mqtt_root)) == 0) { // Default broker is in use, so subscribe to the appropriate MQTT root topic for this region sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name); changes |= SEGMENT_MODULECONFIG; - }; + } service->reloadConfig(changes); rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 367a0f617..d1e4ed081 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -776,8 +776,8 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) // Additionally as a side-effect, assume a new value under myRegion initRegion(); - if (strncmp(moduleConfig.mqtt.root, default_mqtt_root, 3) == 0) { - // Default broker is in use, so subscribe to the appropriate MQTT root topic for this region + if (strncmp(moduleConfig.mqtt.root, default_mqtt_root, strlen(default_mqtt_root)) == 0) { + // Default root is in use, so subscribe to the appropriate MQTT topic for this region sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name); } From 9bb7bb467bf56eba2911906116490288d49c747c Mon Sep 17 00:00:00 2001 From: nexpspace <380097+nexpspace@users.noreply.github.com> Date: Thu, 2 Oct 2025 02:36:17 +0200 Subject: [PATCH 070/166] Add DIRECT_MSG_ONLY buzzer mode (#8158) * Handle existing special case for M5STACK_UNITC6L for DIRECT_MSG_ONLY buzz mode There already exists a special case for M5STACK_UNITC6L. Modified it to adhere to new DIRECT_MSG_ONLY buzzer mode * Add new buzzer mode DIRECT_MSG_ONLY to BuzzerModeMenu * Disable notifications when buzzer mode is DIRECT_MSG_ONLY * Change alert_message_buzzer in notification module in DIRECT_MSG_ONLY buzz mode Better comments * Fixed spelling in debug log Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: nexpspace <4kosjdicx@mozmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ben Meadors --- src/buzz/BuzzerFeedbackThread.cpp | 3 +- src/graphics/Screen.cpp | 8 +++++- src/graphics/draw/MenuHandler.cpp | 4 +-- src/modules/ExternalNotificationModule.cpp | 33 +++++++++++++--------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/buzz/BuzzerFeedbackThread.cpp b/src/buzz/BuzzerFeedbackThread.cpp index afa8c96e2..7de6c0740 100644 --- a/src/buzz/BuzzerFeedbackThread.cpp +++ b/src/buzz/BuzzerFeedbackThread.cpp @@ -15,7 +15,8 @@ int BuzzerFeedbackThread::handleInputEvent(const InputEvent *event) { // Only provide feedback if buzzer is enabled for notifications if (config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_DISABLED || - config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_NOTIFICATIONS_ONLY) { + config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_NOTIFICATIONS_ONLY || + config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY) { return 0; // Let other handlers process the event } diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 1a9cf484b..a3dbbc853 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1494,7 +1494,13 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) #if defined(M5STACK_UNITC6L) screen->setOn(true); screen->showSimpleBanner(banner, 1500); - playLongBeep(); + if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY || + (isAlert && moduleConfig.external_notification.alert_bell_buzzer) || (!isBroadcast(packet->to) && isToUs(p))) { + // Beep if not in DIRECT_MSG_ONLY mode or if in DIRECT_MSG_ONLY mode and either + // - packet contains an alert and alert bell buzzer is enabled + // - packet is a non-broadcast that is addressed to this node + playLongBeep(); + } #else screen->showSimpleBanner(banner, 3000); #endif diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index 43b3fb8ab..6c781e94f 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -911,11 +911,11 @@ void menuHandler::BluetoothToggleMenu() void menuHandler::BuzzerModeMenu() { - static const char *optionsArray[] = {"All Enabled", "Disabled", "Notifications", "System Only"}; + static const char *optionsArray[] = {"All Enabled", "Disabled", "Notifications", "System Only", "DMs Only"}; BannerOverlayOptions bannerOptions; bannerOptions.message = "Buzzer Mode"; bannerOptions.optionsArrayPtr = optionsArray; - bannerOptions.optionsCount = 4; + bannerOptions.optionsCount = 5; bannerOptions.bannerCallback = [](int selected) -> void { config.device.buzzer_mode = (meshtastic_Config_DeviceConfig_BuzzerMode)selected; service->reloadConfig(SEGMENT_CONFIG); diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 1279078b1..3eddcf789 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -533,23 +533,30 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP if (moduleConfig.external_notification.alert_message_buzzer) { LOG_INFO("externalNotificationModule - Notification Module (Buzzer)"); - isNagging = true; - if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) { - setExternalState(2, true); - } else { + if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY || + (!isBroadcast(mp.to) && isToUs(&mp))) { + // Buzz if buzzer mode is not in DIRECT_MSG_ONLY or is DM to us + isNagging = true; + if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) { + setExternalState(2, true); + } else { #ifdef HAS_I2S - if (moduleConfig.external_notification.use_i2s_as_buzzer) { - audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone)); - } else + if (moduleConfig.external_notification.use_i2s_as_buzzer) { + audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone)); + } else #endif - if (moduleConfig.external_notification.use_pwm) { - rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); + if (moduleConfig.external_notification.use_pwm) { + rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); + } + } + if (moduleConfig.external_notification.nag_timeout) { + nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; + } else { + nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms; } - } - if (moduleConfig.external_notification.nag_timeout) { - nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; } else { - nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms; + // Don't beep if buzzer mode is "direct messages only" and it is no direct message + LOG_INFO("Message buzzer was suppressed because buzzer mode DIRECT_MSG_ONLY"); } } setIntervalFromNow(0); // run once so we know if we should do something From 76d480713022f7be1314b8902157fbcad94d601f Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 1 Oct 2025 21:07:30 -0500 Subject: [PATCH 071/166] Add support for the manually_verified bool in SharedContact (#8180) --- src/mesh/NodeDB.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index a32ee37f9..5b235485d 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1597,9 +1597,18 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS void NodeDB::addFromContact(meshtastic_SharedContact contact) { meshtastic_NodeInfoLite *info = getOrCreateMeshNode(contact.node_num); - if (!info) { + if (!info || !contact.has_user) { return; } + // If the local node has this node marked as manually verified + // and the client does not, do not allow the client to update the + // saved public key. + if ((info->bitfield & NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK) && !contact.manually_verified) { + if (contact.user.public_key.size != info->user.public_key.size || + memcmp(contact.user.public_key.bytes, info->user.public_key.bytes, info->user.public_key.size) != 0) { + return; + } + } info->num = contact.node_num; info->has_user = true; info->user = TypeConversions::ConvertToUserLite(contact.user); @@ -1614,10 +1623,12 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact) } else { info->last_heard = getValidTime(RTCQualityNTP); info->is_favorite = true; - info->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK; + // As the clients will begin sending the contact with DMs, we want to strictly check if the node is manually verified + if (contact.manually_verified) { + info->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK; + } // Mark the node's key as manually verified to indicate trustworthiness. updateGUIforNode = info; - // powerFSM.trigger(EVENT_NODEDB_UPDATED); This event has been retired sortMeshDB(); notifyObservers(true); // Force an update whether or not our node counts have changed } From 51ad9d02442f8cae661d3f06a31eb407ee563ba5 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Thu, 2 Oct 2025 17:02:47 +1300 Subject: [PATCH 072/166] run trunk fmt --- src/graphics/Screen.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 2aef9d6f9..4a9e98446 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1499,15 +1499,16 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) strcpy(banner, "New Message"); } #if defined(M5STACK_UNITC6L) - screen->setOn(true); - screen->showSimpleBanner(banner, 1500); - if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY || - (isAlert && moduleConfig.external_notification.alert_bell_buzzer) || (!isBroadcast(packet->to) && isToUs(p))) { - // Beep if not in DIRECT_MSG_ONLY mode or if in DIRECT_MSG_ONLY mode and either - // - packet contains an alert and alert bell buzzer is enabled - // - packet is a non-broadcast that is addressed to this node - playLongBeep(); - } + screen->setOn(true); + screen->showSimpleBanner(banner, 1500); + if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY || + (isAlert && moduleConfig.external_notification.alert_bell_buzzer) || + (!isBroadcast(packet->to) && isToUs(p))) { + // Beep if not in DIRECT_MSG_ONLY mode or if in DIRECT_MSG_ONLY mode and either + // - packet contains an alert and alert bell buzzer is enabled + // - packet is a non-broadcast that is addressed to this node + playLongBeep(); + } #else screen->showSimpleBanner(banner, 3000); #endif From b978c6c86c7d7303de921c01b9d948d067ba6c07 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 05:15:36 -0500 Subject: [PATCH 073/166] Upgrade trunk (#8183) Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com> --- .trunk/trunk.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index fa6fa6d7d..ec1563931 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -9,7 +9,7 @@ plugins: lint: enabled: - checkov@3.2.473 - - renovate@41.132.2 + - renovate@41.132.5 - prettier@3.6.2 - trufflehog@3.90.8 - yamllint@1.37.1 From 878ac3ec84f4779004e285c60fdbc597fdcbc207 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 2 Oct 2025 06:09:52 -0500 Subject: [PATCH 074/166] Update variants/esp32s3/heltec_wireless_tracker_v2/variant.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- variants/esp32s3/heltec_wireless_tracker_v2/variant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h index aec31bba2..9ac064ea2 100644 --- a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h +++ b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h @@ -57,7 +57,7 @@ #define LORA_RESET 12 #define LORA_DIO1 14 // SX1262 IRQ #define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TCXO is enabled #define LORA_SCK 9 #define LORA_MISO 11 From 305f5138348e774606e0274bc85cca7d581ea8b1 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 2 Oct 2025 10:40:32 -0500 Subject: [PATCH 075/166] Properly set Muzi Works R1 Neo HardwareModel --- src/platform/nrf52/architecture.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index 8212bcbc3..47ec4e500 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -55,6 +55,8 @@ #define HW_VENDOR meshtastic_HardwareModel_GAT562_MESH_TRIAL_TRACKER #elif defined(NOMADSTAR_METEOR_PRO) #define HW_VENDOR meshtastic_HardwareModel_NOMADSTAR_METEOR_PRO +#elif defined(R1_NEO) +#define HW_VENDOR meshtastic_HardwareModel_MUZI_R1_NEO // MAke sure all custom RAK4630 boards are defined before the generic RAK4630 #elif defined(RAK4630) #define HW_VENDOR meshtastic_HardwareModel_RAK4631 @@ -98,8 +100,6 @@ #define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK #elif defined(SEEED_WIO_TRACKER_L1) #define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1 -#elif defined(R1_NEO) -#define HW_VENDOR meshtastic_HardwareModel_MUZI_R1_NEO #elif defined(HELTEC_MESH_SOLAR) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_SOLAR #else From 76c1d69560bb4c59bf865ec3aa752f6f1f07f55a Mon Sep 17 00:00:00 2001 From: ford-jones Date: Fri, 3 Oct 2025 15:28:08 +1300 Subject: [PATCH 076/166] Regen protos --- protobufs | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/protobufs b/protobufs index 60c3e6600..394268b02 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 60c3e6600a2f4e6f49e45aeb47aafd8291a0015c +Subproject commit 394268b02ebbc7797de31b09fe72fe2a7bdbbcab diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index 7cc896292..bc0b780b9 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -132,8 +132,6 @@ typedef struct _meshtastic_SharedContact { meshtastic_User user; /* Add this contact to the blocked / ignored list */ bool should_ignore; - /* Set the IS_KEY_MANUALLY_VERIFIED bit */ - bool manually_verified; } meshtastic_SharedContact; /* This message is used by a client to initiate or complete a key verification */ @@ -321,13 +319,13 @@ extern "C" { #define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0} #define meshtastic_HamParameters_init_default {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} -#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0} +#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0} #define meshtastic_KeyVerificationAdmin_init_default {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0} #define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}} #define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0} #define meshtastic_HamParameters_init_zero {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} -#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0} +#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0} #define meshtastic_KeyVerificationAdmin_init_zero {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0} /* Field tags (for use in manual encoding/decoding) */ @@ -343,7 +341,6 @@ extern "C" { #define meshtastic_SharedContact_node_num_tag 1 #define meshtastic_SharedContact_user_tag 2 #define meshtastic_SharedContact_should_ignore_tag 3 -#define meshtastic_SharedContact_manually_verified_tag 4 #define meshtastic_KeyVerificationAdmin_message_type_tag 1 #define meshtastic_KeyVerificationAdmin_remote_nodenum_tag 2 #define meshtastic_KeyVerificationAdmin_nonce_tag 3 @@ -507,8 +504,7 @@ X(a, STATIC, REPEATED, MESSAGE, node_remote_hardware_pins, 1) #define meshtastic_SharedContact_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, node_num, 1) \ X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \ -X(a, STATIC, SINGULAR, BOOL, should_ignore, 3) \ -X(a, STATIC, SINGULAR, BOOL, manually_verified, 4) +X(a, STATIC, SINGULAR, BOOL, should_ignore, 3) #define meshtastic_SharedContact_CALLBACK NULL #define meshtastic_SharedContact_DEFAULT NULL #define meshtastic_SharedContact_user_MSGTYPE meshtastic_User @@ -543,7 +539,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg; #define meshtastic_HamParameters_size 31 #define meshtastic_KeyVerificationAdmin_size 25 #define meshtastic_NodeRemoteHardwarePinsResponse_size 496 -#define meshtastic_SharedContact_size 127 +#define meshtastic_SharedContact_size 125 #ifdef __cplusplus } /* extern "C" */ From 50cfe7c70504ca5423f38c48add1f65d324c6481 Mon Sep 17 00:00:00 2001 From: ford-jones Date: Fri, 3 Oct 2025 15:49:50 +1300 Subject: [PATCH 077/166] Pull latest protobufs --- protobufs | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/protobufs b/protobufs index 394268b02..60c3e6600 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 394268b02ebbc7797de31b09fe72fe2a7bdbbcab +Subproject commit 60c3e6600a2f4e6f49e45aeb47aafd8291a0015c diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index bc0b780b9..7cc896292 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -132,6 +132,8 @@ typedef struct _meshtastic_SharedContact { meshtastic_User user; /* Add this contact to the blocked / ignored list */ bool should_ignore; + /* Set the IS_KEY_MANUALLY_VERIFIED bit */ + bool manually_verified; } meshtastic_SharedContact; /* This message is used by a client to initiate or complete a key verification */ @@ -319,13 +321,13 @@ extern "C" { #define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0} #define meshtastic_HamParameters_init_default {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} -#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0} +#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0} #define meshtastic_KeyVerificationAdmin_init_default {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0} #define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}} #define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0} #define meshtastic_HamParameters_init_zero {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} -#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0} +#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0} #define meshtastic_KeyVerificationAdmin_init_zero {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0} /* Field tags (for use in manual encoding/decoding) */ @@ -341,6 +343,7 @@ extern "C" { #define meshtastic_SharedContact_node_num_tag 1 #define meshtastic_SharedContact_user_tag 2 #define meshtastic_SharedContact_should_ignore_tag 3 +#define meshtastic_SharedContact_manually_verified_tag 4 #define meshtastic_KeyVerificationAdmin_message_type_tag 1 #define meshtastic_KeyVerificationAdmin_remote_nodenum_tag 2 #define meshtastic_KeyVerificationAdmin_nonce_tag 3 @@ -504,7 +507,8 @@ X(a, STATIC, REPEATED, MESSAGE, node_remote_hardware_pins, 1) #define meshtastic_SharedContact_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, node_num, 1) \ X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \ -X(a, STATIC, SINGULAR, BOOL, should_ignore, 3) +X(a, STATIC, SINGULAR, BOOL, should_ignore, 3) \ +X(a, STATIC, SINGULAR, BOOL, manually_verified, 4) #define meshtastic_SharedContact_CALLBACK NULL #define meshtastic_SharedContact_DEFAULT NULL #define meshtastic_SharedContact_user_MSGTYPE meshtastic_User @@ -539,7 +543,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg; #define meshtastic_HamParameters_size 31 #define meshtastic_KeyVerificationAdmin_size 25 #define meshtastic_NodeRemoteHardwarePinsResponse_size 496 -#define meshtastic_SharedContact_size 125 +#define meshtastic_SharedContact_size 127 #ifdef __cplusplus } /* extern "C" */ From 0ddaf710e4f39a60aa679001aa5c2cfa592ffb8d Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 3 Oct 2025 06:33:37 -0500 Subject: [PATCH 078/166] Add FACTORY_INSTALL option to do a filesystem reset on first boot (#8185) * Add FACTORY_INSTALL option to do a filesystem reset on first boot * Check for valid file handle before using Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/mesh/NodeDB.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 5b235485d..a43ef17bc 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -56,6 +56,10 @@ #include #endif +// stringify +#define xstr(s) str(s) +#define str(s) #s + NodeDB *nodeDB = nullptr; // we have plenty of ram so statically alloc this tempbuf (for now) @@ -1152,6 +1156,20 @@ void NodeDB::loadFromDisk() spiLock->unlock(); #endif #ifdef FSCom +#ifdef FACTORY_INSTALL + spiLock->lock(); + if (!FSCom.exists("/prefs/" xstr(BUILD_EPOCH))) { + LOG_WARN("Factory Install Reset!"); + FSCom.format(); + FSCom.mkdir("/prefs"); + File f2 = FSCom.open("/prefs/" xstr(BUILD_EPOCH), FILE_O_WRITE); + if (f2) { + f2.flush(); + f2.close(); + } + } + spiLock->unlock(); +#endif spiLock->lock(); if (FSCom.exists(legacyPrefFileName)) { spiLock->unlock(); From 03baad2c11865d662c2ea7e48218a8dc2ecd8824 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 06:33:53 -0500 Subject: [PATCH 079/166] Update protobufs (#8191) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/device_ui.pb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 60c3e6600..c1e31a965 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 60c3e6600a2f4e6f49e45aeb47aafd8291a0015c +Subproject commit c1e31a9655e9920a8b5b8eccdf7c69ef1ae42a49 diff --git a/src/mesh/generated/meshtastic/device_ui.pb.h b/src/mesh/generated/meshtastic/device_ui.pb.h index d9eb90773..b99fb10b9 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.h +++ b/src/mesh/generated/meshtastic/device_ui.pb.h @@ -68,6 +68,8 @@ typedef enum _meshtastic_Language { meshtastic_Language_BULGARIAN = 17, /* Czech */ meshtastic_Language_CZECH = 18, + /* Danish */ + meshtastic_Language_DANISH = 19, /* Simplified Chinese (experimental) */ meshtastic_Language_SIMPLIFIED_CHINESE = 30, /* Traditional Chinese (experimental) */ From da98622f593260fa6b08775793b511c149705f33 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 06:34:11 -0500 Subject: [PATCH 080/166] Upgrade trunk (#8190) Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com> --- .trunk/trunk.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index ec1563931..74b850b64 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -17,7 +17,7 @@ lint: - trivy@0.67.0 - taplo@0.10.0 - ruff@0.13.2 - - isort@6.0.1 + - isort@6.1.0 - markdownlint@0.45.0 - oxipng@9.1.5 - svgo@4.0.0 From f72a4c50bdc5952182cdd763c9c7e8eee3329dc9 Mon Sep 17 00:00:00 2001 From: Austin Lane Date: Fri, 3 Oct 2025 17:14:00 -0400 Subject: [PATCH 081/166] Don't use IS_ONE_OF when loading Modules --- src/modules/Modules.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 02962dd59..e477574dd 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -148,7 +148,8 @@ void setupModules() } #endif #if !MESHTASTIC_EXCLUDE_ATAK - if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TAK, meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)) { + if (config.device.role == meshtastic_Config_DeviceConfig_Role_TAK || + config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) { atakPluginModule = new AtakPluginModule(); } #endif From 037e56b1fdf6a384d713b4b301cced43f5eed1cd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:34:19 -0500 Subject: [PATCH 082/166] Update meshtastic/device-ui digest to 505ffad (#8195) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index f6c0f3867..b6d6733e3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -120,7 +120,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/9ed5355a24059750e9b2eb5d669574d9ea42a37b.zip + https://github.com/meshtastic/device-ui/archive/505ffadaa7a931df5dc8153229b719a07bbb028c.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From 78d010fd29401938824f0eaf5a203e24156a98e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:35:23 -0500 Subject: [PATCH 083/166] Update actions/stale action to v10.1.0 (#8196) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/stale_bot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale_bot.yml b/.github/workflows/stale_bot.yml index 32e2c2c8b..a80619e90 100644 --- a/.github/workflows/stale_bot.yml +++ b/.github/workflows/stale_bot.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Stale PR+Issues - uses: actions/stale@v10.0.0 + uses: actions/stale@v10.1.0 with: days-before-stale: 45 exempt-issue-labels: pinned,3.0 From 0c2283e19eeec8a2a6c078caab3f2a6daa5cf2fc Mon Sep 17 00:00:00 2001 From: Austin Date: Fri, 3 Oct 2025 17:48:21 -0400 Subject: [PATCH 084/166] GAT562: Use PRIVATE_HW (fix build) (#8198) --- variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini b/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini index 5c1047aae..c6a5a7399 100644 --- a/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini +++ b/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini @@ -6,7 +6,8 @@ board = gat562_mesh_trial_tracker board_check = true build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/gat562_mesh_trial_tracker - -D GAT562_MESH_TRIAL_TRACKER + ;-D GAT562_MESH_TRIAL_TRACKER + -D PRIVATE_HW -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 From b7f6a2acb6402ef8d2a9469e508ff1865eb04cf8 Mon Sep 17 00:00:00 2001 From: Austin Date: Fri, 3 Oct 2025 19:52:51 -0400 Subject: [PATCH 085/166] ESP32s2 doesn't implement HWCDC (#8199) --- src/SerialConsole.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 51dbcb7be..fad0fb92f 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -86,7 +86,7 @@ int32_t SerialConsole::runOnce() #endif int32_t delay = runOncePart(); -#if defined(SERIAL_HAS_ON_RECEIVE) +#if defined(SERIAL_HAS_ON_RECEIVE) || defined(CONFIG_IDF_TARGET_ESP32S2) return Port.available() ? delay : INT32_MAX; #elif defined(IS_USB_SERIAL) return HWCDC::isPlugged() ? delay : (1000 * 20); From 0e38fef5bfc1ad7dadec19b5b51963b7c8475061 Mon Sep 17 00:00:00 2001 From: Ken Piper Date: Fri, 3 Oct 2025 18:53:18 -0500 Subject: [PATCH 086/166] Fix build script failure under certain conditions for devices that use UF2 binaries (#8150) * Validate CR and SF lora config (#8146) * Validate CR and SF lora config * No zero-bw * Update src/modules/AdminModule.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix braces --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Quote firmware paths given to uf2conv --------- Co-authored-by: Ben Meadors Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- bin/platformio-custom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/platformio-custom.py b/bin/platformio-custom.py index e54d1586f..4a1887d9d 100644 --- a/bin/platformio-custom.py +++ b/bin/platformio-custom.py @@ -86,7 +86,7 @@ if platform.name == "espressif32": if platform.name == "nordicnrf52": env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", - env.VerboseAction(f"\"{sys.executable}\" ./bin/uf2conv.py $BUILD_DIR/firmware.hex -c -f 0xADA52840 -o $BUILD_DIR/firmware.uf2", + env.VerboseAction(f"\"{sys.executable}\" ./bin/uf2conv.py \"$BUILD_DIR/firmware.hex\" -c -f 0xADA52840 -o \"$BUILD_DIR/firmware.uf2\"", "Generating UF2 file")) Import("projenv") From e8296914a5167b3636c43d01391f19fcc654c7c1 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sat, 4 Oct 2025 12:29:25 +0200 Subject: [PATCH 087/166] Calculate airtime of transmitted and received packets separately (#8205) --- src/mesh/LR11x0Interface.h | 2 ++ src/mesh/RF95Interface.h | 4 ++- src/mesh/RadioInterface.cpp | 35 +++--------------------- src/mesh/RadioInterface.h | 9 +++---- src/mesh/RadioLibInterface.cpp | 37 ++++++++++++++------------ src/mesh/RadioLibInterface.h | 41 +++++++++++++++++++++++++++++ src/mesh/ReliableRouter.cpp | 2 +- src/mesh/SX126xInterface.h | 2 ++ src/mesh/SX128xInterface.h | 2 ++ src/platform/portduino/SimRadio.cpp | 33 ++++++++++++++++++++--- src/platform/portduino/SimRadio.h | 2 ++ 11 files changed, 110 insertions(+), 59 deletions(-) diff --git a/src/mesh/LR11x0Interface.h b/src/mesh/LR11x0Interface.h index 4829ddc1d..840184bbf 100644 --- a/src/mesh/LR11x0Interface.h +++ b/src/mesh/LR11x0Interface.h @@ -65,5 +65,7 @@ template class LR11x0Interface : public RadioLibInterface virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override; virtual void setStandby() override; + + uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(lora, pl, received); } }; #endif \ No newline at end of file diff --git a/src/mesh/RF95Interface.h b/src/mesh/RF95Interface.h index 327e57900..ffd8ae008 100644 --- a/src/mesh/RF95Interface.h +++ b/src/mesh/RF95Interface.h @@ -65,8 +65,10 @@ class RF95Interface : public RadioLibInterface */ virtual void configHardwareForSend() override; + uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(*lora, pl, received); } + private: /** Some boards require GPIO control of tx vs rx paths */ void setTransmitEnable(bool txon); }; -#endif \ No newline at end of file +#endif diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 29f91060c..88218e406 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -230,33 +230,7 @@ The band is from 902 to 928 MHz. It mentions channel number and its respective c separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts at 903.08 MHz center frequency. */ -/** - * Calculate airtime per - * https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf - * section 4 - * - * @return num msecs for the packet - */ -uint32_t RadioInterface::getPacketTime(uint32_t pl) -{ - float bandwidthHz = bw * 1000.0f; - bool headDisable = false; // we currently always use the header - float tSym = (1 << sf) / bandwidthHz; - - bool lowDataOptEn = tSym > 16e-3 ? true : false; // Needed if symbol time is >16ms - - float tPreamble = (preambleLength + 4.25f) * tSym; - float numPayloadSym = - 8 + max(ceilf(((8.0f * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * cr), 0.0f); - float tPayload = numPayloadSym * tSym; - float tPacket = tPreamble + tPayload; - - uint32_t msecs = tPacket * 1000; - - return msecs; -} - -uint32_t RadioInterface::getPacketTime(const meshtastic_MeshPacket *p) +uint32_t RadioInterface::getPacketTime(const meshtastic_MeshPacket *p, bool received) { uint32_t pl = 0; if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag) { @@ -265,7 +239,7 @@ uint32_t RadioInterface::getPacketTime(const meshtastic_MeshPacket *p) size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded); pl = numbytes + sizeof(PacketHeader); } - return getPacketTime(pl); + return getPacketTime(pl, received); } /** The delay to use for retransmitting dropped packets */ @@ -624,8 +598,7 @@ void RadioInterface::applyModemConfig() saveFreq(freq + loraConfig.frequency_offset); slotTimeMsec = computeSlotTimeMsec(); - preambleTimeMsec = getPacketTime((uint32_t)0); - maxPacketTimeMsec = getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN + sizeof(PacketHeader)); + preambleTimeMsec = preambleLength * (pow_of_2(sf) / bw); LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f", freq, loraConfig.frequency_offset); LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d", myRegion->name, channelName, loraConfig.modem_preset, @@ -635,7 +608,7 @@ void RadioInterface::applyModemConfig() LOG_INFO("numChannels: %d x %.3fkHz", numChannels, bw); LOG_INFO("channel_num: %d", channel_num + 1); LOG_INFO("frequency: %f", getFreq()); - LOG_INFO("Slot time: %u msec", slotTimeMsec); + LOG_INFO("Slot time: %u msec, preamble time: %u msec", slotTimeMsec, preambleTimeMsec); } /** Slottime is the time to detect a transmission has started, consisting of: diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 0c5b6cd1a..6049a11cc 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -87,9 +87,8 @@ class RadioInterface const uint8_t NUM_SYM_CAD = 2; // Number of symbols used for CAD, 2 is the default since RadioLib 6.3.0 as per AN1200.48 const uint8_t NUM_SYM_CAD_24GHZ = 4; // Number of symbols used for CAD in 2.4 GHz, 4 is recommended in AN1200.22 of SX1280 uint32_t slotTimeMsec = computeSlotTimeMsec(); - uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving - uint32_t preambleTimeMsec = 165; // calculated on startup, this is the default for LongFast - uint32_t maxPacketTimeMsec = 3246; // calculated on startup, this is the default for LongFast + uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving + uint32_t preambleTimeMsec = 165; // calculated on startup, this is the default for LongFast const uint32_t PROCESSING_TIME_MSEC = 4500; // time to construct, process and construct a packet again (empirically determined) const uint8_t CWmin = 3; // minimum CWsize @@ -202,8 +201,8 @@ class RadioInterface * * @return num msecs for the packet */ - uint32_t getPacketTime(const meshtastic_MeshPacket *p); - uint32_t getPacketTime(uint32_t totalPacketLen); + uint32_t getPacketTime(const meshtastic_MeshPacket *p, bool received = false); + virtual uint32_t getPacketTime(uint32_t totalPacketLen, bool received = false) = 0; /** * Get the channel we saved. diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 3717e8780..4a18d4139 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -116,16 +116,21 @@ bool RadioLibInterface::receiveDetected(uint16_t irq, ulong syncWordHeaderValidF if (detected) { if (!activeReceiveStart) { activeReceiveStart = millis(); - } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) && !(irq & syncWordHeaderValidFlag)) { - // The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag - activeReceiveStart = 0; - LOG_DEBUG("Ignore false preamble detection"); - return false; - } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) { - // We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag - activeReceiveStart = 0; - LOG_DEBUG("Ignore false header detection"); - return false; + } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec)) { + if (!(irq & syncWordHeaderValidFlag)) { + // The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag + activeReceiveStart = 0; + LOG_DEBUG("Ignore false preamble detection"); + return false; + } else { + uint32_t maxPacketTimeMsec = getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN + sizeof(PacketHeader)); + if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) { + // We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag + activeReceiveStart = 0; + LOG_DEBUG("Ignore false header detection"); + return false; + } + } } } return detected; @@ -411,8 +416,6 @@ void RadioLibInterface::completeSending() void RadioLibInterface::handleReceiveInterrupt() { - uint32_t xmitMsec; - // when this is called, we should be in receive mode - if we are not, just jump out instead of bombing. Possible Race // Condition? if (!isReceiving) { @@ -425,12 +428,12 @@ void RadioLibInterface::handleReceiveInterrupt() // read the number of actually received bytes size_t length = iface->getPacketLength(); - xmitMsec = getPacketTime(length); + uint32_t rxMsec = getPacketTime(length, true); #ifndef DISABLE_WELCOME_UNSET if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) { LOG_WARN("lora rx disabled: Region unset"); - airTime->logAirtime(RX_ALL_LOG, xmitMsec); + airTime->logAirtime(RX_ALL_LOG, rxMsec); return; } #endif @@ -446,7 +449,7 @@ void RadioLibInterface::handleReceiveInterrupt() radioBuffer.header.to, radioBuffer.header.from, radioBuffer.header.flags); rxBad++; - airTime->logAirtime(RX_ALL_LOG, xmitMsec); + airTime->logAirtime(RX_ALL_LOG, rxMsec); } else { // Skip the 4 headers that are at the beginning of the rxBuf @@ -456,7 +459,7 @@ void RadioLibInterface::handleReceiveInterrupt() if (payloadLen < 0) { LOG_WARN("Ignore received packet too short"); rxBad++; - airTime->logAirtime(RX_ALL_LOG, xmitMsec); + airTime->logAirtime(RX_ALL_LOG, rxMsec); } else { rxGood++; // altered packet with "from == 0" can do Remote Node Administration without permission @@ -494,7 +497,7 @@ void RadioLibInterface::handleReceiveInterrupt() printPacket("Lora RX", mp); - airTime->logAirtime(RX_LOG, xmitMsec); + airTime->logAirtime(RX_LOG, rxMsec); deliverToReceiver(mp); } diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 3444b1a2c..d8f38cad3 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -61,6 +61,17 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE); protected: + ModemType_t modemType = RADIOLIB_MODEM_LORA; + DataRate_t getDataRate() const { return {.lora = {.spreadingFactor = sf, .bandwidth = bw, .codingRate = cr}}; } + PacketConfig_t getPacketConfig() const + { + return {.lora = {.preambleLength = preambleLength, + .implicitHeader = false, + .crcEnabled = true, + // We use auto LDRO, meaning it is enabled if the symbol time is >= 16msec + .ldrOptimize = (1 << sf) / bw >= 16}}; + } + /** * We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old * loads 0x14) Note: do not use 0x34 - that is reserved for lorawan @@ -209,6 +220,36 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ virtual void setStandby(); + /** + * Derive packet time either for a received (using header info) or a transmitted packet + */ + template uint32_t computePacketTime(T &lora, uint32_t pl, bool received) + { + if (received) { + // First get the actual coding rate and CRC status from the received packet + uint8_t rxCR; + bool hasCRC; + lora.getLoRaRxHeaderInfo(&rxCR, &hasCRC); + // Go from raw header value to denominator + if (rxCR < 5) { + rxCR += 4; + } else if (rxCR == 7) { + rxCR = 8; + } + + // Received packet configuration must be the same as configured, except for coding rate and CRC + DataRate_t dr = getDataRate(); + dr.lora.codingRate = rxCR; + + PacketConfig_t pc = getPacketConfig(); + pc.lora.crcEnabled = hasCRC; + + return lora.calculateTimeOnAir(modemType, dr, pc, pl) / 1000; + } + + return lora.getTimeOnAir(pl) / 1000; + } + const char *radioLibErr = "RadioLib err="; /** diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index b31c352fe..00066a7a3 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -76,7 +76,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) If we don't add this, we will likely retransmit too early. */ for (auto i = pending.begin(); i != pending.end(); i++) { - i->second.nextTxMsec += iface->getPacketTime(p); + i->second.nextTxMsec += iface->getPacketTime(p, true); } return isBroadcast(p->to) ? FloodingRouter::shouldFilterReceived(p) : NextHopRouter::shouldFilterReceived(p); diff --git a/src/mesh/SX126xInterface.h b/src/mesh/SX126xInterface.h index dc7024daa..b8f16ac6d 100644 --- a/src/mesh/SX126xInterface.h +++ b/src/mesh/SX126xInterface.h @@ -72,6 +72,8 @@ template class SX126xInterface : public RadioLibInterface virtual void setStandby() override; + uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(lora, pl, received); } + private: /** Some boards require GPIO control of tx vs rx paths */ void setTransmitEnable(bool txon); diff --git a/src/mesh/SX128xInterface.h b/src/mesh/SX128xInterface.h index bba31dab4..acdcbbb27 100644 --- a/src/mesh/SX128xInterface.h +++ b/src/mesh/SX128xInterface.h @@ -67,4 +67,6 @@ template class SX128xInterface : public RadioLibInterface virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override; virtual void setStandby() override; + + uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(lora, pl, received); } }; diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp index cea1eab3a..0af2bf47f 100644 --- a/src/platform/portduino/SimRadio.cpp +++ b/src/platform/portduino/SimRadio.cpp @@ -182,7 +182,7 @@ void SimRadio::onNotify(uint32_t notification) assert(txp); startSend(txp); // Packet has been sent, count it toward our TX airtime utilization. - uint32_t xmitMsec = getPacketTime(txp); + uint32_t xmitMsec = RadioInterface::getPacketTime(txp); airTime->logAirtime(TX_LOG, xmitMsec); notifyLater(xmitMsec, ISR_TX, false); // Model the time it is busy sending @@ -252,7 +252,7 @@ void SimRadio::startReceive(meshtastic_MeshPacket *p) if (isActivelyReceiving()) { LOG_WARN("Collision detected, dropping current and previous packet!"); rxBad++; - airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket)); + airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket, true)); packetPool.release(receivingPacket); receivingPacket = nullptr; return; @@ -270,7 +270,7 @@ void SimRadio::startReceive(meshtastic_MeshPacket *p) } isReceiving = true; receivingPacket = packetPool.allocCopy(*p); - uint32_t airtimeMsec = getPacketTime(p); + uint32_t airtimeMsec = getPacketTime(p, true); notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving #else isReceiving = true; @@ -311,7 +311,7 @@ void SimRadio::handleReceiveInterrupt() printPacket("Lora RX", mp); - airTime->logAirtime(RX_LOG, getPacketTime(mp)); + airTime->logAirtime(RX_LOG, RadioInterface::getPacketTime(mp, true)); deliverToReceiver(mp); } @@ -332,4 +332,29 @@ int16_t SimRadio::readData(uint8_t *data, size_t len) } return state; +} + +/** + * Calculate airtime per + * https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf + * section 4 + * + * @return num msecs for the packet + */ +uint32_t SimRadio::getPacketTime(uint32_t pl, bool received) +{ + float bandwidthHz = bw * 1000.0f; + bool headDisable = false; // we currently always use the header + float tSym = (1 << sf) / bandwidthHz; + + bool lowDataOptEn = tSym > 16e-3 ? true : false; // Needed if symbol time is >16ms + + float tPreamble = (preambleLength + 4.25f) * tSym; + float numPayloadSym = + 8 + max(ceilf(((8.0f * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * cr), 0.0f); + float tPayload = numPayloadSym * tSym; + float tPacket = tPreamble + tPayload; + + uint32_t msecs = tPacket * 1000; + return msecs; } \ No newline at end of file diff --git a/src/platform/portduino/SimRadio.h b/src/platform/portduino/SimRadio.h index d8b53739f..d87e6be75 100644 --- a/src/platform/portduino/SimRadio.h +++ b/src/platform/portduino/SimRadio.h @@ -88,6 +88,8 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr /** * If a send was in progress finish it and return the buffer to the pool */ void completeSending(); + + virtual uint32_t getPacketTime(uint32_t pl, bool received = false) override; }; extern SimRadio *simRadio; \ No newline at end of file From 1b97cf57ad4b1c384edbb9f139764a63c32be9d3 Mon Sep 17 00:00:00 2001 From: Szetya Date: Sat, 4 Oct 2025 12:44:47 +0200 Subject: [PATCH 088/166] Correcting GPS PINs (#8087) https://github.com/meshtastic/firmware/issues/8084 Co-authored-by: Ben Meadors --- variants/nrf52840/t-echo-lite/variant.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/variants/nrf52840/t-echo-lite/variant.h b/variants/nrf52840/t-echo-lite/variant.h index 2e2cdce72..34dcee40c 100644 --- a/variants/nrf52840/t-echo-lite/variant.h +++ b/variants/nrf52840/t-echo-lite/variant.h @@ -140,11 +140,12 @@ static const uint8_t A0 = PIN_A0; #define HAS_GPS 1 // #define PIN_GPS_REINIT (32 + 5) // An output to reset L76K GPS. As per datasheet, low for > 100ms will reset the L76K -#define PIN_GPS_STANDBY (32 + 10) // An output to wake GPS, low means allow sleep, high means force wake -// Seems to be missing on this new board -#define PIN_GPS_PPS (0 + 29) // Pulse per second input from the GPS -#define GPS_TX_PIN (32 + 15) // This is for bits going TOWARDS the CPU -#define GPS_RX_PIN (32 + 13) // This is for bits going TOWARDS the GPS +#define PIN_GPS_EN (32 + 11) // GPS power +#define GPS_EN_ACTIVE 1 +#define PIN_GPS_STANDBY (32 + 13) // wakeup pin +#define PIN_GPS_PPS (32 + 15) +#define GPS_TX_PIN (32 + 10) // L76K module RX PIN +#define GPS_RX_PIN (0 + 29) // L76K module TX PIN #define GPS_THREAD_INTERVAL 50 @@ -204,4 +205,4 @@ static const uint8_t A0 = PIN_A0; * Arduino objects - C++ only *----------------------------------------------------------------------------*/ -#endif \ No newline at end of file +#endif From ed32650b9b162dcc5c8f98f93c2ea819381ed6d0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 4 Oct 2025 05:52:04 -0500 Subject: [PATCH 089/166] Update protobufs (#8206) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/telemetry.pb.h | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/protobufs b/protobufs index c1e31a965..a1b8c3d17 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit c1e31a9655e9920a8b5b8eccdf7c69ef1ae42a49 +Subproject commit a1b8c3d171445b2eebfd4b5bd1e4876f3bbed605 diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 9af095e78..a8ca96e95 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -357,6 +357,8 @@ typedef struct _meshtastic_LocalStats { uint32_t heap_total_bytes; /* Number of bytes free in the heap */ uint32_t heap_free_bytes; + /* Number of packets that were dropped because the transmit queue was full. */ + uint16_t num_tx_dropped; } meshtastic_LocalStats; /* Health telemetry metrics */ @@ -454,7 +456,7 @@ extern "C" { #define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_HealthMetrics_init_default {false, 0, false, 0, false, 0} #define meshtastic_HostMetrics_init_default {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""} #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} @@ -463,7 +465,7 @@ extern "C" { #define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_HealthMetrics_init_zero {false, 0, false, 0, false, 0} #define meshtastic_HostMetrics_init_zero {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} @@ -551,6 +553,7 @@ extern "C" { #define meshtastic_LocalStats_num_tx_relay_canceled_tag 11 #define meshtastic_LocalStats_heap_total_bytes_tag 12 #define meshtastic_LocalStats_heap_free_bytes_tag 13 +#define meshtastic_LocalStats_num_tx_dropped_tag 14 #define meshtastic_HealthMetrics_heart_bpm_tag 1 #define meshtastic_HealthMetrics_spO2_tag 2 #define meshtastic_HealthMetrics_temperature_tag 3 @@ -672,7 +675,8 @@ X(a, STATIC, SINGULAR, UINT32, num_rx_dupe, 9) \ X(a, STATIC, SINGULAR, UINT32, num_tx_relay, 10) \ X(a, STATIC, SINGULAR, UINT32, num_tx_relay_canceled, 11) \ X(a, STATIC, SINGULAR, UINT32, heap_total_bytes, 12) \ -X(a, STATIC, SINGULAR, UINT32, heap_free_bytes, 13) +X(a, STATIC, SINGULAR, UINT32, heap_free_bytes, 13) \ +X(a, STATIC, SINGULAR, UINT32, num_tx_dropped, 14) #define meshtastic_LocalStats_CALLBACK NULL #define meshtastic_LocalStats_DEFAULT NULL @@ -749,7 +753,7 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; #define meshtastic_EnvironmentMetrics_size 113 #define meshtastic_HealthMetrics_size 11 #define meshtastic_HostMetrics_size 264 -#define meshtastic_LocalStats_size 72 +#define meshtastic_LocalStats_size 76 #define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 81 #define meshtastic_Telemetry_size 272 From 7c5e2bc95acf81a0997169e7a4243d2a0af963e7 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 4 Oct 2025 06:42:36 -0500 Subject: [PATCH 090/166] Clear out user.id except for sending to phone (#8202) * Null out user.id except for sending to phone * Fix * Update src/modules/NodeInfoModule.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Copilot garbage * This is unnecessary, because we don't stored user.id on userlite * Don't need this * Fix warning * Just alter the protobuf * Alter protobuf doesn't do anything with the altered data, so let's re-encode it * Check inputbroker before access --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/main.cpp | 3 ++- src/mesh/NodeDB.cpp | 9 +++++---- src/modules/AdminModule.cpp | 6 ++---- src/modules/NodeInfoModule.cpp | 24 ++++++++++++++++++++++-- src/modules/NodeInfoModule.h | 3 +++ 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index bca2da2cb..b0f086f14 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1601,7 +1601,8 @@ void loop() service->loop(); #if !MESHTASTIC_EXCLUDE_INPUTBROKER && defined(HAS_FREE_RTOS) - inputBroker->processInputEventQueue(); + if (inputBroker) + inputBroker->processInputEventQueue(); #endif #if defined(LGFX_SDL) if (screen) { diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index a43ef17bc..e3240462d 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -56,10 +56,6 @@ #include #endif -// stringify -#define xstr(s) str(s) -#define str(s) #s - NodeDB *nodeDB = nullptr; // we have plenty of ram so statically alloc this tempbuf (for now) @@ -260,6 +256,8 @@ NodeDB::NodeDB() owner.role = config.device.role; // Ensure macaddr is set to our macaddr as it will be copied in our info below memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr)); + // Ensure owner.id is always derived from the node number + snprintf(owner.id, sizeof(owner.id), "!%08x", getNodeNum()); if (!config.has_security) { config.has_security = true; @@ -1695,6 +1693,9 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde } #endif + // Always ensure user.id is derived from nodeId, regardless of what was received + snprintf(p.id, sizeof(p.id), "!%08x", nodeId); + // Both of info->user and p start as filled with zero so I think this is okay auto lite = TypeConversions::ConvertToUserLite(p); bool changed = memcmp(&info->user, &lite, sizeof(info->user)) || (info->channel != channelIndex); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 353db1a11..d300ff53b 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -554,10 +554,8 @@ void AdminModule::handleSetOwner(const meshtastic_User &o) changed |= strcmp(owner.short_name, o.short_name); strncpy(owner.short_name, o.short_name, sizeof(owner.short_name)); } - if (*o.id) { - changed |= strcmp(owner.id, o.id); - strncpy(owner.id, o.id, sizeof(owner.id)); - } + snprintf(owner.id, sizeof(owner.id), "!%08x", nodeDB->getNodeNum()); + if (owner.is_licensed != o.is_licensed) { changed = 1; owner.is_licensed = o.is_licensed; diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 2c3c274d2..9b94b3933 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -30,14 +30,32 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes bool wasBroadcast = isBroadcast(mp.to); + // LOG_DEBUG("did encode"); // if user has changed while packet was not for us, inform phone - if (hasChanged && !wasBroadcast && !isToUs(&mp)) - service->sendToPhone(packetPool.allocCopy(mp)); + if (hasChanged && !wasBroadcast && !isToUs(&mp)) { + auto packetCopy = packetPool.allocCopy(mp); // Keep a copy of the packet for later analysis + + // Re-encode the user protobuf, as we have stripped out the user.id + packetCopy->decoded.payload.size = pb_encode_to_bytes( + packetCopy->decoded.payload.bytes, sizeof(packetCopy->decoded.payload.bytes), &meshtastic_User_msg, &p); + + service->sendToPhone(packetCopy); + } // LOG_DEBUG("did handleReceived"); return false; // Let others look at this message also if they want } +void NodeInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_User *p) +{ + // Coerce user.id to be derived from the node number + snprintf(p->id, sizeof(p->id), "!%08x", getFrom(&mp)); + + // Re-encode the altered protobuf back into the packet + mp.decoded.payload.size = + pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes), &meshtastic_User_msg, p); +} + void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t channel, bool _shorterTimeout) { // cancel any not yet sent (now stale) position packets @@ -95,6 +113,8 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply() u.public_key.size = 0; } + // Clear the user.id field since it should be derived from node number on the receiving end + u.id[0] = '\0'; LOG_INFO("Send owner %s/%s/%s", u.id, u.long_name, u.short_name); lastSentToMesh = millis(); return allocDataProtobuf(u); diff --git a/src/modules/NodeInfoModule.h b/src/modules/NodeInfoModule.h index c1fb9ccce..572b81700 100644 --- a/src/modules/NodeInfoModule.h +++ b/src/modules/NodeInfoModule.h @@ -30,6 +30,9 @@ class NodeInfoModule : public ProtobufModule, private concurren */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_User *p) override; + /** Called to alter received User protobuf */ + virtual void alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_User *p) override; + /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. */ virtual meshtastic_MeshPacket *allocReply() override; From 888692a3735b10225bc347eeb89ecd178a22f9b4 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sat, 4 Oct 2025 15:13:58 +0200 Subject: [PATCH 091/166] Add dropped packet count to LocalStats (#8207) * Add dropped packet count to LocalStats In case the transmit queue was full * Trunked --------- Co-authored-by: Ben Meadors --- src/mesh/MeshPacketQueue.cpp | 9 ++++++++- src/mesh/MeshPacketQueue.h | 6 ++++-- src/mesh/RadioLibInterface.cpp | 13 +++++++++++-- src/mesh/RadioLibInterface.h | 1 + src/modules/Telemetry/DeviceTelemetry.cpp | 2 ++ src/platform/portduino/SimRadio.cpp | 7 ++++++- src/platform/portduino/SimRadio.h | 1 + variants/nrf52840/t-echo-lite/variant.h | 2 +- 8 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index ef5380eb8..cbea85c62 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -65,7 +65,7 @@ void fixPriority(meshtastic_MeshPacket *p) } /** enqueue a packet, return false if full */ -bool MeshPacketQueue::enqueue(meshtastic_MeshPacket *p) +bool MeshPacketQueue::enqueue(meshtastic_MeshPacket *p, bool *dropped) { // no space - try to replace a lower priority packet in the queue if (queue.size() >= maxLen) { @@ -73,9 +73,16 @@ bool MeshPacketQueue::enqueue(meshtastic_MeshPacket *p) if (!replaced) { LOG_WARN("TX queue is full, and there is no lower-priority packet available to evict in favour of 0x%08x", p->id); } + if (dropped) { + *dropped = true; + } return replaced; } + if (dropped) { + *dropped = false; + } + // Find the correct position using upper_bound to maintain a stable order auto it = std::upper_bound(queue.begin(), queue.end(), p, CompareMeshPacketFunc); queue.insert(it, p); // Insert packet at the found position diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h index ea52eb5bf..3d3902c1e 100644 --- a/src/mesh/MeshPacketQueue.h +++ b/src/mesh/MeshPacketQueue.h @@ -19,8 +19,10 @@ class MeshPacketQueue public: explicit MeshPacketQueue(size_t _maxLen); - /** enqueue a packet, return false if full */ - bool enqueue(meshtastic_MeshPacket *p); + /** enqueue a packet, return false if full + * @param dropped Optional pointer to a bool that will be set to true if a packet was dropped + */ + bool enqueue(meshtastic_MeshPacket *p, bool *dropped = nullptr); /** return true if the queue is empty */ bool empty(); diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 4a18d4139..2567d9e7f 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -177,7 +177,12 @@ ErrorCode RadioLibInterface::send(meshtastic_MeshPacket *p) printPacket("enqueue for send", p); LOG_DEBUG("txGood=%d,txRelay=%d,rxGood=%d,rxBad=%d", txGood, txRelay, rxGood, rxBad); - ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN; + bool dropped = false; + ErrorCode res = txQueue.enqueue(p, &dropped) ? ERRNO_OK : ERRNO_UNKNOWN; + + if (dropped) { + txDrop++; + } if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks packetPool.release(p); @@ -359,11 +364,15 @@ void RadioLibInterface::clampToLateRebroadcastWindow(NodeNum from, PacketId id) meshtastic_MeshPacket *p = txQueue.remove(from, id, true, false); if (p) { p->tx_after = millis() + getTxDelayMsecWeightedWorst(p->rx_snr); - if (txQueue.enqueue(p)) { + bool dropped = false; + if (txQueue.enqueue(p, &dropped)) { LOG_DEBUG("Move existing queued packet to the late rebroadcast window %dms from now", p->tx_after - millis()); } else { packetPool.release(p); } + if (dropped) { + txDrop++; + } } } diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index d8f38cad3..833c88710 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -116,6 +116,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified * Debugging counts */ uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0; + uint16_t txDrop = 0; public: RadioLibInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index ad148b759..7e3018564 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -121,6 +121,7 @@ meshtastic_Telemetry DeviceTelemetryModule::getLocalStatsTelemetry() telemetry.variant.local_stats.num_packets_rx = RadioLibInterface::instance->rxGood + RadioLibInterface::instance->rxBad; telemetry.variant.local_stats.num_packets_rx_bad = RadioLibInterface::instance->rxBad; telemetry.variant.local_stats.num_tx_relay = RadioLibInterface::instance->txRelay; + telemetry.variant.local_stats.num_tx_dropped = RadioLibInterface::instance->txDrop; } #ifdef ARCH_PORTDUINO if (SimRadio::instance) { @@ -128,6 +129,7 @@ meshtastic_Telemetry DeviceTelemetryModule::getLocalStatsTelemetry() telemetry.variant.local_stats.num_packets_rx = SimRadio::instance->rxGood + SimRadio::instance->rxBad; telemetry.variant.local_stats.num_packets_rx_bad = SimRadio::instance->rxBad; telemetry.variant.local_stats.num_tx_relay = SimRadio::instance->txRelay; + telemetry.variant.local_stats.num_tx_dropped = SimRadio::instance->txDrop; } #else telemetry.variant.local_stats.heap_total_bytes = memGet.getHeapSize(); diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp index 0af2bf47f..6e7fe24cb 100644 --- a/src/platform/portduino/SimRadio.cpp +++ b/src/platform/portduino/SimRadio.cpp @@ -13,7 +13,12 @@ ErrorCode SimRadio::send(meshtastic_MeshPacket *p) { printPacket("enqueuing for send", p); - ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN; + bool dropped = false; + ErrorCode res = txQueue.enqueue(p, &dropped) ? ERRNO_OK : ERRNO_UNKNOWN; + + if (dropped) { + txDrop++; + } if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks packetPool.release(p); diff --git a/src/platform/portduino/SimRadio.h b/src/platform/portduino/SimRadio.h index d87e6be75..6f80989da 100644 --- a/src/platform/portduino/SimRadio.h +++ b/src/platform/portduino/SimRadio.h @@ -52,6 +52,7 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr * Debugging counts */ uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0; + uint16_t txDrop = 0; protected: /// are _trying_ to receive a packet currently (note - we might just be waiting for one) diff --git a/variants/nrf52840/t-echo-lite/variant.h b/variants/nrf52840/t-echo-lite/variant.h index 34dcee40c..0748f6d48 100644 --- a/variants/nrf52840/t-echo-lite/variant.h +++ b/variants/nrf52840/t-echo-lite/variant.h @@ -145,7 +145,7 @@ static const uint8_t A0 = PIN_A0; #define PIN_GPS_STANDBY (32 + 13) // wakeup pin #define PIN_GPS_PPS (32 + 15) #define GPS_TX_PIN (32 + 10) // L76K module RX PIN -#define GPS_RX_PIN (0 + 29) // L76K module TX PIN +#define GPS_RX_PIN (0 + 29) // L76K module TX PIN #define GPS_THREAD_INTERVAL 50 From 9ded6a52153d894880a98298ee4896d4316a2c46 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 8 Sep 2025 18:39:36 -0500 Subject: [PATCH 092/166] Pull in panel_sdl directly and drop native-sdl target --- src/graphics/Panel_sdl.cpp | 687 +++++++++++++++++++++++ src/graphics/Panel_sdl.hpp | 165 ++++++ src/graphics/TFTDisplay.cpp | 32 +- src/main.cpp | 5 +- variants/native/portduino/platformio.ini | 20 +- 5 files changed, 871 insertions(+), 38 deletions(-) create mode 100644 src/graphics/Panel_sdl.cpp create mode 100644 src/graphics/Panel_sdl.hpp diff --git a/src/graphics/Panel_sdl.cpp b/src/graphics/Panel_sdl.cpp new file mode 100644 index 000000000..bad6072f9 --- /dev/null +++ b/src/graphics/Panel_sdl.cpp @@ -0,0 +1,687 @@ +/*----------------------------------------------------------------------------/ + Lovyan GFX - Graphics library for embedded devices. + +Original Source: + https://github.com/lovyan03/LovyanGFX/ + +Licence: + [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) + +Author: + [lovyan03](https://twitter.com/lovyan03) + +Contributors: + [ciniml](https://github.com/ciniml) + [mongonta0716](https://github.com/mongonta0716) + [tobozo](https://github.com/tobozo) + +Porting for SDL: + [imliubo](https://github.com/imliubo) +/----------------------------------------------------------------------------*/ +#include "Panel_sdl.hpp" + +#if defined(SDL_h_) + +// #include "../common.hpp" +// #include "../../misc/common_function.hpp" +// #include "../../Bus.hpp" + +#include +#include +#include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace lgfx +{ +inline namespace v1 +{ +SDL_Keymod Panel_sdl::_keymod = KMOD_NONE; +static SDL_semaphore *_update_in_semaphore = nullptr; +static SDL_semaphore *_update_out_semaphore = nullptr; +volatile static uint32_t _in_step_exec = 0; +volatile static uint32_t _msec_step_exec = 512; +static bool _inited = false; +static bool _all_close = false; + +volatile uint8_t Panel_sdl::_gpio_dummy_values[EMULATED_GPIO_MAX]; + +static inline void *heap_alloc_dma(size_t length) +{ + return malloc(length); +} // aligned_alloc(16, length); +static inline void heap_free(void *buf) +{ + free(buf); +} + +static std::list _list_monitor; + +static monitor_t *const getMonitorByWindowID(uint32_t windowID) +{ + for (auto &m : _list_monitor) { + if (SDL_GetWindowID(m->window) == windowID) { + return m; + } + } + return nullptr; +} +//---------------------------------------------------------------------------- + +static std::vector _key_code_map; + +void Panel_sdl::addKeyCodeMapping(SDL_KeyCode keyCode, uint8_t gpio) +{ + if (gpio > EMULATED_GPIO_MAX) + return; + KeyCodeMapping_t map; + map.keycode = keyCode; + map.gpio = gpio; + _key_code_map.push_back(map); +} + +int Panel_sdl::getKeyCodeMapping(SDL_KeyCode keyCode) +{ + for (const auto &i : _key_code_map) { + if (i.keycode == keyCode) + return i.gpio; + } + return -1; +} + +void Panel_sdl::_event_proc(void) +{ + SDL_Event event; + while (SDL_PollEvent(&event)) { + if ((event.type == SDL_KEYDOWN) || (event.type == SDL_KEYUP)) { + auto mon = getMonitorByWindowID(event.button.windowID); + int gpio = -1; + + /// Check key mapping + gpio = getKeyCodeMapping((SDL_KeyCode)event.key.keysym.sym); + if (gpio < 0) { + switch (event.key.keysym.sym) { /// M5StackのBtnA~BtnCのエミュレート; + // case SDLK_LEFT: gpio = 39; break; + // case SDLK_DOWN: gpio = 38; break; + // case SDLK_RIGHT: gpio = 37; break; + // case SDLK_UP: gpio = 36; break; + + /// L/Rキーで画面回転 + case SDLK_r: + case SDLK_l: + if (event.type == SDL_KEYDOWN && event.key.keysym.mod == _keymod) { + if (mon != nullptr) { + mon->frame_rotation = (mon->frame_rotation += event.key.keysym.sym == SDLK_r ? 1 : -1); + int x, y, w, h; + SDL_GetWindowSize(mon->window, &w, &h); + SDL_GetWindowPosition(mon->window, &x, &y); + SDL_SetWindowSize(mon->window, h, w); + SDL_SetWindowPosition(mon->window, x + (w - h) / 2, y + (h - w) / 2); + mon->panel->sdl_invalidate(); + } + } + break; + + /// 1~6キーで画面拡大率変更 + case SDLK_1: + case SDLK_2: + case SDLK_3: + case SDLK_4: + case SDLK_5: + case SDLK_6: + if (event.type == SDL_KEYDOWN && event.key.keysym.mod == _keymod) { + if (mon != nullptr) { + int size = 1 + (event.key.keysym.sym - SDLK_1); + _update_scaling(mon, size, size); + } + } + break; + default: + continue; + } + } + + if (event.type == SDL_KEYDOWN) { + Panel_sdl::gpio_lo(gpio); + } else { + Panel_sdl::gpio_hi(gpio); + } + } else if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEMOTION) { + auto mon = getMonitorByWindowID(event.button.windowID); + if (mon != nullptr) { + { + int x, y, w, h; + SDL_GetWindowSize(mon->window, &w, &h); + SDL_GetMouseState(&x, &y); + float sf = sinf(mon->frame_angle * M_PI / 180); + float cf = cosf(mon->frame_angle * M_PI / 180); + x -= w / 2.0f; + y -= h / 2.0f; + float nx = y * sf + x * cf; + float ny = y * cf - x * sf; + if (mon->frame_rotation & 1) { + std::swap(w, h); + } + x = (nx * mon->frame_width / w) + (mon->frame_width >> 1); + y = (ny * mon->frame_height / h) + (mon->frame_height >> 1); + mon->touch_x = x - mon->frame_inner_x; + mon->touch_y = y - mon->frame_inner_y; + } + if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT) { + mon->touched = true; + } + if (event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_LEFT) { + mon->touched = false; + } + } + } else if (event.type == SDL_WINDOWEVENT) { + auto monitor = getMonitorByWindowID(event.window.windowID); + if (monitor) { + if (event.window.event == SDL_WINDOWEVENT_RESIZED) { + int mw, mh; + SDL_GetRendererOutputSize(monitor->renderer, &mw, &mh); + if (monitor->frame_rotation & 1) { + std::swap(mw, mh); + } + monitor->scaling_x = (mw * 2 / monitor->frame_width) / 2.0f; + monitor->scaling_y = (mh * 2 / monitor->frame_height) / 2.0f; + monitor->panel->sdl_invalidate(); + } else if (event.window.event == SDL_WINDOWEVENT_CLOSE) { + monitor->closing = true; + } + } + } else if (event.type == SDL_QUIT) { + for (auto &m : _list_monitor) { + m->closing = true; + } + } + } +} + +/// デバッガでステップ実行されていることを検出するスレッド用関数。 +static int detectDebugger(bool *running) +{ + uint32_t prev_ms = SDL_GetTicks(); + do { + SDL_Delay(1); + uint32_t ms = SDL_GetTicks(); + /// 時間間隔が広すぎる場合はステップ実行中 (ブレークポイントで止まった)と判断する。 + /// また、解除されたと判断した後も1023msecほど状態を維持する。 + if (ms - prev_ms > 64) { + _in_step_exec = _msec_step_exec; + } else if (_in_step_exec) { + --_in_step_exec; + } + prev_ms = ms; + } while (*running); + return 0; +} + +void Panel_sdl::_update_proc(void) +{ + for (auto it = _list_monitor.begin(); it != _list_monitor.end();) { + if ((*it)->closing) { + if ((*it)->texture_frameimage) { + SDL_DestroyTexture((*it)->texture_frameimage); + } + SDL_DestroyTexture((*it)->texture); + SDL_DestroyRenderer((*it)->renderer); + SDL_DestroyWindow((*it)->window); + _list_monitor.erase(it++); + if (_list_monitor.empty()) { + _all_close = true; + return; + } + continue; + } + (*it)->panel->sdl_update(); + ++it; + } +} + +int Panel_sdl::setup(void) +{ + if (_inited) + return 1; + _inited = true; + + /// Add default keycode mapping + /// M5StackのBtnA~BtnCのエミュレート; + addKeyCodeMapping(SDLK_LEFT, 39); + addKeyCodeMapping(SDLK_DOWN, 38); + addKeyCodeMapping(SDLK_RIGHT, 37); + addKeyCodeMapping(SDLK_UP, 36); + + SDL_CreateThread((SDL_ThreadFunction)detectDebugger, "dbg", &_inited); + + _update_in_semaphore = SDL_CreateSemaphore(0); + _update_out_semaphore = SDL_CreateSemaphore(0); + for (size_t pin = 0; pin < EMULATED_GPIO_MAX; ++pin) { + gpio_hi(pin); + } + /*Initialize the SDL*/ + SDL_Init(SDL_INIT_VIDEO); + SDL_StartTextInput(); + + // SDL_SetThreadPriority(SDL_ThreadPriority::SDL_THREAD_PRIORITY_HIGH); + return 0; +} + +int Panel_sdl::loop(void) +{ + if (!_inited) + return 1; + + _event_proc(); + SDL_SemWaitTimeout(_update_in_semaphore, 1); + _update_proc(); + _event_proc(); + if (SDL_SemValue(_update_out_semaphore) == 0) { + SDL_SemPost(_update_out_semaphore); + } + + return _all_close; +} + +int Panel_sdl::close(void) +{ + if (!_inited) + return 1; + _inited = false; + + SDL_StopTextInput(); + SDL_DestroySemaphore(_update_in_semaphore); + SDL_DestroySemaphore(_update_out_semaphore); + SDL_Quit(); + return 0; +} + +int Panel_sdl::main(int (*fn)(bool *), uint32_t msec_step_exec) +{ + _msec_step_exec = msec_step_exec; + + /// SDLの準備 + if (0 != Panel_sdl::setup()) { + return 1; + } + + /// ユーザコード関数の動作・停止フラグ + bool running = true; + + /// ユーザコード関数を起動する + auto thread = SDL_CreateThread((SDL_ThreadFunction)fn, "fn", &running); + + /// 全部のウィンドウが閉じられるまでSDLのイベント・描画処理を継続 + while (0 == Panel_sdl::loop()) { + }; + + /// ユーザコード関数を終了する + running = false; + SDL_WaitThread(thread, nullptr); + + /// SDLを終了する + return Panel_sdl::close(); +} + +void Panel_sdl::setScaling(uint_fast8_t scaling_x, uint_fast8_t scaling_y) +{ + monitor.scaling_x = scaling_x; + monitor.scaling_y = scaling_y; +} + +void Panel_sdl::setFrameImage(const void *frame_image, int frame_width, int frame_height, int inner_x, int inner_y) +{ + monitor.frame_image = frame_image; + monitor.frame_width = frame_width; + monitor.frame_height = frame_height; + monitor.frame_inner_x = inner_x; + monitor.frame_inner_y = inner_y; +} + +void Panel_sdl::setFrameRotation(uint_fast16_t frame_rotation) +{ + monitor.frame_rotation = frame_rotation; + monitor.frame_angle = (monitor.frame_rotation) * 90; +} + +Panel_sdl::~Panel_sdl(void) +{ + _list_monitor.remove(&monitor); + SDL_DestroyMutex(_sdl_mutex); +} + +Panel_sdl::Panel_sdl(void) : Panel_FrameBufferBase() +{ + _sdl_mutex = SDL_CreateMutex(); + _auto_display = true; + monitor.panel = this; +} + +bool Panel_sdl::init(bool use_reset) +{ + initFrameBuffer(_cfg.panel_width * 4, _cfg.panel_height); + bool res = Panel_FrameBufferBase::init(use_reset); + + _list_monitor.push_back(&monitor); + + return res; +} + +color_depth_t Panel_sdl::setColorDepth(color_depth_t depth) +{ + auto bits = depth & color_depth_t::bit_mask; + if (bits >= 16) { + depth = (bits > 16) ? rgb888_3Byte : rgb565_2Byte; + } else { + depth = (depth == color_depth_t::grayscale_8bit) ? grayscale_8bit : rgb332_1Byte; + } + _write_depth = depth; + _read_depth = depth; + + return depth; +} + +Panel_sdl::lock_t::lock_t(Panel_sdl *parent) : _parent{parent} +{ + SDL_LockMutex(parent->_sdl_mutex); +}; + +Panel_sdl::lock_t::~lock_t(void) +{ + ++_parent->_modified_counter; + SDL_UnlockMutex(_parent->_sdl_mutex); + if (SDL_SemValue(_update_in_semaphore) < 2) { + SDL_SemPost(_update_in_semaphore); + if (!_in_step_exec) { + SDL_SemWaitTimeout(_update_out_semaphore, 1); + } + } +}; + +void Panel_sdl::drawPixelPreclipped(uint_fast16_t x, uint_fast16_t y, uint32_t rawcolor) +{ + lock_t lock(this); + Panel_FrameBufferBase::drawPixelPreclipped(x, y, rawcolor); +} + +void Panel_sdl::writeFillRectPreclipped(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, uint32_t rawcolor) +{ + lock_t lock(this); + Panel_FrameBufferBase::writeFillRectPreclipped(x, y, w, h, rawcolor); +} + +void Panel_sdl::writeBlock(uint32_t rawcolor, uint32_t length) +{ + // lock_t lock(this); + Panel_FrameBufferBase::writeBlock(rawcolor, length); +} + +void Panel_sdl::writeImage(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t *param, bool use_dma) +{ + lock_t lock(this); + Panel_FrameBufferBase::writeImage(x, y, w, h, param, use_dma); +} + +void Panel_sdl::writeImageARGB(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t *param) +{ + lock_t lock(this); + Panel_FrameBufferBase::writeImageARGB(x, y, w, h, param); +} + +void Panel_sdl::writePixels(pixelcopy_t *param, uint32_t len, bool use_dma) +{ + lock_t lock(this); + Panel_FrameBufferBase::writePixels(param, len, use_dma); +} + +void Panel_sdl::display(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h) +{ + (void)x; + (void)y; + (void)w; + (void)h; + if (_in_step_exec) { + if (_display_counter != _modified_counter) { + do { + SDL_SemPost(_update_in_semaphore); + SDL_SemWaitTimeout(_update_out_semaphore, 1); + } while (_display_counter != _modified_counter); + SDL_Delay(1); + } + } +} + +uint_fast8_t Panel_sdl::getTouchRaw(touch_point_t *tp, uint_fast8_t count) +{ + (void)count; + tp->x = monitor.touch_x; + tp->y = monitor.touch_y; + tp->size = monitor.touched ? 1 : 0; + tp->id = 0; + return monitor.touched; +} + +void Panel_sdl::setWindowTitle(const char *title) +{ + _window_title = title; + if (monitor.window) { + SDL_SetWindowTitle(monitor.window, _window_title); + } +} + +void Panel_sdl::_update_scaling(monitor_t *mon, float sx, float sy) +{ + mon->scaling_x = sx; + mon->scaling_y = sy; + int nw = mon->frame_width; + int nh = mon->frame_height; + if (mon->frame_rotation & 1) { + std::swap(nw, nh); + } + + int x, y, w, h; + int rw, rh; + SDL_GetRendererOutputSize(mon->renderer, &rw, &rh); + SDL_GetWindowSize(mon->window, &w, &h); + nw = nw * sx * w / rw; + nh = nh * sy * h / rh; + SDL_GetWindowPosition(mon->window, &x, &y); + SDL_SetWindowSize(mon->window, nw, nh); + SDL_SetWindowPosition(mon->window, x + (w - nw) / 2, y + (h - nh) / 2); + mon->panel->sdl_invalidate(); +} + +void Panel_sdl::sdl_create(monitor_t *m) +{ + int flag = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; +#if SDL_FULLSCREEN + flag |= SDL_WINDOW_FULLSCREEN; +#endif + + if (m->frame_width < _cfg.panel_width) { + m->frame_width = _cfg.panel_width; + } + if (m->frame_height < _cfg.panel_height) { + m->frame_height = _cfg.panel_height; + } + + int window_width = m->frame_width * m->scaling_x; + int window_height = m->frame_height * m->scaling_y; + int scaling_x = m->scaling_x; + int scaling_y = m->scaling_y; + if (m->frame_rotation & 1) { + std::swap(window_width, window_height); + std::swap(scaling_x, scaling_y); + } + + { + m->window = SDL_CreateWindow(_window_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, + flag); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/ + } + m->renderer = SDL_CreateRenderer(m->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + m->texture = + SDL_CreateTexture(m->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, _cfg.panel_width, _cfg.panel_height); + SDL_SetTextureBlendMode(m->texture, SDL_BLENDMODE_NONE); + + if (m->frame_image) { + // 枠画像用のサーフェイスを作成 + auto sf = SDL_CreateRGBSurfaceFrom((void *)m->frame_image, m->frame_width, m->frame_height, 32, m->frame_width * 4, + 0xFF000000, 0xFF0000, 0xFF00, 0xFF); + if (sf != nullptr) { + // 枠画像からテクスチャを作成 + m->texture_frameimage = SDL_CreateTextureFromSurface(m->renderer, sf); + SDL_FreeSurface(sf); + } + } + SDL_SetTextureBlendMode(m->texture_frameimage, SDL_BLENDMODE_BLEND); + _update_scaling(m, scaling_x, scaling_y); +} + +void Panel_sdl::sdl_update(void) +{ + if (monitor.renderer == nullptr) { + sdl_create(&monitor); + } + + bool step_exec = _in_step_exec; + + if (_texupdate_counter != _modified_counter) { + pixelcopy_t pc(nullptr, color_depth_t::rgb888_3Byte, _write_depth, false); + if (_write_depth == rgb565_2Byte) { + pc.fp_copy = pixelcopy_t::copy_rgb_fast; + } else if (_write_depth == rgb888_3Byte) { + pc.fp_copy = pixelcopy_t::copy_rgb_fast; + } else if (_write_depth == rgb332_1Byte) { + pc.fp_copy = pixelcopy_t::copy_rgb_fast; + } else if (_write_depth == grayscale_8bit) { + pc.fp_copy = pixelcopy_t::copy_rgb_fast; + } + + if (0 == SDL_LockMutex(_sdl_mutex)) { + _texupdate_counter = _modified_counter; + for (int y = 0; y < _cfg.panel_height; ++y) { + pc.src_x32 = 0; + pc.src_data = _lines_buffer[y]; + pc.fp_copy(&_texturebuf[y * _cfg.panel_width], 0, _cfg.panel_width, &pc); + } + SDL_UnlockMutex(_sdl_mutex); + SDL_UpdateTexture(monitor.texture, nullptr, _texturebuf, _cfg.panel_width * sizeof(rgb888_t)); + } + } + + int angle = monitor.frame_angle; + int target = (monitor.frame_rotation) * 90; + angle = (((target * 4) + (angle * 4) + (angle < target ? 8 : 0)) >> 3); + + if (monitor.frame_angle != angle) { // 表示する向きを変える + monitor.frame_angle = angle; + sdl_invalidate(); + } else if (monitor.frame_rotation & ~3u) { + monitor.frame_rotation &= 3; + monitor.frame_angle = (monitor.frame_rotation) * 90; + sdl_invalidate(); + } + + if (_invalidated || (_display_counter != _texupdate_counter)) { + SDL_RendererInfo info; + if (0 == SDL_GetRendererInfo(monitor.renderer, &info)) { + // ステップ実行中はVSYNCを待機しない + if (((bool)(info.flags & SDL_RENDERER_PRESENTVSYNC)) == step_exec) { + SDL_RenderSetVSync(monitor.renderer, !step_exec); + } + } + { + int red = 0; + int green = 0; + int blue = 0; +#if defined(M5GFX_BACK_COLOR) + red = ((M5GFX_BACK_COLOR) >> 16) & 0xFF; + green = ((M5GFX_BACK_COLOR) >> 8) & 0xFF; + blue = ((M5GFX_BACK_COLOR)) & 0xFF; +#endif + SDL_SetRenderDrawColor(monitor.renderer, red, green, blue, 0xFF); + } + SDL_RenderClear(monitor.renderer); + if (_invalidated) { + _invalidated = false; + int mw, mh; + SDL_GetRendererOutputSize(monitor.renderer, &mw, &mh); + } + render_texture(monitor.texture, monitor.frame_inner_x, monitor.frame_inner_y, _cfg.panel_width, _cfg.panel_height, angle); + render_texture(monitor.texture_frameimage, 0, 0, monitor.frame_width, monitor.frame_height, angle); + SDL_RenderPresent(monitor.renderer); + _display_counter = _texupdate_counter; + if (_invalidated) { + _invalidated = false; + SDL_SetRenderDrawColor(monitor.renderer, 0, 0, 0, 0xFF); + SDL_RenderClear(monitor.renderer); + render_texture(monitor.texture, monitor.frame_inner_x, monitor.frame_inner_y, _cfg.panel_width, _cfg.panel_height, + angle); + render_texture(monitor.texture_frameimage, 0, 0, monitor.frame_width, monitor.frame_height, angle); + SDL_RenderPresent(monitor.renderer); + } + } +} + +void Panel_sdl::render_texture(SDL_Texture *texture, int tx, int ty, int tw, int th, float angle) +{ + SDL_Point pivot; + pivot.x = (monitor.frame_width / 2.0f - tx) * (float)monitor.scaling_x; + pivot.y = (monitor.frame_height / 2.0f - ty) * (float)monitor.scaling_y; + SDL_Rect dstrect; + dstrect.w = tw * monitor.scaling_x; + dstrect.h = th * monitor.scaling_y; + int mw, mh; + SDL_GetRendererOutputSize(monitor.renderer, &mw, &mh); + dstrect.x = mw / 2.0f - pivot.x; + dstrect.y = mh / 2.0f - pivot.y; + SDL_RenderCopyEx(monitor.renderer, texture, nullptr, &dstrect, angle, &pivot, SDL_RendererFlip::SDL_FLIP_NONE); +} + +bool Panel_sdl::initFrameBuffer(size_t width, size_t height) +{ + uint8_t **lineArray = (uint8_t **)heap_alloc_dma(height * sizeof(uint8_t *)); + if (nullptr == lineArray) { + return false; + } + + _texturebuf = (rgb888_t *)heap_alloc_dma(width * height * sizeof(rgb888_t)); + + /// 8byte alignment; + width = (width + 7) & ~7u; + + _lines_buffer = lineArray; + memset(lineArray, 0, height * sizeof(uint8_t *)); + + uint8_t *framebuffer = (uint8_t *)heap_alloc_dma(width * height + 16); + + auto fb = framebuffer; + { + for (size_t y = 0; y < height; ++y) { + lineArray[y] = fb; + fb += width; + } + } + return true; +} + +void Panel_sdl::deinitFrameBuffer(void) +{ + auto lines = _lines_buffer; + _lines_buffer = nullptr; + if (lines != nullptr) { + heap_free(lines[0]); + heap_free(lines); + } + if (_texturebuf) { + heap_free(_texturebuf); + _texturebuf = nullptr; + } +} + +//---------------------------------------------------------------------------- +} // namespace v1 +} // namespace lgfx + +#endif diff --git a/src/graphics/Panel_sdl.hpp b/src/graphics/Panel_sdl.hpp new file mode 100644 index 000000000..c80c27b73 --- /dev/null +++ b/src/graphics/Panel_sdl.hpp @@ -0,0 +1,165 @@ +/*----------------------------------------------------------------------------/ + Lovyan GFX - Graphics library for embedded devices. + +Original Source: + https://github.com/lovyan03/LovyanGFX/ + +Licence: + [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) + +Author: + [lovyan03](https://twitter.com/lovyan03) + +Contributors: + [ciniml](https://github.com/ciniml) + [mongonta0716](https://github.com/mongonta0716) + [tobozo](https://github.com/tobozo) + +Porting for SDL: + [imliubo](https://github.com/imliubo) +/----------------------------------------------------------------------------*/ +#pragma once + +#define SDL_MAIN_HANDLED +#if __has_include() +#include +#include +#elif __has_include() +#include +#include +#endif + +#if defined(SDL_h_) +#include "lgfx/v1/Touch.hpp" +#include "lgfx/v1/misc/range.hpp" +#include "lgfx/v1/panel/Panel_FrameBufferBase.hpp" +#include + +namespace lgfx +{ +inline namespace v1 +{ + +struct Panel_sdl; +struct monitor_t { + SDL_Window *window = nullptr; + SDL_Renderer *renderer = nullptr; + SDL_Texture *texture = nullptr; + SDL_Texture *texture_frameimage = nullptr; + Panel_sdl *panel = nullptr; + + // 外枠 + const void *frame_image = 0; + uint_fast16_t frame_width = 0; + uint_fast16_t frame_height = 0; + uint_fast16_t frame_inner_x = 0; + uint_fast16_t frame_inner_y = 0; + int_fast16_t frame_rotation = 0; + int_fast16_t frame_angle = 0; + + float scaling_x = 1; + float scaling_y = 1; + int_fast16_t touch_x, touch_y; + bool touched = false; + bool closing = false; +}; +//---------------------------------------------------------------------------- + +struct Touch_sdl : public ITouch { + bool init(void) override { return true; } + void wakeup(void) override {} + void sleep(void) override {} + bool isEnable(void) override { return true; }; + uint_fast8_t getTouchRaw(touch_point_t *tp, uint_fast8_t count) override { return 0; } +}; + +//---------------------------------------------------------------------------- + +struct Panel_sdl : public Panel_FrameBufferBase { + static constexpr size_t EMULATED_GPIO_MAX = 128; + static volatile uint8_t _gpio_dummy_values[EMULATED_GPIO_MAX]; + + public: + Panel_sdl(void); + virtual ~Panel_sdl(void); + + bool init(bool use_reset) override; + + color_depth_t setColorDepth(color_depth_t depth) override; + + void display(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h) override; + + // void setInvert(bool invert) override {} + void drawPixelPreclipped(uint_fast16_t x, uint_fast16_t y, uint32_t rawcolor) override; + void writeFillRectPreclipped(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, uint32_t rawcolor) override; + void writeBlock(uint32_t rawcolor, uint32_t length) override; + void writeImage(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t *param, + bool use_dma) override; + void writeImageARGB(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t *param) override; + void writePixels(pixelcopy_t *param, uint32_t len, bool use_dma) override; + + uint_fast8_t getTouchRaw(touch_point_t *tp, uint_fast8_t count) override; + + void setWindowTitle(const char *title); + void setScaling(uint_fast8_t scaling_x, uint_fast8_t scaling_y); + void setFrameImage(const void *frame_image, int frame_width, int frame_height, int inner_x, int inner_y); + void setFrameRotation(uint_fast16_t frame_rotaion); + void setBrightness(uint8_t brightness) override{}; + + static volatile void gpio_hi(uint32_t pin) { _gpio_dummy_values[pin & (EMULATED_GPIO_MAX - 1)] = 1; } + static volatile void gpio_lo(uint32_t pin) { _gpio_dummy_values[pin & (EMULATED_GPIO_MAX - 1)] = 0; } + static volatile bool gpio_in(uint32_t pin) { return _gpio_dummy_values[pin & (EMULATED_GPIO_MAX - 1)]; } + + static int setup(void); + static int loop(void); + static int close(void); + + static int main(int (*fn)(bool *), uint32_t msec_step_exec = 512); + + static void setShortcutKeymod(SDL_Keymod keymod) { _keymod = keymod; } + + struct KeyCodeMapping_t { + SDL_KeyCode keycode = SDLK_UNKNOWN; + uint8_t gpio = 0; + }; + static void addKeyCodeMapping(SDL_KeyCode keyCode, uint8_t gpio); + static int getKeyCodeMapping(SDL_KeyCode keyCode); + + protected: + const char *_window_title = "LGFX Simulator"; + SDL_mutex *_sdl_mutex = nullptr; + + void sdl_create(monitor_t *m); + void sdl_update(void); + + touch_point_t _touch_point; + monitor_t monitor; + + rgb888_t *_texturebuf = nullptr; + uint_fast16_t _modified_counter; + uint_fast16_t _texupdate_counter; + uint_fast16_t _display_counter; + bool _invalidated; + + static void _event_proc(void); + static void _update_proc(void); + static void _update_scaling(monitor_t *m, float sx, float sy); + void sdl_invalidate(void) { _invalidated = true; } + void render_texture(SDL_Texture *texture, int tx, int ty, int tw, int th, float angle); + bool initFrameBuffer(size_t width, size_t height); + void deinitFrameBuffer(void); + + static SDL_Keymod _keymod; + + struct lock_t { + lock_t(Panel_sdl *parent); + ~lock_t(); + + protected: + Panel_sdl *_parent; + }; +}; +//---------------------------------------------------------------------------- +} // namespace v1 +} // namespace lgfx +#endif \ No newline at end of file diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 3eeb17ef0..0663602d9 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -751,10 +751,8 @@ static LGFX *tft = nullptr; static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h #elif ARCH_PORTDUINO +#include "Panel_sdl.hpp" #include // Graphics and font library for ST7735 driver chip -#if defined(LGFX_SDL) -#include -#endif class LGFX : public lgfx::LGFX_Device { @@ -783,10 +781,10 @@ class LGFX : public lgfx::LGFX_Device _panel_instance = new lgfx::Panel_ILI9488; else if (portduino_config.displayPanel == hx8357d) _panel_instance = new lgfx::Panel_HX8357D; -#if defined(LGFX_SDL) - else if (portduino_config.displayPanel == x11) { +#if defined(SDL_h_) + + else if (portduino_config.displayPanel == x11) _panel_instance = new lgfx::Panel_sdl; - } #endif else { _panel_instance = new lgfx::Panel_NULL; @@ -799,8 +797,9 @@ class LGFX : public lgfx::LGFX_Device buscfg.pin_dc = portduino_config.displayDC.pin; // Set SPI DC pin number (-1 = disable) - _bus_instance.config(buscfg); // applies the set value to the bus. - _panel_instance->setBus(&_bus_instance); // set the bus on the panel. + _bus_instance.config(buscfg); // applies the set value to the bus. + if (portduino_config.displayPanel != x11) + _panel_instance->setBus(&_bus_instance); // set the bus on the panel. auto cfg = _panel_instance->config(); // Gets a structure for display panel settings. LOG_DEBUG("Width: %d, Height: %d", portduino_config.displayWidth, portduino_config.displayHeight); @@ -848,7 +847,7 @@ class LGFX : public lgfx::LGFX_Device _touch_instance->config(touch_cfg); _panel_instance->setTouch(_touch_instance); } -#if defined(LGFX_SDL) +#if defined(SDL_h_) if (portduino_config.displayPanel == x11) { lgfx::Panel_sdl *sdl_panel_ = (lgfx::Panel_sdl *)_panel_instance; sdl_panel_->setup(); @@ -1237,7 +1236,7 @@ void TFTDisplay::display(bool fromBlank) void TFTDisplay::sdlLoop() { -#if defined(LGFX_SDL) +#if defined(SDL_h_) static int lastPressed = 0; static int shuttingDown = false; if (portduino_config.displayPanel == x11) { @@ -1247,27 +1246,26 @@ void TFTDisplay::sdlLoop() InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_SHUTDOWN, .kbchar = 0, .touchX = 0, .touchY = 0}; inputBroker->injectInputEvent(&event); } - // debounce - if (lastPressed != 0 && !lgfx::v1::gpio_in(lastPressed)) + if (lastPressed != 0 && !sdl_panel_->gpio_in(lastPressed)) return; - if (!lgfx::v1::gpio_in(37)) { + if (!sdl_panel_->gpio_in(37)) { lastPressed = 37; InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_RIGHT, .kbchar = 0, .touchX = 0, .touchY = 0}; inputBroker->injectInputEvent(&event); - } else if (!lgfx::v1::gpio_in(36)) { + } else if (!sdl_panel_->gpio_in(36)) { lastPressed = 36; InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_UP, .kbchar = 0, .touchX = 0, .touchY = 0}; inputBroker->injectInputEvent(&event); - } else if (!lgfx::v1::gpio_in(38)) { + } else if (!sdl_panel_->gpio_in(38)) { lastPressed = 38; InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_DOWN, .kbchar = 0, .touchX = 0, .touchY = 0}; inputBroker->injectInputEvent(&event); - } else if (!lgfx::v1::gpio_in(39)) { + } else if (!sdl_panel_->gpio_in(39)) { lastPressed = 39; InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_LEFT, .kbchar = 0, .touchX = 0, .touchY = 0}; inputBroker->injectInputEvent(&event); - } else if (!lgfx::v1::gpio_in(SDL_SCANCODE_KP_ENTER)) { + } else if (!sdl_panel_->gpio_in(SDL_SCANCODE_KP_ENTER)) { lastPressed = SDL_SCANCODE_KP_ENTER; InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_SELECT, .kbchar = 0, .touchX = 0, .touchY = 0}; inputBroker->injectInputEvent(&event); diff --git a/src/main.cpp b/src/main.cpp index b0f086f14..029b8d708 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1604,8 +1604,9 @@ void loop() if (inputBroker) inputBroker->processInputEventQueue(); #endif -#if defined(LGFX_SDL) - if (screen) { +#if ARCH_PORTDUINO && HAS_TFT + if (screen && portduino_config.displayPanel == x11 && + config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { auto dispdev = screen->getDisplayDevice(); if (dispdev) static_cast(dispdev)->sdlLoop(); diff --git a/variants/native/portduino/platformio.ini b/variants/native/portduino/platformio.ini index c47ab8bf1..61eadb459 100644 --- a/variants/native/portduino/platformio.ini +++ b/variants/native/portduino/platformio.ini @@ -40,28 +40,10 @@ build_flags = ${native_base.build_flags} -Os -lX11 -linput -lxkbcommon -ffunctio -D VIEW_320x240 !pkg-config --libs libulfius --silence-errors || : !pkg-config --libs openssl --silence-errors || : + !pkg-config --cflags --libs sdl2 --silence-errors || : build_src_filter = ${native_base.build_src_filter} -[env:native-sdl] -extends = native_base -build_type = release -lib_deps = - ${env.lib_deps} - ${networking_base.lib_deps} - ${radiolib_base.lib_deps} - ${environmental_base.lib_deps} - # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto - rweather/Crypto@0.4.0 - # renovate: datasource=git-refs depName=libch341-spi-userspace packageName=https://github.com/pine64/libch341-spi-userspace gitBranch=main - https://github.com/pine64/libch341-spi-userspace/archive/af9bc27c9c30fa90772279925b7c5913dff789b4.zip - # renovate: datasource=custom.pio depName=adafruit/Adafruit seesaw Library packageName=adafruit/library/Adafruit seesaw Library - adafruit/Adafruit seesaw Library@1.7.9 - https://github.com/jp-bennett/LovyanGFX/archive/7458f84a126c1f8fdc7b038074f71be903f6e4c0.zip -build_flags = ${native_base.build_flags} - !pkg-config --cflags --libs sdl2 --silence-errors || : - -D LGFX_SDL=1 - [env:native-fb] extends = native_base build_type = release From cbd30f95f351c2f94a35a855ed42461e583e9cb6 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 8 Sep 2025 20:08:16 -0500 Subject: [PATCH 093/166] Portduino: Only short-circuit hardware support when forcing sim mode --- 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 b11d2547b..dbc90f9a4 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -202,7 +202,7 @@ void portduinoSetup() exit(EXIT_SUCCESS); } - if (portduino_config.lora_module == use_simradio) { + if (portduino_config.force_simradio) { std::cout << "Running in simulated mode." << std::endl; portduino_config.MaxNodes = 200; // Default to 200 nodes // Set the random seed equal to TCPPort to have a different seed per instance From 6022b749bab67f23cbf75482fd0cf64ec41010d0 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 8 Sep 2025 20:08:31 -0500 Subject: [PATCH 094/166] Don't forget to break! --- src/platform/portduino/PortduinoGlue.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index ec6209487..3fe017d5e 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -444,12 +444,16 @@ extern struct portduino_config_struct { switch (configDisplayMode) { case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR: out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR"; + break; case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED: out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED"; + break; case meshtastic_Config_DisplayConfig_DisplayMode_COLOR: out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR"; + break; case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT: out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT"; + break; } out << YAML::EndMap; // Config From 7c4367cddc1e68945131ffe2e2a7c6acea2a7bb1 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 8 Sep 2025 20:32:07 -0500 Subject: [PATCH 095/166] Cppckeck suppress bogus error --- src/graphics/Panel_sdl.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/graphics/Panel_sdl.hpp b/src/graphics/Panel_sdl.hpp index c80c27b73..802c6c5dc 100644 --- a/src/graphics/Panel_sdl.hpp +++ b/src/graphics/Panel_sdl.hpp @@ -21,6 +21,7 @@ Porting for SDL: #pragma once #define SDL_MAIN_HANDLED +// cppcheck-suppress preprocessorErrorDirective #if __has_include() #include #include From de6a02756dacf6bf6a879beffafb1de9dce6f3ef Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 5 Oct 2025 14:03:55 +0200 Subject: [PATCH 096/166] De-duplicate handling upgraded packet and rebroadcasting logic --- src/mesh/FloodingRouter.cpp | 98 ++++++++++++++----------------------- src/mesh/FloodingRouter.h | 15 ++++-- src/mesh/NextHopRouter.cpp | 91 ++++++++++++++++------------------ src/mesh/NextHopRouter.h | 6 +-- src/mesh/PacketHistory.cpp | 1 - 5 files changed, 92 insertions(+), 119 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 1d8ac247f..1225263a2 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -31,33 +31,8 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) wasSeenRecently(p, true, nullptr, nullptr, &wasUpgraded); // Updates history; returns false when an upgrade is detected // Handle hop_limit upgrade scenario for rebroadcasters - // isRebroadcaster() is duplicated in perhapsRebroadcast(), but this avoids confusing log messages - if (wasUpgraded && isRebroadcaster() && iface && p->hop_limit > 0) { - // wasSeenRecently() reports false in upgrade cases so we handle replacement before the duplicate short-circuit - // If we overhear a duplicate copy of the packet with more hops left than the one we are waiting to - // rebroadcast, then remove the packet currently sitting in the TX queue and use this one instead. - uint8_t dropThreshold = p->hop_limit; // remove queued packets that have fewer hops remaining - if (iface->removePendingTXPacket(getFrom(p), p->id, dropThreshold)) { - LOG_DEBUG("Processing upgraded packet 0x%08x for rebroadcast with hop limit %d (dropping queued < %d)", p->id, - p->hop_limit, dropThreshold); - - if (nodeDB) - nodeDB->updateFrom(*p); -#if !MESHTASTIC_EXCLUDE_TRACEROUTE - if (traceRouteModule && p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && - p->decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP) - traceRouteModule->processUpgradedPacket(*p); -#endif - - perhapsRebroadcast(p); - - // We already enqueued the improved copy, so make sure the incoming packet stops here. - return true; - } - - // No queue entry was replaced by this upgraded copy, so treat it as a duplicate to avoid - // delivering the same packet to applications/phone twice with different hop limits. - seenRecently = true; + if (wasUpgraded && perhapsHandleUpgradedPacket(p)) { + return true; // we handled it, so stop processing } if (seenRecently) { @@ -82,6 +57,40 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) return Router::shouldFilterReceived(p); } +bool FloodingRouter::perhapsHandleUpgradedPacket(const meshtastic_MeshPacket *p) +{ + // isRebroadcaster() is duplicated in perhapsRebroadcast(), but this avoids confusing log messages + if (isRebroadcaster() && iface && p->hop_limit > 0) { + // If we overhear a duplicate copy of the packet with more hops left than the one we are waiting to + // rebroadcast, then remove the packet currently sitting in the TX queue and use this one instead. + uint8_t dropThreshold = p->hop_limit; // remove queued packets that have fewer hops remaining + if (iface->removePendingTXPacket(getFrom(p), p->id, dropThreshold)) { + LOG_DEBUG("Processing upgraded packet 0x%08x for rebroadcast with hop limit %d (dropping queued < %d)", p->id, + p->hop_limit, dropThreshold); + + reprocessPacket(p); + perhapsRebroadcast(p); + + rxDupe++; + // We already enqueued the improved copy, so make sure the incoming packet stops here. + return true; + } + } + + return false; +} + +void FloodingRouter::reprocessPacket(const meshtastic_MeshPacket *p) +{ + if (nodeDB) + nodeDB->updateFrom(*p); +#if !MESHTASTIC_EXCLUDE_TRACEROUTE + if (traceRouteModule && p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && + p->decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP) + traceRouteModule->processUpgradedPacket(*p); +#endif +} + bool FloodingRouter::roleAllowsCancelingDupe(const meshtastic_MeshPacket *p) { if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || @@ -121,41 +130,6 @@ bool FloodingRouter::isRebroadcaster() config.device.rebroadcast_mode != meshtastic_Config_DeviceConfig_RebroadcastMode_NONE; } -void FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) -{ - if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) { - if (p->id != 0) { - if (isRebroadcaster()) { - meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it - - // Use shared logic to determine if hop_limit should be decremented - if (shouldDecrementHopLimit(p)) { - tosend->hop_limit--; // bump down the hop count - } else { - LOG_INFO("favorite-ROUTER/CLIENT_BASE-to-ROUTER/CLIENT_BASE flood: preserving hop_limit"); - } -#if USERPREFS_EVENT_MODE - if (tosend->hop_limit > 2) { - // if we are "correcting" the hop_limit, "correct" the hop_start by the same amount to preserve hops away. - tosend->hop_start -= (tosend->hop_limit - 2); - tosend->hop_limit = 2; - } -#endif - - tosend->next_hop = NO_NEXT_HOP_PREFERENCE; // this should already be the case, but just in case - - LOG_INFO("Rebroadcast received floodmsg"); - // Note: we are careful to resend using the original senders node id - send(tosend); - } else { - LOG_DEBUG("No rebroadcast: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); - } - } else { - LOG_DEBUG("Ignore 0 id broadcast"); - } - } -} - void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index eaf71d294..e8a2e9685 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -27,10 +27,6 @@ */ class FloodingRouter : public Router { - private: - /* Check if we should rebroadcast this packet, and do so if needed */ - void perhapsRebroadcast(const meshtastic_MeshPacket *p); - public: /** * Constructor @@ -59,6 +55,17 @@ class FloodingRouter : public Router */ virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; + /* Check if we should rebroadcast this packet, and do so if needed */ + virtual bool perhapsRebroadcast(const meshtastic_MeshPacket *p) = 0; + + /* Check if we should handle an upgraded packet (with higher hop_limit) + * @return true if we handled it (so stop processing) + */ + bool perhapsHandleUpgradedPacket(const meshtastic_MeshPacket *p); + + /* Call when we receive a packet that needs some reprocessing, but afterwards should be filtered */ + void reprocessPacket(const meshtastic_MeshPacket *p); + // Return false for roles like ROUTER which should always rebroadcast even when we've heard another rebroadcast of // the same packet bool roleAllowsCancelingDupe(const meshtastic_MeshPacket *p); diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 0461d7eb6..7340c0e87 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -43,31 +43,8 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) &wasUpgraded); // Updates history; returns false when an upgrade is detected // Handle hop_limit upgrade scenario for rebroadcasters - // isRebroadcaster() is duplicated in perhapsRelay(), but this avoids confusing log messages - if (wasUpgraded && isRebroadcaster() && iface && p->hop_limit > 0) { - // Upgrade detection bypasses the duplicate short-circuit so we replace the queued packet before exiting - uint8_t dropThreshold = p->hop_limit; // remove queued packets that have fewer hops remaining - if (iface->removePendingTXPacket(getFrom(p), p->id, dropThreshold)) { - LOG_DEBUG("Processing upgraded packet 0x%08x for relay with hop limit %d (dropping queued < %d)", p->id, p->hop_limit, - dropThreshold); - - if (nodeDB) - nodeDB->updateFrom(*p); -#if !MESHTASTIC_EXCLUDE_TRACEROUTE - if (traceRouteModule && p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && - p->decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP) - traceRouteModule->processUpgradedPacket(*p); -#endif - - perhapsRelay(p); - - // We already enqueued the improved copy, so make sure the incoming packet stops here. - return true; - } - - // No queue entry was replaced by this upgraded copy, so treat it as a duplicate to avoid - // delivering the same packet to applications/phone twice with different hop limits. - seenRecently = true; + if (wasUpgraded && perhapsHandleUpgradedPacket(p)) { + return true; // we handled it, so stop processing } if (seenRecently) { @@ -107,13 +84,14 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0 || p->decoded.reply_id != 0); if (isAckorReply) { - // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" is - // not 0 (means implicit ACK) and original packet was also relayed by this node, or we sent it directly to the destination + // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" + // is not 0 (means implicit ACK) and original packet was also relayed by this node, or we sent it directly to the + // destination if (p->from != 0) { meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from); if (origTx) { - // Either relayer of ACK was also a relayer of the packet, or we were the *only* relayer and the ACK came directly - // from the destination + // Either relayer of ACK was also a relayer of the packet, or we were the *only* relayer and the ACK came + // directly from the destination bool wasAlreadyRelayer = wasRelayer(p->relay_node, p->decoded.request_id, p->to); bool weWereSoleRelayer = false; bool weWereRelayer = wasRelayer(ourRelayID, p->decoded.request_id, p->to, &weWereSoleRelayer); @@ -134,34 +112,49 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast } } - perhapsRelay(p); + perhapsRebroadcast(p); // handle the packet as normal Router::sniffReceived(p, c); } -/* Check if we should be relaying this packet if so, do so. */ -bool NextHopRouter::perhapsRelay(const meshtastic_MeshPacket *p) +/* Check if we should be rebroadcasting this packet if so, do so. */ +bool NextHopRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) { if (!isToUs(p) && !isFromUs(p) && p->hop_limit > 0) { - if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum())) { + if (p->id != 0) { if (isRebroadcaster()) { - meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it - LOG_INFO("Relaying received message coming from %x", p->relay_node); + if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum())) { + meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it + LOG_INFO("Rebroadcast received message coming from %x", p->relay_node); - // Use shared logic to determine if hop_limit should be decremented - if (shouldDecrementHopLimit(p)) { - tosend->hop_limit--; // bump down the hop count - } else { - LOG_INFO("Router/CLIENT_BASE-to-favorite-router/CLIENT_BASE relay: preserving hop_limit"); + // Use shared logic to determine if hop_limit should be decremented + if (shouldDecrementHopLimit(p)) { + tosend->hop_limit--; // bump down the hop count + } else { + LOG_INFO("favorite-ROUTER/CLIENT_BASE-to-ROUTER/CLIENT_BASE flood: preserving hop_limit"); + } +#if USERPREFS_EVENT_MODE + if (tosend->hop_limit > 2) { + // if we are "correcting" the hop_limit, "correct" the hop_start by the same amount to preserve hops away. + tosend->hop_start -= (tosend->hop_limit - 2); + tosend->hop_limit = 2; + } +#endif + + if (p->next_hop == NO_NEXT_HOP_PREFERENCE) { + FloodingRouter::send(tosend); + } else { + NextHopRouter::send(tosend); + } + + return true; } - - NextHopRouter::send(tosend); - - return true; } else { - LOG_DEBUG("Not rebroadcasting: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); + LOG_DEBUG("No rebroadcast: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); } + } else { + LOG_DEBUG("Ignore 0 id broadcast"); } } @@ -231,13 +224,13 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key) } } - // Regardless of whether or not we canceled this packet from the txQueue, remove it from our pending list so it doesn't - // get scheduled again. (This is the core of stopRetransmission.) + // Regardless of whether or not we canceled this packet from the txQueue, remove it from our pending list so it + // doesn't get scheduled again. (This is the core of stopRetransmission.) auto numErased = pending.erase(key); assert(numErased == 1); - // When we remove an entry from pending, always be sure to release the copy of the packet that was allocated in the call - // to startRetransmission. + // When we remove an entry from pending, always be sure to release the copy of the packet that was allocated in the + // call to startRetransmission. packetPool.release(p); return true; diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h index 0022644e9..c1df3596b 100644 --- a/src/mesh/NextHopRouter.h +++ b/src/mesh/NextHopRouter.h @@ -148,7 +148,7 @@ class NextHopRouter : public FloodingRouter */ uint8_t getNextHop(NodeNum to, uint8_t relay_node); - /** Check if we should be relaying this packet if so, do so. - * @return true if we did relay */ - bool perhapsRelay(const meshtastic_MeshPacket *p); + /** Check if we should be rebroadcasting this packet if so, do so. + * @return true if we did rebroadcast */ + bool perhapsRebroadcast(const meshtastic_MeshPacket *p) override; }; \ No newline at end of file diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 49d581d9a..b4af707ae 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -94,7 +94,6 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd LOG_DEBUG("Packet History - Hop limit upgrade: packet 0x%08x from hop_limit=%d to hop_limit=%d", p->id, found->hop_limit, p->hop_limit); *wasUpgraded = true; - seenRecently = false; // Allow router processing but prevent duplicate app delivery } else if (wasUpgraded) { *wasUpgraded = false; // Initialize to false if not an upgrade } From 7c373b76c40cf74dd69cf9c3cd07f1729cc0702d Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 5 Oct 2025 14:04:35 +0200 Subject: [PATCH 097/166] Reprocess repeated packets also --- src/mesh/FloodingRouter.cpp | 4 +++- src/mesh/NextHopRouter.cpp | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 1225263a2..032be241b 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -45,8 +45,10 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) if (isRepeated) { LOG_DEBUG("Repeated reliable tx"); // Check if it's still in the Tx queue, if not, we have to relay it again - if (!findInTxQueue(p->from, p->id)) + if (!findInTxQueue(p->from, p->id)) { + reprocessPacket(p); perhapsRebroadcast(p); + } } else { perhapsCancelDupe(p); } diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 7340c0e87..1ab4b43ed 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -59,14 +59,20 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) if (wasFallback) { LOG_INFO("Fallback to flooding from relay_node=0x%x", p->relay_node); // Check if it's still in the Tx queue, if not, we have to relay it again - if (!findInTxQueue(p->from, p->id)) - perhapsRelay(p); + if (!findInTxQueue(p->from, p->id)) { + reprocessPacket(p); + perhapsRebroadcast(p); + } } else { bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit; // If repeated and not in Tx queue anymore, try relaying again, or if we are the destination, send the ACK again if (isRepeated) { - if (!findInTxQueue(p->from, p->id) && !perhapsRelay(p) && isToUs(p) && p->want_ack) - sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); + if (!findInTxQueue(p->from, p->id)) { + reprocessPacket(p); + if (!perhapsRebroadcast(p) && isToUs(p) && p->want_ack) { + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); + } + } } else if (!weWereNextHop) { perhapsCancelDupe(p); // If it's a dupe, cancel relay if we were not explicitly asked to relay } From f7cf5e6b0ad11fc17eed25f20cb99517ebaf6b06 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 5 Oct 2025 15:56:45 +0200 Subject: [PATCH 098/166] Change to "rebroadcast" --- src/mesh/NextHopRouter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 1ab4b43ed..afdb4d096 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -138,7 +138,7 @@ bool NextHopRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) if (shouldDecrementHopLimit(p)) { tosend->hop_limit--; // bump down the hop count } else { - LOG_INFO("favorite-ROUTER/CLIENT_BASE-to-ROUTER/CLIENT_BASE flood: preserving hop_limit"); + LOG_INFO("favorite-ROUTER/CLIENT_BASE-to-ROUTER/CLIENT_BASE rebroadcast: preserving hop_limit"); } #if USERPREFS_EVENT_MODE if (tosend->hop_limit > 2) { From c147ce9a85396a38527a250d586ae2d380786a10 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 5 Oct 2025 16:58:42 +0200 Subject: [PATCH 099/166] Update next-hops based on traceroute result --- src/modules/TraceRouteModule.cpp | 64 ++++++++++++++++++++++++++++++++ src/modules/TraceRouteModule.h | 6 +++ 2 files changed, 70 insertions(+) diff --git a/src/modules/TraceRouteModule.cpp b/src/modules/TraceRouteModule.cpp index fc2cc232b..c2c5669c9 100644 --- a/src/modules/TraceRouteModule.cpp +++ b/src/modules/TraceRouteModule.cpp @@ -21,6 +21,11 @@ void TraceRouteModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtasti { const meshtastic_Data &incoming = p.decoded; + // Update next-hops using returned route + if (incoming.request_id) { + updateNextHops(p, r); + } + // Insert unknown hops if necessary insertUnknownHops(p, r, !incoming.request_id); @@ -153,6 +158,65 @@ void TraceRouteModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtasti } } +void TraceRouteModule::updateNextHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r) +{ + // E.g. if the route is A->B->C->D and we are B, we can set C as next-hop for C and D + // Similarly, if we are C, we can set D as next-hop for D + // If we are A, we can set B as next-hop for B, C and D + + // First check if we were the original sender or in the original route + int8_t nextHopIndex = -1; + if (isToUs(&p)) { + nextHopIndex = 0; // We are the original sender, next hop is first in route + } else { + // Check if we are in the original route + for (uint8_t i = 0; i < r->route_count; i++) { + if (r->route[i] == nodeDB->getNodeNum()) { + nextHopIndex = i + 1; // Next hop is the one after us + break; + } + } + } + + // If we are in the original route, update the next hops + if (nextHopIndex != -1) { + // For every node after us, we can set the next-hop to the first node after us + NodeNum nextHop; + if (nextHopIndex == r->route_count) { + nextHop = p.from; // We are the last in the route, next hop is destination + } else { + nextHop = r->route[nextHopIndex]; + } + + if (nextHop == NODENUM_BROADCAST) { + return; + } + uint8_t nextHopByte = nodeDB->getLastByteOfNodeNum(nextHop); + + // For the rest of the nodes in the route, set their next-hop + // Note: if we are the last in the route, this loop will not run + for (int8_t i = nextHopIndex; i < r->route_count; i++) { + NodeNum targetNode = r->route[i]; + maybeSetNextHop(targetNode, nextHopByte); + } + + // Also set next-hop for the destination node + maybeSetNextHop(p.from, nextHopByte); + } +} + +void TraceRouteModule::maybeSetNextHop(NodeNum target, uint8_t nextHopByte) +{ + if (target == NODENUM_BROADCAST) + return; + + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(target); + if (node && node->next_hop != nextHopByte) { + LOG_INFO("Updating next-hop for 0x%08x to 0x%08x based on traceroute", target, nextHopByte); + node->next_hop = nextHopByte; + } +} + void TraceRouteModule::processUpgradedPacket(const meshtastic_MeshPacket &mp) { if (mp.which_payload_variant != meshtastic_MeshPacket_decoded_tag || mp.decoded.portnum != meshtastic_PortNum_TRACEROUTE_APP) diff --git a/src/modules/TraceRouteModule.h b/src/modules/TraceRouteModule.h index a069f7157..dac422388 100644 --- a/src/modules/TraceRouteModule.h +++ b/src/modules/TraceRouteModule.h @@ -55,6 +55,12 @@ class TraceRouteModule : public ProtobufModule, // Call to add your ID to the route array of a RouteDiscovery message void appendMyIDandSNR(meshtastic_RouteDiscovery *r, float snr, bool isTowardsDestination, bool SNRonly); + // Update next-hops in the routing table based on the returned route + void updateNextHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r); + + // Helper to update next-hop for a single node + void maybeSetNextHop(NodeNum target, uint8_t nextHopByte); + /* Call to print the route array of a RouteDiscovery message. Set origin to where the request came from. Set dest to the ID of its destination, or NODENUM_BROADCAST if it has not yet arrived there. */ From 5c2997ef535c8abeb5ac58c42abbdaed7ea2d6fc Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 5 Oct 2025 17:03:52 +0200 Subject: [PATCH 100/166] Print only one byte --- src/modules/TraceRouteModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/TraceRouteModule.cpp b/src/modules/TraceRouteModule.cpp index c2c5669c9..5bdde1919 100644 --- a/src/modules/TraceRouteModule.cpp +++ b/src/modules/TraceRouteModule.cpp @@ -212,7 +212,7 @@ void TraceRouteModule::maybeSetNextHop(NodeNum target, uint8_t nextHopByte) meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(target); if (node && node->next_hop != nextHopByte) { - LOG_INFO("Updating next-hop for 0x%08x to 0x%08x based on traceroute", target, nextHopByte); + LOG_INFO("Updating next-hop for 0x%08x to 0x%02x based on traceroute", target, nextHopByte); node->next_hop = nextHopByte; } } From 036a58735e582a1622e42786777a8a0726378824 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 05:50:16 -0500 Subject: [PATCH 101/166] Upgrade trunk (#8229) Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com> --- .trunk/trunk.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 74b850b64..8c981850d 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -16,7 +16,7 @@ lint: - bandit@1.8.6 - trivy@0.67.0 - taplo@0.10.0 - - ruff@0.13.2 + - ruff@0.13.3 - isort@6.1.0 - markdownlint@0.45.0 - oxipng@9.1.5 From 29f4d99bf64e503f3cf9cb9dcc33d037ea15cf86 Mon Sep 17 00:00:00 2001 From: Dmitry Dubinin <4762973+capricornusx@users.noreply.github.com> Date: Mon, 6 Oct 2025 13:52:40 +0300 Subject: [PATCH 102/166] Add Adaptive Polling Intervals to WebServer (#7864) * feat: add adaptive polling intervals to WebServer Replace fixed 5ms polling with adaptive intervals based on HTTP activity: - 50ms during active periods (first 5 seconds after request) - 200ms during medium activity (5-30 seconds) - 1000ms during idle periods (30+ seconds) Reduces CPU usage significantly during idle periods while maintaining responsiveness when handling HTTP requests. * Fix integer overflow and magic numbers in WebServer - Handle millis() overflow in getAdaptiveInterval() - Replace magic numbers with named constants - Improve code readability and maintainability --- src/mesh/http/ContentHandler.cpp | 5 +++++ src/mesh/http/WebServer.cpp | 35 ++++++++++++++++++++++++++++++-- src/mesh/http/WebServer.h | 4 ++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index f87c6e3b0..7b7ebb595 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -148,6 +148,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) { + if (webServerThread) + webServerThread->markActivity(); LOG_DEBUG("webAPI handleAPIv1FromRadio"); @@ -391,6 +393,9 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res) void handleStatic(HTTPRequest *req, HTTPResponse *res) { + if (webServerThread) + webServerThread->markActivity(); + // Get access to the parameters ResourceParameters *params = req->getParams(); diff --git a/src/mesh/http/WebServer.cpp b/src/mesh/http/WebServer.cpp index bf170de59..3a264fa5a 100644 --- a/src/mesh/http/WebServer.cpp +++ b/src/mesh/http/WebServer.cpp @@ -49,6 +49,12 @@ Preferences prefs; using namespace httpsserver; #include "mesh/http/ContentHandler.h" +static const uint32_t ACTIVE_THRESHOLD_MS = 5000; +static const uint32_t MEDIUM_THRESHOLD_MS = 30000; +static const int32_t ACTIVE_INTERVAL_MS = 50; +static const int32_t MEDIUM_INTERVAL_MS = 200; +static const int32_t IDLE_INTERVAL_MS = 1000; + static SSLCert *cert; static HTTPSServer *secureServer; static HTTPServer *insecureServer; @@ -175,6 +181,32 @@ WebServerThread::WebServerThread() : concurrency::OSThread("WebServer") if (!config.network.wifi_enabled && !config.network.eth_enabled) { disable(); } + lastActivityTime = millis(); +} + +void WebServerThread::markActivity() +{ + lastActivityTime = millis(); +} + +int32_t WebServerThread::getAdaptiveInterval() +{ + uint32_t currentTime = millis(); + uint32_t timeSinceActivity; + + if (currentTime >= lastActivityTime) { + timeSinceActivity = currentTime - lastActivityTime; + } else { + timeSinceActivity = (UINT32_MAX - lastActivityTime) + currentTime + 1; + } + + if (timeSinceActivity < ACTIVE_THRESHOLD_MS) { + return ACTIVE_INTERVAL_MS; + } else if (timeSinceActivity < MEDIUM_THRESHOLD_MS) { + return MEDIUM_INTERVAL_MS; + } else { + return IDLE_INTERVAL_MS; + } } int32_t WebServerThread::runOnce() @@ -189,8 +221,7 @@ int32_t WebServerThread::runOnce() ESP.restart(); } - // Loop every 5ms. - return (5); + return getAdaptiveInterval(); } void initWebServer() diff --git a/src/mesh/http/WebServer.h b/src/mesh/http/WebServer.h index 815d87432..e7a29a5a7 100644 --- a/src/mesh/http/WebServer.h +++ b/src/mesh/http/WebServer.h @@ -10,13 +10,17 @@ void createSSLCert(); class WebServerThread : private concurrency::OSThread { + private: + uint32_t lastActivityTime = 0; public: WebServerThread(); uint32_t requestRestart = 0; + void markActivity(); protected: virtual int32_t runOnce() override; + int32_t getAdaptiveInterval(); }; extern WebServerThread *webServerThread; From 627c0145e7df9f52109a822a73c35f08a2951a43 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 6 Oct 2025 07:56:27 -0500 Subject: [PATCH 103/166] Centralize getNodeId and fix references to owner.id (#8230) --- src/mesh/NodeDB.cpp | 7 ++++ src/mesh/NodeDB.h | 4 ++ src/mesh/PhoneAPI.cpp | 2 + src/mesh/wifi/WiFiAPClient.cpp | 4 +- src/mqtt/MQTT.cpp | 38 ++++++++++++++----- src/serialization/MeshPacketSerializer.cpp | 2 +- .../MeshPacketSerializer_nRF52.cpp | 2 +- test/test_mqtt/MQTT.cpp | 4 +- 8 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index e3240462d..dec8411fe 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1874,6 +1874,13 @@ uint8_t NodeDB::getMeshNodeChannel(NodeNum n) return info->channel; } +std::string NodeDB::getNodeId() const +{ + char nodeId[16]; + snprintf(nodeId, sizeof(nodeId), "!%08x", myNodeInfo.my_node_num); + return std::string(nodeId); +} + /// Find a node in our DB, return null for missing /// NOTE: This function might be called from an ISR meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n) diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index f73f64f92..e8724f2c9 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "MeshTypes.h" @@ -203,6 +204,9 @@ class NodeDB /// @return our node number NodeNum getNodeNum() { return myNodeInfo.my_node_num; } + /// @return our node ID as a string in the format "!xxxxxxxx" + std::string getNodeId() const; + // @return last byte of a NodeNum, 0xFF if it ended at 0x00 uint8_t getLastByteOfNodeNum(NodeNum num) { return (uint8_t)((num & 0xFF) ? (num & 0xFF) : 0xFF); } diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 07f314415..210e0ba06 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -433,6 +433,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) case STATE_SEND_OTHER_NODEINFOS: { LOG_DEBUG("Send known nodes"); if (nodeInfoForPhone.num != 0) { + // Just in case we stored a different user.id in the past, but should never happen going forward + sprintf(nodeInfoForPhone.user.id, "!%08x", nodeInfoForPhone.num); LOG_INFO("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s", nodeInfoForPhone.num, nodeInfoForPhone.last_heard, nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name); fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag; diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index 1133ad424..7d210dd33 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -94,11 +94,11 @@ static void onNetworkConnected() // ESPmDNS (ESP32) and SimpleMDNS (RP2040) have slightly different APIs for adding TXT records #ifdef ARCH_ESP32 MDNS.addServiceTxt("meshtastic", "tcp", "shortname", String(owner.short_name)); - MDNS.addServiceTxt("meshtastic", "tcp", "id", String(owner.id)); + MDNS.addServiceTxt("meshtastic", "tcp", "id", String(nodeDB->getNodeId().c_str())); // ESP32 prints obtained IP address in WiFiEvent #elif defined(ARCH_RP2040) MDNS.addServiceTxt("meshtastic", "shortname", owner.short_name); - MDNS.addServiceTxt("meshtastic", "id", owner.id); + MDNS.addServiceTxt("meshtastic", "id", nodeDB->getNodeId().c_str()); LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str()); #endif } diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 7f7a9d511..8ce352f14 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -60,7 +60,9 @@ inline void onReceiveProto(char *topic, byte *payload, size_t length) return; } const meshtastic_Channel &ch = channels.getByName(e.channel_id); - if (strcmp(e.gateway_id, owner.id) == 0) { + // Generate node ID from nodenum for comparison + std::string nodeId = nodeDB->getNodeId(); + if (strcmp(e.gateway_id, nodeId.c_str()) == 0) { // Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message. // We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node // receives it when we get our own packet back. Then we'll stop our retransmissions. @@ -128,8 +130,10 @@ inline void onReceiveProto(char *topic, byte *payload, size_t length) // returns true if this is a valid JSON envelope which we accept on downlink inline bool isValidJsonEnvelope(JSONObject &json) { + // Generate node ID from nodenum for comparison + std::string nodeId = nodeDB->getNodeId(); // if "sender" is provided, avoid processing packets we uplinked - return (json.find("sender") != json.end() ? (json["sender"]->AsString().compare(owner.id) != 0) : true) && + return (json.find("sender") != json.end() ? (json["sender"]->AsString().compare(nodeId) != 0) : true) && (json.find("hopLimit") != json.end() ? json["hopLimit"]->IsNumber() : true) && // hop limit should be a number (json.find("from") != json.end()) && json["from"]->IsNumber() && (json["from"]->AsNumber() == nodeDB->getNodeNum()) && // only accept message if the "from" is us @@ -297,7 +301,9 @@ bool connectPubSub(const PubSubConfig &config, PubSubClient &pubSub, Client &cli LOG_INFO("Connecting directly to MQTT server %s, port: %d, username: %s, password: %s", config.serverAddr.c_str(), config.serverPort, config.mqttUsername, config.mqttPassword); - const bool connected = pubSub.connect(owner.id, config.mqttUsername, config.mqttPassword); + // Generate node ID from nodenum for client identification + std::string nodeId = nodeDB->getNodeId(); + const bool connected = pubSub.connect(nodeId.c_str(), config.mqttUsername, config.mqttPassword); if (connected) { LOG_INFO("MQTT connected"); } else { @@ -687,11 +693,14 @@ void MQTT::publishQueuedMessages() if (jsonString.length() == 0) return; + // Generate node ID from nodenum for topic + std::string nodeId = nodeDB->getNodeId(); + std::string topicJson; if (env.packet->pki_encrypted) { - topicJson = jsonTopic + "PKI/" + owner.id; + topicJson = jsonTopic + "PKI/" + nodeId; } else { - topicJson = jsonTopic + env.channel_id + "/" + owner.id; + topicJson = jsonTopic + env.channel_id + "/" + nodeId; } LOG_INFO("JSON publish message to %s, %u bytes: %s", topicJson.c_str(), jsonString.length(), jsonString.c_str()); publish(topicJson.c_str(), jsonString.c_str(), false); @@ -749,10 +758,14 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_Me return; // Don't upload a still-encrypted PKI packet if not encryption_enabled } - const meshtastic_ServiceEnvelope env = { - .packet = const_cast(p), .channel_id = const_cast(channelId), .gateway_id = owner.id}; + // Generate node ID from nodenum for service envelope + std::string nodeId = nodeDB->getNodeId(); + + const meshtastic_ServiceEnvelope env = {.packet = const_cast(p), + .channel_id = const_cast(channelId), + .gateway_id = const_cast(nodeId.c_str())}; size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, &env); - std::string topic = cryptTopic + channelId + "/" + owner.id; + std::string topic = cryptTopic + channelId + "/" + nodeId; if (moduleConfig.mqtt.proxy_to_client_enabled || this->isConnectedDirectly()) { LOG_DEBUG("MQTT Publish %s, %u bytes", topic.c_str(), numBytes); @@ -766,7 +779,9 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_Me auto jsonString = MeshPacketSerializer::JsonSerialize(&mp_decoded); if (jsonString.length() == 0) return; - std::string topicJson = jsonTopic + channelId + "/" + owner.id; + // Generate node ID from nodenum for JSON topic + std::string nodeIdForJson = nodeDB->getNodeId(); + std::string topicJson = jsonTopic + channelId + "/" + nodeIdForJson; LOG_INFO("JSON publish message to %s, %u bytes: %s", topicJson.c_str(), jsonString.length(), jsonString.c_str()); publish(topicJson.c_str(), jsonString.c_str(), false); #endif // ARCH_NRF52 NRF52_USE_JSON @@ -845,11 +860,14 @@ void MQTT::perhapsReportToMap() mp->decoded.payload.size = pb_encode_to_bytes(mp->decoded.payload.bytes, sizeof(mp->decoded.payload.bytes), &meshtastic_MapReport_msg, &mapReport); + // Generate node ID from nodenum for service envelope + std::string nodeId = nodeDB->getNodeId(); + // Encode the MeshPacket into a binary ServiceEnvelope and publish const meshtastic_ServiceEnvelope se = { .packet = mp, .channel_id = (char *)channels.getGlobalId(channels.getPrimaryIndex()), // Use primary channel as the channel_id - .gateway_id = owner.id}; + .gateway_id = const_cast(nodeId.c_str())}; size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, &se); LOG_INFO("MQTT Publish map report to %s", mapTopic.c_str()); diff --git a/src/serialization/MeshPacketSerializer.cpp b/src/serialization/MeshPacketSerializer.cpp index 5a1f8ed7e..b31d2dc2e 100644 --- a/src/serialization/MeshPacketSerializer.cpp +++ b/src/serialization/MeshPacketSerializer.cpp @@ -413,7 +413,7 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, jsonObj["from"] = new JSONValue((unsigned int)mp->from); jsonObj["channel"] = new JSONValue((unsigned int)mp->channel); jsonObj["type"] = new JSONValue(msgType.c_str()); - jsonObj["sender"] = new JSONValue(owner.id); + jsonObj["sender"] = new JSONValue(nodeDB->getNodeId().c_str()); if (mp->rx_rssi != 0) jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi); if (mp->rx_snr != 0) diff --git a/src/serialization/MeshPacketSerializer_nRF52.cpp b/src/serialization/MeshPacketSerializer_nRF52.cpp index e0daa1a88..353c710a1 100644 --- a/src/serialization/MeshPacketSerializer_nRF52.cpp +++ b/src/serialization/MeshPacketSerializer_nRF52.cpp @@ -353,7 +353,7 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, jsonObj["from"] = (unsigned int)mp->from; jsonObj["channel"] = (unsigned int)mp->channel; jsonObj["type"] = msgType.c_str(); - jsonObj["sender"] = owner.id; + jsonObj["sender"] = nodeDB->getNodeId().c_str(); if (mp->rx_rssi != 0) jsonObj["rssi"] = (int)mp->rx_rssi; if (mp->rx_snr != 0) diff --git a/test/test_mqtt/MQTT.cpp b/test/test_mqtt/MQTT.cpp index ede3d22b7..8726d1ccb 100644 --- a/test/test_mqtt/MQTT.cpp +++ b/test/test_mqtt/MQTT.cpp @@ -591,7 +591,7 @@ void test_receiveEncryptedPKITopicToUs(void) // Should ignore messages published to MQTT by this gateway. void test_receiveIgnoresOwnPublishedMessages(void) { - unitTest->publish(&decoded, owner.id); + unitTest->publish(&decoded, nodeDB->getNodeId().c_str()); TEST_ASSERT_TRUE(mockRouter->packets_.empty()); TEST_ASSERT_TRUE(mockRoutingModule->ackNacks_.empty()); @@ -603,7 +603,7 @@ void test_receiveAcksOwnSentMessages(void) meshtastic_MeshPacket p = decoded; p.from = myNodeInfo.my_node_num; - unitTest->publish(&p, owner.id); + unitTest->publish(&p, nodeDB->getNodeId().c_str()); TEST_ASSERT_TRUE(mockRouter->packets_.empty()); TEST_ASSERT_EQUAL(1, mockRoutingModule->ackNacks_.size()); From 329a494ce2e35b4c13c726602f4be1fad24d54c7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:59:40 -0500 Subject: [PATCH 104/166] Update meshtastic-ArduinoThread digest to b841b04 (#8233) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index b6d6733e3..2e6f851df 100644 --- a/platformio.ini +++ b/platformio.ini @@ -70,7 +70,7 @@ lib_deps = # renovate: datasource=git-refs depName=meshtastic-TinyGPSPlus packageName=https://github.com/meshtastic/TinyGPSPlus gitBranch=master https://github.com/meshtastic/TinyGPSPlus/archive/71a82db35f3b973440044c476d4bcdc673b104f4.zip # renovate: datasource=git-refs depName=meshtastic-ArduinoThread packageName=https://github.com/meshtastic/ArduinoThread gitBranch=master - https://github.com/meshtastic/ArduinoThread/archive/7c3ee9e1951551b949763b1f5280f8db1fa4068d.zip + https://github.com/meshtastic/ArduinoThread/archive/b841b0415721f1341ea41cccfb4adccfaf951567.zip # renovate: datasource=custom.pio depName=Nanopb packageName=nanopb/library/Nanopb nanopb/Nanopb@0.4.91 # renovate: datasource=custom.pio depName=ErriezCRC32 packageName=erriez/library/ErriezCRC32 From 87e3540f48eb17cffd6cda2cbebef274ced29885 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:59:50 -0500 Subject: [PATCH 105/166] Update meshtastic/device-ui digest to f920b12 (#8234) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 2e6f851df..4ae2da54f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -120,7 +120,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/505ffadaa7a931df5dc8153229b719a07bbb028c.zip + https://github.com/meshtastic/device-ui/archive/f920b1273df750c2e3e01385d3ba30553b913afa.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From 735784e6e422ab5383dcb5afc29eb7c915117a9d Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 6 Oct 2025 13:00:44 -0500 Subject: [PATCH 106/166] Run Integration test in simulator mode (#8232) --- .github/workflows/test_native.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 6b788f4c7..9cf1c9e53 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -40,7 +40,7 @@ jobs: - name: Integration test run: | - .pio/build/coverage/program & + .pio/build/coverage/program -s & PID=$! timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done" echo "Simulator started, launching python test..." From fc1737c9495937ba142d9018593df4b3937e29ed Mon Sep 17 00:00:00 2001 From: Austin Date: Mon, 6 Oct 2025 20:58:00 -0400 Subject: [PATCH 107/166] Actions: Simplify matrices, cleanup build_one_* (#8218) --- .github/workflows/build_firmware.yml | 3 + .github/workflows/build_one_arch.yml | 302 +----------------- .github/workflows/build_one_target.yml | 173 +--------- .github/workflows/main_matrix.yml | 141 ++------ .github/workflows/merge_queue.yml | 134 +------- bin/generate_ci_matrix.py | 55 ++-- .../native/portduino-buildroot/platformio.ini | 1 + variants/native/portduino/platformio.ini | 3 +- 8 files changed, 92 insertions(+), 720 deletions(-) diff --git a/.github/workflows/build_firmware.yml b/.github/workflows/build_firmware.yml index 2ef67405a..b62729332 100644 --- a/.github/workflows/build_firmware.yml +++ b/.github/workflows/build_firmware.yml @@ -19,6 +19,8 @@ jobs: pio-build: name: build-${{ inputs.platform }} runs-on: ubuntu-24.04 + outputs: + artifact-id: ${{ steps.upload.outputs.artifact-id }} steps: - uses: actions/checkout@v5 with: @@ -55,6 +57,7 @@ jobs: - name: Store binaries as an artifact uses: actions/upload-artifact@v4 + id: upload with: name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}.zip overwrite: true diff --git a/.github/workflows/build_one_arch.yml b/.github/workflows/build_one_arch.yml index f5352b3c4..6d9134941 100644 --- a/.github/workflows/build_one_arch.yml +++ b/.github/workflows/build_one_arch.yml @@ -3,6 +3,7 @@ name: Build One Arch on: workflow_dispatch: inputs: + # trunk-ignore(checkov/CKV_GHA_7) arch: type: choice options: @@ -16,10 +17,13 @@ on: - stm32 - native +permissions: read-all + +env: + INPUT_ARCH: ${{ github.event.inputs.arch }} + jobs: setup: - strategy: - fail-fast: false runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v5 @@ -31,23 +35,11 @@ jobs: - name: Generate matrix id: jsonStep run: | - if [[ "$GITHUB_HEAD_REF" == "" ]]; then - TARGETS=$(./bin/generate_ci_matrix.py ${{inputs.arch}} extra) - else - TARGETS=$(./bin/generate_ci_matrix.py ${{inputs.arch}} pr) - fi - echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS" - echo "${{inputs.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT + TARGETS=$(./bin/generate_ci_matrix.py $INPUT_ARCH --level extra) + echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF" + echo "selected_arch=$TARGETS" >> $GITHUB_OUTPUT outputs: - esp32: ${{ steps.jsonStep.outputs.esp32 }} - esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }} - esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }} - esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }} - nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }} - rp2040: ${{ steps.jsonStep.outputs.rp2040 }} - rp2350: ${{ steps.jsonStep.outputs.rp2350 }} - stm32: ${{ steps.jsonStep.outputs.stm32 }} - check: ${{ steps.jsonStep.outputs.check }} + selected_arch: ${{ steps.jsonStep.outputs.selected_arch }} version: runs-on: ubuntu-latest @@ -64,101 +56,18 @@ jobs: long: ${{ steps.version.outputs.long }} deb: ${{ steps.version.outputs.deb }} - build-esp32: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32'}} + build: + if: ${{ github.event_name != 'workflow_dispatch' }} needs: [setup, version] strategy: fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32) }} + matrix: + build: ${{ fromJson(needs.setup.outputs.selected_arch) }} uses: ./.github/workflows/build_firmware.yml with: version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32 - - build-esp32s3: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32s3'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32s3 - - build-esp32c3: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32c3'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c3 - - build-esp32c6: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32c6'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c6 - - build-nrf52840: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'nrf52840'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: nrf52840 - - build-rp2040: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'rp2040'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.rp2040) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2040 - - build-rp2350: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'rp2350'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.rp2350) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2350 - - build-stm32: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'stm32' }} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.stm32) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: stm32 + pio_env: ${{ matrix.build.board }} + platform: ${{ matrix.build.arch }} build-debian-src: if: ${{ github.repository == 'meshtastic/firmware' && github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }} @@ -252,18 +161,7 @@ jobs: - rp2350 - stm32 runs-on: ubuntu-latest - needs: - [ - version, - build-esp32, - build-esp32s3, - build-esp32c3, - build-esp32c6, - build-nrf52840, - build-rp2040, - build-rp2350, - build-stm32, - ] + needs: [version, build] steps: - name: Checkout code uses: actions/checkout@v5 @@ -332,169 +230,3 @@ jobs: name: firmware-${{inputs.arch}}-${{ needs.version.outputs.long }} description: "Download firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation" github-token: ${{ secrets.GITHUB_TOKEN }} - - release-artifacts: - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' }} - outputs: - upload_url: ${{ steps.create_release.outputs.upload_url }} - needs: - - version - - gather-artifacts - - build-debian-src - - package-pio-deps-native-tft - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - name: Create release - uses: softprops/action-gh-release@v2 - id: create_release - with: - draft: true - prerelease: true - name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha - tag_name: v${{ needs.version.outputs.long }} - body: | - Autogenerated by github action, developer should edit as required before publishing... - - - name: Download source deb - uses: actions/download-artifact@v5 - with: - pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src - merge-multiple: true - path: ./output/debian-src - - - name: Download `native-tft` pio deps - uses: actions/download-artifact@v5 - with: - pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./output/pio-deps-native-tft - - - name: Zip Linux sources - working-directory: output - run: | - zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src - zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft - - # For diagnostics - - name: Display structure of downloaded files - run: ls -lR - - - name: Add Linux sources to GtiHub Release - # Only run when targeting master branch with workflow_dispatch - if: ${{ github.ref_name == 'master' }} - run: | - gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip - gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - release-firmware: - strategy: - fail-fast: false - matrix: - arch: - - esp32 - - esp32s3 - - esp32c3 - - esp32c6 - - nrf52840 - - rp2040 - - rp2350 - - stm32 - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' }} - needs: [release-artifacts, version] - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - uses: actions/download-artifact@v5 - with: - pattern: firmware-${{inputs.arch}}-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./output - - - name: Display structure of downloaded files - run: ls -lR - - - name: Device scripts permissions - run: | - chmod +x ./output/device-install.sh - chmod +x ./output/device-update.sh - - - name: Zip firmware - run: zip -j -9 -r ./firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip ./output - - - uses: actions/download-artifact@v5 - with: - name: debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip - merge-multiple: true - path: ./elfs - - - name: Zip debug elfs - run: zip -j -9 -r ./debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip ./elfs - - # For diagnostics - - name: Display structure of downloaded files - run: ls -lR - - - name: Add bins and debug elfs to GitHub Release - # Only run when targeting master branch with workflow_dispatch - if: ${{ github.ref_name == 'master' }} - run: | - gh release upload v${{ needs.version.outputs.long }} ./firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip - gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - publish-firmware: - runs-on: ubuntu-24.04 - if: ${{ github.event_name == 'workflow_dispatch' }} - needs: [release-firmware, version] - env: - targets: |- - esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32 - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - uses: actions/download-artifact@v5 - with: - pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./publish - - - name: Publish firmware to meshtastic.github.io - uses: peaceiris/actions-gh-pages@v4 - env: - # On event/* branches, use the event name as the destination prefix - DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }} - with: - deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }} - external_repository: meshtastic/meshtastic.github.io - publish_branch: master - publish_dir: ./publish - destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }} - keep_files: true - user_name: github-actions[bot] - user_email: github-actions[bot]@users.noreply.github.com - commit_message: ${{ needs.version.outputs.long }} - enable_jekyll: true diff --git a/.github/workflows/build_one_target.yml b/.github/workflows/build_one_target.yml index 3c83ce960..ba1d5080f 100644 --- a/.github/workflows/build_one_target.yml +++ b/.github/workflows/build_one_target.yml @@ -3,6 +3,7 @@ name: Build One Target on: workflow_dispatch: inputs: + # trunk-ignore(checkov/CKV_GHA_7) arch: type: choice options: @@ -19,11 +20,13 @@ on: type: string required: false description: Choose the target board, e.g. nrf52_promicro_diy_tcxo. If blank, will find available targets. - # find-target: # type: boolean # default: true # description: 'Find the available targets' + +permissions: read-all + jobs: find-targets: if: ${{ inputs.target == '' }} @@ -51,13 +54,13 @@ jobs: - name: Generate matrix id: jsonStep run: | - TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} extra) + TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level extra) echo "Name: $GITHUB_REF_NAME" >> $GITHUB_STEP_SUMMARY echo "Base: $GITHUB_BASE_REF" >> $GITHUB_STEP_SUMMARY echo "Arch: ${{matrix.arch}}" >> $GITHUB_STEP_SUMMARY echo "Ref: $GITHUB_REF" >> $GITHUB_STEP_SUMMARY echo "Targets:" >> $GITHUB_STEP_SUMMARY - echo $TARGETS | sed 's/[][]//g; s/", "/\n- /g; s/"//g; s/^/- /' >> $GITHUB_STEP_SUMMARY + echo $TARGETS >> $GITHUB_STEP_SUMMARY version: if: ${{ inputs.target != '' }} @@ -75,11 +78,9 @@ jobs: long: ${{ steps.version.outputs.long }} deb: ${{ steps.version.outputs.deb }} - build-arch: + build: if: ${{ inputs.target != '' && inputs.arch != 'native' }} needs: [version] - strategy: - fail-fast: false uses: ./.github/workflows/build_firmware.yml with: version: ${{ needs.version.outputs.long }} @@ -165,10 +166,8 @@ jobs: permissions: contents: write pull-requests: write - strategy: - fail-fast: false runs-on: ubuntu-latest - needs: [version, build-arch] + needs: [version, build] steps: - name: Checkout code uses: actions/checkout@v5 @@ -237,159 +236,3 @@ jobs: name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }} description: "Download firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation" github-token: ${{ secrets.GITHUB_TOKEN }} - - release-artifacts: - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' && inputs.target != ''}} - outputs: - upload_url: ${{ steps.create_release.outputs.upload_url }} - needs: - - version - - gather-artifacts - - build-debian-src - - package-pio-deps-native-tft - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - name: Create release - uses: softprops/action-gh-release@v2 - id: create_release - with: - draft: true - prerelease: true - name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha - tag_name: v${{ needs.version.outputs.long }} - body: | - Autogenerated by github action, developer should edit as required before publishing... - - - name: Download source deb - uses: actions/download-artifact@v5 - with: - pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src - merge-multiple: true - path: ./output/debian-src - - - name: Download `native-tft` pio deps - uses: actions/download-artifact@v5 - with: - pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./output/pio-deps-native-tft - - - name: Zip Linux sources - working-directory: output - run: | - zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src - zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft - - # For diagnostics - - name: Display structure of downloaded files - run: ls -lR - - - name: Add Linux sources to GtiHub Release - # Only run when targeting master branch with workflow_dispatch - if: ${{ github.ref_name == 'master' }} - run: | - gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip - gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - release-firmware: - strategy: - fail-fast: false - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' && inputs.target != ''}} - needs: [release-artifacts, version] - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - uses: actions/download-artifact@v5 - with: - pattern: firmware-*-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./output - - - name: Display structure of downloaded files - run: ls -lR - - - name: Device scripts permissions - run: | - chmod +x ./output/device-install.sh - chmod +x ./output/device-update.sh - - - name: Zip firmware - run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output - - - uses: actions/download-artifact@v5 - with: - pattern: debug-elfs-*-${{ needs.version.outputs.long }}.zip - merge-multiple: true - path: ./elfs - - - name: Zip debug elfs - run: zip -j -9 -r ./debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./elfs - - # For diagnostics - - name: Display structure of downloaded files - run: ls -lR - - - name: Add bins and debug elfs to GitHub Release - # Only run when targeting master branch with workflow_dispatch - if: ${{ github.ref_name == 'master' }} - run: | - gh release upload v${{ needs.version.outputs.long }} ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip - gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - publish-firmware: - runs-on: ubuntu-24.04 - if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' && inputs.target != '' }} - needs: [release-firmware, version] - env: - targets: |- - esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32 - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - uses: actions/download-artifact@v5 - with: - pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./publish - - - name: Publish firmware to meshtastic.github.io - uses: peaceiris/actions-gh-pages@v4 - env: - # On event/* branches, use the event name as the destination prefix - DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }} - with: - deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }} - external_repository: meshtastic/meshtastic.github.io - publish_branch: master - publish_dir: ./publish - destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }} - keep_files: true - user_name: github-actions[bot] - user_email: github-actions[bot]@users.noreply.github.com - commit_message: ${{ needs.version.outputs.long }} - enable_jekyll: true diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index f61e314a7..887bf3081 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -27,19 +27,11 @@ on: jobs: setup: - if: github.repository == 'meshtastic/firmware' strategy: - fail-fast: false + fail-fast: true matrix: arch: - - esp32 - - esp32s3 - - esp32c3 - - esp32c6 - - nrf52840 - - rp2040 - - rp2350 - - stm32 + - all - check runs-on: ubuntu-24.04 steps: @@ -49,33 +41,22 @@ jobs: python-version: 3.x cache: pip - run: pip install -U platformio - - name: Uncomment build epoch - shell: bash - run: | - sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini - name: Generate matrix id: jsonStep run: | if [[ "$GITHUB_HEAD_REF" == "" ]]; then TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}}) else - TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} pr) + TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level pr) fi - echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS" - echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT + echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF" + echo "${{matrix.arch}}=$TARGETS" >> $GITHUB_OUTPUT + echo "$TARGETS" >> $GITHUB_STEP_SUMMARY outputs: - esp32: ${{ steps.jsonStep.outputs.esp32 }} - esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }} - esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }} - esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }} - nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }} - rp2040: ${{ steps.jsonStep.outputs.rp2040 }} - rp2350: ${{ steps.jsonStep.outputs.rp2350 }} - stm32: ${{ steps.jsonStep.outputs.stm32 }} + all: ${{ steps.jsonStep.outputs.all }} check: ${{ steps.jsonStep.outputs.check }} version: - if: github.repository == 'meshtastic/firmware' runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -94,7 +75,8 @@ jobs: needs: setup strategy: fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.check) }} + matrix: + check: ${{ fromJson(needs.setup.outputs.check) }} runs-on: ubuntu-latest if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }} @@ -103,96 +85,20 @@ jobs: - name: Build base id: base uses: ./.github/actions/setup-base - - name: Check ${{ matrix.board }} - run: bin/check-all.sh ${{ matrix.board }} + - name: Check ${{ matrix.check.board }} + run: bin/check-all.sh ${{ matrix.check.board }} - build-esp32: + build: needs: [setup, version] strategy: fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32) }} + matrix: + build: ${{ fromJson(needs.setup.outputs.all) }} uses: ./.github/workflows/build_firmware.yml with: version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32 - - build-esp32s3: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32s3 - - build-esp32c3: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c3 - - build-esp32c6: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c6 - - build-nrf52840: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: nrf52840 - - build-rp2040: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.rp2040) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2040 - - build-rp2350: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.rp2350) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2350 - - build-stm32: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.stm32) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: stm32 + pio_env: ${{ matrix.build.board }} + platform: ${{ matrix.build.platform }} build-debian-src: if: github.repository == 'meshtastic/firmware' @@ -203,7 +109,7 @@ jobs: secrets: inherit package-pio-deps-native-tft: - if: ${{ github.event_name == 'workflow_dispatch' }} + if: ${{ github.repository == 'meshtastic/firmware' && github.event_name == 'workflow_dispatch' }} uses: ./.github/workflows/package_pio_deps.yml with: pio_env: native-tft @@ -288,18 +194,7 @@ jobs: - rp2350 - stm32 runs-on: ubuntu-latest - needs: - [ - version, - build-esp32, - build-esp32s3, - build-esp32c3, - build-esp32c6, - build-nrf52840, - build-rp2040, - build-rp2350, - build-stm32, - ] + needs: [version, build] steps: - name: Checkout code uses: actions/checkout@v5 diff --git a/.github/workflows/merge_queue.yml b/.github/workflows/merge_queue.yml index 7f397ce18..79e8b0803 100644 --- a/.github/workflows/merge_queue.yml +++ b/.github/workflows/merge_queue.yml @@ -7,23 +7,13 @@ on: # Merge group is a special trigger that is used to trigger the workflow when a merge group is created. merge_group: -env: - FAIL_FAST_PER_ARCH: true - jobs: setup: strategy: fail-fast: true matrix: arch: - - esp32 - - esp32s3 - - esp32c3 - - esp32c6 - - nrf52840 - - rp2040 - - rp2350 - - stm32 + - all - check runs-on: ubuntu-24.04 steps: @@ -39,19 +29,12 @@ jobs: if [[ "$GITHUB_HEAD_REF" == "" ]]; then TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}}) else - TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} pr) + TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level pr) fi - echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS" - echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT + echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF" + echo "${{matrix.arch}}=$TARGETS" >> $GITHUB_OUTPUT outputs: - esp32: ${{ steps.jsonStep.outputs.esp32 }} - esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }} - esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }} - esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }} - nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }} - rp2040: ${{ steps.jsonStep.outputs.rp2040 }} - rp2350: ${{ steps.jsonStep.outputs.rp2350 }} - stm32: ${{ steps.jsonStep.outputs.stm32 }} + all: ${{ steps.jsonStep.outputs.all }} check: ${{ steps.jsonStep.outputs.check }} version: @@ -73,7 +56,8 @@ jobs: needs: setup strategy: fail-fast: true - matrix: ${{ fromJson(needs.setup.outputs.check) }} + matrix: + check: ${{ fromJson(needs.setup.outputs.check) }} runs-on: ubuntu-latest if: ${{ github.event_name != 'workflow_dispatch' }} @@ -82,96 +66,19 @@ jobs: - name: Build base id: base uses: ./.github/actions/setup-base - - name: Check ${{ matrix.board }} - run: bin/check-all.sh ${{ matrix.board }} + - name: Check ${{ matrix.check.board }} + run: bin/check-all.sh ${{ matrix.check.board }} - build-esp32: + build: needs: [setup, version] strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.esp32) }} + matrix: + build: ${{ fromJson(needs.setup.outputs.all) }} uses: ./.github/workflows/build_firmware.yml with: version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32 - - build-esp32s3: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32s3 - - build-esp32c3: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c3 - - build-esp32c6: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c6 - - build-nrf52840: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: nrf52840 - - build-rp2040: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.rp2040) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2040 - - build-rp2350: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.rp2350) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2350 - - build-stm32: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.stm32) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: stm32 + pio_env: ${{ matrix.build.board }} + platform: ${{ matrix.build.platform }} build-debian-src: if: github.repository == 'meshtastic/firmware' @@ -260,18 +167,7 @@ jobs: - rp2350 - stm32 runs-on: ubuntu-latest - needs: - [ - version, - build-esp32, - build-esp32s3, - build-esp32c3, - build-esp32c6, - build-nrf52840, - build-rp2040, - build-rp2350, - build-stm32, - ] + needs: [version, build] steps: - name: Checkout code uses: actions/checkout@v5 diff --git a/bin/generate_ci_matrix.py b/bin/generate_ci_matrix.py index aaa76aa45..b4c18c05b 100755 --- a/bin/generate_ci_matrix.py +++ b/bin/generate_ci_matrix.py @@ -1,28 +1,32 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """Generate the CI matrix.""" +import argparse import json -import sys -import random import re from platformio.project.config import ProjectConfig -options = sys.argv[1:] +parser = argparse.ArgumentParser(description="Generate the CI matrix") +parser.add_argument("platform", help="Platform to build for") +parser.add_argument( + "--level", + choices=["extra", "pr"], + nargs="*", + default=[], + help="Board level to build for (omit for full release boards)", +) +args = parser.parse_args() outlist = [] -if len(options) < 1: - print(json.dumps(outlist)) - exit(1) - cfg = ProjectConfig.get_instance() pio_envs = cfg.envs() # Gather all PlatformIO environments for filtering later all_envs = [] for pio_env in pio_envs: - env_build_flags = cfg.get(f"env:{pio_env}", 'build_flags') + env_build_flags = cfg.get(f"env:{pio_env}", "build_flags") env_platform = None for flag in env_build_flags: # Extract the platform from the build flags @@ -37,36 +41,35 @@ for pio_env in pio_envs: exit(1) # Store env details as a dictionary, and add to 'all_envs' list env = { - 'name': pio_env, - 'platform': env_platform, - 'board_level': cfg.get(f"env:{pio_env}", 'board_level', default=None), - 'board_check': bool(cfg.get(f"env:{pio_env}", 'board_check', default=False)) + "ci": {"board": pio_env, "platform": env_platform}, + "board_level": cfg.get(f"env:{pio_env}", "board_level", default=None), + "board_check": bool(cfg.get(f"env:{pio_env}", "board_check", default=False)), } all_envs.append(env) # Filter outputs based on options # Check is mutually exclusive with other options (except 'pr') -if "check" in options: +if "check" in args.platform: for env in all_envs: - if env['board_check']: - if "pr" in options: - if env['board_level'] == 'pr': - outlist.append(env['name']) + if env["board_check"]: + if "pr" in args.level: + if env["board_level"] == "pr": + outlist.append(env["ci"]) else: - outlist.append(env['name']) + outlist.append(env["ci"]) # Filter (non-check) builds by platform else: for env in all_envs: - if options[0] == env['platform']: + if args.platform == env["ci"]["platform"] or args.platform == "all": # Always include board_level = 'pr' - if env['board_level'] == 'pr': - outlist.append(env['name']) + if env["board_level"] == "pr": + outlist.append(env["ci"]) # Include board_level = 'extra' when requested - elif "extra" in options and env['board_level'] == "extra": - outlist.append(env['name']) + elif "extra" in args.level and env["board_level"] == "extra": + outlist.append(env["ci"]) # If no board level is specified, include in release builds (not PR) - elif "pr" not in options and not env['board_level']: - outlist.append(env['name']) + elif "pr" not in args.level and not env["board_level"]: + outlist.append(env["ci"]) # Return as a JSON list print(json.dumps(outlist)) diff --git a/variants/native/portduino-buildroot/platformio.ini b/variants/native/portduino-buildroot/platformio.ini index d1bd39e10..a3d0f4639 100644 --- a/variants/native/portduino-buildroot/platformio.ini +++ b/variants/native/portduino-buildroot/platformio.ini @@ -4,5 +4,6 @@ extends = portduino_base ; environment variable in the buildroot environment. build_flags = ${portduino_base.build_flags} -O0 -I variants/native/portduino-buildroot board = buildroot +board_level = extra lib_deps = ${portduino_base.lib_deps} build_src_filter = ${portduino_base.build_src_filter} \ No newline at end of file diff --git a/variants/native/portduino/platformio.ini b/variants/native/portduino/platformio.ini index 61eadb459..2ccdfbbfc 100644 --- a/variants/native/portduino/platformio.ini +++ b/variants/native/portduino/platformio.ini @@ -3,6 +3,7 @@ extends = portduino_base build_flags = ${portduino_base.build_flags} -I variants/native/portduino -I /usr/include board = cross_platform +board_level = extra lib_deps = ${portduino_base.lib_deps} melopero/Melopero RV3028@^1.1.0 @@ -50,7 +51,6 @@ build_type = release lib_deps = ${native_base.lib_deps} ${device-ui_base.lib_deps} -board_level = extra build_flags = ${native_base.build_flags} -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -D RAM_SIZE=8192 -D USE_FRAMEBUFFER=1 @@ -79,7 +79,6 @@ build_type = debug lib_deps = ${native_base.lib_deps} ${device-ui_base.lib_deps} -board_level = extra build_flags = ${native_base.build_flags} -O0 -fsanitize=address -lX11 -linput -lxkbcommon -D DEBUG_HEAP -D RAM_SIZE=16384 From 518680514f6249866ade68b7b11c5906ee1599ca Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 7 Oct 2025 13:37:13 +1100 Subject: [PATCH 108/166] Actions: Simplify matrices, cleanup build_one_* (#8218) (#8239) Co-authored-by: Austin --- .github/workflows/build_firmware.yml | 3 + .github/workflows/build_one_arch.yml | 302 +----------------- .github/workflows/build_one_target.yml | 173 +--------- .github/workflows/main_matrix.yml | 135 ++------ .github/workflows/merge_queue.yml | 134 +------- bin/generate_ci_matrix.py | 55 ++-- .../native/portduino-buildroot/platformio.ini | 1 + variants/native/portduino/platformio.ini | 3 +- 8 files changed, 92 insertions(+), 714 deletions(-) diff --git a/.github/workflows/build_firmware.yml b/.github/workflows/build_firmware.yml index 2ef67405a..b62729332 100644 --- a/.github/workflows/build_firmware.yml +++ b/.github/workflows/build_firmware.yml @@ -19,6 +19,8 @@ jobs: pio-build: name: build-${{ inputs.platform }} runs-on: ubuntu-24.04 + outputs: + artifact-id: ${{ steps.upload.outputs.artifact-id }} steps: - uses: actions/checkout@v5 with: @@ -55,6 +57,7 @@ jobs: - name: Store binaries as an artifact uses: actions/upload-artifact@v4 + id: upload with: name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}.zip overwrite: true diff --git a/.github/workflows/build_one_arch.yml b/.github/workflows/build_one_arch.yml index f5352b3c4..6d9134941 100644 --- a/.github/workflows/build_one_arch.yml +++ b/.github/workflows/build_one_arch.yml @@ -3,6 +3,7 @@ name: Build One Arch on: workflow_dispatch: inputs: + # trunk-ignore(checkov/CKV_GHA_7) arch: type: choice options: @@ -16,10 +17,13 @@ on: - stm32 - native +permissions: read-all + +env: + INPUT_ARCH: ${{ github.event.inputs.arch }} + jobs: setup: - strategy: - fail-fast: false runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v5 @@ -31,23 +35,11 @@ jobs: - name: Generate matrix id: jsonStep run: | - if [[ "$GITHUB_HEAD_REF" == "" ]]; then - TARGETS=$(./bin/generate_ci_matrix.py ${{inputs.arch}} extra) - else - TARGETS=$(./bin/generate_ci_matrix.py ${{inputs.arch}} pr) - fi - echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS" - echo "${{inputs.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT + TARGETS=$(./bin/generate_ci_matrix.py $INPUT_ARCH --level extra) + echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF" + echo "selected_arch=$TARGETS" >> $GITHUB_OUTPUT outputs: - esp32: ${{ steps.jsonStep.outputs.esp32 }} - esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }} - esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }} - esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }} - nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }} - rp2040: ${{ steps.jsonStep.outputs.rp2040 }} - rp2350: ${{ steps.jsonStep.outputs.rp2350 }} - stm32: ${{ steps.jsonStep.outputs.stm32 }} - check: ${{ steps.jsonStep.outputs.check }} + selected_arch: ${{ steps.jsonStep.outputs.selected_arch }} version: runs-on: ubuntu-latest @@ -64,101 +56,18 @@ jobs: long: ${{ steps.version.outputs.long }} deb: ${{ steps.version.outputs.deb }} - build-esp32: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32'}} + build: + if: ${{ github.event_name != 'workflow_dispatch' }} needs: [setup, version] strategy: fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32) }} + matrix: + build: ${{ fromJson(needs.setup.outputs.selected_arch) }} uses: ./.github/workflows/build_firmware.yml with: version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32 - - build-esp32s3: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32s3'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32s3 - - build-esp32c3: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32c3'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c3 - - build-esp32c6: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32c6'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c6 - - build-nrf52840: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'nrf52840'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: nrf52840 - - build-rp2040: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'rp2040'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.rp2040) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2040 - - build-rp2350: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'rp2350'}} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.rp2350) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2350 - - build-stm32: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'stm32' }} - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.stm32) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: stm32 + pio_env: ${{ matrix.build.board }} + platform: ${{ matrix.build.arch }} build-debian-src: if: ${{ github.repository == 'meshtastic/firmware' && github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }} @@ -252,18 +161,7 @@ jobs: - rp2350 - stm32 runs-on: ubuntu-latest - needs: - [ - version, - build-esp32, - build-esp32s3, - build-esp32c3, - build-esp32c6, - build-nrf52840, - build-rp2040, - build-rp2350, - build-stm32, - ] + needs: [version, build] steps: - name: Checkout code uses: actions/checkout@v5 @@ -332,169 +230,3 @@ jobs: name: firmware-${{inputs.arch}}-${{ needs.version.outputs.long }} description: "Download firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation" github-token: ${{ secrets.GITHUB_TOKEN }} - - release-artifacts: - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' }} - outputs: - upload_url: ${{ steps.create_release.outputs.upload_url }} - needs: - - version - - gather-artifacts - - build-debian-src - - package-pio-deps-native-tft - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - name: Create release - uses: softprops/action-gh-release@v2 - id: create_release - with: - draft: true - prerelease: true - name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha - tag_name: v${{ needs.version.outputs.long }} - body: | - Autogenerated by github action, developer should edit as required before publishing... - - - name: Download source deb - uses: actions/download-artifact@v5 - with: - pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src - merge-multiple: true - path: ./output/debian-src - - - name: Download `native-tft` pio deps - uses: actions/download-artifact@v5 - with: - pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./output/pio-deps-native-tft - - - name: Zip Linux sources - working-directory: output - run: | - zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src - zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft - - # For diagnostics - - name: Display structure of downloaded files - run: ls -lR - - - name: Add Linux sources to GtiHub Release - # Only run when targeting master branch with workflow_dispatch - if: ${{ github.ref_name == 'master' }} - run: | - gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip - gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - release-firmware: - strategy: - fail-fast: false - matrix: - arch: - - esp32 - - esp32s3 - - esp32c3 - - esp32c6 - - nrf52840 - - rp2040 - - rp2350 - - stm32 - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' }} - needs: [release-artifacts, version] - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - uses: actions/download-artifact@v5 - with: - pattern: firmware-${{inputs.arch}}-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./output - - - name: Display structure of downloaded files - run: ls -lR - - - name: Device scripts permissions - run: | - chmod +x ./output/device-install.sh - chmod +x ./output/device-update.sh - - - name: Zip firmware - run: zip -j -9 -r ./firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip ./output - - - uses: actions/download-artifact@v5 - with: - name: debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip - merge-multiple: true - path: ./elfs - - - name: Zip debug elfs - run: zip -j -9 -r ./debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip ./elfs - - # For diagnostics - - name: Display structure of downloaded files - run: ls -lR - - - name: Add bins and debug elfs to GitHub Release - # Only run when targeting master branch with workflow_dispatch - if: ${{ github.ref_name == 'master' }} - run: | - gh release upload v${{ needs.version.outputs.long }} ./firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip - gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - publish-firmware: - runs-on: ubuntu-24.04 - if: ${{ github.event_name == 'workflow_dispatch' }} - needs: [release-firmware, version] - env: - targets: |- - esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32 - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - uses: actions/download-artifact@v5 - with: - pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./publish - - - name: Publish firmware to meshtastic.github.io - uses: peaceiris/actions-gh-pages@v4 - env: - # On event/* branches, use the event name as the destination prefix - DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }} - with: - deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }} - external_repository: meshtastic/meshtastic.github.io - publish_branch: master - publish_dir: ./publish - destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }} - keep_files: true - user_name: github-actions[bot] - user_email: github-actions[bot]@users.noreply.github.com - commit_message: ${{ needs.version.outputs.long }} - enable_jekyll: true diff --git a/.github/workflows/build_one_target.yml b/.github/workflows/build_one_target.yml index 3c83ce960..ba1d5080f 100644 --- a/.github/workflows/build_one_target.yml +++ b/.github/workflows/build_one_target.yml @@ -3,6 +3,7 @@ name: Build One Target on: workflow_dispatch: inputs: + # trunk-ignore(checkov/CKV_GHA_7) arch: type: choice options: @@ -19,11 +20,13 @@ on: type: string required: false description: Choose the target board, e.g. nrf52_promicro_diy_tcxo. If blank, will find available targets. - # find-target: # type: boolean # default: true # description: 'Find the available targets' + +permissions: read-all + jobs: find-targets: if: ${{ inputs.target == '' }} @@ -51,13 +54,13 @@ jobs: - name: Generate matrix id: jsonStep run: | - TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} extra) + TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level extra) echo "Name: $GITHUB_REF_NAME" >> $GITHUB_STEP_SUMMARY echo "Base: $GITHUB_BASE_REF" >> $GITHUB_STEP_SUMMARY echo "Arch: ${{matrix.arch}}" >> $GITHUB_STEP_SUMMARY echo "Ref: $GITHUB_REF" >> $GITHUB_STEP_SUMMARY echo "Targets:" >> $GITHUB_STEP_SUMMARY - echo $TARGETS | sed 's/[][]//g; s/", "/\n- /g; s/"//g; s/^/- /' >> $GITHUB_STEP_SUMMARY + echo $TARGETS >> $GITHUB_STEP_SUMMARY version: if: ${{ inputs.target != '' }} @@ -75,11 +78,9 @@ jobs: long: ${{ steps.version.outputs.long }} deb: ${{ steps.version.outputs.deb }} - build-arch: + build: if: ${{ inputs.target != '' && inputs.arch != 'native' }} needs: [version] - strategy: - fail-fast: false uses: ./.github/workflows/build_firmware.yml with: version: ${{ needs.version.outputs.long }} @@ -165,10 +166,8 @@ jobs: permissions: contents: write pull-requests: write - strategy: - fail-fast: false runs-on: ubuntu-latest - needs: [version, build-arch] + needs: [version, build] steps: - name: Checkout code uses: actions/checkout@v5 @@ -237,159 +236,3 @@ jobs: name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }} description: "Download firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation" github-token: ${{ secrets.GITHUB_TOKEN }} - - release-artifacts: - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' && inputs.target != ''}} - outputs: - upload_url: ${{ steps.create_release.outputs.upload_url }} - needs: - - version - - gather-artifacts - - build-debian-src - - package-pio-deps-native-tft - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - name: Create release - uses: softprops/action-gh-release@v2 - id: create_release - with: - draft: true - prerelease: true - name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha - tag_name: v${{ needs.version.outputs.long }} - body: | - Autogenerated by github action, developer should edit as required before publishing... - - - name: Download source deb - uses: actions/download-artifact@v5 - with: - pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src - merge-multiple: true - path: ./output/debian-src - - - name: Download `native-tft` pio deps - uses: actions/download-artifact@v5 - with: - pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./output/pio-deps-native-tft - - - name: Zip Linux sources - working-directory: output - run: | - zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src - zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft - - # For diagnostics - - name: Display structure of downloaded files - run: ls -lR - - - name: Add Linux sources to GtiHub Release - # Only run when targeting master branch with workflow_dispatch - if: ${{ github.ref_name == 'master' }} - run: | - gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip - gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - release-firmware: - strategy: - fail-fast: false - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' && inputs.target != ''}} - needs: [release-artifacts, version] - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - uses: actions/download-artifact@v5 - with: - pattern: firmware-*-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./output - - - name: Display structure of downloaded files - run: ls -lR - - - name: Device scripts permissions - run: | - chmod +x ./output/device-install.sh - chmod +x ./output/device-update.sh - - - name: Zip firmware - run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output - - - uses: actions/download-artifact@v5 - with: - pattern: debug-elfs-*-${{ needs.version.outputs.long }}.zip - merge-multiple: true - path: ./elfs - - - name: Zip debug elfs - run: zip -j -9 -r ./debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./elfs - - # For diagnostics - - name: Display structure of downloaded files - run: ls -lR - - - name: Add bins and debug elfs to GitHub Release - # Only run when targeting master branch with workflow_dispatch - if: ${{ github.ref_name == 'master' }} - run: | - gh release upload v${{ needs.version.outputs.long }} ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip - gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - publish-firmware: - runs-on: ubuntu-24.04 - if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' && inputs.target != '' }} - needs: [release-firmware, version] - env: - targets: |- - esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32 - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.x - - - uses: actions/download-artifact@v5 - with: - pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }} - merge-multiple: true - path: ./publish - - - name: Publish firmware to meshtastic.github.io - uses: peaceiris/actions-gh-pages@v4 - env: - # On event/* branches, use the event name as the destination prefix - DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }} - with: - deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }} - external_repository: meshtastic/meshtastic.github.io - publish_branch: master - publish_dir: ./publish - destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }} - keep_files: true - user_name: github-actions[bot] - user_email: github-actions[bot]@users.noreply.github.com - commit_message: ${{ needs.version.outputs.long }} - enable_jekyll: true diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index f61e314a7..812990eca 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -29,17 +29,10 @@ jobs: setup: if: github.repository == 'meshtastic/firmware' strategy: - fail-fast: false + fail-fast: true matrix: arch: - - esp32 - - esp32s3 - - esp32c3 - - esp32c6 - - nrf52840 - - rp2040 - - rp2350 - - stm32 + - all - check runs-on: ubuntu-24.04 steps: @@ -59,19 +52,13 @@ jobs: if [[ "$GITHUB_HEAD_REF" == "" ]]; then TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}}) else - TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} pr) + TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level pr) fi - echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS" - echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT + echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF" + echo "${{matrix.arch}}=$TARGETS" >> $GITHUB_OUTPUT + echo "$TARGETS" >> $GITHUB_STEP_SUMMARY outputs: - esp32: ${{ steps.jsonStep.outputs.esp32 }} - esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }} - esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }} - esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }} - nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }} - rp2040: ${{ steps.jsonStep.outputs.rp2040 }} - rp2350: ${{ steps.jsonStep.outputs.rp2350 }} - stm32: ${{ steps.jsonStep.outputs.stm32 }} + all: ${{ steps.jsonStep.outputs.all }} check: ${{ steps.jsonStep.outputs.check }} version: @@ -94,7 +81,8 @@ jobs: needs: setup strategy: fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.check) }} + matrix: + check: ${{ fromJson(needs.setup.outputs.check) }} runs-on: ubuntu-latest if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }} @@ -103,96 +91,20 @@ jobs: - name: Build base id: base uses: ./.github/actions/setup-base - - name: Check ${{ matrix.board }} - run: bin/check-all.sh ${{ matrix.board }} + - name: Check ${{ matrix.check.board }} + run: bin/check-all.sh ${{ matrix.check.board }} - build-esp32: + build: needs: [setup, version] strategy: fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32) }} + matrix: + build: ${{ fromJson(needs.setup.outputs.all) }} uses: ./.github/workflows/build_firmware.yml with: version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32 - - build-esp32s3: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32s3 - - build-esp32c3: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c3 - - build-esp32c6: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c6 - - build-nrf52840: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: nrf52840 - - build-rp2040: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.rp2040) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2040 - - build-rp2350: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.rp2350) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2350 - - build-stm32: - needs: [setup, version] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup.outputs.stm32) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: stm32 + pio_env: ${{ matrix.build.board }} + platform: ${{ matrix.build.platform }} build-debian-src: if: github.repository == 'meshtastic/firmware' @@ -203,7 +115,7 @@ jobs: secrets: inherit package-pio-deps-native-tft: - if: ${{ github.event_name == 'workflow_dispatch' }} + if: ${{ github.repository == 'meshtastic/firmware' && github.event_name == 'workflow_dispatch' }} uses: ./.github/workflows/package_pio_deps.yml with: pio_env: native-tft @@ -288,18 +200,7 @@ jobs: - rp2350 - stm32 runs-on: ubuntu-latest - needs: - [ - version, - build-esp32, - build-esp32s3, - build-esp32c3, - build-esp32c6, - build-nrf52840, - build-rp2040, - build-rp2350, - build-stm32, - ] + needs: [version, build] steps: - name: Checkout code uses: actions/checkout@v5 diff --git a/.github/workflows/merge_queue.yml b/.github/workflows/merge_queue.yml index 7f397ce18..79e8b0803 100644 --- a/.github/workflows/merge_queue.yml +++ b/.github/workflows/merge_queue.yml @@ -7,23 +7,13 @@ on: # Merge group is a special trigger that is used to trigger the workflow when a merge group is created. merge_group: -env: - FAIL_FAST_PER_ARCH: true - jobs: setup: strategy: fail-fast: true matrix: arch: - - esp32 - - esp32s3 - - esp32c3 - - esp32c6 - - nrf52840 - - rp2040 - - rp2350 - - stm32 + - all - check runs-on: ubuntu-24.04 steps: @@ -39,19 +29,12 @@ jobs: if [[ "$GITHUB_HEAD_REF" == "" ]]; then TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}}) else - TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} pr) + TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level pr) fi - echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS" - echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT + echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF" + echo "${{matrix.arch}}=$TARGETS" >> $GITHUB_OUTPUT outputs: - esp32: ${{ steps.jsonStep.outputs.esp32 }} - esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }} - esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }} - esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }} - nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }} - rp2040: ${{ steps.jsonStep.outputs.rp2040 }} - rp2350: ${{ steps.jsonStep.outputs.rp2350 }} - stm32: ${{ steps.jsonStep.outputs.stm32 }} + all: ${{ steps.jsonStep.outputs.all }} check: ${{ steps.jsonStep.outputs.check }} version: @@ -73,7 +56,8 @@ jobs: needs: setup strategy: fail-fast: true - matrix: ${{ fromJson(needs.setup.outputs.check) }} + matrix: + check: ${{ fromJson(needs.setup.outputs.check) }} runs-on: ubuntu-latest if: ${{ github.event_name != 'workflow_dispatch' }} @@ -82,96 +66,19 @@ jobs: - name: Build base id: base uses: ./.github/actions/setup-base - - name: Check ${{ matrix.board }} - run: bin/check-all.sh ${{ matrix.board }} + - name: Check ${{ matrix.check.board }} + run: bin/check-all.sh ${{ matrix.check.board }} - build-esp32: + build: needs: [setup, version] strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.esp32) }} + matrix: + build: ${{ fromJson(needs.setup.outputs.all) }} uses: ./.github/workflows/build_firmware.yml with: version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32 - - build-esp32s3: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32s3 - - build-esp32c3: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c3 - - build-esp32c6: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: esp32c6 - - build-nrf52840: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: nrf52840 - - build-rp2040: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.rp2040) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2040 - - build-rp2350: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.rp2350) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: rp2350 - - build-stm32: - needs: [setup, version] - strategy: - fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }} - matrix: ${{ fromJson(needs.setup.outputs.stm32) }} - uses: ./.github/workflows/build_firmware.yml - with: - version: ${{ needs.version.outputs.long }} - pio_env: ${{ matrix.board }} - platform: stm32 + pio_env: ${{ matrix.build.board }} + platform: ${{ matrix.build.platform }} build-debian-src: if: github.repository == 'meshtastic/firmware' @@ -260,18 +167,7 @@ jobs: - rp2350 - stm32 runs-on: ubuntu-latest - needs: - [ - version, - build-esp32, - build-esp32s3, - build-esp32c3, - build-esp32c6, - build-nrf52840, - build-rp2040, - build-rp2350, - build-stm32, - ] + needs: [version, build] steps: - name: Checkout code uses: actions/checkout@v5 diff --git a/bin/generate_ci_matrix.py b/bin/generate_ci_matrix.py index aaa76aa45..b4c18c05b 100755 --- a/bin/generate_ci_matrix.py +++ b/bin/generate_ci_matrix.py @@ -1,28 +1,32 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """Generate the CI matrix.""" +import argparse import json -import sys -import random import re from platformio.project.config import ProjectConfig -options = sys.argv[1:] +parser = argparse.ArgumentParser(description="Generate the CI matrix") +parser.add_argument("platform", help="Platform to build for") +parser.add_argument( + "--level", + choices=["extra", "pr"], + nargs="*", + default=[], + help="Board level to build for (omit for full release boards)", +) +args = parser.parse_args() outlist = [] -if len(options) < 1: - print(json.dumps(outlist)) - exit(1) - cfg = ProjectConfig.get_instance() pio_envs = cfg.envs() # Gather all PlatformIO environments for filtering later all_envs = [] for pio_env in pio_envs: - env_build_flags = cfg.get(f"env:{pio_env}", 'build_flags') + env_build_flags = cfg.get(f"env:{pio_env}", "build_flags") env_platform = None for flag in env_build_flags: # Extract the platform from the build flags @@ -37,36 +41,35 @@ for pio_env in pio_envs: exit(1) # Store env details as a dictionary, and add to 'all_envs' list env = { - 'name': pio_env, - 'platform': env_platform, - 'board_level': cfg.get(f"env:{pio_env}", 'board_level', default=None), - 'board_check': bool(cfg.get(f"env:{pio_env}", 'board_check', default=False)) + "ci": {"board": pio_env, "platform": env_platform}, + "board_level": cfg.get(f"env:{pio_env}", "board_level", default=None), + "board_check": bool(cfg.get(f"env:{pio_env}", "board_check", default=False)), } all_envs.append(env) # Filter outputs based on options # Check is mutually exclusive with other options (except 'pr') -if "check" in options: +if "check" in args.platform: for env in all_envs: - if env['board_check']: - if "pr" in options: - if env['board_level'] == 'pr': - outlist.append(env['name']) + if env["board_check"]: + if "pr" in args.level: + if env["board_level"] == "pr": + outlist.append(env["ci"]) else: - outlist.append(env['name']) + outlist.append(env["ci"]) # Filter (non-check) builds by platform else: for env in all_envs: - if options[0] == env['platform']: + if args.platform == env["ci"]["platform"] or args.platform == "all": # Always include board_level = 'pr' - if env['board_level'] == 'pr': - outlist.append(env['name']) + if env["board_level"] == "pr": + outlist.append(env["ci"]) # Include board_level = 'extra' when requested - elif "extra" in options and env['board_level'] == "extra": - outlist.append(env['name']) + elif "extra" in args.level and env["board_level"] == "extra": + outlist.append(env["ci"]) # If no board level is specified, include in release builds (not PR) - elif "pr" not in options and not env['board_level']: - outlist.append(env['name']) + elif "pr" not in args.level and not env["board_level"]: + outlist.append(env["ci"]) # Return as a JSON list print(json.dumps(outlist)) diff --git a/variants/native/portduino-buildroot/platformio.ini b/variants/native/portduino-buildroot/platformio.ini index d1bd39e10..a3d0f4639 100644 --- a/variants/native/portduino-buildroot/platformio.ini +++ b/variants/native/portduino-buildroot/platformio.ini @@ -4,5 +4,6 @@ extends = portduino_base ; environment variable in the buildroot environment. build_flags = ${portduino_base.build_flags} -O0 -I variants/native/portduino-buildroot board = buildroot +board_level = extra lib_deps = ${portduino_base.lib_deps} build_src_filter = ${portduino_base.build_src_filter} \ No newline at end of file diff --git a/variants/native/portduino/platformio.ini b/variants/native/portduino/platformio.ini index 61eadb459..2ccdfbbfc 100644 --- a/variants/native/portduino/platformio.ini +++ b/variants/native/portduino/platformio.ini @@ -3,6 +3,7 @@ extends = portduino_base build_flags = ${portduino_base.build_flags} -I variants/native/portduino -I /usr/include board = cross_platform +board_level = extra lib_deps = ${portduino_base.lib_deps} melopero/Melopero RV3028@^1.1.0 @@ -50,7 +51,6 @@ build_type = release lib_deps = ${native_base.lib_deps} ${device-ui_base.lib_deps} -board_level = extra build_flags = ${native_base.build_flags} -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -D RAM_SIZE=8192 -D USE_FRAMEBUFFER=1 @@ -79,7 +79,6 @@ build_type = debug lib_deps = ${native_base.lib_deps} ${device-ui_base.lib_deps} -board_level = extra build_flags = ${native_base.build_flags} -O0 -fsanitize=address -lX11 -linput -lxkbcommon -D DEBUG_HEAP -D RAM_SIZE=16384 From 68a2c4adda4236bcc3e260751617b5ca2106200d Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 7 Oct 2025 16:11:36 +1100 Subject: [PATCH 109/166] Run Integration test in simulator mode (#8232) (#8242) Co-authored-by: Jonathan Bennett --- .github/workflows/test_native.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 6b788f4c7..9cf1c9e53 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -40,7 +40,7 @@ jobs: - name: Integration test run: | - .pio/build/coverage/program & + .pio/build/coverage/program -s & PID=$! timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done" echo "Simulator started, launching python test..." From b214f09ca1b8b63df62ee8733d7d4138ff6b3979 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 16:34:00 +1100 Subject: [PATCH 110/166] Update meshtastic/web to v2.6.6 (#7583) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- bin/web.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/web.version b/bin/web.version index e46a05b19..952f449f1 100644 --- a/bin/web.version +++ b/bin/web.version @@ -1 +1 @@ -2.6.4 \ No newline at end of file +2.6.6 \ No newline at end of file From b696e083f39dc76b3dd364838671ae6881d74c83 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 7 Oct 2025 00:37:04 -0500 Subject: [PATCH 111/166] Log antispam (#8241) * less power spam * Don't warn about the first 4 GPS checksum failures --- src/Power.cpp | 7 +++++-- src/gps/GPS.cpp | 8 ++++++-- src/power.h | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 7de82b8d6..bb5d16d10 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -828,8 +828,11 @@ void Power::readPowerStatus() // Notify any status instances that are observing us const PowerStatus powerStatus2 = PowerStatus(hasBattery, usbPowered, isChargingNow, batteryVoltageMv, batteryChargePercent); - LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d", powerStatus2.getHasUSB(), powerStatus2.getIsCharging(), - powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent()); + if (millis() > lastLogTime + 50 * 1000) { + LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d", powerStatus2.getHasUSB(), + powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent()); + lastLogTime = millis(); + } newStatus.notifyObservers(&powerStatus2); #ifdef DEBUG_HEAP if (lastheap != memGet.getFreeHeap()) { diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 0487d1fea..36ec7c580 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1589,8 +1589,12 @@ bool GPS::lookForLocation() #ifndef TINYGPS_OPTION_NO_STATISTICS if (reader.failedChecksum() > lastChecksumFailCount) { - LOG_WARN("%u new GPS checksum failures, for a total of %u", reader.failedChecksum() - lastChecksumFailCount, - reader.failedChecksum()); +// In a GPS_DEBUG build we want to log all of these. In production, we only care if there are many of them. +#ifndef GPS_DEBUG + if (reader.failedChecksum() > 4) +#endif + LOG_WARN("%u new GPS checksum failures, for a total of %u", reader.failedChecksum() - lastChecksumFailCount, + reader.failedChecksum()); lastChecksumFailCount = reader.failedChecksum(); } #endif diff --git a/src/power.h b/src/power.h index 23eb95064..cdbdd3ea0 100644 --- a/src/power.h +++ b/src/power.h @@ -138,6 +138,7 @@ class Power : private concurrency::OSThread void reboot(); // open circuit voltage lookup table uint8_t low_voltage_counter; + int32_t lastLogTime = 0; #ifdef DEBUG_HEAP uint32_t lastheap; #endif From 1d5b3438363190226e5bb294f404766ab12299ef Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 16:56:13 +1100 Subject: [PATCH 112/166] Update meshtastic/device-ui digest to e564d78 (#8235) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 4ae2da54f..2e101a8a2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -120,7 +120,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/f920b1273df750c2e3e01385d3ba30553b913afa.zip + https://github.com/meshtastic/device-ui/archive/e564d78ae1a7e9a225aaf4a73b1cb84c549f510f.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From 668cc9fd64513fc41b94627bd6fc7c7ec3b69e63 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 7 Oct 2025 05:58:39 -0500 Subject: [PATCH 113/166] Do slightly better at threading the search for GPS hardware (#8240) * Do slightly better at threading the search for GPS hardware * Formatting and minor logic fix * Remove now-spam GPS Log messages --------- Co-authored-by: Ben Meadors --- src/gps/GPS.cpp | 316 ++++++++++++++++++++++++++---------------------- src/gps/GPS.h | 2 + 2 files changed, 176 insertions(+), 142 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 36ec7c580..e70eed362 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -506,10 +506,9 @@ bool GPS::setup() delay(1000); #endif if (probeTries < GPS_PROBETRIES) { - LOG_DEBUG("Probe for GPS at %d", serialSpeeds[speedSelect]); gnssModel = probe(serialSpeeds[speedSelect]); if (gnssModel == GNSS_MODEL_UNKNOWN) { - if (++speedSelect == array_count(serialSpeeds)) { + if (currentStep == 0 && ++speedSelect == array_count(serialSpeeds)) { speedSelect = 0; ++probeTries; } @@ -518,10 +517,9 @@ bool GPS::setup() // Rare Serial Speeds #ifndef CONFIG_IDF_TARGET_ESP32C6 if (probeTries == GPS_PROBETRIES) { - LOG_DEBUG("Probe for GPS at %d", rareSerialSpeeds[speedSelect]); gnssModel = probe(rareSerialSpeeds[speedSelect]); if (gnssModel == GNSS_MODEL_UNKNOWN) { - if (++speedSelect == array_count(rareSerialSpeeds)) { + if (currentStep == 0 && ++speedSelect == array_count(rareSerialSpeeds)) { LOG_WARN("Give up on GPS probe and set to %d", GPS_BAUDRATE); return true; } @@ -1094,7 +1092,7 @@ int32_t GPS::runOnce() return disable(); } if (!setup()) - return 2000; // Setup failed, re-run in two seconds + return currentDelay; // Setup failed, re-run in two seconds // We have now loaded our saved preferences from flash if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) { @@ -1218,163 +1216,197 @@ static const char *DETECTED_MESSAGE = "%s detected"; GnssModel_t GPS::probe(int serialSpeed) { + uint8_t buffer[768] = {0}; + + switch (currentStep) { + case 0: { #if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL) - _serial_gps->end(); - _serial_gps->begin(serialSpeed); + _serial_gps->end(); + _serial_gps->begin(serialSpeed); #elif defined(ARCH_RP2040) - _serial_gps->end(); - _serial_gps->setFIFOSize(256); - _serial_gps->begin(serialSpeed); + _serial_gps->end(); + _serial_gps->setFIFOSize(256); + _serial_gps->begin(serialSpeed); #else - if (_serial_gps->baudRate() != serialSpeed) { - LOG_DEBUG("Set Baud to %i", serialSpeed); - _serial_gps->updateBaudRate(serialSpeed); - } + if (_serial_gps->baudRate() != serialSpeed) { + LOG_DEBUG("Set GPS Baud to %i", serialSpeed); + _serial_gps->updateBaudRate(serialSpeed); + } #endif - memset(&ublox_info, 0, sizeof(ublox_info)); - uint8_t buffer[768] = {0}; - delay(100); + memset(&ublox_info, 0, sizeof(ublox_info)); + delay(100); - // Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices) - _serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n"); - delay(20); - // Close NMEA sequences on Ublox - _serial_gps->write("$PUBX,40,GLL,0,0,0,0,0,0*5C\r\n"); - _serial_gps->write("$PUBX,40,GSV,0,0,0,0,0,0*59\r\n"); - _serial_gps->write("$PUBX,40,VTG,0,0,0,0,0,0*5E\r\n"); - delay(20); - // Close NMEA sequences on CM121 - _serial_gps->write("$CFGMSG,0,1,0,1*1B\r\n"); - _serial_gps->write("$CFGMSG,0,2,0,1*18\r\n"); - _serial_gps->write("$CFGMSG,0,3,0,1*19\r\n"); - delay(20); - - // Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A,or CM121 - std::vector unicore = { - {"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}, {"CM121", "CM121", GNSS_MODEL_CM121}}; - PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500); - - std::vector atgm = { - {"ATGM336H", "$GPTXT,01,01,02,HW=ATGM336H", GNSS_MODEL_ATGM336H}, - /* ATGM332D series (-11(GPS), -21(BDS), -31(GPS+BDS), -51(GPS+GLONASS), -71-0(GPS+BDS+GLONASS)) based on AT6558 */ - {"ATGM332D", "$GPTXT,01,01,02,HW=ATGM332D", GNSS_MODEL_ATGM336H}}; - PROBE_FAMILY("ATGM33xx Family", "$PCAS06,1*1A", atgm, 500); - - /* Airoha (Mediatek) AG3335A/M/S, A3352Q, Quectel L89 2.0, SimCom SIM65M */ - _serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF to reduce volume - _serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF to reduce volume - _serial_gps->write("$PAIR513*3D\r\n"); // save configuration - std::vector airoha = {{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335}, - {"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352}, - {"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352}}; - PROBE_FAMILY("Airoha Family", "$PAIR021*39", airoha, 1000); - - PROBE_SIMPLE("LC86", "$PQTMVERNO*58", "$PQTMVERNO,LC86", GNSS_MODEL_AG3352, 500); - PROBE_SIMPLE("L76K", "$PCAS06,0*1B", "$GPTXT,01,01,02,SW=", GNSS_MODEL_MTK, 500); - - // Close all NMEA sentences, valid for MTK3333 and MTK3339 platforms - _serial_gps->write("$PMTK514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2E\r\n"); - delay(20); - std::vector mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B}, {"PA1010D", "1010D", GNSS_MODEL_MTK_PA1010D}, - {"PA1616S", "1616S", GNSS_MODEL_MTK_PA1616S}, {"LS20031", "MC-1513", GNSS_MODEL_MTK_L76B}, - {"L96", "Quectel-L96", GNSS_MODEL_MTK_L76B}, {"L80-R", "_3337_", GNSS_MODEL_MTK_L76B}, - {"L80", "_3339_", GNSS_MODEL_MTK_L76B}}; - - PROBE_FAMILY("MTK Family", "$PMTK605*31", mtk, 500); - - uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00}; - UBXChecksum(cfg_rate, sizeof(cfg_rate)); - clearBuffer(); - _serial_gps->write(cfg_rate, sizeof(cfg_rate)); - // Check that the returned response class and message ID are correct - GPS_RESPONSE response = getACK(0x06, 0x08, 750); - if (response == GNSS_RESPONSE_NONE) { - LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed); + // Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices) + _serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n"); + delay(20); + // Close NMEA sequences on Ublox + _serial_gps->write("$PUBX,40,GLL,0,0,0,0,0,0*5C\r\n"); + _serial_gps->write("$PUBX,40,GSV,0,0,0,0,0,0*59\r\n"); + _serial_gps->write("$PUBX,40,VTG,0,0,0,0,0,0*5E\r\n"); + delay(20); + // Close NMEA sequences on CM121 + _serial_gps->write("$CFGMSG,0,1,0,1*1B\r\n"); + _serial_gps->write("$CFGMSG,0,2,0,1*18\r\n"); + _serial_gps->write("$CFGMSG,0,3,0,1*19\r\n"); + currentDelay = 20; + currentStep = 1; return GNSS_MODEL_UNKNOWN; - } else if (response == GNSS_RESPONSE_FRAME_ERRORS) { - LOG_INFO("UBlox Frame Errors (baudrate %d)", serialSpeed); } + case 1: { - memset(buffer, 0, sizeof(buffer)); - uint8_t _message_MONVER[8] = { - 0xB5, 0x62, // Sync message for UBX protocol - 0x0A, 0x04, // Message class and ID (UBX-MON-VER) - 0x00, 0x00, // Length of payload (we're asking for an answer, so no payload) - 0x00, 0x00 // Checksum - }; - // Get Ublox gnss module hardware and software info - UBXChecksum(_message_MONVER, sizeof(_message_MONVER)); - clearBuffer(); - _serial_gps->write(_message_MONVER, sizeof(_message_MONVER)); + // Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A,or CM121 + std::vector unicore = { + {"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}, {"CM121", "CM121", GNSS_MODEL_CM121}}; + PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500); + currentDelay = 20; + currentStep = 2; + return GNSS_MODEL_UNKNOWN; + } + case 2: { + std::vector atgm = { + {"ATGM336H", "$GPTXT,01,01,02,HW=ATGM336H", GNSS_MODEL_ATGM336H}, + /* ATGM332D series (-11(GPS), -21(BDS), -31(GPS+BDS), -51(GPS+GLONASS), -71-0(GPS+BDS+GLONASS)) based on AT6558 */ + {"ATGM332D", "$GPTXT,01,01,02,HW=ATGM332D", GNSS_MODEL_ATGM336H}}; + PROBE_FAMILY("ATGM33xx Family", "$PCAS06,1*1A", atgm, 500); + currentDelay = 20; + currentStep = 3; + return GNSS_MODEL_UNKNOWN; + } + case 3: { + /* Airoha (Mediatek) AG3335A/M/S, A3352Q, Quectel L89 2.0, SimCom SIM65M */ + _serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF to reduce volume + _serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF to reduce volume + _serial_gps->write("$PAIR513*3D\r\n"); // save configuration + std::vector airoha = {{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335}, + {"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352}, + {"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352}}; + PROBE_FAMILY("Airoha Family", "$PAIR021*39", airoha, 1000); + currentDelay = 20; + currentStep = 4; + return GNSS_MODEL_UNKNOWN; + } + case 4: { + PROBE_SIMPLE("LC86", "$PQTMVERNO*58", "$PQTMVERNO,LC86", GNSS_MODEL_AG3352, 500); + PROBE_SIMPLE("L76K", "$PCAS06,0*1B", "$GPTXT,01,01,02,SW=", GNSS_MODEL_MTK, 500); + currentDelay = 20; + currentStep = 5; + return GNSS_MODEL_UNKNOWN; + } + case 5: { - uint16_t len = getACK(buffer, sizeof(buffer), 0x0A, 0x04, 1200); - if (len) { - uint16_t position = 0; - for (int i = 0; i < 30; i++) { - ublox_info.swVersion[i] = buffer[position]; - position++; - } - for (int i = 0; i < 10; i++) { - ublox_info.hwVersion[i] = buffer[position]; - position++; - } + // Close all NMEA sentences, valid for MTK3333 and MTK3339 platforms + _serial_gps->write("$PMTK514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2E\r\n"); + delay(20); + std::vector mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B}, {"PA1010D", "1010D", GNSS_MODEL_MTK_PA1010D}, + {"PA1616S", "1616S", GNSS_MODEL_MTK_PA1616S}, {"LS20031", "MC-1513", GNSS_MODEL_MTK_L76B}, + {"L96", "Quectel-L96", GNSS_MODEL_MTK_L76B}, {"L80-R", "_3337_", GNSS_MODEL_MTK_L76B}, + {"L80", "_3339_", GNSS_MODEL_MTK_L76B}}; - while (len >= position + 30) { - for (int i = 0; i < 30; i++) { - ublox_info.extension[ublox_info.extensionNo][i] = buffer[position]; - position++; - } - ublox_info.extensionNo++; - if (ublox_info.extensionNo > 9) - break; - } - - LOG_DEBUG("Module Info : "); - LOG_DEBUG("Soft version: %s", ublox_info.swVersion); - LOG_DEBUG("Hard version: %s", ublox_info.hwVersion); - LOG_DEBUG("Extensions:%d", ublox_info.extensionNo); - for (int i = 0; i < ublox_info.extensionNo; i++) { - LOG_DEBUG(" %s", ublox_info.extension[i]); + PROBE_FAMILY("MTK Family", "$PMTK605*31", mtk, 500); + currentDelay = 20; + currentStep = 6; + return GNSS_MODEL_UNKNOWN; + } + case 6: { + uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00}; + UBXChecksum(cfg_rate, sizeof(cfg_rate)); + clearBuffer(); + _serial_gps->write(cfg_rate, sizeof(cfg_rate)); + // Check that the returned response class and message ID are correct + GPS_RESPONSE response = getACK(0x06, 0x08, 750); + if (response == GNSS_RESPONSE_NONE) { + LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed); + currentDelay = 2000; + currentStep = 0; + return GNSS_MODEL_UNKNOWN; + } else if (response == GNSS_RESPONSE_FRAME_ERRORS) { + LOG_INFO("UBlox Frame Errors (baudrate %d)", serialSpeed); } memset(buffer, 0, sizeof(buffer)); + uint8_t _message_MONVER[8] = { + 0xB5, 0x62, // Sync message for UBX protocol + 0x0A, 0x04, // Message class and ID (UBX-MON-VER) + 0x00, 0x00, // Length of payload (we're asking for an answer, so no payload) + 0x00, 0x00 // Checksum + }; + // Get Ublox gnss module hardware and software info + UBXChecksum(_message_MONVER, sizeof(_message_MONVER)); + clearBuffer(); + _serial_gps->write(_message_MONVER, sizeof(_message_MONVER)); - // tips: extensionNo field is 0 on some 6M GNSS modules - for (int i = 0; i < ublox_info.extensionNo; ++i) { - if (!strncmp(ublox_info.extension[i], "MOD=", 4)) { - strncpy((char *)buffer, &(ublox_info.extension[i][4]), sizeof(buffer)); - } else if (!strncmp(ublox_info.extension[i], "PROTVER", 7)) { - char *ptr = nullptr; - memset(buffer, 0, sizeof(buffer)); - strncpy((char *)buffer, &(ublox_info.extension[i][8]), sizeof(buffer)); - LOG_DEBUG("Protocol Version:%s", (char *)buffer); - if (strlen((char *)buffer)) { - ublox_info.protocol_version = strtoul((char *)buffer, &ptr, 10); - LOG_DEBUG("ProtVer=%d", ublox_info.protocol_version); - } else { - ublox_info.protocol_version = 0; + uint16_t len = getACK(buffer, sizeof(buffer), 0x0A, 0x04, 1200); + if (len) { + uint16_t position = 0; + for (int i = 0; i < 30; i++) { + ublox_info.swVersion[i] = buffer[position]; + position++; + } + for (int i = 0; i < 10; i++) { + ublox_info.hwVersion[i] = buffer[position]; + position++; + } + + while (len >= position + 30) { + for (int i = 0; i < 30; i++) { + ublox_info.extension[ublox_info.extensionNo][i] = buffer[position]; + position++; + } + ublox_info.extensionNo++; + if (ublox_info.extensionNo > 9) + break; + } + + LOG_DEBUG("Module Info : "); + LOG_DEBUG("Soft version: %s", ublox_info.swVersion); + LOG_DEBUG("Hard version: %s", ublox_info.hwVersion); + LOG_DEBUG("Extensions:%d", ublox_info.extensionNo); + for (int i = 0; i < ublox_info.extensionNo; i++) { + LOG_DEBUG(" %s", ublox_info.extension[i]); + } + + memset(buffer, 0, sizeof(buffer)); + + // tips: extensionNo field is 0 on some 6M GNSS modules + for (int i = 0; i < ublox_info.extensionNo; ++i) { + if (!strncmp(ublox_info.extension[i], "MOD=", 4)) { + strncpy((char *)buffer, &(ublox_info.extension[i][4]), sizeof(buffer)); + } else if (!strncmp(ublox_info.extension[i], "PROTVER", 7)) { + char *ptr = nullptr; + memset(buffer, 0, sizeof(buffer)); + strncpy((char *)buffer, &(ublox_info.extension[i][8]), sizeof(buffer)); + LOG_DEBUG("Protocol Version:%s", (char *)buffer); + if (strlen((char *)buffer)) { + ublox_info.protocol_version = strtoul((char *)buffer, &ptr, 10); + LOG_DEBUG("ProtVer=%d", ublox_info.protocol_version); + } else { + ublox_info.protocol_version = 0; + } } } - } - if (strncmp(ublox_info.hwVersion, "00040007", 8) == 0) { - LOG_INFO(DETECTED_MESSAGE, "U-blox 6", "6"); - return GNSS_MODEL_UBLOX6; - } else if (strncmp(ublox_info.hwVersion, "00070000", 8) == 0) { - LOG_INFO(DETECTED_MESSAGE, "U-blox 7", "7"); - return GNSS_MODEL_UBLOX7; - } else if (strncmp(ublox_info.hwVersion, "00080000", 8) == 0) { - LOG_INFO(DETECTED_MESSAGE, "U-blox 8", "8"); - return GNSS_MODEL_UBLOX8; - } else if (strncmp(ublox_info.hwVersion, "00190000", 8) == 0) { - LOG_INFO(DETECTED_MESSAGE, "U-blox 9", "9"); - return GNSS_MODEL_UBLOX9; - } else if (strncmp(ublox_info.hwVersion, "000A0000", 8) == 0) { - LOG_INFO(DETECTED_MESSAGE, "U-blox 10", "10"); - return GNSS_MODEL_UBLOX10; + if (strncmp(ublox_info.hwVersion, "00040007", 8) == 0) { + LOG_INFO(DETECTED_MESSAGE, "U-blox 6", "6"); + return GNSS_MODEL_UBLOX6; + } else if (strncmp(ublox_info.hwVersion, "00070000", 8) == 0) { + LOG_INFO(DETECTED_MESSAGE, "U-blox 7", "7"); + return GNSS_MODEL_UBLOX7; + } else if (strncmp(ublox_info.hwVersion, "00080000", 8) == 0) { + LOG_INFO(DETECTED_MESSAGE, "U-blox 8", "8"); + return GNSS_MODEL_UBLOX8; + } else if (strncmp(ublox_info.hwVersion, "00190000", 8) == 0) { + LOG_INFO(DETECTED_MESSAGE, "U-blox 9", "9"); + return GNSS_MODEL_UBLOX9; + } else if (strncmp(ublox_info.hwVersion, "000A0000", 8) == 0) { + LOG_INFO(DETECTED_MESSAGE, "U-blox 10", "10"); + return GNSS_MODEL_UBLOX10; + } } } + } LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed); + currentDelay = 2000; + currentStep = 0; return GNSS_MODEL_UNKNOWN; } diff --git a/src/gps/GPS.h b/src/gps/GPS.h index cba767460..f3bcf37f5 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -151,6 +151,8 @@ class GPS : private concurrency::OSThread TinyGPSPlus reader; uint8_t fixQual = 0; // fix quality from GPGGA uint32_t lastChecksumFailCount = 0; + uint8_t currentStep = 0; + int32_t currentDelay = 2000; #ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS // (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field From 5bcc47dddb6aa339e51651a05ff7f2bdc6e27bd2 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 7 Oct 2025 22:00:09 +1100 Subject: [PATCH 114/166] Revert "develop --> Master" (#8244) --- .github/workflows/main_matrix.yml | 6 ++ src/Power.cpp | 7 +- src/gps/GPS.cpp | 8 +-- src/mesh/FloodingRouter.cpp | 102 ++++++++++++++++++----------- src/mesh/FloodingRouter.h | 15 ++--- src/mesh/NextHopRouter.cpp | 105 +++++++++++++++--------------- src/mesh/NextHopRouter.h | 6 +- src/mesh/PacketHistory.cpp | 1 + src/mesh/http/ContentHandler.cpp | 5 -- src/mesh/http/WebServer.cpp | 35 +--------- src/mesh/http/WebServer.h | 4 -- src/modules/TraceRouteModule.cpp | 64 ------------------ src/modules/TraceRouteModule.h | 6 -- src/power.h | 1 - 14 files changed, 136 insertions(+), 229 deletions(-) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 887bf3081..812990eca 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -27,6 +27,7 @@ on: jobs: setup: + if: github.repository == 'meshtastic/firmware' strategy: fail-fast: true matrix: @@ -41,6 +42,10 @@ jobs: python-version: 3.x cache: pip - run: pip install -U platformio + - name: Uncomment build epoch + shell: bash + run: | + sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini - name: Generate matrix id: jsonStep run: | @@ -57,6 +62,7 @@ jobs: check: ${{ steps.jsonStep.outputs.check }} version: + if: github.repository == 'meshtastic/firmware' runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 diff --git a/src/Power.cpp b/src/Power.cpp index bb5d16d10..7de82b8d6 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -828,11 +828,8 @@ void Power::readPowerStatus() // Notify any status instances that are observing us const PowerStatus powerStatus2 = PowerStatus(hasBattery, usbPowered, isChargingNow, batteryVoltageMv, batteryChargePercent); - if (millis() > lastLogTime + 50 * 1000) { - LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d", powerStatus2.getHasUSB(), - powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent()); - lastLogTime = millis(); - } + LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d", powerStatus2.getHasUSB(), powerStatus2.getIsCharging(), + powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent()); newStatus.notifyObservers(&powerStatus2); #ifdef DEBUG_HEAP if (lastheap != memGet.getFreeHeap()) { diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 36ec7c580..0487d1fea 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1589,12 +1589,8 @@ bool GPS::lookForLocation() #ifndef TINYGPS_OPTION_NO_STATISTICS if (reader.failedChecksum() > lastChecksumFailCount) { -// In a GPS_DEBUG build we want to log all of these. In production, we only care if there are many of them. -#ifndef GPS_DEBUG - if (reader.failedChecksum() > 4) -#endif - LOG_WARN("%u new GPS checksum failures, for a total of %u", reader.failedChecksum() - lastChecksumFailCount, - reader.failedChecksum()); + LOG_WARN("%u new GPS checksum failures, for a total of %u", reader.failedChecksum() - lastChecksumFailCount, + reader.failedChecksum()); lastChecksumFailCount = reader.failedChecksum(); } #endif diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 032be241b..1d8ac247f 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -31,8 +31,33 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) wasSeenRecently(p, true, nullptr, nullptr, &wasUpgraded); // Updates history; returns false when an upgrade is detected // Handle hop_limit upgrade scenario for rebroadcasters - if (wasUpgraded && perhapsHandleUpgradedPacket(p)) { - return true; // we handled it, so stop processing + // isRebroadcaster() is duplicated in perhapsRebroadcast(), but this avoids confusing log messages + if (wasUpgraded && isRebroadcaster() && iface && p->hop_limit > 0) { + // wasSeenRecently() reports false in upgrade cases so we handle replacement before the duplicate short-circuit + // If we overhear a duplicate copy of the packet with more hops left than the one we are waiting to + // rebroadcast, then remove the packet currently sitting in the TX queue and use this one instead. + uint8_t dropThreshold = p->hop_limit; // remove queued packets that have fewer hops remaining + if (iface->removePendingTXPacket(getFrom(p), p->id, dropThreshold)) { + LOG_DEBUG("Processing upgraded packet 0x%08x for rebroadcast with hop limit %d (dropping queued < %d)", p->id, + p->hop_limit, dropThreshold); + + if (nodeDB) + nodeDB->updateFrom(*p); +#if !MESHTASTIC_EXCLUDE_TRACEROUTE + if (traceRouteModule && p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && + p->decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP) + traceRouteModule->processUpgradedPacket(*p); +#endif + + perhapsRebroadcast(p); + + // We already enqueued the improved copy, so make sure the incoming packet stops here. + return true; + } + + // No queue entry was replaced by this upgraded copy, so treat it as a duplicate to avoid + // delivering the same packet to applications/phone twice with different hop limits. + seenRecently = true; } if (seenRecently) { @@ -45,10 +70,8 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) if (isRepeated) { LOG_DEBUG("Repeated reliable tx"); // Check if it's still in the Tx queue, if not, we have to relay it again - if (!findInTxQueue(p->from, p->id)) { - reprocessPacket(p); + if (!findInTxQueue(p->from, p->id)) perhapsRebroadcast(p); - } } else { perhapsCancelDupe(p); } @@ -59,40 +82,6 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) return Router::shouldFilterReceived(p); } -bool FloodingRouter::perhapsHandleUpgradedPacket(const meshtastic_MeshPacket *p) -{ - // isRebroadcaster() is duplicated in perhapsRebroadcast(), but this avoids confusing log messages - if (isRebroadcaster() && iface && p->hop_limit > 0) { - // If we overhear a duplicate copy of the packet with more hops left than the one we are waiting to - // rebroadcast, then remove the packet currently sitting in the TX queue and use this one instead. - uint8_t dropThreshold = p->hop_limit; // remove queued packets that have fewer hops remaining - if (iface->removePendingTXPacket(getFrom(p), p->id, dropThreshold)) { - LOG_DEBUG("Processing upgraded packet 0x%08x for rebroadcast with hop limit %d (dropping queued < %d)", p->id, - p->hop_limit, dropThreshold); - - reprocessPacket(p); - perhapsRebroadcast(p); - - rxDupe++; - // We already enqueued the improved copy, so make sure the incoming packet stops here. - return true; - } - } - - return false; -} - -void FloodingRouter::reprocessPacket(const meshtastic_MeshPacket *p) -{ - if (nodeDB) - nodeDB->updateFrom(*p); -#if !MESHTASTIC_EXCLUDE_TRACEROUTE - if (traceRouteModule && p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && - p->decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP) - traceRouteModule->processUpgradedPacket(*p); -#endif -} - bool FloodingRouter::roleAllowsCancelingDupe(const meshtastic_MeshPacket *p) { if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || @@ -132,6 +121,41 @@ bool FloodingRouter::isRebroadcaster() config.device.rebroadcast_mode != meshtastic_Config_DeviceConfig_RebroadcastMode_NONE; } +void FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) +{ + if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) { + if (p->id != 0) { + if (isRebroadcaster()) { + meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it + + // Use shared logic to determine if hop_limit should be decremented + if (shouldDecrementHopLimit(p)) { + tosend->hop_limit--; // bump down the hop count + } else { + LOG_INFO("favorite-ROUTER/CLIENT_BASE-to-ROUTER/CLIENT_BASE flood: preserving hop_limit"); + } +#if USERPREFS_EVENT_MODE + if (tosend->hop_limit > 2) { + // if we are "correcting" the hop_limit, "correct" the hop_start by the same amount to preserve hops away. + tosend->hop_start -= (tosend->hop_limit - 2); + tosend->hop_limit = 2; + } +#endif + + tosend->next_hop = NO_NEXT_HOP_PREFERENCE; // this should already be the case, but just in case + + LOG_INFO("Rebroadcast received floodmsg"); + // Note: we are careful to resend using the original senders node id + send(tosend); + } else { + LOG_DEBUG("No rebroadcast: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); + } + } else { + LOG_DEBUG("Ignore 0 id broadcast"); + } + } +} + void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index e8a2e9685..eaf71d294 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -27,6 +27,10 @@ */ class FloodingRouter : public Router { + private: + /* Check if we should rebroadcast this packet, and do so if needed */ + void perhapsRebroadcast(const meshtastic_MeshPacket *p); + public: /** * Constructor @@ -55,17 +59,6 @@ class FloodingRouter : public Router */ virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; - /* Check if we should rebroadcast this packet, and do so if needed */ - virtual bool perhapsRebroadcast(const meshtastic_MeshPacket *p) = 0; - - /* Check if we should handle an upgraded packet (with higher hop_limit) - * @return true if we handled it (so stop processing) - */ - bool perhapsHandleUpgradedPacket(const meshtastic_MeshPacket *p); - - /* Call when we receive a packet that needs some reprocessing, but afterwards should be filtered */ - void reprocessPacket(const meshtastic_MeshPacket *p); - // Return false for roles like ROUTER which should always rebroadcast even when we've heard another rebroadcast of // the same packet bool roleAllowsCancelingDupe(const meshtastic_MeshPacket *p); diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index afdb4d096..0461d7eb6 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -43,8 +43,31 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) &wasUpgraded); // Updates history; returns false when an upgrade is detected // Handle hop_limit upgrade scenario for rebroadcasters - if (wasUpgraded && perhapsHandleUpgradedPacket(p)) { - return true; // we handled it, so stop processing + // isRebroadcaster() is duplicated in perhapsRelay(), but this avoids confusing log messages + if (wasUpgraded && isRebroadcaster() && iface && p->hop_limit > 0) { + // Upgrade detection bypasses the duplicate short-circuit so we replace the queued packet before exiting + uint8_t dropThreshold = p->hop_limit; // remove queued packets that have fewer hops remaining + if (iface->removePendingTXPacket(getFrom(p), p->id, dropThreshold)) { + LOG_DEBUG("Processing upgraded packet 0x%08x for relay with hop limit %d (dropping queued < %d)", p->id, p->hop_limit, + dropThreshold); + + if (nodeDB) + nodeDB->updateFrom(*p); +#if !MESHTASTIC_EXCLUDE_TRACEROUTE + if (traceRouteModule && p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && + p->decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP) + traceRouteModule->processUpgradedPacket(*p); +#endif + + perhapsRelay(p); + + // We already enqueued the improved copy, so make sure the incoming packet stops here. + return true; + } + + // No queue entry was replaced by this upgraded copy, so treat it as a duplicate to avoid + // delivering the same packet to applications/phone twice with different hop limits. + seenRecently = true; } if (seenRecently) { @@ -59,20 +82,14 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) if (wasFallback) { LOG_INFO("Fallback to flooding from relay_node=0x%x", p->relay_node); // Check if it's still in the Tx queue, if not, we have to relay it again - if (!findInTxQueue(p->from, p->id)) { - reprocessPacket(p); - perhapsRebroadcast(p); - } + if (!findInTxQueue(p->from, p->id)) + perhapsRelay(p); } else { bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit; // If repeated and not in Tx queue anymore, try relaying again, or if we are the destination, send the ACK again if (isRepeated) { - if (!findInTxQueue(p->from, p->id)) { - reprocessPacket(p); - if (!perhapsRebroadcast(p) && isToUs(p) && p->want_ack) { - sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); - } - } + if (!findInTxQueue(p->from, p->id) && !perhapsRelay(p) && isToUs(p) && p->want_ack) + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); } else if (!weWereNextHop) { perhapsCancelDupe(p); // If it's a dupe, cancel relay if we were not explicitly asked to relay } @@ -90,14 +107,13 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0 || p->decoded.reply_id != 0); if (isAckorReply) { - // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" - // is not 0 (means implicit ACK) and original packet was also relayed by this node, or we sent it directly to the - // destination + // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" is + // not 0 (means implicit ACK) and original packet was also relayed by this node, or we sent it directly to the destination if (p->from != 0) { meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from); if (origTx) { - // Either relayer of ACK was also a relayer of the packet, or we were the *only* relayer and the ACK came - // directly from the destination + // Either relayer of ACK was also a relayer of the packet, or we were the *only* relayer and the ACK came directly + // from the destination bool wasAlreadyRelayer = wasRelayer(p->relay_node, p->decoded.request_id, p->to); bool weWereSoleRelayer = false; bool weWereRelayer = wasRelayer(ourRelayID, p->decoded.request_id, p->to, &weWereSoleRelayer); @@ -118,49 +134,34 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast } } - perhapsRebroadcast(p); + perhapsRelay(p); // handle the packet as normal Router::sniffReceived(p, c); } -/* Check if we should be rebroadcasting this packet if so, do so. */ -bool NextHopRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) +/* Check if we should be relaying this packet if so, do so. */ +bool NextHopRouter::perhapsRelay(const meshtastic_MeshPacket *p) { if (!isToUs(p) && !isFromUs(p) && p->hop_limit > 0) { - if (p->id != 0) { + if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum())) { if (isRebroadcaster()) { - if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum())) { - meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it - LOG_INFO("Rebroadcast received message coming from %x", p->relay_node); + meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it + LOG_INFO("Relaying received message coming from %x", p->relay_node); - // Use shared logic to determine if hop_limit should be decremented - if (shouldDecrementHopLimit(p)) { - tosend->hop_limit--; // bump down the hop count - } else { - LOG_INFO("favorite-ROUTER/CLIENT_BASE-to-ROUTER/CLIENT_BASE rebroadcast: preserving hop_limit"); - } -#if USERPREFS_EVENT_MODE - if (tosend->hop_limit > 2) { - // if we are "correcting" the hop_limit, "correct" the hop_start by the same amount to preserve hops away. - tosend->hop_start -= (tosend->hop_limit - 2); - tosend->hop_limit = 2; - } -#endif - - if (p->next_hop == NO_NEXT_HOP_PREFERENCE) { - FloodingRouter::send(tosend); - } else { - NextHopRouter::send(tosend); - } - - return true; + // Use shared logic to determine if hop_limit should be decremented + if (shouldDecrementHopLimit(p)) { + tosend->hop_limit--; // bump down the hop count + } else { + LOG_INFO("Router/CLIENT_BASE-to-favorite-router/CLIENT_BASE relay: preserving hop_limit"); } + + NextHopRouter::send(tosend); + + return true; } else { - LOG_DEBUG("No rebroadcast: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); + LOG_DEBUG("Not rebroadcasting: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); } - } else { - LOG_DEBUG("Ignore 0 id broadcast"); } } @@ -230,13 +231,13 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key) } } - // Regardless of whether or not we canceled this packet from the txQueue, remove it from our pending list so it - // doesn't get scheduled again. (This is the core of stopRetransmission.) + // Regardless of whether or not we canceled this packet from the txQueue, remove it from our pending list so it doesn't + // get scheduled again. (This is the core of stopRetransmission.) auto numErased = pending.erase(key); assert(numErased == 1); - // When we remove an entry from pending, always be sure to release the copy of the packet that was allocated in the - // call to startRetransmission. + // When we remove an entry from pending, always be sure to release the copy of the packet that was allocated in the call + // to startRetransmission. packetPool.release(p); return true; diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h index c1df3596b..0022644e9 100644 --- a/src/mesh/NextHopRouter.h +++ b/src/mesh/NextHopRouter.h @@ -148,7 +148,7 @@ class NextHopRouter : public FloodingRouter */ uint8_t getNextHop(NodeNum to, uint8_t relay_node); - /** Check if we should be rebroadcasting this packet if so, do so. - * @return true if we did rebroadcast */ - bool perhapsRebroadcast(const meshtastic_MeshPacket *p) override; + /** Check if we should be relaying this packet if so, do so. + * @return true if we did relay */ + bool perhapsRelay(const meshtastic_MeshPacket *p); }; \ No newline at end of file diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index b4af707ae..49d581d9a 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -94,6 +94,7 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd LOG_DEBUG("Packet History - Hop limit upgrade: packet 0x%08x from hop_limit=%d to hop_limit=%d", p->id, found->hop_limit, p->hop_limit); *wasUpgraded = true; + seenRecently = false; // Allow router processing but prevent duplicate app delivery } else if (wasUpgraded) { *wasUpgraded = false; // Initialize to false if not an upgrade } diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 7b7ebb595..f87c6e3b0 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -148,8 +148,6 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) { - if (webServerThread) - webServerThread->markActivity(); LOG_DEBUG("webAPI handleAPIv1FromRadio"); @@ -393,9 +391,6 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res) void handleStatic(HTTPRequest *req, HTTPResponse *res) { - if (webServerThread) - webServerThread->markActivity(); - // Get access to the parameters ResourceParameters *params = req->getParams(); diff --git a/src/mesh/http/WebServer.cpp b/src/mesh/http/WebServer.cpp index 3a264fa5a..bf170de59 100644 --- a/src/mesh/http/WebServer.cpp +++ b/src/mesh/http/WebServer.cpp @@ -49,12 +49,6 @@ Preferences prefs; using namespace httpsserver; #include "mesh/http/ContentHandler.h" -static const uint32_t ACTIVE_THRESHOLD_MS = 5000; -static const uint32_t MEDIUM_THRESHOLD_MS = 30000; -static const int32_t ACTIVE_INTERVAL_MS = 50; -static const int32_t MEDIUM_INTERVAL_MS = 200; -static const int32_t IDLE_INTERVAL_MS = 1000; - static SSLCert *cert; static HTTPSServer *secureServer; static HTTPServer *insecureServer; @@ -181,32 +175,6 @@ WebServerThread::WebServerThread() : concurrency::OSThread("WebServer") if (!config.network.wifi_enabled && !config.network.eth_enabled) { disable(); } - lastActivityTime = millis(); -} - -void WebServerThread::markActivity() -{ - lastActivityTime = millis(); -} - -int32_t WebServerThread::getAdaptiveInterval() -{ - uint32_t currentTime = millis(); - uint32_t timeSinceActivity; - - if (currentTime >= lastActivityTime) { - timeSinceActivity = currentTime - lastActivityTime; - } else { - timeSinceActivity = (UINT32_MAX - lastActivityTime) + currentTime + 1; - } - - if (timeSinceActivity < ACTIVE_THRESHOLD_MS) { - return ACTIVE_INTERVAL_MS; - } else if (timeSinceActivity < MEDIUM_THRESHOLD_MS) { - return MEDIUM_INTERVAL_MS; - } else { - return IDLE_INTERVAL_MS; - } } int32_t WebServerThread::runOnce() @@ -221,7 +189,8 @@ int32_t WebServerThread::runOnce() ESP.restart(); } - return getAdaptiveInterval(); + // Loop every 5ms. + return (5); } void initWebServer() diff --git a/src/mesh/http/WebServer.h b/src/mesh/http/WebServer.h index e7a29a5a7..815d87432 100644 --- a/src/mesh/http/WebServer.h +++ b/src/mesh/http/WebServer.h @@ -10,17 +10,13 @@ void createSSLCert(); class WebServerThread : private concurrency::OSThread { - private: - uint32_t lastActivityTime = 0; public: WebServerThread(); uint32_t requestRestart = 0; - void markActivity(); protected: virtual int32_t runOnce() override; - int32_t getAdaptiveInterval(); }; extern WebServerThread *webServerThread; diff --git a/src/modules/TraceRouteModule.cpp b/src/modules/TraceRouteModule.cpp index 5bdde1919..fc2cc232b 100644 --- a/src/modules/TraceRouteModule.cpp +++ b/src/modules/TraceRouteModule.cpp @@ -21,11 +21,6 @@ void TraceRouteModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtasti { const meshtastic_Data &incoming = p.decoded; - // Update next-hops using returned route - if (incoming.request_id) { - updateNextHops(p, r); - } - // Insert unknown hops if necessary insertUnknownHops(p, r, !incoming.request_id); @@ -158,65 +153,6 @@ void TraceRouteModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtasti } } -void TraceRouteModule::updateNextHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r) -{ - // E.g. if the route is A->B->C->D and we are B, we can set C as next-hop for C and D - // Similarly, if we are C, we can set D as next-hop for D - // If we are A, we can set B as next-hop for B, C and D - - // First check if we were the original sender or in the original route - int8_t nextHopIndex = -1; - if (isToUs(&p)) { - nextHopIndex = 0; // We are the original sender, next hop is first in route - } else { - // Check if we are in the original route - for (uint8_t i = 0; i < r->route_count; i++) { - if (r->route[i] == nodeDB->getNodeNum()) { - nextHopIndex = i + 1; // Next hop is the one after us - break; - } - } - } - - // If we are in the original route, update the next hops - if (nextHopIndex != -1) { - // For every node after us, we can set the next-hop to the first node after us - NodeNum nextHop; - if (nextHopIndex == r->route_count) { - nextHop = p.from; // We are the last in the route, next hop is destination - } else { - nextHop = r->route[nextHopIndex]; - } - - if (nextHop == NODENUM_BROADCAST) { - return; - } - uint8_t nextHopByte = nodeDB->getLastByteOfNodeNum(nextHop); - - // For the rest of the nodes in the route, set their next-hop - // Note: if we are the last in the route, this loop will not run - for (int8_t i = nextHopIndex; i < r->route_count; i++) { - NodeNum targetNode = r->route[i]; - maybeSetNextHop(targetNode, nextHopByte); - } - - // Also set next-hop for the destination node - maybeSetNextHop(p.from, nextHopByte); - } -} - -void TraceRouteModule::maybeSetNextHop(NodeNum target, uint8_t nextHopByte) -{ - if (target == NODENUM_BROADCAST) - return; - - meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(target); - if (node && node->next_hop != nextHopByte) { - LOG_INFO("Updating next-hop for 0x%08x to 0x%02x based on traceroute", target, nextHopByte); - node->next_hop = nextHopByte; - } -} - void TraceRouteModule::processUpgradedPacket(const meshtastic_MeshPacket &mp) { if (mp.which_payload_variant != meshtastic_MeshPacket_decoded_tag || mp.decoded.portnum != meshtastic_PortNum_TRACEROUTE_APP) diff --git a/src/modules/TraceRouteModule.h b/src/modules/TraceRouteModule.h index dac422388..a069f7157 100644 --- a/src/modules/TraceRouteModule.h +++ b/src/modules/TraceRouteModule.h @@ -55,12 +55,6 @@ class TraceRouteModule : public ProtobufModule, // Call to add your ID to the route array of a RouteDiscovery message void appendMyIDandSNR(meshtastic_RouteDiscovery *r, float snr, bool isTowardsDestination, bool SNRonly); - // Update next-hops in the routing table based on the returned route - void updateNextHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r); - - // Helper to update next-hop for a single node - void maybeSetNextHop(NodeNum target, uint8_t nextHopByte); - /* Call to print the route array of a RouteDiscovery message. Set origin to where the request came from. Set dest to the ID of its destination, or NODENUM_BROADCAST if it has not yet arrived there. */ diff --git a/src/power.h b/src/power.h index cdbdd3ea0..23eb95064 100644 --- a/src/power.h +++ b/src/power.h @@ -138,7 +138,6 @@ class Power : private concurrency::OSThread void reboot(); // open circuit voltage lookup table uint8_t low_voltage_counter; - int32_t lastLogTime = 0; #ifdef DEBUG_HEAP uint32_t lastheap; #endif From 81a5aeff7480021dce73d0a75ab0f5e77d8fe8c5 Mon Sep 17 00:00:00 2001 From: Chloe Bethel Date: Tue, 7 Oct 2025 12:11:26 +0100 Subject: [PATCH 115/166] Fix serial pins for Ebyte E77 MBL board (#8246) Also move RAK3172 and new EBYTE_E77_MBL define to variant.h, as this makes VSCode know about the defines properly... Co-authored-by: Ben Meadors --- src/modules/SerialModule.cpp | 2 +- variants/stm32/CDEBYTE_E77-MBL/platformio.ini | 5 ++++- variants/stm32/CDEBYTE_E77-MBL/variant.h | 2 ++ variants/stm32/rak3172/platformio.ini | 1 - variants/stm32/rak3172/variant.h | 2 ++ 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 7485f1c2d..a9ec8f6a8 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -67,7 +67,7 @@ SerialModuleRadio *serialModuleRadio; defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {} static Print *serialPrint = &Serial; -#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) +#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) || defined(EBYTE_E77_MBL) SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial") {} static Print *serialPrint = &Serial1; #else diff --git a/variants/stm32/CDEBYTE_E77-MBL/platformio.ini b/variants/stm32/CDEBYTE_E77-MBL/platformio.ini index 290982405..c5af9a4a4 100644 --- a/variants/stm32/CDEBYTE_E77-MBL/platformio.ini +++ b/variants/stm32/CDEBYTE_E77-MBL/platformio.ini @@ -6,9 +6,12 @@ board_level = extra build_flags = ${stm32_base.build_flags} -Ivariants/stm32/CDEBYTE_E77-MBL - -DSERIAL_UART_INSTANCE=1 + -DSERIAL_UART_INSTANCE=2 -DPIN_SERIAL_RX=PA3 -DPIN_SERIAL_TX=PA2 + -DENABLE_HWSERIAL1 + -DPIN_SERIAL1_RX=PB7 + -DPIN_SERIAL1_TX=PB6 -DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1 -DMESHTASTIC_EXCLUDE_I2C=1 -DMESHTASTIC_EXCLUDE_GPS=1 diff --git a/variants/stm32/CDEBYTE_E77-MBL/variant.h b/variants/stm32/CDEBYTE_E77-MBL/variant.h index 317f44489..e3d111a33 100644 --- a/variants/stm32/CDEBYTE_E77-MBL/variant.h +++ b/variants/stm32/CDEBYTE_E77-MBL/variant.h @@ -18,4 +18,6 @@ Do not expect a working Meshtastic device with this target. #define LED_PIN PB4 // LED1 // #define LED_PIN PB3 // LED2 #define LED_STATE_ON 1 + +#define EBYTE_E77_MBL #endif diff --git a/variants/stm32/rak3172/platformio.ini b/variants/stm32/rak3172/platformio.ini index 7fc6c7cba..b9a4b8a04 100644 --- a/variants/stm32/rak3172/platformio.ini +++ b/variants/stm32/rak3172/platformio.ini @@ -6,7 +6,6 @@ board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem build_flags = ${stm32_base.build_flags} -Ivariants/stm32/rak3172 - -DRAK3172 -DENABLE_HWSERIAL1 -DPIN_SERIAL1_RX=PB7 -DPIN_SERIAL1_TX=PB6 diff --git a/variants/stm32/rak3172/variant.h b/variants/stm32/rak3172/variant.h index 45752b481..30d2b57b4 100644 --- a/variants/stm32/rak3172/variant.h +++ b/variants/stm32/rak3172/variant.h @@ -16,4 +16,6 @@ Do not expect a working Meshtastic device with this target. #define LED_PIN PA0 // Green LED #define LED_STATE_ON 1 +#define RAK3172 + #endif From bd9076b7401aed73b1810e746fbb1aed30ba8649 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 7 Oct 2025 06:14:35 -0500 Subject: [PATCH 116/166] Remove risky change --- src/modules/NodeInfoModule.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 9b94b3933..aaab019d6 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -113,8 +113,12 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply() u.public_key.size = 0; } - // Clear the user.id field since it should be derived from node number on the receiving end - u.id[0] = '\0'; + // FIXME: Clear the user.id field since it should be derived from node number on the receiving end + // u.id[0] = '\0'; + + // Ensure our user.id is derived correctly + strcpy(u.id, nodeDB->getNodeId().c_str()); + LOG_INFO("Send owner %s/%s/%s", u.id, u.long_name, u.short_name); lastSentToMesh = millis(); return allocDataProtobuf(u); From 468b40e8dbf2bf899ec0020e57fa2035b4f03b54 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 7 Oct 2025 22:24:09 +1100 Subject: [PATCH 117/166] Wait until after GPS lock hold before updating position, if we can. (#8064) * Wait until after GPS lock hold before updating position, if we can. After the recent patch, we hold lock for a bit before updating the position. The positions that come in after the hold are genuinely better positions than what we've been doing before. However, they only come 20 seconds after we've got lock. Previously, we would update the local position as soon as we got a lock as well as at the end of the hold, since a hold was not always possible. With this patch, if the settings allow, we should skip that first local position update. Fixes https://github.com/meshtastic/firmware/issues/8029 * Fix falling edge handling. * spelling Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Congeal lock handling * Add named constants * define unit to avoid confusion Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * ifdef, not if. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add handling for when we first turn on. * Don't run if not active * Reset fixhold * Logic fixes * Add path for ACTIVE--> IDLE --> ACTIVE Previously we only covered HARDSLEEP --> ACTIVE. * Change hold time to gps_update_interval - 10s * Update comment * Add extra buffer to avoid re-starting hold --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ben Meadors --- src/gps/GPS.cpp | 125 +++++++++++++++++++++++++++++++++--------------- src/gps/GPS.h | 5 +- 2 files changed, 90 insertions(+), 40 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 1125cf998..2cfa558ed 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1031,7 +1031,7 @@ void GPS::down() LOG_DEBUG("%us until next search", sleepTime / 1000); // If update interval less than 10 seconds, no attempt to sleep - if (updateInterval <= 10 * 1000UL || sleepTime == 0) + if (updateInterval <= GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS || sleepTime == 0) setPowerState(GPS_IDLE); else { @@ -1102,6 +1102,29 @@ int32_t GPS::runOnce() publishUpdate(); } + // ======================== GPS_ACTIVE state ======================== + // In GPS_ACTIVE state, GPS is powered on and we're receiving NMEA messages. + // We use the following logic to determine when to update the local position + // or time by running GPS::publishUpdate. + // Note: Local position update is asynchronous to position broadcast. We + // generally run this state every gps_update_interval seconds, and in most cases + // gps_update_interval is faster than the position broadcast interval so there's a + // fresh position ready when the device wants to broadcast one on the mesh. + // + // 1. Got a time for the first time --> set the time, don't publish. + // 2. Got a lock for the first time + // --> If gps_update_interval is <= 10s --> publishUpdate + // --> Otherwise, hold for MIN(gps_update_interval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS, 20s) + // 3. Got a lock after turning back on + // --> If gps_update_interval is <= 10s --> publishUpdate + // --> Otherwise, hold for MIN(gps_update_interval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS, 20s) + // 4. Hold has expired + // --> If we have a time and a location --> publishUpdate + // --> down() + // 5. Search time has expired + // --> If we have a time and a location --> publishUpdate + // --> If we had a location before but don't now --> publishUpdate + // --> down() if (whileActive()) { // if we have received valid NMEA claim we are connected setConnected(); @@ -1111,55 +1134,81 @@ int32_t GPS::runOnce() if (!config.position.fixed_position && powerState != GPS_ACTIVE && scheduling.isUpdateDue()) up(); - // If we've already set time from the GPS, no need to ask the GPS - bool gotTime = (getRTCQuality() >= RTCQualityGPS); - if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time - gotTime = true; - shouldPublish = true; - } - + // quality of the previous fix. We set it to 0 when we go down, so it's a way + // to check if we're getting a lock after being GPS_OFF. uint8_t prev_fixQual = fixQual; - bool gotLoc = lookForLocation(); - if (gotLoc && !hasValidLocation) { // declare that we have location ASAP - LOG_DEBUG("hasValidLocation RISING EDGE"); - hasValidLocation = true; - shouldPublish = true; - // Hold for 20secs after getting a lock to download ephemeris etc - fixHoldEnds = millis() + 20000; - } - if (gotLoc && prev_fixQual == 0) { // just got a lock after turning back on. - fixHoldEnds = millis() + 20000; - shouldPublish = true; // Publish immediately, since next publish is at end of hold - } + if (powerState == GPS_ACTIVE) { + // if gps_update_interval is <=10s, GPS never goes off, so we treat that differently + uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval); - bool tooLong = scheduling.searchedTooLong(); - if (tooLong) - LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time"); + // 1. Got a time for the first time + bool gotTime = (getRTCQuality() >= RTCQualityGPS); + if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time + gotTime = true; + } - // Once we get a location we no longer desperately want an update - if ((gotLoc && gotTime) || tooLong) { + // 2. Got a lock for the first time, or 3. Got a lock after turning back on + bool gotLoc = lookForLocation(); + if (gotLoc) { +#ifdef GPS_DEBUG + if (!hasValidLocation) { // declare that we have location ASAP + LOG_DEBUG("hasValidLocation RISING EDGE"); + } +#endif + if (updateInterval <= GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS) { + hasValidLocation = true; + shouldPublish = true; + } else if (!hasValidLocation || prev_fixQual == 0 || (fixHoldEnds + GPS_THREAD_INTERVAL) < millis()) { + hasValidLocation = true; + // Hold for up to 20secs after getting a lock to download ephemeris etc + uint32_t holdTime = updateInterval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS; + if (holdTime > GPS_FIX_HOLD_MAX_MS) + holdTime = GPS_FIX_HOLD_MAX_MS; + fixHoldEnds = millis() + holdTime; +#ifdef GPS_DEBUG + LOG_DEBUG("Holding for %ums after lock", holdTime); +#endif + } + } + + bool tooLong = scheduling.searchedTooLong(); if (tooLong && !gotLoc) { + LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time"); // we didn't get a location during this ack window, therefore declare loss of lock if (hasValidLocation) { - LOG_DEBUG("hasValidLocation FALLING EDGE"); - } - p = meshtastic_Position_init_default; - hasValidLocation = false; - } - if (millis() > fixHoldEnds) { - shouldPublish = true; // publish our update at the end of the lock hold - publishUpdate(); - down(); + p = meshtastic_Position_init_default; + hasValidLocation = false; + shouldPublish = true; #ifdef GPS_DEBUG - } else { + LOG_DEBUG("hasValidLocation FALLING EDGE"); +#endif + } + } + + // Hold has expired , Search time has expired, we got a time only, or we never needed to hold. + bool holdExpired = (fixHoldEnds != 0 && millis() > fixHoldEnds); + if (shouldPublish || tooLong || holdExpired) { + if (gotTime && hasValidLocation) { + shouldPublish = true; + } + if (shouldPublish) { + fixHoldEnds = 0; + publishUpdate(); + } + + // There's a chance we just got a time, so keep going to see if we can get a location too + if (tooLong || holdExpired) { + down(); + } + +#ifdef GPS_DEBUG + } else if (fixHoldEnds != 0) { LOG_DEBUG("Holding for GPS data download: %d ms (numSats=%d)", fixHoldEnds - millis(), p.sats_in_view); #endif } } - - // If state has changed do a publish - publishUpdate(); + // ===================== end GPS_ACTIVE state ======================== if (config.position.fixed_position == true && hasValidLocation) return disable(); // This should trigger when we have a fixed position, and get that first position diff --git a/src/gps/GPS.h b/src/gps/GPS.h index f3bcf37f5..8ba1ce0a6 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -16,6 +16,9 @@ #define GPS_EN_ACTIVE 1 #endif +static constexpr uint32_t GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS = 10 * 1000UL; +static constexpr uint32_t GPS_FIX_HOLD_MAX_MS = 20000; + typedef enum { GNSS_MODEL_ATGM336H, GNSS_MODEL_MTK, @@ -175,8 +178,6 @@ class GPS : private concurrency::OSThread */ bool hasValidLocation = false; // default to false, until we complete our first read - bool isInPowersave = false; - bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop() bool hasGPS = false; // Do we have a GPS we are talking to From f0e4ea76649a49f614e391bbb7c16519e163a219 Mon Sep 17 00:00:00 2001 From: szlifier Date: Tue, 7 Oct 2025 13:25:38 +0200 Subject: [PATCH 118/166] Add SHT4x serial number for detection (#8222) SHT4X chip recognized as SHT31, registerValue that stores first bytes of chip's serial number did not mach the chip. Added a serial number match for SHT40 found in a SONOFF SNZB-02P. --- src/detect/ScanI2CTwoWire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 6df3f8be1..89a0610b4 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -378,7 +378,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2); - if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c || registerValue == 0xc8d) { + if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0x11f3 || registerValue == 0xe9c || registerValue == 0xc8d) { type = SHT4X; logFoundDevice("SHT4X", (uint8_t)addr.address); } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) { From e4ec719e6f888c47ee3a1cc78afd2b96d5f196d1 Mon Sep 17 00:00:00 2001 From: Austin Lane Date: Tue, 7 Oct 2025 12:54:02 -0400 Subject: [PATCH 119/166] Force coverage tests to run in simulation mode --- variants/native/portduino/platformio.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/variants/native/portduino/platformio.ini b/variants/native/portduino/platformio.ini index 2ccdfbbfc..1385aa0c7 100644 --- a/variants/native/portduino/platformio.ini +++ b/variants/native/portduino/platformio.ini @@ -107,3 +107,5 @@ build_src_filter = ${env:native-tft.build_src_filter} [env:coverage] extends = env:native build_flags = -lgcov --coverage -fprofile-abs-path -fsanitize=address ${env:native.build_flags} +; https://docs.platformio.org/en/latest/projectconf/sections/env/options/test/test_testing_command.html +test_testing_command = ${platformio.build_dir}/${this.__env__}/program -s From e8e8ee0993ff1fddfa6b0ac42dc114a77e36d90b Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 7 Oct 2025 12:04:50 -0500 Subject: [PATCH 120/166] Revert "Force coverage tests to run in simulation mode" This reverts commit e4ec719e6f888c47ee3a1cc78afd2b96d5f196d1. --- variants/native/portduino/platformio.ini | 2 -- 1 file changed, 2 deletions(-) diff --git a/variants/native/portduino/platformio.ini b/variants/native/portduino/platformio.ini index 1385aa0c7..2ccdfbbfc 100644 --- a/variants/native/portduino/platformio.ini +++ b/variants/native/portduino/platformio.ini @@ -107,5 +107,3 @@ build_src_filter = ${env:native-tft.build_src_filter} [env:coverage] extends = env:native build_flags = -lgcov --coverage -fprofile-abs-path -fsanitize=address ${env:native.build_flags} -; https://docs.platformio.org/en/latest/projectconf/sections/env/options/test/test_testing_command.html -test_testing_command = ${platformio.build_dir}/${this.__env__}/program -s From 74e6723ad90f1211421f7b8d6b5be62405eb0a7d Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 7 Oct 2025 14:14:19 -0400 Subject: [PATCH 121/166] Force coverage tests to run in simulation mode (#8251) * Force coverage tests to run in simulation mode * Revert "Force coverage tests to run in simulation mode" This reverts commit e4ec719e6f888c47ee3a1cc78afd2b96d5f196d1. * Force coverage tests to run in simulation mode --------- Co-authored-by: Ben Meadors --- variants/native/portduino/platformio.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/variants/native/portduino/platformio.ini b/variants/native/portduino/platformio.ini index 2ccdfbbfc..4e6a592de 100644 --- a/variants/native/portduino/platformio.ini +++ b/variants/native/portduino/platformio.ini @@ -107,3 +107,7 @@ build_src_filter = ${env:native-tft.build_src_filter} [env:coverage] extends = env:native build_flags = -lgcov --coverage -fprofile-abs-path -fsanitize=address ${env:native.build_flags} +; https://docs.platformio.org/en/latest/projectconf/sections/env/options/test/test_testing_command.html +test_testing_command = + ${platformio.build_dir}/${this.__env__}/program + -s From 0c2673ee2f4d3f41f2ff27801ec8af020c1f8a2b Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 7 Oct 2025 14:32:36 -0500 Subject: [PATCH 122/166] Mercy --- test/test_mqtt/MQTT.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_mqtt/MQTT.cpp b/test/test_mqtt/MQTT.cpp index 8726d1ccb..1c2f0642a 100644 --- a/test/test_mqtt/MQTT.cpp +++ b/test/test_mqtt/MQTT.cpp @@ -332,7 +332,7 @@ void setUp(void) }; channelFile.channels_count = 1; owner = meshtastic_User{.id = "!12345678"}; - myNodeInfo = meshtastic_MyNodeInfo{.my_node_num = 10}; + myNodeInfo = meshtastic_MyNodeInfo{.my_node_num = 0x12345678}; // Match the expected gateway ID in topic localPosition = meshtastic_Position{.has_latitude_i = true, .latitude_i = 7 * 1e7, .has_longitude_i = true, .longitude_i = 3 * 1e7}; From fcb1d64eb936fa77522cd9b8e7867e680e6b27e3 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 7 Oct 2025 17:47:08 -0500 Subject: [PATCH 123/166] Bloop --- src/graphics/Screen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 31c211019..4485ca7a3 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1503,7 +1503,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) screen->showSimpleBanner(banner, 1500); if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY || (isAlert && moduleConfig.external_notification.alert_bell_buzzer) || - (!isBroadcast(packet->to) && isToUs(p))) { + (!isBroadcast(packet->to) && isToUs(packet))) { // Beep if not in DIRECT_MSG_ONLY mode or if in DIRECT_MSG_ONLY mode and either // - packet contains an alert and alert bell buzzer is enabled // - packet is a non-broadcast that is addressed to this node From d332dfa19b851d93b1dc39f5fe3831995136e971 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 17:33:39 +1100 Subject: [PATCH 124/166] Update python Docker tag to v3.14 (#8255) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Dockerfile | 2 +- alpine.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b1e151ac7..111dd69fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # trunk-ignore-all(hadolint/DL3008): Do not pin apt package versions # trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions -FROM python:3.13-slim-trixie AS builder +FROM python:3.14-slim-trixie AS builder ARG PIO_ENV=native ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Etc/UTC diff --git a/alpine.Dockerfile b/alpine.Dockerfile index 670736241..0469874e4 100644 --- a/alpine.Dockerfile +++ b/alpine.Dockerfile @@ -3,7 +3,7 @@ # trunk-ignore-all(hadolint/DL3018): Do not pin apk package versions # trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions -FROM python:3.13-alpine3.22 AS builder +FROM python:3.14-alpine3.22 AS builder ARG PIO_ENV=native ENV PIP_ROOT_USER_ACTION=ignore From 7822f28152cab468b13567b5cef583cde8468832 Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Thu, 9 Oct 2025 00:33:50 +0800 Subject: [PATCH 125/166] fix: Move `#include "variant.h"` to top of file (fixes #8276) (#8278) * Force coverage tests to run in simulation mode * Revert "Force coverage tests to run in simulation mode" This reverts commit e4ec719e6f888c47ee3a1cc78afd2b96d5f196d1. * fix: Move `#include "variant.h"` to top of file (fixes #8276) The original line being further down the file causes any #ifdef/defined() checks for definitions in variant.h to silently skip. This was noticed when `USE_GC1109_PA` in Heltec v4 and Heltec Wireless Tracker failed to correct program TX_GAIN_LORA, but will also affect any variant.h-dependent configurations in this file, if they would have been defined above where the `#include` previously was. --------- Co-authored-by: Austin Lane Co-authored-by: Ben Meadors --- src/configuration.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index e67f0b8e5..c6c8d673c 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -33,6 +33,9 @@ along with this program. If not, see . #include "pcf8563.h" #endif +/* Offer chance for variant-specific defines */ +#include "variant.h" + // ----------------------------------------------------------------------------- // Version // ----------------------------------------------------------------------------- @@ -260,9 +263,6 @@ along with this program. If not, see . // convert 24-bit color to 16-bit (56K) #define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)) -/* Step #1: offer chance for variant-specific defines */ -#include "variant.h" - #if defined(VEXT_ENABLE) && !defined(VEXT_ON_VALUE) // Older variant.h files might not be defining this value, so stay with the old default #define VEXT_ON_VALUE LOW From adae68fbfe94d1415e54a1bafb842f144e02a4df Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 11:34:11 -0500 Subject: [PATCH 126/166] Update meshtastic/device-ui digest to 6d8cc22 (#8275) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 2e101a8a2..7121f00b7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -120,7 +120,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/e564d78ae1a7e9a225aaf4a73b1cb84c549f510f.zip + https://github.com/meshtastic/device-ui/archive/6d8cc228298a1ecd9913aed757187e9527c1facc.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From 828e11cc482a802b3385c9a4aa7cb7b00a519360 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 8 Oct 2025 14:16:57 -0500 Subject: [PATCH 127/166] NimBLE speedup (#8281) * Remove status polling code in NimBLE * Goober --------- Co-authored-by: Jonathan Bennett --- src/mesh/PhoneAPI.cpp | 2 +- src/nimble/NimbleBluetooth.cpp | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 210e0ba06..d2ed2d4cb 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -431,7 +431,6 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) break; case STATE_SEND_OTHER_NODEINFOS: { - LOG_DEBUG("Send known nodes"); if (nodeInfoForPhone.num != 0) { // Just in case we stored a different user.id in the past, but should never happen going forward sprintf(nodeInfoForPhone.user.id, "!%08x", nodeInfoForPhone.num); @@ -592,6 +591,7 @@ bool PhoneAPI::available() nodeInfoForPhone.snr = isUs ? 0 : nodeInfoForPhone.snr; nodeInfoForPhone.via_mqtt = isUs ? false : nodeInfoForPhone.via_mqtt; nodeInfoForPhone.is_favorite = nodeInfoForPhone.is_favorite || isUs; // Our node is always a favorite + onNowHasData(0); } } diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 5524765f3..030e00d6b 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -120,14 +120,19 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks virtual void onRead(NimBLECharacteristic *pCharacteristic) #endif { - int tries = 0; - bluetoothPhoneAPI->phoneWants = true; - while (!bluetoothPhoneAPI->hasChecked && tries < 100) { - bluetoothPhoneAPI->setIntervalFromNow(0); - delay(20); - tries++; - } std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); + + // If we don't have fresh data, trigger a refresh + if (!bluetoothPhoneAPI->hasChecked || bluetoothPhoneAPI->numBytes == 0) { + bluetoothPhoneAPI->phoneWants = true; + bluetoothPhoneAPI->setIntervalFromNow(0); + + // Get fresh data immediately + bluetoothPhoneAPI->numBytes = bluetoothPhoneAPI->getFromRadio(bluetoothPhoneAPI->fromRadioBytes); + bluetoothPhoneAPI->hasChecked = true; + } + + // Set the characteristic value with whatever data we have pCharacteristic->setValue(bluetoothPhoneAPI->fromRadioBytes, bluetoothPhoneAPI->numBytes); if (bluetoothPhoneAPI->numBytes != 0) // if we did send something, queue it up right away to reload From 05edcc5d6ce1ed755fe40013459b718bafe84e24 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Thu, 9 Oct 2025 08:03:26 +1100 Subject: [PATCH 128/166] Fix Station G2 Lora Power Settings (#8273) * Force coverage tests to run in simulation mode * Revert "Force coverage tests to run in simulation mode" This reverts commit e4ec719e6f888c47ee3a1cc78afd2b96d5f196d1. * Fix Station G2 Lora Power Settings In #8107 we introduced the ability to specify gain values for non-linear power amplifiers. This patch adds appropriate values for the Station G2, based on the table at https://wiki.uniteng.com/en/meshtastic/station-g2#summary-for-lora-power-amplifier-conduction-test Fixes https://github.com/meshtastic/firmware/issues/7239 --------- Co-authored-by: Austin Lane Co-authored-by: Ben Meadors --- src/configuration.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/configuration.h b/src/configuration.h index c6c8d673c..b6b1c1e5e 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -126,6 +126,11 @@ along with this program. If not, see . #define TX_GAIN_LORA 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7 #endif +#ifdef STATION_G2 +#define NUM_PA_POINTS 19 +#define TX_GAIN_LORA 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 19, 19, 18, 18 +#endif + // Default system gain to 0 if not defined #ifndef TX_GAIN_LORA #define TX_GAIN_LORA 0 From 2a1469652540d85710c62ab80b65626a3ee17b08 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:32:41 +1100 Subject: [PATCH 129/166] chore(deps): update github/codeql-action action to v4 (#8250) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/sec_sast_semgrep_cron.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sec_sast_semgrep_cron.yml b/.github/workflows/sec_sast_semgrep_cron.yml index 96c993cba..2059fde2c 100644 --- a/.github/workflows/sec_sast_semgrep_cron.yml +++ b/.github/workflows/sec_sast_semgrep_cron.yml @@ -41,7 +41,7 @@ jobs: # step 4 - name: publish code scanning alerts - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: report.sarif category: semgrep From 45f15b8fe66b42ac31b05fe06e65d54467317c7b Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 9 Oct 2025 12:44:00 -0500 Subject: [PATCH 130/166] Fix BLE stateful issues (#8287) --- src/mesh/PhoneAPI.cpp | 2 +- src/nimble/NimbleBluetooth.cpp | 23 +++-------------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index d2ed2d4cb..e8dc9843c 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -734,7 +734,7 @@ int PhoneAPI::onNotify(uint32_t newValue) LOG_INFO("Tell client we have new packets %u", newValue); onNowHasData(newValue); } else { - LOG_DEBUG("(Client not yet interested in packets)"); + LOG_DEBUG("Client not yet interested in packets (state=%d)", state); } return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 030e00d6b..0b3009d39 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -31,11 +31,8 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread std::vector nimble_queue; std::mutex nimble_mutex; uint8_t queue_size = 0; - bool has_fromRadio = false; uint8_t fromRadioBytes[meshtastic_FromRadio_size] = {0}; size_t numBytes = 0; - bool hasChecked = false; - bool phoneWants = false; protected: virtual int32_t runOnce() override @@ -48,10 +45,7 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread LOG_DEBUG("Queue_size %u", queue_size); queue_size = 0; } - if (hasChecked == false && phoneWants == true) { - numBytes = getFromRadio(fromRadioBytes); - hasChecked = true; - } + // Note: phoneWants/hasChecked logic removed since onRead() handles getFromRadio() directly // the run is triggered via NimbleBluetoothToRadioCallback and NimbleBluetoothFromRadioCallback return INT32_MAX; @@ -122,15 +116,8 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks { std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); - // If we don't have fresh data, trigger a refresh - if (!bluetoothPhoneAPI->hasChecked || bluetoothPhoneAPI->numBytes == 0) { - bluetoothPhoneAPI->phoneWants = true; - bluetoothPhoneAPI->setIntervalFromNow(0); - - // Get fresh data immediately - bluetoothPhoneAPI->numBytes = bluetoothPhoneAPI->getFromRadio(bluetoothPhoneAPI->fromRadioBytes); - bluetoothPhoneAPI->hasChecked = true; - } + // Get fresh data immediately when client reads + bluetoothPhoneAPI->numBytes = bluetoothPhoneAPI->getFromRadio(bluetoothPhoneAPI->fromRadioBytes); // Set the characteristic value with whatever data we have pCharacteristic->setValue(bluetoothPhoneAPI->fromRadioBytes, bluetoothPhoneAPI->numBytes); @@ -138,8 +125,6 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks if (bluetoothPhoneAPI->numBytes != 0) // if we did send something, queue it up right away to reload bluetoothPhoneAPI->setIntervalFromNow(0); bluetoothPhoneAPI->numBytes = 0; - bluetoothPhoneAPI->hasChecked = false; - bluetoothPhoneAPI->phoneWants = false; } }; @@ -248,8 +233,6 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks if (bluetoothPhoneAPI) { std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); bluetoothPhoneAPI->close(); - bluetoothPhoneAPI->hasChecked = false; - bluetoothPhoneAPI->phoneWants = false; bluetoothPhoneAPI->numBytes = 0; bluetoothPhoneAPI->queue_size = 0; } From e5a2ce54e74f6cfaec8e44c43764fa062b1b862b Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 8 Oct 2025 23:13:02 -0500 Subject: [PATCH 131/166] Attach an interrupt to EXT_PWR_DETECT if present, and force a screen redraw on a power change. --- src/Power.cpp | 10 ++++++++++ src/graphics/Screen.cpp | 3 +++ 2 files changed, 13 insertions(+) diff --git a/src/Power.cpp b/src/Power.cpp index 7de82b8d6..39d47610b 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -691,6 +691,16 @@ bool Power::setup() #ifdef NRF_APM found = true; #endif +#ifdef EXT_PWR_DETECT + attachInterrupt( + EXT_PWR_DETECT, + []() { + power->setIntervalFromNow(0); + runASAP = true; + BaseType_t higherWake = 0; + }, + CHANGE); +#endif enabled = found; low_voltage_counter = 0; diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 4485ca7a3..767f97eed 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1428,6 +1428,9 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) } nodeDB->updateGUI = false; break; + case STATUS_TYPE_POWER: + forceDisplay(true); + break; } return 0; From 05febc25e1d6ca0fd37752fa9be23d6d515730c1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 11 Oct 2025 17:12:10 +1100 Subject: [PATCH 132/166] Update XPowersLib to v0.3.1 (#8303) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- arch/esp32/esp32.ini | 2 +- arch/esp32/esp32c6.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index d2c933461..327444a60 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -56,7 +56,7 @@ lib_deps = # renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip # renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib - https://github.com/lewisxhe/XPowersLib/archive/v0.3.0.zip + https://github.com/lewisxhe/XPowersLib/archive/v0.3.1.zip # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto diff --git a/arch/esp32/esp32c6.ini b/arch/esp32/esp32c6.ini index 1afb9b547..7b06f4cd8 100644 --- a/arch/esp32/esp32c6.ini +++ b/arch/esp32/esp32c6.ini @@ -28,7 +28,7 @@ lib_deps = ${environmental_extra.lib_deps} ${radiolib_base.lib_deps} # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib - lewisxhe/XPowersLib@0.3.0 + lewisxhe/XPowersLib@0.3.1 # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto From 0bb1c1fe6f537cefff17c9a360be772d731b075b Mon Sep 17 00:00:00 2001 From: thebentern <9000580+thebentern@users.noreply.github.com> Date: Sat, 11 Oct 2025 15:27:33 +0000 Subject: [PATCH 133/166] Automated version bumps --- bin/org.meshtastic.meshtasticd.metainfo.xml | 3 +++ debian/changelog | 6 ++++++ version.properties | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/bin/org.meshtastic.meshtasticd.metainfo.xml b/bin/org.meshtastic.meshtasticd.metainfo.xml index 3505f1940..6fc5e8597 100644 --- a/bin/org.meshtastic.meshtasticd.metainfo.xml +++ b/bin/org.meshtastic.meshtasticd.metainfo.xml @@ -87,6 +87,9 @@ + + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.13 + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.12 diff --git a/debian/changelog b/debian/changelog index 8bd053b25..e124f8929 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +meshtasticd (2.7.13.0) unstable; urgency=medium + + * Version 2.7.13 + + -- GitHub Actions Sat, 11 Oct 2025 15:27:28 +0000 + meshtasticd (2.7.12.0) unstable; urgency=medium [ Austin Lane ] diff --git a/version.properties b/version.properties index 5c84a8e65..f33f0f1cb 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 7 -build = 12 +build = 13 From 694b669eb7c4f24825ee7c058875505c5f31ff68 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 11 Oct 2025 10:30:33 -0500 Subject: [PATCH 134/166] Double the number of bluetooth bonds NimBLE will store (from 3 to 6) (#8296) --- arch/esp32/esp32.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 327444a60..810c9780e 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -31,6 +31,7 @@ build_flags = -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL -DAXP_DEBUG_PORT=Serial -DCONFIG_BT_NIMBLE_ENABLED + -DCONFIG_BT_NIMBLE_MAX_BONDS=6 # default is 3 -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192 From cafb007ec466c283c671fec92e1915fde109c80c Mon Sep 17 00:00:00 2001 From: Austin Date: Sat, 11 Oct 2025 11:30:47 -0400 Subject: [PATCH 135/166] mDNS: Advertise pio_env (for OTA scripts) (#8298) --- src/mesh/wifi/WiFiAPClient.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index 7d210dd33..18f67706a 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -95,10 +95,12 @@ static void onNetworkConnected() #ifdef ARCH_ESP32 MDNS.addServiceTxt("meshtastic", "tcp", "shortname", String(owner.short_name)); MDNS.addServiceTxt("meshtastic", "tcp", "id", String(nodeDB->getNodeId().c_str())); + MDNS.addServiceTxt("meshtastic", "tcp", "pio_env", optstr(APP_ENV)); // ESP32 prints obtained IP address in WiFiEvent #elif defined(ARCH_RP2040) MDNS.addServiceTxt("meshtastic", "shortname", owner.short_name); MDNS.addServiceTxt("meshtastic", "id", nodeDB->getNodeId().c_str()); + MDNS.addServiceTxt("meshtastic", "pio_env", optstr(APP_ENV)); LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str()); #endif } From fca5343460f0253a08c80e6e972b5046e62148c0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 17:33:39 +1100 Subject: [PATCH 136/166] Update python Docker tag to v3.14 (#8255) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Dockerfile | 2 +- alpine.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b1e151ac7..111dd69fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # trunk-ignore-all(hadolint/DL3008): Do not pin apt package versions # trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions -FROM python:3.13-slim-trixie AS builder +FROM python:3.14-slim-trixie AS builder ARG PIO_ENV=native ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Etc/UTC diff --git a/alpine.Dockerfile b/alpine.Dockerfile index 670736241..0469874e4 100644 --- a/alpine.Dockerfile +++ b/alpine.Dockerfile @@ -3,7 +3,7 @@ # trunk-ignore-all(hadolint/DL3018): Do not pin apk package versions # trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions -FROM python:3.13-alpine3.22 AS builder +FROM python:3.14-alpine3.22 AS builder ARG PIO_ENV=native ENV PIP_ROOT_USER_ACTION=ignore From 64bfe73c06d6da0c3f1c4976f063f0190c07ad43 Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Thu, 9 Oct 2025 00:33:50 +0800 Subject: [PATCH 137/166] fix: Move `#include "variant.h"` to top of file (fixes #8276) (#8278) * Force coverage tests to run in simulation mode * Revert "Force coverage tests to run in simulation mode" This reverts commit e4ec719e6f888c47ee3a1cc78afd2b96d5f196d1. * fix: Move `#include "variant.h"` to top of file (fixes #8276) The original line being further down the file causes any #ifdef/defined() checks for definitions in variant.h to silently skip. This was noticed when `USE_GC1109_PA` in Heltec v4 and Heltec Wireless Tracker failed to correct program TX_GAIN_LORA, but will also affect any variant.h-dependent configurations in this file, if they would have been defined above where the `#include` previously was. --------- Co-authored-by: Austin Lane Co-authored-by: Ben Meadors --- src/configuration.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index e67f0b8e5..c6c8d673c 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -33,6 +33,9 @@ along with this program. If not, see . #include "pcf8563.h" #endif +/* Offer chance for variant-specific defines */ +#include "variant.h" + // ----------------------------------------------------------------------------- // Version // ----------------------------------------------------------------------------- @@ -260,9 +263,6 @@ along with this program. If not, see . // convert 24-bit color to 16-bit (56K) #define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)) -/* Step #1: offer chance for variant-specific defines */ -#include "variant.h" - #if defined(VEXT_ENABLE) && !defined(VEXT_ON_VALUE) // Older variant.h files might not be defining this value, so stay with the old default #define VEXT_ON_VALUE LOW From 91d928d4c5ad4daa92da86067f57e1bf096fd220 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 11:34:11 -0500 Subject: [PATCH 138/166] Update meshtastic/device-ui digest to 6d8cc22 (#8275) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 2e101a8a2..7121f00b7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -120,7 +120,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/e564d78ae1a7e9a225aaf4a73b1cb84c549f510f.zip + https://github.com/meshtastic/device-ui/archive/6d8cc228298a1ecd9913aed757187e9527c1facc.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From f99747180e2fe3ea68d4826ce81219c30286fe9a Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 8 Oct 2025 14:16:57 -0500 Subject: [PATCH 139/166] NimBLE speedup (#8281) * Remove status polling code in NimBLE * Goober --------- Co-authored-by: Jonathan Bennett --- src/mesh/PhoneAPI.cpp | 2 +- src/nimble/NimbleBluetooth.cpp | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 210e0ba06..d2ed2d4cb 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -431,7 +431,6 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) break; case STATE_SEND_OTHER_NODEINFOS: { - LOG_DEBUG("Send known nodes"); if (nodeInfoForPhone.num != 0) { // Just in case we stored a different user.id in the past, but should never happen going forward sprintf(nodeInfoForPhone.user.id, "!%08x", nodeInfoForPhone.num); @@ -592,6 +591,7 @@ bool PhoneAPI::available() nodeInfoForPhone.snr = isUs ? 0 : nodeInfoForPhone.snr; nodeInfoForPhone.via_mqtt = isUs ? false : nodeInfoForPhone.via_mqtt; nodeInfoForPhone.is_favorite = nodeInfoForPhone.is_favorite || isUs; // Our node is always a favorite + onNowHasData(0); } } diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 5524765f3..030e00d6b 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -120,14 +120,19 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks virtual void onRead(NimBLECharacteristic *pCharacteristic) #endif { - int tries = 0; - bluetoothPhoneAPI->phoneWants = true; - while (!bluetoothPhoneAPI->hasChecked && tries < 100) { - bluetoothPhoneAPI->setIntervalFromNow(0); - delay(20); - tries++; - } std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); + + // If we don't have fresh data, trigger a refresh + if (!bluetoothPhoneAPI->hasChecked || bluetoothPhoneAPI->numBytes == 0) { + bluetoothPhoneAPI->phoneWants = true; + bluetoothPhoneAPI->setIntervalFromNow(0); + + // Get fresh data immediately + bluetoothPhoneAPI->numBytes = bluetoothPhoneAPI->getFromRadio(bluetoothPhoneAPI->fromRadioBytes); + bluetoothPhoneAPI->hasChecked = true; + } + + // Set the characteristic value with whatever data we have pCharacteristic->setValue(bluetoothPhoneAPI->fromRadioBytes, bluetoothPhoneAPI->numBytes); if (bluetoothPhoneAPI->numBytes != 0) // if we did send something, queue it up right away to reload From 30d6962e791a6aaf7040d328ad860d1ab73fb3d7 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Thu, 9 Oct 2025 08:03:26 +1100 Subject: [PATCH 140/166] Fix Station G2 Lora Power Settings (#8273) * Force coverage tests to run in simulation mode * Revert "Force coverage tests to run in simulation mode" This reverts commit e4ec719e6f888c47ee3a1cc78afd2b96d5f196d1. * Fix Station G2 Lora Power Settings In #8107 we introduced the ability to specify gain values for non-linear power amplifiers. This patch adds appropriate values for the Station G2, based on the table at https://wiki.uniteng.com/en/meshtastic/station-g2#summary-for-lora-power-amplifier-conduction-test Fixes https://github.com/meshtastic/firmware/issues/7239 --------- Co-authored-by: Austin Lane Co-authored-by: Ben Meadors --- src/configuration.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/configuration.h b/src/configuration.h index c6c8d673c..b6b1c1e5e 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -126,6 +126,11 @@ along with this program. If not, see . #define TX_GAIN_LORA 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7 #endif +#ifdef STATION_G2 +#define NUM_PA_POINTS 19 +#define TX_GAIN_LORA 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 19, 19, 18, 18 +#endif + // Default system gain to 0 if not defined #ifndef TX_GAIN_LORA #define TX_GAIN_LORA 0 From eee80ce6364fee804e6f92ceaea41f69a5d206b5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:32:41 +1100 Subject: [PATCH 141/166] chore(deps): update github/codeql-action action to v4 (#8250) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/sec_sast_semgrep_cron.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sec_sast_semgrep_cron.yml b/.github/workflows/sec_sast_semgrep_cron.yml index 96c993cba..2059fde2c 100644 --- a/.github/workflows/sec_sast_semgrep_cron.yml +++ b/.github/workflows/sec_sast_semgrep_cron.yml @@ -41,7 +41,7 @@ jobs: # step 4 - name: publish code scanning alerts - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: report.sarif category: semgrep From 73cadce58125141d3d7c7027d3a380416935a5ed Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 9 Oct 2025 12:44:00 -0500 Subject: [PATCH 142/166] Fix BLE stateful issues (#8287) --- src/mesh/PhoneAPI.cpp | 2 +- src/nimble/NimbleBluetooth.cpp | 23 +++-------------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index d2ed2d4cb..e8dc9843c 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -734,7 +734,7 @@ int PhoneAPI::onNotify(uint32_t newValue) LOG_INFO("Tell client we have new packets %u", newValue); onNowHasData(newValue); } else { - LOG_DEBUG("(Client not yet interested in packets)"); + LOG_DEBUG("Client not yet interested in packets (state=%d)", state); } return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 030e00d6b..0b3009d39 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -31,11 +31,8 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread std::vector nimble_queue; std::mutex nimble_mutex; uint8_t queue_size = 0; - bool has_fromRadio = false; uint8_t fromRadioBytes[meshtastic_FromRadio_size] = {0}; size_t numBytes = 0; - bool hasChecked = false; - bool phoneWants = false; protected: virtual int32_t runOnce() override @@ -48,10 +45,7 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread LOG_DEBUG("Queue_size %u", queue_size); queue_size = 0; } - if (hasChecked == false && phoneWants == true) { - numBytes = getFromRadio(fromRadioBytes); - hasChecked = true; - } + // Note: phoneWants/hasChecked logic removed since onRead() handles getFromRadio() directly // the run is triggered via NimbleBluetoothToRadioCallback and NimbleBluetoothFromRadioCallback return INT32_MAX; @@ -122,15 +116,8 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks { std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); - // If we don't have fresh data, trigger a refresh - if (!bluetoothPhoneAPI->hasChecked || bluetoothPhoneAPI->numBytes == 0) { - bluetoothPhoneAPI->phoneWants = true; - bluetoothPhoneAPI->setIntervalFromNow(0); - - // Get fresh data immediately - bluetoothPhoneAPI->numBytes = bluetoothPhoneAPI->getFromRadio(bluetoothPhoneAPI->fromRadioBytes); - bluetoothPhoneAPI->hasChecked = true; - } + // Get fresh data immediately when client reads + bluetoothPhoneAPI->numBytes = bluetoothPhoneAPI->getFromRadio(bluetoothPhoneAPI->fromRadioBytes); // Set the characteristic value with whatever data we have pCharacteristic->setValue(bluetoothPhoneAPI->fromRadioBytes, bluetoothPhoneAPI->numBytes); @@ -138,8 +125,6 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks if (bluetoothPhoneAPI->numBytes != 0) // if we did send something, queue it up right away to reload bluetoothPhoneAPI->setIntervalFromNow(0); bluetoothPhoneAPI->numBytes = 0; - bluetoothPhoneAPI->hasChecked = false; - bluetoothPhoneAPI->phoneWants = false; } }; @@ -248,8 +233,6 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks if (bluetoothPhoneAPI) { std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); bluetoothPhoneAPI->close(); - bluetoothPhoneAPI->hasChecked = false; - bluetoothPhoneAPI->phoneWants = false; bluetoothPhoneAPI->numBytes = 0; bluetoothPhoneAPI->queue_size = 0; } From 8bf32dc042fc3e6f7a5d9b988c12492da9930305 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 8 Oct 2025 23:13:02 -0500 Subject: [PATCH 143/166] Attach an interrupt to EXT_PWR_DETECT if present, and force a screen redraw on a power change. --- src/Power.cpp | 10 ++++++++++ src/graphics/Screen.cpp | 3 +++ 2 files changed, 13 insertions(+) diff --git a/src/Power.cpp b/src/Power.cpp index 7de82b8d6..39d47610b 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -691,6 +691,16 @@ bool Power::setup() #ifdef NRF_APM found = true; #endif +#ifdef EXT_PWR_DETECT + attachInterrupt( + EXT_PWR_DETECT, + []() { + power->setIntervalFromNow(0); + runASAP = true; + BaseType_t higherWake = 0; + }, + CHANGE); +#endif enabled = found; low_voltage_counter = 0; diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 4485ca7a3..767f97eed 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1428,6 +1428,9 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) } nodeDB->updateGUI = false; break; + case STATUS_TYPE_POWER: + forceDisplay(true); + break; } return 0; From 29458cd8c4f7699a43e6b97315ff1334c2376d1f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 11 Oct 2025 17:12:10 +1100 Subject: [PATCH 144/166] Update XPowersLib to v0.3.1 (#8303) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- arch/esp32/esp32.ini | 2 +- arch/esp32/esp32c6.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index d2c933461..327444a60 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -56,7 +56,7 @@ lib_deps = # renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip # renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib - https://github.com/lewisxhe/XPowersLib/archive/v0.3.0.zip + https://github.com/lewisxhe/XPowersLib/archive/v0.3.1.zip # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto diff --git a/arch/esp32/esp32c6.ini b/arch/esp32/esp32c6.ini index 1afb9b547..7b06f4cd8 100644 --- a/arch/esp32/esp32c6.ini +++ b/arch/esp32/esp32c6.ini @@ -28,7 +28,7 @@ lib_deps = ${environmental_extra.lib_deps} ${radiolib_base.lib_deps} # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib - lewisxhe/XPowersLib@0.3.0 + lewisxhe/XPowersLib@0.3.1 # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto From 554112ceb5be8994ff785aa16fcede0cd133c2a1 Mon Sep 17 00:00:00 2001 From: thebentern <9000580+thebentern@users.noreply.github.com> Date: Sat, 11 Oct 2025 15:27:33 +0000 Subject: [PATCH 145/166] Automated version bumps --- bin/org.meshtastic.meshtasticd.metainfo.xml | 3 +++ debian/changelog | 6 ++++++ version.properties | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/bin/org.meshtastic.meshtasticd.metainfo.xml b/bin/org.meshtastic.meshtasticd.metainfo.xml index 3505f1940..6fc5e8597 100644 --- a/bin/org.meshtastic.meshtasticd.metainfo.xml +++ b/bin/org.meshtastic.meshtasticd.metainfo.xml @@ -87,6 +87,9 @@ + + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.13 + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.12 diff --git a/debian/changelog b/debian/changelog index 8bd053b25..e124f8929 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +meshtasticd (2.7.13.0) unstable; urgency=medium + + * Version 2.7.13 + + -- GitHub Actions Sat, 11 Oct 2025 15:27:28 +0000 + meshtasticd (2.7.12.0) unstable; urgency=medium [ Austin Lane ] diff --git a/version.properties b/version.properties index 5c84a8e65..f33f0f1cb 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 7 -build = 12 +build = 13 From 9056915e7b62c505678a5c7644ed97acd064f093 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 11 Oct 2025 10:30:33 -0500 Subject: [PATCH 146/166] Double the number of bluetooth bonds NimBLE will store (from 3 to 6) (#8296) --- arch/esp32/esp32.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 327444a60..810c9780e 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -31,6 +31,7 @@ build_flags = -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL -DAXP_DEBUG_PORT=Serial -DCONFIG_BT_NIMBLE_ENABLED + -DCONFIG_BT_NIMBLE_MAX_BONDS=6 # default is 3 -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192 From 981d058e9f427a851a363222349f1c0a60fa0c96 Mon Sep 17 00:00:00 2001 From: Austin Date: Sat, 11 Oct 2025 16:56:59 -0400 Subject: [PATCH 147/166] Actions: CI docker with a fancy matrix (#8253) --- .github/workflows/build_one_arch.yml | 56 ------------------- .github/workflows/build_one_target.yml | 56 ------------------- .github/workflows/main_matrix.yml | 76 ++++++-------------------- .github/workflows/merge_queue.yml | 64 ++++++---------------- 4 files changed, 36 insertions(+), 216 deletions(-) diff --git a/.github/workflows/build_one_arch.yml b/.github/workflows/build_one_arch.yml index 6d9134941..9c57f8b7d 100644 --- a/.github/workflows/build_one_arch.yml +++ b/.github/workflows/build_one_arch.yml @@ -88,62 +88,6 @@ jobs: if: ${{ !contains(github.ref_name, 'event/') && github.event_name != 'workflow_dispatch' || !contains(github.ref_name, 'event/') && inputs.arch == 'native' }} uses: ./.github/workflows/test_native.yml - docker-deb-amd64: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - - docker-deb-amd64-tft: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - pio_env: native-tft - - docker-alp-amd64: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: alpine - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - - docker-alp-amd64-tft: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: alpine - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - pio_env: native-tft - - docker-deb-arm64: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/arm64 - runs-on: ubuntu-24.04-arm - push: false - - docker-deb-armv7: - if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/arm/v7 - runs-on: ubuntu-24.04-arm - push: false - gather-artifacts: permissions: contents: write diff --git a/.github/workflows/build_one_target.yml b/.github/workflows/build_one_target.yml index ba1d5080f..15b3fdba9 100644 --- a/.github/workflows/build_one_target.yml +++ b/.github/workflows/build_one_target.yml @@ -106,62 +106,6 @@ jobs: if: ${{ !contains(github.ref_name, 'event/') && github.event_name != 'workflow_dispatch' || !contains(github.ref_name, 'event/') && inputs.arch == 'native' && inputs.target != '' }} uses: ./.github/workflows/test_native.yml - docker-deb-amd64: - if: ${{ inputs.target != '' && inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - - docker-deb-amd64-tft: - if: ${{ inputs.target != '' && inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - pio_env: native-tft - - docker-alp-amd64: - if: ${{ inputs.target != '' && inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: alpine - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - - docker-alp-amd64-tft: - if: ${{ inputs.target != '' && inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: alpine - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - pio_env: native-tft - - docker-deb-arm64: - if: ${{ inputs.target != '' && inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/arm64 - runs-on: ubuntu-24.04-arm - push: false - - docker-deb-armv7: - if: ${{ inputs.target != '' && inputs.arch == 'native' }} - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/arm/v7 - runs-on: ubuntu-24.04-arm - push: false - gather-artifacts: permissions: contents: write diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 812990eca..02a4c23b8 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -27,7 +27,6 @@ on: jobs: setup: - if: github.repository == 'meshtastic/firmware' strategy: fail-fast: true matrix: @@ -42,10 +41,6 @@ jobs: python-version: 3.x cache: pip - run: pip install -U platformio - - name: Uncomment build epoch - shell: bash - run: | - sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini - name: Generate matrix id: jsonStep run: | @@ -62,7 +57,6 @@ jobs: check: ${{ steps.jsonStep.outputs.check }} version: - if: github.repository == 'meshtastic/firmware' runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -125,60 +119,26 @@ jobs: if: ${{ !contains(github.ref_name, 'event/') && github.repository == 'meshtastic/firmware' }} uses: ./.github/workflows/test_native.yml - docker-deb-amd64: - if: github.repository == 'meshtastic/firmware' + docker: + strategy: + fail-fast: false + matrix: + distro: [debian, alpine] + platform: [linux/amd64, linux/arm64, linux/arm/v7] + pio_env: [native, native-tft] + exclude: + - distro: alpine + platform: linux/arm/v7 + - pio_env: native-tft + platform: linux/arm64 + - pio_env: native-tft + platform: linux/arm/v7 uses: ./.github/workflows/docker_build.yml with: - distro: debian - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - - docker-deb-amd64-tft: - if: github.repository == 'meshtastic/firmware' - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - pio_env: native-tft - - docker-alp-amd64: - if: github.repository == 'meshtastic/firmware' - uses: ./.github/workflows/docker_build.yml - with: - distro: alpine - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - - docker-alp-amd64-tft: - if: github.repository == 'meshtastic/firmware' - uses: ./.github/workflows/docker_build.yml - with: - distro: alpine - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - pio_env: native-tft - - docker-deb-arm64: - if: github.repository == 'meshtastic/firmware' - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/arm64 - runs-on: ubuntu-24.04-arm - push: false - - docker-deb-armv7: - if: github.repository == 'meshtastic/firmware' - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/arm/v7 - runs-on: ubuntu-24.04-arm + distro: ${{ matrix.distro }} + platform: ${{ matrix.platform }} + runs-on: ${{ contains(matrix.platform, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} + pio_env: ${{ matrix.pio_env }} push: false gather-artifacts: diff --git a/.github/workflows/merge_queue.yml b/.github/workflows/merge_queue.yml index 79e8b0803..e8c3d3450 100644 --- a/.github/workflows/merge_queue.yml +++ b/.github/workflows/merge_queue.yml @@ -99,54 +99,26 @@ jobs: if: ${{ !contains(github.ref_name, 'event/') }} uses: ./.github/workflows/test_native.yml - docker-deb-amd64: + docker: + strategy: + fail-fast: false + matrix: + distro: [debian, alpine] + platform: [linux/amd64, linux/arm64, linux/arm/v7] + pio_env: [native, native-tft] + exclude: + - distro: alpine + platform: linux/arm/v7 + - pio_env: native-tft + platform: linux/arm64 + - pio_env: native-tft + platform: linux/arm/v7 uses: ./.github/workflows/docker_build.yml with: - distro: debian - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - - docker-deb-amd64-tft: - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - pio_env: native-tft - - docker-alp-amd64: - uses: ./.github/workflows/docker_build.yml - with: - distro: alpine - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - - docker-alp-amd64-tft: - uses: ./.github/workflows/docker_build.yml - with: - distro: alpine - platform: linux/amd64 - runs-on: ubuntu-24.04 - push: false - pio_env: native-tft - - docker-deb-arm64: - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/arm64 - runs-on: ubuntu-24.04-arm - push: false - - docker-deb-armv7: - uses: ./.github/workflows/docker_build.yml - with: - distro: debian - platform: linux/arm/v7 - runs-on: ubuntu-24.04-arm + distro: ${{ matrix.distro }} + platform: ${{ matrix.platform }} + runs-on: ${{ contains(matrix.platform, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} + pio_env: ${{ matrix.pio_env }} push: false gather-artifacts: From 464663b496708b9845b878d38e122272bc2c1ae6 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 12 Oct 2025 05:33:34 -0500 Subject: [PATCH 148/166] GPS_POWER_TOGGLE no longer has a function, so purge (#8312) --- variants/esp32/diy/hydra/variant.h | 1 - variants/esp32/heltec_v2.1/platformio.ini | 1 - variants/esp32/heltec_wsl_v2.1/platformio.ini | 1 - variants/esp32/tbeam/platformio.ini | 1 - variants/esp32/tlora_v2_1_16/platformio.ini | 1 - variants/esp32/tlora_v2_1_16_tcxo/platformio.ini | 1 - variants/esp32/tlora_v3_3_0_tcxo/platformio.ini | 1 - variants/esp32s3/CDEBYTE_EoRa-S3/platformio.ini | 1 - variants/esp32s3/crowpanel-esp32s3-5-epaper/platformio.ini | 3 --- variants/esp32s3/heltec_capsule_sensor_v3/platformio.ini | 1 - variants/esp32s3/heltec_v3/platformio.ini | 1 - variants/esp32s3/heltec_v4/platformio.ini | 1 - variants/esp32s3/heltec_wireless_tracker/platformio.ini | 1 - variants/esp32s3/heltec_wireless_tracker_V1_0/platformio.ini | 1 - variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini | 1 - variants/esp32s3/heltec_wsl_v3/platformio.ini | 1 - variants/esp32s3/link32_s3_v1/platformio.ini | 1 - variants/esp32s3/t-deck-pro/platformio.ini | 1 - variants/esp32s3/t-deck/platformio.ini | 1 - variants/esp32s3/t-eth-elite/platformio.ini | 1 - variants/esp32s3/tlora-pager/platformio.ini | 1 - variants/esp32s3/tlora_t3s3_epaper/platformio.ini | 1 - variants/esp32s3/tlora_t3s3_v1/platformio.ini | 1 - variants/esp32s3/tracksenger/platformio.ini | 3 --- variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini | 1 - variants/nrf52840/ME25LS01-4Y10TD/platformio.ini | 1 - variants/nrf52840/ME25LS01-4Y10TD_e-ink/platformio.ini | 1 - variants/nrf52840/MS24SF1/platformio.ini | 1 - variants/nrf52840/diy/nrf52_promicro_diy_tcxo/variant.h | 1 - variants/nrf52840/diy/nrf52_promicro_diy_xtal/variant.h | 1 - variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini | 1 - variants/nrf52840/heltec_mesh_node_t114/platformio.ini | 1 - variants/nrf52840/heltec_mesh_solar/platformio.ini | 1 - variants/nrf52840/meshlink/platformio.ini | 1 - variants/nrf52840/meshlink_eink/platformio.ini | 1 - variants/nrf52840/r1-neo/platformio.ini | 1 - variants/nrf52840/rak2560/platformio.ini | 1 - variants/nrf52840/rak4631/platformio.ini | 1 - variants/nrf52840/rak4631_eth_gw/platformio.ini | 1 - variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini | 1 - variants/nrf52840/rak_wismeshtag/platformio.ini | 1 - variants/nrf52840/rak_wismeshtap/platformio.ini | 1 - variants/nrf52840/t-echo-lite/platformio.ini | 1 - variants/nrf52840/t-echo/platformio.ini | 1 - variants/nrf52840/tracker-t1000-e/platformio.ini | 1 - variants/nrf52840/wio-sdk-wm1110/platformio.ini | 1 - variants/nrf52840/wio-t1000-s/platformio.ini | 1 - variants/nrf52840/wio-tracker-wm1110/platformio.ini | 1 - 48 files changed, 52 deletions(-) diff --git a/variants/esp32/diy/hydra/variant.h b/variants/esp32/diy/hydra/variant.h index 0d64c1b5e..e5c10e26b 100644 --- a/variants/esp32/diy/hydra/variant.h +++ b/variants/esp32/diy/hydra/variant.h @@ -6,7 +6,6 @@ #define GPS_TX_PIN 15 #define GPS_RX_PIN 12 #define PIN_GPS_EN 4 -#define GPS_POWER_TOGGLE // Moved definition from platformio.ini to here #define BUTTON_PIN 39 // The middle button GPIO on the T-Beam // Note: On the ESP32 base version, gpio34-39 are input-only, and do not have internal pull-ups. diff --git a/variants/esp32/heltec_v2.1/platformio.ini b/variants/esp32/heltec_v2.1/platformio.ini index 763f9764c..4dcd9e583 100644 --- a/variants/esp32/heltec_v2.1/platformio.ini +++ b/variants/esp32/heltec_v2.1/platformio.ini @@ -7,4 +7,3 @@ build_flags = ${esp32_base.build_flags} -D HELTEC_V2_1 -I variants/esp32/heltec_v2.1 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. diff --git a/variants/esp32/heltec_wsl_v2.1/platformio.ini b/variants/esp32/heltec_wsl_v2.1/platformio.ini index eb44c88d2..6a77cf11b 100644 --- a/variants/esp32/heltec_wsl_v2.1/platformio.ini +++ b/variants/esp32/heltec_wsl_v2.1/platformio.ini @@ -6,4 +6,3 @@ build_flags = ${esp32_base.build_flags} -D PRIVATE_HW -I variants/esp32/heltec_wsl_v2.1 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. diff --git a/variants/esp32/tbeam/platformio.ini b/variants/esp32/tbeam/platformio.ini index ea17751c6..e53f22d30 100644 --- a/variants/esp32/tbeam/platformio.ini +++ b/variants/esp32/tbeam/platformio.ini @@ -10,7 +10,6 @@ build_flags = ${esp32_base.build_flags} -D TBEAM_V10 -I variants/esp32/tbeam - -DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely. -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue upload_speed = 921600 diff --git a/variants/esp32/tlora_v2_1_16/platformio.ini b/variants/esp32/tlora_v2_1_16/platformio.ini index bd85aa847..6967bb480 100644 --- a/variants/esp32/tlora_v2_1_16/platformio.ini +++ b/variants/esp32/tlora_v2_1_16/platformio.ini @@ -4,5 +4,4 @@ board = ttgo-lora32-v21 board_check = true build_flags = ${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/esp32/tlora_v2_1_16 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. upload_speed = 115200 diff --git a/variants/esp32/tlora_v2_1_16_tcxo/platformio.ini b/variants/esp32/tlora_v2_1_16_tcxo/platformio.ini index 9404faa02..a6b9d2254 100644 --- a/variants/esp32/tlora_v2_1_16_tcxo/platformio.ini +++ b/variants/esp32/tlora_v2_1_16_tcxo/platformio.ini @@ -6,6 +6,5 @@ build_flags = ${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/esp32/tlora_v2_1_16 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -D LORA_TCXO_GPIO=33 upload_speed = 115200 \ No newline at end of file diff --git a/variants/esp32/tlora_v3_3_0_tcxo/platformio.ini b/variants/esp32/tlora_v3_3_0_tcxo/platformio.ini index f1110386e..1258fd8b7 100644 --- a/variants/esp32/tlora_v3_3_0_tcxo/platformio.ini +++ b/variants/esp32/tlora_v3_3_0_tcxo/platformio.ini @@ -5,6 +5,5 @@ build_flags = ${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/esp32/tlora_v2_1_16 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -D LORA_TCXO_GPIO=12 -D BUTTON_PIN=0 \ No newline at end of file diff --git a/variants/esp32s3/CDEBYTE_EoRa-S3/platformio.ini b/variants/esp32s3/CDEBYTE_EoRa-S3/platformio.ini index dbd420f04..3fcfbf281 100644 --- a/variants/esp32s3/CDEBYTE_EoRa-S3/platformio.ini +++ b/variants/esp32s3/CDEBYTE_EoRa-S3/platformio.ini @@ -5,4 +5,3 @@ build_flags = ${esp32s3_base.build_flags} -D CDEBYTE_EORA_S3 -I variants/esp32s3/CDEBYTE_EoRa-S3 - -D GPS_POWER_TOGGLE diff --git a/variants/esp32s3/crowpanel-esp32s3-5-epaper/platformio.ini b/variants/esp32s3/crowpanel-esp32s3-5-epaper/platformio.ini index 49e84bf4f..eed21a412 100644 --- a/variants/esp32s3/crowpanel-esp32s3-5-epaper/platformio.ini +++ b/variants/esp32s3/crowpanel-esp32s3-5-epaper/platformio.ini @@ -16,7 +16,6 @@ build_flags = -I variants/esp32s3/crowpanel-esp32s3-5-epaper -D PRIVATE_HW -DBOARD_HAS_PSRAM - -DGPS_POWER_TOGGLE -DEINK_DISPLAY_MODEL=GxEPD2_579_GDEY0579T93 ;https://www.good-display.com/product/439.html -DEINK_WIDTH=792 -DEINK_HEIGHT=272 @@ -46,7 +45,6 @@ build_flags = -I variants/esp32s3/crowpanel-esp32s3-5-epaper -D PRIVATE_HW -DBOARD_HAS_PSRAM - -DGPS_POWER_TOGGLE -DEINK_DISPLAY_MODEL=GxEPD2_420_GYE042A87 ; similar Panel: GDEY042T81 : https://www.good-display.com/product/386.html -DEINK_WIDTH=400 -DEINK_HEIGHT=300 @@ -76,7 +74,6 @@ build_flags = -I variants/esp32s3/crowpanel-esp32s3-5-epaper -D PRIVATE_HW -DBOARD_HAS_PSRAM - -DGPS_POWER_TOGGLE -DEINK_DISPLAY_MODEL=GxEPD2_290_GDEY029T94 ;https://www.good-display.com/product/389.html -DEINK_WIDTH=296 -DEINK_HEIGHT=128 diff --git a/variants/esp32s3/heltec_capsule_sensor_v3/platformio.ini b/variants/esp32s3/heltec_capsule_sensor_v3/platformio.ini index d43ffd0df..0bb21581a 100644 --- a/variants/esp32s3/heltec_capsule_sensor_v3/platformio.ini +++ b/variants/esp32s3/heltec_capsule_sensor_v3/platformio.ini @@ -6,5 +6,4 @@ board_build.partitions = default_8MB.csv build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/heltec_capsule_sensor_v3 -D HELTEC_CAPSULE_SENSOR_V3 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output diff --git a/variants/esp32s3/heltec_v3/platformio.ini b/variants/esp32s3/heltec_v3/platformio.ini index b521e11ca..af0854e49 100644 --- a/variants/esp32s3/heltec_v3/platformio.ini +++ b/variants/esp32s3/heltec_v3/platformio.ini @@ -8,4 +8,3 @@ build_flags = ${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/esp32s3/heltec_v3 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. diff --git a/variants/esp32s3/heltec_v4/platformio.ini b/variants/esp32s3/heltec_v4/platformio.ini index d0a250ad3..7057f9646 100644 --- a/variants/esp32s3/heltec_v4/platformio.ini +++ b/variants/esp32s3/heltec_v4/platformio.ini @@ -7,4 +7,3 @@ build_flags = ${esp32s3_base.build_flags} -D HELTEC_V4 -I variants/esp32s3/heltec_v4 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. diff --git a/variants/esp32s3/heltec_wireless_tracker/platformio.ini b/variants/esp32s3/heltec_wireless_tracker/platformio.ini index 2faba45a8..3a373bf4f 100644 --- a/variants/esp32s3/heltec_wireless_tracker/platformio.ini +++ b/variants/esp32s3/heltec_wireless_tracker/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/heltec_wireless_tracker -D HELTEC_TRACKER_V1_1 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output lib_deps = diff --git a/variants/esp32s3/heltec_wireless_tracker_V1_0/platformio.ini b/variants/esp32s3/heltec_wireless_tracker_V1_0/platformio.ini index 89fe4b385..cd961533d 100644 --- a/variants/esp32s3/heltec_wireless_tracker_V1_0/platformio.ini +++ b/variants/esp32s3/heltec_wireless_tracker_V1_0/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/heltec_wireless_tracker_V1_0 -D HELTEC_TRACKER_V1_0 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output lib_deps = ${esp32s3_base.lib_deps} diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini b/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini index 4872561db..0f9265f91 100644 --- a/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini +++ b/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/heltec_wireless_tracker_v2 -D HELTEC_WIRELESS_TRACKER_V2 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX@^1.2.0 diff --git a/variants/esp32s3/heltec_wsl_v3/platformio.ini b/variants/esp32s3/heltec_wsl_v3/platformio.ini index 06cde2304..c038a463e 100644 --- a/variants/esp32s3/heltec_wsl_v3/platformio.ini +++ b/variants/esp32s3/heltec_wsl_v3/platformio.ini @@ -7,4 +7,3 @@ build_flags = ${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/esp32s3/heltec_wsl_v3 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. diff --git a/variants/esp32s3/link32_s3_v1/platformio.ini b/variants/esp32s3/link32_s3_v1/platformio.ini index c1b71b3b5..8d88075c4 100644 --- a/variants/esp32s3/link32_s3_v1/platformio.ini +++ b/variants/esp32s3/link32_s3_v1/platformio.ini @@ -5,7 +5,6 @@ build_flags = ${esp32_base.build_flags} -D LINK_32 -I variants/esp32s3/link32_s3_v1 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DARDUINO_USB_CDC_ON_BOOT -DARDUINO_USB_MODE=1 -DRADIOLIB_EXCLUDE_SX128X=1 diff --git a/variants/esp32s3/t-deck-pro/platformio.ini b/variants/esp32s3/t-deck-pro/platformio.ini index 45c3ae4ea..0b3c7843a 100644 --- a/variants/esp32s3/t-deck-pro/platformio.ini +++ b/variants/esp32s3/t-deck-pro/platformio.ini @@ -7,7 +7,6 @@ upload_protocol = esptool build_flags = ${esp32_base.build_flags} -I variants/esp32s3/t-deck-pro -D T_DECK_PRO - -D GPS_POWER_TOGGLE -D USE_EINK -D EINK_DISPLAY_MODEL=GxEPD2_310_GDEQ031T10 -D EINK_WIDTH=240 diff --git a/variants/esp32s3/t-deck/platformio.ini b/variants/esp32s3/t-deck/platformio.ini index 7c8070c3e..9ab0756d1 100644 --- a/variants/esp32s3/t-deck/platformio.ini +++ b/variants/esp32s3/t-deck/platformio.ini @@ -9,7 +9,6 @@ upload_protocol = esptool build_flags = ${esp32s3_base.build_flags} -D T_DECK -D BOARD_HAS_PSRAM - -D GPS_POWER_TOGGLE -I variants/esp32s3/t-deck lib_deps = ${esp32s3_base.lib_deps} diff --git a/variants/esp32s3/t-eth-elite/platformio.ini b/variants/esp32s3/t-eth-elite/platformio.ini index 6107185ce..1a5823bc3 100644 --- a/variants/esp32s3/t-eth-elite/platformio.ini +++ b/variants/esp32s3/t-eth-elite/platformio.ini @@ -9,7 +9,6 @@ build_flags = -D T_ETH_ELITE -D HAS_UDP_MULTICAST=1 -I variants/esp32s3/t-eth-elite - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. lib_ignore = Ethernet diff --git a/variants/esp32s3/tlora-pager/platformio.ini b/variants/esp32s3/tlora-pager/platformio.ini index 9800161bb..d63537904 100644 --- a/variants/esp32s3/tlora-pager/platformio.ini +++ b/variants/esp32s3/tlora-pager/platformio.ini @@ -10,7 +10,6 @@ build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/tlora-pager -D T_LORA_PAGER -D BOARD_HAS_PSRAM - -D GPS_POWER_TOGGLE -D HAS_SDCARD -D SDCARD_USE_SPI1 -D ENABLE_ROTARY_PULLUP diff --git a/variants/esp32s3/tlora_t3s3_epaper/platformio.ini b/variants/esp32s3/tlora_t3s3_epaper/platformio.ini index 71644ee77..eca052f57 100644 --- a/variants/esp32s3/tlora_t3s3_epaper/platformio.ini +++ b/variants/esp32s3/tlora_t3s3_epaper/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${esp32_base.build_flags} -D TLORA_T3S3_EPAPER -I variants/esp32s3/tlora_t3s3_epaper - -DGPS_POWER_TOGGLE -DUSE_EINK -DEINK_DISPLAY_MODEL=GxEPD2_213_BN -DEINK_WIDTH=250 diff --git a/variants/esp32s3/tlora_t3s3_v1/platformio.ini b/variants/esp32s3/tlora_t3s3_v1/platformio.ini index d9624f043..56ece0d62 100644 --- a/variants/esp32s3/tlora_t3s3_v1/platformio.ini +++ b/variants/esp32s3/tlora_t3s3_v1/platformio.ini @@ -6,4 +6,3 @@ upload_protocol = esptool build_flags = ${esp32_base.build_flags} -D TLORA_T3S3_V1 -I variants/esp32s3/tlora_t3s3_v1 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. diff --git a/variants/esp32s3/tracksenger/platformio.ini b/variants/esp32s3/tracksenger/platformio.ini index 0e9f08541..213a917b1 100644 --- a/variants/esp32s3/tracksenger/platformio.ini +++ b/variants/esp32s3/tracksenger/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/tracksenger/internal -D HELTEC_TRACKER_V1_1 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output lib_deps = @@ -25,7 +24,6 @@ build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/tracksenger/lcd -D HELTEC_TRACKER_V1_1 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output lib_deps = @@ -42,5 +40,4 @@ build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/tracksenger/oled -D HELTEC_TRACKER_V1_1 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output diff --git a/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini b/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini index 0578bcfe8..f89b05d1f 100644 --- a/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini +++ b/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini @@ -9,7 +9,6 @@ debug_tool = jlink build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/ELECROW-ThinkNode-M1 -DELECROW_ThinkNode_M1 - -DGPS_POWER_TOGGLE -DUSE_EINK -DEINK_DISPLAY_MODEL=GxEPD2_154_D67 -DEINK_WIDTH=200 diff --git a/variants/nrf52840/ME25LS01-4Y10TD/platformio.ini b/variants/nrf52840/ME25LS01-4Y10TD/platformio.ini index 89a45694c..1279f12c6 100644 --- a/variants/nrf52840/ME25LS01-4Y10TD/platformio.ini +++ b/variants/nrf52840/ME25LS01-4Y10TD/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${nrf52840_base.build_flags} -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DME25LS01_4Y10TD - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/ME25LS01-4Y10TD> lib_deps = diff --git a/variants/nrf52840/ME25LS01-4Y10TD_e-ink/platformio.ini b/variants/nrf52840/ME25LS01-4Y10TD_e-ink/platformio.ini index ad5867bd5..f8d6da008 100644 --- a/variants/nrf52840/ME25LS01-4Y10TD_e-ink/platformio.ini +++ b/variants/nrf52840/ME25LS01-4Y10TD_e-ink/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${nrf52840_base.build_flags} -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DME25LS01_4Y10TD - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DEINK_DISPLAY_MODEL=GxEPD2_420_GDEY042T81 -DEINK_WIDTH=400 -DEINK_HEIGHT=300 diff --git a/variants/nrf52840/MS24SF1/platformio.ini b/variants/nrf52840/MS24SF1/platformio.ini index f162cbd60..df15b5605 100644 --- a/variants/nrf52840/MS24SF1/platformio.ini +++ b/variants/nrf52840/MS24SF1/platformio.ini @@ -7,7 +7,6 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/MS24SF1 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/MS24SF1> lib_deps = diff --git a/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/variant.h b/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/variant.h index e93442c7e..87342a02f 100644 --- a/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/variant.h +++ b/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/variant.h @@ -94,7 +94,6 @@ NRF52 PRO MICRO PIN ASSIGNMENT #define PIN_GPS_RX (0 + 20) // P0.20 #define PIN_GPS_EN (0 + 24) // P0.24 -#define GPS_POWER_TOGGLE #define GPS_UBLOX // define GPS_DEBUG diff --git a/variants/nrf52840/diy/nrf52_promicro_diy_xtal/variant.h b/variants/nrf52840/diy/nrf52_promicro_diy_xtal/variant.h index 7aafab7da..6e208e79f 100644 --- a/variants/nrf52840/diy/nrf52_promicro_diy_xtal/variant.h +++ b/variants/nrf52840/diy/nrf52_promicro_diy_xtal/variant.h @@ -93,7 +93,6 @@ NRF52 PRO MICRO PIN ASSIGNMENT #define PIN_GPS_RX (0 + 20) // P0.20 #define PIN_GPS_EN (0 + 24) // P0.24 -#define GPS_POWER_TOGGLE #define GPS_UBLOX // define GPS_DEBUG diff --git a/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini b/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini index c6a5a7399..c6cd23314 100644 --- a/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini +++ b/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/gat562_mesh_trial_tracker ;-D GAT562_MESH_TRIAL_TRACKER -D PRIVATE_HW - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 diff --git a/variants/nrf52840/heltec_mesh_node_t114/platformio.ini b/variants/nrf52840/heltec_mesh_node_t114/platformio.ini index c7b30b339..c49dadd56 100644 --- a/variants/nrf52840/heltec_mesh_node_t114/platformio.ini +++ b/variants/nrf52840/heltec_mesh_node_t114/platformio.ini @@ -8,7 +8,6 @@ debug_tool = jlink # add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/heltec_mesh_node_t114 - -DGPS_POWER_TOGGLE -DHELTEC_T114 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_mesh_node_t114> diff --git a/variants/nrf52840/heltec_mesh_solar/platformio.ini b/variants/nrf52840/heltec_mesh_solar/platformio.ini index 625dd1d43..36a7904d6 100644 --- a/variants/nrf52840/heltec_mesh_solar/platformio.ini +++ b/variants/nrf52840/heltec_mesh_solar/platformio.ini @@ -8,7 +8,6 @@ debug_tool = jlink # add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/heltec_mesh_solar - -DGPS_POWER_TOGGLE -DHELTEC_MESH_SOLAR build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_mesh_solar> diff --git a/variants/nrf52840/meshlink/platformio.ini b/variants/nrf52840/meshlink/platformio.ini index 466362242..2a4e27fe8 100644 --- a/variants/nrf52840/meshlink/platformio.ini +++ b/variants/nrf52840/meshlink/platformio.ini @@ -9,7 +9,6 @@ board_level = extra build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/meshlink -D MESHLINK - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -D EINK_DISPLAY_MODEL=GxEPD2_213_B74 -D EINK_WIDTH=250 -D EINK_HEIGHT=122 diff --git a/variants/nrf52840/meshlink_eink/platformio.ini b/variants/nrf52840/meshlink_eink/platformio.ini index af5a0040e..c0c0cb1dd 100644 --- a/variants/nrf52840/meshlink_eink/platformio.ini +++ b/variants/nrf52840/meshlink_eink/platformio.ini @@ -9,7 +9,6 @@ board_level = extra build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/meshlink_eink -D MESHLINK - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -D EINK_DISPLAY_MODEL=GxEPD2_213_B74 -D EINK_WIDTH=250 -D EINK_HEIGHT=122 diff --git a/variants/nrf52840/r1-neo/platformio.ini b/variants/nrf52840/r1-neo/platformio.ini index 6feb55dc9..60f1f6ae1 100644 --- a/variants/nrf52840/r1-neo/platformio.ini +++ b/variants/nrf52840/r1-neo/platformio.ini @@ -6,7 +6,6 @@ board_check = true build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/r1-neo -D R1_NEO - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 diff --git a/variants/nrf52840/rak2560/platformio.ini b/variants/nrf52840/rak2560/platformio.ini index edc648b9b..021e6d03b 100644 --- a/variants/nrf52840/rak2560/platformio.ini +++ b/variants/nrf52840/rak2560/platformio.ini @@ -6,7 +6,6 @@ board_check = true build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/rak2560 -D RAK_4631 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 diff --git a/variants/nrf52840/rak4631/platformio.ini b/variants/nrf52840/rak4631/platformio.ini index 6bf5f44cb..205966529 100644 --- a/variants/nrf52840/rak4631/platformio.ini +++ b/variants/nrf52840/rak4631/platformio.ini @@ -7,7 +7,6 @@ board_check = true build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/rak4631 -D RAK_4631 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DEINK_DISPLAY_MODEL=GxEPD2_213_BN -DEINK_WIDTH=250 -DEINK_HEIGHT=122 diff --git a/variants/nrf52840/rak4631_eth_gw/platformio.ini b/variants/nrf52840/rak4631_eth_gw/platformio.ini index 4be8843a2..3c61e3498 100644 --- a/variants/nrf52840/rak4631_eth_gw/platformio.ini +++ b/variants/nrf52840/rak4631_eth_gw/platformio.ini @@ -6,7 +6,6 @@ board_check = true build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/rak4631_eth_gw -D RAK_4631 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DHAS_UDP_MULTICAST=1 -DEINK_DISPLAY_MODEL=GxEPD2_213_BN -DEINK_WIDTH=250 diff --git a/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini b/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini index e94eef1ee..d7dab2678 100644 --- a/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini +++ b/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini @@ -6,7 +6,6 @@ board_check = true build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/rak4631_nomadstar_meteor_pro -D NOMADSTAR_METEOR_PRO - ;-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DEINK_DISPLAY_MODEL=GxEPD2_213_BN -DEINK_WIDTH=250 -DEINK_HEIGHT=122 diff --git a/variants/nrf52840/rak_wismeshtag/platformio.ini b/variants/nrf52840/rak_wismeshtag/platformio.ini index 08e723302..f04d1f186 100644 --- a/variants/nrf52840/rak_wismeshtag/platformio.ini +++ b/variants/nrf52840/rak_wismeshtag/platformio.ini @@ -7,7 +7,6 @@ build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/rak_wismeshtag -D WISMESH_TAG -D RAK_4631 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 diff --git a/variants/nrf52840/rak_wismeshtap/platformio.ini b/variants/nrf52840/rak_wismeshtap/platformio.ini index adf301537..3369f9c77 100644 --- a/variants/nrf52840/rak_wismeshtap/platformio.ini +++ b/variants/nrf52840/rak_wismeshtap/platformio.ini @@ -6,7 +6,6 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/rak_wismeshtap -DWISMESH_TAP -DRAK_4631 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DEINK_DISPLAY_MODEL=GxEPD2_213_BN -DEINK_WIDTH=250 -DEINK_HEIGHT=122 diff --git a/variants/nrf52840/t-echo-lite/platformio.ini b/variants/nrf52840/t-echo-lite/platformio.ini index 68ae59dcb..90e6487a7 100644 --- a/variants/nrf52840/t-echo-lite/platformio.ini +++ b/variants/nrf52840/t-echo-lite/platformio.ini @@ -9,7 +9,6 @@ debug_tool = jlink build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/t-echo-lite -D T_ECHO_LITE - -D GPS_POWER_TOGGLE -D EINK_DISPLAY_MODEL=GxEPD2_122_T61 -D EINK_WIDTH=192 -D EINK_HEIGHT=176 diff --git a/variants/nrf52840/t-echo/platformio.ini b/variants/nrf52840/t-echo/platformio.ini index 6541c9796..051fb3099 100644 --- a/variants/nrf52840/t-echo/platformio.ini +++ b/variants/nrf52840/t-echo/platformio.ini @@ -9,7 +9,6 @@ debug_tool = jlink # add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/t-echo - -DGPS_POWER_TOGGLE -DEINK_DISPLAY_MODEL=GxEPD2_154_D67 -DEINK_WIDTH=200 -DEINK_HEIGHT=200 diff --git a/variants/nrf52840/tracker-t1000-e/platformio.ini b/variants/nrf52840/tracker-t1000-e/platformio.ini index c6c3f269c..905d751fd 100644 --- a/variants/nrf52840/tracker-t1000-e/platformio.ini +++ b/variants/nrf52840/tracker-t1000-e/platformio.ini @@ -7,7 +7,6 @@ build_flags = ${nrf52840_base.build_flags} -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DTRACKER_T1000_E - -DGPS_POWER_TOGGLE -DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL=1 -DMESHTASTIC_EXCLUDE_CANNEDMESSAGES=1 -DMESHTASTIC_EXCLUDE_SCREEN=1 diff --git a/variants/nrf52840/wio-sdk-wm1110/platformio.ini b/variants/nrf52840/wio-sdk-wm1110/platformio.ini index 2c65246b8..028129783 100644 --- a/variants/nrf52840/wio-sdk-wm1110/platformio.ini +++ b/variants/nrf52840/wio-sdk-wm1110/platformio.ini @@ -14,7 +14,6 @@ build_flags = ${nrf52840_base.build_flags} -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DCFG_TUD_CDC=0 board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/wio-sdk-wm1110> diff --git a/variants/nrf52840/wio-t1000-s/platformio.ini b/variants/nrf52840/wio-t1000-s/platformio.ini index 3594bcf07..c6b61fc8a 100644 --- a/variants/nrf52840/wio-t1000-s/platformio.ini +++ b/variants/nrf52840/wio-t1000-s/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${nrf52840_base.build_flags} -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/wio-t1000-s> lib_deps = diff --git a/variants/nrf52840/wio-tracker-wm1110/platformio.ini b/variants/nrf52840/wio-tracker-wm1110/platformio.ini index b383043bb..73b7dedd4 100644 --- a/variants/nrf52840/wio-tracker-wm1110/platformio.ini +++ b/variants/nrf52840/wio-tracker-wm1110/platformio.ini @@ -7,7 +7,6 @@ build_flags = ${nrf52840_base.build_flags} -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 - -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/wio-tracker-wm1110> lib_deps = From cb11e6b720fcf3eceed1b0e557013ec68153421e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 12 Oct 2025 05:34:00 -0500 Subject: [PATCH 149/166] Update protobufs (#8305) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/channel.pb.h | 22 ++++++++----------- src/mesh/generated/meshtastic/deviceonly.pb.h | 4 ++-- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/protobufs b/protobufs index a1b8c3d17..38638f19f 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit a1b8c3d171445b2eebfd4b5bd1e4876f3bbed605 +Subproject commit 38638f19f84ad886222b484d6bf5a8459aed8c7e diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index db9dedaaf..f4c33bd79 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 695 +#define meshtastic_ChannelSet_size 679 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index d5573a1e2..9dc757ab4 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -34,9 +34,9 @@ typedef enum _meshtastic_Channel_Role { typedef struct _meshtastic_ModuleSettings { /* Bits of precision for the location sent in position packets. */ uint32_t position_precision; - /* Controls whether or not the phone / clients should mute the current channel + /* Controls whether or not the client / device should mute the current channel Useful for noisy public channels you don't necessarily want to disable */ - bool is_client_muted; + bool is_muted; } meshtastic_ModuleSettings; typedef PB_BYTES_ARRAY_T(32) meshtastic_ChannelSettings_psk_t; @@ -97,8 +97,6 @@ typedef struct _meshtastic_ChannelSettings { /* Per-channel module settings. */ bool has_module_settings; meshtastic_ModuleSettings module_settings; - /* Whether or not we should receive notifactions / alerts through this channel */ - bool mute; } meshtastic_ChannelSettings; /* A pair of a channel number, mode and the (sharable) settings for that channel */ @@ -130,16 +128,16 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0} +#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default} #define meshtastic_ModuleSettings_init_default {0, 0} #define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN} -#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0} +#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero} #define meshtastic_ModuleSettings_init_zero {0, 0} #define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_ModuleSettings_position_precision_tag 1 -#define meshtastic_ModuleSettings_is_client_muted_tag 2 +#define meshtastic_ModuleSettings_is_muted_tag 2 #define meshtastic_ChannelSettings_channel_num_tag 1 #define meshtastic_ChannelSettings_psk_tag 2 #define meshtastic_ChannelSettings_name_tag 3 @@ -147,7 +145,6 @@ extern "C" { #define meshtastic_ChannelSettings_uplink_enabled_tag 5 #define meshtastic_ChannelSettings_downlink_enabled_tag 6 #define meshtastic_ChannelSettings_module_settings_tag 7 -#define meshtastic_ChannelSettings_mute_tag 8 #define meshtastic_Channel_index_tag 1 #define meshtastic_Channel_settings_tag 2 #define meshtastic_Channel_role_tag 3 @@ -160,15 +157,14 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \ X(a, STATIC, SINGULAR, FIXED32, id, 4) \ X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \ -X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \ -X(a, STATIC, SINGULAR, BOOL, mute, 8) +X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) #define meshtastic_ChannelSettings_CALLBACK NULL #define meshtastic_ChannelSettings_DEFAULT NULL #define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings #define meshtastic_ModuleSettings_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, position_precision, 1) \ -X(a, STATIC, SINGULAR, BOOL, is_client_muted, 2) +X(a, STATIC, SINGULAR, BOOL, is_muted, 2) #define meshtastic_ModuleSettings_CALLBACK NULL #define meshtastic_ModuleSettings_DEFAULT NULL @@ -191,8 +187,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size -#define meshtastic_ChannelSettings_size 74 -#define meshtastic_Channel_size 89 +#define meshtastic_ChannelSettings_size 72 +#define meshtastic_Channel_size 87 #define meshtastic_ModuleSettings_size 8 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index b5b116137..7fab82ff7 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -360,8 +360,8 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_NodeDatabase_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size -#define meshtastic_BackupPreferences_size 2293 -#define meshtastic_ChannelFile_size 734 +#define meshtastic_BackupPreferences_size 2277 +#define meshtastic_ChannelFile_size 718 #define meshtastic_DeviceState_size 1737 #define meshtastic_NodeInfoLite_size 196 #define meshtastic_PositionLite_size 28 From 11aff46af1e41a4800ae0cead411641a13c5822d Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Sun, 12 Oct 2025 21:34:34 +1100 Subject: [PATCH 150/166] Remove T1000E GPS startup delay sequence (#8236) 8 months ago, when this was added to the code, the GPS probe code was still a little flaky. Particularly after #6114 and #6116 were added, reliability improved for all devices as we were sending fewer calls on the bus. Today, the T1000E is the only Meshtastic device that regularly takes 2, 3, or 4 attempts to be detected via the probe code. Removing these lines, on my T1000E, results in the AG3335 being detected immediately. Co-authored-by: Jonathan Bennett --- src/gps/GPS.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 2cfa558ed..297ed3dfa 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -494,17 +494,6 @@ bool GPS::setup() if (!didSerialInit) { int msglen = 0; if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { -#ifdef TRACKER_T1000_E - // add power up/down strategy, improve ag3335 detection success - digitalWrite(PIN_GPS_EN, LOW); - delay(500); - digitalWrite(GPS_VRTC_EN, LOW); - delay(1000); - digitalWrite(GPS_VRTC_EN, HIGH); - delay(500); - digitalWrite(PIN_GPS_EN, HIGH); - delay(1000); -#endif if (probeTries < GPS_PROBETRIES) { gnssModel = probe(serialSpeeds[speedSelect]); if (gnssModel == GNSS_MODEL_UNKNOWN) { From fb08e17c39f625c5ddfea85918a0f6d86c67a019 Mon Sep 17 00:00:00 2001 From: Clive Blackledge Date: Sun, 12 Oct 2025 03:35:00 -0700 Subject: [PATCH 151/166] Increase bluetooth 5.0 PHY speed and MTU on esp32_s3 (#8261) * Increase Bluetooth speed to 2MB, increase MTU * Adding esp32c6 * trunk fmt.. --- src/detect/ScanI2CTwoWire.cpp | 3 +- src/nimble/NimbleBluetooth.cpp | 62 +++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 89a0610b4..d6daf7b7a 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -378,7 +378,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2); - if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0x11f3 || registerValue == 0xe9c || registerValue == 0xc8d) { + if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0x11f3 || registerValue == 0xe9c || + registerValue == 0xc8d) { type = SHT4X; logFoundDevice("SHT4X", (uint8_t)addr.address); } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) { diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 0b3009d39..60165b2c0 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -17,6 +17,21 @@ #include "PowerStatus.h" #endif +#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6) +#if defined(CONFIG_NIMBLE_CPP_IDF) +#include "host/ble_gap.h" +#else +#include "nimble/nimble/host/include/host/ble_gap.h" +#endif + +namespace +{ +constexpr uint16_t kPreferredBleMtu = 517; +constexpr uint16_t kPreferredBleTxOctets = 251; +constexpr uint16_t kPreferredBleTxTimeUs = (kPreferredBleTxOctets + 14) * 8; +} // namespace +#endif + NimBLECharacteristic *fromNumCharacteristic; NimBLECharacteristic *BatteryCharacteristic; NimBLECharacteristic *logRadioCharacteristic; @@ -212,6 +227,27 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks virtual void onConnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo) { LOG_INFO("BLE incoming connection %s", connInfo.getAddress().toString().c_str()); + +#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6) + const uint16_t connHandle = connInfo.getConnHandle(); + int phyResult = + ble_gap_set_prefered_le_phy(connHandle, BLE_GAP_LE_PHY_2M_MASK, BLE_GAP_LE_PHY_2M_MASK, BLE_GAP_LE_PHY_CODED_ANY); + if (phyResult == 0) { + LOG_INFO("BLE conn %u requested 2M PHY", connHandle); + } else { + LOG_WARN("Failed to prefer 2M PHY for conn %u, rc=%d", connHandle, phyResult); + } + + int dataLenResult = ble_gap_set_data_len(connHandle, kPreferredBleTxOctets, kPreferredBleTxTimeUs); + if (dataLenResult == 0) { + LOG_INFO("BLE conn %u requested data length %u bytes", connHandle, kPreferredBleTxOctets); + } else { + LOG_WARN("Failed to raise data length for conn %u, rc=%d", connHandle, dataLenResult); + } + + LOG_INFO("BLE conn %u initial MTU %u (target %u)", connHandle, connInfo.getMTU(), kPreferredBleMtu); + pServer->updateConnParams(connHandle, 6, 12, 0, 200); +#endif } virtual void onDisconnect(NimBLEServer *pServer, NimBLEConnInfo &connInfo, int reason) @@ -316,6 +352,30 @@ void NimbleBluetooth::setup() NimBLEDevice::init(getDeviceName()); NimBLEDevice::setPower(ESP_PWR_LVL_P9); +#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C6) + int mtuResult = NimBLEDevice::setMTU(kPreferredBleMtu); + if (mtuResult == 0) { + LOG_INFO("BLE MTU request set to %u", kPreferredBleMtu); + } else { + LOG_WARN("Unable to request MTU %u, rc=%d", kPreferredBleMtu, mtuResult); + } + + int phyResult = ble_gap_set_prefered_default_le_phy(BLE_GAP_LE_PHY_2M_MASK, BLE_GAP_LE_PHY_2M_MASK); + if (phyResult == 0) { + LOG_INFO("BLE default PHY preference set to 2M"); + } else { + LOG_WARN("Failed to prefer 2M PHY by default, rc=%d", phyResult); + } + + int dataLenResult = ble_gap_write_sugg_def_data_len(kPreferredBleTxOctets, kPreferredBleTxTimeUs); + if (dataLenResult == 0) { + LOG_INFO("BLE suggested data length set to %u bytes", kPreferredBleTxOctets); + } else { + LOG_WARN("Failed to raise suggested data length (%u/%u), rc=%d", kPreferredBleTxOctets, kPreferredBleTxTimeUs, + dataLenResult); + } +#endif + if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) { NimBLEDevice::setSecurityAuth(BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM | BLE_SM_PAIR_AUTHREQ_SC); NimBLEDevice::setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID); @@ -459,4 +519,4 @@ void clearNVS() ESP.restart(); #endif } -#endif \ No newline at end of file +#endif From f0126d44e2c6e464144a1df98a24b660c6c92496 Mon Sep 17 00:00:00 2001 From: Jason P Date: Sun, 12 Oct 2025 06:28:23 -0500 Subject: [PATCH 152/166] More BaseUI Frame Visibility Toggles (#8252) * Add Power and Environmental Telemetry Hide/Show * Allow Power and Telemetry Frames even if module disabled --------- Co-authored-by: Ben Meadors --- src/graphics/draw/MenuHandler.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index c93e34545..3e139c0d6 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -1431,6 +1431,8 @@ void menuHandler::FrameToggles_menu() lora, clock, show_favorites, + show_telemetry, + show_power, enumEnd }; static const char *optionsArray[enumEnd] = {"Finish"}; @@ -1469,6 +1471,12 @@ void menuHandler::FrameToggles_menu() optionsArray[options] = screen->isFrameHidden("show_favorites") ? "Show Favorites" : "Hide Favorites"; optionsEnumArray[options++] = show_favorites; + optionsArray[options] = moduleConfig.telemetry.environment_screen_enabled ? "Hide Telemetry" : "Show Telemetry"; + optionsEnumArray[options++] = show_telemetry; + + optionsArray[options] = moduleConfig.telemetry.power_screen_enabled ? "Hide Power" : "Show Power"; + optionsEnumArray[options++] = show_power; + BannerOverlayOptions bannerOptions; bannerOptions.message = "Show/Hide Frames"; bannerOptions.optionsArrayPtr = optionsArray; @@ -1523,6 +1531,14 @@ void menuHandler::FrameToggles_menu() screen->toggleFrameVisibility("show_favorites"); menuHandler::menuQueue = menuHandler::FrameToggles; screen->runNow(); + } else if (selected == show_telemetry) { + moduleConfig.telemetry.environment_screen_enabled = !moduleConfig.telemetry.environment_screen_enabled; + menuHandler::menuQueue = menuHandler::FrameToggles; + screen->runNow(); + } else if (selected == show_power) { + moduleConfig.telemetry.power_screen_enabled = !moduleConfig.telemetry.power_screen_enabled; + menuHandler::menuQueue = menuHandler::FrameToggles; + screen->runNow(); } }; screen->showOverlayBanner(bannerOptions); From a6732682deb60b31f0779f730b464499e30f5da4 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 12 Oct 2025 06:30:17 -0500 Subject: [PATCH 153/166] Opt in to telemetry going forward (#8059) --- src/modules/Telemetry/DeviceTelemetry.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 7e3018564..066b9361d 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -26,7 +26,8 @@ int32_t DeviceTelemetryModule::runOnce() Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval, default_telemetry_broadcast_interval_secs, numOnlineNodes))) && airTime->isTxAllowedChannelUtil(!isImpoliteRole) && airTime->isTxAllowedAirUtil() && - config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) { + config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN && + moduleConfig.telemetry.device_telemetry_enabled) { sendTelemetry(); lastSentToMesh = uptimeLastMs; } else if (service->isToPhoneQueueEmpty()) { From 661e596dbb71a91f3c30098ac0a82a608e933b70 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 12 Oct 2025 07:39:23 -0500 Subject: [PATCH 154/166] Fix muted channel compile errors after protobuf move (#8316) --- src/graphics/Screen.cpp | 2 +- src/modules/ExternalNotificationModule.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 767f97eed..e1cc0ccad 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1490,7 +1490,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) strcpy(banner, "Alert Received"); } screen->showSimpleBanner(banner, 3000); - } else if (!channel.settings.mute) { + } else if (!channel.settings.has_module_settings || !channel.settings.module_settings.is_muted) { if (longName && longName[0]) { #if defined(M5STACK_UNITC6L) strcpy(banner, "New Message"); diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 2346cd299..ffc789275 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -510,7 +510,8 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_message && + (!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) { LOG_INFO("externalNotificationModule - Notification Module"); isNagging = true; setExternalState(0, true); @@ -521,7 +522,8 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_vibra && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_message_vibra && + (!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) { LOG_INFO("externalNotificationModule - Notification Module (Vibra)"); isNagging = true; setExternalState(1, true); @@ -532,7 +534,8 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_buzzer && !ch.settings.mute) { + if (moduleConfig.external_notification.alert_message_buzzer && + (!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) { LOG_INFO("externalNotificationModule - Notification Module (Buzzer)"); if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY || (!isBroadcast(mp.to) && isToUs(&mp))) { From 5eeffdb290b1e1f1a35d186066ffaf2cdf76dbfc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 12 Oct 2025 07:44:54 -0500 Subject: [PATCH 155/166] chore(deps): update meshtastic/device-ui digest to 3fb7c0e (#8291) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 7121f00b7..5b7f5ddcf 100644 --- a/platformio.ini +++ b/platformio.ini @@ -120,7 +120,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/6d8cc228298a1ecd9913aed757187e9527c1facc.zip + https://github.com/meshtastic/device-ui/archive/3fb7c0e28e8e51fc0a7d56facacf3411f1d29fe0.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From 7537d28419d2bd2dc70519889b509cc1994789ff Mon Sep 17 00:00:00 2001 From: l0g-lab <72365840+l0g-lab@users.noreply.github.com> Date: Sun, 12 Oct 2025 09:25:15 -0400 Subject: [PATCH 156/166] Nodelist: choice of long or short name (#7926) * update to use long names for pager * remove duplicate * add menu item * fix after conflict * menu name change. use sanitizeString * fix formatting issue. should pass trunk now. * remove auto-generated protobufs * remove log, add tdeck, improvements. --------- Co-authored-by: l0g-lab Co-authored-by: Tom Fifield Co-authored-by: Ben Meadors --- src/graphics/draw/MenuHandler.cpp | 42 ++++++++++++++++++++++++-- src/graphics/draw/MenuHandler.h | 2 ++ src/graphics/draw/NodeListRenderer.cpp | 32 ++++++++++++-------- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index 3e139c0d6..701062e08 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -762,6 +762,31 @@ void menuHandler::nodeListMenu() screen->showOverlayBanner(bannerOptions); } +void menuHandler::nodeNameLengthMenu() +{ + enum OptionsNumbers { Back, Long, Short }; + static const char *optionsArray[] = {"Back", "Long", "Short"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Node Name Length"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 3; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Long) { + // Set names to long + LOG_INFO("Setting names to long"); + config.display.use_long_node_name = true; + } else if (selected == Short) { + // Set names to short + LOG_INFO("Setting names to short"); + config.display.use_long_node_name = false; + } else if (selected == Back) { + menuQueue = screen_options_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + void menuHandler::resetNodeDBMenu() { static const char *optionsArray[] = {"Back", "Confirm"}; @@ -1304,11 +1329,16 @@ void menuHandler::screenOptionsMenu() hasSupportBrightness = false; #endif - enum optionsNumbers { Back, Brightness, ScreenColor }; - static const char *optionsArray[4] = {"Back"}; - static int optionsEnumArray[4] = {Back}; + enum optionsNumbers { Back, NodeNameLength, Brightness, ScreenColor }; + static const char *optionsArray[5] = {"Back"}; + static int optionsEnumArray[5] = {Back}; int options = 1; +#if defined(T_DECK) || defined(T_LORA_PAGER) + optionsArray[options] = "Show Long/Short Name"; + optionsEnumArray[options++] = NodeNameLength; +#endif + // Only show brightness for B&W displays if (hasSupportBrightness) { optionsArray[options] = "Brightness"; @@ -1333,6 +1363,9 @@ void menuHandler::screenOptionsMenu() } else if (selected == ScreenColor) { menuHandler::menuQueue = menuHandler::tftcolormenupicker; screen->runNow(); + } else if (selected == NodeNameLength) { + menuHandler::menuQueue = menuHandler::node_name_length_menu; + screen->runNow(); } else { menuQueue = system_base_menu; screen->runNow(); @@ -1610,6 +1643,9 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display) case brightness_picker: BrightnessPickerMenu(); break; + case node_name_length_menu: + nodeNameLengthMenu(); + break; case reboot_menu: rebootMenu(); break; diff --git a/src/graphics/draw/MenuHandler.h b/src/graphics/draw/MenuHandler.h index 47dbb2543..1f7bbac8c 100644 --- a/src/graphics/draw/MenuHandler.h +++ b/src/graphics/draw/MenuHandler.h @@ -43,6 +43,7 @@ class menuHandler key_verification_final_prompt, trace_route_menu, throttle_message, + node_name_length_menu, FrameToggles }; static screenMenus menuQueue; @@ -85,6 +86,7 @@ class menuHandler static void notificationsMenu(); static void screenOptionsMenu(); static void powerMenu(); + static void nodeNameLengthMenu(); static void FrameToggles_menu(); static void textMessageMenu(); diff --git a/src/graphics/draw/NodeListRenderer.cpp b/src/graphics/draw/NodeListRenderer.cpp index 7d6a38dd3..07577db8c 100644 --- a/src/graphics/draw/NodeListRenderer.cpp +++ b/src/graphics/draw/NodeListRenderer.cpp @@ -55,26 +55,32 @@ static int scrollIndex = 0; const char *getSafeNodeName(meshtastic_NodeInfoLite *node) { + const char *name = NULL; static char nodeName[16] = "?"; - if (node->has_user && strlen(node->user.short_name) > 0) { - bool valid = true; - const char *name = node->user.short_name; - for (size_t i = 0; i < strlen(name); i++) { - uint8_t c = (uint8_t)name[i]; - if (c < 32 || c > 126) { - valid = false; - break; - } - } - if (valid) { - strncpy(nodeName, name, sizeof(nodeName) - 1); - nodeName[sizeof(nodeName) - 1] = '\0'; + if (config.display.use_long_node_name == true) { + if (node->has_user && strlen(node->user.long_name) > 0) { + name = node->user.long_name; } else { snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF)); } + } else { + if (node->has_user && strlen(node->user.short_name) > 0) { + name = node->user.short_name; + } else { + snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF)); + } + } + + // Use sanitizeString() function and copy directly into nodeName + std::string sanitized_name = sanitizeString(name ? name : ""); + + if (!sanitized_name.empty()) { + strncpy(nodeName, sanitized_name.c_str(), sizeof(nodeName) - 1); + nodeName[sizeof(nodeName) - 1] = '\0'; } else { snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF)); } + return nodeName; } From fcaa168d2d7a36f7ca37e741f79e77c11768ac33 Mon Sep 17 00:00:00 2001 From: Clive Blackledge Date: Mon, 13 Oct 2025 04:32:05 -0700 Subject: [PATCH 157/166] Ble reconnect prefetch bug fix, plus some speed enhancements (#8324) * Fixing bluetooth reconnects and adding performance * Added comments --- src/mesh/PhoneAPI.cpp | 58 +++++++++++++++++++++++----------- src/mesh/PhoneAPI.h | 7 ++++ src/nimble/NimbleBluetooth.cpp | 51 ++++++++++++++++++++++++++---- 3 files changed, 91 insertions(+), 25 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index e8dc9843c..9eeadf5a2 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -72,6 +72,7 @@ void PhoneAPI::handleStartConfig() LOG_INFO("Start API client config"); nodeInfoForPhone.num = 0; // Don't keep returning old nodeinfos + nodeInfoQueue.clear(); resetReadIndex(); } @@ -94,6 +95,7 @@ void PhoneAPI::close() fromRadioScratch = {}; toRadioScratch = {}; nodeInfoForPhone = {}; + nodeInfoQueue.clear(); packetForPhone = NULL; filesManifest.clear(); fromRadioNum = 0; @@ -431,17 +433,25 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) break; case STATE_SEND_OTHER_NODEINFOS: { + LOG_DEBUG("Send known nodes"); + if (nodeInfoForPhone.num == 0 && !nodeInfoQueue.empty()) { + // Serve the next cached node without re-reading from the DB iterator. + nodeInfoForPhone = nodeInfoQueue.front(); + nodeInfoQueue.pop_front(); + } + if (nodeInfoForPhone.num != 0) { // Just in case we stored a different user.id in the past, but should never happen going forward sprintf(nodeInfoForPhone.user.id, "!%08x", nodeInfoForPhone.num); - LOG_INFO("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s", nodeInfoForPhone.num, nodeInfoForPhone.last_heard, - nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name); + LOG_DEBUG("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s", nodeInfoForPhone.num, nodeInfoForPhone.last_heard, + nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name); fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag; fromRadioScratch.node_info = nodeInfoForPhone; - // Stay in current state until done sending nodeinfos - nodeInfoForPhone.num = 0; // We just consumed a nodeinfo, will need a new one next time + nodeInfoForPhone = {}; + prefetchNodeInfos(); } else { LOG_DEBUG("Done sending nodeinfo"); + nodeInfoQueue.clear(); state = STATE_SEND_FILEMANIFEST; // Go ahead and send that ID right now return getFromRadio(buf); @@ -545,6 +555,30 @@ void PhoneAPI::releaseQueueStatusPhonePacket() } } +void PhoneAPI::prefetchNodeInfos() +{ + bool added = false; + // Keep the queue topped up so BLE reads stay responsive even if DB fetches take a moment. + while (nodeInfoQueue.size() < kNodePrefetchDepth) { + auto nextNode = nodeDB->readNextMeshNode(readIndex); + if (!nextNode) + break; + + auto info = TypeConversions::ConvertToNodeInfo(nextNode); + bool isUs = info.num == nodeDB->getNodeNum(); + info.hops_away = isUs ? 0 : info.hops_away; + info.last_heard = isUs ? getValidTime(RTCQualityFromNet) : info.last_heard; + info.snr = isUs ? 0 : info.snr; + info.via_mqtt = isUs ? false : info.via_mqtt; + info.is_favorite = info.is_favorite || isUs; + nodeInfoQueue.push_back(info); + added = true; + } + + if (added) + onNowHasData(0); +} + void PhoneAPI::releaseMqttClientProxyPhonePacket() { if (mqttClientProxyMessageForPhone) { @@ -581,20 +615,8 @@ bool PhoneAPI::available() return true; case STATE_SEND_OTHER_NODEINFOS: - if (nodeInfoForPhone.num == 0) { - auto nextNode = nodeDB->readNextMeshNode(readIndex); - if (nextNode) { - nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(nextNode); - bool isUs = nodeInfoForPhone.num == nodeDB->getNodeNum(); - nodeInfoForPhone.hops_away = isUs ? 0 : nodeInfoForPhone.hops_away; - nodeInfoForPhone.last_heard = isUs ? getValidTime(RTCQualityFromNet) : nodeInfoForPhone.last_heard; - nodeInfoForPhone.snr = isUs ? 0 : nodeInfoForPhone.snr; - nodeInfoForPhone.via_mqtt = isUs ? false : nodeInfoForPhone.via_mqtt; - nodeInfoForPhone.is_favorite = nodeInfoForPhone.is_favorite || isUs; // Our node is always a favorite - - onNowHasData(0); - } - } + if (nodeInfoQueue.empty()) + prefetchNodeInfos(); return true; // Always say we have something, because we might need to advance our state machine case STATE_SEND_PACKETS: { if (!queueStatusPacketForPhone) diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 0d7772d17..692fdd0b9 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -3,6 +3,7 @@ #include "Observer.h" #include "mesh-pb-constants.h" #include "meshtastic/portnums.pb.h" +#include #include #include #include @@ -79,6 +80,10 @@ class PhoneAPI /// We temporarily keep the nodeInfo here between the call to available and getFromRadio meshtastic_NodeInfo nodeInfoForPhone = meshtastic_NodeInfo_init_default; + // Prefetched node info entries ready for immediate transmission to the phone. + std::deque nodeInfoQueue; + // Tunable size of the node info cache so we can keep BLE reads non-blocking. + static constexpr size_t kNodePrefetchDepth = 4; meshtastic_ToRadio toRadioScratch = { 0}; // this is a static scratch object, any data must be copied elsewhere before returning @@ -158,6 +163,8 @@ class PhoneAPI void releaseQueueStatusPhonePacket(); + void prefetchNodeInfos(); + void releaseMqttClientProxyPhonePacket(); void releaseClientNotification(); diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 60165b2c0..4b0c33609 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -48,6 +48,8 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread uint8_t queue_size = 0; uint8_t fromRadioBytes[meshtastic_FromRadio_size] = {0}; size_t numBytes = 0; + bool hasChecked = false; + bool phoneWants = false; protected: virtual int32_t runOnce() override @@ -60,7 +62,11 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread LOG_DEBUG("Queue_size %u", queue_size); queue_size = 0; } - // Note: phoneWants/hasChecked logic removed since onRead() handles getFromRadio() directly + if (!hasChecked && phoneWants) { + // Pull fresh data while we're outside of the NimBLE callback context. + numBytes = getFromRadio(fromRadioBytes); + hasChecked = true; + } // the run is triggered via NimbleBluetoothToRadioCallback and NimbleBluetoothFromRadioCallback return INT32_MAX; @@ -117,6 +123,8 @@ class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks bluetoothPhoneAPI->queue_size++; bluetoothPhoneAPI->setIntervalFromNow(0); } + } else { + LOG_DEBUG("Drop duplicate ToRadio packet (%u bytes)", val.length()); } } }; @@ -129,17 +137,32 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks virtual void onRead(NimBLECharacteristic *pCharacteristic) #endif { + bluetoothPhoneAPI->phoneWants = true; + bluetoothPhoneAPI->setIntervalFromNow(0); std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); - // Get fresh data immediately when client reads - bluetoothPhoneAPI->numBytes = bluetoothPhoneAPI->getFromRadio(bluetoothPhoneAPI->fromRadioBytes); + if (!bluetoothPhoneAPI->hasChecked) { + // Fetch payload on demand; prefetch keeps this fast for the first read. + bluetoothPhoneAPI->numBytes = bluetoothPhoneAPI->getFromRadio(bluetoothPhoneAPI->fromRadioBytes); + bluetoothPhoneAPI->hasChecked = true; + } - // Set the characteristic value with whatever data we have pCharacteristic->setValue(bluetoothPhoneAPI->fromRadioBytes, bluetoothPhoneAPI->numBytes); + if (bluetoothPhoneAPI->numBytes != 0) { +#ifdef NIMBLE_TWO + // Notify immediately so subscribed clients see the packet without an extra read. + pCharacteristic->notify(bluetoothPhoneAPI->fromRadioBytes, bluetoothPhoneAPI->numBytes, BLE_HS_CONN_HANDLE_NONE); +#else + pCharacteristic->notify(); +#endif + } + if (bluetoothPhoneAPI->numBytes != 0) // if we did send something, queue it up right away to reload bluetoothPhoneAPI->setIntervalFromNow(0); bluetoothPhoneAPI->numBytes = 0; + bluetoothPhoneAPI->hasChecked = false; + bluetoothPhoneAPI->phoneWants = false; } }; @@ -271,6 +294,8 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks bluetoothPhoneAPI->close(); bluetoothPhoneAPI->numBytes = 0; bluetoothPhoneAPI->queue_size = 0; + bluetoothPhoneAPI->hasChecked = false; + bluetoothPhoneAPI->phoneWants = false; } // Clear the last ToRadio packet buffer to avoid rejecting first packet from new connection @@ -278,6 +303,15 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks #ifdef NIMBLE_TWO // Restart Advertising ble->startAdvertising(); +#else + NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); + if (!pAdvertising->start(0)) { + if (pAdvertising->isAdvertising()) { + LOG_DEBUG("BLE advertising already running"); + } else { + LOG_ERROR("BLE failed to restart advertising"); + } + } #endif } }; @@ -401,15 +435,18 @@ void NimbleBluetooth::setupService() // Define the characteristics that the app is looking for if (config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) { ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE); - FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ); + // Allow notifications so phones can stream FromRadio without polling. + FromRadioCharacteristic = + bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY); fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ); logRadioCharacteristic = bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ, 512U); } else { ToRadioCharacteristic = bleService->createCharacteristic( TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC); - FromRadioCharacteristic = bleService->createCharacteristic( - FROMRADIO_UUID, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); + FromRadioCharacteristic = + bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | + NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::NOTIFY); fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); From fe6509a0f2f07661b38bccbcd765ed9612e493c1 Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Mon, 13 Oct 2025 13:57:21 +0200 Subject: [PATCH 158/166] Avoid exceeding allocated buffers when doing MQTT proxying (#8320) the topic length could be longer than 65 characters. similarly for the payload. Co-authored-by: Ben Meadors --- src/mqtt/MQTT.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 8ce352f14..33887557f 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -473,7 +473,9 @@ bool MQTT::publish(const char *topic, const uint8_t *payload, size_t length, boo if (moduleConfig.mqtt.proxy_to_client_enabled) { meshtastic_MqttClientProxyMessage *msg = mqttClientProxyMessagePool.allocZeroed(); msg->which_payload_variant = meshtastic_MqttClientProxyMessage_data_tag; - strcpy(msg->topic, topic); + strlcpy(msg->topic, topic, sizeof(msg->topic)); + if (length > sizeof(msg->payload_variant.data.bytes)) + length = sizeof(msg->payload_variant.data.bytes); msg->payload_variant.data.size = length; memcpy(msg->payload_variant.data.bytes, payload, length); msg->retained = retained; From 130833b5be168f0c78c25d32fe87f6b1496da11a Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Mon, 13 Oct 2025 23:50:57 +1100 Subject: [PATCH 159/166] Fix erroneous limiting of power in Ham Mode (#8322) Ham Mode ignores region regulatory limits, so regardless of whether we set a single TX_GAIN_LORA or an array with a non-linear PA, we shouldn't limit the power. Co-authored-by: Ben Meadors --- src/mesh/RadioInterface.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 88218e406..31ec5acc5 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -647,23 +647,24 @@ void RadioInterface::limitPower(int8_t loraMaxPower) } #ifndef NUM_PA_POINTS - if (TX_GAIN_LORA > 0) { + if (TX_GAIN_LORA > 0 && !devicestate.owner.is_licensed) { LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, TX_GAIN_LORA); power -= TX_GAIN_LORA; } #else - // we have an array of PA gain values. Find the highest power setting that works. - const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA}; - for (int radio_dbm = 0; radio_dbm < NUM_PA_POINTS; radio_dbm++) { - if (((radio_dbm + tx_gain[radio_dbm]) > power) || - ((radio_dbm == (NUM_PA_POINTS - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) { - // we've exceeded the power limit, or hit the max we can do - LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]); - power -= tx_gain[radio_dbm]; - break; + if (!devicestate.owner.is_licensed) { + // we have an array of PA gain values. Find the highest power setting that works. + const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA}; + for (int radio_dbm = 0; radio_dbm < NUM_PA_POINTS; radio_dbm++) { + if (((radio_dbm + tx_gain[radio_dbm]) > power) || + ((radio_dbm == (NUM_PA_POINTS - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) { + // we've exceeded the power limit, or hit the max we can do + LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]); + power -= tx_gain[radio_dbm]; + break; + } } } - #endif if (power > loraMaxPower) // Clamp power to maximum defined level power = loraMaxPower; From 9df5aa8c708d20546f145f594ebc4ff0a3298178 Mon Sep 17 00:00:00 2001 From: Steven Wu <31466039+steven52880@users.noreply.github.com> Date: Mon, 13 Oct 2025 21:15:21 +0800 Subject: [PATCH 160/166] Fix can not detect battery status while using INA226 (#8330) Co-authored-by: Ben Meadors --- src/Power.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Power.cpp b/src/Power.cpp index 39d47610b..1f4c341f0 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -562,6 +562,7 @@ class AnalogBatteryLevel : public HasBatteryLevel config.power.device_battery_ina_address) { if (!ina226Sensor.isInitialized()) return ina226Sensor.runOnce() > 0; + return ina226Sensor.isRunning(); } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260].first == config.power.device_battery_ina_address) { if (!ina260Sensor.isInitialized()) From a71b47b5bb0dad7267bb5b97c4088741668a7cc9 Mon Sep 17 00:00:00 2001 From: Markus <974709+Links2004@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:09:33 +0200 Subject: [PATCH 161/166] rework sensor instantiation to saves memory by removing the static allocation (#8054) * rework I2C sensor init the goal is to only instantiate sensors that are pressend to save memory. side effacts: - easyer sensor integration (less C&P code) - nodeTelemetrySensorsMap can be removed when all devices are migrated * add missing ifdef * refactor a bunch of more sensors RAM -816 Flash -916 * fix build for t1000 * refactor more sensors RAM -192 Flash -60 * improve error handling Flash -112 * fix build * fix build * fix IndicatorSensor * fix tracker-t1000-e build not sure what magic is used but it works * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/modules/Telemetry/Sensor/DFRobotGravitySensor.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix --------- Co-authored-by: Ben Meadors Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/detect/ScanI2CConsumer.cpp | 16 + src/detect/ScanI2CConsumer.h | 13 + src/detect/ScanI2CTwoWire.cpp | 2 +- src/detect/ScanI2CTwoWire.h | 4 +- src/main.cpp | 32 +- .../Telemetry/EnvironmentTelemetry.cpp | 534 +++++------------- src/modules/Telemetry/EnvironmentTelemetry.h | 9 +- src/modules/Telemetry/Sensor/AHT10.cpp | 25 +- src/modules/Telemetry/Sensor/AHT10.h | 5 +- src/modules/Telemetry/Sensor/BME280Sensor.cpp | 13 +- src/modules/Telemetry/Sensor/BME280Sensor.h | 5 +- src/modules/Telemetry/Sensor/BME680Sensor.cpp | 19 +- src/modules/Telemetry/Sensor/BME680Sensor.h | 3 +- src/modules/Telemetry/Sensor/BMP085Sensor.cpp | 13 +- src/modules/Telemetry/Sensor/BMP085Sensor.h | 5 +- src/modules/Telemetry/Sensor/BMP280Sensor.cpp | 16 +- src/modules/Telemetry/Sensor/BMP280Sensor.h | 5 +- src/modules/Telemetry/Sensor/BMP3XXSensor.cpp | 15 +- src/modules/Telemetry/Sensor/BMP3XXSensor.h | 3 +- .../Telemetry/Sensor/CGRadSensSensor.cpp | 14 +- .../Telemetry/Sensor/CGRadSensSensor.h | 3 +- .../Telemetry/Sensor/DFRobotGravitySensor.cpp | 34 +- .../Telemetry/Sensor/DFRobotGravitySensor.h | 8 +- .../Telemetry/Sensor/DFRobotLarkSensor.cpp | 13 +- .../Telemetry/Sensor/DFRobotLarkSensor.h | 5 +- src/modules/Telemetry/Sensor/DPS310Sensor.cpp | 13 +- src/modules/Telemetry/Sensor/DPS310Sensor.h | 5 +- .../Telemetry/Sensor/IndicatorSensor.cpp | 4 +- .../Telemetry/Sensor/IndicatorSensor.h | 8 +- .../Telemetry/Sensor/LPS22HBSensor.cpp | 16 +- src/modules/Telemetry/Sensor/LPS22HBSensor.h | 5 +- .../Telemetry/Sensor/LTR390UVSensor.cpp | 14 +- src/modules/Telemetry/Sensor/LTR390UVSensor.h | 5 +- .../Telemetry/Sensor/MCP9808Sensor.cpp | 16 +- src/modules/Telemetry/Sensor/MCP9808Sensor.h | 5 +- .../Telemetry/Sensor/MLX90632Sensor.cpp | 13 +- src/modules/Telemetry/Sensor/MLX90632Sensor.h | 5 +- .../Telemetry/Sensor/NAU7802Sensor.cpp | 13 +- src/modules/Telemetry/Sensor/NAU7802Sensor.h | 3 +- .../Telemetry/Sensor/OPT3001Sensor.cpp | 19 +- src/modules/Telemetry/Sensor/OPT3001Sensor.h | 8 +- .../Telemetry/Sensor/PCT2075Sensor.cpp | 14 +- src/modules/Telemetry/Sensor/PCT2075Sensor.h | 5 +- .../Telemetry/Sensor/RAK12035Sensor.cpp | 15 +- src/modules/Telemetry/Sensor/RAK12035Sensor.h | 9 +- .../Telemetry/Sensor/RCWL9620Sensor.cpp | 12 +- src/modules/Telemetry/Sensor/RCWL9620Sensor.h | 3 +- src/modules/Telemetry/Sensor/SHT31Sensor.cpp | 17 +- src/modules/Telemetry/Sensor/SHT31Sensor.h | 5 +- src/modules/Telemetry/Sensor/SHT4XSensor.cpp | 18 +- src/modules/Telemetry/Sensor/SHT4XSensor.h | 5 +- src/modules/Telemetry/Sensor/SHTC3Sensor.cpp | 14 +- src/modules/Telemetry/Sensor/SHTC3Sensor.h | 5 +- src/modules/Telemetry/Sensor/T1000xSensor.cpp | 12 +- src/modules/Telemetry/Sensor/T1000xSensor.h | 5 +- .../Telemetry/Sensor/TSL2561Sensor.cpp | 19 +- src/modules/Telemetry/Sensor/TSL2561Sensor.h | 5 +- .../Telemetry/Sensor/TSL2591Sensor.cpp | 17 +- src/modules/Telemetry/Sensor/TSL2591Sensor.h | 5 +- .../Telemetry/Sensor/TelemetrySensor.h | 15 +- .../Telemetry/Sensor/VEML7700Sensor.cpp | 13 +- src/modules/Telemetry/Sensor/VEML7700Sensor.h | 5 +- src/modules/Telemetry/Sensor/nullSensor.cpp | 2 +- 63 files changed, 428 insertions(+), 758 deletions(-) create mode 100644 src/detect/ScanI2CConsumer.cpp create mode 100644 src/detect/ScanI2CConsumer.h diff --git a/src/detect/ScanI2CConsumer.cpp b/src/detect/ScanI2CConsumer.cpp new file mode 100644 index 000000000..a70fa5398 --- /dev/null +++ b/src/detect/ScanI2CConsumer.cpp @@ -0,0 +1,16 @@ +#include "ScanI2CConsumer.h" +#include + +static std::forward_list ScanI2CConsumers; + +ScanI2CConsumer::ScanI2CConsumer() +{ + ScanI2CConsumers.push_front(this); +} + +void ScanI2CCompleted(ScanI2C *i2cScanner) +{ + for (ScanI2CConsumer *consumer : ScanI2CConsumers) { + consumer->i2cScanFinished(i2cScanner); + } +} \ No newline at end of file diff --git a/src/detect/ScanI2CConsumer.h b/src/detect/ScanI2CConsumer.h new file mode 100644 index 000000000..fd97f7edc --- /dev/null +++ b/src/detect/ScanI2CConsumer.h @@ -0,0 +1,13 @@ +#pragma once + +#include "ScanI2C.h" +#include + +class ScanI2CConsumer +{ + public: + ScanI2CConsumer(); + virtual void i2cScanFinished(ScanI2C *i2cScanner) = 0; +}; + +void ScanI2CCompleted(ScanI2C *i2cScanner); \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index d6daf7b7a..da2a57fee 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -581,7 +581,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port) scanPort(port, nullptr, 0); } -TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const +TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) { if (address.port == ScanI2C::I2CPort::WIRE) { return &Wire; diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 6988091ad..c5b791920 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -23,12 +23,12 @@ class ScanI2CTwoWire : public ScanI2C ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; - TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const; - bool exists(ScanI2C::DeviceType) const override; size_t countDevices() const override; + static TwoWire *fetchI2CBus(ScanI2C::DeviceAddress); + protected: FoundDevice firstOfOrNONE(size_t, DeviceType[]) const override; diff --git a/src/main.cpp b/src/main.cpp index 029b8d708..bb97a1aa6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include "power.h" #if !MESHTASTIC_EXCLUDE_I2C +#include "detect/ScanI2CConsumer.h" #include "detect/ScanI2CTwoWire.h" #include #endif @@ -718,46 +719,21 @@ void setup() LOG_DEBUG("acc_info = %i", acc_info.type); #endif - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_3XX, meshtastic_TelemetrySensorType_BMP3XX); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA226, meshtastic_TelemetrySensorType_INA226); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::HMC5883L, meshtastic_TelemetrySensorType_QMC5883L); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::VEML7700, meshtastic_TelemetrySensorType_VEML7700); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2591, meshtastic_TelemetrySensorType_TSL25911FN); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::OPT3001, meshtastic_TelemetrySensorType_OPT3001); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90632, meshtastic_TelemetrySensorType_MLX90632); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90614, meshtastic_TelemetrySensorType_MLX90614); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::CGRADSENS, meshtastic_TelemetrySensorType_RADSENS); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_RAIN, meshtastic_TelemetrySensorType_DFROBOT_RAIN); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LTR390UV, meshtastic_TelemetrySensorType_LTR390UV); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DPS310, meshtastic_TelemetrySensorType_DPS310); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2561, meshtastic_TelemetrySensorType_TSL2561); - i2cScanner.reset(); #endif #ifdef HAS_SDCARD @@ -964,6 +940,12 @@ void setup() // Now that the mesh service is created, create any modules setupModules(); +#if !MESHTASTIC_EXCLUDE_I2C + // Inform modules about I2C devices + ScanI2CCompleted(i2cScanner.get()); + i2cScanner.reset(); +#endif + // warn the user about a low entropy key if (nodeDB->keyIsLowEntropy && !nodeDB->hasWarned) { LOG_WARN(LOW_ENTROPY_WARNING); diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 8ac160f8b..95947560d 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -35,175 +35,103 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c } #if __has_include() #include "Sensor/AHT10.h" -AHT10Sensor aht10Sensor; -#else -NullSensor aht10Sensor; #endif + #if __has_include() #include "Sensor/BME280Sensor.h" -BME280Sensor bme280Sensor; -#else -NullSensor bmp280Sensor; #endif #if __has_include() #include "Sensor/BMP085Sensor.h" -BMP085Sensor bmp085Sensor; -#else -NullSensor bmp085Sensor; #endif #if __has_include() #include "Sensor/BMP280Sensor.h" -BMP280Sensor bmp280Sensor; -#else -NullSensor bme280Sensor; #endif #if __has_include() #include "Sensor/LTR390UVSensor.h" -LTR390UVSensor ltr390uvSensor; -#else -NullSensor ltr390uvSensor; #endif #if __has_include() #include "Sensor/BME680Sensor.h" -BME680Sensor bme680Sensor; -#else -NullSensor bme680Sensor; #endif #if __has_include() #include "Sensor/DPS310Sensor.h" -DPS310Sensor dps310Sensor; -#else -NullSensor dps310Sensor; #endif #if __has_include() #include "Sensor/MCP9808Sensor.h" -MCP9808Sensor mcp9808Sensor; -#else -NullSensor mcp9808Sensor; #endif #if __has_include() #include "Sensor/SHT31Sensor.h" -SHT31Sensor sht31Sensor; -#else -NullSensor sht31Sensor; #endif #if __has_include() #include "Sensor/LPS22HBSensor.h" -LPS22HBSensor lps22hbSensor; -#else -NullSensor lps22hbSensor; #endif #if __has_include() #include "Sensor/SHTC3Sensor.h" -SHTC3Sensor shtc3Sensor; -#else -NullSensor shtc3Sensor; #endif #if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1 #include "Sensor/RAK12035Sensor.h" -RAK12035Sensor rak12035Sensor; -#else -NullSensor rak12035Sensor; #endif #if __has_include() #include "Sensor/VEML7700Sensor.h" -VEML7700Sensor veml7700Sensor; -#else -NullSensor veml7700Sensor; #endif #if __has_include() #include "Sensor/TSL2591Sensor.h" -TSL2591Sensor tsl2591Sensor; -#else -NullSensor tsl2591Sensor; #endif #if __has_include() #include "Sensor/OPT3001Sensor.h" -OPT3001Sensor opt3001Sensor; -#else -NullSensor opt3001Sensor; #endif #if __has_include() #include "Sensor/SHT4XSensor.h" -SHT4XSensor sht4xSensor; -#else -NullSensor sht4xSensor; #endif #if __has_include() #include "Sensor/MLX90632Sensor.h" -MLX90632Sensor mlx90632Sensor; -#else -NullSensor mlx90632Sensor; #endif #if __has_include() #include "Sensor/DFRobotLarkSensor.h" -DFRobotLarkSensor dfRobotLarkSensor; -#else -NullSensor dfRobotLarkSensor; #endif #if __has_include() #include "Sensor/DFRobotGravitySensor.h" -DFRobotGravitySensor dfRobotGravitySensor; -#else -NullSensor dfRobotGravitySensor; #endif #if __has_include() #include "Sensor/NAU7802Sensor.h" -NAU7802Sensor nau7802Sensor; -#else -NullSensor nau7802Sensor; #endif #if __has_include() #include "Sensor/BMP3XXSensor.h" -BMP3XXSensor bmp3xxSensor; -#else -NullSensor bmp3xxSensor; #endif #if __has_include() #include "Sensor/PCT2075Sensor.h" -PCT2075Sensor pct2075Sensor; -#else -NullSensor pct2075Sensor; #endif -RCWL9620Sensor rcwl9620Sensor; -CGRadSensSensor cgRadSens; - #endif #ifdef T1000X_SENSOR_EN #include "Sensor/T1000xSensor.h" -T1000xSensor t1000xSensor; #endif + #ifdef SENSECAP_INDICATOR #include "Sensor/IndicatorSensor.h" -IndicatorSensor indicatorSensor; #endif #if __has_include() #include "Sensor/TSL2561Sensor.h" -TSL2561Sensor tsl2561Sensor; -#else -NullSensor tsl2561Sensor; #endif #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 @@ -212,6 +140,132 @@ NullSensor tsl2561Sensor; #include "graphics/ScreenFonts.h" #include +#include + +static std::forward_list sensors; + +template void addSensor(ScanI2C *i2cScanner, ScanI2C::DeviceType type) +{ + ScanI2C::FoundDevice dev = i2cScanner->find(type); + if (dev.type != ScanI2C::DeviceType::NONE || type == ScanI2C::DeviceType::NONE) { + TelemetrySensor *sensor = new T(); +#if WIRE_INTERFACES_COUNT > 1 + TwoWire *bus = ScanI2CTwoWire::fetchI2CBus(dev.address); + if (dev.address.port != ScanI2C::I2CPort::WIRE1 && sensor->onlyWire1()) { + // This sensor only works on Wire (Wire1 is not supported) + delete sensor; + return; + } +#else + TwoWire *bus = &Wire; +#endif + if (sensor->initDevice(bus, &dev)) { + sensors.push_front(sensor); + return; + } + // destroy sensor + delete sensor; + } +} + +void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner) +{ + if (!moduleConfig.telemetry.environment_measurement_enabled && !ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE) { + return; + } + LOG_INFO("Environment Telemetry adding I2C devices..."); + + // order by priority of metrics/values (low top, high bottom) + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR +#ifdef T1000X_SENSOR_EN + // Not a real I2C device + addSensor(i2cScanner, ScanI2C::DeviceType::NONE); +#else +#ifdef SENSECAP_INDICATOR + // Not a real I2C device, uses UART + addSensor(i2cScanner, ScanI2C::DeviceType::NONE); +#endif + addSensor(i2cScanner, ScanI2C::DeviceType::RCWL9620); + addSensor(i2cScanner, ScanI2C::DeviceType::CGRADSENS); +#endif +#endif + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::DFROBOT_LARK); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::DFROBOT_RAIN); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::AHT10); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::BMP_085); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::BME_280); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::LTR390UV); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::BME_680); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::BMP_280); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::DPS310); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::MCP9808); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::SHT31); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::LPS22HB); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::SHTC3); +#endif +#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1 + addSensor(i2cScanner, ScanI2C::DeviceType::RAK12035); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::VEML7700); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::TSL2591); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::OPT3001); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::SHT4X); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::MLX90632); +#endif + +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::BMP_3XX); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::PCT2075); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::TSL2561); +#endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::NAU7802); +#endif + +#endif +} + int32_t EnvironmentTelemetryModule::runOnce() { if (sleepOnNextExecution == true) { @@ -244,81 +298,27 @@ int32_t EnvironmentTelemetryModule::runOnce() if (moduleConfig.telemetry.environment_measurement_enabled || ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE) { LOG_INFO("Environment Telemetry: init"); -#ifdef SENSECAP_INDICATOR - result = indicatorSensor.runOnce(); -#endif + + // check if we have at least one sensor + if (!sensors.empty()) { + result = DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + } + #ifdef T1000X_SENSOR_EN - result = t1000xSensor.runOnce(); #elif !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL - if (dfRobotLarkSensor.hasSensor()) - result = dfRobotLarkSensor.runOnce(); - if (dfRobotGravitySensor.hasSensor()) - result = dfRobotGravitySensor.runOnce(); - if (bmp085Sensor.hasSensor()) - result = bmp085Sensor.runOnce(); -#if __has_include() - if (bmp280Sensor.hasSensor()) - result = bmp280Sensor.runOnce(); -#endif - if (bme280Sensor.hasSensor()) - result = bme280Sensor.runOnce(); - if (ltr390uvSensor.hasSensor()) - result = ltr390uvSensor.runOnce(); - if (bmp3xxSensor.hasSensor()) - result = bmp3xxSensor.runOnce(); - if (bme680Sensor.hasSensor()) - result = bme680Sensor.runOnce(); - if (dps310Sensor.hasSensor()) - result = dps310Sensor.runOnce(); - if (mcp9808Sensor.hasSensor()) - result = mcp9808Sensor.runOnce(); - if (shtc3Sensor.hasSensor()) - result = shtc3Sensor.runOnce(); - if (lps22hbSensor.hasSensor()) - result = lps22hbSensor.runOnce(); - if (sht31Sensor.hasSensor()) - result = sht31Sensor.runOnce(); - if (sht4xSensor.hasSensor()) - result = sht4xSensor.runOnce(); if (ina219Sensor.hasSensor()) result = ina219Sensor.runOnce(); if (ina260Sensor.hasSensor()) result = ina260Sensor.runOnce(); if (ina3221Sensor.hasSensor()) result = ina3221Sensor.runOnce(); - if (veml7700Sensor.hasSensor()) - result = veml7700Sensor.runOnce(); - if (tsl2591Sensor.hasSensor()) - result = tsl2591Sensor.runOnce(); - if (opt3001Sensor.hasSensor()) - result = opt3001Sensor.runOnce(); - if (rcwl9620Sensor.hasSensor()) - result = rcwl9620Sensor.runOnce(); - if (aht10Sensor.hasSensor()) - result = aht10Sensor.runOnce(); - if (mlx90632Sensor.hasSensor()) - result = mlx90632Sensor.runOnce(); - if (nau7802Sensor.hasSensor()) - result = nau7802Sensor.runOnce(); if (max17048Sensor.hasSensor()) result = max17048Sensor.runOnce(); - if (cgRadSens.hasSensor()) - result = cgRadSens.runOnce(); - if (tsl2561Sensor.hasSensor()) - result = tsl2561Sensor.runOnce(); - if (pct2075Sensor.hasSensor()) - result = pct2075Sensor.runOnce(); // this only works on the wismesh hub with the solar option. This is not an I2C sensor, so we don't need the // sensormap here. #ifdef HAS_RAKPROT - result = rak9154Sensor.runOnce(); #endif -#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1 - if (rak12035Sensor.hasSensor()) { - result = rak12035Sensor.runOnce(); - } -#endif #endif } // it's possible to have this module enabled, only for displaying values on the screen. @@ -328,11 +328,13 @@ int32_t EnvironmentTelemetryModule::runOnce() // if we somehow got to a second run of this module with measurement disabled, then just wait forever if (!moduleConfig.telemetry.environment_measurement_enabled && !ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE) { return disable(); - } else { -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL - if (bme680Sensor.hasSensor()) - result = bme680Sensor.runTrigger(); -#endif + } + + for (TelemetrySensor *sensor : sensors) { + uint32_t delay = sensor->runOnce(); + if (delay < result) { + result = delay; + } } if (((lastSentToMesh == 0) || @@ -550,72 +552,12 @@ 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; -#else - if (dfRobotLarkSensor.hasSensor()) { - valid = valid && dfRobotLarkSensor.getMetrics(m); - hasSensor = true; - } - if (dfRobotGravitySensor.hasSensor()) { - valid = valid && dfRobotGravitySensor.getMetrics(m); - hasSensor = true; - } - if (sht31Sensor.hasSensor()) { - valid = valid && sht31Sensor.getMetrics(m); - hasSensor = true; - } - if (sht4xSensor.hasSensor()) { - valid = valid && sht4xSensor.getMetrics(m); - hasSensor = true; - } - if (lps22hbSensor.hasSensor()) { - valid = valid && lps22hbSensor.getMetrics(m); - hasSensor = true; - } - if (shtc3Sensor.hasSensor()) { - valid = valid && shtc3Sensor.getMetrics(m); - hasSensor = true; - } - if (bmp085Sensor.hasSensor()) { - valid = valid && bmp085Sensor.getMetrics(m); - hasSensor = true; - } -#if __has_include() - if (bmp280Sensor.hasSensor()) { - valid = valid && bmp280Sensor.getMetrics(m); - hasSensor = true; - } -#endif - if (bme280Sensor.hasSensor()) { - valid = valid && bme280Sensor.getMetrics(m); - hasSensor = true; - } - if (ltr390uvSensor.hasSensor()) { - valid = valid && ltr390uvSensor.getMetrics(m); - hasSensor = true; - } - if (bmp3xxSensor.hasSensor()) { - valid = valid && bmp3xxSensor.getMetrics(m); - hasSensor = true; - } - if (bme680Sensor.hasSensor()) { - valid = valid && bme680Sensor.getMetrics(m); - hasSensor = true; - } - if (dps310Sensor.hasSensor()) { - valid = valid && dps310Sensor.getMetrics(m); - hasSensor = true; - } - if (mcp9808Sensor.hasSensor()) { - valid = valid && mcp9808Sensor.getMetrics(m); + for (TelemetrySensor *sensor : sensors) { + valid = valid && sensor->getMetrics(m); hasSensor = true; } + +#ifndef T1000X_SENSOR_EN if (ina219Sensor.hasSensor()) { valid = valid && ina219Sensor.getMetrics(m); hasSensor = true; @@ -628,78 +570,14 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m valid = valid && ina3221Sensor.getMetrics(m); hasSensor = true; } - if (veml7700Sensor.hasSensor()) { - valid = valid && veml7700Sensor.getMetrics(m); - hasSensor = true; - } - if (tsl2591Sensor.hasSensor()) { - valid = valid && tsl2591Sensor.getMetrics(m); - hasSensor = true; - } - if (opt3001Sensor.hasSensor()) { - valid = valid && opt3001Sensor.getMetrics(m); - hasSensor = true; - } - if (mlx90632Sensor.hasSensor()) { - valid = valid && mlx90632Sensor.getMetrics(m); - hasSensor = true; - } - if (rcwl9620Sensor.hasSensor()) { - valid = valid && rcwl9620Sensor.getMetrics(m); - hasSensor = true; - } - if (nau7802Sensor.hasSensor()) { - valid = valid && nau7802Sensor.getMetrics(m); - hasSensor = true; - } - if (tsl2561Sensor.hasSensor()) { - valid = valid && tsl2561Sensor.getMetrics(m); - hasSensor = true; - } - if (aht10Sensor.hasSensor()) { - if (!bmp280Sensor.hasSensor() && !bmp3xxSensor.hasSensor()) { - valid = valid && aht10Sensor.getMetrics(m); - hasSensor = true; - } else if (bmp280Sensor.hasSensor()) { - // prefer bmp280 temp if both sensors are present, fetch only humidity - meshtastic_Telemetry m_ahtx = meshtastic_Telemetry_init_zero; - LOG_INFO("AHTX0+BMP280 module detected: using temp from BMP280 and humy from AHTX0"); - aht10Sensor.getMetrics(&m_ahtx); - m->variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity; - m->variant.environment_metrics.has_relative_humidity = m_ahtx.variant.environment_metrics.has_relative_humidity; - } else { - // prefer bmp3xx temp if both sensors are present, fetch only humidity - meshtastic_Telemetry m_ahtx = meshtastic_Telemetry_init_zero; - LOG_INFO("AHTX0+BMP3XX module detected: using temp from BMP3XX and humy from AHTX0"); - aht10Sensor.getMetrics(&m_ahtx); - m->variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity; - m->variant.environment_metrics.has_relative_humidity = m_ahtx.variant.environment_metrics.has_relative_humidity; - } - } if (max17048Sensor.hasSensor()) { valid = valid && max17048Sensor.getMetrics(m); hasSensor = true; } - if (cgRadSens.hasSensor()) { - valid = valid && cgRadSens.getMetrics(m); - hasSensor = true; - } - if (pct2075Sensor.hasSensor()) { - valid = valid && pct2075Sensor.getMetrics(m); - hasSensor = true; - } +#endif #ifdef HAS_RAKPROT valid = valid && rak9154Sensor.getMetrics(m); hasSensor = true; -#endif -#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && \ - RAK_4631 == \ - 1 // Not really needed, but may as well just skip at a lower level it if no library or not a RAK_4631 - if (rak12035Sensor.hasSensor()) { - valid = valid && rak12035Sensor.getMetrics(m); - hasSensor = true; - } -#endif #endif return valid && hasSensor; } @@ -737,11 +615,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; m.which_variant = meshtastic_Telemetry_environment_metrics_tag; m.time = getTime(); -#ifdef T1000X_SENSOR_EN - if (t1000xSensor.getMetrics(&m)) { -#else + if (getEnvironmentTelemetry(&m)) { -#endif LOG_INFO("Send: barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f", m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current, m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity, @@ -803,71 +678,13 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule { AdminMessageHandleResult result = AdminMessageHandleResult::NOT_HANDLED; #if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL - if (dfRobotLarkSensor.hasSensor()) { - result = dfRobotLarkSensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (dfRobotGravitySensor.hasSensor()) { - result = dfRobotGravitySensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (sht31Sensor.hasSensor()) { - result = sht31Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (lps22hbSensor.hasSensor()) { - result = lps22hbSensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (shtc3Sensor.hasSensor()) { - result = shtc3Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (bmp085Sensor.hasSensor()) { - result = bmp085Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (bmp280Sensor.hasSensor()) { - result = bmp280Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (bme280Sensor.hasSensor()) { - result = bme280Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (ltr390uvSensor.hasSensor()) { - result = ltr390uvSensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (bmp3xxSensor.hasSensor()) { - result = bmp3xxSensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (bme680Sensor.hasSensor()) { - result = bme680Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (dps310Sensor.hasSensor()) { - result = dps310Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (mcp9808Sensor.hasSensor()) { - result = mcp9808Sensor.handleAdminMessage(mp, request, response); + + for (TelemetrySensor *sensor : sensors) { + result = sensor->handleAdminMessage(mp, request, response); if (result != AdminMessageHandleResult::NOT_HANDLED) return result; } + if (ina219Sensor.hasSensor()) { result = ina219Sensor.handleAdminMessage(mp, request, response); if (result != AdminMessageHandleResult::NOT_HANDLED) @@ -883,60 +700,11 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule if (result != AdminMessageHandleResult::NOT_HANDLED) return result; } - if (veml7700Sensor.hasSensor()) { - result = veml7700Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (tsl2591Sensor.hasSensor()) { - result = tsl2591Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (opt3001Sensor.hasSensor()) { - result = opt3001Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (mlx90632Sensor.hasSensor()) { - result = mlx90632Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (rcwl9620Sensor.hasSensor()) { - result = rcwl9620Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (nau7802Sensor.hasSensor()) { - result = nau7802Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } - if (aht10Sensor.hasSensor()) { - result = aht10Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } if (max17048Sensor.hasSensor()) { result = max17048Sensor.handleAdminMessage(mp, request, response); if (result != AdminMessageHandleResult::NOT_HANDLED) return result; } - if (cgRadSens.hasSensor()) { - result = cgRadSens.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } -#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && \ - RAK_4631 == \ - 1 // Not really needed, but may as well just skip it at a lower level if no library or not a RAK_4631 - if (rak12035Sensor.hasSensor()) { - result = rak12035Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } -#endif #endif return result; } diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h index d70c063fc..6e4ce82e7 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.h +++ b/src/modules/Telemetry/EnvironmentTelemetry.h @@ -11,10 +11,13 @@ #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "NodeDB.h" #include "ProtobufModule.h" +#include "detect/ScanI2CConsumer.h" #include #include -class EnvironmentTelemetryModule : private concurrency::OSThread, public ProtobufModule +class EnvironmentTelemetryModule : private concurrency::OSThread, + public ScanI2CConsumer, + public ProtobufModule { CallbackObserver nodeStatusObserver = CallbackObserver(this, @@ -22,7 +25,7 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu public: EnvironmentTelemetryModule() - : concurrency::OSThread("EnvironmentTelemetry"), + : concurrency::OSThread("EnvironmentTelemetry"), ScanI2CConsumer(), ProtobufModule("EnvironmentTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg) { lastMeasurementPacket = nullptr; @@ -56,6 +59,8 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu meshtastic_AdminMessage *request, meshtastic_AdminMessage *response) override; + void i2cScanFinished(ScanI2C *i2cScanner); + private: bool firstTime = 1; meshtastic_MeshPacket *lastMeasurementPacket; diff --git a/src/modules/Telemetry/Sensor/AHT10.cpp b/src/modules/Telemetry/Sensor/AHT10.cpp index 35934533b..52fdc05c0 100644 --- a/src/modules/Telemetry/Sensor/AHT10.cpp +++ b/src/modules/Telemetry/Sensor/AHT10.cpp @@ -15,20 +15,16 @@ AHT10Sensor::AHT10Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_AHT10, "AHT10") {} -int32_t AHT10Sensor::runOnce() +bool AHT10Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } aht10 = Adafruit_AHTX0(); - status = aht10.begin(nodeTelemetrySensorsMap[sensorType].second, 0, nodeTelemetrySensorsMap[sensorType].first); + status = aht10.begin(bus, 0, dev->address.address); - return initI2CSensor(); + initI2CSensor(); + return status; } -void AHT10Sensor::setup() {} - bool AHT10Sensor::getMetrics(meshtastic_Telemetry *measurement) { LOG_DEBUG("AHT10 getMetrics"); @@ -36,11 +32,16 @@ bool AHT10Sensor::getMetrics(meshtastic_Telemetry *measurement) sensors_event_t humidity, temp; aht10.getEvent(&humidity, &temp); - measurement->variant.environment_metrics.has_temperature = true; - measurement->variant.environment_metrics.has_relative_humidity = true; + // prefer other sensors like bmp280, bmp3xx + if (!measurement->variant.environment_metrics.has_temperature) { + measurement->variant.environment_metrics.has_temperature = true; + measurement->variant.environment_metrics.temperature = temp.temperature; + } - measurement->variant.environment_metrics.temperature = temp.temperature; - measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity; + if (!measurement->variant.environment_metrics.has_relative_humidity) { + measurement->variant.environment_metrics.has_relative_humidity = true; + measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity; + } return true; } diff --git a/src/modules/Telemetry/Sensor/AHT10.h b/src/modules/Telemetry/Sensor/AHT10.h index a6fa19952..ab3f5806c 100644 --- a/src/modules/Telemetry/Sensor/AHT10.h +++ b/src/modules/Telemetry/Sensor/AHT10.h @@ -15,13 +15,10 @@ class AHT10Sensor : public TelemetrySensor private: Adafruit_AHTX0 aht10; - protected: - virtual void setup() override; - public: AHT10Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif diff --git a/src/modules/Telemetry/Sensor/BME280Sensor.cpp b/src/modules/Telemetry/Sensor/BME280Sensor.cpp index d7b0a8a38..779b2e603 100644 --- a/src/modules/Telemetry/Sensor/BME280Sensor.cpp +++ b/src/modules/Telemetry/Sensor/BME280Sensor.cpp @@ -10,13 +10,13 @@ BME280Sensor::BME280Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME280, "BME280") {} -int32_t BME280Sensor::runOnce() +bool BME280Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + status = bme280.begin(dev->address.address, bus); + if (!status) { + return status; } - status = bme280.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second); bme280.setSampling(Adafruit_BME280::MODE_FORCED, Adafruit_BME280::SAMPLING_X1, // Temp. oversampling @@ -24,11 +24,10 @@ int32_t BME280Sensor::runOnce() Adafruit_BME280::SAMPLING_X1, // Humidity oversampling Adafruit_BME280::FILTER_OFF, Adafruit_BME280::STANDBY_MS_1000); - return initI2CSensor(); + initI2CSensor(); + return status; } -void BME280Sensor::setup() {} - bool BME280Sensor::getMetrics(meshtastic_Telemetry *measurement) { measurement->variant.environment_metrics.has_temperature = true; diff --git a/src/modules/Telemetry/Sensor/BME280Sensor.h b/src/modules/Telemetry/Sensor/BME280Sensor.h index d1e21c8d5..fadae46cd 100644 --- a/src/modules/Telemetry/Sensor/BME280Sensor.h +++ b/src/modules/Telemetry/Sensor/BME280Sensor.h @@ -11,13 +11,10 @@ class BME280Sensor : public TelemetrySensor private: Adafruit_BME280 bme280; - protected: - virtual void setup() override; - public: BME280Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.cpp b/src/modules/Telemetry/Sensor/BME680Sensor.cpp index fce029deb..95f3dc5f0 100644 --- a/src/modules/Telemetry/Sensor/BME680Sensor.cpp +++ b/src/modules/Telemetry/Sensor/BME680Sensor.cpp @@ -10,7 +10,7 @@ BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {} -int32_t BME680Sensor::runTrigger() +int32_t BME680Sensor::runOnce() { if (!bme680.run()) { checkStatus("runTrigger"); @@ -18,13 +18,10 @@ int32_t BME680Sensor::runTrigger() return 35; } -int32_t BME680Sensor::runOnce() +bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { - - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } - if (!bme680.begin(nodeTelemetrySensorsMap[sensorType].first, *nodeTelemetrySensorsMap[sensorType].second)) + status = 0; + if (!bme680.begin(dev->address.address, *bus)) checkStatus("begin"); if (bme680.status == BSEC_OK) { @@ -40,17 +37,15 @@ int32_t BME680Sensor::runOnce() } LOG_INFO("Init sensor: %s with the BSEC Library version %d.%d.%d.%d ", sensorName, bme680.version.major, bme680.version.minor, bme680.version.major_bugfix, bme680.version.minor_bugfix); - } else { - status = 0; } + if (status == 0) LOG_DEBUG("BME680Sensor::runOnce: bme680.status %d", bme680.status); - return initI2CSensor(); + initI2CSensor(); + return status; } -void BME680Sensor::setup() {} - bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement) { if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0) diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.h b/src/modules/Telemetry/Sensor/BME680Sensor.h index ce1fa4f3b..f4ead95f7 100644 --- a/src/modules/Telemetry/Sensor/BME680Sensor.h +++ b/src/modules/Telemetry/Sensor/BME680Sensor.h @@ -18,7 +18,6 @@ class BME680Sensor : public TelemetrySensor Bsec2 bme680; protected: - virtual void setup() override; const char *bsecConfigFileName = "/prefs/bsec.dat"; uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0}; uint8_t accuracy = 0; @@ -38,9 +37,9 @@ class BME680Sensor : public TelemetrySensor public: BME680Sensor(); - int32_t runTrigger(); virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/BMP085Sensor.cpp b/src/modules/Telemetry/Sensor/BMP085Sensor.cpp index 8087eb4b9..1fb2ecc28 100644 --- a/src/modules/Telemetry/Sensor/BMP085Sensor.cpp +++ b/src/modules/Telemetry/Sensor/BMP085Sensor.cpp @@ -10,20 +10,17 @@ BMP085Sensor::BMP085Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BMP085, "BMP085") {} -int32_t BMP085Sensor::runOnce() +bool BMP085Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } + bmp085 = Adafruit_BMP085(); - status = bmp085.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second); + status = bmp085.begin(dev->address.address, bus); - return initI2CSensor(); + initI2CSensor(); + return status; } -void BMP085Sensor::setup() {} - bool BMP085Sensor::getMetrics(meshtastic_Telemetry *measurement) { measurement->variant.environment_metrics.has_temperature = true; diff --git a/src/modules/Telemetry/Sensor/BMP085Sensor.h b/src/modules/Telemetry/Sensor/BMP085Sensor.h index 8dadceab4..12ccf35a1 100644 --- a/src/modules/Telemetry/Sensor/BMP085Sensor.h +++ b/src/modules/Telemetry/Sensor/BMP085Sensor.h @@ -11,13 +11,10 @@ class BMP085Sensor : public TelemetrySensor private: Adafruit_BMP085 bmp085; - protected: - virtual void setup() override; - public: BMP085Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/BMP280Sensor.cpp b/src/modules/Telemetry/Sensor/BMP280Sensor.cpp index 47069b8e0..2b7407c43 100644 --- a/src/modules/Telemetry/Sensor/BMP280Sensor.cpp +++ b/src/modules/Telemetry/Sensor/BMP280Sensor.cpp @@ -10,25 +10,25 @@ BMP280Sensor::BMP280Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BMP280, "BMP280") {} -int32_t BMP280Sensor::runOnce() +bool BMP280Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + + bmp280 = Adafruit_BMP280(bus); + status = bmp280.begin(dev->address.address); + if (!status) { + return status; } - bmp280 = Adafruit_BMP280(nodeTelemetrySensorsMap[sensorType].second); - status = bmp280.begin(nodeTelemetrySensorsMap[sensorType].first); bmp280.setSampling(Adafruit_BMP280::MODE_FORCED, Adafruit_BMP280::SAMPLING_X1, // Temp. oversampling Adafruit_BMP280::SAMPLING_X1, // Pressure oversampling Adafruit_BMP280::FILTER_OFF, Adafruit_BMP280::STANDBY_MS_1000); - return initI2CSensor(); + initI2CSensor(); + return status; } -void BMP280Sensor::setup() {} - bool BMP280Sensor::getMetrics(meshtastic_Telemetry *measurement) { measurement->variant.environment_metrics.has_temperature = true; diff --git a/src/modules/Telemetry/Sensor/BMP280Sensor.h b/src/modules/Telemetry/Sensor/BMP280Sensor.h index d615411b2..2199fc0cd 100644 --- a/src/modules/Telemetry/Sensor/BMP280Sensor.h +++ b/src/modules/Telemetry/Sensor/BMP280Sensor.h @@ -11,13 +11,10 @@ class BMP280Sensor : public TelemetrySensor private: Adafruit_BMP280 bmp280; - protected: - virtual void setup() override; - public: BMP280Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/BMP3XXSensor.cpp b/src/modules/Telemetry/Sensor/BMP3XXSensor.cpp index 28a71b48f..ac80732bf 100644 --- a/src/modules/Telemetry/Sensor/BMP3XXSensor.cpp +++ b/src/modules/Telemetry/Sensor/BMP3XXSensor.cpp @@ -6,20 +6,18 @@ BMP3XXSensor::BMP3XXSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BMP3XX, "BMP3XX") {} -void BMP3XXSensor::setup() {} - -int32_t BMP3XXSensor::runOnce() +bool BMP3XXSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } // Get a singleton instance and initialise the bmp3xx if (bmp3xx == nullptr) { bmp3xx = BMP3XXSingleton::GetInstance(); } - status = bmp3xx->begin_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second); + status = bmp3xx->begin_I2C(dev->address.address, bus); + if (!status) { + return status; + } // set up oversampling and filter initialization bmp3xx->setTemperatureOversampling(BMP3_OVERSAMPLING_4X); @@ -31,7 +29,8 @@ int32_t BMP3XXSensor::runOnce() for (int i = 0; i < 3; i++) { bmp3xx->performReading(); } - return initI2CSensor(); + initI2CSensor(); + return status; } bool BMP3XXSensor::getMetrics(meshtastic_Telemetry *measurement) diff --git a/src/modules/Telemetry/Sensor/BMP3XXSensor.h b/src/modules/Telemetry/Sensor/BMP3XXSensor.h index 6ab0f533d..7ce14d9db 100644 --- a/src/modules/Telemetry/Sensor/BMP3XXSensor.h +++ b/src/modules/Telemetry/Sensor/BMP3XXSensor.h @@ -43,12 +43,11 @@ class BMP3XXSensor : public TelemetrySensor { protected: BMP3XXSingleton *bmp3xx = nullptr; - virtual void setup() override; public: BMP3XXSensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif diff --git a/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp index ac5df1b81..e7b191398 100644 --- a/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp +++ b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp @@ -14,22 +14,16 @@ CGRadSensSensor::CGRadSensSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RADSENS, "RadSens") {} -int32_t CGRadSensSensor::runOnce() +bool CGRadSensSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { // Initialize the sensor following the same pattern as RCWL9620Sensor LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } - status = true; - begin(nodeTelemetrySensorsMap[sensorType].second, nodeTelemetrySensorsMap[sensorType].first); - - return initI2CSensor(); + begin(bus, dev->address.address); + initI2CSensor(); + return status; } -void CGRadSensSensor::setup() {} - void CGRadSensSensor::begin(TwoWire *wire, uint8_t addr) { // Store the Wire and address to the sensor following the same pattern as RCWL9620Sensor diff --git a/src/modules/Telemetry/Sensor/CGRadSensSensor.h b/src/modules/Telemetry/Sensor/CGRadSensSensor.h index 3b15a19a2..c677e8899 100644 --- a/src/modules/Telemetry/Sensor/CGRadSensSensor.h +++ b/src/modules/Telemetry/Sensor/CGRadSensSensor.h @@ -17,14 +17,13 @@ class CGRadSensSensor : public TelemetrySensor TwoWire *_wire = &Wire; protected: - virtual void setup() override; void begin(TwoWire *wire = &Wire, uint8_t addr = 0x66); float getStaticRadiation(); public: CGRadSensSensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp b/src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp index 9581057b0..59a98e291 100644 --- a/src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp +++ b/src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp @@ -10,31 +10,39 @@ DFRobotGravitySensor::DFRobotGravitySensor() : TelemetrySensor(meshtastic_TelemetrySensorType_DFROBOT_RAIN, "DFROBOT_RAIN") {} -int32_t DFRobotGravitySensor::runOnce() +DFRobotGravitySensor::~DFRobotGravitySensor() { - LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + if (gravity) { + delete gravity; + gravity = nullptr; } - - gravity = DFRobot_RainfallSensor_I2C(nodeTelemetrySensorsMap[sensorType].second); - status = gravity.begin(); - - return initI2CSensor(); } -void DFRobotGravitySensor::setup() +bool DFRobotGravitySensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { - LOG_DEBUG("%s VID: %x, PID: %x, Version: %s", sensorName, gravity.vid, gravity.pid, gravity.getFirmwareVersion().c_str()); + LOG_INFO("Init sensor: %s", sensorName); + + gravity = new DFRobot_RainfallSensor_I2C(bus); + status = gravity->begin(); + + LOG_DEBUG("%s VID: %x, PID: %x, Version: %s", sensorName, gravity->vid, gravity->pid, gravity->getFirmwareVersion().c_str()); + + initI2CSensor(); + return status; } bool DFRobotGravitySensor::getMetrics(meshtastic_Telemetry *measurement) { + if (!gravity) { + LOG_ERROR("DFRobotGravitySensor not initialized"); + return false; + } + measurement->variant.environment_metrics.has_rainfall_1h = true; measurement->variant.environment_metrics.has_rainfall_24h = true; - measurement->variant.environment_metrics.rainfall_1h = gravity.getRainfall(1); - measurement->variant.environment_metrics.rainfall_24h = gravity.getRainfall(24); + measurement->variant.environment_metrics.rainfall_1h = gravity->getRainfall(1); + measurement->variant.environment_metrics.rainfall_24h = gravity->getRainfall(24); LOG_INFO("Rain 1h: %f mm", measurement->variant.environment_metrics.rainfall_1h); LOG_INFO("Rain 24h: %f mm", measurement->variant.environment_metrics.rainfall_24h); diff --git a/src/modules/Telemetry/Sensor/DFRobotGravitySensor.h b/src/modules/Telemetry/Sensor/DFRobotGravitySensor.h index dfd81a913..2b4890e30 100644 --- a/src/modules/Telemetry/Sensor/DFRobotGravitySensor.h +++ b/src/modules/Telemetry/Sensor/DFRobotGravitySensor.h @@ -14,15 +14,13 @@ class DFRobotGravitySensor : public TelemetrySensor { private: - DFRobot_RainfallSensor_I2C gravity = DFRobot_RainfallSensor_I2C(nodeTelemetrySensorsMap[sensorType].second); - - protected: - virtual void setup() override; + DFRobot_RainfallSensor_I2C *gravity = nullptr; public: DFRobotGravitySensor(); - virtual int32_t runOnce() override; + ~DFRobotGravitySensor(); virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif diff --git a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.cpp b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.cpp index d962f1634..2c2aeed6d 100644 --- a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.cpp +++ b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.cpp @@ -11,14 +11,10 @@ DFRobotLarkSensor::DFRobotLarkSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_DFROBOT_LARK, "DFROBOT_LARK") {} -int32_t DFRobotLarkSensor::runOnce() +bool DFRobotLarkSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } - - lark = DFRobot_LarkWeatherStation_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second); + lark = DFRobot_LarkWeatherStation_I2C(dev->address.address, bus); if (lark.begin() == 0) // DFRobotLarkSensor init { @@ -28,11 +24,10 @@ int32_t DFRobotLarkSensor::runOnce() LOG_ERROR("DFRobotLarkSensor Init Failed"); status = false; } - return initI2CSensor(); + initI2CSensor(); + return status; } -void DFRobotLarkSensor::setup() {} - bool DFRobotLarkSensor::getMetrics(meshtastic_Telemetry *measurement) { measurement->variant.environment_metrics.has_temperature = true; diff --git a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h index 7b67bc5b6..f3e4661a1 100644 --- a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h +++ b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h @@ -16,13 +16,10 @@ class DFRobotLarkSensor : public TelemetrySensor private: DFRobot_LarkWeatherStation_I2C lark = DFRobot_LarkWeatherStation_I2C(); - protected: - virtual void setup() override; - public: DFRobotLarkSensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif diff --git a/src/modules/Telemetry/Sensor/DPS310Sensor.cpp b/src/modules/Telemetry/Sensor/DPS310Sensor.cpp index cc9b83af8..19e54aa4b 100644 --- a/src/modules/Telemetry/Sensor/DPS310Sensor.cpp +++ b/src/modules/Telemetry/Sensor/DPS310Sensor.cpp @@ -9,23 +9,22 @@ DPS310Sensor::DPS310Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_DPS310, "DPS310") {} -int32_t DPS310Sensor::runOnce() +bool DPS310Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + status = dps310.begin_I2C(dev->address.address, bus); + if (!status) { + return status; } - status = dps310.begin_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second); dps310.configurePressure(DPS310_1HZ, DPS310_4SAMPLES); dps310.configureTemperature(DPS310_1HZ, DPS310_4SAMPLES); dps310.setMode(DPS310_CONT_PRESTEMP); - return initI2CSensor(); + initI2CSensor(); + return status; } -void DPS310Sensor::setup() {} - bool DPS310Sensor::getMetrics(meshtastic_Telemetry *measurement) { sensors_event_t temp, press; diff --git a/src/modules/Telemetry/Sensor/DPS310Sensor.h b/src/modules/Telemetry/Sensor/DPS310Sensor.h index e9b4ece89..4de8b2d1a 100644 --- a/src/modules/Telemetry/Sensor/DPS310Sensor.h +++ b/src/modules/Telemetry/Sensor/DPS310Sensor.h @@ -11,13 +11,10 @@ class DPS310Sensor : public TelemetrySensor private: Adafruit_DPS310 dps310; - protected: - virtual void setup() override; - public: DPS310Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/IndicatorSensor.cpp b/src/modules/Telemetry/Sensor/IndicatorSensor.cpp index 317357137..26a4bc5fc 100644 --- a/src/modules/Telemetry/Sensor/IndicatorSensor.cpp +++ b/src/modules/Telemetry/Sensor/IndicatorSensor.cpp @@ -61,11 +61,11 @@ static int cmd_send(uint8_t cmd, const char *p_data, uint8_t len) return -1; } -int32_t IndicatorSensor::runOnce() +bool IndicatorSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("%s: init", sensorName); setup(); - return 2 * DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; // give it some time to start up + return true; } void IndicatorSensor::setup() diff --git a/src/modules/Telemetry/Sensor/IndicatorSensor.h b/src/modules/Telemetry/Sensor/IndicatorSensor.h index 48ecef8de..22a0d9c83 100644 --- a/src/modules/Telemetry/Sensor/IndicatorSensor.h +++ b/src/modules/Telemetry/Sensor/IndicatorSensor.h @@ -7,13 +7,13 @@ class IndicatorSensor : public TelemetrySensor { - protected: - virtual void setup() override; - public: IndicatorSensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; + + private: + void setup(); }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp b/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp index cf0fbe4a9..4ed78dcb0 100644 --- a/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp +++ b/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp @@ -10,19 +10,17 @@ LPS22HBSensor::LPS22HBSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_LPS22, "LPS22HB") {} -int32_t LPS22HBSensor::runOnce() +bool LPS22HBSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + status = lps22hb.begin_I2C(dev->address.address, bus); + if (!status) { + return status; } - status = lps22hb.begin_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second); - return initI2CSensor(); -} - -void LPS22HBSensor::setup() -{ lps22hb.setDataRate(LPS22_RATE_10_HZ); + + initI2CSensor(); + return status; } bool LPS22HBSensor::getMetrics(meshtastic_Telemetry *measurement) diff --git a/src/modules/Telemetry/Sensor/LPS22HBSensor.h b/src/modules/Telemetry/Sensor/LPS22HBSensor.h index 24d75e903..90b006fa2 100644 --- a/src/modules/Telemetry/Sensor/LPS22HBSensor.h +++ b/src/modules/Telemetry/Sensor/LPS22HBSensor.h @@ -12,13 +12,10 @@ class LPS22HBSensor : public TelemetrySensor private: Adafruit_LPS22 lps22hb; - protected: - virtual void setup() override; - public: LPS22HBSensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/LTR390UVSensor.cpp b/src/modules/Telemetry/Sensor/LTR390UVSensor.cpp index fb84700c4..cb7290fee 100644 --- a/src/modules/Telemetry/Sensor/LTR390UVSensor.cpp +++ b/src/modules/Telemetry/Sensor/LTR390UVSensor.cpp @@ -9,23 +9,23 @@ LTR390UVSensor::LTR390UVSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_LTR390UV, "LTR390UV") {} -int32_t LTR390UVSensor::runOnce() +bool LTR390UVSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + + status = ltr390uv.begin(bus); + if (!status) { + return status; } - status = ltr390uv.begin(nodeTelemetrySensorsMap[sensorType].second); ltr390uv.setMode(LTR390_MODE_UVS); ltr390uv.setGain(LTR390_GAIN_18); // Datasheet default ltr390uv.setResolution(LTR390_RESOLUTION_20BIT); // Datasheet default - return initI2CSensor(); + initI2CSensor(); + return status; } -void LTR390UVSensor::setup() {} - bool LTR390UVSensor::getMetrics(meshtastic_Telemetry *measurement) { LOG_DEBUG("LTR390UV getMetrics"); diff --git a/src/modules/Telemetry/Sensor/LTR390UVSensor.h b/src/modules/Telemetry/Sensor/LTR390UVSensor.h index 40206bce8..e12d17274 100644 --- a/src/modules/Telemetry/Sensor/LTR390UVSensor.h +++ b/src/modules/Telemetry/Sensor/LTR390UVSensor.h @@ -13,13 +13,10 @@ class LTR390UVSensor : public TelemetrySensor float lastLuxReading = 0; float lastUVReading = 0; - protected: - virtual void setup() override; - public: LTR390UVSensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp b/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp index 906634c40..c93d6a927 100644 --- a/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp +++ b/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp @@ -9,19 +9,17 @@ MCP9808Sensor::MCP9808Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_MCP9808, "MCP9808") {} -int32_t MCP9808Sensor::runOnce() +bool MCP9808Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + status = mcp9808.begin(dev->address.address, bus); + if (!status) { + return status; } - status = mcp9808.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second); - return initI2CSensor(); -} - -void MCP9808Sensor::setup() -{ mcp9808.setResolution(2); + + initI2CSensor(); + return status; } bool MCP9808Sensor::getMetrics(meshtastic_Telemetry *measurement) diff --git a/src/modules/Telemetry/Sensor/MCP9808Sensor.h b/src/modules/Telemetry/Sensor/MCP9808Sensor.h index 705a71700..cef7a48c2 100644 --- a/src/modules/Telemetry/Sensor/MCP9808Sensor.h +++ b/src/modules/Telemetry/Sensor/MCP9808Sensor.h @@ -11,13 +11,10 @@ class MCP9808Sensor : public TelemetrySensor private: Adafruit_MCP9808 mcp9808; - protected: - virtual void setup() override; - public: MCP9808Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/MLX90632Sensor.cpp b/src/modules/Telemetry/Sensor/MLX90632Sensor.cpp index dfc049023..eb84edffc 100644 --- a/src/modules/Telemetry/Sensor/MLX90632Sensor.cpp +++ b/src/modules/Telemetry/Sensor/MLX90632Sensor.cpp @@ -8,16 +8,12 @@ MLX90632Sensor::MLX90632Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_MLX90632, "MLX90632") {} -int32_t MLX90632Sensor::runOnce() +bool MLX90632Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } MLX90632::status returnError; - if (mlx.begin(nodeTelemetrySensorsMap[sensorType].first, *nodeTelemetrySensorsMap[sensorType].second, returnError) == - true) // MLX90632 init + if (mlx.begin(dev->address.address, *bus, returnError) == true) // MLX90632 init { LOG_DEBUG("MLX90632 Init Succeed"); status = true; @@ -25,11 +21,10 @@ int32_t MLX90632Sensor::runOnce() LOG_ERROR("MLX90632 Init Failed"); status = false; } - return initI2CSensor(); + initI2CSensor(); + return status; } -void MLX90632Sensor::setup() {} - bool MLX90632Sensor::getMetrics(meshtastic_Telemetry *measurement) { measurement->variant.environment_metrics.has_temperature = true; diff --git a/src/modules/Telemetry/Sensor/MLX90632Sensor.h b/src/modules/Telemetry/Sensor/MLX90632Sensor.h index ef7be180a..566db8319 100644 --- a/src/modules/Telemetry/Sensor/MLX90632Sensor.h +++ b/src/modules/Telemetry/Sensor/MLX90632Sensor.h @@ -11,13 +11,10 @@ class MLX90632Sensor : public TelemetrySensor private: MLX90632 mlx = MLX90632(); - protected: - virtual void setup() override; - public: MLX90632Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp index b6b5d89f7..e67b78145 100644 --- a/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp +++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp @@ -16,24 +16,23 @@ meshtastic_Nau7802Config nau7802config = meshtastic_Nau7802Config_init_zero; NAU7802Sensor::NAU7802Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_NAU7802, "NAU7802") {} -int32_t NAU7802Sensor::runOnce() +bool NAU7802Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + status = nau7802.begin(*bus); + if (!status) { + return status; } - status = nau7802.begin(*nodeTelemetrySensorsMap[sensorType].second); nau7802.setSampleRate(NAU7802_SPS_320); if (!loadCalibrationData()) { LOG_ERROR("Failed to load calibration data"); } nau7802.calibrateAFE(); LOG_INFO("Offset: %d, Calibration factor: %.2f", nau7802.getZeroOffset(), nau7802.getCalibrationFactor()); - return initI2CSensor(); + initI2CSensor(); + return status; } -void NAU7802Sensor::setup() {} - bool NAU7802Sensor::getMetrics(meshtastic_Telemetry *measurement) { LOG_DEBUG("NAU7802 getMetrics"); diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.h b/src/modules/Telemetry/Sensor/NAU7802Sensor.h index cb9e64829..a45e9a78a 100644 --- a/src/modules/Telemetry/Sensor/NAU7802Sensor.h +++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.h @@ -13,15 +13,14 @@ class NAU7802Sensor : public TelemetrySensor NAU7802 nau7802; protected: - virtual void setup() override; const char *nau7802ConfigFileName = "/prefs/nau7802.dat"; bool saveCalibrationData(); bool loadCalibrationData(); public: NAU7802Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; void tare(); void calibrate(float weight); AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, diff --git a/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp b/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp index 1f0407374..3407f2f0f 100644 --- a/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp +++ b/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp @@ -9,20 +9,15 @@ OPT3001Sensor::OPT3001Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_OPT3001, "OPT3001") {} -int32_t OPT3001Sensor::runOnce() +bool OPT3001Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } - auto errorCode = opt3001.begin(nodeTelemetrySensorsMap[sensorType].first); + auto errorCode = opt3001.begin(dev->address.address); status = errorCode == NO_ERROR; + if (!status) { + return status; + } - return initI2CSensor(); -} - -void OPT3001Sensor::setup() -{ OPT3001_Config newConfig; newConfig.RangeNumber = 0b1100; @@ -34,6 +29,10 @@ void OPT3001Sensor::setup() if (errorConfig != NO_ERROR) { LOG_ERROR("OPT3001 configuration error #%d", errorConfig); } + status = errorConfig == NO_ERROR; + + initI2CSensor(); + return status; } bool OPT3001Sensor::getMetrics(meshtastic_Telemetry *measurement) diff --git a/src/modules/Telemetry/Sensor/OPT3001Sensor.h b/src/modules/Telemetry/Sensor/OPT3001Sensor.h index a9da2d705..c8a140b51 100644 --- a/src/modules/Telemetry/Sensor/OPT3001Sensor.h +++ b/src/modules/Telemetry/Sensor/OPT3001Sensor.h @@ -12,13 +12,13 @@ class OPT3001Sensor : public TelemetrySensor private: ClosedCube_OPT3001 opt3001; - protected: - virtual void setup() override; - public: OPT3001Sensor(); - virtual int32_t runOnce() override; +#if WIRE_INTERFACES_COUNT > 1 + virtual bool onlyWire1() { return true; } +#endif virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/PCT2075Sensor.cpp b/src/modules/Telemetry/Sensor/PCT2075Sensor.cpp index d2b50d983..189317bf2 100644 --- a/src/modules/Telemetry/Sensor/PCT2075Sensor.cpp +++ b/src/modules/Telemetry/Sensor/PCT2075Sensor.cpp @@ -9,24 +9,18 @@ PCT2075Sensor::PCT2075Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_PCT2075, "PCT2075") {} -int32_t PCT2075Sensor::runOnce() +bool PCT2075Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } + status = pct2075.begin(dev->address.address, bus); - status = pct2075.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second); - - return initI2CSensor(); + initI2CSensor(); + return status; } -void PCT2075Sensor::setup() {} - bool PCT2075Sensor::getMetrics(meshtastic_Telemetry *measurement) { measurement->variant.environment_metrics.has_temperature = true; - measurement->variant.environment_metrics.temperature = pct2075.getTemperature(); return true; diff --git a/src/modules/Telemetry/Sensor/PCT2075Sensor.h b/src/modules/Telemetry/Sensor/PCT2075Sensor.h index 842c973d0..55f9423d4 100644 --- a/src/modules/Telemetry/Sensor/PCT2075Sensor.h +++ b/src/modules/Telemetry/Sensor/PCT2075Sensor.h @@ -12,13 +12,10 @@ class PCT2075Sensor : public TelemetrySensor private: Adafruit_PCT2075 pct2075; - protected: - virtual void setup() override; - public: PCT2075Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif diff --git a/src/modules/Telemetry/Sensor/RAK12035Sensor.cpp b/src/modules/Telemetry/Sensor/RAK12035Sensor.cpp index 7a1bb01ce..ff0628cc3 100644 --- a/src/modules/Telemetry/Sensor/RAK12035Sensor.cpp +++ b/src/modules/Telemetry/Sensor/RAK12035Sensor.cpp @@ -6,16 +6,12 @@ RAK12035Sensor::RAK12035Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RAK12035, "RAK12035") {} -int32_t RAK12035Sensor::runOnce() +bool RAK12035Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } - // TODO:: check for up to 2 additional sensors and start them if present. sensor.set_sensor_addr(RAK120351_ADDR); delay(100); - sensor.begin(nodeTelemetrySensorsMap[sensorType].first); + sensor.begin(dev->address.address); // Get sensor firmware version uint8_t data = 0; @@ -31,8 +27,13 @@ int32_t RAK12035Sensor::runOnce() LOG_ERROR("RAK12035Sensor Init Failed"); status = false; } + if (!status) { + return status; + } + setup(); - return initI2CSensor(); + initI2CSensor(); + return status; } void RAK12035Sensor::setup() diff --git a/src/modules/Telemetry/Sensor/RAK12035Sensor.h b/src/modules/Telemetry/Sensor/RAK12035Sensor.h index 2c32a840d..6a38d2eb3 100644 --- a/src/modules/Telemetry/Sensor/RAK12035Sensor.h +++ b/src/modules/Telemetry/Sensor/RAK12035Sensor.h @@ -16,13 +16,14 @@ class RAK12035Sensor : public TelemetrySensor { private: RAK12035 sensor; - - protected: - virtual void setup() override; + void setup(); public: RAK12035Sensor(); - virtual int32_t runOnce() override; +#if WIRE_INTERFACES_COUNT > 1 + virtual bool onlyWire1() { return true; } +#endif virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif diff --git a/src/modules/Telemetry/Sensor/RCWL9620Sensor.cpp b/src/modules/Telemetry/Sensor/RCWL9620Sensor.cpp index 9f7a55cc5..3dbd06e8d 100644 --- a/src/modules/Telemetry/Sensor/RCWL9620Sensor.cpp +++ b/src/modules/Telemetry/Sensor/RCWL9620Sensor.cpp @@ -8,19 +8,15 @@ RCWL9620Sensor::RCWL9620Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RCWL9620, "RCWL9620") {} -int32_t RCWL9620Sensor::runOnce() +bool RCWL9620Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } status = 1; - begin(nodeTelemetrySensorsMap[sensorType].second, nodeTelemetrySensorsMap[sensorType].first); - return initI2CSensor(); + begin(bus, dev->address.address); + initI2CSensor(); + return status; } -void RCWL9620Sensor::setup() {} - bool RCWL9620Sensor::getMetrics(meshtastic_Telemetry *measurement) { measurement->variant.environment_metrics.has_distance = true; diff --git a/src/modules/Telemetry/Sensor/RCWL9620Sensor.h b/src/modules/Telemetry/Sensor/RCWL9620Sensor.h index 7f9486d25..408db3633 100644 --- a/src/modules/Telemetry/Sensor/RCWL9620Sensor.h +++ b/src/modules/Telemetry/Sensor/RCWL9620Sensor.h @@ -16,14 +16,13 @@ class RCWL9620Sensor : public TelemetrySensor uint32_t _speed = 200000UL; protected: - virtual void setup() override; void begin(TwoWire *wire = &Wire, uint8_t addr = 0x57, uint8_t sda = -1, uint8_t scl = -1, uint32_t speed = 200000UL); float getDistance(); public: RCWL9620Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHT31Sensor.cpp b/src/modules/Telemetry/Sensor/SHT31Sensor.cpp index 8619a7905..67a36933d 100644 --- a/src/modules/Telemetry/Sensor/SHT31Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SHT31Sensor.cpp @@ -9,20 +9,13 @@ SHT31Sensor::SHT31Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT31, "SHT31") {} -int32_t SHT31Sensor::runOnce() +bool SHT31Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } - sht31 = Adafruit_SHT31(nodeTelemetrySensorsMap[sensorType].second); - status = sht31.begin(nodeTelemetrySensorsMap[sensorType].first); - return initI2CSensor(); -} - -void SHT31Sensor::setup() -{ - // Set up oversampling and filter initialization + sht31 = Adafruit_SHT31(bus); + status = sht31.begin(dev->address.address); + initI2CSensor(); + return status; } bool SHT31Sensor::getMetrics(meshtastic_Telemetry *measurement) diff --git a/src/modules/Telemetry/Sensor/SHT31Sensor.h b/src/modules/Telemetry/Sensor/SHT31Sensor.h index c3d81af95..ecb7d63a6 100644 --- a/src/modules/Telemetry/Sensor/SHT31Sensor.h +++ b/src/modules/Telemetry/Sensor/SHT31Sensor.h @@ -11,13 +11,10 @@ class SHT31Sensor : public TelemetrySensor private: Adafruit_SHT31 sht31; - protected: - virtual void setup() override; - public: SHT31Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHT4XSensor.cpp b/src/modules/Telemetry/Sensor/SHT4XSensor.cpp index 83fdaf6c6..b11795d97 100644 --- a/src/modules/Telemetry/Sensor/SHT4XSensor.cpp +++ b/src/modules/Telemetry/Sensor/SHT4XSensor.cpp @@ -9,16 +9,16 @@ SHT4XSensor::SHT4XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT4X, "SHT4X") {} -int32_t SHT4XSensor::runOnce() +bool SHT4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } uint32_t serialNumber = 0; - sht4x.begin(nodeTelemetrySensorsMap[sensorType].second); + status = sht4x.begin(bus); + if (!status) { + return status; + } serialNumber = sht4x.readSerial(); if (serialNumber != 0) { @@ -29,12 +29,8 @@ int32_t SHT4XSensor::runOnce() status = 0; } - return initI2CSensor(); -} - -void SHT4XSensor::setup() -{ - // Set up oversampling and filter initialization + initI2CSensor(); + return status; } bool SHT4XSensor::getMetrics(meshtastic_Telemetry *measurement) diff --git a/src/modules/Telemetry/Sensor/SHT4XSensor.h b/src/modules/Telemetry/Sensor/SHT4XSensor.h index da608cb82..7311d2366 100644 --- a/src/modules/Telemetry/Sensor/SHT4XSensor.h +++ b/src/modules/Telemetry/Sensor/SHT4XSensor.h @@ -11,13 +11,10 @@ class SHT4XSensor : public TelemetrySensor private: Adafruit_SHT4x sht4x = Adafruit_SHT4x(); - protected: - virtual void setup() override; - public: SHT4XSensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp b/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp index e9c4d2a0b..fdab0b266 100644 --- a/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp @@ -9,19 +9,13 @@ SHTC3Sensor::SHTC3Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHTC3, "SHTC3") {} -int32_t SHTC3Sensor::runOnce() +bool SHTC3Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } - status = shtc3.begin(nodeTelemetrySensorsMap[sensorType].second); - return initI2CSensor(); -} + status = shtc3.begin(bus); -void SHTC3Sensor::setup() -{ - // Set up oversampling and filter initialization + initI2CSensor(); + return status; } bool SHTC3Sensor::getMetrics(meshtastic_Telemetry *measurement) diff --git a/src/modules/Telemetry/Sensor/SHTC3Sensor.h b/src/modules/Telemetry/Sensor/SHTC3Sensor.h index 458af6465..51cee18f7 100644 --- a/src/modules/Telemetry/Sensor/SHTC3Sensor.h +++ b/src/modules/Telemetry/Sensor/SHTC3Sensor.h @@ -11,13 +11,10 @@ class SHTC3Sensor : public TelemetrySensor private: Adafruit_SHTC3 shtc3 = Adafruit_SHTC3(); - protected: - virtual void setup() override; - public: SHTC3Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/T1000xSensor.cpp b/src/modules/Telemetry/Sensor/T1000xSensor.cpp index 068969e8e..b123450ec 100644 --- a/src/modules/Telemetry/Sensor/T1000xSensor.cpp +++ b/src/modules/Telemetry/Sensor/T1000xSensor.cpp @@ -38,18 +38,10 @@ int8_t ntc_temp2[136] = { T1000xSensor::T1000xSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "T1000x") {} -int32_t T1000xSensor::runOnce() +bool T1000xSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; - } - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; -} - -void T1000xSensor::setup() -{ - // Set up oversampling and filter initialization + return true; } float T1000xSensor::getLux() diff --git a/src/modules/Telemetry/Sensor/T1000xSensor.h b/src/modules/Telemetry/Sensor/T1000xSensor.h index a1c771cfa..b840a2d88 100644 --- a/src/modules/Telemetry/Sensor/T1000xSensor.h +++ b/src/modules/Telemetry/Sensor/T1000xSensor.h @@ -7,13 +7,10 @@ class T1000xSensor : public TelemetrySensor { - protected: - virtual void setup() override; - public: T1000xSensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; virtual float getLux(); virtual float getTemp(); }; diff --git a/src/modules/Telemetry/Sensor/TSL2561Sensor.cpp b/src/modules/Telemetry/Sensor/TSL2561Sensor.cpp index 9f3b7e460..4e02af642 100644 --- a/src/modules/Telemetry/Sensor/TSL2561Sensor.cpp +++ b/src/modules/Telemetry/Sensor/TSL2561Sensor.cpp @@ -9,22 +9,19 @@ TSL2561Sensor::TSL2561Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_TSL2561, "TSL2561") {} -int32_t TSL2561Sensor::runOnce() +bool TSL2561Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + + status = tsl.begin(bus); + if (!status) { + return status; } - - status = tsl.begin(nodeTelemetrySensorsMap[sensorType].second); - - return initI2CSensor(); -} - -void TSL2561Sensor::setup() -{ tsl.setGain(TSL2561_GAIN_1X); tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); + + initI2CSensor(); + return status; } bool TSL2561Sensor::getMetrics(meshtastic_Telemetry *measurement) diff --git a/src/modules/Telemetry/Sensor/TSL2561Sensor.h b/src/modules/Telemetry/Sensor/TSL2561Sensor.h index 0329becd8..abf5a8f73 100644 --- a/src/modules/Telemetry/Sensor/TSL2561Sensor.h +++ b/src/modules/Telemetry/Sensor/TSL2561Sensor.h @@ -12,12 +12,9 @@ class TSL2561Sensor : public TelemetrySensor // The magic number is a sensor id, the actual value doesn't matter Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_LOW, 12345); - protected: - virtual void setup() override; - public: TSL2561Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif diff --git a/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp b/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp index 04443ebec..0899d4470 100644 --- a/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp +++ b/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp @@ -10,21 +10,18 @@ TSL2591Sensor::TSL2591Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_TSL25911FN, "TSL2591") {} -int32_t TSL2591Sensor::runOnce() +bool TSL2591Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + status = tsl.begin(bus); + if (!status) { + return status; } - status = tsl.begin(nodeTelemetrySensorsMap[sensorType].second); - - return initI2CSensor(); -} - -void TSL2591Sensor::setup() -{ tsl.setGain(TSL2591_GAIN_LOW); // 1x gain tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); + + initI2CSensor(); + return status; } bool TSL2591Sensor::getMetrics(meshtastic_Telemetry *measurement) diff --git a/src/modules/Telemetry/Sensor/TSL2591Sensor.h b/src/modules/Telemetry/Sensor/TSL2591Sensor.h index edf7698b1..1ac430a03 100644 --- a/src/modules/Telemetry/Sensor/TSL2591Sensor.h +++ b/src/modules/Telemetry/Sensor/TSL2591Sensor.h @@ -11,12 +11,9 @@ class TSL2591Sensor : public TelemetrySensor private: Adafruit_TSL2591 tsl; - protected: - virtual void setup() override; - public: TSL2591Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/TelemetrySensor.h b/src/modules/Telemetry/Sensor/TelemetrySensor.h index 83d7b38b0..3c3e61808 100644 --- a/src/modules/Telemetry/Sensor/TelemetrySensor.h +++ b/src/modules/Telemetry/Sensor/TelemetrySensor.h @@ -6,6 +6,7 @@ #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "MeshModule.h" #include "NodeDB.h" +#include "detect/ScanI2C.h" #include #if !ARCH_PORTDUINO @@ -42,22 +43,32 @@ class TelemetrySensor initialized = true; return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } - virtual void setup() = 0; + + // TODO: check is setup used at all? + virtual void setup() {} public: + virtual ~TelemetrySensor() {} + virtual AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, meshtastic_AdminMessage *response) { return AdminMessageHandleResult::NOT_HANDLED; } + // TODO: delete after migration bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; } - virtual int32_t runOnce() = 0; +#if WIRE_INTERFACES_COUNT > 1 + // Set to true if Implementation only works first I2C port (Wire) + virtual bool onlyWire1() { return false; } +#endif + virtual int32_t runOnce() { return INT32_MAX; } virtual bool isInitialized() { return initialized; } virtual bool isRunning() { return status > 0; } virtual bool getMetrics(meshtastic_Telemetry *measurement) = 0; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { return false; }; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/VEML7700Sensor.cpp b/src/modules/Telemetry/Sensor/VEML7700Sensor.cpp index b075bf405..c89463be5 100644 --- a/src/modules/Telemetry/Sensor/VEML7700Sensor.cpp +++ b/src/modules/Telemetry/Sensor/VEML7700Sensor.cpp @@ -11,23 +11,22 @@ VEML7700Sensor::VEML7700Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_VEML7700, "VEML7700") {} -int32_t VEML7700Sensor::runOnce() +bool VEML7700Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { LOG_INFO("Init sensor: %s", sensorName); - if (!hasSensor()) { - return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + status = veml7700.begin(bus); + if (!status) { + return status; } - status = veml7700.begin(nodeTelemetrySensorsMap[sensorType].second); veml7700.setLowThreshold(10000); veml7700.setHighThreshold(20000); veml7700.interruptEnable(true); - return initI2CSensor(); + initI2CSensor(); + return status; } -void VEML7700Sensor::setup() {} - /*! * @brief Copmute lux from ALS reading. * @param rawALS raw ALS register value diff --git a/src/modules/Telemetry/Sensor/VEML7700Sensor.h b/src/modules/Telemetry/Sensor/VEML7700Sensor.h index f40384ad3..92883df08 100644 --- a/src/modules/Telemetry/Sensor/VEML7700Sensor.h +++ b/src/modules/Telemetry/Sensor/VEML7700Sensor.h @@ -16,12 +16,9 @@ class VEML7700Sensor : public TelemetrySensor float computeLux(uint16_t rawALS, bool corrected); float getResolution(void); - protected: - virtual void setup() override; - public: VEML7700Sensor(); - virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/nullSensor.cpp b/src/modules/Telemetry/Sensor/nullSensor.cpp index c84b9d27f..1d545186a 100644 --- a/src/modules/Telemetry/Sensor/nullSensor.cpp +++ b/src/modules/Telemetry/Sensor/nullSensor.cpp @@ -11,7 +11,7 @@ NullSensor::NullSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR int32_t NullSensor::runOnce() { - return 0; + return INT32_MAX; } void NullSensor::setup() {} From 37a0f774a2117487c45ef34f2efc96a7a06d1e45 Mon Sep 17 00:00:00 2001 From: Jason P Date: Mon, 13 Oct 2025 12:51:27 -0500 Subject: [PATCH 162/166] Fix multitude of warnings during builds (#8331) --- variants/nrf52840/meshtiny/variant.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/variants/nrf52840/meshtiny/variant.h b/variants/nrf52840/meshtiny/variant.h index d1139b3be..55aabe930 100644 --- a/variants/nrf52840/meshtiny/variant.h +++ b/variants/nrf52840/meshtiny/variant.h @@ -19,7 +19,9 @@ #ifndef _VARIANT_MESHTINY_ #define _VARIANT_MESHTINY_ +#ifndef MESHTINY #define MESHTINY +#endif /** Master clock frequency */ #define VARIANT_MCK (64000000ul) From 9ab9650248883c11995f4bf2cb6e68a5506bf605 Mon Sep 17 00:00:00 2001 From: Tom <116762865+NomDeTom@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:04:10 +0100 Subject: [PATCH 163/166] Update stale_bot.yml Extend stale period to 60 days, and added a message on stale marking. --- .github/workflows/stale_bot.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stale_bot.yml b/.github/workflows/stale_bot.yml index a80619e90..4044278e8 100644 --- a/.github/workflows/stale_bot.yml +++ b/.github/workflows/stale_bot.yml @@ -19,6 +19,7 @@ jobs: - name: Stale PR+Issues uses: actions/stale@v10.1.0 with: - days-before-stale: 45 + days-before-stale: 60 + stale-issue-message: 'This issue hasn not had any comment or update in the last 2 months. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days.' exempt-issue-labels: pinned,3.0 exempt-pr-labels: pinned,3.0 From 910fe911f80fd713c62166d61e72cede64af53e4 Mon Sep 17 00:00:00 2001 From: Tom <116762865+NomDeTom@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:12:45 +0100 Subject: [PATCH 164/166] Update stale_bot.yml --- .github/workflows/stale_bot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale_bot.yml b/.github/workflows/stale_bot.yml index 4044278e8..8a0c61a80 100644 --- a/.github/workflows/stale_bot.yml +++ b/.github/workflows/stale_bot.yml @@ -20,6 +20,6 @@ jobs: uses: actions/stale@v10.1.0 with: days-before-stale: 60 - stale-issue-message: 'This issue hasn not had any comment or update in the last 2 months. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days.' + stale-issue-message: This issue hasn not had any comment or update in the last 2 months. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days. exempt-issue-labels: pinned,3.0 exempt-pr-labels: pinned,3.0 From c4d7ad2190fa41aa3eca4435391c91cf228a6c9d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 13 Oct 2025 19:56:39 -0500 Subject: [PATCH 165/166] Kill github actions script --- bin/kill-github-actions.sh | 116 +++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100755 bin/kill-github-actions.sh diff --git a/bin/kill-github-actions.sh b/bin/kill-github-actions.sh new file mode 100755 index 000000000..f71047c5e --- /dev/null +++ b/bin/kill-github-actions.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +# Script to cancel all running GitHub Actions workflows +# Requires GitHub CLI (gh) to be installed and authenticated + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if gh CLI is installed +if ! command -v gh &> /dev/null; then + print_error "GitHub CLI (gh) is not installed. Please install it first:" + echo " brew install gh" + echo " Or visit: https://cli.github.com/" + exit 1 +fi + +# Check if authenticated +if ! gh auth status &> /dev/null; then + print_error "GitHub CLI is not authenticated. Please run:" + echo " gh auth login" + exit 1 +fi + +# Get repository info +REPO=$(gh repo view --json owner,name -q '.owner.login + "/" + .name') +if [[ -z "$REPO" ]]; then + print_error "Could not determine repository. Make sure you're in a GitHub repository." + exit 1 +fi + +print_status "Working with repository: $REPO" + +# Get all active workflows (both queued and in-progress) +print_status "Fetching active workflows (queued and in-progress)..." +QUEUED_WORKFLOWS=$(gh run list --status queued --json databaseId,displayTitle,headBranch,status --limit 100) +IN_PROGRESS_WORKFLOWS=$(gh run list --status in_progress --json databaseId,displayTitle,headBranch,status --limit 100) + +# Combine both lists +ALL_WORKFLOWS=$(echo "$QUEUED_WORKFLOWS $IN_PROGRESS_WORKFLOWS" | jq -s 'add | unique_by(.databaseId)') + +if [[ "$ALL_WORKFLOWS" == "[]" ]]; then + print_status "No active workflows found." + exit 0 +fi + +# Parse and display active workflows +echo +print_warning "Found active workflows:" +echo "$ALL_WORKFLOWS" | jq -r '.[] | " - \(.displayTitle) (Branch: \(.headBranch), Status: \(.status), ID: \(.databaseId))"' + +echo +read -p "Do you want to cancel ALL these workflows? (y/N): " -n 1 -r +echo + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_status "Cancelled by user." + exit 0 +fi + +# Cancel each workflow +print_status "Cancelling workflows..." +CANCELLED_COUNT=0 +FAILED_COUNT=0 + +while IFS= read -r WORKFLOW_ID; do + if [[ -n "$WORKFLOW_ID" ]]; then + print_status "Cancelling workflow ID: $WORKFLOW_ID" + if gh run cancel "$WORKFLOW_ID" 2>/dev/null; then + ((CANCELLED_COUNT++)) + else + print_error "Failed to cancel workflow ID: $WORKFLOW_ID" + ((FAILED_COUNT++)) + fi + fi +done < <(echo "$ALL_WORKFLOWS" | jq -r '.[].databaseId') + +echo +print_status "Summary:" +echo " - Cancelled: $CANCELLED_COUNT workflows" +if [[ $FAILED_COUNT -gt 0 ]]; then + echo " - Failed: $FAILED_COUNT workflows" +fi + +print_status "Done!" + +# Optional: Show remaining active workflows +echo +print_status "Checking for any remaining active workflows..." +REMAINING_QUEUED=$(gh run list --status queued --json databaseId --limit 10) +REMAINING_IN_PROGRESS=$(gh run list --status in_progress --json databaseId --limit 10) +REMAINING_ALL=$(echo "$REMAINING_QUEUED $REMAINING_IN_PROGRESS" | jq -s 'add | unique_by(.databaseId)') + +if [[ "$REMAINING_ALL" == "[]" ]]; then + print_status "All workflows successfully cancelled." +else + REMAINING_COUNT=$(echo "$REMAINING_ALL" | jq '. | length') + print_warning "Still $REMAINING_COUNT workflows active (may take a moment to update status)" +fi \ No newline at end of file From b8bfed28105c1ea2918449c30ec3ab1802c512dd Mon Sep 17 00:00:00 2001 From: Tom <116762865+NomDeTom@users.noreply.github.com> Date: Tue, 14 Oct 2025 12:37:40 +0100 Subject: [PATCH 166/166] return to 45 days and put a closure message. --- .github/workflows/stale_bot.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale_bot.yml b/.github/workflows/stale_bot.yml index 8a0c61a80..b528f80b2 100644 --- a/.github/workflows/stale_bot.yml +++ b/.github/workflows/stale_bot.yml @@ -19,7 +19,8 @@ jobs: - name: Stale PR+Issues uses: actions/stale@v10.1.0 with: - days-before-stale: 60 - stale-issue-message: This issue hasn not had any comment or update in the last 2 months. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days. + days-before-stale: 45 + stale-issue-message: This issue has not had any comment or update in the last month. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days. + close-issue-message: This issue has not had any comment since the last notice. It has been closed automatically. If this is incorrect, or the issue becomes relevant again, please request that it is reopened. exempt-issue-labels: pinned,3.0 exempt-pr-labels: pinned,3.0