From 4a3d28f06b46bc4cb51d08d8c38f850f92ca10eb Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 17 Oct 2025 00:36:26 -0500 Subject: [PATCH] Add FUNCTION_START and FUNCTION_END to public NodeDB functions --- src/mesh/NodeDB.cpp | 124 +++++++++++++++++++++++++++++++------------- src/mesh/NodeDB.h | 100 ++++++++++++++++++++++++++++++----- 2 files changed, 174 insertions(+), 50 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index d2dcad802..af71da733 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -424,7 +424,7 @@ NodeDB::NodeDB() config.has_position = true; info->has_position = true; info->position = TypeConversions::ConvertToPositionLite(fixedGPS); - nodeDB->setLocalPosition(fixedGPS); + nodeDB->_setLocalPosition(fixedGPS); config.position.fixed_position = true; #endif } @@ -479,6 +479,7 @@ void NodeDB::_resetRadioConfig(bool is_fresh_install) bool NodeDB::factoryReset(bool eraseBleBonds) { + FUNCTION_START("factoryReset"); LOG_INFO("Perform factory reset!"); // first, remove the "/prefs" (this removes most prefs) spiLock->lock(); @@ -512,6 +513,7 @@ bool NodeDB::factoryReset(bool eraseBleBonds) Bluefruit.Central.clearBonds(); #endif } + FUNCTION_END; return true; } @@ -979,6 +981,7 @@ void NodeDB::installDefaultChannels() void NodeDB::resetNodes() { + FUNCTION_START("resetNodes"); if (!config.position.fixed_position) clearLocalPosition(); numMeshNodes = 1; @@ -989,10 +992,12 @@ void NodeDB::resetNodes() saveDeviceStateToDisk(); if (neighborInfoModule && moduleConfig.neighbor_info.enabled) neighborInfoModule->resetNeighbors(); + FUNCTION_END; } void NodeDB::removeNodeByNum(NodeNum nodeNum) { + FUNCTION_START("removeNodeByNum"); int newPos = 0, removed = 0; for (int i = 0; i < numMeshNodes; i++) { if (meshNodes->at(i).num != nodeNum) @@ -1005,6 +1010,7 @@ void NodeDB::removeNodeByNum(NodeNum nodeNum) meshtastic_NodeInfoLite()); LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Save changes", removed); saveNodeDatabaseToDisk(); + FUNCTION_END; } void NodeDB::_clearLocalPosition() @@ -1014,7 +1020,7 @@ void NodeDB::_clearLocalPosition() node->position.longitude_i = 0; node->position.altitude = 0; node->position.time = 0; - setLocalPosition(meshtastic_Position_init_default); + _setLocalPosition(meshtastic_Position_init_default); } void NodeDB::cleanupMeshDB() @@ -1429,10 +1435,12 @@ bool NodeDB::_saveToDisk(int saveWhat) const meshtastic_NodeInfoLite *NodeDB::readNextMeshNode(uint32_t &readIndex) { + FUNCTION_START("readNextMeshNode"); + meshtastic_NodeInfoLite *retVal = nullptr; if (readIndex < numMeshNodes) - return &meshNodes->at(readIndex++); - else - return NULL; + retVal = &meshNodes->at(readIndex++); + FUNCTION_END; + return retVal; } /// Given a node, return how many seconds in the past (vs now) that we last heard from it @@ -1482,8 +1490,10 @@ size_t NodeDB::_getNumOnlineMeshNodes(bool localOnly) */ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSource src) { + FUNCTION_START("updatePosition"); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId); if (!info) { + FUNCTION_END; return; } @@ -1492,7 +1502,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou LOG_INFO("updatePosition LOCAL pos@%x time=%u lat=%d lon=%d alt=%d", p.timestamp, p.time, p.latitude_i, p.longitude_i, p.altitude); - setLocalPosition(p); + _setLocalPosition(p); info->position = TypeConversions::ConvertToPositionLite(p); } else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) { // FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO @@ -1520,6 +1530,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou info->has_position = true; updateGUIforNode = info; _notifyObservers(true); // Force an update whether or not our node counts have changed + FUNCTION_END; } /** Update telemetry info for this node based on received metrics @@ -1527,9 +1538,11 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou */ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxSource src) { + FUNCTION_START("updatePosition"); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId); // Environment metrics should never go to NodeDb but we'll safegaurd anyway if (!info || t.which_variant != meshtastic_Telemetry_device_metrics_tag) { + FUNCTION_END; return; } @@ -1543,6 +1556,7 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS info->has_device_metrics = true; updateGUIforNode = info; _notifyObservers(true); // Force an update whether or not our node counts have changed + FUNCTION_END; } /** @@ -1550,8 +1564,10 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS */ void NodeDB::addFromContact(meshtastic_SharedContact contact) { + FUNCTION_START("addFromContact"); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(contact.node_num); if (!info || !contact.has_user) { + FUNCTION_END; return; } // If the local node has this node marked as manually verified @@ -1560,6 +1576,7 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact) 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) { + FUNCTION_END; return; } } @@ -1587,14 +1604,18 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact) _notifyObservers(true); // Force an update whether or not our node counts have changed } saveNodeDatabaseToDisk(); + FUNCTION_END; } /** Update user info and channel for this node based on received user data */ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelIndex) { + FUNCTION_START("updateUser"); + meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId); if (!info) { + FUNCTION_END; return false; } @@ -1616,6 +1637,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde sprintf(cn->message, warning, p.long_name); service->sendClientNotification(cn); } + FUNCTION_END; return false; } } @@ -1623,6 +1645,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde // if the key doesn't match, don't update nodeDB at all. if (p.public_key.size != 32 || (memcmp(p.public_key.bytes, info->user.public_key.bytes, 32) != 0)) { LOG_WARN("Public Key mismatch, dropping NodeInfo"); + FUNCTION_END; return false; } LOG_INFO("Public Key set for node, not updating!"); @@ -1662,7 +1685,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde LOG_DEBUG("Defer NodeDB saveToDisk for now"); } } - + FUNCTION_END; return changed; } @@ -1670,63 +1693,68 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde /// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) { + FUNCTION_START("updateFrom"); if (mp.from == getNodeNum()) { LOG_DEBUG("Ignore update from self"); - return; - } - if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) { + } else if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) { LOG_DEBUG("Update DB node 0x%x, rx_time=%u", mp.from, mp.rx_time); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getFrom(&mp)); - if (!info) { - return; + if (info) { + if (mp.rx_time) // if the packet has a valid timestamp use it to update our last_heard + info->last_heard = mp.rx_time; + + if (mp.rx_snr) + info->snr = mp.rx_snr; // keep the most recent SNR we received for this node. + + info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT + + // If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway + if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) { + info->has_hops_away = true; + info->hops_away = mp.hop_start - mp.hop_limit; + } + sortMeshDB(); } - - if (mp.rx_time) // if the packet has a valid timestamp use it to update our last_heard - info->last_heard = mp.rx_time; - - if (mp.rx_snr) - info->snr = mp.rx_snr; // keep the most recent SNR we received for this node. - - info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT - - // If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway - if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) { - info->has_hops_away = true; - info->hops_away = mp.hop_start - mp.hop_limit; - } - sortMeshDB(); } + FUNCTION_END; } void NodeDB::set_favorite(bool is_favorite, uint32_t nodeId) { + FUNCTION_START("set_favorite"); meshtastic_NodeInfoLite *lite = _getMeshNode(nodeId); if (lite && lite->is_favorite != is_favorite) { lite->is_favorite = is_favorite; sortMeshDB(); saveNodeDatabaseToDisk(); } + FUNCTION_END; } +// returns true if nodeId is_favorite; false if not or not found bool NodeDB::isFavorite(uint32_t nodeId) { - // returns true if nodeId is_favorite; false if not or not found - + FUNCTION_START("set_favorite"); // NODENUM_BROADCAST will never be in the DB - if (nodeId == NODENUM_BROADCAST) + if (nodeId == NODENUM_BROADCAST) { + FUNCTION_END; return false; + } meshtastic_NodeInfoLite *lite = _getMeshNode(nodeId); if (lite) { + FUNCTION_END; return lite->is_favorite; } + FUNCTION_END; return false; } bool NodeDB::isFromOrToFavoritedNode(const meshtastic_MeshPacket &p) { + FUNCTION_START("isFromOrToFavoritedNode"); // This method is logically equivalent to: // return isFavorite(p.from) || isFavorite(p.to); // but is more efficient by: @@ -1745,32 +1773,41 @@ bool NodeDB::isFromOrToFavoritedNode(const meshtastic_MeshPacket &p) lite = &meshNodes->at(i); if (!seenFrom && lite->num == p.from) { - if (lite->is_favorite) + if (lite->is_favorite) { + FUNCTION_END; return true; + } seenFrom = true; } if (!seenTo && lite->num == p.to) { - if (lite->is_favorite) + if (lite->is_favorite) { + FUNCTION_END; return true; + } seenTo = true; } - if (seenFrom && seenTo) + if (seenFrom && seenTo) { + FUNCTION_END; return false; // we've seen both, and neither is a favorite, so we can stop searching early + } // Note: if we knew that sortMeshDB was always called after any change to is_favorite, we could exit early after searching // all favorited nodes first. } - + FUNCTION_END; return false; } void NodeDB::pause_sort(bool paused) { + // Including the mutex macro for completeness, but it's possible it isn't appropriate here + FUNCTION_START("pause_sort"); sortingIsPaused = paused; + FUNCTION_END; } void NodeDB::sortMeshDB() @@ -1805,10 +1842,13 @@ void NodeDB::sortMeshDB() uint8_t NodeDB::getMeshNodeChannel(NodeNum n) { + FUNCTION_START("getMeshNodeChannel"); const meshtastic_NodeInfoLite *info = _getMeshNode(n); if (!info) { + FUNCTION_END; return 0; // defaults to PRIMARY } + FUNCTION_END; return info->channel; } @@ -1894,18 +1934,25 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) /// valid lat/lon bool NodeDB::hasValidPosition(const meshtastic_NodeInfoLite *n) { - return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0); + FUNCTION_START("hasValidPosition"); + auto retVal = n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0); + FUNCTION_END; + return retVal; } /// If we have a node / user and they report is_licensed = true /// we consider them licensed UserLicenseStatus NodeDB::getLicenseStatus(uint32_t nodeNum) { + FUNCTION_START("getLicenseStatus"); meshtastic_NodeInfoLite *info = _getMeshNode(nodeNum); if (!info || !info->has_user) { + FUNCTION_END; return UserLicenseStatus::NotKnown; } - return info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed; + auto retVal = info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed; + FUNCTION_END; + return retVal; } bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest) @@ -1925,6 +1972,7 @@ bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_pub bool NodeDB::backupPreferences(meshtastic_AdminMessage_BackupLocation location) { + FUNCTION_START("backupPreferences"); bool success = false; lastBackupAttempt = millis(); #ifdef FSCom @@ -1958,11 +2006,13 @@ bool NodeDB::backupPreferences(meshtastic_AdminMessage_BackupLocation location) // TODO: After more mainline SD card support } #endif + FUNCTION_END; return success; } bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location, int restoreWhat) { + FUNCTION_START("backupPreferences"); bool success = false; #ifdef FSCom if (location == meshtastic_AdminMessage_BackupLocation_FLASH) { @@ -1970,6 +2020,7 @@ bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location, if (!FSCom.exists(backupFileName)) { spiLock->unlock(); LOG_WARN("Could not restore. No backup file found"); + FUNCTION_END; return false; } else { spiLock->unlock(); @@ -2007,6 +2058,7 @@ bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location, } else if (location == meshtastic_AdminMessage_BackupLocation_SD) { // TODO: After more mainline SD card support } + FUNCTION_END; return success; #endif } diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 229f6b14e..3c41b7db8 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -18,6 +18,13 @@ #include "PortduinoGlue.h" #endif +#define FUNCTION_START(FUNCTION_NAME) \ + if (fakeMutex) \ + LOG_ERROR("Concurrency violation in " FUNCTION_NAME); \ + fakeMutex = true; + +#define FUNCTION_END fakeMutex = false; + #if !defined(MESHTASTIC_EXCLUDE_PKI) // E3B0C442 is the blank hash static const uint8_t LOW_ENTROPY_HASHES[][32] = { @@ -139,7 +146,10 @@ class NodeDB bool saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS | SEGMENT_NODEDATABASE) { - return _saveToDisk(saveWhat); + FUNCTION_START("saveToDisk"); + auto retVal = _saveToDisk(saveWhat); + FUNCTION_END; + return retVal; } /** Reinit radio config if needed, because either: @@ -148,7 +158,12 @@ class NodeDB * * @param is_fresh_install set to true after a fresh install, to trigger NodeInfo/Position requests */ - void resetRadioConfig(bool is_fresh_install = false) { _resetRadioConfig(is_fresh_install); } + void resetRadioConfig(bool is_fresh_install = false) + { + FUNCTION_START("resetRadioConfig"); + _resetRadioConfig(is_fresh_install); + FUNCTION_END; + } /// given a subpacket sniffed from the network, update our DB state /// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw @@ -195,7 +210,13 @@ class NodeDB std::string getNodeId() const; // @return last byte of a NodeNum, 0xFF if it ended at 0x00 - uint8_t getLastByteOfNodeNum(NodeNum num) { return (uint8_t)((num & 0xFF) ? (num & 0xFF) : 0xFF); } + uint8_t getLastByteOfNodeNum(NodeNum num) + { + FUNCTION_START("getLastByteOfNodeNum"); + auto retVal = (uint8_t)((num & 0xFF) ? (num & 0xFF) : 0xFF); + FUNCTION_END; + return retVal; + } /// if returns false, that means our node should send a DenyNodeNum response. If true, we think the number is okay for use // bool handleWantNodeNum(NodeNum n); @@ -214,33 +235,77 @@ class NodeDB /* Return the number of nodes we've heard from recently (within the last 2 hrs?) * @param localOnly if true, ignore nodes heard via MQTT */ - size_t getNumOnlineMeshNodes(bool localOnly = false) { return _getNumOnlineMeshNodes(localOnly); } + size_t getNumOnlineMeshNodes(bool localOnly = false) + { + FUNCTION_START("getNumOnlineMeshNodes"); + auto retVal = _getNumOnlineMeshNodes(localOnly); + FUNCTION_END; + return retVal; + } void resetNodes(), removeNodeByNum(NodeNum nodeNum); bool factoryReset(bool eraseBleBonds = false); - void installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) { _installRoleDefaults(role); } + void installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) + { + FUNCTION_START("installRoleDefaults"); + _installRoleDefaults(role); + FUNCTION_END; + } const meshtastic_NodeInfoLite *readNextMeshNode(uint32_t &readIndex); meshtastic_NodeInfoLite *getMeshNodeByIndex(size_t x) { - assert(x < numMeshNodes); - return &meshNodes->at(x); + FUNCTION_START("getMeshNodeByIndex"); + meshtastic_NodeInfoLite *retValue = nullptr; + if (x < numMeshNodes) + retValue = &meshNodes->at(x); + FUNCTION_END; + return retValue; } - meshtastic_NodeInfoLite *getMeshNode(NodeNum n) { return getMeshNode(n); } - size_t getNumMeshNodes() { return numMeshNodes; } + meshtastic_NodeInfoLite *getMeshNode(NodeNum n) + { + FUNCTION_START("getMeshNode"); + auto retVal = _getMeshNode(n); + FUNCTION_END; + return retVal; + } + + size_t getNumMeshNodes() + { + FUNCTION_START("getNumMeshNodes"); + auto retVal = numMeshNodes; + FUNCTION_END; + return retVal; + } UserLicenseStatus getLicenseStatus(uint32_t nodeNum); // returns true if the maximum number of nodes is reached or we are running low on memory - bool isFull() { return _isFull(); } + bool isFull() + { + FUNCTION_START("isFull"); + auto retVal = _isFull(); + FUNCTION_END; + return retVal; + } - void clearLocalPosition() { _clearLocalPosition(); } + void clearLocalPosition() + { + FUNCTION_START("clearLocalPosition"); + _clearLocalPosition(); + FUNCTION_END; + } - void setLocalPosition(meshtastic_Position position, bool timeOnly = false) { _setLocalPosition(position, timeOnly); } + void setLocalPosition(meshtastic_Position position, bool timeOnly = false) + { + FUNCTION_START("setLocalPosition"); + _setLocalPosition(position, timeOnly); + FUNCTION_END; + } bool hasValidPosition(const meshtastic_NodeInfoLite *n); @@ -248,14 +313,21 @@ class NodeDB bool restorePreferences(meshtastic_AdminMessage_BackupLocation location, int restoreWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS); - void notifyObservers(bool forceUpdate = false) { _notifyObservers(forceUpdate); } + void notifyObservers(bool forceUpdate = false) + { + FUNCTION_START("notifyObservers"); + _notifyObservers(forceUpdate); + FUNCTION_END; + } private: + bool fakeMutex = false; + /// Notify observers of changes to the DB void _notifyObservers(bool forceUpdate = false) { // Notify observers of the current node state - const meshtastic::NodeStatus status = meshtastic::NodeStatus(_getNumOnlineMeshNodes(), getNumMeshNodes(), forceUpdate); + const meshtastic::NodeStatus status = meshtastic::NodeStatus(_getNumOnlineMeshNodes(), numMeshNodes, forceUpdate); newStatus.notifyObservers(&status); }