From 9da92626e51466b328b1d5aba1de5abf7886c2ea Mon Sep 17 00:00:00 2001 From: ford-jones Date: Thu, 11 Sep 2025 14:16:48 +1200 Subject: [PATCH 01/98] 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 02/98] 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 03/98] 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 04/98] 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 05/98] 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 06/98] 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 07/98] 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 08/98] 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 09/98] 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 10/98] 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 11/98] 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 12/98] 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 13/98] 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 14/98] 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 15/98] 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 16/98] 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 17/98] 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 18/98] 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 19/98] 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 20/98] 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 21/98] 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 22/98] 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 23/98] 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 24/98] 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 25/98] 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 26/98] 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 27/98] 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 28/98] 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 29/98] 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 30/98] 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 31/98] 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 32/98] 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 33/98] 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 34/98] 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 35/98] 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 36/98] 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 37/98] 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 38/98] 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 39/98] 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 40/98] 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 41/98] 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 42/98] 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 43/98] 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 44/98] 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 45/98] 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 46/98] 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 8d323a1cf1e0570a31f1cb9499b8bb552b8bb72e Mon Sep 17 00:00:00 2001 From: Quency-D Date: Mon, 29 Sep 2025 17:49:31 +0800 Subject: [PATCH 47/98] 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 48/98] 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 49/98] 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 50/98] 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 51/98] 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 52/98] 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 53/98] 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 54/98] 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 55/98] 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 56/98] 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 57/98] 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 58/98] 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 59/98] 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 60/98] 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 61/98] 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 62/98] 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 63/98] 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 f7469159cf8c992f9869fc67ca04531edab4479a Mon Sep 17 00:00:00 2001 From: Mike Robbins Date: Wed, 1 Oct 2025 16:31:53 -0400 Subject: [PATCH 64/98] 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 65/98] 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 66/98] 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 67/98] 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 68/98] 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 69/98] 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 70/98] 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 71/98] 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 72/98] 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 73/98] 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 74/98] 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 75/98] 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 76/98] 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 77/98] 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 78/98] 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 79/98] 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 80/98] 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 81/98] 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 82/98] 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 83/98] 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 84/98] 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 85/98] 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 86/98] 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 87/98] 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 88/98] 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 89/98] 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 90/98] 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 91/98] 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 92/98] 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 93/98] 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 94/98] 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 95/98] 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 96/98] 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 97/98] 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 98/98] 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; } }