mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-19 09:51:30 +10:00
2.8: NodeDB shrink, decoupling, and restructuring (#10413)
* 2.8: NodeDB refactor to decouple satellite entries and decrease size * Regen * Refactor node mute handling to use dedicated functions for clarity and consistency * Develop ref * Fix NodeDB review follow-ups Agent-Logs-Url: https://github.com/meshtastic/firmware/sessions/6b1d6cf6-ed6b-43b6-95cb-8e141757664e Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Address review validation nits Agent-Logs-Url: https://github.com/meshtastic/firmware/sessions/6b1d6cf6-ed6b-43b6-95cb-8e141757664e Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Trunk * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Extract legacy NodeDatabase migration * Fix remaining NodeDB review issues Agent-Logs-Url: https://github.com/meshtastic/firmware/sessions/c76b9a5a-7244-4fbc-9ef0-98091d8caaea Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Fixes * Trunk * Fix latest review compile follow-ups Agent-Logs-Url: https://github.com/meshtastic/firmware/sessions/5198da01-ec4c-4c16-8a09-68b8e6d5d410 Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Fix cppcheck style warnings Agent-Logs-Url: https://github.com/meshtastic/firmware/sessions/e60287ba-4ece-46e0-83d8-a6d89664c0bb Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Change pointer type for mesh node in set_favorite function * Change pointer types for mesh node references to const in multiple applets * Add NodeDB layout v25 documentation and migration guidelines * Remove tests for uninitialized PacketHistory state due to undefined behavior * Fix code block formatting in copilot instructions --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
thebentern
Copilot Autofix powered by AI
copilot-swe-agent[bot]
parent
1bcabb893b
commit
94bb21ecc7
+15
-14
@@ -107,14 +107,14 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
|
||||
// Automatically favorite the node that is using the admin key
|
||||
auto remoteNode = nodeDB->getMeshNode(mp.from);
|
||||
if (remoteNode && !remoteNode->is_favorite) {
|
||||
if (remoteNode && !nodeInfoLiteIsFavorite(remoteNode)) {
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_CLIENT_BASE) {
|
||||
// Special case for CLIENT_BASE: is_favorite has special meaning, and we don't want to automatically set it
|
||||
// without the user doing so deliberately.
|
||||
LOG_INFO("PKC admin valid, but not auto-favoriting node %x because role==CLIENT_BASE", mp.from);
|
||||
} else {
|
||||
LOG_INFO("PKC admin valid. Auto-favoriting node %x", mp.from);
|
||||
remoteNode->is_favorite = true;
|
||||
nodeInfoLiteSetBit(remoteNode, NODEINFO_BITFIELD_IS_FAVORITE_MASK, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -393,7 +393,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
LOG_INFO("Client received set_favorite_node command");
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->set_favorite_node);
|
||||
if (node != NULL) {
|
||||
node->is_favorite = true;
|
||||
nodeInfoLiteSetBit(node, NODEINFO_BITFIELD_IS_FAVORITE_MASK, true);
|
||||
saveChanges(SEGMENT_NODEDATABASE, false);
|
||||
if (screen)
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE); // <-- Rebuild screens
|
||||
@@ -404,7 +404,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
LOG_INFO("Client received remove_favorite_node command");
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->remove_favorite_node);
|
||||
if (node != NULL) {
|
||||
node->is_favorite = false;
|
||||
nodeInfoLiteSetBit(node, NODEINFO_BITFIELD_IS_FAVORITE_MASK, false);
|
||||
saveChanges(SEGMENT_NODEDATABASE, false);
|
||||
if (screen)
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE); // <-- Rebuild screens
|
||||
@@ -415,11 +415,10 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
LOG_INFO("Client received set_ignored_node command");
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->set_ignored_node);
|
||||
if (node != NULL) {
|
||||
node->is_ignored = true;
|
||||
node->has_device_metrics = false;
|
||||
node->has_position = false;
|
||||
node->user.public_key.size = 0;
|
||||
memset(node->user.public_key.bytes, 0, sizeof(node->user.public_key.bytes));
|
||||
nodeInfoLiteSetBit(node, NODEINFO_BITFIELD_IS_IGNORED_MASK, true);
|
||||
nodeDB->eraseNodeSatellites(node->num);
|
||||
node->public_key.size = 0;
|
||||
memset(node->public_key.bytes, 0, sizeof(node->public_key.bytes));
|
||||
saveChanges(SEGMENT_NODEDATABASE, false);
|
||||
}
|
||||
break;
|
||||
@@ -428,7 +427,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
LOG_INFO("Client received remove_ignored_node command");
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->remove_ignored_node);
|
||||
if (node != NULL) {
|
||||
node->is_ignored = false;
|
||||
nodeInfoLiteSetBit(node, NODEINFO_BITFIELD_IS_IGNORED_MASK, false);
|
||||
saveChanges(SEGMENT_NODEDATABASE, false);
|
||||
}
|
||||
break;
|
||||
@@ -437,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;
|
||||
@@ -445,9 +444,11 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
|
||||
case meshtastic_AdminMessage_set_fixed_position_tag: {
|
||||
LOG_INFO("Client received set_fixed_position command");
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
node->has_position = true;
|
||||
node->position = TypeConversions::ConvertToPositionLite(r->set_fixed_position);
|
||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
// Route the fixed position through updatePosition so it lands in the
|
||||
// satellite map (or, on builds with PositionDB excluded, just sets
|
||||
// localPosition for the local broadcast path).
|
||||
nodeDB->updatePosition(node->num, r->set_fixed_position, RX_SRC_LOCAL);
|
||||
nodeDB->setLocalPosition(r->set_fixed_position);
|
||||
config.position.fixed_position = true;
|
||||
saveChanges(SEGMENT_NODEDATABASE | SEGMENT_CONFIG, false);
|
||||
|
||||
@@ -141,7 +141,7 @@ void CannedMessageModule::LaunchFreetextWithDestination(NodeNum newDest, uint8_t
|
||||
static bool returnToCannedList = false;
|
||||
bool hasKeyForNode(const meshtastic_NodeInfoLite *node)
|
||||
{
|
||||
return node && node->has_user && node->user.public_key.size > 0;
|
||||
return nodeInfoLiteHasUser(node) && node->public_key.size > 0;
|
||||
}
|
||||
/**
|
||||
* @brief Items in array this->messages will be set to be pointing on the right
|
||||
@@ -262,10 +262,10 @@ void CannedMessageModule::updateDestinationSelectionList()
|
||||
|
||||
for (size_t i = 0; i < numMeshNodes; ++i) {
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
||||
if (!node || node->num == myNodeNum || !node->has_user || node->user.public_key.size != 32)
|
||||
if (!node || node->num == myNodeNum || !nodeInfoLiteHasUser(node) || node->public_key.size != 32)
|
||||
continue;
|
||||
|
||||
const String &nodeName = node->user.long_name;
|
||||
const String &nodeName = node->long_name;
|
||||
|
||||
if (searchQuery.length() == 0) {
|
||||
this->filteredNodes.push_back({node, sinceLastSeen(node)});
|
||||
@@ -1054,7 +1054,7 @@ void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const cha
|
||||
}
|
||||
|
||||
NodeNum myNodeNum = nodeDB->getNodeNum();
|
||||
if (node && node->num != myNodeNum && node->has_user && node->user.public_key.size == 32) {
|
||||
if (node && node->num != myNodeNum && nodeInfoLiteHasUser(node) && node->public_key.size == 32) {
|
||||
p->pki_encrypted = true;
|
||||
p->channel = 0; // force PKI
|
||||
}
|
||||
@@ -1415,8 +1415,8 @@ const char *CannedMessageModule::getNodeName(NodeNum node)
|
||||
return "Broadcast";
|
||||
|
||||
meshtastic_NodeInfoLite *info = nodeDB->getMeshNode(node);
|
||||
if (info && info->has_user && strlen(info->user.long_name) > 0) {
|
||||
return info->user.long_name;
|
||||
if (nodeInfoLiteHasUser(info) && strlen(info->long_name) > 0) {
|
||||
return info->long_name;
|
||||
}
|
||||
|
||||
static char fallback[12];
|
||||
@@ -1723,17 +1723,17 @@ void CannedMessageModule::drawDestinationSelectionScreen(OLEDDisplay *display, O
|
||||
meshtastic_NodeInfoLite *node = this->filteredNodes[nodeIndex].node;
|
||||
if (node) {
|
||||
if (display->getWidth() <= 64) {
|
||||
entryText = node->user.short_name;
|
||||
} else if (node->user.long_name[0]) {
|
||||
entryText = node->user.long_name;
|
||||
entryText = node->short_name;
|
||||
} else if (node->long_name[0]) {
|
||||
entryText = node->long_name;
|
||||
} else {
|
||||
entryText = node->user.short_name;
|
||||
entryText = node->short_name;
|
||||
}
|
||||
}
|
||||
|
||||
int availWidth = display->getWidth() -
|
||||
((graphics::currentResolution == graphics::ScreenResolution::High) ? 40 : 20) -
|
||||
((node && node->is_favorite) ? 10 : 0);
|
||||
((nodeInfoLiteIsFavorite(node)) ? 10 : 0);
|
||||
if (availWidth < 0)
|
||||
availWidth = 0;
|
||||
char truncatedEntry[96];
|
||||
@@ -1742,7 +1742,7 @@ void CannedMessageModule::drawDestinationSelectionScreen(OLEDDisplay *display, O
|
||||
entryText = truncatedEntry;
|
||||
|
||||
// Prepend "* " if this is a favorite
|
||||
if (node && node->is_favorite) {
|
||||
if (nodeInfoLiteIsFavorite(node)) {
|
||||
entryText = "* " + entryText;
|
||||
}
|
||||
graphics::UIRenderer::truncateStringWithEmotes(display, entryText.c_str(), truncatedEntry, sizeof(truncatedEntry),
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -10,6 +10,18 @@
|
||||
|
||||
KeyVerificationModule *keyVerificationModule;
|
||||
|
||||
namespace
|
||||
{
|
||||
void copyNodeLongNameOrUnknown(char *dest, size_t destSize, const meshtastic_NodeInfoLite *node)
|
||||
{
|
||||
if (!dest || destSize == 0)
|
||||
return;
|
||||
const char *name = (node && nodeInfoLiteHasUser(node) && node->long_name[0]) ? node->long_name : "Unknown";
|
||||
strncpy(dest, name, destSize - 1);
|
||||
dest[destSize - 1] = '\0';
|
||||
}
|
||||
} // namespace
|
||||
|
||||
KeyVerificationModule::KeyVerificationModule()
|
||||
: ProtobufModule("KeyVerification", meshtastic_PortNum_KEY_VERIFICATION_APP, &meshtastic_KeyVerification_msg)
|
||||
{
|
||||
@@ -37,7 +49,8 @@ AdminMessageHandleResult KeyVerificationModule::handleAdminMessageForModule(cons
|
||||
} else if (request->key_verification.message_type == meshtastic_KeyVerificationAdmin_MessageType_DO_VERIFY &&
|
||||
request->key_verification.nonce == currentNonce) {
|
||||
auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode);
|
||||
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
|
||||
if (remoteNodePtr)
|
||||
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
|
||||
resetToIdle();
|
||||
} else if (request->key_verification.message_type == meshtastic_KeyVerificationAdmin_MessageType_DO_NOT_VERIFY) {
|
||||
resetToIdle();
|
||||
@@ -72,9 +85,9 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
||||
sprintf(cn->message, "Enter Security Number for Key Verification");
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_number_request_tag;
|
||||
cn->payload_variant.key_verification_number_request.nonce = currentNonce;
|
||||
strncpy(cn->payload_variant.key_verification_number_request.remote_longname, // should really check for nulls, etc
|
||||
nodeDB->getMeshNode(currentRemoteNode)->user.long_name,
|
||||
sizeof(cn->payload_variant.key_verification_number_request.remote_longname));
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_number_request.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_number_request.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
service->sendClientNotification(cn);
|
||||
LOG_INFO("Received hash2");
|
||||
currentState = KEY_VERIFICATION_SENDER_AWAITING_NUMBER;
|
||||
@@ -95,7 +108,8 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
||||
[=](int selected) {
|
||||
if (selected == 1) {
|
||||
auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode);
|
||||
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
|
||||
if (remoteNodePtr)
|
||||
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
|
||||
}
|
||||
};
|
||||
screen->showOverlayBanner(options);)
|
||||
@@ -104,9 +118,9 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
||||
sprintf(cn->message, "Final confirmation for incoming manual key verification %s", message);
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_final_tag;
|
||||
cn->payload_variant.key_verification_final.nonce = currentNonce;
|
||||
strncpy(cn->payload_variant.key_verification_final.remote_longname, // should really check for nulls, etc
|
||||
nodeDB->getMeshNode(currentRemoteNode)->user.long_name,
|
||||
sizeof(cn->payload_variant.key_verification_final.remote_longname));
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_final.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_final.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
cn->payload_variant.key_verification_final.isSender = false;
|
||||
service->sendClientNotification(cn);
|
||||
|
||||
@@ -202,9 +216,9 @@ meshtastic_MeshPacket *KeyVerificationModule::allocReply()
|
||||
currentSecurityNumber % 1000);
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_number_inform_tag;
|
||||
cn->payload_variant.key_verification_number_inform.nonce = currentNonce;
|
||||
strncpy(cn->payload_variant.key_verification_number_inform.remote_longname, // should really check for nulls, etc
|
||||
nodeDB->getMeshNode(currentRemoteNode)->user.long_name,
|
||||
sizeof(cn->payload_variant.key_verification_number_inform.remote_longname));
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_number_inform.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_number_inform.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
cn->payload_variant.key_verification_number_inform.security_number = currentSecurityNumber;
|
||||
service->sendClientNotification(cn);
|
||||
LOG_WARN("Security Number %04u, nonce %llu", currentSecurityNumber, currentNonce);
|
||||
@@ -219,7 +233,7 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber)
|
||||
LOG_WARN("received security number: %u", incomingNumber);
|
||||
meshtastic_NodeInfoLite *remoteNodePtr = nullptr;
|
||||
remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode);
|
||||
if (remoteNodePtr == nullptr || !remoteNodePtr->has_user || remoteNodePtr->user.public_key.size != 32) {
|
||||
if (!remoteNodePtr || !nodeInfoLiteHasUser(remoteNodePtr) || remoteNodePtr->public_key.size != 32) {
|
||||
currentState = KEY_VERIFICATION_IDLE;
|
||||
return; // should we throw an error here?
|
||||
}
|
||||
@@ -232,7 +246,7 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber)
|
||||
hash.update(¤tRemoteNode, sizeof(currentRemoteNode));
|
||||
hash.update(owner.public_key.bytes, owner.public_key.size);
|
||||
|
||||
hash.update(remoteNodePtr->user.public_key.bytes, remoteNodePtr->user.public_key.size);
|
||||
hash.update(remoteNodePtr->public_key.bytes, remoteNodePtr->public_key.size);
|
||||
hash.finalize(hash1, 32);
|
||||
|
||||
hash.reset();
|
||||
@@ -265,9 +279,9 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber)
|
||||
sprintf(cn->message, "Final confirmation for outgoing manual key verification %s", message);
|
||||
cn->which_payload_variant = meshtastic_ClientNotification_key_verification_final_tag;
|
||||
cn->payload_variant.key_verification_final.nonce = currentNonce;
|
||||
strncpy(cn->payload_variant.key_verification_final.remote_longname, // should really check for nulls, etc
|
||||
nodeDB->getMeshNode(currentRemoteNode)->user.long_name,
|
||||
sizeof(cn->payload_variant.key_verification_final.remote_longname));
|
||||
copyNodeLongNameOrUnknown(cn->payload_variant.key_verification_final.remote_longname,
|
||||
sizeof(cn->payload_variant.key_verification_final.remote_longname),
|
||||
nodeDB->getMeshNode(currentRemoteNode));
|
||||
cn->payload_variant.key_verification_final.isSender = true;
|
||||
service->sendClientNotification(cn);
|
||||
LOG_INFO(message);
|
||||
@@ -310,4 +324,4 @@ void KeyVerificationModule::generateVerificationCode(char *readableCode)
|
||||
readableCode[i] = (hash1[i] >> 2) + 48; // not a standardized base64, but workable and avoids having a dictionary.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -183,8 +183,7 @@ meshtastic_MeshPacket *PositionModule::allocPositionPacket()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
meshtastic_NodeInfoLite *node = service->refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
assert(node->has_position);
|
||||
const meshtastic_NodeInfoLite *node = service->refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
|
||||
// configuration of POSITION packet
|
||||
// consider making this a function argument?
|
||||
@@ -194,7 +193,9 @@ meshtastic_MeshPacket *PositionModule::allocPositionPacket()
|
||||
meshtastic_Position p = meshtastic_Position_init_default; // Start with an empty structure
|
||||
// if localPosition is totally empty, put our last saved position (lite) in there
|
||||
if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0) {
|
||||
nodeDB->setLocalPosition(TypeConversions::ConvertToPosition(node->position));
|
||||
meshtastic_PositionLite cachedSelf;
|
||||
if (nodeDB->copyNodePosition(node->num, cachedSelf))
|
||||
nodeDB->setLocalPosition(TypeConversions::ConvertToPosition(cachedSelf));
|
||||
}
|
||||
localPosition.seq_number++;
|
||||
|
||||
@@ -420,7 +421,7 @@ int32_t PositionModule::runOnce()
|
||||
doDeepSleep(nightyNightMs, false, false);
|
||||
}
|
||||
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
if (node == nullptr)
|
||||
return RUNONCE_INTERVAL;
|
||||
|
||||
@@ -445,8 +446,11 @@ int32_t PositionModule::runOnce()
|
||||
} else if (nodeDB->hasValidPosition(node)) {
|
||||
lastGpsSend = now;
|
||||
|
||||
lastGpsLatitude = node->position.latitude_i;
|
||||
lastGpsLongitude = node->position.longitude_i;
|
||||
meshtastic_PositionLite selfPos;
|
||||
if (nodeDB->copyNodePosition(node->num, selfPos)) {
|
||||
lastGpsLatitude = selfPos.latitude_i;
|
||||
lastGpsLongitude = selfPos.longitude_i;
|
||||
}
|
||||
|
||||
if (transmitHistory)
|
||||
transmitHistory->setLastSentToMesh(meshtastic_PortNum_POSITION_APP);
|
||||
@@ -461,7 +465,10 @@ int32_t PositionModule::runOnce()
|
||||
if (nodeDB->hasValidPosition(node2)) {
|
||||
// The minimum time (in seconds) that would pass before we are able to send a new position packet.
|
||||
|
||||
auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
|
||||
meshtastic_PositionLite selfPos;
|
||||
if (!nodeDB->copyNodePosition(node->num, selfPos))
|
||||
return RUNONCE_INTERVAL; // Defensive: hasValidPosition should imply this is non-null
|
||||
auto smartPosition = getDistanceTraveledSinceLastSend(selfPos);
|
||||
msSinceLastSend = now - lastGpsSend;
|
||||
|
||||
if (smartPosition.hasTraveledOverThreshold &&
|
||||
@@ -479,8 +486,8 @@ int32_t PositionModule::runOnce()
|
||||
msSinceLastSend, minimumTimeThreshold);
|
||||
|
||||
// Set the current coords as our last ones, after we've compared distance with current and decided to send
|
||||
lastGpsLatitude = node->position.latitude_i;
|
||||
lastGpsLongitude = node->position.longitude_i;
|
||||
lastGpsLatitude = selfPos.latitude_i;
|
||||
lastGpsLongitude = selfPos.longitude_i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -563,11 +570,14 @@ struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic
|
||||
|
||||
void PositionModule::handleNewPosition()
|
||||
{
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
const meshtastic_NodeInfoLite *node2 = service->refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
// We limit our GPS broadcasts to a max rate
|
||||
if (nodeDB->hasValidPosition(node2)) {
|
||||
auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
|
||||
meshtastic_PositionLite selfPos;
|
||||
if (!nodeDB->copyNodePosition(node->num, selfPos))
|
||||
return;
|
||||
auto smartPosition = getDistanceTraveledSinceLastSend(selfPos);
|
||||
uint32_t msSinceLastSend = millis() - lastGpsSend;
|
||||
if (smartPosition.hasTraveledOverThreshold &&
|
||||
Throttle::execute(
|
||||
@@ -583,8 +593,8 @@ void PositionModule::handleNewPosition()
|
||||
minimumTimeThreshold);
|
||||
|
||||
// Set the current coords as our last ones, after we've compared distance with current and decided to send
|
||||
lastGpsLatitude = node->position.latitude_i;
|
||||
lastGpsLongitude = node->position.longitude_i;
|
||||
lastGpsLatitude = selfPos.latitude_i;
|
||||
lastGpsLongitude = selfPos.longitude_i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,26 +268,36 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
|
||||
fileToAppend.printf("??:??:??,"); // Time
|
||||
}
|
||||
|
||||
fileToAppend.printf("%d,", getFrom(&mp)); // From
|
||||
fileToAppend.printf("%s,", n->user.long_name); // Long Name
|
||||
fileToAppend.printf("%f,", n->position.latitude_i * 1e-7); // Sender Lat
|
||||
fileToAppend.printf("%f,", n->position.longitude_i * 1e-7); // Sender Long
|
||||
fileToAppend.printf("%d,", getFrom(&mp)); // From
|
||||
fileToAppend.printf("%s,", n ? n->long_name : ""); // Long Name
|
||||
meshtastic_PositionLite senderPos;
|
||||
const bool haveSenderPos = nodeDB->copyNodePosition(getFrom(&mp), senderPos);
|
||||
if (haveSenderPos) {
|
||||
fileToAppend.printf("%f,", senderPos.latitude_i * 1e-7); // Sender Lat
|
||||
fileToAppend.printf("%f,", senderPos.longitude_i * 1e-7); // Sender Long
|
||||
} else {
|
||||
fileToAppend.printf("0.0,0.0,");
|
||||
}
|
||||
if (gpsStatus->getIsConnected() || config.position.fixed_position) {
|
||||
fileToAppend.printf("%f,", gpsStatus->getLatitude() * 1e-7); // RX Lat
|
||||
fileToAppend.printf("%f,", gpsStatus->getLongitude() * 1e-7); // RX Long
|
||||
fileToAppend.printf("%d,", gpsStatus->getAltitude()); // RX Altitude
|
||||
} else {
|
||||
// When the phone API is in use, the node info will be updated with position
|
||||
meshtastic_NodeInfoLite *us = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
fileToAppend.printf("%f,", us->position.latitude_i * 1e-7); // RX Lat
|
||||
fileToAppend.printf("%f,", us->position.longitude_i * 1e-7); // RX Long
|
||||
fileToAppend.printf("%d,", us->position.altitude); // RX Altitude
|
||||
meshtastic_PositionLite usPos;
|
||||
if (nodeDB->copyNodePosition(nodeDB->getNodeNum(), usPos)) {
|
||||
fileToAppend.printf("%f,", usPos.latitude_i * 1e-7); // RX Lat
|
||||
fileToAppend.printf("%f,", usPos.longitude_i * 1e-7); // RX Long
|
||||
fileToAppend.printf("%d,", usPos.altitude); // RX Altitude
|
||||
} else {
|
||||
fileToAppend.printf("0.0,0.0,0,");
|
||||
}
|
||||
}
|
||||
|
||||
fileToAppend.printf("%f,", mp.rx_snr); // RX SNR
|
||||
|
||||
if (n->position.latitude_i && n->position.longitude_i && gpsStatus->getLatitude() && gpsStatus->getLongitude()) {
|
||||
float distance = GeoCoord::latLongToMeter(n->position.latitude_i * 1e-7, n->position.longitude_i * 1e-7,
|
||||
if (haveSenderPos && senderPos.latitude_i && senderPos.longitude_i && gpsStatus->getLatitude() && gpsStatus->getLongitude()) {
|
||||
float distance = GeoCoord::latLongToMeter(senderPos.latitude_i * 1e-7, senderPos.longitude_i * 1e-7,
|
||||
gpsStatus->getLatitude() * 1e-7, gpsStatus->getLongitude() * 1e-7);
|
||||
fileToAppend.printf("%f,", distance); // Distance in meters
|
||||
} else {
|
||||
@@ -340,4 +350,4 @@ bool RangeTestModuleRadio::removeFile()
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@ bool RoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mesh
|
||||
config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY)) {
|
||||
if (!maybePKI)
|
||||
return false;
|
||||
if ((nodeDB->getMeshNode(mp.from) == NULL || !nodeDB->getMeshNode(mp.from)->has_user) &&
|
||||
(nodeDB->getMeshNode(mp.to) == NULL || !nodeDB->getMeshNode(mp.to)->has_user))
|
||||
if (!nodeInfoLiteHasUser(nodeDB->getMeshNode(mp.from)) && !nodeInfoLiteHasUser(nodeDB->getMeshNode(mp.to)))
|
||||
return false;
|
||||
} else if (owner.is_licensed && ((nodeDB->getLicenseStatus(mp.from) == UserLicenseStatus::NotLicensed) ||
|
||||
(nodeDB->getLicenseStatus(mp.to) == UserLicenseStatus::NotLicensed))) {
|
||||
|
||||
@@ -250,9 +250,12 @@ int32_t SerialModule::runOnce()
|
||||
uint32_t readIndex = 0;
|
||||
const meshtastic_NodeInfoLite *tempNodeInfo = nodeDB->readNextMeshNode(readIndex);
|
||||
while (tempNodeInfo != NULL) {
|
||||
if (tempNodeInfo->has_user && nodeDB->hasValidPosition(tempNodeInfo)) {
|
||||
printWPL(outbuf, sizeof(outbuf), tempNodeInfo->position, tempNodeInfo->user.long_name, true);
|
||||
serialPrint->printf("%s", outbuf);
|
||||
if (nodeInfoLiteHasUser(tempNodeInfo) && nodeDB->hasValidPosition(tempNodeInfo)) {
|
||||
meshtastic_PositionLite pos;
|
||||
if (nodeDB->copyNodePosition(tempNodeInfo->num, pos)) {
|
||||
printWPL(outbuf, sizeof(outbuf), pos, tempNodeInfo->long_name, true);
|
||||
serialPrint->printf("%s", outbuf);
|
||||
}
|
||||
}
|
||||
tempNodeInfo = nodeDB->readNextMeshNode(readIndex);
|
||||
}
|
||||
@@ -401,7 +404,7 @@ ProcessMessage SerialModuleRadio::handleReceived(const meshtastic_MeshPacket &mp
|
||||
serialPrint->write(p.payload.bytes, p.payload.size);
|
||||
} else if (moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG) {
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
|
||||
const char *sender = (node && node->has_user) ? node->user.short_name : "???";
|
||||
const char *sender = nodeInfoLiteHasUser(node) ? node->short_name : "???";
|
||||
serialPrint->println();
|
||||
serialPrint->printf("%s: %s", sender, p.payload.bytes);
|
||||
serialPrint->println();
|
||||
@@ -417,9 +420,13 @@ ProcessMessage SerialModuleRadio::handleReceived(const meshtastic_MeshPacket &mp
|
||||
decoded = &scratch;
|
||||
}
|
||||
// send position packet as WPL to the serial port
|
||||
printWPL(outbuf, sizeof(outbuf), *decoded, nodeDB->getMeshNode(getFrom(&mp))->user.long_name,
|
||||
moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO);
|
||||
serialPrint->printf("%s", outbuf);
|
||||
{
|
||||
meshtastic_NodeInfoLite *senderNode = nodeDB->getMeshNode(getFrom(&mp));
|
||||
const char *senderName = senderNode ? senderNode->long_name : "";
|
||||
printWPL(outbuf, sizeof(outbuf), *decoded, senderName,
|
||||
moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO);
|
||||
serialPrint->printf("%s", outbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -714,4 +721,4 @@ void SerialModule::processWXSerial()
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "StatusMessageModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "ProtobufModule.h"
|
||||
|
||||
StatusMessageModule *statusMessageModule;
|
||||
@@ -36,16 +37,8 @@ ProcessMessage StatusMessageModule::handleReceived(const meshtastic_MeshPacket &
|
||||
|
||||
LOG_INFO("Received a NodeStatus message %s", incomingMessage.status);
|
||||
|
||||
RecentStatus entry;
|
||||
entry.fromNodeId = mp.from;
|
||||
entry.statusText = incomingMessage.status;
|
||||
|
||||
recentReceived.push_back(std::move(entry));
|
||||
|
||||
// Keep only last MAX_RECENT_STATUSMESSAGES
|
||||
if (recentReceived.size() > MAX_RECENT_STATUSMESSAGES) {
|
||||
recentReceived.erase(recentReceived.begin()); // drop oldest
|
||||
}
|
||||
if (nodeDB)
|
||||
nodeDB->setNodeStatus(mp.from, incomingMessage);
|
||||
}
|
||||
}
|
||||
return ProcessMessage::CONTINUE;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||
#include "SinglePortModule.h"
|
||||
#include "configuration.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class StatusMessageModule : public SinglePortModule, private concurrency::OSThread
|
||||
{
|
||||
@@ -20,29 +18,16 @@ class StatusMessageModule : public SinglePortModule, private concurrency::OSThre
|
||||
this->setInterval(1000 * 12 * 60 * 60);
|
||||
}
|
||||
// TODO: If we have a string, set the initial delay (15 minutes maybe)
|
||||
|
||||
// Keep vector from reallocating as we fill up to MAX_RECENT_STATUSMESSAGES
|
||||
recentReceived.reserve(MAX_RECENT_STATUSMESSAGES);
|
||||
}
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
struct RecentStatus {
|
||||
uint32_t fromNodeId; // mp.from
|
||||
std::string statusText; // incomingMessage.status
|
||||
};
|
||||
|
||||
const std::vector<RecentStatus> &getRecentReceived() const { return recentReceived; }
|
||||
|
||||
protected:
|
||||
/** Called to handle a particular incoming message
|
||||
/** Called to handle a particular incoming message. The cached most-recent
|
||||
* status for each node lives on NodeDB; use nodeDB->copyNodeStatus(num, ...).
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_RECENT_STATUSMESSAGES = 5;
|
||||
std::vector<RecentStatus> recentReceived;
|
||||
};
|
||||
|
||||
extern StatusMessageModule *statusMessageModule;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -515,6 +515,10 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
|
||||
packetPool.release(lastMeasurementPacket);
|
||||
|
||||
lastMeasurementPacket = packetPool.allocCopy(mp);
|
||||
|
||||
// Cache the latest env metrics per node on NodeDB so the phone can
|
||||
// pull last-known values across reboots and replays.
|
||||
nodeDB->updateTelemetry(getFrom(&mp), *t, RX_SRC_RADIO);
|
||||
}
|
||||
|
||||
return false; // Let others look at this message also if they want
|
||||
|
||||
@@ -492,12 +492,12 @@ TraceRouteModule::TraceRouteModule()
|
||||
const char *TraceRouteModule::getNodeName(NodeNum node)
|
||||
{
|
||||
meshtastic_NodeInfoLite *info = nodeDB->getMeshNode(node);
|
||||
if (info && info->has_user) {
|
||||
if (strlen(info->user.short_name) > 0) {
|
||||
return info->user.short_name;
|
||||
if (nodeInfoLiteHasUser(info)) {
|
||||
if (strlen(info->short_name) > 0) {
|
||||
return info->short_name;
|
||||
}
|
||||
if (strlen(info->user.long_name) > 0) {
|
||||
return info->user.long_name;
|
||||
if (strlen(info->long_name) > 0) {
|
||||
return info->long_name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1226,9 +1226,9 @@ bool TrafficManagementModule::shouldRespondToNodeInfo(const meshtastic_MeshPacke
|
||||
// Fallback only when PSRAM cache is unavailable on this target.
|
||||
// In this mode we use the node-wide table maintained by NodeInfoModule.
|
||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(p->to);
|
||||
if (!node || !node->has_user)
|
||||
if (!nodeInfoLiteHasUser(node))
|
||||
return false;
|
||||
cachedUser = TypeConversions::ConvertToUser(node->num, node->user);
|
||||
cachedUser = TypeConversions::ConvertToUser(node);
|
||||
}
|
||||
|
||||
if (!sendResponse)
|
||||
|
||||
@@ -100,7 +100,7 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
char distStr[20] = "";
|
||||
|
||||
// Get our node, to use our own position
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
const meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
|
||||
// Match compass sizing/placement to favorite node screen logic.
|
||||
const int w = display->getWidth();
|
||||
@@ -147,8 +147,10 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
const char *statusLine2 = nullptr;
|
||||
|
||||
// Distance only needs our own position fix; compass/bearing additionally needs heading.
|
||||
if (hasOwnPositionFix) {
|
||||
const meshtastic_PositionLite &op = ourNode->position;
|
||||
meshtastic_PositionLite ownPos;
|
||||
const bool haveOwnPos = ourNode && nodeDB->copyNodePosition(ourNode->num, ownPos);
|
||||
if (hasOwnPositionFix && haveOwnPos) {
|
||||
const meshtastic_PositionLite &op = ownPos;
|
||||
const float d =
|
||||
GeoCoord::latLongToMeter(DegD(wp.latitude_i), DegD(wp.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user