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
9 changes: 2 additions & 7 deletions examples/companion_radio/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1065,13 +1065,8 @@ void MyMesh::handleCmdFrame(size_t len) {
} else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) {
uint32_t secs;
memcpy(&secs, &cmd_frame[1], 4);
uint32_t curr = getRTCClock()->getCurrentTime();
if (secs >= curr) {
getRTCClock()->setCurrentTime(secs);
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
getRTCClock()->setCurrentTime(secs);
writeOKFrame();
} else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) {
mesh::Packet* pkt;
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) {
Expand Down
4 changes: 2 additions & 2 deletions examples/companion_radio/ui-new/UITask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ 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
int secs = _rtc->getCurrentTime() - a->recv_timestamp;
uint32_t secs = safeElapsedSecs(_rtc->getCurrentTime(), a->recv_timestamp);
if (secs < 60) {
sprintf(tmp, "%ds", secs);
} else if (secs < 60*60) {
Expand Down Expand Up @@ -488,7 +488,7 @@ class MsgPreviewScreen : public UIScreen {

auto p = &unread[head];

int secs = _rtc->getCurrentTime() - p->timestamp;
uint32_t secs = safeElapsedSecs(_rtc->getCurrentTime(), p->timestamp);
if (secs < 60) {
sprintf(tmp, "%ds", secs);
} else if (secs < 60*60) {
Expand Down
4 changes: 2 additions & 2 deletions examples/simple_repeater/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t

// add next neighbour to results
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], &heard_seconds_ago, 4); results_offset += 4;
memcpy(&results_buffer[results_offset], &neighbour->snr, 1); results_offset += 1;
Expand Down Expand Up @@ -934,7 +934,7 @@ void MyMesh::formatNeighborsReply(char *reply) {
mesh::Utils::toHex(hex, neighbour->id.pub_key, 4);

// 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);
while (*dp)
dp++; // find end of string
Expand Down
9 changes: 2 additions & 7 deletions examples/simple_secure_chat/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor {
}

void setClock(uint32_t timestamp) {
uint32_t curr = getRTCClock()->getCurrentTime();
if (timestamp > curr) {
getRTCClock()->setCurrentTime(timestamp);
Serial.println(" (OK - clock set!)");
} else {
Serial.println(" (ERR: clock cannot go backwards)");
}
getRTCClock()->setCurrentTime(timestamp);
Serial.println(" (OK - clock set!)");
}

void importCard(const char* command) {
Expand Down
3 changes: 2 additions & 1 deletion examples/simple_sensor/TimeSeriesData.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "TimeSeriesData.h"
#include <helpers/ArduinoHelpers.h>

void TimeSeriesData::recordData(mesh::RTCClock* clock, float value) {
uint32_t now = clock->getCurrentTime();
Expand All @@ -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 {
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;
float total = 0.0f;

Expand Down
9 changes: 9 additions & 0 deletions src/helpers/ArduinoHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
#include <Mesh.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 {
uint32_t base_time;
uint64_t accumulator;
Expand Down
19 changes: 11 additions & 8 deletions src/helpers/BaseChatMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,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;
connections[use_idx].next_ping = futureMillis(interval);
connections[use_idx].expected_ack = 0;
connections[use_idx].last_activity = getRTCClock()->getCurrentTime();
connections[use_idx].last_activity_ms = _ms->getMillis();
return true; // success
}

Expand All @@ -619,7 +619,7 @@ void BaseChatMesh::stopConnection(const uint8_t* pub_key) {
connections[i].keep_alive_millis = 0; // mark slot as now free
connections[i].next_ping = 0;
connections[i].expected_ack = 0;
connections[i].last_activity = 0;
connections[i].last_activity_ms = 0;
break;
}
}
Expand All @@ -635,7 +635,7 @@ bool BaseChatMesh::hasConnectionTo(const uint8_t* pub_key) {
void BaseChatMesh::markConnectionActive(const ContactInfo& contact) {
for (int i = 0; i < MAX_CONNECTIONS; i++) {
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
connections[i].next_ping = futureMillis(connections[i].keep_alive_millis);
Expand All @@ -649,7 +649,7 @@ ContactInfo* BaseChatMesh::checkConnectionsAck(const uint8_t* data) {
if (connections[i].keep_alive_millis > 0 && memcmp(&connections[i].expected_ack, data, 4) == 0) {
// yes, got an ack for our keep_alive request!
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
connections[i].next_ping = futureMillis(connections[i].keep_alive_millis);
Expand All @@ -666,14 +666,17 @@ void BaseChatMesh::checkConnections() {
for (int i = 0; i < MAX_CONNECTIONS; i++) {
if (connections[i].keep_alive_millis == 0) continue; // unused slot

uint32_t now = getRTCClock()->getCurrentTime();
uint32_t expire_secs = (connections[i].keep_alive_millis / 1000) * 5 / 2; // 2.5 x keep_alive interval
if (now >= connections[i].last_activity + expire_secs) {
// Monotonic time is immune to RTC clock changes (GPS, NTP, manual sync).
// Assumes light sleep (millis() keeps incrementing). Deep sleep resets millis(),
// 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
connections[i].keep_alive_millis = 0;
connections[i].next_ping = 0;
connections[i].expected_ack = 0;
connections[i].last_activity = 0;
connections[i].last_activity_ms = 0;
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion src/helpers/BaseChatMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class ContactsIterator {
struct ConnectionInfo {
mesh::Identity server_id;
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 expected_ack;
};
Expand Down
26 changes: 8 additions & 18 deletions src/helpers/CommonCLI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,15 +205,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
_callbacks->sendSelfAdvertisement(1500, true); // longer delay, give CLI response time to be sent first
strcpy(reply, "OK - Advert sent");
} else if (memcmp(command, "clock sync", 10) == 0) {
uint32_t curr = getRTCClock()->getCurrentTime();
if (sender_timestamp > curr) {
getRTCClock()->setCurrentTime(sender_timestamp + 1);
uint32_t now = getRTCClock()->getCurrentTime();
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");
}
getRTCClock()->setCurrentTime(sender_timestamp + 1);
uint32_t now = getRTCClock()->getCurrentTime();
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 if (memcmp(command, "start ota", 9) == 0) {
if (!_board->startOTAUpdate(_prefs->node_name, reply)) {
strcpy(reply, "Error");
Expand All @@ -224,15 +219,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
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)
uint32_t secs = _atoi(&command[5]);
uint32_t curr = getRTCClock()->getCurrentTime();
if (secs > curr) {
getRTCClock()->setCurrentTime(secs);
uint32_t now = getRTCClock()->getCurrentTime();
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)");
}
getRTCClock()->setCurrentTime(secs);
uint32_t now = getRTCClock()->getCurrentTime();
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 if (memcmp(command, "neighbors", 9) == 0) {
_callbacks->formatNeighborsReply(reply);
} else if (memcmp(command, "neighbor.remove ", 16) == 0) {
Expand Down