From 36827d62070c9732befb8cf65b95bfc31d84664f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 7 May 2026 12:23:48 -0500 Subject: [PATCH] Refactor node mute handling to use dedicated functions for clarity and consistency --- src/graphics/draw/MenuHandler.cpp | 12 ++---- src/graphics/draw/NodeListRenderer.cpp | 8 ++-- src/mesh/NodeDB.cpp | 48 ++++++++++------------ src/mesh/NodeDB.h | 8 ++++ src/mesh/TypeConversions.cpp | 18 ++++---- src/modules/AdminModule.cpp | 2 +- src/modules/ExternalNotificationModule.cpp | 2 +- 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index e1783bf88..440555fd7 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -1362,7 +1362,7 @@ void menuHandler::manageNodeMenu() } optionsEnumArray[options++] = Favorite; - bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0; + bool isMuted = nodeInfoLiteIsMuted(node); if (isMuted) { optionsArray[options] = "Unmute Notifications"; } else { @@ -1426,13 +1426,9 @@ void menuHandler::manageNodeMenu() return; } - if (n->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) { - n->bitfield &= ~NODEINFO_BITFIELD_IS_MUTED_MASK; - LOG_INFO("Unmuted node %08X", menuHandler::pickedNodeNum); - } else { - n->bitfield |= NODEINFO_BITFIELD_IS_MUTED_MASK; - LOG_INFO("Muted node %08X", menuHandler::pickedNodeNum); - } + const bool wasMuted = nodeInfoLiteIsMuted(n); + nodeInfoLiteSetBit(n, NODEINFO_BITFIELD_IS_MUTED_MASK, !wasMuted); + LOG_INFO(wasMuted ? "Unmuted node %08X" : "Muted node %08X", menuHandler::pickedNodeNum); nodeDB->notifyObservers(true); nodeDB->saveToDisk(); screen->setFrames(graphics::Screen::FOCUS_PRESERVE); diff --git a/src/graphics/draw/NodeListRenderer.cpp b/src/graphics/draw/NodeListRenderer.cpp index eed99b020..570001e7e 100644 --- a/src/graphics/draw/NodeListRenderer.cpp +++ b/src/graphics/draw/NodeListRenderer.cpp @@ -253,7 +253,7 @@ void drawEntryLastHeard(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int #if GRAPHICS_TFT_COLORING_ENABLED applyFavoriteNodeNameColor(display, node, nodeName, nameX, y, nameMaxWidth); #endif - bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0; + bool isMuted = nodeInfoLiteIsMuted(node); char timeStr[10]; uint32_t seconds = sinceLastSeen(node); @@ -315,7 +315,7 @@ void drawEntryHopSignal(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int #if GRAPHICS_TFT_COLORING_ENABLED applyFavoriteNodeNameColor(display, node, nodeName, nameX, y, nameMaxWidth); #endif - bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0; + bool isMuted = nodeInfoLiteIsMuted(node); display->setTextAlignment(TEXT_ALIGN_LEFT); display->setFont(FONT_SMALL); @@ -395,7 +395,7 @@ void drawNodeDistance(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16 #if GRAPHICS_TFT_COLORING_ENABLED applyFavoriteNodeNameColor(display, node, nodeName, nameX, y, nameMaxWidth); #endif - bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0; + bool isMuted = nodeInfoLiteIsMuted(node); char distStr[10] = ""; meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); @@ -505,7 +505,7 @@ void drawEntryCompass(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16 #if GRAPHICS_TFT_COLORING_ENABLED applyFavoriteNodeNameColor(display, node, nodeName, nameX, y, nameMaxWidth); #endif - bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0; + bool isMuted = nodeInfoLiteIsMuted(node); display->setTextAlignment(TEXT_ALIGN_LEFT); display->setFont(FONT_SMALL); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index c61b780a1..01e623d41 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1137,7 +1137,7 @@ void NodeDB::resetNodes(bool keepFavorites) LOG_INFO("Clearing node database - preserving favorites"); for (size_t i = 0; i < meshNodes->size(); i++) { meshtastic_NodeInfoLite &node = meshNodes->at(i); - if (i > 0 && !(node.bitfield & NODEINFO_BITFIELD_IS_FAVORITE_MASK)) { + if (i > 0 && !nodeInfoLiteIsFavorite(&node)) { eraseNodeSatellites(node.num); node = meshtastic_NodeInfoLite(); } else { @@ -1264,7 +1264,7 @@ void NodeDB::cleanupMeshDB() int newPos = 0, removed = 0; for (int i = 0; i < numMeshNodes; i++) { meshtastic_NodeInfoLite &n = meshNodes->at(i); - if (n.bitfield & NODEINFO_BITFIELD_HAS_USER_MASK) { + if (nodeInfoLiteHasUser(&n)) { if (n.public_key.size > 0) { if (memfll(n.public_key.bytes, 0, n.public_key.size)) { n.public_key.size = 0; @@ -1343,7 +1343,7 @@ void NodeDB::pickNewNodeNum() return false; if (owner.public_key.size == 32 && n->public_key.size == 32) return memcmp(n->public_key.bytes, owner.public_key.bytes, 32) == 0; - return !(n->bitfield & NODEINFO_BITFIELD_HAS_USER_MASK); + return !nodeInfoLiteHasUser(n); }; meshtastic_NodeInfoLite *found; @@ -1599,16 +1599,16 @@ void NodeDB::loadFromDisk() // Attempt recovery of owner fields from our own NodeDB entry if available. meshtastic_NodeInfoLite *us = getMeshNode(getNodeNum()); - if (us && (us->bitfield & NODEINFO_BITFIELD_HAS_USER_MASK)) { + if (nodeInfoLiteHasUser(us)) { LOG_WARN("Restoring owner fields (long_name/short_name/is_licensed/is_unmessagable) from NodeDB for our node 0x%08x", us->num); memcpy(owner.long_name, us->long_name, sizeof(owner.long_name)); owner.long_name[sizeof(owner.long_name) - 1] = '\0'; memcpy(owner.short_name, us->short_name, sizeof(owner.short_name)); owner.short_name[sizeof(owner.short_name) - 1] = '\0'; - owner.is_licensed = (us->bitfield & NODEINFO_BITFIELD_IS_LICENSED_MASK) != 0; - owner.has_is_unmessagable = (us->bitfield & NODEINFO_BITFIELD_HAS_IS_UNMESSAGABLE_MASK) != 0; - owner.is_unmessagable = (us->bitfield & NODEINFO_BITFIELD_IS_UNMESSAGABLE_MASK) != 0; + owner.is_licensed = nodeInfoLiteIsLicensed(us); + owner.has_is_unmessagable = nodeInfoLiteHasIsUnmessagable(us); + owner.is_unmessagable = nodeInfoLiteIsUnmessagable(us); // Save the recovered owner to device state on disk saveToDisk(SEGMENT_DEVICESTATE); @@ -2091,7 +2091,7 @@ size_t NodeDB::getNumOnlineMeshNodes(bool localOnly) // FIXME this implementation is kinda expensive for (int i = 0; i < numMeshNodes; i++) { - if (localOnly && (meshNodes->at(i).bitfield & NODEINFO_BITFIELD_VIA_MQTT_MASK)) + if (localOnly && nodeInfoLiteViaMqtt(&meshNodes->at(i))) continue; if (sinceLastSeen(&meshNodes->at(i)) < NUM_ONLINE_SECS) numseen++; @@ -2217,7 +2217,7 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact) // 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 (nodeInfoLiteIsKeyManuallyVerified(info) && !contact.manually_verified) { if (contact.user.public_key.size != info->public_key.size || memcmp(contact.user.public_key.bytes, info->public_key.bytes, info->public_key.size) != 0) { return; @@ -2256,7 +2256,7 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact) // 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; + nodeInfoLiteSetBit(info, NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK, true); } // Mark the node's key as manually verified to indicate trustworthiness. updateGUIforNode = info; @@ -2470,12 +2470,10 @@ void NodeDB::sortMeshDB() // TODO: Look for at(i-1) also matching own node num, and throw the DB in the trash std::swap(meshNodes->at(i), meshNodes->at(i - 1)); changed = true; - } else if ((meshNodes->at(i).bitfield & NODEINFO_BITFIELD_IS_FAVORITE_MASK) && - !(meshNodes->at(i - 1).bitfield & NODEINFO_BITFIELD_IS_FAVORITE_MASK)) { + } else if (nodeInfoLiteIsFavorite(&meshNodes->at(i)) && !nodeInfoLiteIsFavorite(&meshNodes->at(i - 1))) { std::swap(meshNodes->at(i), meshNodes->at(i - 1)); changed = true; - } else if (!(meshNodes->at(i).bitfield & NODEINFO_BITFIELD_IS_FAVORITE_MASK) && - (meshNodes->at(i - 1).bitfield & NODEINFO_BITFIELD_IS_FAVORITE_MASK)) { + } else if (!nodeInfoLiteIsFavorite(&meshNodes->at(i)) && nodeInfoLiteIsFavorite(&meshNodes->at(i - 1))) { // noop } else if (meshNodes->at(i).last_heard > meshNodes->at(i - 1).last_heard) { std::swap(meshNodes->at(i), meshNodes->at(i - 1)); @@ -2535,19 +2533,18 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) int oldestIndex = -1; int oldestBoringIndex = -1; for (int i = 1; i < numMeshNodes; i++) { - const uint32_t bf = meshNodes->at(i).bitfield; - const bool isFavorite = (bf & NODEINFO_BITFIELD_IS_FAVORITE_MASK) != 0; - const bool isIgnored = (bf & NODEINFO_BITFIELD_IS_IGNORED_MASK) != 0; - const bool isVerified = (bf & NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK) != 0; + const meshtastic_NodeInfoLite *cand = &meshNodes->at(i); + const bool isFavorite = nodeInfoLiteIsFavorite(cand); + const bool isIgnored = nodeInfoLiteIsIgnored(cand); + const bool isVerified = nodeInfoLiteIsKeyManuallyVerified(cand); // Simply the oldest non-favorite, non-ignored, non-verified node - if (!isFavorite && !isIgnored && !isVerified && meshNodes->at(i).last_heard < oldest) { - oldest = meshNodes->at(i).last_heard; + if (!isFavorite && !isIgnored && !isVerified && cand->last_heard < oldest) { + oldest = cand->last_heard; oldestIndex = i; } // The oldest "boring" node - if (!isFavorite && !isIgnored && meshNodes->at(i).public_key.size == 0 && - meshNodes->at(i).last_heard < oldestBoring) { - oldestBoring = meshNodes->at(i).last_heard; + if (!isFavorite && !isIgnored && cand->public_key.size == 0 && cand->last_heard < oldestBoring) { + oldestBoring = cand->last_heard; oldestBoringIndex = i; } } @@ -2592,10 +2589,9 @@ bool NodeDB::hasValidPosition(const meshtastic_NodeInfoLite *n) UserLicenseStatus NodeDB::getLicenseStatus(uint32_t nodeNum) { meshtastic_NodeInfoLite *info = getMeshNode(nodeNum); - if (!info || !(info->bitfield & NODEINFO_BITFIELD_HAS_USER_MASK)) { + if (!nodeInfoLiteHasUser(info)) return UserLicenseStatus::NotKnown; - } - return (info->bitfield & NODEINFO_BITFIELD_IS_LICENSED_MASK) ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed; + return nodeInfoLiteIsLicensed(info) ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed; } #if !defined(MESHTASTIC_EXCLUDE_PKI) diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 6313e1e86..6e25c97dd 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -484,6 +484,14 @@ inline bool nodeInfoLiteIsUnmessagable(const meshtastic_NodeInfoLite *n) { return n && (n->bitfield & NODEINFO_BITFIELD_IS_UNMESSAGABLE_MASK); } +inline bool nodeInfoLiteIsMuted(const meshtastic_NodeInfoLite *n) +{ + return n && (n->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK); +} +inline bool nodeInfoLiteIsKeyManuallyVerified(const meshtastic_NodeInfoLite *n) +{ + return n && (n->bitfield & NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK); +} inline void nodeInfoLiteSetBit(meshtastic_NodeInfoLite *n, uint32_t mask, bool value) { diff --git a/src/mesh/TypeConversions.cpp b/src/mesh/TypeConversions.cpp index 392de47f7..b7c483e40 100644 --- a/src/mesh/TypeConversions.cpp +++ b/src/mesh/TypeConversions.cpp @@ -13,11 +13,11 @@ meshtastic_NodeInfo TypeConversions::ConvertToNodeInfo(const meshtastic_NodeInfo info.snr = lite->snr; info.last_heard = lite->last_heard; info.channel = lite->channel; - info.via_mqtt = (lite->bitfield & NODEINFO_BITFIELD_VIA_MQTT_MASK) != 0; - info.is_favorite = (lite->bitfield & NODEINFO_BITFIELD_IS_FAVORITE_MASK) != 0; - info.is_ignored = (lite->bitfield & NODEINFO_BITFIELD_IS_IGNORED_MASK) != 0; - info.is_key_manually_verified = (lite->bitfield & NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK) != 0; - info.is_muted = (lite->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0; + info.via_mqtt = nodeInfoLiteViaMqtt(lite); + info.is_favorite = nodeInfoLiteIsFavorite(lite); + info.is_ignored = nodeInfoLiteIsIgnored(lite); + info.is_key_manually_verified = nodeInfoLiteIsKeyManuallyVerified(lite); + info.is_muted = nodeInfoLiteIsMuted(lite); if (lite->has_hops_away) { info.has_hops_away = true; @@ -38,7 +38,7 @@ meshtastic_NodeInfo TypeConversions::ConvertToNodeInfo(const meshtastic_NodeInfo info.position.location_source = position->location_source; info.position.time = position->time; } - if (lite->bitfield & NODEINFO_BITFIELD_HAS_USER_MASK) { + if (nodeInfoLiteHasUser(lite)) { info.has_user = true; info.user = ConvertToUser(lite); } @@ -128,11 +128,11 @@ meshtastic_User TypeConversions::ConvertToUser(const meshtastic_NodeInfoLite *li sanitizeUtf8(user.short_name, sizeof(user.short_name)); user.hw_model = lite->hw_model; user.role = lite->role; - user.is_licensed = (lite->bitfield & NODEINFO_BITFIELD_IS_LICENSED_MASK) != 0; + user.is_licensed = nodeInfoLiteIsLicensed(lite); memcpy(user.public_key.bytes, lite->public_key.bytes, sizeof(user.public_key.bytes)); user.public_key.size = lite->public_key.size; - user.has_is_unmessagable = (lite->bitfield & NODEINFO_BITFIELD_HAS_IS_UNMESSAGABLE_MASK) != 0; - user.is_unmessagable = (lite->bitfield & NODEINFO_BITFIELD_IS_UNMESSAGABLE_MASK) != 0; + user.has_is_unmessagable = nodeInfoLiteHasIsUnmessagable(lite); + user.is_unmessagable = nodeInfoLiteIsUnmessagable(lite); // macaddr is gone from the slim header; zero-fill for old clients that read it. memset(user.macaddr, 0, sizeof(user.macaddr)); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 31cf377ee..1c379e1c5 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -436,7 +436,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta LOG_INFO("Client received toggle_muted_node command"); meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->toggle_muted_node); if (node != NULL) { - node->bitfield ^= (1 << NODEINFO_BITFIELD_IS_MUTED_SHIFT); + nodeInfoLiteSetBit(node, NODEINFO_BITFIELD_IS_MUTED_MASK, !nodeInfoLiteIsMuted(node)); saveChanges(SEGMENT_NODEDATABASE, false); } break; diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 16ccdd744..1a0b69930 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -372,7 +372,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP // If we receive a direct message and the receipent is us, apply DM mute setting // Else we just handle it as not muted. const bool isDmToUs = !isBroadcast(mp.to) && isToUs(&mp); - bool is_muted = isDmToUs ? (sender && ((sender->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0)) + bool is_muted = isDmToUs ? nodeInfoLiteIsMuted(sender) : (ch.settings.has_module_settings && ch.settings.module_settings.is_muted); const bool buzzerModeIsDirectOnly =