mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-10-05 18:48:31 +00:00
Merge pull request #3431 from meshcore-dev/abstract-ui-overhaul
Abstract UI overhaul
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#endif
|
||||
|
||||
#include "NodePrefs.h"
|
||||
#include "MyMesh.h"
|
||||
|
||||
enum class UIEventType {
|
||||
none,
|
||||
@@ -22,25 +23,21 @@ enum class UIEventType {
|
||||
ack
|
||||
};
|
||||
|
||||
class AbstractUITask {
|
||||
class AbstractUITask : public MyMesh::Listener {
|
||||
protected:
|
||||
mesh::MainBoard* _board;
|
||||
MultiSerialInterface* _interfaceManager;
|
||||
bool _connected;
|
||||
|
||||
AbstractUITask(mesh::MainBoard* board, MultiSerialInterface* interfaceManager) : _board(board), _interfaceManager(interfaceManager) {
|
||||
_connected = false;
|
||||
}
|
||||
|
||||
public:
|
||||
void setHasConnection(bool connected) { _connected = connected; }
|
||||
bool hasConnection() const { return _connected; }
|
||||
bool hasConnection() const { return _interfaceManager->isConnected(); }
|
||||
uint16_t getBattMilliVolts() const { return _board->getBattMilliVolts(); }
|
||||
bool isBluetoothEnabled() const { return _interfaceManager->isBluetoothEnabled(); }
|
||||
void enableBluetooth() { _interfaceManager->enableBluetooth(); }
|
||||
void disableBluetooth() { _interfaceManager->disableBluetooth(); }
|
||||
virtual void msgRead(int msgcount) = 0;
|
||||
virtual void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) = 0;
|
||||
|
||||
virtual void notify(UIEventType t = UIEventType::none) = 0;
|
||||
virtual void loop() = 0;
|
||||
};
|
||||
|
||||
@@ -139,10 +139,6 @@
|
||||
#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
|
||||
@@ -368,10 +364,6 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path
|
||||
memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE);
|
||||
_serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE);
|
||||
}
|
||||
} else {
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (_ui) _ui->notify(UIEventType::newContactMessage);
|
||||
#endif
|
||||
}
|
||||
|
||||
// add inbound-path to mem cache
|
||||
@@ -395,6 +387,8 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path
|
||||
p->path_len = mesh::Packet::copyPath(p->path, path, path_len);
|
||||
}
|
||||
|
||||
if (_listener) _listener->onDiscoveredContact(contact, is_new, path_len, path);
|
||||
|
||||
if (!is_new) dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); // only schedule lazy write for contacts that are in contacts[]
|
||||
}
|
||||
|
||||
@@ -412,53 +406,6 @@ 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);
|
||||
@@ -468,6 +415,11 @@ void MyMesh::onContactPathUpdated(const ContactInfo &contact) {
|
||||
}
|
||||
|
||||
ContactInfo* MyMesh::processAck(const uint8_t *data) {
|
||||
if (_listener) {
|
||||
uint32_t ack_crc;
|
||||
memcpy(&ack_crc, data, 4);
|
||||
_listener->onACKRecv(ack_crc);
|
||||
}
|
||||
// see if matches any in a table
|
||||
for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) {
|
||||
if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient
|
||||
@@ -520,16 +472,10 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe
|
||||
_serial->writeFrame(frame, 1);
|
||||
}
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
// we only want to show text messages on display, not cli data
|
||||
bool should_display = txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN;
|
||||
if (should_display && _ui) {
|
||||
_ui->newMsg(path_len, from.name, text, offline_queue_len);
|
||||
if (!_serial->isConnected()) {
|
||||
_ui->notify(UIEventType::contactMessage);
|
||||
}
|
||||
if (_listener) {
|
||||
_listener->onMessageRecv(pkt, from, txt_type, sender_timestamp, text);
|
||||
_listener->onQueueSizeChanged(offline_queue_len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MyMesh::filterRecvFloodPacket(mesh::Packet* packet) {
|
||||
@@ -640,20 +586,16 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe
|
||||
uint8_t frame[1];
|
||||
frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle'
|
||||
_serial->writeFrame(frame, 1);
|
||||
} else {
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (_ui) _ui->notify(UIEventType::channelMessage);
|
||||
#endif
|
||||
}
|
||||
#ifdef DISPLAY_CLASS
|
||||
// Get the channel name from the channel index
|
||||
const char *channel_name = "Unknown";
|
||||
ChannelDetails channel_details;
|
||||
if (getChannel(channel_idx, channel_details)) {
|
||||
channel_name = channel_details.name;
|
||||
if (_listener) {
|
||||
// Get the channel name from the channel index
|
||||
ChannelDetails channel_details;
|
||||
if (!getChannel(channel_idx, channel_details)) {
|
||||
strcpy(channel_details.name, "Unknown");
|
||||
}
|
||||
_listener->onChannelMessageRecv(pkt, channel_details, text);
|
||||
_listener->onQueueSizeChanged(offline_queue_len);
|
||||
}
|
||||
if (_ui) _ui->newMsg(path_len, channel_name, text, offline_queue_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MyMesh::onChannelDataRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint16_t data_type,
|
||||
@@ -689,6 +631,9 @@ void MyMesh::onChannelDataRecv(const mesh::GroupChannel &channel, mesh::Packet *
|
||||
frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle'
|
||||
_serial->writeFrame(frame, 1);
|
||||
}
|
||||
if (_listener) {
|
||||
_listener->onChannelDataRecv(pkt, channel, data_type, data, data_len);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data,
|
||||
@@ -736,6 +681,8 @@ uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_tim
|
||||
memcpy(&reply[4], telemetry.getBuffer(), tlen);
|
||||
return 4 + tlen;
|
||||
}
|
||||
} else if (_listener) {
|
||||
return _listener->onUnhandledRequest(contact, sender_timestamp, data, len, reply);
|
||||
}
|
||||
return 0; // unknown
|
||||
}
|
||||
@@ -811,6 +758,8 @@ 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 (_listener && len > 4) {
|
||||
_listener->onUnhandledResponse(contact, tag, &data[4], len - 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,9 +799,6 @@ 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);
|
||||
@@ -866,6 +812,8 @@ void MyMesh::onControlDataRecv(mesh::Packet *packet) {
|
||||
} else {
|
||||
MESH_DEBUG_PRINTLN("onControlDataRecv(), data received while app offline");
|
||||
}
|
||||
|
||||
if (_listener) _listener->onControlDataRecv(packet);
|
||||
}
|
||||
|
||||
void MyMesh::onRawDataRecv(mesh::Packet *packet) {
|
||||
@@ -886,6 +834,9 @@ void MyMesh::onRawDataRecv(mesh::Packet *packet) {
|
||||
} else {
|
||||
MESH_DEBUG_PRINTLN("onRawDataRecv(), data received while app offline");
|
||||
}
|
||||
if (_listener) {
|
||||
_listener->onRawDataRecv(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags,
|
||||
@@ -916,6 +867,9 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code,
|
||||
} else {
|
||||
MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline");
|
||||
}
|
||||
if (_listener) {
|
||||
_listener->onTraceRecv(packet, tag, auth_code, flags, path_snrs, path_hashes, path_len);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const {
|
||||
@@ -930,9 +884,9 @@ uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t
|
||||
|
||||
void MyMesh::onSendTimeout() {}
|
||||
|
||||
MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store, AbstractUITask* ui)
|
||||
MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store)
|
||||
: BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables),
|
||||
_serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4), _store(&store), _ui(ui), _iter(0) {
|
||||
_serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4), _store(&store), _listener(NULL), _iter(0) {
|
||||
_iter_started = false;
|
||||
_cli_rescue = false;
|
||||
cli_command[0] = 0;
|
||||
@@ -975,7 +929,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
||||
#endif
|
||||
}
|
||||
|
||||
void MyMesh::begin(bool has_display) {
|
||||
void MyMesh::begin() {
|
||||
BaseChatMesh::begin();
|
||||
|
||||
if (!_store->loadMainIdentity(self_id)) {
|
||||
@@ -1027,29 +981,12 @@ void MyMesh::begin(bool has_display) {
|
||||
_prefs.gps_enabled = constrain(_prefs.gps_enabled, 0, 1); // Ensure boolean 0 or 1
|
||||
_prefs.gps_interval = constrain(_prefs.gps_interval, 0, 86400); // Max 24 hours
|
||||
|
||||
#ifdef BLE_PIN_CODE // 123456 by default
|
||||
if (_prefs.ble_pin == 0) {
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (has_display && BLE_PIN_CODE == 123456) {
|
||||
StdRNG rng;
|
||||
_active_ble_pin = rng.nextInt(100000, 999999); // random pin each session
|
||||
} else {
|
||||
_active_ble_pin = BLE_PIN_CODE; // otherwise static pin
|
||||
}
|
||||
#else
|
||||
_active_ble_pin = BLE_PIN_CODE; // otherwise static pin
|
||||
#endif
|
||||
} else {
|
||||
_active_ble_pin = _prefs.ble_pin;
|
||||
}
|
||||
#else
|
||||
_active_ble_pin = 0;
|
||||
#endif
|
||||
_active_ble_pin = _prefs.ble_pin;
|
||||
|
||||
resetContacts();
|
||||
_store->loadContacts(this);
|
||||
bootstrapRTCfromContacts();
|
||||
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
|
||||
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure public channel
|
||||
_store->loadChannels(this);
|
||||
|
||||
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
|
||||
@@ -1071,6 +1008,9 @@ NodePrefs *MyMesh::getNodePrefs() {
|
||||
uint32_t MyMesh::getBLEPin() {
|
||||
return _active_ble_pin;
|
||||
}
|
||||
void MyMesh::setBLEPin(uint32_t active_pin) {
|
||||
_active_ble_pin = active_pin;
|
||||
}
|
||||
|
||||
struct FreqRange {
|
||||
uint32_t lower_freq, upper_freq;
|
||||
@@ -1463,9 +1403,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
int out_len;
|
||||
if ((out_len = getFromOfflineQueue(out_frame)) > 0) {
|
||||
_serial->writeFrame(out_frame, out_len);
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (_ui) _ui->msgRead(offline_queue_len);
|
||||
#endif
|
||||
if (_listener) _listener->onQueueSizeChanged(offline_queue_len);
|
||||
} else {
|
||||
out_frame[0] = RESP_CODE_NO_MORE_MESSAGES;
|
||||
_serial->writeFrame(out_frame, 1);
|
||||
@@ -2480,10 +2418,6 @@ void MyMesh::loop() {
|
||||
saveContacts();
|
||||
dirty_contacts_expiry = 0;
|
||||
}
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (_ui) _ui->setHasConnection(_serial->isConnected());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MyMesh::advert() {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Mesh.h>
|
||||
#include "AbstractUITask.h"
|
||||
|
||||
/*------------ Frame Protocol --------------*/
|
||||
#define FIRMWARE_VER_CODE 14
|
||||
@@ -76,6 +75,10 @@
|
||||
#define REQ_TYPE_KEEP_ALIVE 0x02
|
||||
#define REQ_TYPE_GET_TELEMETRY_DATA 0x03
|
||||
|
||||
// Copied from simple_repeater
|
||||
#define CTL_TYPE_NODE_DISCOVER_REQ 0x80
|
||||
#define CTL_TYPE_NODE_DISCOVER_RESP 0x90
|
||||
|
||||
struct AdvertPath {
|
||||
uint8_t pubkey_prefix[7];
|
||||
uint8_t path_len;
|
||||
@@ -84,26 +87,37 @@ 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);
|
||||
class Listener {
|
||||
public:
|
||||
virtual void onMessageRecv(mesh::Packet *pkt, const ContactInfo &from, uint8_t txt_type, uint32_t sender_timestamp, const char* text) = 0;
|
||||
virtual void onChannelMessageRecv(mesh::Packet *pkt, ChannelDetails& channel_details, const char* text) = 0;
|
||||
virtual void onQueueSizeChanged(int msgcount) = 0;
|
||||
virtual void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) { }
|
||||
virtual void onControlDataRecv(const mesh::Packet* pkt) { }
|
||||
virtual void onChannelDataRecv(mesh::Packet *pkt, const mesh::GroupChannel &channel, uint16_t data_type,
|
||||
const uint8_t *data, size_t data_len) { }
|
||||
virtual void onACKRecv(uint32_t ack_crc) { }
|
||||
virtual uint8_t onUnhandledRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data,
|
||||
uint8_t len, uint8_t *reply) { return 0; /* unknown request type */ }
|
||||
virtual void onUnhandledResponse(const ContactInfo &from, uint32_t tag, const uint8_t* data, uint8_t len) { }
|
||||
virtual void onTraceRecv(mesh::Packet *pkt, uint32_t tag, uint32_t auth_code, uint8_t flags,
|
||||
const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) { }
|
||||
virtual void onRawDataRecv(mesh::Packet *pkt) { }
|
||||
virtual ~Listener() { }
|
||||
};
|
||||
|
||||
void begin(bool has_display);
|
||||
MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store);
|
||||
|
||||
void begin();
|
||||
void startInterface(BaseSerialInterface &serial);
|
||||
void setListener(Listener* listener) { _listener = listener; }
|
||||
|
||||
const char *getNodeName();
|
||||
NodePrefs *getNodePrefs();
|
||||
uint32_t getBLEPin();
|
||||
void setBLEPin(uint32_t active_pin);
|
||||
|
||||
void loop();
|
||||
void handleCmdFrame(size_t len);
|
||||
@@ -112,11 +126,6 @@ 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;
|
||||
@@ -237,7 +246,7 @@ private:
|
||||
uint32_t pending_telemetry, pending_discovery; // pending _TELEMETRY_REQ
|
||||
uint32_t pending_req; // pending _BINARY_REQ
|
||||
BaseSerialInterface *_serial;
|
||||
AbstractUITask* _ui;
|
||||
Listener* _listener;
|
||||
|
||||
ContactsIterator _iter;
|
||||
uint32_t _iter_filter_since;
|
||||
@@ -279,19 +288,6 @@ 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;
|
||||
|
||||
@@ -114,11 +114,7 @@ MultiSerialInterface interface_manager;
|
||||
|
||||
StdRNG fast_rng;
|
||||
SimpleMeshTables tables;
|
||||
MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables, store
|
||||
#ifdef DISPLAY_CLASS
|
||||
, &ui_task
|
||||
#endif
|
||||
);
|
||||
MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables, store);
|
||||
|
||||
/* END GLOBAL OBJECTS */
|
||||
|
||||
@@ -176,37 +172,38 @@ void setup() {
|
||||
#endif
|
||||
#endif
|
||||
store.begin();
|
||||
the_mesh.begin(
|
||||
#ifdef DISPLAY_CLASS
|
||||
disp != NULL
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
the_mesh.begin();
|
||||
#elif defined(RP2040_PLATFORM)
|
||||
LittleFS.begin();
|
||||
store.begin();
|
||||
the_mesh.begin(
|
||||
#ifdef DISPLAY_CLASS
|
||||
disp != NULL
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
the_mesh.begin();
|
||||
#elif defined(ESP32)
|
||||
SPIFFS.begin(true);
|
||||
store.begin();
|
||||
the_mesh.begin(
|
||||
#ifdef DISPLAY_CLASS
|
||||
disp != NULL
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
the_mesh.begin();
|
||||
#else
|
||||
#error "need to define filesystem"
|
||||
#endif
|
||||
|
||||
#ifdef BLE_PIN_CODE // 123456 by default
|
||||
if (the_mesh.getNodePrefs()->ble_pin == 0) {
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (disp != NULL && BLE_PIN_CODE == 123456) {
|
||||
StdRNG rng;
|
||||
the_mesh.setBLEPin(rng.nextInt(100000, 999999)); // random pin each session
|
||||
} else {
|
||||
the_mesh.setBLEPin(BLE_PIN_CODE); // otherwise static pin
|
||||
}
|
||||
#else
|
||||
the_mesh.setBLEPin(BLE_PIN_CODE); // otherwise static pin
|
||||
#endif
|
||||
} else {
|
||||
the_mesh.setBLEPin(the_mesh.getNodePrefs()->ble_pin);
|
||||
}
|
||||
#else
|
||||
the_mesh.setBLEPin(0);
|
||||
#endif
|
||||
|
||||
// add bluetooth interface
|
||||
#if defined(BLE_PIN_CODE)
|
||||
bluetooth_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin());
|
||||
@@ -286,6 +283,7 @@ void setup() {
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.begin(disp, &sensors, the_mesh.getNodePrefs()); // still want to pass this in as dependency, as prefs might be moved
|
||||
the_mesh.setListener(&ui_task);
|
||||
#endif
|
||||
|
||||
board.onBootComplete();
|
||||
|
||||
@@ -99,7 +99,7 @@ class HomeScreen : public UIScreen {
|
||||
#if UI_SENSORS_PAGE == 1
|
||||
SENSORS,
|
||||
#endif
|
||||
#if !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
#if UI_DISCOVER_SCREEN
|
||||
DISCOVERY,
|
||||
#endif
|
||||
#ifndef UI_NO_HIBERNATE
|
||||
@@ -115,8 +115,10 @@ 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];
|
||||
#if UI_DISCOVER_SCREEN
|
||||
DiscoveredNode discovered[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;
|
||||
uint32_t discovery_req_time = 0;
|
||||
bool discovery_disp_names = true; // by default desplay names if available (removes SNR_O)
|
||||
#endif
|
||||
@@ -206,6 +208,40 @@ public:
|
||||
: _task(task), _rtc(rtc), _sensors(sensors), _node_prefs(node_prefs), _page(0),
|
||||
_shutdown_init(false), sensors_lpp(200) { }
|
||||
|
||||
#if UI_DISCOVER_SCREEN
|
||||
bool sendDiscoverRequest() {
|
||||
uint8_t cmd_bytes[6];
|
||||
cmd_bytes[0] = CTL_TYPE_NODE_DISCOVER_REQ | 1; // DISCOVER_REQ | prefix only
|
||||
cmd_bytes[1] = 0xFF; // Repeaters
|
||||
the_mesh.getRNG()->random((uint8_t *) &disc_node_req_tag, 4); // generate random tag
|
||||
memcpy(&cmd_bytes[2], &disc_node_req_tag, 4);
|
||||
disc_nodes_count = 0;
|
||||
mesh::Packet* req = the_mesh.createControlData(cmd_bytes, sizeof(cmd_bytes));
|
||||
if (req) {
|
||||
the_mesh.sendZeroHop(req);
|
||||
discovery_req_time = millis();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void handleDiscoverResponse(const mesh::Packet* packet) {
|
||||
if (disc_nodes_count < DISCOVERED_NODES_TABLE_SIZE && memcmp(&packet->payload[2], &disc_node_req_tag, 4) == 0) {
|
||||
auto d = &discovered[disc_nodes_count++];
|
||||
memcpy(d->pubkey_prefix, &packet->payload[6], 8);
|
||||
d->type = packet->payload[0] & 0xF;
|
||||
d->snr_out = ((int8_t)packet->payload[1]) / 4.0;
|
||||
d->snr_in = radio_driver.getLastSNR();
|
||||
ContactInfo* c = the_mesh.lookupContactByPubKey(&packet->payload[6], 8);
|
||||
if (c != NULL) {
|
||||
strncpy(d->name, c->name, 32);
|
||||
} else {
|
||||
d->name[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void poll() override {
|
||||
if (_shutdown_init && !_task->isButtonPressed()) { // must wait for USR button to be released
|
||||
_task->shutdown();
|
||||
@@ -464,9 +500,9 @@ 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))
|
||||
#if UI_DISCOVER_SCREEN
|
||||
} else if (_page == HomePage::DISCOVERY) {
|
||||
int count = the_mesh.getDiscoveredNodes(discovered, UI_RECENT_LIST_SIZE);
|
||||
int count = disc_nodes_count;
|
||||
display.setColor(UIColor::primary_txt);
|
||||
int y = 20;
|
||||
for (int i = 0; i < count; i++, y += 11) {
|
||||
@@ -493,8 +529,8 @@ public:
|
||||
}
|
||||
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;
|
||||
} else if (count < DISCOVERED_NODES_TABLE_SIZE -1) { // show only 5 sec after last disc
|
||||
y = 10 + 11 * DISCOVERED_NODES_TABLE_SIZE;
|
||||
display.drawTextCentered(display.width() / 2, y, "discover: " PRESS_LABEL);
|
||||
}
|
||||
#endif
|
||||
@@ -525,7 +561,7 @@ public:
|
||||
if (_page == HomePage::RECENT) {
|
||||
_task->showAlert("Recent adverts", 800);
|
||||
}
|
||||
#if !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
#if UI_DISCOVER_SCREEN
|
||||
if (_page == HomePage::DISCOVERY) {
|
||||
_task->showAlert("Repeater disc", 800);
|
||||
}
|
||||
@@ -562,11 +598,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if !(defined(UI_NO_DISCOVER_SCREEN) && (UI_NO_DISCOVER_SCREEN + 0 != 0))
|
||||
#if UI_DISCOVER_SCREEN
|
||||
if (c == KEY_ENTER && _page == HomePage::DISCOVERY) {
|
||||
if (millis() > discovery_req_time + 5000) { // rate limiter
|
||||
the_mesh.requestRepeatersDiscovery();
|
||||
discovery_req_time = millis();
|
||||
sendDiscoverRequest();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -751,18 +786,12 @@ switch(t){
|
||||
#endif
|
||||
}
|
||||
|
||||
void UITask::onMessageRecv(mesh::Packet *pkt, const ContactInfo &from, uint8_t txt_type, uint32_t sender_timestamp, const char* text) {
|
||||
// we only want to show text messages on display, not cli data
|
||||
if (!(txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN)) return;
|
||||
|
||||
void UITask::msgRead(int msgcount) {
|
||||
_msgcount = msgcount;
|
||||
if (msgcount == 0) {
|
||||
gotoHomeScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) {
|
||||
_msgcount = msgcount;
|
||||
|
||||
((MsgPreviewScreen *) msg_preview)->addPreview(path_len, from_name, text);
|
||||
uint8_t path_len = pkt->isRouteFlood() ? pkt->path_len : 0xFF;
|
||||
((MsgPreviewScreen *) msg_preview)->addPreview(path_len, from.name, text);
|
||||
setCurrScreen(msg_preview);
|
||||
|
||||
if (_display != NULL) {
|
||||
@@ -774,6 +803,51 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
|
||||
_next_refresh = 100; // trigger refresh
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasConnection()) {
|
||||
notify(UIEventType::contactMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::onChannelMessageRecv(mesh::Packet *pkt, ChannelDetails& channel_details, const char* text) {
|
||||
uint8_t path_len = pkt->isRouteFlood() ? pkt->path_len : 0xFF;
|
||||
((MsgPreviewScreen *) msg_preview)->addPreview(path_len, channel_details.name, text);
|
||||
setCurrScreen(msg_preview);
|
||||
|
||||
if (_display != NULL) {
|
||||
if (!_display->isOn() && !hasConnection()) {
|
||||
_display->turnOn();
|
||||
}
|
||||
if (_display->isOn()) {
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer
|
||||
_next_refresh = 100; // trigger refresh
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasConnection()) {
|
||||
notify(UIEventType::channelMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::onQueueSizeChanged(int msgcount) {
|
||||
_msgcount = msgcount;
|
||||
if (msgcount == 0) {
|
||||
gotoHomeScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
||||
if (!hasConnection()) {
|
||||
notify(UIEventType::newContactMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::onControlDataRecv(const mesh::Packet* packet) {
|
||||
#if UI_DISCOVER_SCREEN
|
||||
if (packet->payload_len >= 14 && (packet->payload[0] & 0xF0) == CTL_TYPE_NODE_DISCOVER_RESP) {
|
||||
((HomeScreen *) home)->handleDiscoverResponse(packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UITask::userLedHandler() {
|
||||
|
||||
@@ -22,6 +22,30 @@
|
||||
#include "../AbstractUITask.h"
|
||||
#include "../NodePrefs.h"
|
||||
|
||||
#ifdef UI_NO_DISCOVER_SCREEN
|
||||
#error "UI_NO_DISCOVER_SCREEN is obsolete - use -D UI_DISCOVER_SCREEN=0 instead"
|
||||
#endif
|
||||
|
||||
#ifndef UI_DISCOVER_SCREEN
|
||||
#define UI_DISCOVER_SCREEN 1
|
||||
#endif
|
||||
|
||||
#if UI_DISCOVER_SCREEN
|
||||
#ifdef UI_RECENT_LIST_SIZE
|
||||
#define DISCOVERED_NODES_TABLE_SIZE UI_RECENT_LIST_SIZE
|
||||
#else
|
||||
#define DISCOVERED_NODES_TABLE_SIZE 4
|
||||
#endif
|
||||
|
||||
struct DiscoveredNode {
|
||||
float snr_in;
|
||||
float snr_out;
|
||||
uint8_t pubkey_prefix[9];
|
||||
uint8_t type;
|
||||
char name[32];
|
||||
};
|
||||
#endif
|
||||
|
||||
class UITask : public AbstractUITask {
|
||||
DisplayDriver* _display;
|
||||
SensorManager* _sensors;
|
||||
@@ -90,10 +114,14 @@ public:
|
||||
bool getGPSState();
|
||||
void toggleGPS();
|
||||
|
||||
// MyMesh::Listener
|
||||
void onMessageRecv(mesh::Packet *pkt, const ContactInfo &from, uint8_t txt_type, uint32_t sender_timestamp, const char* text) override;
|
||||
void onChannelMessageRecv(mesh::Packet *pkt, ChannelDetails& channel_details, const char* text) override;
|
||||
void onQueueSizeChanged(int offline_queue_size) override;
|
||||
void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override;
|
||||
void onControlDataRecv(const mesh::Packet* pkt) override;
|
||||
|
||||
// from AbstractUITask
|
||||
void msgRead(int msgcount) override;
|
||||
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override;
|
||||
void notify(UIEventType t = UIEventType::none) override;
|
||||
void loop() override;
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ switch(t){
|
||||
// Serial.println((int) t);
|
||||
}
|
||||
|
||||
void UITask::msgRead(int msgcount) {
|
||||
void UITask::onQueueSizeChanged(int msgcount) {
|
||||
_msgcount = msgcount;
|
||||
if (msgcount == 0) {
|
||||
clearMsgPreview();
|
||||
@@ -139,17 +139,19 @@ void UITask::clearMsgPreview() {
|
||||
_need_refresh = true;
|
||||
}
|
||||
|
||||
void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) {
|
||||
_msgcount = msgcount;
|
||||
void UITask::onMessageRecv(mesh::Packet *pkt, const ContactInfo &from, uint8_t txt_type, uint32_t sender_timestamp, const char* text) {
|
||||
// we only want to show text messages on display, not cli data
|
||||
if (!(txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN)) return;
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
vibration.trigger(); // vibrate even while the app is connected (honors quiet + cooldown)
|
||||
#endif
|
||||
|
||||
uint8_t path_len = pkt->isRouteFlood() ? pkt->path_len : 0xFF;
|
||||
if (path_len == 0xFF) {
|
||||
sprintf(_origin, "(F) %s", from_name);
|
||||
sprintf(_origin, "(F) %s", from.name);
|
||||
} else {
|
||||
sprintf(_origin, "(%d) %s", (uint32_t) path_len, from_name);
|
||||
sprintf(_origin, "(%d) %s", (uint32_t) path_len, from.name);
|
||||
}
|
||||
StrHelper::strncpy(_msg, text, sizeof(_msg));
|
||||
|
||||
@@ -158,10 +160,46 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
|
||||
_display->turnOn();
|
||||
}
|
||||
if (_display->isOn()) {
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer
|
||||
_need_refresh = true;
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer
|
||||
_need_refresh = true;
|
||||
}
|
||||
}
|
||||
if (!hasConnection()) {
|
||||
notify(UIEventType::contactMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::onChannelMessageRecv(mesh::Packet *pkt, ChannelDetails& channel_details, const char* text) {
|
||||
#ifdef HAS_DRV2605
|
||||
vibration.trigger(); // vibrate even while the app is connected (honors quiet + cooldown)
|
||||
#endif
|
||||
|
||||
uint8_t path_len = pkt->isRouteFlood() ? pkt->path_len : 0xFF;
|
||||
if (path_len == 0xFF) {
|
||||
sprintf(_origin, "(F) %s", channel_details.name);
|
||||
} else {
|
||||
sprintf(_origin, "(%d) %s", (uint32_t) path_len, channel_details.name);
|
||||
}
|
||||
StrHelper::strncpy(_msg, text, sizeof(_msg));
|
||||
|
||||
if (_display != NULL) {
|
||||
if (!_display->isOn() && !hasConnection()) {
|
||||
_display->turnOn();
|
||||
}
|
||||
if (_display->isOn()) {
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer
|
||||
_need_refresh = true;
|
||||
}
|
||||
}
|
||||
if (!hasConnection()) {
|
||||
notify(UIEventType::channelMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
||||
if (!hasConnection()) {
|
||||
notify(UIEventType::newContactMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::renderBatteryIndicator(uint16_t batteryMilliVolts) {
|
||||
@@ -262,7 +300,7 @@ void UITask::renderCurrScreen() {
|
||||
_display->print(tmp);
|
||||
|
||||
// BT pin
|
||||
if (!_connected && the_mesh.getBLEPin() != 0) {
|
||||
if (!hasConnection() && the_mesh.getBLEPin() != 0) {
|
||||
_display->setColor(UIColor::warning_txt);
|
||||
_display->setTextSize(2);
|
||||
_display->setCursor(0, 43);
|
||||
@@ -372,7 +410,7 @@ void UITask::userLedHandler() {
|
||||
statusLedWrite(255, 0, 0); // red: battery low
|
||||
} else if (_msgcount > 0) {
|
||||
statusLedWrite(255, 90, 0); // amber: unread messages
|
||||
} else if (_connected) {
|
||||
} else if (hasConnection()) {
|
||||
statusLedWrite(0, 0, 255); // blue: app connected
|
||||
} else {
|
||||
statusLedWrite(0, 255, 0); // green: heartbeat
|
||||
|
||||
@@ -70,9 +70,13 @@ public:
|
||||
bool hasDisplay() const { return _display != NULL; }
|
||||
void clearMsgPreview();
|
||||
|
||||
// MyMesh::Listener
|
||||
void onMessageRecv(mesh::Packet *pkt, const ContactInfo &from, uint8_t txt_type, uint32_t sender_timestamp, const char* text) override;
|
||||
void onChannelMessageRecv(mesh::Packet *pkt, ChannelDetails& channel_details, const char* text) override;
|
||||
void onQueueSizeChanged(int offline_queue_size) override;
|
||||
void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override;
|
||||
|
||||
// from AbstractUITask
|
||||
void msgRead(int msgcount) override;
|
||||
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override;
|
||||
void notify(UIEventType t = UIEventType::none) override;
|
||||
void loop() override;
|
||||
|
||||
|
||||
@@ -503,15 +503,16 @@ switch(t){
|
||||
}
|
||||
|
||||
|
||||
void UITask::msgRead(int msgcount) {
|
||||
void UITask::onQueueSizeChanged(int msgcount) {
|
||||
_msgcount = msgcount;
|
||||
if (msgcount == 0) {
|
||||
gotoHomeScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) {
|
||||
_msgcount = msgcount;
|
||||
void UITask::onMessageRecv(mesh::Packet *pkt, const ContactInfo &from, uint8_t txt_type, uint32_t sender_timestamp, const char* text) {
|
||||
// we only want to show text messages on display, not cli data
|
||||
if (!(txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN)) return;
|
||||
|
||||
if (_display != NULL) {
|
||||
if (!_display->isOn() && !hasConnection()) {
|
||||
@@ -522,6 +523,30 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
|
||||
_next_refresh = 100; // trigger refresh
|
||||
}
|
||||
}
|
||||
if (!hasConnection()) {
|
||||
notify(UIEventType::contactMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::onChannelMessageRecv(mesh::Packet *pkt, ChannelDetails& channel_details, const char* text) {
|
||||
if (_display != NULL) {
|
||||
if (!_display->isOn() && !hasConnection()) {
|
||||
_display->turnOn();
|
||||
}
|
||||
if (_display->isOn()) {
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer
|
||||
_next_refresh = 100; // trigger refresh
|
||||
}
|
||||
}
|
||||
if (!hasConnection()) {
|
||||
notify(UIEventType::channelMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
||||
if (!hasConnection()) {
|
||||
notify(UIEventType::newContactMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::userLedHandler() {
|
||||
|
||||
@@ -98,10 +98,13 @@ public:
|
||||
bool getGPSState();
|
||||
void toggleGPS();
|
||||
|
||||
// MyMesh::Listener
|
||||
void onMessageRecv(mesh::Packet *pkt, const ContactInfo &from, uint8_t txt_type, uint32_t sender_timestamp, const char* text) override;
|
||||
void onChannelMessageRecv(mesh::Packet *pkt, ChannelDetails& channel_details, const char* text) override;
|
||||
void onQueueSizeChanged(int offline_queue_size) override;
|
||||
void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override;
|
||||
|
||||
// from AbstractUITask
|
||||
void msgRead(int msgcount) override;
|
||||
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override;
|
||||
void notify(UIEventType t = UIEventType::none) override;
|
||||
void loop() override;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user