Browse Source

Merge 6106acb8e1 into adc631f315

pull/1349/merge
Wessel 2 days ago
committed by GitHub
parent
commit
7d6a9bac4d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 9
      examples/companion_radio/MyMesh.cpp
  2. 4
      examples/companion_radio/ui-new/UITask.cpp
  3. 4
      examples/simple_repeater/MyMesh.cpp
  4. 9
      examples/simple_secure_chat/main.cpp
  5. 3
      examples/simple_sensor/TimeSeriesData.cpp
  6. 9
      src/helpers/ArduinoHelpers.h
  7. 19
      src/helpers/BaseChatMesh.cpp
  8. 2
      src/helpers/BaseChatMesh.h
  9. 26
      src/helpers/CommonCLI.cpp

9
examples/companion_radio/MyMesh.cpp

@ -1236,13 +1236,8 @@ void MyMesh::handleCmdFrame(size_t len) {
} else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) { } else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) {
uint32_t secs; uint32_t secs;
memcpy(&secs, &cmd_frame[1], 4); memcpy(&secs, &cmd_frame[1], 4);
uint32_t curr = getRTCClock()->getCurrentTime(); getRTCClock()->setCurrentTime(secs);
if (secs >= curr) { writeOKFrame();
getRTCClock()->setCurrentTime(secs);
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) { } else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) {
mesh::Packet* pkt; mesh::Packet* pkt;
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) { if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) {

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

@ -249,7 +249,7 @@ public:
for (int i = 0; i < UI_RECENT_LIST_SIZE; i++, y += 11) { for (int i = 0; i < UI_RECENT_LIST_SIZE; i++, y += 11) {
auto a = &recent[i]; auto a = &recent[i];
if (a->name[0] == 0) continue; // empty slot if (a->name[0] == 0) continue; // empty slot
int secs = _rtc->getCurrentTime() - a->recv_timestamp; uint32_t secs = safeElapsedSecs(_rtc->getCurrentTime(), a->recv_timestamp);
if (secs < 60) { if (secs < 60) {
sprintf(tmp, "%ds", secs); sprintf(tmp, "%ds", secs);
} else if (secs < 60*60) { } else if (secs < 60*60) {
@ -527,7 +527,7 @@ public:
auto p = &unread[head]; auto p = &unread[head];
int secs = _rtc->getCurrentTime() - p->timestamp; uint32_t secs = safeElapsedSecs(_rtc->getCurrentTime(), p->timestamp);
if (secs < 60) { if (secs < 60) {
sprintf(tmp, "%ds", secs); sprintf(tmp, "%ds", secs);
} else if (secs < 60*60) { } else if (secs < 60*60) {

4
examples/simple_repeater/MyMesh.cpp

@ -355,7 +355,7 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t
#if MAX_NEIGHBOURS #if MAX_NEIGHBOURS
// add next neighbour to results // add next neighbour to results
auto neighbour = sorted_neighbours[index + offset]; auto neighbour = sorted_neighbours[index + offset];
uint32_t heard_seconds_ago = getRTCClock()->getCurrentTime() - neighbour->heard_timestamp; uint32_t heard_seconds_ago = safeElapsedSecs(getRTCClock()->getCurrentTime(), neighbour->heard_timestamp);
memcpy(&results_buffer[results_offset], neighbour->id.pub_key, pubkey_prefix_length); results_offset += pubkey_prefix_length; memcpy(&results_buffer[results_offset], neighbour->id.pub_key, pubkey_prefix_length); results_offset += pubkey_prefix_length;
memcpy(&results_buffer[results_offset], &heard_seconds_ago, 4); results_offset += 4; memcpy(&results_buffer[results_offset], &heard_seconds_ago, 4); results_offset += 4;
memcpy(&results_buffer[results_offset], &neighbour->snr, 1); results_offset += 1; memcpy(&results_buffer[results_offset], &neighbour->snr, 1); results_offset += 1;
@ -1095,7 +1095,7 @@ void MyMesh::formatNeighborsReply(char *reply) {
mesh::Utils::toHex(hex, neighbour->id.pub_key, 4); mesh::Utils::toHex(hex, neighbour->id.pub_key, 4);
// add next neighbour // add next neighbour
uint32_t secs_ago = getRTCClock()->getCurrentTime() - neighbour->heard_timestamp; uint32_t secs_ago = safeElapsedSecs(getRTCClock()->getCurrentTime(), neighbour->heard_timestamp);
sprintf(dp, "%s:%d:%d", hex, secs_ago, neighbour->snr); sprintf(dp, "%s:%d:%d", hex, secs_ago, neighbour->snr);
while (*dp) while (*dp)
dp++; // find end of string dp++; // find end of string

9
examples/simple_secure_chat/main.cpp

@ -158,13 +158,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor {
} }
void setClock(uint32_t timestamp) { void setClock(uint32_t timestamp) {
uint32_t curr = getRTCClock()->getCurrentTime(); getRTCClock()->setCurrentTime(timestamp);
if (timestamp > curr) { Serial.println(" (OK - clock set!)");
getRTCClock()->setCurrentTime(timestamp);
Serial.println(" (OK - clock set!)");
} else {
Serial.println(" (ERR: clock cannot go backwards)");
}
} }
void importCard(const char* command) { void importCard(const char* command) {

3
examples/simple_sensor/TimeSeriesData.cpp

@ -1,4 +1,5 @@
#include "TimeSeriesData.h" #include "TimeSeriesData.h"
#include <helpers/ArduinoHelpers.h>
void TimeSeriesData::recordData(mesh::RTCClock* clock, float value) { void TimeSeriesData::recordData(mesh::RTCClock* clock, float value) {
uint32_t now = clock->getCurrentTime(); uint32_t now = clock->getCurrentTime();
@ -12,7 +13,7 @@ void TimeSeriesData::recordData(mesh::RTCClock* clock, float value) {
void TimeSeriesData::calcMinMaxAvg(mesh::RTCClock* clock, uint32_t start_secs_ago, uint32_t end_secs_ago, MinMaxAvg* dest, uint8_t channel, uint8_t lpp_type) const { void TimeSeriesData::calcMinMaxAvg(mesh::RTCClock* clock, uint32_t start_secs_ago, uint32_t end_secs_ago, MinMaxAvg* dest, uint8_t channel, uint8_t lpp_type) const {
int i = next, n = num_slots; int i = next, n = num_slots;
uint32_t ago = clock->getCurrentTime() - last_timestamp; uint32_t ago = safeElapsedSecs(clock->getCurrentTime(), last_timestamp);
int num_values = 0; int num_values = 0;
float total = 0.0f; float total = 0.0f;

9
src/helpers/ArduinoHelpers.h

@ -3,6 +3,15 @@
#include <Mesh.h> #include <Mesh.h>
#include <Arduino.h> #include <Arduino.h>
// Safe elapsed time calculation that handles clock corrections (when RTC is set backwards).
// Returns 0 if recorded_timestamp is in the "future" relative to current_time.
inline uint32_t safeElapsedSecs(uint32_t current_time, uint32_t recorded_timestamp) {
if (recorded_timestamp > current_time) {
return 0; // Clock was corrected backwards; treat as "just now"
}
return current_time - recorded_timestamp;
}
class VolatileRTCClock : public mesh::RTCClock { class VolatileRTCClock : public mesh::RTCClock {
uint32_t base_time; uint32_t base_time;
uint64_t accumulator; uint64_t accumulator;

19
src/helpers/BaseChatMesh.cpp

@ -700,7 +700,7 @@ bool BaseChatMesh::startConnection(const ContactInfo& contact, uint16_t keep_ali
uint32_t interval = connections[use_idx].keep_alive_millis = ((uint32_t)keep_alive_secs)*1000; uint32_t interval = connections[use_idx].keep_alive_millis = ((uint32_t)keep_alive_secs)*1000;
connections[use_idx].next_ping = futureMillis(interval); connections[use_idx].next_ping = futureMillis(interval);
connections[use_idx].expected_ack = 0; connections[use_idx].expected_ack = 0;
connections[use_idx].last_activity = getRTCClock()->getCurrentTime(); connections[use_idx].last_activity_ms = _ms->getMillis();
return true; // success return true; // success
} }
@ -710,7 +710,7 @@ void BaseChatMesh::stopConnection(const uint8_t* pub_key) {
connections[i].keep_alive_millis = 0; // mark slot as now free connections[i].keep_alive_millis = 0; // mark slot as now free
connections[i].next_ping = 0; connections[i].next_ping = 0;
connections[i].expected_ack = 0; connections[i].expected_ack = 0;
connections[i].last_activity = 0; connections[i].last_activity_ms = 0;
break; break;
} }
} }
@ -726,7 +726,7 @@ bool BaseChatMesh::hasConnectionTo(const uint8_t* pub_key) {
void BaseChatMesh::markConnectionActive(const ContactInfo& contact) { void BaseChatMesh::markConnectionActive(const ContactInfo& contact) {
for (int i = 0; i < MAX_CONNECTIONS; i++) { for (int i = 0; i < MAX_CONNECTIONS; i++) {
if (connections[i].keep_alive_millis > 0 && connections[i].server_id.matches(contact.id)) { if (connections[i].keep_alive_millis > 0 && connections[i].server_id.matches(contact.id)) {
connections[i].last_activity = getRTCClock()->getCurrentTime(); connections[i].last_activity_ms = _ms->getMillis();
// re-schedule next KEEP_ALIVE, now that we have heard from server // re-schedule next KEEP_ALIVE, now that we have heard from server
connections[i].next_ping = futureMillis(connections[i].keep_alive_millis); connections[i].next_ping = futureMillis(connections[i].keep_alive_millis);
@ -740,7 +740,7 @@ ContactInfo* BaseChatMesh::checkConnectionsAck(const uint8_t* data) {
if (connections[i].keep_alive_millis > 0 && memcmp(&connections[i].expected_ack, data, 4) == 0) { if (connections[i].keep_alive_millis > 0 && memcmp(&connections[i].expected_ack, data, 4) == 0) {
// yes, got an ack for our keep_alive request! // yes, got an ack for our keep_alive request!
connections[i].expected_ack = 0; connections[i].expected_ack = 0;
connections[i].last_activity = getRTCClock()->getCurrentTime(); connections[i].last_activity_ms = _ms->getMillis();
// re-schedule next KEEP_ALIVE, now that we have heard from server // re-schedule next KEEP_ALIVE, now that we have heard from server
connections[i].next_ping = futureMillis(connections[i].keep_alive_millis); connections[i].next_ping = futureMillis(connections[i].keep_alive_millis);
@ -757,14 +757,17 @@ void BaseChatMesh::checkConnections() {
for (int i = 0; i < MAX_CONNECTIONS; i++) { for (int i = 0; i < MAX_CONNECTIONS; i++) {
if (connections[i].keep_alive_millis == 0) continue; // unused slot if (connections[i].keep_alive_millis == 0) continue; // unused slot
uint32_t now = getRTCClock()->getCurrentTime(); // Monotonic time is immune to RTC clock changes (GPS, NTP, manual sync).
uint32_t expire_secs = (connections[i].keep_alive_millis / 1000) * 5 / 2; // 2.5 x keep_alive interval // Assumes light sleep (millis() keeps incrementing). Deep sleep resets millis(),
if (now >= connections[i].last_activity + expire_secs) { // but BaseChatMesh is only used by companion_radio which uses light sleep.
unsigned long now = _ms->getMillis();
unsigned long expire_millis = (connections[i].keep_alive_millis * 5UL) / 2; // 2.5 x keep_alive interval
if ((now - connections[i].last_activity_ms) >= expire_millis) {
// connection now lost // connection now lost
connections[i].keep_alive_millis = 0; connections[i].keep_alive_millis = 0;
connections[i].next_ping = 0; connections[i].next_ping = 0;
connections[i].expected_ack = 0; connections[i].expected_ack = 0;
connections[i].last_activity = 0; connections[i].last_activity_ms = 0;
continue; continue;
} }

2
src/helpers/BaseChatMesh.h

@ -47,7 +47,7 @@ public:
struct ConnectionInfo { struct ConnectionInfo {
mesh::Identity server_id; mesh::Identity server_id;
unsigned long next_ping; unsigned long next_ping;
uint32_t last_activity; unsigned long last_activity_ms; // monotonic millis() for connection expiry
uint32_t keep_alive_millis; uint32_t keep_alive_millis;
uint32_t expected_ack; uint32_t expected_ack;
}; };

26
src/helpers/CommonCLI.cpp

@ -196,15 +196,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
_callbacks->sendSelfAdvertisement(1500, true); // longer delay, give CLI response time to be sent first _callbacks->sendSelfAdvertisement(1500, true); // longer delay, give CLI response time to be sent first
strcpy(reply, "OK - Advert sent"); strcpy(reply, "OK - Advert sent");
} else if (memcmp(command, "clock sync", 10) == 0) { } else if (memcmp(command, "clock sync", 10) == 0) {
uint32_t curr = getRTCClock()->getCurrentTime(); getRTCClock()->setCurrentTime(sender_timestamp + 1);
if (sender_timestamp > curr) { uint32_t now = getRTCClock()->getCurrentTime();
getRTCClock()->setCurrentTime(sender_timestamp + 1); DateTime dt = DateTime(now);
uint32_t now = getRTCClock()->getCurrentTime(); sprintf(reply, "OK - clock set: %02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
DateTime dt = DateTime(now);
sprintf(reply, "OK - clock set: %02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
} else {
strcpy(reply, "ERR: clock cannot go backwards");
}
} else if (memcmp(command, "start ota", 9) == 0) { } else if (memcmp(command, "start ota", 9) == 0) {
if (!_board->startOTAUpdate(_prefs->node_name, reply)) { if (!_board->startOTAUpdate(_prefs->node_name, reply)) {
strcpy(reply, "Error"); strcpy(reply, "Error");
@ -215,15 +210,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
sprintf(reply, "%02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year()); sprintf(reply, "%02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
} else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds) } else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds)
uint32_t secs = _atoi(&command[5]); uint32_t secs = _atoi(&command[5]);
uint32_t curr = getRTCClock()->getCurrentTime(); getRTCClock()->setCurrentTime(secs);
if (secs > curr) { uint32_t now = getRTCClock()->getCurrentTime();
getRTCClock()->setCurrentTime(secs); DateTime dt = DateTime(now);
uint32_t now = getRTCClock()->getCurrentTime(); sprintf(reply, "OK - clock set: %02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
DateTime dt = DateTime(now);
sprintf(reply, "OK - clock set: %02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
} else {
strcpy(reply, "(ERR: clock cannot go backwards)");
}
} else if (memcmp(command, "neighbors", 9) == 0) { } else if (memcmp(command, "neighbors", 9) == 0) {
_callbacks->formatNeighborsReply(reply); _callbacks->formatNeighborsReply(reply);
} else if (memcmp(command, "neighbor.remove ", 16) == 0) { } else if (memcmp(command, "neighbor.remove ", 16) == 0) {

Loading…
Cancel
Save