WIP: checkpoint geocaching before main integration

This commit is contained in:
Trail Mate Dev committed 2026-09-24 08:47:53 +08:00
1 parent d7a2f35328
commit 3d65ece83d
244 files changed
+25291 -126

No files matched your search

@@ -18,6 +18,8 @@ namespace chat::lxmf
constexpr uint32_t kFieldTelemetry = 0x02;
constexpr uint32_t kFieldTelemetryStream = 0x03;
constexpr uint32_t kFieldCommands = 0x09;
constexpr uint32_t kFieldCustomType = 0xFB;
constexpr uint32_t kFieldCustomData = 0xFC;
struct DecodedField
{
@@ -37,6 +39,13 @@ struct ByteSpanList
size_t size = 0;
};
enum class CustomDataResult : uint8_t
{
NotCustom,
Invalid,
Valid,
};
using BinItemCallback = bool (*)(const uint8_t* data,
size_t len,
void* context);
@@ -202,6 +211,11 @@ bool encodeTextPayload(double timestamp,
uint8_t* out_payload,
size_t* inout_len);
// Standard custom fields: type is MessagePack str; data is MessagePack bin.
bool encodeCustomDataPayload(double timestamp, const char* title, const char* content,
const char* custom_type, ByteSpan custom_data,
uint8_t* out_payload, size_t* inout_len);
bool encodeAppDataPayload(uint32_t portnum,
uint32_t packet_id,
uint32_t request_id,
@@ -390,6 +404,9 @@ bool encodeSidebandTelemetryLocationPayload(
uint8_t* out_payload,
size_t* inout_len);
const DecodedField* findField(const DecodedTextPayload& payload, uint32_t key);
// Output borrows payload.fields storage; reject duplicate and wrong-type fields.
CustomDataResult extractCustomData(const DecodedTextPayload& payload,
ByteSpan* out_type, ByteSpan* out_data);
bool decodeSidebandTelemetryLocation(const DecodedTextPayload& payload,
SidebandTelemetryLocation* out_location);
bool decodeSidebandTelemetryRequest(const DecodedTextPayload& payload,
@@ -11,6 +11,15 @@ class MeshAdapterRouterCore : public IMeshAdapter
{
public:
bool installBackend(MeshProtocol protocol, std::unique_ptr<IMeshAdapter> backend);
// Installs a background service without changing the selected chat protocol.
// Refuses to replace any existing backend; its lifetime may have borrowers.
bool installServiceBackend(MeshProtocol protocol, std::unique_ptr<IMeshAdapter> backend);
std::unique_ptr<IMeshAdapter> takeServiceBackend(MeshProtocol protocol, const IMeshAdapter* expected = nullptr);
std::unique_ptr<IMeshAdapter> takeInactiveBackend(MeshProtocol protocol, const IMeshAdapter* expected = nullptr);
// Advances an inactive service only. The caller must configure its carrier
// so it cannot contend with the active backend for a shared radio.
bool processServiceQueue(MeshProtocol protocol);
bool isServiceBackend(MeshProtocol protocol) const;
void setActiveProtocol(MeshProtocol protocol);
bool hasBackend() const;
MeshProtocol backendProtocol() const;
@@ -74,6 +83,8 @@ class MeshAdapterRouterCore : public IMeshAdapter
std::unique_ptr<IMeshAdapter> meshcore_backend_;
std::unique_ptr<IMeshAdapter> reticulum_backend_;
MeshProtocol active_protocol_ = MeshProtocol::Meshtastic;
// Only explicitly installed service backends may run while inactive.
uint8_t service_backend_mask_ = 0;
};
} // namespace chat
@@ -0,0 +1,52 @@
#pragma once
#include "chat/domain/chat_types.h"
#include "chat/infra/lxmf/lxmf_wire.h"
#include <cstring>
#include <array>
namespace chat
{
namespace lxmf
{
// These views borrow transport-owned memory for the callback duration only.
struct CustomDeliveryView
{
ByteSpan source;
ByteSpan destination;
ByteSpan message_hash;
ByteSpan data;
};
// True means durable acceptance; volatile queueing alone must return false.
using CustomDeliveryHandler = bool (*)(const CustomDeliveryView&, void*);
struct GeocachingAnnouncementView
{
ByteSpan discovery_destination;
ByteSpan delivery_destination;
ByteSpan public_key;
ByteSpan app_data;
};
using GeocachingAnnouncementHandler = void (*)(const GeocachingAnnouncementView&, void*);
}
// Optional application transport capability; unrelated adapters need not
// implement it. The owning router controls lifetime and serializes access.
class IGeocachingTransport
{
public:
virtual ~IGeocachingTransport() = default;
virtual bool getGeocachingAuthorKey(uint8_t out[64])
{ if (out) std::memset(out, 0, 64); return false; }
virtual bool signGeocachingRecord(lxmf::ByteSpan, uint8_t*, size_t, uint8_t*, size_t, size_t& written)
{ written = 0; return false; }
// Input bytes are borrowed for this call only; deferred transport work must
// own its encoded payload and must not retain the caller's pointer.
virtual MeshSendResult sendGeocachingData(const uint8_t destination_hash[16],
lxmf::ByteSpan data, bool response = false,
std::array<uint8_t, 32>* accepted_lxmf_hash = nullptr) = 0;
virtual void setGeocachingAnnouncementHandler(
void (*handler)(const lxmf::GeocachingAnnouncementView&, void*), void* context) = 0;
virtual void setGeocachingDeliveryHandler(
bool (*handler)(const lxmf::CustomDeliveryView&, void*), void* context) = 0;
};
} // namespace chat
@@ -11,6 +11,7 @@
namespace chat
{
class IIncomingDeliveryCommitPort;
class IGeocachingTransport;
namespace meshcore
{
@@ -63,6 +64,7 @@ struct ReticulumLocalIdentityInfo
class IMeshAdapter
{
public:
virtual IGeocachingTransport* geocachingTransport() { return nullptr; }
virtual ~IMeshAdapter() = default;
/**