mirror of
https://github.com/vicliu624/trail-mate.git
synced 2026-08-28 05:24:08 +00:00
refactor(protocol): route meshtastic node actions through runtime
This commit is contained in:
@@ -11,6 +11,19 @@ set(TRAIL_MATE_REPO_ROOT
|
||||
include("${TRAIL_MATE_REPO_ROOT}/cmake/TrailMateUxPacks.cmake")
|
||||
trailmate_add_ui_lvgl_ux_packs(trailmate_ui_lvgl_ux_packs)
|
||||
|
||||
set(TRAIL_MATE_MESHTASTIC_GENERATED_SOURCES
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/admin.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/channel.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/config.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/connection_status.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/device_ui.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/localonly.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/mesh.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/module_config.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/portnums.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/telemetry.pb.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated/meshtastic/xmodem.pb.cpp")
|
||||
|
||||
add_library(trailmate_linux_sim_shell
|
||||
src/linux_sim_app_shell.cpp
|
||||
src/linux_sim_runtime_entry.cpp
|
||||
@@ -120,7 +133,10 @@ if(BUILD_TESTING)
|
||||
COMMAND trailmate_mesh_adapter_router_core_smoke)
|
||||
|
||||
add_executable(trailmate_protocol_effect_executor_smoke
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/tests/test_protocol_effect_executor.cpp")
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/tests/test_protocol_effect_executor.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/third_party/nanopb/pb_common.c"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/third_party/nanopb/pb_encode.c"
|
||||
${TRAIL_MATE_MESHTASTIC_GENERATED_SOURCES})
|
||||
target_include_directories(trailmate_protocol_effect_executor_smoke
|
||||
PRIVATE
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/include"
|
||||
@@ -131,6 +147,22 @@ if(BUILD_TESTING)
|
||||
add_test(NAME trailmate_protocol_effect_executor_smoke
|
||||
COMMAND trailmate_protocol_effect_executor_smoke)
|
||||
|
||||
add_executable(trailmate_meshtastic_runtime_smoke
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/tests/test_meshtastic_runtime.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/third_party/nanopb/pb_common.c"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/third_party/nanopb/pb_decode.c"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/third_party/nanopb/pb_encode.c"
|
||||
${TRAIL_MATE_MESHTASTIC_GENERATED_SOURCES})
|
||||
target_include_directories(trailmate_meshtastic_runtime_smoke
|
||||
PRIVATE
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/include"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/generated"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_chat/third_party/nanopb")
|
||||
target_compile_features(trailmate_meshtastic_runtime_smoke
|
||||
PRIVATE cxx_std_17)
|
||||
add_test(NAME trailmate_meshtastic_runtime_smoke
|
||||
COMMAND trailmate_meshtastic_runtime_smoke)
|
||||
|
||||
add_executable(trailmate_meshcore_protocol_strategy_smoke
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_mesh/tests/test_meshcore_protocol_strategy.cpp"
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/core_mesh/src/protocol/meshcore/meshcore_protocol_strategy.cpp"
|
||||
|
||||
@@ -17,8 +17,8 @@ Primary root cause:
|
||||
| --- | --- | --- | --- |
|
||||
| Meshtastic NodeInfo peer reannounce | Shared policy in working tree | Medium | ESP32 and nRF now call the same reannounce gate; platform adapters still own the actual queue/send IO. |
|
||||
| Meshtastic broadcast `want_response` | Shared policy in working tree | Medium | ESP32 and nRF now share the app-data destination/ACK/response decision; broadcast air ACK is suppressed while request response intent is preserved. |
|
||||
| Meshtastic request/reply core | Mostly shared | Medium | NodeInfo/Position reply gating, NodeInfo/Position payload construction, TraceRoute reply gating, TraceRoute payload mutation, and TraceRoute/Position action lifecycle tracking are shared; reply radio send still lives in adapters/UI. |
|
||||
| Meshtastic duplicated policy ownership | Mostly shared | Medium | App-data send intent, NodeInfo reannounce gate, NodeInfo/Position reply gates, NodeInfo self-announcement packet construction, Position payload construction, TraceRoute reply gate, TraceRoute payload mutation, TraceRoute/Position result lifecycle, and PKI/NO_CHANNEL resync decisions now live in shared runtime/policy. Radio IO and local data sources still live in adapters. |
|
||||
| Meshtastic request/reply core | Mostly shared | Medium | NodeInfo/Position reply gating, NodeInfo/Position payload construction, TraceRoute/Position outgoing request packet decisions, TraceRoute reply gating, TraceRoute payload mutation, and TraceRoute/Position action lifecycle tracking are shared; radio send still lives in adapters/UI executors. |
|
||||
| Meshtastic duplicated policy ownership | Mostly shared | Medium | App-data send intent, NodeInfo reannounce gate, NodeInfo/Position reply gates, NodeInfo self-announcement packet construction, Position payload construction, TraceRoute/Position outgoing request packet decisions, TraceRoute reply gate, TraceRoute payload mutation, TraceRoute/Position result lifecycle, and PKI/NO_CHANNEL resync decisions now live in shared runtime/policy. Radio IO and local data sources still live in adapters. |
|
||||
| MeshCore NodeInfo query/reply | Shared runtime/effects | Medium | ESP32 and nRF now route `requestNodeInfo()` through `MeshCoreRuntime` and shared control payload codecs; platform adapters still own packet IO/projection. |
|
||||
| MeshCore trace | Shared lifecycle, platform-limited routing | Medium | ESP32 and nRF use native `PAYLOAD_TYPE_TRACE` and shared completion/timeout policy; nRF still uses a minimal one-hop hash route. |
|
||||
| MeshCore app-data ACK/capability | Shared lifecycle | Medium | ESP32 and nRF now declare ACK tracking only when runtime pending/completion handling is wired. ACK frame scheduling remains adapter IO. |
|
||||
@@ -189,9 +189,12 @@ Current state:
|
||||
- Shared `MeshtasticAppActionRuntime` now owns outgoing TraceRoute and Position Exchange
|
||||
lifecycle interpretation: pending, routing delivered where available, routing error,
|
||||
matching app response completed, and timeout.
|
||||
- `MeshtasticRuntime::prepareOutgoing(...)` now maps nRF mono UI `TraceRouteIntent` and
|
||||
`ExchangePositionIntent` into `SendPacketEffect`, so the UI no longer constructs
|
||||
`TRACEROUTE_APP` / `POSITION_APP` packets or protobuf payloads directly.
|
||||
- Mono UI observes `ChatService::IncomingDataObserver` instead of polling the adapter queue
|
||||
directly, so TraceRoute result state does not steal app-data from BLE/other consumers.
|
||||
- Adapter send mechanics still exist on ESP32 and nRF.
|
||||
- Adapter/UI executor send mechanics still exist on ESP32 and nRF.
|
||||
|
||||
Residual risk:
|
||||
|
||||
|
||||
@@ -321,6 +321,18 @@ It does not own:
|
||||
- BLE phone protocol transport;
|
||||
- memory placement or ISR details.
|
||||
|
||||
Current C++17 migration state:
|
||||
|
||||
- Meshtastic TraceRoute and Position Exchange outgoing user actions can now enter
|
||||
`MeshtasticRuntime::prepareOutgoing(...)` as `TraceRouteIntent` / `ExchangePositionIntent`.
|
||||
The runtime chooses Meshtastic portnum, request id fallback, ACK/response flags, and protobuf payload shape,
|
||||
then emits `SendPacketEffect`.
|
||||
- nRF mono UI executes those `SendPacketEffect`s through its platform mesh adapter and keeps UI-only lifecycle
|
||||
projection in `MeshtasticAppActionRuntime`; it no longer constructs `TRACEROUTE_APP` /
|
||||
`POSITION_APP` packets directly.
|
||||
- Platform adapters still own physical radio send, local GPS source selection, BLE projection, queueing, and
|
||||
adapter-side incoming packet execution until those can be represented as runtime effects/state.
|
||||
|
||||
### Meshtastic PKI Resync State
|
||||
|
||||
PKI resync must be a State object, not scattered if branches.
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
#include "chat/runtime/protocol_runtime.h"
|
||||
#include "meshtastic/mesh.pb.h"
|
||||
#include "meshtastic/portnums.pb.h"
|
||||
#include "pb_encode.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace chat::runtime
|
||||
{
|
||||
@@ -86,10 +89,25 @@ class MeshtasticPkiResyncState
|
||||
class MeshtasticRuntime final : public IProtocolRuntime
|
||||
{
|
||||
public:
|
||||
ProtocolEffects prepareOutgoing(const ProtocolIntent&,
|
||||
const RuntimeContext&) override
|
||||
ProtocolEffects prepareOutgoing(const ProtocolIntent& intent,
|
||||
const RuntimeContext& context) override
|
||||
{
|
||||
return ProtocolEffects{};
|
||||
ProtocolEffects effects{};
|
||||
std::visit(
|
||||
[&effects, &context](const auto& item)
|
||||
{
|
||||
using Intent = std::decay_t<decltype(item)>;
|
||||
if constexpr (std::is_same_v<Intent, TraceRouteIntent>)
|
||||
{
|
||||
resolveTraceRoute(item, context, effects);
|
||||
}
|
||||
else if constexpr (std::is_same_v<Intent, ExchangePositionIntent>)
|
||||
{
|
||||
resolveExchangePosition(item, context, effects);
|
||||
}
|
||||
},
|
||||
intent);
|
||||
return effects;
|
||||
}
|
||||
|
||||
ProtocolEffects handleIncoming(const IncomingPacket&,
|
||||
@@ -115,6 +133,113 @@ class MeshtasticRuntime final : public IProtocolRuntime
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kTraceRouteRequestSalt = 0x4D545254UL;
|
||||
static constexpr uint32_t kPositionRequestSalt = 0x4D54504FUL;
|
||||
|
||||
static NodeId normalizePeer(NodeId peer)
|
||||
{
|
||||
return peer == 0xFFFFFFFFUL ? 0 : peer;
|
||||
}
|
||||
|
||||
static MessageId makeRequestId(MessageId requested,
|
||||
NodeId peer,
|
||||
const RuntimeContext& context,
|
||||
uint32_t salt)
|
||||
{
|
||||
if (requested != 0)
|
||||
{
|
||||
return requested;
|
||||
}
|
||||
MessageId id = context.now_ms ^ context.self_node ^ peer ^ salt;
|
||||
return id == 0 ? 1 : id;
|
||||
}
|
||||
|
||||
static EmitActionResultEffect buildFailedAction(ProtocolActionKind action,
|
||||
NodeId peer,
|
||||
MessageId request_id,
|
||||
int32_t detail)
|
||||
{
|
||||
EmitActionResultEffect failed{};
|
||||
failed.protocol = MeshProtocol::Meshtastic;
|
||||
failed.action = action;
|
||||
failed.state = ProtocolActionState::Failed;
|
||||
failed.peer = peer;
|
||||
failed.request_id = request_id;
|
||||
failed.detail = detail;
|
||||
return failed;
|
||||
}
|
||||
|
||||
static void resolveTraceRoute(const TraceRouteIntent& intent,
|
||||
const RuntimeContext& context,
|
||||
ProtocolEffects& effects)
|
||||
{
|
||||
const NodeId peer = normalizePeer(intent.peer);
|
||||
const MessageId request_id = makeRequestId(intent.request_id,
|
||||
peer,
|
||||
context,
|
||||
kTraceRouteRequestSalt);
|
||||
if (peer == 0 || peer == context.self_node)
|
||||
{
|
||||
effects.add(buildFailedAction(ProtocolActionKind::TraceRoute,
|
||||
peer,
|
||||
request_id,
|
||||
-1));
|
||||
return;
|
||||
}
|
||||
|
||||
meshtastic_RouteDiscovery route = meshtastic_RouteDiscovery_init_zero;
|
||||
uint8_t route_buf[96] = {};
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(route_buf, sizeof(route_buf));
|
||||
if (!pb_encode(&stream, meshtastic_RouteDiscovery_fields, &route))
|
||||
{
|
||||
effects.add(buildFailedAction(ProtocolActionKind::TraceRoute,
|
||||
peer,
|
||||
request_id,
|
||||
-2));
|
||||
return;
|
||||
}
|
||||
|
||||
SendPacketEffect packet{};
|
||||
packet.protocol = MeshProtocol::Meshtastic;
|
||||
packet.channel = intent.channel;
|
||||
packet.dest = peer;
|
||||
packet.portnum = meshtastic_PortNum_TRACEROUTE_APP;
|
||||
packet.request_id = request_id;
|
||||
packet.want_ack = true;
|
||||
packet.want_response = true;
|
||||
packet.payload.assign(route_buf, route_buf + stream.bytes_written);
|
||||
effects.add(std::move(packet));
|
||||
}
|
||||
|
||||
static void resolveExchangePosition(const ExchangePositionIntent& intent,
|
||||
const RuntimeContext& context,
|
||||
ProtocolEffects& effects)
|
||||
{
|
||||
const NodeId peer = normalizePeer(intent.peer);
|
||||
const MessageId request_id = makeRequestId(intent.request_id,
|
||||
peer,
|
||||
context,
|
||||
kPositionRequestSalt);
|
||||
if (peer == 0 || peer == context.self_node)
|
||||
{
|
||||
effects.add(buildFailedAction(ProtocolActionKind::ExchangePosition,
|
||||
peer,
|
||||
request_id,
|
||||
-1));
|
||||
return;
|
||||
}
|
||||
|
||||
SendPacketEffect packet{};
|
||||
packet.protocol = MeshProtocol::Meshtastic;
|
||||
packet.channel = intent.channel;
|
||||
packet.dest = peer;
|
||||
packet.portnum = meshtastic_PortNum_POSITION_APP;
|
||||
packet.request_id = request_id;
|
||||
packet.want_ack = false;
|
||||
packet.want_response = true;
|
||||
effects.add(std::move(packet));
|
||||
}
|
||||
|
||||
MeshtasticPkiResyncState pki_resync_{};
|
||||
};
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ struct RequestNodeInfoIntent
|
||||
|
||||
struct TraceRouteIntent
|
||||
{
|
||||
ChannelId channel = ChannelId::PRIMARY;
|
||||
NodeId peer = 0;
|
||||
MessageId request_id = 0;
|
||||
uint32_t auth = 0;
|
||||
@@ -64,7 +65,9 @@ struct TraceRouteIntent
|
||||
|
||||
struct ExchangePositionIntent
|
||||
{
|
||||
ChannelId channel = ChannelId::PRIMARY;
|
||||
NodeId peer = 0;
|
||||
MessageId request_id = 0;
|
||||
};
|
||||
|
||||
struct DiscoverIntent
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "chat/runtime/meshtastic_runtime.h"
|
||||
|
||||
#include "pb_decode.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace
|
||||
@@ -18,14 +20,86 @@ int main()
|
||||
{
|
||||
using chat::ChannelId;
|
||||
using chat::MeshProtocol;
|
||||
using chat::runtime::EmitActionResultEffect;
|
||||
using chat::runtime::ExchangePositionIntent;
|
||||
using chat::runtime::ForgetPeerKeyEffect;
|
||||
using chat::runtime::MeshtasticPkiResyncCause;
|
||||
using chat::runtime::MeshtasticPkiResyncInput;
|
||||
using chat::runtime::MeshtasticRuntime;
|
||||
using chat::runtime::ProtocolActionKind;
|
||||
using chat::runtime::ProtocolActionState;
|
||||
using chat::runtime::RuntimeContext;
|
||||
using chat::runtime::SendNodeInfoEffect;
|
||||
using chat::runtime::SendPacketEffect;
|
||||
using chat::runtime::SendRoutingErrorEffect;
|
||||
using chat::runtime::TraceRouteIntent;
|
||||
|
||||
MeshtasticRuntime runtime;
|
||||
RuntimeContext context{};
|
||||
context.protocol = MeshProtocol::Meshtastic;
|
||||
context.self_node = 0x11111111UL;
|
||||
context.now_ms = 0x20240614UL;
|
||||
|
||||
{
|
||||
TraceRouteIntent intent{};
|
||||
intent.channel = ChannelId::SECONDARY;
|
||||
intent.peer = 0x22222222UL;
|
||||
intent.request_id = 0x01020304UL;
|
||||
intent.timeout_ms = 9000;
|
||||
|
||||
const auto effects = runtime.prepareOutgoing(intent, context);
|
||||
assert(effects.items.size() == 1);
|
||||
const auto* packet = effectAt<SendPacketEffect>(effects, 0);
|
||||
assert(packet);
|
||||
assert(packet->protocol == MeshProtocol::Meshtastic);
|
||||
assert(packet->channel == intent.channel);
|
||||
assert(packet->dest == intent.peer);
|
||||
assert(packet->portnum == meshtastic_PortNum_TRACEROUTE_APP);
|
||||
assert(packet->request_id == intent.request_id);
|
||||
assert(packet->want_ack);
|
||||
assert(packet->want_response);
|
||||
|
||||
meshtastic_RouteDiscovery decoded = meshtastic_RouteDiscovery_init_zero;
|
||||
pb_istream_t stream = pb_istream_from_buffer(packet->payload.data(),
|
||||
packet->payload.size());
|
||||
assert(pb_decode(&stream, meshtastic_RouteDiscovery_fields, &decoded));
|
||||
}
|
||||
|
||||
{
|
||||
ExchangePositionIntent intent{};
|
||||
intent.channel = ChannelId::PRIMARY;
|
||||
intent.peer = 0x33333333UL;
|
||||
intent.request_id = 0x05060708UL;
|
||||
|
||||
const auto effects = runtime.prepareOutgoing(intent, context);
|
||||
assert(effects.items.size() == 1);
|
||||
const auto* packet = effectAt<SendPacketEffect>(effects, 0);
|
||||
assert(packet);
|
||||
assert(packet->protocol == MeshProtocol::Meshtastic);
|
||||
assert(packet->channel == intent.channel);
|
||||
assert(packet->dest == intent.peer);
|
||||
assert(packet->portnum == meshtastic_PortNum_POSITION_APP);
|
||||
assert(packet->request_id == intent.request_id);
|
||||
assert(!packet->want_ack);
|
||||
assert(packet->want_response);
|
||||
assert(packet->payload.empty());
|
||||
}
|
||||
|
||||
{
|
||||
TraceRouteIntent intent{};
|
||||
intent.peer = context.self_node;
|
||||
intent.request_id = 0x0A0B0C0DUL;
|
||||
|
||||
const auto effects = runtime.prepareOutgoing(intent, context);
|
||||
assert(effects.items.size() == 1);
|
||||
const auto* failed = effectAt<EmitActionResultEffect>(effects, 0);
|
||||
assert(failed);
|
||||
assert(failed->protocol == MeshProtocol::Meshtastic);
|
||||
assert(failed->action == ProtocolActionKind::TraceRoute);
|
||||
assert(failed->state == ProtocolActionState::Failed);
|
||||
assert(failed->peer == context.self_node);
|
||||
assert(failed->request_id == intent.request_id);
|
||||
}
|
||||
|
||||
{
|
||||
MeshtasticPkiResyncInput input{};
|
||||
|
||||
@@ -6,12 +6,11 @@
|
||||
#include "chat/infra/meshcore/mc_region_presets.h"
|
||||
#include "chat/infra/meshtastic/mt_protocol_helpers.h"
|
||||
#include "chat/infra/meshtastic/mt_region.h"
|
||||
#include "chat/runtime/meshtastic_runtime.h"
|
||||
#include "chat/runtime/self_identity_policy.h"
|
||||
#include "chat/usecase/chat_service.h"
|
||||
#include "chat/usecase/contact_service.h"
|
||||
#include "generated/meshtastic/mesh.pb.h"
|
||||
#include "generated/meshtastic/portnums.pb.h"
|
||||
#include "pb_encode.h"
|
||||
#include "platform/ui/screen_runtime.h"
|
||||
#include "ui/mono/assets/trailmate_sleep_logo.h"
|
||||
#include "ui/mono/screens/screensaver_layout.h"
|
||||
@@ -176,6 +175,33 @@ uint16_t normalizedMeshtasticChannelNum(uint16_t channel_num)
|
||||
return std::min<uint16_t>(channel_num, kMeshtasticChannelNumMax);
|
||||
}
|
||||
|
||||
const chat::runtime::SendPacketEffect* firstSendPacketEffect(
|
||||
const chat::runtime::ProtocolEffects& effects)
|
||||
{
|
||||
for (const auto& effect : effects.items)
|
||||
{
|
||||
if (const auto* packet = std::get_if<chat::runtime::SendPacketEffect>(&effect))
|
||||
{
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool executeSendPacketEffect(chat::IMeshAdapter& mesh,
|
||||
const chat::runtime::SendPacketEffect& packet)
|
||||
{
|
||||
const uint8_t* payload = packet.payload.empty() ? nullptr : packet.payload.data();
|
||||
return mesh.sendAppData(packet.channel,
|
||||
packet.portnum,
|
||||
payload,
|
||||
packet.payload.size(),
|
||||
packet.dest,
|
||||
packet.want_ack,
|
||||
packet.request_id,
|
||||
packet.want_response);
|
||||
}
|
||||
|
||||
void sanitizeMeshtasticChannelNum(app::AppConfig& cfg)
|
||||
{
|
||||
cfg.meshtastic_config.channel_num = normalizedMeshtasticChannelNum(cfg.meshtastic_config.channel_num);
|
||||
@@ -7388,25 +7414,21 @@ void Runtime::executeNodeAction()
|
||||
showTransientPopup("TRACE ROUTE", "UNAVAILABLE");
|
||||
return;
|
||||
}
|
||||
meshtastic_RouteDiscovery route = meshtastic_RouteDiscovery_init_zero;
|
||||
uint8_t route_buf[96] = {};
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(route_buf, sizeof(route_buf));
|
||||
if (!pb_encode(&stream, meshtastic_RouteDiscovery_fields, &route))
|
||||
{
|
||||
appendBootLog("trace encode err");
|
||||
showTransientPopup("TRACE ROUTE", "ENCODE FAILED");
|
||||
return;
|
||||
}
|
||||
chat::runtime::MeshtasticRuntime protocol_runtime{};
|
||||
chat::runtime::RuntimeContext context{};
|
||||
context.protocol = chat::MeshProtocol::Meshtastic;
|
||||
context.self_node = mesh->getNodeId();
|
||||
context.now_ms = nowMs();
|
||||
|
||||
const chat::MessageId request_id = nextMeshtasticActionRequestId(node->node_id);
|
||||
const bool ok = mesh->sendAppData(chat::ChannelId::PRIMARY,
|
||||
meshtastic_PortNum_TRACEROUTE_APP,
|
||||
route_buf,
|
||||
stream.bytes_written,
|
||||
node->node_id,
|
||||
true,
|
||||
request_id,
|
||||
true);
|
||||
chat::runtime::TraceRouteIntent intent{};
|
||||
intent.channel = chat::ChannelId::PRIMARY;
|
||||
intent.peer = node->node_id;
|
||||
intent.request_id = nextMeshtasticActionRequestId(node->node_id);
|
||||
|
||||
const auto effects = protocol_runtime.prepareOutgoing(intent, context);
|
||||
const auto* packet = firstSendPacketEffect(effects);
|
||||
const chat::MessageId request_id = packet ? packet->request_id : intent.request_id;
|
||||
const bool ok = packet && executeSendPacketEffect(*mesh, *packet);
|
||||
if (ok)
|
||||
{
|
||||
meshtastic_action_runtime_.startTraceRoute(request_id, node->node_id, nowMs());
|
||||
@@ -7458,15 +7480,21 @@ void Runtime::requestNodePositionExchange()
|
||||
return;
|
||||
}
|
||||
|
||||
const chat::MessageId request_id = nextMeshtasticActionRequestId(node->node_id);
|
||||
const bool ok = mesh->sendAppData(chat::ChannelId::PRIMARY,
|
||||
meshtastic_PortNum_POSITION_APP,
|
||||
nullptr,
|
||||
0,
|
||||
node->node_id,
|
||||
false,
|
||||
request_id,
|
||||
true);
|
||||
chat::runtime::MeshtasticRuntime protocol_runtime{};
|
||||
chat::runtime::RuntimeContext context{};
|
||||
context.protocol = chat::MeshProtocol::Meshtastic;
|
||||
context.self_node = mesh->getNodeId();
|
||||
context.now_ms = nowMs();
|
||||
|
||||
chat::runtime::ExchangePositionIntent intent{};
|
||||
intent.channel = chat::ChannelId::PRIMARY;
|
||||
intent.peer = node->node_id;
|
||||
intent.request_id = nextMeshtasticActionRequestId(node->node_id);
|
||||
|
||||
const auto effects = protocol_runtime.prepareOutgoing(intent, context);
|
||||
const auto* packet = firstSendPacketEffect(effects);
|
||||
const chat::MessageId request_id = packet ? packet->request_id : intent.request_id;
|
||||
const bool ok = packet && executeSendPacketEffect(*mesh, *packet);
|
||||
if (ok)
|
||||
{
|
||||
meshtastic_action_runtime_.startPositionExchange(request_id, node->node_id, nowMs());
|
||||
|
||||
Reference in New Issue
Block a user