Skip to content

Commit

Permalink
WIP ATAK plugin message handling
Browse files Browse the repository at this point in the history
  • Loading branch information
thebentern committed Feb 4, 2024
1 parent 7db02ad commit bda6a24
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 22 deletions.
2 changes: 1 addition & 1 deletion protobufs
5 changes: 3 additions & 2 deletions src/mesh/MeshModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ meshtastic_MeshPacket *MeshModule::allocErrorResponse(meshtastic_Routing_Error e
return r;
}

void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src)
void MeshModule::callPlugins(meshtastic_MeshPacket &mp, RxSource src)
{
// LOG_DEBUG("In call modules\n");
bool moduleFound = false;
Expand Down Expand Up @@ -124,9 +124,10 @@ void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src)
} else
printPacket("packet on wrong channel, but can't respond", &mp);
} else {

ProcessMessage handled = pi.handleReceived(mp);

pi.alterReceived(mp);

// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious
// sniffing) also: we only let the one module send a reply, once that happens, remaining modules are not
// considered
Expand Down
27 changes: 10 additions & 17 deletions src/mesh/MeshModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,15 @@ class MeshModule

/** For use only by MeshService
*/
static void callPlugins(const meshtastic_MeshPacket &mp, RxSource src = RX_SRC_RADIO);
static void callPlugins(meshtastic_MeshPacket &mp, RxSource src = RX_SRC_RADIO);

static std::vector<MeshModule *> GetMeshModulesWithUIFrames();
static void observeUIEvents(Observer<const UIFrameEvent *> *observer);
static AdminMessageHandleResult handleAdminMessageForAllPlugins(const meshtastic_MeshPacket &mp,
meshtastic_AdminMessage *request,
meshtastic_AdminMessage *response);
#if HAS_SCREEN
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
return;
}
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
#endif
protected:
const char *name;
Expand Down Expand Up @@ -135,10 +132,12 @@ class MeshModule
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for
it
*/
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp)
{
return ProcessMessage::CONTINUE;
}
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) { return ProcessMessage::CONTINUE; }

/** Called to change a particular incoming message
This allows the module to change the message before it is passed through the rest of the call-chain.
*/
virtual void alterReceived(meshtastic_MeshPacket &mp) {}

/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender.
Expand All @@ -151,14 +150,8 @@ class MeshModule
/***
* @return true if you want to be alloced a UI screen frame
*/
virtual bool wantUIFrame()
{
return false;
}
virtual Observable<const UIFrameEvent *> *getUIFrameObservable()
{
return NULL;
}
virtual bool wantUIFrame() { return false; }
virtual Observable<const UIFrameEvent *> *getUIFrameObservable() { return NULL; }

meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);

Expand Down
26 changes: 26 additions & 0 deletions src/mesh/ProtobufModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ template <class T> class ProtobufModule : protected SinglePortModule
*/
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, T *decoded) = 0;

/** Called to make changes to a particular incoming message
*/
virtual void alterReceivedProtobuf(meshtastic_MeshPacket &mp, T *decoded){};

/**
* Return a mesh packet which has been preinited with a particular protobuf data payload and port number.
* You can then send this packet (after customizing any of the payload fields you might need) with
Expand Down Expand Up @@ -86,4 +90,26 @@ template <class T> class ProtobufModule : protected SinglePortModule

return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE;
}

/** Called to alter a particular incoming message
*/
virtual void alterReceived(meshtastic_MeshPacket &mp) override
{
auto &p = mp.decoded;

T scratch;
T *decoded = NULL;
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.decoded.portnum == ourPortNum) {
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) {
decoded = &scratch;
} else {
LOG_ERROR("Error decoding protobuf module!\n");
// if we can't decode it, nobody can process it!
return;
}
}

return alterReceivedProtobuf(mp, decoded);
}
};
2 changes: 1 addition & 1 deletion src/mesh/generated/meshtastic/config.pb.h
Original file line number Diff line number Diff line change
Expand Up @@ -836,4 +836,4 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
} /* extern "C" */
#endif

#endif
#endif
6 changes: 6 additions & 0 deletions src/mesh/generated/meshtastic/mesh.pb.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ PB_BIND(meshtastic_Neighbor, meshtastic_Neighbor, AUTO)
PB_BIND(meshtastic_DeviceMetadata, meshtastic_DeviceMetadata, AUTO)


PB_BIND(meshtastic_TAK_Packet, meshtastic_TAK_Packet, AUTO)


PB_BIND(meshtastic_TAK_PLI, meshtastic_TAK_PLI, AUTO)





Expand Down
65 changes: 65 additions & 0 deletions src/mesh/generated/meshtastic/mesh.pb.h
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,36 @@ typedef struct _meshtastic_FromRadio {
};
} meshtastic_FromRadio;

/* Position Location Information from ATAK */
typedef struct _meshtastic_TAK_PLI {
/* The new preferred location encoding, multiply by 1e-7 to get degrees
in floating point */
int32_t latitude_i;
/* The new preferred location encoding, multiply by 1e-7 to get degrees
in floating point */
int32_t longitude_i;
/* Altitude */
int32_t altitude;
} meshtastic_TAK_PLI;

/* Packets for the official ATAK Plugin */
typedef struct _meshtastic_TAK_Packet {
pb_size_t which_callsign_variant;
union {
/* Uncompressed callsign from ATAK */
char callsign_uncompressed[64];
/* Compressed callsign using unishox2 for the wire */
char callsign_compressed[64];
} callsign_variant;
pb_size_t which_payload_variant;
union {
/* TAK position report */
meshtastic_TAK_PLI tak_pli;
/* Other binary data */
pb_callback_t data;
} payload_variant;
} meshtastic_TAK_Packet;


#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -869,6 +899,8 @@ extern "C" {
#define meshtastic_DeviceMetadata_hw_model_ENUMTYPE meshtastic_HardwareModel




/* Initializer values for message structs */
#define meshtastic_Position_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
Expand All @@ -888,6 +920,8 @@ extern "C" {
#define meshtastic_NeighborInfo_init_default {0, 0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}}
#define meshtastic_Neighbor_init_default {0, 0, 0, 0}
#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
#define meshtastic_TAK_Packet_init_default {0, {""}, 0, {meshtastic_TAK_PLI_init_default}}
#define meshtastic_TAK_PLI_init_default {0, 0, 0}
#define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
Expand All @@ -906,6 +940,8 @@ extern "C" {
#define meshtastic_NeighborInfo_init_zero {0, 0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}}
#define meshtastic_Neighbor_init_zero {0, 0, 0, 0}
#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
#define meshtastic_TAK_Packet_init_zero {0, {""}, 0, {meshtastic_TAK_PLI_init_zero}}
#define meshtastic_TAK_PLI_init_zero {0, 0, 0}

/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_Position_latitude_i_tag 1
Expand Down Expand Up @@ -1032,6 +1068,13 @@ extern "C" {
#define meshtastic_FromRadio_xmodemPacket_tag 12
#define meshtastic_FromRadio_metadata_tag 13
#define meshtastic_FromRadio_mqttClientProxyMessage_tag 14
#define meshtastic_TAK_PLI_latitude_i_tag 1
#define meshtastic_TAK_PLI_longitude_i_tag 2
#define meshtastic_TAK_PLI_altitude_tag 3
#define meshtastic_TAK_Packet_callsign_uncompressed_tag 1
#define meshtastic_TAK_Packet_callsign_compressed_tag 2
#define meshtastic_TAK_Packet_tak_pli_tag 3
#define meshtastic_TAK_Packet_data_tag 4

/* Struct field encoding specification for nanopb */
#define meshtastic_Position_FIELDLIST(X, a) \
Expand Down Expand Up @@ -1251,6 +1294,22 @@ X(a, STATIC, SINGULAR, BOOL, hasRemoteHardware, 10)
#define meshtastic_DeviceMetadata_CALLBACK NULL
#define meshtastic_DeviceMetadata_DEFAULT NULL

#define meshtastic_TAK_Packet_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, STRING, (callsign_variant,callsign_uncompressed,callsign_variant.callsign_uncompressed), 1) \
X(a, STATIC, ONEOF, STRING, (callsign_variant,callsign_compressed,callsign_variant.callsign_compressed), 2) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,tak_pli,payload_variant.tak_pli), 3) \
X(a, CALLBACK, ONEOF, BYTES, (payload_variant,data,payload_variant.data), 4)
#define meshtastic_TAK_Packet_CALLBACK pb_default_field_callback
#define meshtastic_TAK_Packet_DEFAULT NULL
#define meshtastic_TAK_Packet_payload_variant_tak_pli_MSGTYPE meshtastic_TAK_PLI

#define meshtastic_TAK_PLI_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 1) \
X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 2) \
X(a, STATIC, SINGULAR, INT32, altitude, 3)
#define meshtastic_TAK_PLI_CALLBACK NULL
#define meshtastic_TAK_PLI_DEFAULT NULL

extern const pb_msgdesc_t meshtastic_Position_msg;
extern const pb_msgdesc_t meshtastic_User_msg;
extern const pb_msgdesc_t meshtastic_RouteDiscovery_msg;
Expand All @@ -1269,6 +1328,8 @@ extern const pb_msgdesc_t meshtastic_Compressed_msg;
extern const pb_msgdesc_t meshtastic_NeighborInfo_msg;
extern const pb_msgdesc_t meshtastic_Neighbor_msg;
extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
extern const pb_msgdesc_t meshtastic_TAK_Packet_msg;
extern const pb_msgdesc_t meshtastic_TAK_PLI_msg;

/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_Position_fields &meshtastic_Position_msg
Expand All @@ -1289,8 +1350,11 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
#define meshtastic_NeighborInfo_fields &meshtastic_NeighborInfo_msg
#define meshtastic_Neighbor_fields &meshtastic_Neighbor_msg
#define meshtastic_DeviceMetadata_fields &meshtastic_DeviceMetadata_msg
#define meshtastic_TAK_Packet_fields &meshtastic_TAK_Packet_msg
#define meshtastic_TAK_PLI_fields &meshtastic_TAK_PLI_msg

/* Maximum encoded size of messages (where known) */
/* meshtastic_TAK_Packet_size depends on runtime parameters */
#define meshtastic_Compressed_size 243
#define meshtastic_Data_size 270
#define meshtastic_DeviceMetadata_size 46
Expand All @@ -1306,6 +1370,7 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
#define meshtastic_QueueStatus_size 23
#define meshtastic_RouteDiscovery_size 40
#define meshtastic_Routing_size 42
#define meshtastic_TAK_PLI_size 21
#define meshtastic_ToRadio_size 504
#define meshtastic_User_size 79
#define meshtastic_Waypoint_size 165
Expand Down
3 changes: 3 additions & 0 deletions src/mesh/generated/meshtastic/portnums.pb.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ typedef enum _meshtastic_PortNum {
/* Aggregates edge info for the network by sending out a list of each node's neighbors
ENCODING: Protobuf */
meshtastic_PortNum_NEIGHBORINFO_APP = 71,
/* ATAK Plugin
Portnum for payloads from the official Meshtastic ATAK plugin */
meshtastic_PortNum_ATAK_PLUGIN = 72,
/* Private applications should use portnums >= 256.
To simplify initial development and testing you can use "PRIVATE_APP"
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */
Expand Down
79 changes: 79 additions & 0 deletions src/modules/AtakPluginModule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "AtakPluginModule.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "main.h"

extern "C" {
#include "mesh/compression/unishox2.h"
}

AtakPluginModule *atakPluginModule;

AtakPluginModule::AtakPluginModule()
: ProtobufModule("atak", meshtastic_PortNum_ATAK_PLUGIN, &meshtastic_TAK_Packet_msg),
concurrency::OSThread("AtakPluginModule")
{
ourPortNum = meshtastic_PortNum_ATAK_PLUGIN;
}

/*
Encompasses the full construction and sending packet to mesh
Will be used for broadcast.
*/
int32_t AtakPluginModule::runOnce()
{
return default_broadcast_interval_secs;
}

bool AtakPluginModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_TAK_Packet *r)
{
return false;
}

void AtakPluginModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_TAK_Packet *t)
{
// Not PLI, ignore it
if (t->which_payload_variant != meshtastic_TAK_Packet_tak_pli_tag)
return;

// From Phone (EUD)
if (mp.from == 0) {
LOG_DEBUG("Received uncompressed TAK payload from phone with %d bytes\n", mp.decoded.payload.size);
// Compress for LoRA transport
meshtastic_TAK_Packet compressed = meshtastic_TAK_Packet_init_default;
compressed.which_callsign_variant = meshtastic_TAK_Packet_callsign_compressed_tag;
compressed.which_payload_variant = meshtastic_TAK_Packet_tak_pli_tag;
compressed.payload_variant.tak_pli = t->payload_variant.tak_pli;
auto length =
unishox2_compress_simple(t->callsign_variant.callsign_uncompressed, sizeof(t->callsign_variant.callsign_uncompressed),
compressed.callsign_variant.callsign_compressed);
LOG_DEBUG("Unompressed callsign %d bytes\n", strlen(t->callsign_variant.callsign_uncompressed));
LOG_DEBUG("Compressed callsign %d bytes\n", length);
mp.decoded.payload.size = pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes),
meshtastic_TAK_Packet_fields, &compressed);
LOG_DEBUG("Final payload size of %d bytes\n", mp.decoded.payload.size);
} else {
if (t->which_callsign_variant != meshtastic_TAK_Packet_callsign_compressed_tag) {
// Not compressed. Something
LOG_ERROR("Received uncompressed TAK_Packet atak plugin msg!\n");
return;
}
// From another node on the mesh
// Decompress for Phone (EUD)
auto decompressedCopy = packetPool.allocCopy(mp);
meshtastic_TAK_Packet uncompressed = meshtastic_TAK_Packet_init_default;
uncompressed.which_callsign_variant = meshtastic_TAK_Packet_callsign_uncompressed_tag;
uncompressed.which_payload_variant = meshtastic_TAK_Packet_tak_pli_tag;
uncompressed.payload_variant.tak_pli = t->payload_variant.tak_pli;
auto length = unishox2_decompress_simple(t->callsign_variant.callsign_compressed, decompressedCopy->decoded.payload.size,
uncompressed.callsign_variant.callsign_uncompressed);
decompressedCopy->decoded.payload.size =
pb_encode_to_bytes(decompressedCopy->decoded.payload.bytes, sizeof(decompressedCopy->decoded.payload),
meshtastic_TAK_Packet_fields, &uncompressed);
service.sendToPhone(decompressedCopy);
delete decompressedCopy;
}
return;
}
22 changes: 22 additions & 0 deletions src/modules/AtakPluginModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once
#include "ProtobufModule.h"

/**
* Waypoint message handling for meshtastic
*/
class AtakPluginModule : public ProtobufModule<meshtastic_TAK_Packet>, private concurrency::OSThread
{
public:
/** Constructor
* name is for debugging output
*/
AtakPluginModule();

protected:
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_TAK_Packet *t) override;
virtual void alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_TAK_Packet *t) override;
/* Does our periodic broadcast */
int32_t runOnce() override;
};

extern AtakPluginModule *atakPluginModule;
3 changes: 2 additions & 1 deletion src/modules/Modules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "input/cardKbI2cImpl.h"
#include "input/kbMatrixImpl.h"
#include "modules/AdminModule.h"
#include "modules/AtakPluginModule.h"
#include "modules/CannedMessageModule.h"
#include "modules/DetectionSensorModule.h"
#include "modules/NeighborInfoModule.h"
Expand Down Expand Up @@ -61,7 +62,7 @@ void setupModules()
traceRouteModule = new TraceRouteModule();
neighborInfoModule = new NeighborInfoModule();
detectionSensorModule = new DetectionSensorModule();

atakPluginModule = new AtakPluginModule();
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
// to a global variable.

Expand Down

0 comments on commit bda6a24

Please sign in to comment.