From 4051bf8465af773f5891a628efb21e4a9e6aee65 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 2 Feb 2020 09:59:00 -0800 Subject: [PATCH] begin adding rx from radio handling --- .vscode/settings.json | 3 +- lib/nanopb/{ => src}/pb.h | 0 lib/nanopb/{ => src}/pb_common.c | 0 lib/nanopb/{ => src}/pb_common.h | 0 lib/nanopb/{ => src}/pb_decode.c | 0 lib/nanopb/{ => src}/pb_decode.h | 0 lib/nanopb/{ => src}/pb_encode.c | 0 lib/nanopb/{ => src}/pb_encode.h | 0 src/MemoryPool.h | 47 ++++++++++++++++++++++++++++++ src/MeshBluetoothService.cpp | 43 +++++++++++++++++++++++++++ src/MeshRadio.h | 4 +-- src/TypedQueue.h | 50 ++++++++++++++++++++++++++++++++ src/mesh.pb.c | 9 ++---- src/mesh.pb.h | 33 +++++---------------- 14 files changed, 155 insertions(+), 34 deletions(-) rename lib/nanopb/{ => src}/pb.h (100%) rename lib/nanopb/{ => src}/pb_common.c (100%) rename lib/nanopb/{ => src}/pb_common.h (100%) rename lib/nanopb/{ => src}/pb_decode.c (100%) rename lib/nanopb/{ => src}/pb_decode.h (100%) rename lib/nanopb/{ => src}/pb_encode.c (100%) rename lib/nanopb/{ => src}/pb_encode.h (100%) create mode 100644 src/MemoryPool.h create mode 100644 src/TypedQueue.h diff --git a/.vscode/settings.json b/.vscode/settings.json index c33946c6..55767055 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,6 +39,7 @@ "streambuf": "cpp", "cinttypes": "cpp", "utility": "cpp", - "typeinfo": "cpp" + "typeinfo": "cpp", + "string": "cpp" } } \ No newline at end of file diff --git a/lib/nanopb/pb.h b/lib/nanopb/src/pb.h similarity index 100% rename from lib/nanopb/pb.h rename to lib/nanopb/src/pb.h diff --git a/lib/nanopb/pb_common.c b/lib/nanopb/src/pb_common.c similarity index 100% rename from lib/nanopb/pb_common.c rename to lib/nanopb/src/pb_common.c diff --git a/lib/nanopb/pb_common.h b/lib/nanopb/src/pb_common.h similarity index 100% rename from lib/nanopb/pb_common.h rename to lib/nanopb/src/pb_common.h diff --git a/lib/nanopb/pb_decode.c b/lib/nanopb/src/pb_decode.c similarity index 100% rename from lib/nanopb/pb_decode.c rename to lib/nanopb/src/pb_decode.c diff --git a/lib/nanopb/pb_decode.h b/lib/nanopb/src/pb_decode.h similarity index 100% rename from lib/nanopb/pb_decode.h rename to lib/nanopb/src/pb_decode.h diff --git a/lib/nanopb/pb_encode.c b/lib/nanopb/src/pb_encode.c similarity index 100% rename from lib/nanopb/pb_encode.c rename to lib/nanopb/src/pb_encode.c diff --git a/lib/nanopb/pb_encode.h b/lib/nanopb/src/pb_encode.h similarity index 100% rename from lib/nanopb/pb_encode.h rename to lib/nanopb/src/pb_encode.h diff --git a/src/MemoryPool.h b/src/MemoryPool.h new file mode 100644 index 00000000..969ee291 --- /dev/null +++ b/src/MemoryPool.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + + +/** + * A pool based allocator + * + * Eventually this routine will even be safe for ISR use... + */ +template class MemoryPool { + TypedQueue dead; + + T *buf; // our large raw block of memory + +public: + MemoryPool(int maxElements): queued(maxElements), dead(maxElements) { + buf = new T[maxElements]; + + // prefill dead + for(int i = 0; i < maxElements; i++) + release(&buf[i]); + } + + ~MemoryPool() { + delete[] buf; + } + + /// Return a queable object which has been prefilled with zeros + T *allocZeroed(TickType_t maxWait = portMAX_DELAY) { + T *p; + + if(dead.dequeue(&p, maxWait) != pdTRUE) + return NULL; + + memset(p, 0, sizeof(T)); + return p; + } + + /// Return a buffer for use by others + void free(T *p) { + int res = dead.enqueue(p, 0); + assert(res == pdTRUE); + } +}; + diff --git a/src/MeshBluetoothService.cpp b/src/MeshBluetoothService.cpp index af7bf6d4..6de61207 100644 --- a/src/MeshBluetoothService.cpp +++ b/src/MeshBluetoothService.cpp @@ -9,6 +9,8 @@ #include #include "mesh.pb.h" #include "MeshRadio.h" +#include "TypedQueue.h" +#include "MemoryPool.h" /* receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone. @@ -53,6 +55,9 @@ public: */ +#define MAX_PACKETS 32 // max number of packets which can be in flight (either queued from reception or queued for sending) +#define MAX_RX_TOPHONE 16 // max number of packets which can be waiting for delivery to android + /// A temporary buffer used for sending packets, sized to hold the biggest buffer we might need static uint8_t outbuf[MeshPacket_size]; @@ -62,7 +67,45 @@ static uint8_t outbuf[MeshPacket_size]; */ class MeshService { + MemoryPool packetPool; + + /// received packets waiting for the phone to process them + /// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure + /// we never hang because android hasn't been there in a while + PointerQueue toPhoneQueue; + + /// Packets which have just arrived from the radio, ready to be processed by this service and possibly + /// forwarded to the phone. Note: not using yet - seeing if I can just handle everything asap in handleFromRadio + // PointerQueue fromRadioQueue; + public: + MeshService() : packetPool(MAX_PACKETS), toPhoneQueue(MAX_RX_TOPHONE) { + + } + + /// Do idle processing (mostly processing messages which have been queued from the radio) + // void loop() { } + + /** + * handle an incoming MeshPacket from the radio, update DB state and queue it for the phone + */ + void handleFromRadio(NodeNum from, NodeNum to, const uint8_t *buf, size_t len) { + MeshPacket *p = packetPool.allocZeroed(); + assert(p); + + pb_istream_t stream = pb_istream_from_buffer(buf, len); + if (!pb_decode(&stream, MeshPacket_fields, p) || !p->has_payload) + { + Serial.printf("Error: can't decode MeshPacket %s\n", PB_GET_ERROR(&stream)); + } + else + { + // FIXME - update DB state based on payload and show recevied texts + + toPhoneQueue.enqueue(p); + } + } + /// Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh) void handleToRadio(std::string s) { diff --git a/src/MeshRadio.h b/src/MeshRadio.h index e9269b40..9d11665c 100644 --- a/src/MeshRadio.h +++ b/src/MeshRadio.h @@ -10,8 +10,8 @@ typedef int ErrorCode; typedef uint8_t NodeNum; -/// Callback for a receive packet -typedef void (*MeshRXHandler)(NodeNum from, NodeNum to, std::string packet); +/// Callback for a receive packet, the callee must copy/queue the payload elsewhere before returning +typedef void (*MeshRXHandler)(NodeNum from, NodeNum to, const uint8_t *buf, size_t len); /** * A raw low level interface to our mesh. Only understands nodenums and bytes (not protobufs or node ids) diff --git a/src/TypedQueue.h b/src/TypedQueue.h new file mode 100644 index 00000000..0ee42d51 --- /dev/null +++ b/src/TypedQueue.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +/** + * A wrapper for freertos queues. Note: each element object must be quite small, so T should be only + * pointer types or ints + */ +template class TypedQueue { + QueueHandle_t h; +public: + TypedQueue(int maxElements) { + h = xQueueCreate(maxElements, sizeof(T)); + assert(h); + } + + ~TypedQueue() { + vQueueDelete(h); + } + + // pdTRUE for success else failure + BaseType_t enqueue(T x, TickType_t maxWait = portMAX_DELAY) { + return xQueueSendToBack(h, &x, maxWait); + } + + // pdTRUE for success else failure + BaseType_t dequeue(T *p, TickType_t maxWait = portMAX_DELAY) { + return xQueueReceive(h, p, maxWait); + } +}; + + +/** + * A wrapper for freertos queues that assumes each element is a pointer + */ +template class PointerQueue: public TypedQueue { + TypedQueue h; +public: + PointerQueue(int maxElements) : TypedQueue(maxElements) { + } + + // preturns a ptr or null if the queue was empty + T *dequeuePtr(TickType_t maxWait = portMAX_DELAY) { + T *p; + + return dequeue(&p, maxWait) == pdTRUE ? p : NULL; + } +}; + diff --git a/src/mesh.pb.c b/src/mesh.pb.c index 829867b4..82a3cd1b 100644 --- a/src/mesh.pb.c +++ b/src/mesh.pb.c @@ -27,10 +27,7 @@ PB_BIND(DenyNodeNum, DenyNodeNum, AUTO) PB_BIND(SubPacket, SubPacket, AUTO) -PB_BIND(MeshPayload, MeshPayload, 2) - - -PB_BIND(MeshPacket, MeshPacket, 2) +PB_BIND(MeshPacket, MeshPacket, AUTO) PB_BIND(RadioConfig, RadioConfig, 2) @@ -39,10 +36,10 @@ PB_BIND(RadioConfig, RadioConfig, 2) PB_BIND(NodeInfo, NodeInfo, AUTO) -PB_BIND(DeviceState, DeviceState, 4) +PB_BIND(DeviceState, DeviceState, 2) -PB_BIND(FromRadio, FromRadio, 2) +PB_BIND(FromRadio, FromRadio, AUTO) PB_BIND(ToRadio, ToRadio, 2) diff --git a/src/mesh.pb.h b/src/mesh.pb.h index ea490c88..54982769 100644 --- a/src/mesh.pb.h +++ b/src/mesh.pb.h @@ -86,16 +86,11 @@ typedef struct _SubPacket { } variant; } SubPacket; -typedef struct _MeshPayload { - pb_size_t subPackets_count; - SubPacket subPackets[4]; -} MeshPayload; - typedef struct _MeshPacket { int32_t from; int32_t to; bool has_payload; - MeshPayload payload; + SubPacket payload; } MeshPacket; typedef struct _DeviceState { @@ -143,8 +138,7 @@ typedef struct _ToRadio { #define WantNodeNum_init_default {0, ""} #define DenyNodeNum_init_default {""} #define SubPacket_init_default {0, {Position_init_default}} -#define MeshPayload_init_default {0, {SubPacket_init_default, SubPacket_init_default, SubPacket_init_default, SubPacket_init_default}} -#define MeshPacket_init_default {0, 0, false, MeshPayload_init_default} +#define MeshPacket_init_default {0, 0, false, SubPacket_init_default} #define RadioConfig_init_default {0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, false, Time_init_default} #define DeviceState_init_default {false, RadioConfig_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default}, 0} @@ -158,8 +152,7 @@ typedef struct _ToRadio { #define WantNodeNum_init_zero {0, ""} #define DenyNodeNum_init_zero {""} #define SubPacket_init_zero {0, {Position_init_zero}} -#define MeshPayload_init_zero {0, {SubPacket_init_zero, SubPacket_init_zero, SubPacket_init_zero, SubPacket_init_zero}} -#define MeshPacket_init_zero {0, 0, false, MeshPayload_init_zero} +#define MeshPacket_init_zero {0, 0, false, SubPacket_init_zero} #define RadioConfig_init_zero {0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, false, Time_init_zero} #define DeviceState_init_zero {false, RadioConfig_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero}, 0} @@ -195,7 +188,6 @@ typedef struct _ToRadio { #define SubPacket_user_tag 4 #define SubPacket_want_node_tag 5 #define SubPacket_deny_node_tag 6 -#define MeshPayload_subPackets_tag 3 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 #define MeshPacket_payload_tag 3 @@ -268,19 +260,13 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,deny_node,variant.deny_node), 6) #define SubPacket_variant_want_node_MSGTYPE WantNodeNum #define SubPacket_variant_deny_node_MSGTYPE DenyNodeNum -#define MeshPayload_FIELDLIST(X, a) \ -X(a, STATIC, REPEATED, MESSAGE, subPackets, 3) -#define MeshPayload_CALLBACK NULL -#define MeshPayload_DEFAULT NULL -#define MeshPayload_subPackets_MSGTYPE SubPacket - #define MeshPacket_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, INT32, from, 1) \ X(a, STATIC, SINGULAR, INT32, to, 2) \ X(a, STATIC, OPTIONAL, MESSAGE, payload, 3) #define MeshPacket_CALLBACK NULL #define MeshPacket_DEFAULT NULL -#define MeshPacket_payload_MSGTYPE MeshPayload +#define MeshPacket_payload_MSGTYPE SubPacket #define RadioConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, keep_all_packets, 100) \ @@ -344,7 +330,6 @@ extern const pb_msgdesc_t User_msg; extern const pb_msgdesc_t WantNodeNum_msg; extern const pb_msgdesc_t DenyNodeNum_msg; extern const pb_msgdesc_t SubPacket_msg; -extern const pb_msgdesc_t MeshPayload_msg; extern const pb_msgdesc_t MeshPacket_msg; extern const pb_msgdesc_t RadioConfig_msg; extern const pb_msgdesc_t NodeInfo_msg; @@ -361,7 +346,6 @@ extern const pb_msgdesc_t ToRadio_WantNodes_msg; #define WantNodeNum_fields &WantNodeNum_msg #define DenyNodeNum_fields &DenyNodeNum_msg #define SubPacket_fields &SubPacket_msg -#define MeshPayload_fields &MeshPayload_msg #define MeshPacket_fields &MeshPacket_msg #define RadioConfig_fields &RadioConfig_msg #define NodeInfo_fields &NodeInfo_msg @@ -378,13 +362,12 @@ extern const pb_msgdesc_t ToRadio_WantNodes_msg; #define WantNodeNum_size 13 #define DenyNodeNum_size 7 #define SubPacket_size 106 -#define MeshPayload_size 432 -#define MeshPacket_size 457 +#define MeshPacket_size 130 #define RadioConfig_size 6 #define NodeInfo_size 140 -#define DeviceState_size 19310 -#define FromRadio_size 466 -#define ToRadio_size 460 +#define DeviceState_size 8846 +#define FromRadio_size 149 +#define ToRadio_size 133 #define ToRadio_WantNodes_size 0 #ifdef __cplusplus