mirror of
https://github.com/agessaman/MeshCore.git
synced 2026-09-01 22:18:34 +00:00
Merge pull request #3279 from fdlamotte/node_discover_ui
Node discover UI
This commit is contained in:
@@ -136,6 +136,10 @@
|
||||
#define ERR_CODE_FILE_IO_ERROR 5
|
||||
#define ERR_CODE_ILLEGAL_ARG 6
|
||||
|
||||
// Copied from simple_repeater (could probably be shared)
|
||||
#define CTL_TYPE_NODE_DISCOVER_REQ 0x80
|
||||
#define CTL_TYPE_NODE_DISCOVER_RESP 0x90
|
||||
|
||||
#define MAX_SIGN_DATA_LEN (8 * 1024) // 8K
|
||||
|
||||
// Auto-add config bitmask
|
||||
@@ -405,6 +409,53 @@ int MyMesh::getRecentlyHeard(AdvertPath dest[], int max_num) {
|
||||
return max_num;
|
||||
}
|
||||
|
||||
#if defined(DISPLAY_CLASS) && !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
int MyMesh::getDiscoveredNodes(DiscoveredNode nodes[], int max_num) {
|
||||
if (max_num > DISCOVERED_NODES_TABLE_SIZE) max_num = DISCOVERED_NODES_TABLE_SIZE;
|
||||
if (max_num > disc_nodes_count) max_num = disc_nodes_count;
|
||||
|
||||
for (int i = 0; i < max_num; i++) {
|
||||
nodes[i] = discovered_nodes[i];
|
||||
}
|
||||
return max_num;
|
||||
}
|
||||
|
||||
bool MyMesh::requestRepeatersDiscovery() {
|
||||
uint8_t cmd_bytes[6];
|
||||
cmd_bytes[0] = CTL_TYPE_NODE_DISCOVER_REQ | 1; // DISCOVER_REQ | prefix only
|
||||
cmd_bytes[1] = 0xFF; // Repeaters
|
||||
getRNG()->random(&cmd_bytes[2], 4); // tag
|
||||
disc_nodes_count = 0;
|
||||
disc_node_req_tag = *((uint32_t*)&cmd_bytes[2]);
|
||||
mesh::Packet* req = createControlData(cmd_bytes, sizeof(cmd_bytes));
|
||||
if (req) {
|
||||
sendZeroHop(req);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MyMesh::checkControlDataForPendingDiscovery(uint8_t payload[], size_t p_len) {
|
||||
if ((p_len < 12)
|
||||
|| (payload[0] & 0xF0 != CTL_TYPE_NODE_DISCOVER_RESP)
|
||||
|| (disc_nodes_count >= DISCOVERED_NODES_TABLE_SIZE)
|
||||
|| (memcmp(&payload[2], &disc_node_req_tag, 4))) {
|
||||
return;
|
||||
}
|
||||
memcpy(&discovered_nodes[disc_nodes_count].pubkey_prefix, &payload[6], 8);
|
||||
discovered_nodes[disc_nodes_count].type = payload[0] & 0xF;
|
||||
discovered_nodes[disc_nodes_count].snr_out = ((int8_t)payload[1]) / 4.0;
|
||||
discovered_nodes[disc_nodes_count].snr_in = _radio->getLastSNR();
|
||||
ContactInfo* c = lookupContactByPubKey(&payload[6], 8);
|
||||
if (c != NULL) {
|
||||
strncpy(discovered_nodes[disc_nodes_count].name, c->name, 32);
|
||||
} else {
|
||||
discovered_nodes[disc_nodes_count].name[0] = 0;
|
||||
}
|
||||
disc_nodes_count ++;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MyMesh::onContactPathUpdated(const ContactInfo &contact) {
|
||||
out_frame[0] = PUSH_CODE_PATH_UPDATED;
|
||||
memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE);
|
||||
@@ -796,6 +847,9 @@ void MyMesh::onControlDataRecv(mesh::Packet *packet) {
|
||||
MESH_DEBUG_PRINTLN("onControlDataRecv(), payload_len too long: %d", packet->payload_len);
|
||||
return;
|
||||
}
|
||||
#if defined(DISPLAY_CLASS) && !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
checkControlDataForPendingDiscovery(packet->payload, packet->payload_len);
|
||||
#endif
|
||||
int i = 0;
|
||||
out_frame[i++] = PUSH_CODE_CONTROL_DATA;
|
||||
out_frame[i++] = (int8_t)(_radio->getLastSNR() * 4);
|
||||
|
||||
@@ -84,6 +84,16 @@ struct AdvertPath {
|
||||
uint8_t path[MAX_PATH_SIZE];
|
||||
};
|
||||
|
||||
#if defined(DISPLAY_CLASS) && !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
struct DiscoveredNode {
|
||||
uint8_t pubkey_prefix[9];
|
||||
float snr_in;
|
||||
float snr_out;
|
||||
char name[32];
|
||||
uint8_t type;
|
||||
};
|
||||
#endif
|
||||
|
||||
class MyMesh : public BaseChatMesh, public DataStoreHost {
|
||||
public:
|
||||
MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store, AbstractUITask* ui=NULL);
|
||||
@@ -102,6 +112,11 @@ public:
|
||||
|
||||
int getRecentlyHeard(AdvertPath dest[], int max_num);
|
||||
|
||||
#if defined(DISPLAY_CLASS) && !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
bool requestRepeatersDiscovery();
|
||||
int getDiscoveredNodes(DiscoveredNode nodes[], int max_num);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
float getAirtimeBudgetFactor() const override;
|
||||
int getInterferenceThreshold() const override;
|
||||
@@ -261,6 +276,19 @@ private:
|
||||
|
||||
#define ADVERT_PATH_TABLE_SIZE 16
|
||||
AdvertPath advert_paths[ADVERT_PATH_TABLE_SIZE]; // circular table
|
||||
|
||||
#if defined(DISPLAY_CLASS) && !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
#ifdef UI_RECENT_LIST_SIZE
|
||||
#define DISCOVERED_NODES_TABLE_SIZE UI_RECENT_LIST_SIZE
|
||||
#else
|
||||
#define DISCOVERED_NODES_TABLE_SIZE 4
|
||||
#endif
|
||||
DiscoveredNode discovered_nodes[DISCOVERED_NODES_TABLE_SIZE]; // not circular, latest discovered nodes are not kept
|
||||
uint32_t disc_node_req_tag = 0;
|
||||
uint32_t disc_nodes_count = 0;
|
||||
|
||||
void checkControlDataForPendingDiscovery(uint8_t payload[], size_t p_len);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern MyMesh the_mesh;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#define LONG_PRESS_MILLIS 1200
|
||||
|
||||
// Used both for recent adverts and discovered nodes
|
||||
#ifndef UI_RECENT_LIST_SIZE
|
||||
#define UI_RECENT_LIST_SIZE 4
|
||||
#endif
|
||||
@@ -102,6 +103,9 @@ class HomeScreen : public UIScreen {
|
||||
#if UI_SENSORS_PAGE == 1
|
||||
SENSORS,
|
||||
#endif
|
||||
#if !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
DISCOVERY,
|
||||
#endif
|
||||
#ifndef UI_NO_HIBERNATE
|
||||
SHUTDOWN,
|
||||
#endif
|
||||
@@ -115,7 +119,11 @@ class HomeScreen : public UIScreen {
|
||||
uint8_t _page;
|
||||
bool _shutdown_init;
|
||||
AdvertPath recent[UI_RECENT_LIST_SIZE];
|
||||
|
||||
#if !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
DiscoveredNode discovered[UI_RECENT_LIST_SIZE];
|
||||
uint32_t discovery_req_time = 0;
|
||||
bool discovery_disp_names = true; // by default desplay names if available (removes SNR_O)
|
||||
#endif
|
||||
|
||||
void renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts) {
|
||||
// Convert millivolts to percentage
|
||||
@@ -461,6 +469,40 @@ public:
|
||||
if (sensors_scroll) sensors_scroll_offset = (sensors_scroll_offset+1)%sensors_nb;
|
||||
else sensors_scroll_offset = 0;
|
||||
#endif
|
||||
#if !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
} else if (_page == HomePage::DISCOVERY) {
|
||||
int count = the_mesh.getDiscoveredNodes(discovered, UI_RECENT_LIST_SIZE);
|
||||
display.setColor(UIColor::primary_txt);
|
||||
int y = 20;
|
||||
for (int i = 0; i < count; i++, y += 11) {
|
||||
char name[32];
|
||||
auto a = &discovered[i];
|
||||
if ((a->name[0] == 0) || !discovery_disp_names) {
|
||||
mesh::Utils::toHex(name, a->pubkey_prefix, 4);
|
||||
} else {
|
||||
strncpy(name, a->name, 32);
|
||||
}
|
||||
char filtered_name[sizeof(name)];
|
||||
char snr_s[12];
|
||||
if (strlen(name) <= 8) { // display snr_o
|
||||
sprintf(snr_s, "%02.1f>%02.1f", a->snr_out, a->snr_in);
|
||||
} else {
|
||||
sprintf(snr_s, "%02.1f", a->snr_in);
|
||||
}
|
||||
int snr_width = display.getTextWidth(snr_s);
|
||||
int max_name_width = display.width() - snr_width - 1;
|
||||
display.translateUTF8ToBlocks(filtered_name, name, sizeof(filtered_name));
|
||||
display.drawTextEllipsized(0, y, max_name_width, filtered_name);
|
||||
display.setCursor(display.width() - snr_width - 1, y);
|
||||
display.print(snr_s);
|
||||
}
|
||||
if (millis() < discovery_req_time + 5000) {
|
||||
return 1000; // more frequent updates just after req
|
||||
} else if (count < UI_RECENT_LIST_SIZE -1) { // show only 5 sec after last disc
|
||||
y = 10 + 11 * UI_RECENT_LIST_SIZE;
|
||||
display.drawTextCentered(display.width() / 2, y, "discover: " PRESS_LABEL);
|
||||
}
|
||||
#endif
|
||||
#ifndef UI_NO_HIBERNATE
|
||||
} else if (_page == HomePage::SHUTDOWN) {
|
||||
display.setColor(UIColor::corp_blue);
|
||||
@@ -488,6 +530,11 @@ public:
|
||||
if (_page == HomePage::RECENT) {
|
||||
_task->showAlert("Recent adverts", 800);
|
||||
}
|
||||
#if !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
if (_page == HomePage::DISCOVERY) {
|
||||
_task->showAlert("Repeater disc", 800);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
if (c == KEY_ENTER && _page == HomePage::BLUETOOTH) {
|
||||
@@ -520,6 +567,19 @@ public:
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
if (c == KEY_ENTER && _page == HomePage::DISCOVERY) {
|
||||
if (millis() > discovery_req_time + 5000) { // rate limiter
|
||||
the_mesh.requestRepeatersDiscovery();
|
||||
discovery_req_time = millis();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (c == KEY_SELECT && _page == HomePage::DISCOVERY) {
|
||||
discovery_disp_names = !discovery_disp_names;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifndef UI_NO_HIBERNATE
|
||||
if (c == KEY_ENTER && _page == HomePage::SHUTDOWN) {
|
||||
_shutdown_init = true; // need to wait for button to be released
|
||||
|
||||
Reference in New Issue
Block a user