Skip to content

Commit

Permalink
settimeofday_cb: distinguish from user or sntp (esp8266#7637)
Browse files Browse the repository at this point in the history
* settimeofday_cb: distinguish from user or sntp
  • Loading branch information
d-a-v authored Oct 23, 2020
1 parent ace5e98 commit 95fb104
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 46 deletions.
3 changes: 2 additions & 1 deletion cores/esp8266/coredecls.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff);

#include <functional>

using BoolCB = std::function<void(bool)>;
using TrivialCB = std::function<void()>;

void settimeofday_cb (TrivialCB&& cb);
void settimeofday_cb (const BoolCB& cb);
void settimeofday_cb (const TrivialCB& cb);

#endif
Expand Down
24 changes: 19 additions & 5 deletions cores/esp8266/time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,14 @@ void configTime(const char* tz, const char* server1, const char* server2, const
sntp_init();
}

static TrivialCB _settimeofday_cb;
static BoolCB _settimeofday_cb;

void settimeofday_cb (TrivialCB&& cb)
void settimeofday_cb (const TrivialCB& cb)
{
_settimeofday_cb = std::move(cb);
_settimeofday_cb = [cb](bool sntp) { (void)sntp; cb(); };
}

void settimeofday_cb (const TrivialCB& cb)
void settimeofday_cb (const BoolCB& cb)
{
_settimeofday_cb = cb;
}
Expand All @@ -222,6 +222,20 @@ extern "C" {

int settimeofday(const struct timeval* tv, const struct timezone* tz)
{
bool from_sntp;
if (tz == (struct timezone*)0xFeedC0de)
{
// This special constant is used by lwip2/SNTP calling
// settimeofday(sntp-time, 0xfeedc0de), secretly using the
// obsolete-but-yet-still-there `tz` field.
// It allows to avoid duplicating this function and inform user
// about the source time change.
tz = nullptr;
from_sntp = true;
}
else
from_sntp = false;

if (tz || !tv)
// tz is obsolete (cf. man settimeofday)
return EINVAL;
Expand All @@ -230,7 +244,7 @@ int settimeofday(const struct timeval* tv, const struct timezone* tz)
tune_timeshift64(tv->tv_sec * 1000000ULL + tv->tv_usec);

if (_settimeofday_cb)
schedule_recurrent_function_us([](){ _settimeofday_cb(); return false; }, 0);
schedule_recurrent_function_us([from_sntp](){ _settimeofday_cb(from_sntp); return false; }, 0);

return 0;
}
Expand Down
100 changes: 63 additions & 37 deletions libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ static time_t now;
static uint32_t now_ms, now_us;

static esp8266::polledTimeout::periodicMs showTimeNow(60000);
static int time_machine_days = 0; // 0 = now
static int time_machine_days = 0; // 0 = present
static bool time_machine_running = false;
static bool time_machine_run_once = false;

// OPTIONAL: change SNTP startup delay
// a weak function is already defined and returns 0 (RFC violation)
Expand Down Expand Up @@ -112,7 +113,7 @@ void showTime() {
// time from boot
Serial.print("clock: ");
Serial.print((uint32_t)tp.tv_sec);
Serial.print("s / ");
Serial.print("s + ");
Serial.print((uint32_t)tp.tv_nsec);
Serial.println("ns");

Expand All @@ -125,7 +126,7 @@ void showTime() {
// EPOCH+tz+dst
Serial.print("gtod: ");
Serial.print((uint32_t)tv.tv_sec);
Serial.print("s / ");
Serial.print("s + ");
Serial.print((uint32_t)tv.tv_usec);
Serial.println("us");

Expand All @@ -140,7 +141,7 @@ void showTime() {
Serial.print("ctime: ");
Serial.print(ctime(&now));

// LwIP v2 is able to list more details about the currently configured SNTP servers
// lwIP v2 is able to list more details about the currently configured SNTP servers
for (int i = 0; i < SNTP_MAX_SERVERS; i++) {
IPAddress sntp = *sntp_getserver(i);
const char* name = sntp_getservername(i);
Expand All @@ -151,48 +152,67 @@ void showTime() {
} else {
Serial.printf("%s ", sntp.toString().c_str());
}
Serial.printf("IPv6: %s Reachability: %o\n",
Serial.printf("- IPv6: %s - Reachability: %o\n",
sntp.isV6() ? "Yes" : "No",
sntp_getreachability(i));
}
}

Serial.println();

// subsecond synchronisation
gettimeofday(&tv, nullptr);
time_t sec = tv.tv_sec;
do {
// show subsecond synchronisation
timeval prevtv;
time_t prevtime = time(nullptr);
gettimeofday(&prevtv, nullptr);

while (true) {
gettimeofday(&tv, nullptr);
Serial.printf("time(): %u gettimeofday(): %u.%06u",
(uint32_t)time(nullptr),
(uint32_t)tv.tv_sec, (uint32_t)tv.tv_usec);
if (tv.tv_sec == sec) {
Serial.println(" second unchanged");
} else {
Serial.println(" <-- second changed");
if (tv.tv_sec != prevtv.tv_sec) {
Serial.printf("time(): %u gettimeofday(): %u.%06u seconds are unchanged\n",
(uint32_t)prevtime,
(uint32_t)prevtv.tv_sec, (uint32_t)prevtv.tv_usec);
Serial.printf("time(): %u gettimeofday(): %u.%06u <-- seconds have changed\n",
(uint32_t)(prevtime = time(nullptr)),
(uint32_t)tv.tv_sec, (uint32_t)tv.tv_usec);
break;
}
prevtv = tv;
delay(50);
} while (tv.tv_sec == sec);
}

Serial.println();
}

void time_is_set_scheduled() {
// everything is allowed in this function
void time_is_set(bool from_sntp /* <= this parameter is optional */) {
// in CONT stack, unlike ISRs,
// any function is allowed in this callback

if (time_machine_days == 0) {
time_machine_running = !time_machine_running;
if (time_machine_running) {
time_machine_run_once = true;
time_machine_running = false;
} else {
time_machine_running = from_sntp && !time_machine_run_once;
}
if (time_machine_running) {
Serial.printf("\n-- \n-- Starting time machine demo to show libc's "
"automatic DST handling\n-- \n");
}
}

Serial.print("settimeofday(");
if (from_sntp) {
Serial.print("SNTP");
} else {
Serial.print("USER");
}
Serial.print(")");

// time machine demo
if (time_machine_running) {
if (time_machine_days == 0)
Serial.printf("---- settimeofday() has been called - possibly from SNTP\n"
" (starting time machine demo to show libc's automatic DST handling)\n\n");
now = time(nullptr);
const tm* tm = localtime(&now);
Serial.printf("future=%3ddays: DST=%s - ",
Serial.printf(": future=%3ddays: DST=%s - ",
time_machine_days,
tm->tm_isdst ? "true " : "false");
Serial.print(ctime(&now));
Expand All @@ -207,49 +227,55 @@ void time_is_set_scheduled() {
}
settimeofday(&tv, nullptr);
} else {
showTime();
Serial.println();
}
}

void setup() {
WiFi.persistent(false);
WiFi.mode(WIFI_OFF);

Serial.begin(115200);
Serial.println("\nStarting...\n");
Serial.println("\nStarting in 2secs...\n");
delay(2000);

// install callback - called when settimeofday is called (by SNTP or user)
// once enabled (by DHCP), SNTP is updated every hour by default
// ** optional boolean in callback function is true when triggerred by SNTP **
settimeofday_cb(time_is_set);

// setup RTC time
// it will be used until NTP server will send us real current time
Serial.println("Manually setting some time from some RTC:");
time_t rtc = RTC_UTC_TEST;
timeval tv = { rtc, 0 };
settimeofday(&tv, nullptr);

// install callback - called when settimeofday is called (by SNTP or us)
// once enabled (by DHCP), SNTP is updated every hour
settimeofday_cb(time_is_set_scheduled);

// NTP servers may be overriden by your DHCP server for a more local one
// (see below)

// ----> Here is the ONLY ONE LINE needed in your sketch

configTime(MYTZ, "pool.ntp.org");
// <----
// Replace MYTZ by a value from TZ.h (search for this file in your filesystem).

// Here is the ONLY ONE LINE needed in your sketch <----
// pick a value from TZ.h (search for this file in your filesystem) for MYTZ

// former configTime is still valid, here is the call for 7 hours to the west
// Former configTime is still valid, here is the call for 7 hours to the west
// with an enabled 30mn DST
//configTime(7 * 3600, 3600 / 2, "pool.ntp.org");

// OPTIONAL: disable obtaining SNTP servers from DHCP
//sntp_servermode_dhcp(0); // 0: disable obtaining SNTP servers from DHCP (enabled by default)

// Give now a chance to the settimeofday callback,
// because it is *always* deferred to the next yield()/loop()-call.
yield();

// start network
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(STASSID, STAPSK);

// don't wait for network, observe time changing
// when NTP timestamp is received
Serial.printf("Time is currently set by a constant:\n");
showTime();
}

Expand Down
Binary file modified tools/sdk/lib/liblwip2-1460-feat.a
Binary file not shown.
Binary file modified tools/sdk/lib/liblwip2-1460.a
Binary file not shown.
Binary file modified tools/sdk/lib/liblwip2-536-feat.a
Binary file not shown.
Binary file modified tools/sdk/lib/liblwip2-536.a
Binary file not shown.
Binary file modified tools/sdk/lib/liblwip6-1460-feat.a
Binary file not shown.
Binary file modified tools/sdk/lib/liblwip6-536-feat.a
Binary file not shown.
2 changes: 1 addition & 1 deletion tools/sdk/lwip2/builder
2 changes: 1 addition & 1 deletion tools/sdk/lwip2/include/lwip-git-hash.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// generated by makefiles/make-lwip2-hash
#ifndef LWIP_HASH_H
#define LWIP_HASH_H
#define LWIP_HASH_STR "STABLE-2_1_2_RELEASE/glue:1.2-34-gf56e795"
#define LWIP_HASH_STR "STABLE-2_1_2_RELEASE/glue:1.2-43-ge20f213"
#endif // LWIP_HASH_H
2 changes: 1 addition & 1 deletion tools/sdk/lwip2/include/lwipopts.h
Original file line number Diff line number Diff line change
Expand Up @@ -3574,7 +3574,7 @@ extern "C" {

#define SNTP_SERVER_DNS 1 // enable SNTP support DNS names through sntp_setservername / sntp_getservername

#define SNTP_SET_SYSTEM_TIME_US(t,us) do { struct timeval tv = { t, us }; settimeofday(&tv, NULL); } while (0)
#define SNTP_SET_SYSTEM_TIME_US(t,us) do { struct timeval tv = { t, us }; settimeofday(&tv, (struct timezone*)0xFeedC0de); } while (0)

#define SNTP_SUPPRESS_DELAY_CHECK 1
#define SNTP_UPDATE_DELAY_DEFAULT 3600000 // update delay defined by a default weak function
Expand Down

0 comments on commit 95fb104

Please sign in to comment.