From df33321bdc37cd7633e196163eafcda0ae7f2ba5 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 14 Jul 2025 12:25:34 +1000 Subject: [PATCH] * companion: added CMD_SEND_BINARY_REQ (50) --- examples/companion_radio/MyMesh.cpp | 43 ++++++++++++---- examples/companion_radio/MyMesh.h | 2 +- src/helpers/BaseChatMesh.cpp | 77 ++++++++++++++++++++--------- src/helpers/BaseChatMesh.h | 1 + 4 files changed, 90 insertions(+), 33 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index c230cb8a..47111c32 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -46,6 +46,8 @@ #define CMD_SET_CUSTOM_VAR 41 #define CMD_GET_ADVERT_PATH 42 #define CMD_GET_TUNING_PARAMS 43 +// NOTE: CMD range 44..49 parked, potentially for WiFi operations +#define CMD_SEND_BINARY_REQ 50 #define RESP_CODE_OK 0 #define RESP_CODE_ERR 1 @@ -92,7 +94,7 @@ #define PUSH_CODE_LOG_RX_DATA 0x88 #define PUSH_CODE_TRACE_DATA 0x89 #define PUSH_CODE_NEW_ADVERT 0x8A -#define PUSH_CODE_TELEMETRY_RESPONSE 0x8B +#define PUSH_CODE_BINARY_RESPONSE 0x8B // was 'PUSH_CODE_TELEMETRY_RESPONSE' #define ERR_CODE_UNSUPPORTED_CMD 1 #define ERR_CODE_NOT_FOUND 2 @@ -490,11 +492,11 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, memcpy(&out_frame[i], &data[4], len - 4); i += (len - 4); _serial->writeFrame(out_frame, i); - } else if (len > 4 && tag == pending_telemetry) { // check for telemetry response - pending_telemetry = 0; + } else if (len > 4 && tag == pending_req) { // check for matching response tag + pending_req = 0; int i = 0; - out_frame[i++] = PUSH_CODE_TELEMETRY_RESPONSE; + out_frame[i++] = PUSH_CODE_BINARY_RESPONSE; out_frame[i++] = 0; // reserved memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix @@ -566,7 +568,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe _cli_rescue = false; offline_queue_len = 0; app_target_ver = 0; - pending_login = pending_status = pending_telemetry = 0; + pending_login = pending_status = pending_req = 0; next_ack_idx = 0; sign_data = NULL; dirty_contacts_expiry = 0; @@ -1103,7 +1105,7 @@ void MyMesh::handleCmdFrame(size_t len) { if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } else { - pending_telemetry = pending_status = 0; + pending_req = pending_status = 0; memcpy(&pending_login, recipient->id.pub_key, 4); // match this to onContactResponse() out_frame[0] = RESP_CODE_SENT; out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0; @@ -1123,7 +1125,7 @@ void MyMesh::handleCmdFrame(size_t len) { if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } else { - pending_telemetry = pending_login = 0; + pending_req = pending_login = 0; // FUTURE: pending_status = tag; // match this in onContactResponse() memcpy(&pending_status, recipient->id.pub_key, 4); // legacy matching scheme out_frame[0] = RESP_CODE_SENT; @@ -1135,7 +1137,7 @@ void MyMesh::handleCmdFrame(size_t len) { } else { writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found } - } else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) { + } else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) { // can deprecate, in favour of CMD_SEND_BINARY_REQ uint8_t *pub_key = &cmd_frame[4]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { @@ -1145,7 +1147,7 @@ void MyMesh::handleCmdFrame(size_t len) { writeErrFrame(ERR_CODE_TABLE_FULL); } else { pending_status = pending_login = 0; - pending_telemetry = tag; // match this in onContactResponse() + pending_req = tag; // match this in onContactResponse() out_frame[0] = RESP_CODE_SENT; out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0; memcpy(&out_frame[2], &tag, 4); @@ -1162,7 +1164,7 @@ void MyMesh::handleCmdFrame(size_t len) { sensors.querySensors(0xFF, telemetry); int i = 0; - out_frame[i++] = PUSH_CODE_TELEMETRY_RESPONSE; + out_frame[i++] = PUSH_CODE_BINARY_RESPONSE; out_frame[i++] = 0; // reserved memcpy(&out_frame[i], self_id.pub_key, 6); i += 6; // pub_key_prefix @@ -1170,6 +1172,27 @@ void MyMesh::handleCmdFrame(size_t len) { memcpy(&out_frame[i], telemetry.getBuffer(), tlen); i += tlen; _serial->writeFrame(out_frame, i); + } else if (cmd_frame[0] == CMD_SEND_BINARY_REQ && len >= 2 + PUB_KEY_SIZE) { + uint8_t *pub_key = &cmd_frame[1]; + ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + if (recipient) { + uint8_t *req_data = &cmd_frame[1 + PUB_KEY_SIZE]; + uint32_t tag, est_timeout; + int result = sendRequest(*recipient, req_data, len - (1 + PUB_KEY_SIZE), tag, est_timeout); + if (result == MSG_SEND_FAILED) { + writeErrFrame(ERR_CODE_TABLE_FULL); + } else { + pending_status = pending_login = 0; + pending_req = tag; // match this in onContactResponse() + out_frame[0] = RESP_CODE_SENT; + out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0; + memcpy(&out_frame[2], &tag, 4); + memcpy(&out_frame[6], &est_timeout, 4); + _serial->writeFrame(out_frame, 10); + } + } else { + writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found + } } else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; if (hasConnectionTo(pub_key)) { diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 247a9b3d..73e67684 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -160,7 +160,7 @@ private: NodePrefs _prefs; uint32_t pending_login; uint32_t pending_status; - uint32_t pending_telemetry; + uint32_t pending_req; // pending _BINARY_REQ (or legacy _TELEMETRY_REQ) BaseSerialInterface *_serial; ContactsIterator _iter; diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index 271f28da..d6ba17b9 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -403,22 +403,52 @@ bool BaseChatMesh::importContact(const uint8_t src_buf[], uint8_t len) { } int BaseChatMesh::sendLogin(const ContactInfo& recipient, const char* password, uint32_t& est_timeout) { - int tlen; - uint8_t temp[24]; - uint32_t now = getRTCClock()->getCurrentTimeUnique(); - memcpy(temp, &now, 4); // mostly an extra blob to help make packet_hash unique - if (recipient.type == ADV_TYPE_ROOM) { - memcpy(&temp[4], &recipient.sync_since, 4); - int len = strlen(password); if (len > 15) len = 15; // max 15 chars currently - memcpy(&temp[8], password, len); - tlen = 8 + len; - } else { - int len = strlen(password); if (len > 15) len = 15; // max 15 chars currently - memcpy(&temp[4], password, len); - tlen = 4 + len; - } + mesh::Packet* pkt; + { + int tlen; + uint8_t temp[24]; + uint32_t now = getRTCClock()->getCurrentTimeUnique(); + memcpy(temp, &now, 4); // mostly an extra blob to help make packet_hash unique + if (recipient.type == ADV_TYPE_ROOM) { + memcpy(&temp[4], &recipient.sync_since, 4); + int len = strlen(password); if (len > 15) len = 15; // max 15 chars currently + memcpy(&temp[8], password, len); + tlen = 8 + len; + } else { + int len = strlen(password); if (len > 15) len = 15; // max 15 chars currently + memcpy(&temp[4], password, len); + tlen = 4 + len; + } - auto pkt = createAnonDatagram(PAYLOAD_TYPE_ANON_REQ, self_id, recipient.id, recipient.shared_secret, temp, tlen); + pkt = createAnonDatagram(PAYLOAD_TYPE_ANON_REQ, self_id, recipient.id, recipient.shared_secret, temp, tlen); + } + if (pkt) { + uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); + if (recipient.out_path_len < 0) { + sendFlood(pkt); + est_timeout = calcFloodTimeoutMillisFor(t); + return MSG_SEND_SENT_FLOOD; + } else { + sendDirect(pkt, recipient.out_path, recipient.out_path_len); + est_timeout = calcDirectTimeoutMillisFor(t, recipient.out_path_len); + return MSG_SEND_SENT_DIRECT; + } + } + return MSG_SEND_FAILED; +} + +int BaseChatMesh::sendRequest(const ContactInfo& recipient, const uint8_t* req_data, uint8_t data_len, uint32_t& tag, uint32_t& est_timeout) { + if (data_len > MAX_PACKET_PAYLOAD - 16) return MSG_SEND_FAILED; + + mesh::Packet* pkt; + { + uint8_t temp[MAX_PACKET_PAYLOAD]; + tag = getRTCClock()->getCurrentTimeUnique(); + memcpy(temp, &tag, 4); // mostly an extra blob to help make packet_hash unique + memcpy(&temp[4], req_data, data_len); + + pkt = createDatagram(PAYLOAD_TYPE_REQ, recipient.id, recipient.shared_secret, temp, 4 + data_len); + } if (pkt) { uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); if (recipient.out_path_len < 0) { @@ -435,14 +465,17 @@ int BaseChatMesh::sendLogin(const ContactInfo& recipient, const char* password, } int BaseChatMesh::sendRequest(const ContactInfo& recipient, uint8_t req_type, uint32_t& tag, uint32_t& est_timeout) { - uint8_t temp[13]; - tag = getRTCClock()->getCurrentTimeUnique(); - memcpy(temp, &tag, 4); // mostly an extra blob to help make packet_hash unique - temp[4] = req_type; - memset(&temp[5], 0, 4); // reserved (possibly for 'since' param) - getRNG()->random(&temp[9], 4); // random blob to help make packet-hash unique + mesh::Packet* pkt; + { + uint8_t temp[13]; + tag = getRTCClock()->getCurrentTimeUnique(); + memcpy(temp, &tag, 4); // mostly an extra blob to help make packet_hash unique + temp[4] = req_type; + memset(&temp[5], 0, 4); // reserved (possibly for 'since' param) + getRNG()->random(&temp[9], 4); // random blob to help make packet-hash unique - auto pkt = createDatagram(PAYLOAD_TYPE_REQ, recipient.id, recipient.shared_secret, temp, sizeof(temp)); + pkt = createDatagram(PAYLOAD_TYPE_REQ, recipient.id, recipient.shared_secret, temp, sizeof(temp)); + } if (pkt) { uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); if (recipient.out_path_len < 0) { diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 53cd5018..903b4ece 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -134,6 +134,7 @@ public: bool sendGroupMessage(uint32_t timestamp, mesh::GroupChannel& channel, const char* sender_name, const char* text, int text_len); int sendLogin(const ContactInfo& recipient, const char* password, uint32_t& est_timeout); int sendRequest(const ContactInfo& recipient, uint8_t req_type, uint32_t& tag, uint32_t& est_timeout); + int sendRequest(const ContactInfo& recipient, const uint8_t* req_data, uint8_t data_len, uint32_t& tag, uint32_t& est_timeout); bool shareContactZeroHop(const ContactInfo& contact); uint8_t exportContact(const ContactInfo& contact, uint8_t dest_buf[]); bool importContact(const uint8_t src_buf[], uint8_t len);