Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions examples/companion_radio/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,30 @@ int MyMesh::getRecentlyHeard(AdvertPath dest[], int max_num) {
return max_num;
}

int MyMesh::startPing(const ContactInfo& recipient, uint32_t& est_timeout) {
if (recipient.out_path_len == OUT_PATH_UNKNOWN) return MSG_SEND_FAILED; // direct path required
uint32_t tag = 0;
int result = sendRequest(recipient, REQ_TYPE_GET_STATUS, tag, est_timeout);
if (result == MSG_SEND_FAILED) return MSG_SEND_FAILED;
clearPendingReqs();
memcpy(&pending_ping, recipient.id.pub_key, sizeof(pending_ping));
pending_ping_at_ms = millis();
_ping_result.ready = false;
return result;
}

bool MyMesh::consumePingResult(uint8_t* pub_key_prefix, float& snr, int8_t& rssi, float& out_snr, int16_t& out_rssi, uint16_t& rtt_ms) {
if (!_ping_result.ready) return false;
memcpy(pub_key_prefix, _ping_result.pubkey_prefix, sizeof(_ping_result.pubkey_prefix));
snr = _ping_result.snr;
rssi = _ping_result.rssi;
out_snr = _ping_result.out_snr;
out_rssi = _ping_result.out_rssi;
rtt_ms = _ping_result.rtt_ms;
_ping_result.ready = false;
return true;
}

void MyMesh::onContactPathUpdated(const ContactInfo &contact) {
out_frame[0] = PUSH_CODE_PATH_UPDATED;
memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE);
Expand Down Expand Up @@ -698,6 +722,22 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data,
i += 6; // pub_key_prefix
}
_serial->writeFrame(out_frame, i);
} else if (pending_ping && memcmp(&pending_ping, contact.id.pub_key, sizeof(pending_ping)) == 0) {
pending_ping = 0;
_ping_result.snr = _last_resp_snr;
_ping_result.rssi = _last_resp_rssi;
_ping_result.out_snr = 0;
_ping_result.out_rssi = 0;
if (len >= 48) { // tag(4) + RepeaterStats up through last_snr at offset 42
int16_t their_rssi, their_snr_x4;
memcpy(&their_rssi, &data[10], sizeof(their_rssi));
memcpy(&their_snr_x4, &data[46], sizeof(their_snr_x4));
_ping_result.out_snr = their_snr_x4 / 4.0f;
_ping_result.out_rssi = their_rssi;
}
_ping_result.rtt_ms = (uint16_t)(millis() - pending_ping_at_ms);
memcpy(_ping_result.pubkey_prefix, contact.id.pub_key, sizeof(_ping_result.pubkey_prefix));
_ping_result.ready = true;
} else if (len > 4 && // check for status response
pending_status &&
memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme
Expand Down
17 changes: 16 additions & 1 deletion examples/companion_radio/MyMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
void enterCLIRescue();

int getRecentlyHeard(AdvertPath dest[], int max_num);
int startPing(const ContactInfo& recipient, uint32_t& est_timeout);
bool consumePingResult(uint8_t* pub_key_prefix, float& snr, int8_t& rssi, float& out_snr, int16_t& out_rssi, uint16_t& rtt_ms);

protected:
float getAirtimeBudgetFactor() const override;
Expand Down Expand Up @@ -160,7 +162,7 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
bool getChannelForSave(uint8_t channel_idx, ChannelDetails& ch) override { return getChannel(channel_idx, ch); }

void clearPendingReqs() {
pending_login = pending_status = pending_telemetry = pending_discovery = pending_req = 0;
pending_login = pending_status = pending_telemetry = pending_discovery = pending_req = pending_ping = 0;
}

public:
Expand Down Expand Up @@ -206,6 +208,19 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
uint32_t pending_status;
uint32_t pending_telemetry, pending_discovery; // pending _TELEMETRY_REQ
uint32_t pending_req; // pending _BINARY_REQ

uint32_t pending_ping;
unsigned long pending_ping_at_ms;
struct {
uint8_t pubkey_prefix[6];
bool ready;
float snr;
int8_t rssi;
float out_snr;
int16_t out_rssi;
uint16_t rtt_ms;
} _ping_result;

BaseSerialInterface *_serial;
AbstractUITask* _ui;

Expand Down
100 changes: 95 additions & 5 deletions examples/companion_radio/ui-new/UITask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ class HomeScreen : public UIScreen {
uint8_t _page;
bool _shutdown_init;
AdvertPath recent[UI_RECENT_LIST_SIZE];

bool _select_mode = false;
int _select_idx = 0;
unsigned long _select_at_ms = 0;
bool _ping_in_flight = false;
unsigned long _ping_deadline = 0;

void renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts) {
// Convert millivolts to percentage
Expand Down Expand Up @@ -185,6 +189,26 @@ class HomeScreen : public UIScreen {
if (_shutdown_init && !_task->isButtonPressed()) { // must wait for USR button to be released
_task->shutdown();
}
if (_select_mode && millis() - _select_at_ms > 10000) {
_select_mode = false;
}
if (_ping_in_flight) {
uint8_t pubkey[6];
float snr, out_snr;
int8_t rssi;
int16_t out_rssi;
uint16_t rtt_ms;
if (the_mesh.consumePingResult(pubkey, snr, rssi, out_snr, out_rssi, rtt_ms)) {
char buf[80];
sprintf(buf, "rx SNR %.1f RSSI %d\ntx SNR %.1f RSSI %d %dms",
snr, rssi, out_snr, out_rssi, rtt_ms);
_task->showAlert(buf, 5000);
_ping_in_flight = false;
} else if (millis() > _ping_deadline) {
_task->showAlert("no response", 3000);
_ping_in_flight = false;
}
}
}

int render(DisplayDriver& display) override {
Expand Down Expand Up @@ -241,6 +265,12 @@ class HomeScreen : public UIScreen {
for (int i = 0; i < UI_RECENT_LIST_SIZE; i++, y += 11) {
auto a = &recent[i];
if (a->name[0] == 0) continue; // empty slot
display.setColor(DisplayDriver::GREEN);
if (_select_mode && i == _select_idx) {
display.setColor(DisplayDriver::YELLOW);
display.drawRect(0, y - 1, display.width(), 11);
display.setColor(DisplayDriver::GREEN); // restore for text
}
int secs = _rtc->getCurrentTime() - a->recv_timestamp;
if (secs < 60) {
sprintf(tmp, "%ds", secs);
Expand Down Expand Up @@ -414,6 +444,35 @@ class HomeScreen : public UIScreen {
}

bool handleInput(char c) override {
if (_page == HomePage::RECENT && _select_mode) {
if (c == KEY_NEXT || c == KEY_RIGHT) {
for (int i = 1; i <= UI_RECENT_LIST_SIZE; i++) {
int idx = (_select_idx + i) % UI_RECENT_LIST_SIZE;
if (recent[idx].name[0] != 0) { _select_idx = idx; break; }
}
_select_at_ms = millis();
return true;
}
if (c == KEY_ENTER) {
auto* contact = the_mesh.lookupContactByPubKey(recent[_select_idx].pubkey_prefix, 6);
if (contact == NULL) {
_task->showAlert("not in contacts", 2000);
} else {
uint32_t est_timeout = 0;
int result = the_mesh.startPing(*contact, est_timeout);
if (result == MSG_SEND_FAILED) {
_task->showAlert("no direct path", 2000);
} else {
_task->showAlert("Pinging...", 800);
_ping_in_flight = true;
_ping_deadline = millis() + 7000;
}
}
_select_mode = false;
return true;
}
return false;
}
if (c == KEY_LEFT || c == KEY_PREV) {
_page = (_page + HomePage::Count - 1) % HomePage::Count;
return true;
Expand All @@ -433,6 +492,16 @@ class HomeScreen : public UIScreen {
}
return true;
}
if (c == KEY_ENTER && _page == HomePage::RECENT) {
for (int i = 0; i < UI_RECENT_LIST_SIZE; i++) {
if (recent[i].name[0] != 0) {
_select_idx = i;
_select_mode = true;
_select_at_ms = millis();
return true;
}
}
}
if (c == KEY_ENTER && _page == HomePage::ADVERT) {
_task->notify(UIEventType::ack);
if (the_mesh.advert()) {
Expand Down Expand Up @@ -592,8 +661,21 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
}

void UITask::showAlert(const char* text, int duration_millis) {
strcpy(_alert, text);
strncpy(_alert, text, sizeof(_alert) - 1);
_alert[sizeof(_alert) - 1] = '\0';
_alert_line_count = 1;
for (char* p = _alert; *p; p++) {
if (*p == '\n') {
*p = '\0';
_alert_line_count++;
}
}
_alert_expiry = millis() + duration_millis;
if (_display != NULL && !_display->isOn() && !hasConnection()) {
_display->turnOn();
}
_auto_off = millis() + AUTO_OFF_MILLIS;
_next_refresh = 100;
}

void UITask::notify(UIEventType t) {
Expand Down Expand Up @@ -797,11 +879,19 @@ void UITask::loop() {
_display->setTextSize(1);
int y = _display->height() / 3;
int p = _display->height() / 32;
const int line_h = 12;
int box_h = y;
int needed = p*6 + line_h * _alert_line_count;
if (needed > box_h) box_h = needed;
_display->setColor(DisplayDriver::DARK);
_display->fillRect(p, y, _display->width() - p*2, y);
_display->fillRect(p, y, _display->width() - p*2, box_h);
_display->setColor(DisplayDriver::LIGHT); // draw box border
_display->drawRect(p, y, _display->width() - p*2, y);
_display->drawTextCentered(_display->width() / 2, y + p*3, _alert);
_display->drawRect(p, y, _display->width() - p*2, box_h);
const char* line = _alert;
for (uint8_t i = 0; i < _alert_line_count; i++) {
_display->drawTextCentered(_display->width() / 2, y + p*3 + i*line_h, line);
line += strlen(line) + 1; // step past the '\0' separator
}
_next_refresh = _alert_expiry; // will need refresh when alert is dismissed
} else {
_next_refresh = millis() + delay_millis;
Expand Down
1 change: 1 addition & 0 deletions examples/companion_radio/ui-new/UITask.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class UITask : public AbstractUITask {
NodePrefs* _node_prefs;
char _alert[80];
unsigned long _alert_expiry;
uint8_t _alert_line_count;
int _msgcount;
unsigned long ui_started_at, next_batt_chck;
int next_backlight_btn_check = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/Dispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ void Dispatcher::checkRecv() {
} else {
if (tryParsePacket(pkt, raw, len)) {
pkt->_snr = _radio->getLastSNR() * 4.0f;
pkt->_rssi = _radio->getLastRSSI();
score = _radio->packetScore(_radio->getLastSNR(), len);
air_time = _radio->getEstAirtimeFor(len);
rx_air_time += air_time;
Expand Down Expand Up @@ -359,6 +360,7 @@ Packet* Dispatcher::obtainNewPacket() {
} else {
pkt->payload_len = pkt->path_len = 0;
pkt->_snr = 0;
pkt->_rssi = 0;
}
return pkt;
}
Expand Down
2 changes: 2 additions & 0 deletions src/Packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Packet {
uint8_t path[MAX_PATH_SIZE];
uint8_t payload[MAX_PACKET_PAYLOAD];
int8_t _snr;
int8_t _rssi;

/**
* \brief calculate the hash of payload + type
Expand Down Expand Up @@ -90,6 +91,7 @@ class Packet {
bool isMarkedDoNotRetransmit() const { return header == 0xFF; }

float getSNR() const { return ((float)_snr) / 4.0f; }
int8_t getRSSI() const { return _rssi; }

/**
* \returns the encoded/wire format length of this packet
Expand Down
4 changes: 4 additions & 0 deletions src/helpers/BaseChatMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
}
}
} else if (type == PAYLOAD_TYPE_RESPONSE && len > 0) {
_last_resp_snr = packet->getSNR();
_last_resp_rssi = packet->getRSSI();
onContactResponse(from, data, len);
if (packet->isRouteFlood() && from.out_path_len != OUT_PATH_UNKNOWN) {
// we have direct path, but other node is still sending flood response, so maybe they didn't receive reciprocal path properly(?)
Expand All @@ -298,6 +300,8 @@ bool BaseChatMesh::onPeerPathRecv(mesh::Packet* packet, int sender_idx, const ui

ContactInfo& from = contacts[i];

_last_resp_snr = packet->getSNR();
_last_resp_rssi = packet->getRSSI();
return onContactPathRecv(from, packet->path, packet->path_len, path, path_len, extra_type, extra, extra_len);
}

Expand Down
3 changes: 3 additions & 0 deletions src/helpers/BaseChatMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ class BaseChatMesh : public mesh::Mesh {
void sendAckTo(const ContactInfo& dest, uint32_t ack_hash);

protected:
float _last_resp_snr = 0;
int8_t _last_resp_rssi = 0;

BaseChatMesh(mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::PacketManager& mgr, mesh::MeshTables& tables)
: mesh::Mesh(radio, ms, rng, rtc, mgr, tables)
{
Expand Down