Browse Source

Merge c2cfe23568 into 5f3b7f25d0

pull/2510/merge
hank 22 hours ago
committed by GitHub
parent
commit
19bb0f42eb
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 40
      examples/companion_radio/MyMesh.cpp
  2. 17
      examples/companion_radio/MyMesh.h
  3. 100
      examples/companion_radio/ui-new/UITask.cpp
  4. 1
      examples/companion_radio/ui-new/UITask.h
  5. 2
      src/Dispatcher.cpp
  6. 2
      src/Packet.h
  7. 4
      src/helpers/BaseChatMesh.cpp
  8. 3
      src/helpers/BaseChatMesh.h

40
examples/companion_radio/MyMesh.cpp

@ -400,6 +400,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);
@ -699,6 +723,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

17
examples/companion_radio/MyMesh.h

@ -101,6 +101,8 @@ public:
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;
@ -160,7 +162,7 @@ protected:
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:
@ -209,6 +211,19 @@ private:
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;

100
examples/companion_radio/ui-new/UITask.cpp

@ -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
@ -185,6 +189,26 @@ public:
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 {
@ -241,6 +265,12 @@ public:
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);
@ -414,6 +444,35 @@ public:
}
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;
@ -433,6 +492,16 @@ public:
}
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()) {
@ -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) {
@ -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;

1
examples/companion_radio/ui-new/UITask.h

@ -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;

2
src/Dispatcher.cpp

@ -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;
@ -359,6 +360,7 @@ Packet* Dispatcher::obtainNewPacket() {
} else {
pkt->payload_len = pkt->path_len = 0;
pkt->_snr = 0;
pkt->_rssi = 0;
}
return pkt;
}

2
src/Packet.h

@ -49,6 +49,7 @@ public:
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
@ -90,6 +91,7 @@ public:
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

4
src/helpers/BaseChatMesh.cpp

@ -293,6 +293,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(?)
@ -310,6 +312,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);
}

3
src/helpers/BaseChatMesh.h

@ -77,6 +77,9 @@ class BaseChatMesh : public mesh::Mesh {
void sendAckTo(const ContactInfo& dest, const uint8_t* ack_hash, uint8_t ack_len=4);
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)
{

Loading…
Cancel
Save