diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index fbb73c8a..d1813dcf 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -123,6 +123,7 @@ static uint32_t _atoi(const char* sp) { #define CMD_DEVICE_QEURY 22 #define CMD_EXPORT_PRIVATE_KEY 23 #define CMD_IMPORT_PRIVATE_KEY 24 +#define CMD_SEND_RAW_DATA 25 #define RESP_CODE_OK 0 #define RESP_CODE_ERR 1 @@ -146,6 +147,7 @@ static uint32_t _atoi(const char* sp) { #define PUSH_CODE_PATH_UPDATED 0x81 #define PUSH_CODE_SEND_CONFIRMED 0x82 #define PUSH_CODE_MSG_WAITING 0x83 +#define PUSH_CODE_RAW_DATA 0x84 /* -------------------------------------------------------------------------------------- */ @@ -480,6 +482,21 @@ protected: // TODO: check for Get Stats response } + void onRawDataRecv(mesh::Packet* packet) override { + int i = 0; + out_frame[i++] = PUSH_CODE_RAW_DATA; + out_frame[i++] = (int8_t)(_radio->getLastSNR() * 4); + out_frame[i++] = (int8_t)(_radio->getLastRSSI()); + out_frame[i++] = 0xFF; // reserved (possibly path_len in future) + memcpy(&out_frame[i], packet->payload, packet->payload_len); i += packet->payload_len; + + if (_serial->isConnected()) { + _serial->writeFrame(out_frame, i); + } else { + MESH_DEBUG_PRINTLN("onRawDataRecv(), data received while app offline"); + } + } + uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override { return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); } @@ -887,6 +904,21 @@ public: #else writeDisabledFrame(); #endif + } else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) { + int i = 1; + int8_t path_len = cmd_frame[i++]; + if (path_len >= 0 && i + path_len + 4 <= len) { // minimum 4 byte payload + uint8_t* path = &cmd_frame[i]; i += path_len; + auto pkt = createRawData(&cmd_frame[i], len - i); + if (pkt) { + sendDirect(pkt, path, path_len); + writeOKFrame(); + } else { + writeErrFrame(); + } + } else { + writeErrFrame(); // flood, not supported (yet) + } } else { writeErrFrame(); MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); diff --git a/src/Mesh.cpp b/src/Mesh.cpp index c1da4677..be0ba118 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -213,6 +213,13 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { } break; } + case PAYLOAD_TYPE_RAW_CUSTOM: { + if (pkt->isRouteDirect() && !_tables->hasSeen(pkt)) { + onRawDataRecv(pkt); + //action = routeRecvPacket(pkt); don't flood route these (yet) + } + break; + } default: MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): unknown payload type, header: %d", getLogDateTime(), (int) pkt->header); // Don't flood route unknown packet types! action = routeRecvPacket(pkt); @@ -401,6 +408,22 @@ Packet* Mesh::createAck(uint32_t ack_crc) { return packet; } +Packet* Mesh::createRawData(const uint8_t* data, size_t len) { + if (len > sizeof(Packet::payload)) return NULL; // invalid arg + + Packet* packet = obtainNewPacket(); + if (packet == NULL) { + MESH_DEBUG_PRINTLN("%s Mesh::createRawData(): error, packet pool empty", getLogDateTime()); + return NULL; + } + packet->header = (PAYLOAD_TYPE_RAW_CUSTOM << PH_TYPE_SHIFT); // ROUTE_TYPE_* set later + + memcpy(packet->payload, data, len); + packet->payload_len = len; + + return packet; +} + void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) { packet->header &= ~PH_ROUTE_MASK; packet->header |= ROUTE_TYPE_FLOOD; diff --git a/src/Mesh.h b/src/Mesh.h index d347f017..4552c85b 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -125,6 +125,11 @@ protected: */ virtual void onPathRecv(Packet* packet, Identity& sender, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) { } + /** + * \brief A packet with PAYLOAD_TYPE_RAW_CUSTOM has been received. + */ + virtual void onRawDataRecv(Packet* packet) { } + /** * \brief Perform search of local DB of matching GroupChannels. * \param channels OUT - store matching channels in this array, up to max_matches @@ -169,6 +174,7 @@ public: Packet* createAck(uint32_t ack_crc); Packet* createPathReturn(const uint8_t* dest_hash, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len); Packet* createPathReturn(const Identity& dest, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len); + Packet* createRawData(const uint8_t* data, size_t len); /** * \brief send a locally-generated Packet with flood routing diff --git a/src/Packet.h b/src/Packet.h index c8769d8c..bff04321 100644 --- a/src/Packet.h +++ b/src/Packet.h @@ -26,7 +26,7 @@ namespace mesh { #define PAYLOAD_TYPE_ANON_REQ 0x07 // generic request (prefixed with dest_hash, ephemeral pub_key, MAC) (enc data: ...) #define PAYLOAD_TYPE_PATH 0x08 // returned path (prefixed with dest/src hashes, MAC) (enc data: path, extra) //... -#define PAYLOAD_TYPE_RESERVEDM 0x0F // FUTURE +#define PAYLOAD_TYPE_RAW_CUSTOM 0x0F // custom packet as raw bytes, for applications with custom encryption, payloads, etc #define PAYLOAD_VER_1 0x00 // 1-byte src/dest hashes, 2-byte MAC #define PAYLOAD_VER_2 0x01 // FUTURE (eg. 2-byte hashes, 4-byte MAC ??)