feat(core): implement batched node info handling for mesh handshake

This commit optimizes the mesh handshake protocol by introducing explicit support for `NodeInfoBatch` messages. It updates the configuration flow to handle both primary batched node delivery and legacy single-node delivery for backwards compatibility with older firmware.

Key changes include:

- **Batch Processing Optimization:**
    - Added `handleNodeInfoBatch` to the `MeshConfigFlowManager` interface to allow bulk processing of node information, reducing per-item overhead during the initial handshake.
    - Updated `MeshConfigFlowManagerImpl` to accumulate batched nodes efficiently using `addAll`.
    - Refactored `FromRadioPacketHandlerImpl` to delegate batch processing directly to the manager instead of iterating through individual items.

- **Handshake Protocol Updates:**
    - Updated `HandshakeConstants` to distinguish between `BATCH_NODE_INFO_NONCE` (primary Stage 2) and `NODE_INFO_NONCE` (legacy Stage 2).
    - Modified `handleConfigComplete` logic to trigger Stage 2 completion for both batched and legacy nonces.
    - Ensured `MeshConnectionManager` prioritizes the batch nonce when requesting node information.

- **Testing & Simulation:**
    - Created `MeshConfigFlowManagerImplTest` to validate node accumulation, batch handling, and handshake nonce routing.
    - Improved `MockInterface` to better simulate real-world packet ordering by delaying live traffic until after the handshake completion coroutine has processed the node database.
    - Added verification tests to ensure the connection manager uses the correct batching nonces.

Specific changes:
- Added `handleNodeInfoBatch` implementation to `MeshConfigFlowManagerImpl`.
- Updated documentation in `HandshakeConstants` regarding two-stage mesh handshake protocol.
- Refactored `MockInterface.sendStage2NodeInfoResponse` to handle packet encoding and simulation delays.
- Added unit tests covering edge cases for empty and mixed node info batches.
This commit is contained in:
James Rich 2026-04-03 10:36:16 -05:00
parent b708b2ff76
commit a74d5d470a
8 changed files with 271 additions and 30 deletions

View file

@ -18,9 +18,9 @@ package org.meshtastic.core.repository
/**
* Shared constants for the two-stage mesh handshake protocol.
*
* Stage 1 (`CONFIG_NONCE`): requests device config, module config, and channels. Stage 2 (`BATCH_NODE_INFO_NONCE`):
* requests the full node database with batched NodeInfo delivery.
* - Stage 1 ([CONFIG_NONCE]): requests device config, module config, and channels.
* - Stage 2 ([BATCH_NODE_INFO_NONCE], primary): requests the full node database with batched [NodeInfoBatch] delivery.
* - Stage 2 ([NODE_INFO_NONCE], legacy): requests node info one-at-a-time; kept for firmware that pre-dates batching.
*
* Both [MeshConfigFlowManager] (consumer) and [MeshConnectionManager] (sender) reference these.
*/
@ -31,6 +31,8 @@ object HandshakeConstants {
/** Nonce sent in `want_config_id` to request node info only — unbatched legacy (Stage 2). */
const val NODE_INFO_NONCE = 69421
/** Nonce sent in `want_config_id` to request node info only — batched (Stage 2). */
// 69422 intentionally skipped — reserved for future use.
/** Nonce sent in `want_config_id` to request node info only — batched (Stage 2, primary). */
const val BATCH_NODE_INFO_NONCE = 69423
}

View file

@ -36,6 +36,16 @@ interface MeshConfigFlowManager {
/** Handles received node information. */
fun handleNodeInfo(info: NodeInfo)
/**
* Handles a batch of node information records delivered in a single [NodeInfoBatch] message.
*
* The default implementation simply delegates to [handleNodeInfo] for each item. Implementations should override
* this with a bulk `addAll` to avoid per-item overhead on large meshes.
*/
fun handleNodeInfoBatch(items: List<NodeInfo>) {
items.forEach { handleNodeInfo(it) }
}
/**
* Handles a [FileInfo] packet received during STATE_SEND_FILEMANIFEST.
*