* support for GroupChannels in BaseChatMesh, and terminal chat
This commit is contained in:
@@ -45,6 +45,7 @@
|
|||||||
#define DIRECT_SEND_PERHOP_FACTOR 4.0f
|
#define DIRECT_SEND_PERHOP_FACTOR 4.0f
|
||||||
#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 200
|
#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 200
|
||||||
|
|
||||||
|
#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg=="
|
||||||
|
|
||||||
#if defined(HELTEC_LORA_V3)
|
#if defined(HELTEC_LORA_V3)
|
||||||
#include <helpers/HeltecV3Board.h>
|
#include <helpers/HeltecV3Board.h>
|
||||||
@@ -74,6 +75,7 @@ static int curr_contact_idx = 0;
|
|||||||
class MyMesh : public BaseChatMesh, ContactVisitor {
|
class MyMesh : public BaseChatMesh, ContactVisitor {
|
||||||
FILESYSTEM* _fs;
|
FILESYSTEM* _fs;
|
||||||
uint32_t expected_ack_crc;
|
uint32_t expected_ack_crc;
|
||||||
|
mesh::GroupChannel* _public;
|
||||||
unsigned long last_msg_sent;
|
unsigned long last_msg_sent;
|
||||||
ContactInfo* curr_recipient;
|
ContactInfo* curr_recipient;
|
||||||
char command[MAX_TEXT_LEN+1];
|
char command[MAX_TEXT_LEN+1];
|
||||||
@@ -191,6 +193,15 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onChannelMessageRecv(const mesh::GroupChannel& channel, int in_path_len, uint32_t timestamp, const char *text) override {
|
||||||
|
if (in_path_len < 0) {
|
||||||
|
Serial.printf("PUBLIC CHANNEL MSG -> (Direct!)\n");
|
||||||
|
} else {
|
||||||
|
Serial.printf("PUBLIC CHANNEL MSG -> (Flood) hops %d\n", in_path_len);
|
||||||
|
}
|
||||||
|
Serial.printf(" %s\n", text);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override {
|
uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override {
|
||||||
return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis);
|
return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis);
|
||||||
}
|
}
|
||||||
@@ -226,6 +237,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadContacts();
|
loadContacts();
|
||||||
|
_public = addChannel(PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
|
||||||
}
|
}
|
||||||
|
|
||||||
void showWelcome() {
|
void showWelcome() {
|
||||||
@@ -261,6 +273,23 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
Serial.println(" ERROR: no recipient selected (use 'to' cmd).");
|
Serial.println(" ERROR: no recipient selected (use 'to' cmd).");
|
||||||
}
|
}
|
||||||
|
} else if (memcmp(command, "public ", 7) == 0) { // send GroupChannel msg
|
||||||
|
uint8_t temp[5+MAX_TEXT_LEN+32];
|
||||||
|
uint32_t timestamp = getRTCClock()->getCurrentTime();
|
||||||
|
memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique
|
||||||
|
temp[4] = 0; // attempt and flags
|
||||||
|
|
||||||
|
sprintf((char *) &temp[5], "%s: %s", self_name, &command[7]); // <sender>: <msg>
|
||||||
|
temp[5 + MAX_TEXT_LEN] = 0; // truncate if too long
|
||||||
|
|
||||||
|
int len = strlen((char *) &temp[5]);
|
||||||
|
auto pkt = createGroupDatagram(PAYLOAD_TYPE_GRP_TXT, *_public, temp, 5 + len);
|
||||||
|
if (pkt) {
|
||||||
|
sendFlood(pkt);
|
||||||
|
Serial.println(" Sent.");
|
||||||
|
} else {
|
||||||
|
Serial.println(" ERROR: unable to send");
|
||||||
|
}
|
||||||
} else if (memcmp(command, "list", 4) == 0) { // show Contact list, by most recent
|
} else if (memcmp(command, "list", 4) == 0) { // show Contact list, by most recent
|
||||||
int n = 0;
|
int n = 0;
|
||||||
if (command[4] == ' ') { // optional param, last 'N'
|
if (command[4] == ' ') { // optional param, last 'N'
|
||||||
@@ -313,6 +342,7 @@ public:
|
|||||||
Serial.println(" send <text>");
|
Serial.println(" send <text>");
|
||||||
Serial.println(" advert");
|
Serial.println(" advert");
|
||||||
Serial.println(" reset path");
|
Serial.println(" reset path");
|
||||||
|
Serial.println(" public <text>");
|
||||||
} else {
|
} else {
|
||||||
Serial.print(" ERROR: unknown command: "); Serial.println(command);
|
Serial.print(" ERROR: unknown command: "); Serial.println(command);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,12 +96,14 @@ extends = Heltec_lora32_v3
|
|||||||
build_flags =
|
build_flags =
|
||||||
${Heltec_lora32_v3.build_flags}
|
${Heltec_lora32_v3.build_flags}
|
||||||
-D MAX_CONTACTS=100
|
-D MAX_CONTACTS=100
|
||||||
|
-D MAX_CHANNELS=1
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
; -D MESH_DEBUG=1
|
; -D MESH_DEBUG=1
|
||||||
build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
|
build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${Heltec_lora32_v3.lib_deps}
|
${Heltec_lora32_v3.lib_deps}
|
||||||
adafruit/RTClib @ ^2.1.3
|
adafruit/RTClib @ ^2.1.3
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
[env:Heltec_v3_test_admin]
|
[env:Heltec_v3_test_admin]
|
||||||
extends = Heltec_lora32_v3
|
extends = Heltec_lora32_v3
|
||||||
@@ -261,9 +263,11 @@ extends = rak4631
|
|||||||
build_flags =
|
build_flags =
|
||||||
${rak4631.build_flags}
|
${rak4631.build_flags}
|
||||||
-D MAX_CONTACTS=100
|
-D MAX_CONTACTS=100
|
||||||
|
-D MAX_CHANNELS=1
|
||||||
-D MESH_PACKET_LOGGING=1
|
-D MESH_PACKET_LOGGING=1
|
||||||
-D MESH_DEBUG=1
|
-D MESH_DEBUG=1
|
||||||
build_src_filter = ${rak4631.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
|
build_src_filter = ${rak4631.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${rak4631.lib_deps}
|
${rak4631.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
adafruit/RTClib @ ^2.1.3
|
adafruit/RTClib @ ^2.1.3
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include <helpers/BaseChatMesh.h>
|
#include <helpers/BaseChatMesh.h>
|
||||||
|
#include <base64.hpp>
|
||||||
|
#include <Utils.h>
|
||||||
|
|
||||||
mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name) {
|
mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name) {
|
||||||
uint8_t app_data[MAX_ADVERT_DATA_SIZE];
|
uint8_t app_data[MAX_ADVERT_DATA_SIZE];
|
||||||
@@ -150,6 +152,30 @@ void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
if (channels[i].hash[0] == hash[0]) {
|
||||||
|
dest[n++] = channels[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseChatMesh::onGroupDataRecv(mesh::Packet* packet, uint8_t type, const mesh::GroupChannel& channel, uint8_t* data, size_t len) {
|
||||||
|
uint8_t txt_type = data[4];
|
||||||
|
if (type == PAYLOAD_TYPE_GRP_TXT && len > 5 && (txt_type >> 2) == 0) { // 0 = plain text msg
|
||||||
|
uint32_t timestamp;
|
||||||
|
memcpy(×tamp, data, 4);
|
||||||
|
|
||||||
|
// len can be > original length, but 'text' will be padded with zeroes
|
||||||
|
data[len] = 0; // need to make a C string again, with null terminator
|
||||||
|
|
||||||
|
// notify UI of this new message
|
||||||
|
onChannelMessageRecv(channel, packet->isRouteFlood() ? packet->path_len : -1, timestamp, (const char *) &data[5]); // let UI know
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mesh::Packet* BaseChatMesh::composeMsgPacket(const ContactInfo& recipient, uint8_t attempt, const char *text, uint32_t& expected_ack) {
|
mesh::Packet* BaseChatMesh::composeMsgPacket(const ContactInfo& recipient, uint8_t attempt, const char *text, uint32_t& expected_ack) {
|
||||||
int text_len = strlen(text);
|
int text_len = strlen(text);
|
||||||
if (text_len > MAX_TEXT_LEN) return NULL;
|
if (text_len > MAX_TEXT_LEN) return NULL;
|
||||||
@@ -240,6 +266,21 @@ bool BaseChatMesh::addContact(const ContactInfo& contact) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mesh::GroupChannel* BaseChatMesh::addChannel(const char* psk_base64) {
|
||||||
|
if (num_channels < MAX_CHANNELS) {
|
||||||
|
auto dest = &channels[num_channels];
|
||||||
|
|
||||||
|
memset(dest->secret, 0, sizeof(dest->secret));
|
||||||
|
int len = decode_base64((unsigned char *) psk_base64, strlen(psk_base64), dest->secret);
|
||||||
|
if (len == 32 || len == 16) {
|
||||||
|
mesh::Utils::sha256(dest->hash, sizeof(dest->hash), dest->secret, len);
|
||||||
|
num_channels++;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bool ContactsIterator::hasNext(const BaseChatMesh* mesh, ContactInfo& dest) {
|
bool ContactsIterator::hasNext(const BaseChatMesh* mesh, ContactInfo& dest) {
|
||||||
if (next_idx >= mesh->num_contacts) return false;
|
if (next_idx >= mesh->num_contacts) return false;
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ class BaseChatMesh : public mesh::Mesh {
|
|||||||
int sort_array[MAX_CONTACTS];
|
int sort_array[MAX_CONTACTS];
|
||||||
int matching_peer_indexes[MAX_SEARCH_RESULTS];
|
int matching_peer_indexes[MAX_SEARCH_RESULTS];
|
||||||
unsigned long txt_send_timeout;
|
unsigned long txt_send_timeout;
|
||||||
|
mesh::GroupChannel channels[MAX_CHANNELS];
|
||||||
|
int num_channels;
|
||||||
|
|
||||||
mesh::Packet* composeMsgPacket(const ContactInfo& recipient, uint8_t attempt, const char *text, uint32_t& expected_ack);
|
mesh::Packet* composeMsgPacket(const ContactInfo& recipient, uint8_t attempt, const char *text, uint32_t& expected_ack);
|
||||||
|
|
||||||
@@ -56,6 +58,7 @@ protected:
|
|||||||
: mesh::Mesh(radio, ms, rng, rtc, mgr, tables)
|
: mesh::Mesh(radio, ms, rng, rtc, mgr, tables)
|
||||||
{
|
{
|
||||||
num_contacts = 0;
|
num_contacts = 0;
|
||||||
|
num_channels = 0;
|
||||||
txt_send_timeout = 0;
|
txt_send_timeout = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +70,7 @@ protected:
|
|||||||
virtual uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const = 0;
|
virtual uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const = 0;
|
||||||
virtual uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const = 0;
|
virtual uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const = 0;
|
||||||
virtual void onSendTimeout() = 0;
|
virtual void onSendTimeout() = 0;
|
||||||
|
virtual void onChannelMessageRecv(const mesh::GroupChannel& channel, int in_path_len, uint32_t timestamp, const char *text) = 0;
|
||||||
|
|
||||||
// Mesh overrides
|
// Mesh overrides
|
||||||
void onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len) override;
|
void onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len) override;
|
||||||
@@ -75,6 +79,8 @@ protected:
|
|||||||
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override;
|
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override;
|
||||||
bool onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override;
|
bool onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override;
|
||||||
void onAckRecv(mesh::Packet* packet, uint32_t ack_crc) override;
|
void onAckRecv(mesh::Packet* packet, uint32_t ack_crc) override;
|
||||||
|
int searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel channels[], int max_matches) override;
|
||||||
|
void onGroupDataRecv(mesh::Packet* packet, uint8_t type, const mesh::GroupChannel& channel, uint8_t* data, size_t len) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
mesh::Packet* createSelfAdvert(const char* name);
|
mesh::Packet* createSelfAdvert(const char* name);
|
||||||
@@ -83,6 +89,7 @@ public:
|
|||||||
void scanRecentContacts(int last_n, ContactVisitor* visitor);
|
void scanRecentContacts(int last_n, ContactVisitor* visitor);
|
||||||
ContactInfo* searchContactsByPrefix(const char* name_prefix);
|
ContactInfo* searchContactsByPrefix(const char* name_prefix);
|
||||||
bool addContact(const ContactInfo& contact);
|
bool addContact(const ContactInfo& contact);
|
||||||
|
mesh::GroupChannel* addChannel(const char* psk_base64);
|
||||||
|
|
||||||
void loop();
|
void loop();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user