From 8c68dbb6e95b56970e6d451c58f316d22d180fd6 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Tue, 11 Mar 2025 14:50:40 +1100 Subject: [PATCH] * Companion: new CMD_GET_CHANNEL, CMD_SET_CHANNEL --- examples/companion_radio/main.cpp | 37 ++++++++++++++++++++++++++---- platformio.ini | 36 ++++++++++++++--------------- src/helpers/BaseChatMesh.cpp | 38 ++++++++++++++++++++++++++++++- src/helpers/BaseChatMesh.h | 6 ++++- 4 files changed, 92 insertions(+), 25 deletions(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 35600de1..c8178b25 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -161,6 +161,8 @@ static uint32_t _atoi(const char* sp) { #define CMD_HAS_CONNECTION 28 #define CMD_LOGOUT 29 // 'Disconnect' #define CMD_GET_CONTACT_BY_KEY 30 +#define CMD_GET_CHANNEL 31 +#define CMD_SET_CHANNEL 32 #define RESP_CODE_OK 0 #define RESP_CODE_ERR 1 @@ -178,6 +180,7 @@ static uint32_t _atoi(const char* sp) { #define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QEURY #define RESP_CODE_PRIVATE_KEY 14 // a reply to CMD_EXPORT_PRIVATE_KEY #define RESP_CODE_DISABLED 15 +#define RESP_CODE_CHANNEL_INFO 16 // a reply to CMD_GET_CHANNEL // these are _pushed_ to client app at any time #define PUSH_CODE_ADVERT 0x80 @@ -216,7 +219,6 @@ class MyMesh : public BaseChatMesh { uint32_t expected_ack_crc; // TODO: keep table of expected ACKs uint32_t pending_login; uint32_t pending_status; - mesh::GroupChannel* _public; BaseSerialInterface* _serial; unsigned long last_msg_sent; ContactsIterator _iter; @@ -536,7 +538,7 @@ protected: void onChannelMessageRecv(const mesh::GroupChannel& channel, int in_path_len, uint32_t timestamp, const char *text) override { int i = 0; out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV; - out_frame[i++] = 0; // FUTURE: channel_idx (will just be 'public' for now) + out_frame[i++] = findChannelIdx(channel); out_frame[i++] = in_path_len < 0 ? 0xFF : in_path_len; out_frame[i++] = TXT_TYPE_PLAIN; memcpy(&out_frame[i], ×tamp, 4); i += 4; @@ -713,7 +715,7 @@ public: _fs->mkdir("/bl"); loadContacts(); - _public = addChannel(PUBLIC_GROUP_PSK); // pre-configure Andy's public channel + addChannel(PUBLIC_GROUP_PSK); // pre-configure Andy's public channel _phy->setFrequency(_prefs.freq); _phy->setSpreadingFactor(_prefs.sf); @@ -844,12 +846,14 @@ public: } else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg int i = 1; uint8_t txt_type = cmd_frame[i++]; // should be TXT_TYPE_PLAIN - uint8_t channel_idx = cmd_frame[i++]; // reserved future + uint8_t channel_idx = cmd_frame[i++]; uint32_t msg_timestamp; memcpy(&msg_timestamp, &cmd_frame[i], 4); i += 4; const char *text = (char *) &cmd_frame[i]; - if (txt_type == TXT_TYPE_PLAIN && sendGroupMessage(msg_timestamp, *_public, _prefs.node_name, text, len - i)) { // hard-coded to 'public' channel for now + mesh::GroupChannel channel; + bool success = getChannel(channel_idx, channel); + if (success && txt_type == TXT_TYPE_PLAIN && sendGroupMessage(msg_timestamp, channel, _prefs.node_name, text, len - i)) { writeOKFrame(); } else { writeErrFrame(); @@ -1161,6 +1165,29 @@ public: uint8_t* pub_key = &cmd_frame[1]; stopConnection(pub_key); writeOKFrame(); + } else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) { + uint8_t channel_idx = cmd_frame[1]; + mesh::GroupChannel channel; + if (getChannel(channel_idx, channel)) { + out_frame[0] = RESP_CODE_CHANNEL_INFO; + out_frame[1] = channel_idx; + memcpy(&out_frame[2], channel.secret, 16); // NOTE: only 128-bit supported + _serial->writeFrame(out_frame, 2 + 16); + } else { + writeErrFrame(); + } + } else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 3+32) { + writeErrFrame(); // not supported (yet) + } else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 3+16) { + uint8_t channel_idx = cmd_frame[1]; + mesh::GroupChannel channel; + memset(channel.secret, 0, sizeof(channel.secret)); + memcpy(channel.secret, &cmd_frame[2], 16); // NOTE: only 128-bit supported + if (setChannel(channel_idx, channel)) { + writeOKFrame(); + } else { + writeErrFrame(); + } } else { writeErrFrame(); MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); diff --git a/platformio.ini b/platformio.ini index 6175206f..07ffbf91 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,7 +78,7 @@ extends = Heltec_lora32_v2 build_flags = ${Heltec_lora32_v2.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v2.build_src_filter} @@ -93,7 +93,7 @@ extends = Heltec_lora32_v2 build_flags = ${Heltec_lora32_v2.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 @@ -180,7 +180,7 @@ extends = Heltec_lora32_v3 build_flags = ${Heltec_lora32_v3.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=SSD1306Display ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 @@ -198,7 +198,7 @@ extends = Heltec_lora32_v3 build_flags = ${Heltec_lora32_v3.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=SSD1306Display -D BLE_PIN_CODE=0 ; dynamic, random PIN -D BLE_DEBUG_LOGGING=1 @@ -219,7 +219,7 @@ extends = Heltec_lora32_v3 build_flags = ${Heltec_lora32_v3.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=SSD1306Display -D WIFI_DEBUG_LOGGING=1 -D WIFI_SSID='"myssid"' @@ -268,7 +268,7 @@ extends = Heltec_lora32_v3 build_flags = ${Heltec_lora32_v3.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 @@ -375,7 +375,7 @@ extends = Xiao_S3_WIO build_flags = ${Xiao_S3_WIO.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${Xiao_S3_WIO.build_src_filter} @@ -389,7 +389,7 @@ extends = Xiao_S3_WIO build_flags = ${Xiao_S3_WIO.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 ; -D BLE_DEBUG_LOGGING=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 @@ -454,7 +454,7 @@ extends = LilyGo_TLora_V2_1_1_6 build_flags = ${LilyGo_TLora_V2_1_1_6.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} @@ -469,7 +469,7 @@ extends = LilyGo_TLora_V2_1_1_6 build_flags = ${LilyGo_TLora_V2_1_1_6.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 @@ -486,7 +486,7 @@ extends = LilyGo_TLora_V2_1_1_6 build_flags = ${LilyGo_TLora_V2_1_1_6.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 ; -D BLE_DEBUG_LOGGING=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 @@ -572,7 +572,7 @@ extends = LilyGo_T3S3_sx1262 build_flags = ${LilyGo_T3S3_sx1262.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 @@ -588,7 +588,7 @@ extends = LilyGo_T3S3_sx1262 build_flags = ${LilyGo_T3S3_sx1262.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 @@ -728,7 +728,7 @@ extends = rak4631 build_flags = ${rak4631.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 @@ -744,7 +744,7 @@ extends = rak4631 build_flags = ${rak4631.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 @@ -796,7 +796,7 @@ upload_protocol = nrfutil extends = t1000-e build_flags = ${t1000-e.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D MESH_PACKET_LOGGING=1 @@ -870,7 +870,7 @@ extends = Heltec_t114 build_flags = ${Heltec_t114.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 @@ -943,7 +943,7 @@ extends = LilyGo_Techo build_flags = ${LilyGo_Techo.build_flags} -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index e8e48e53..e44ffcf3 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -203,7 +203,7 @@ void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) { #ifdef MAX_GROUP_CHANNELS int BaseChatMesh::searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel dest[], int max_matches) { int n = 0; - for (int i = 0; i < num_channels && n < max_matches; i++) { + for (int i = 0; i < MAX_GROUP_CHANNELS && n < max_matches; i++) { if (channels[i].hash[0] == hash[0]) { dest[n++] = channels[i]; } @@ -602,10 +602,46 @@ mesh::GroupChannel* BaseChatMesh::addChannel(const char* psk_base64) { } return NULL; } +bool BaseChatMesh::getChannel(int idx, mesh::GroupChannel& dest) { + if (idx >= 0 && idx < MAX_GROUP_CHANNELS) { + dest = channels[idx]; + return true; + } + return false; +} +bool BaseChatMesh::setChannel(int idx, const mesh::GroupChannel& src) { + static uint8_t zeroes[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + + if (idx >= 0 && idx < MAX_GROUP_CHANNELS) { + channels[idx] = src; + if (memcmp(&src.secret[16], zeroes, 16) == 0) { + mesh::Utils::sha256(channels[idx].hash, sizeof(channels[idx].hash), src.secret, 16); // 128-bit key + } else { + mesh::Utils::sha256(channels[idx].hash, sizeof(channels[idx].hash), src.secret, 32); // 256-bit key + } + return true; + } + return false; +} +int BaseChatMesh::findChannelIdx(const mesh::GroupChannel& ch) { + for (int i = 0; i < MAX_GROUP_CHANNELS; i++) { + if (memcmp(ch.secret, channels[i].secret, sizeof(ch.secret)) == 0) return i; + } + return -1; // not found +} #else mesh::GroupChannel* BaseChatMesh::addChannel(const char* psk_base64) { return NULL; // not supported } +bool BaseChatMesh::getChannel(int idx, mesh::GroupChannel& dest) { + return false; +} +bool BaseChatMesh::setChannel(int idx, const mesh::GroupChannel& src) { + return false; +} +int BaseChatMesh::findChannelIdx(const mesh::GroupChannel& ch) { + return -1; // not found +} #endif ContactsIterator BaseChatMesh::startContactsIterator() { diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 0f2e0283..c5b60dd1 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -75,7 +75,7 @@ class BaseChatMesh : public mesh::Mesh { unsigned long txt_send_timeout; #ifdef MAX_GROUP_CHANNELS mesh::GroupChannel channels[MAX_GROUP_CHANNELS]; - int num_channels; + int num_channels; // only for addChannel() #endif mesh::Packet* _pendingLoopback; uint8_t temp_buf[MAX_TRANS_UNIT]; @@ -89,6 +89,7 @@ protected: { num_contacts = 0; #ifdef MAX_GROUP_CHANNELS + memset(channels, 0, sizeof(channels)); num_channels = 0; #endif txt_send_timeout = 0; @@ -152,6 +153,9 @@ public: int getNumContacts() const { return num_contacts; } ContactsIterator startContactsIterator(); mesh::GroupChannel* addChannel(const char* psk_base64); + bool getChannel(int idx, mesh::GroupChannel& dest); + bool setChannel(int idx, const mesh::GroupChannel& src); + int findChannelIdx(const mesh::GroupChannel& ch); void loop(); };