Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

time() does not work without active NTP server #1679

Closed
av1024 opened this issue Feb 25, 2016 · 80 comments · Fixed by #4001
Closed

time() does not work without active NTP server #1679

av1024 opened this issue Feb 25, 2016 · 80 comments · Fixed by #4001

Comments

@av1024
Copy link

av1024 commented Feb 25, 2016

Basic Infos

Hardware

Hardware: ESP-12E
Core Version: 2.1.0-rc2

Description

"Internal" time.c functions always return 0 /1970-01-01/ if not synced via NTP.

I want to initialize internal clock via constant or from RTC for log timestamping (so I don't need precise time on startup, but valid measured intervals)

Settings in IDE

Module: Generic ESP8266 Module
Flash Size: 4MB
CPU Frequency: 80Mhz
Flash Mode: qio
Flash Frequency: 80Mhz
Upload Using: SERIAL
Reset Method: ck

Sketch

#include <Arduino.h>
#include <time.h>

void setup() {
 // WiFi.begin(); // wifi disabled for example
 // configTime(3*3600, 0, "not.avail.ntp"); 
 Serial.begin(115200);
}

void loop() {
  time_t now = time(nullptr);
 Serial.println(ctime(&now));
 delay(1000);
}

Debug Messages

Thu Jan 01 00:00:00 1970

Thu Jan 01 00:00:00 1970

...

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@everslick
Copy link
Contributor

I use this workaround for now:

static uint32_t starttime = millis() / 1000;
static uint32_t localtime = starttime;

void time_set(uint32_t time) {
  starttime = millis() / 1000;
  localtime = time;
}

uint32_t time_get(void) {
  return (millis() / 1000 - starttime + localtime);
} 

@miky2k
Copy link

miky2k commented Feb 28, 2016

I m looking for full software rtc in core libraries too.

@av1024
Copy link
Author

av1024 commented Feb 28, 2016

Thanks, @everslick!
I have my implementations RTC and/or NTP sync from my "raw C" projects on AVR, but I want to use "embedded" code because it already exists.

@far5893 There is widely known Time library from arduino.cc, but it is not compiled with 2.1.0-rc2 for me. And of course, this is not core lib

@igrr Please take attention to string handling in sntp_xxx code. I have got exception 28 (or sometimes 9) with sntp_asctime[_r] and sntp_sync_xxx approx after 22-24 hours uptime. there is only ctime(&now) calls in my code. One of saved traces:

Decoding 17 resultsException code: 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
0x402265f9: sntp_asctime_r at ??:?
0x402265f9: sntp_asctime_r at ??:?
0x4020d6cc: TwoWire::requestFrom(unsigned char, unsigned int, bool) at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/libraries/Wire/Wire.cpp:240
0x40226647: sntp_asctime at ??:?
0x4020d6f8: TwoWire::requestFrom(unsigned char, unsigned char) at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/libraries/Wire/Wire.cpp:240
0x40201b44: asctime at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/cores/esp8266/time.c:110
0x4020df5e: Adafruit_BMP280::read24(unsigned char) at /home/av/Arduino/libraries/Adafruit_BMP280_Library/Adafruit_BMP280.cpp:210
0x40209742: check_float(float, float, float&) at /home/av/bin/arduino-1.6.5/WebConfig.ino:311
0x4020986e: readSensors() at /home/av/bin/arduino-1.6.5/WebConfig.ino:311
0x40105c2e: ets_timer_setfn at ??:?
0x4020a534: ESP8266WiFiSTAClass::status() at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp:635
0x4020ad5c: WiFiClient::operator=(WiFiClient const&) at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/libraries/ESP8266WiFi/src/WiFiClient.cpp:362
0x40209e08: every_s() at /home/av/bin/arduino-1.6.5/WebConfig.ino:311
0x40209eb8: handle_ms() at /home/av/bin/arduino-1.6.5/WebConfig.ino:323
0x40209ef3: loop at /home/av/bin/arduino-1.6.5/WebConfig.ino:337
0x4020f6f8: loop_wrapper at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/cores/esp8266/core_esp8266_main.cpp:43
0x40100114: cont_norm at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/cores/esp8266/cont.S:109

@igrr
Copy link
Member

igrr commented Feb 28, 2016

sntp_xxx functions come from espressif SDK, as far as I can tell.

On Sun, Feb 28, 2016, 13:04 Alexander Voronin [email protected]
wrote:

Thanks, @everslick https://github.com/everslick!
I have my implementations RTC and/or NTP sync from my "raw C" projects on
AVR, but I want to use "embedded" code because it already exists.

@far5893 https://github.com/far5893 There is widely known Time library
from arduino.cc, but it is not compiled with 2.1.0-rc2 for me. And of
course, this is not core lib

@igrr https://github.com/igrr Please take attention to string handling
in sntp_xxx code. I have got exception 28 (or sometimes 9) with
sntp_asctime[_r] and sntp_sync_xxx approx after 22-24 hours uptime. there
is only ctime(&now) calls in my code. One of saved traces:

Decoding 17 resultsException code: 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
0x402265f9: sntp_asctime_r at ??:?
0x402265f9: sntp_asctime_r at ??:?
0x4020d6cc: TwoWire::requestFrom(unsigned char, unsigned int, bool) at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/libraries/Wire/Wire.cpp:240
0x40226647: sntp_asctime at ??:?
0x4020d6f8: TwoWire::requestFrom(unsigned char, unsigned char) at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/libraries/Wire/Wire.cpp:240
0x40201b44: asctime at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/cores/esp8266/time.c:110
0x4020df5e: Adafruit_BMP280::read24(unsigned char) at /home/av/Arduino/libraries/Adafruit_BMP280_Library/Adafruit_BMP280.cpp:210
0x40209742: check_float(float, float, float&) at /home/av/bin/arduino-1.6.5/WebConfig.ino:311
0x4020986e: readSensors() at /home/av/bin/arduino-1.6.5/WebConfig.ino:311
0x40105c2e: ets_timer_setfn at ??:?
0x4020a534: ESP8266WiFiSTAClass::status() at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp:635
0x4020ad5c: WiFiClient::operator=(WiFiClient const&) at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/libraries/ESP8266WiFi/src/WiFiClient.cpp:362
0x40209e08: every_s() at /home/av/bin/arduino-1.6.5/WebConfig.ino:311
0x40209eb8: handle_ms() at /home/av/bin/arduino-1.6.5/WebConfig.ino:323
0x40209ef3: loop at /home/av/bin/arduino-1.6.5/WebConfig.ino:337
0x4020f6f8: loop_wrapper at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/cores/esp8266/core_esp8266_main.cpp:43
0x40100114: cont_norm at /home/av/.arduino15/packages/esp8266/hardware/esp8266/2.1.0-rc2/cores/esp8266/cont.S:109


Reply to this email directly or view it on GitHub
#1679 (comment).

@av1024
Copy link
Author

av1024 commented Feb 28, 2016

@igrr Huh :( May be some try/catch over sntp_xxx in esp8266/time.c ? But I'm not sure this may help

@Juppit
Copy link
Contributor

Juppit commented Feb 28, 2016

Maybe you will have a look at this library:
https://github.com/Juppit/esp8266-SNTPClock

It was developed from a version with ticker library without network
access. Therefore uncommenting the network stuff it should still give
you time functions.

Am 28.02.2016 um 11:30 schrieb Alexander Voronin:

@igrr https://github.com/igrr Huh :( May be some try/catch over
sntp_xxx in esp8266/time.c ? But I'm not sure this may help


Reply to this email directly or view it on GitHub
#1679 (comment).

@Juppit
Copy link
Contributor

Juppit commented Feb 28, 2016

Wrong thread, I guess.
There was someone looking for time finctions without network.

@av1024
Copy link
Author

av1024 commented Feb 28, 2016

@Juppit Your version have same issue as this - system snmp_xxx functions does not provide correct time if no ntp sync was made prior. Another bug is in SNTPClock::begin - while(!m_secsSince1900) loop never ends if no network/success ntp sync made

@igrr
Copy link
Member

igrr commented Feb 28, 2016

These are not c++ exceptions, these are CPU exceptions, so try/catch won't help here. Do you have a test case which is failing? I'd rather try to reproduce it and report to Espressif.

@av1024
Copy link
Author

av1024 commented Feb 28, 2016

@igrr I don't know how to reproduce it a bit stable. I'll try write minimal code only for timesync/print just now, but I have no idea how to speed up testing - 20+ hours before exception.. may be wifi connection issue while sync, may be some string formatting...

@igrr
Copy link
Member

igrr commented Feb 28, 2016

20 hours is not that bad, I can probably hook it up to gdb and let it run
until it crashes.

On Sun, Feb 28, 2016, 14:50 Alexander Voronin [email protected]
wrote:

@igrr https://github.com/igrr I don't know how to reproduce it a bit
stable. I'll try write minimal code only for timesync/print just now, but I
have no idea how to speed up testing - 20+ hours before exception.. may be
wifi connection issue while sync, may be some string formatting...


Reply to this email directly or view it on GitHub
#1679 (comment).

@kaeferfreund
Copy link

hey, if I got this right you are looking for some RTC capabilities. I have used the "TimeLib.h" for that. To initialize the time, I send a head request to a google server. I sync it every night and it's running since 2 weeks now...

@av1024
Copy link
Author

av1024 commented Feb 28, 2016

@kaeferfreund Nope. I am looking for system capability to work w/o internet/NTP server. I know about TimeLib (distributed now as arduino.cc's Time.h). My use case is sensor, that may be sometimes offline and may go online w/o internet/NTP access. I plan to use DS3231 as backup RTC in my v3.1 PCB design but I just don't want to use third party lib where an system implementation exists.

@igrr, 5hrs. Still working. Neither blocking port 123 on router, nor disabling wifi access does not reproduce fail. But for now I know time intervals of internal time sync )) - if NTP accessible, then sunc performed every hour, if not - every approx 33seconds. PS: I am not familiar with gdb, but try tomorrow at work (not sure it will work on cubietruck, sot first try on PC)

@av1024
Copy link
Author

av1024 commented Mar 2, 2016

@igrr Three day test - all ok, no crash. May be an issue with printing asctime(nullptr) - this call immediately throws exception 28. But I have no code with this call, only commented out from old exercises.

I'll try with more complex code and open separate issue if found something.

@everslick
Copy link
Contributor

FYI: I have the feeling, that stack growth has to do with Exception(28). I
could not find out yet, how to measure stack usage. I guess the stack
collides with heap occasionally. I could prevent Exception(28 by moving
stack variables to the heap.

On Wed, Mar 2, 2016 at 4:32 PM, Alexander Voronin [email protected]
wrote:

@igrr https://github.com/igrr Three day test - all ok, no crash. May
be an issue with printing asctime(nullptr) - this call immediately throws
exception 28. But I have no code with this call, only commented out from
old exercises.

I'll try with more complex code and open separate issue if found something.


Reply to this email directly or view it on GitHub
#1679 (comment).

@igrr
Copy link
Member

igrr commented Mar 2, 2016

You can measure stack usage for the code which runs on Arduino task (i.e. called from setup and loop). See https://github.com/esp8266/Arduino/blob/master/cores/esp8266/cont.h#L65.
For code which runs on other tasks, there is no way to check this at the moment.

Edit:
the cont_t structure which has to be passed into this function is not currently exposed to the user. It is declared here: https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_main.cpp#L64. I think you can declare it as extern in your sketch as a workaround.

@av1024
Copy link
Author

av1024 commented Mar 2, 2016

In my case Exception 28 usually indicate incorrect usage of pointers - asctime(NULL) as above and mostly print(PSTR/FPSTR/F(...)). In most cases I use something like print(PSTR("debug")) instead of print(F("debug")) and got error as should.

UPD: tested with cont_get_free_stack(). Got about 3136-3144 of 4096 bytes, looks ok )) and 35200 bytes of heap (I2C, Web Server, 5x100words sensor logs,1500bytes String in web server handler)

@everslick
Copy link
Contributor

@ivan: thanx for the hint. but i'm not sure, if i do it right:

i create a cont_t object:

static cont_t stack;

in setup() i call:
cont_init(&stack);

in loop() i do:
LogPrint(" free stack: %i bytes\n", cont_get_free_stack(&stack));
LogPrint(" stack guard: %s\n", cont_check(&stack) ? "CORRUPTED" :
"OK");

every two seconds.

but the log always reads:
free stack: 4100 bytes

do i have to spawn a separate main loop with my cont_t object using
cont_run() ?

On Wed, Mar 2, 2016 at 6:13 PM, Alexander Voronin [email protected]
wrote:

In my case Exception 28 usually indicate incorrect usage of pointers -
asctime(NULL) as above and mostly print(PSTR/FPSTR/F(...)). In most cases
I use something like print(PSTR("debug")) instead of print(F("debug"))
and got error as should.


Reply to this email directly or view it on GitHub
#1679 (comment).

@igrr
Copy link
Member

igrr commented Mar 3, 2016

Not exactly, you need to use the existing object.

extern "C" cont_t g_cont;

loop() {
  size_t free = cont_get_free_stack(&g_cont);
  // etc
}

P.S. for further discussion please visit our gitter chat or open a separate issue, let's not hijack the original issue :)

@everslick
Copy link
Contributor

On Thu, Mar 3, 2016 at 4:32 PM, Ivan Grokhotkov [email protected]
wrote:

extern "C" cont_t g_cont;

ahh, thx. without calling cont_init() on it i guess ?

@igrr igrr modified the milestones: 2.2.0, 2.3.0 Apr 18, 2016
@igrr igrr modified the milestones: 2.3.0, 2.4.0 Jun 3, 2016
@5chufti
Copy link
Contributor

5chufti commented Nov 24, 2017

thank you for your effort, your implementation and example seem to work.
BUT:
a) with all the headers to pull in and undocumented functions it is not very "arduinish" to use.

b) I think it should be emphasized in the example that there is no automatic DST switchover in core functions. So maybe you would like to add few lines to setup() to show how easy real TZ setup can be achieved?

#else // ntp

  configTime(0, 0, "pool.ntp.org");
  settimeofday(0, nullptr);
  setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 3);
  tzset();
  WiFi.mode(WIFI_STA);
  WiFi.begin(SSID, SSIDPWD);
  // don't wait, observe time changing when ntp timestamp is received

#endif // ntp

I'm not belitteling your effort but I think the general arduino user is not concerned about monotonic system timestamps, they more likely are searching for local realtime. IMHO People concerned about monotonic µs timestamps should be using sdk ...
have system allways return UTC (be ntp compatible, all un*x systems I know have hw/system clock on UTC) and forget about tz and dst-offset in core functions, they are more confusing than helpfull.

@d-a-v
Copy link
Collaborator

d-a-v commented Nov 24, 2017

It would be nice to have such an official example sketch with energy saving and NTP updates when coming up alive to keep sensor logs accurate.

Instead of adding your not-arduinish-too few lines, why wouldn't you write something like this function and propose it as a PR along with a sketch using it (a new one or the current esp8266/NTP-TZ-DST)

#define TZ_CHINA_MAINLAND "xxxyyy"
#define TZ_GERMANY "CET-1CEST,M3.5.0,M10.5.0/3"
#define TZ_...
...

void configTime (const char* TZ, const char* server1, const char* server2, const char* server3)
{
    setenv("TZ", TZ, ...);
    tzset()
    ...
}

@igrr @devyte what would you think of such an overload of configTime() ?

@5chufti
Copy link
Contributor

5chufti commented Nov 24, 2017

Hi d-a-v,
sorry if I just seem to be wasting your time.
I am not asking anybody to do something on my behalf, after 30+years in SW development I find my way around (except where problems hide in binary blobs - as is often the case with ESP).
I am just around to remind some of the devs that arduino is about "k.i.s.s." and I couldn't see it here.
Having system ignorant about TZ and DST (UTC only) is fine, so no overload is necessary, just remove the confusing remains also and give a decent example of how - even w/o additional libs - local time is achievable via ntp or rtc - easy as that. If thinking about overload, I would plead for an initial timestamp!

@devyte
Copy link
Collaborator

devyte commented Nov 24, 2017

Alright, I've been keeping out of this discussion on purpose, mostly because I'm not using this time functionality, and because I currently don't have the details loaded into my brain of what the "standard" or "posixy" way of doing things are.

What I am using is TimeLib, from which I derived my own slightly modified version, and it has been working without issues for months now.
Here are my thoughts from a top-level point of view, which completely disregard the current state of this implementation. To be specific, that means that I haven't looked at this implementation (apologies), and this is how I would approach implementing the whole thing:

  1. I would break this functionality into 3 parts: time keeping, time providing, time adjusting.
  • Time keeping means just maintain time on the ESP, as in adjust a seconds counter or something every so-and-so ticks.
  • Time providing means where does the time get set from after bootup. There are three possibilities: manual setting, NTP, or external RTC. In addition, for the last two cases at least, time should be synced every so often from the provider. I would suggest a callback method here, similar to what TimeLib does, simply because it is so easy. You pass as argument a function that when called somehow returns the current time, whether it comes from an NTP request or from an external RTC comm.
  • Time adjusting means compensate for time zone and DST. Time keeping should be in UTC, but when requesting the time from the system, these adjustments should be taken into account. Something most implementations forget is that there are non-integer timezones.
    Each of these is a separate concept, and should be more or less separate of the other, which means function calls that are specific to each, and don't mix arguments.
    So, about the configTime overload, I would prefer to not mix a TZ setting with NTP server names.
  1. There are several implementations of time and zones and so on out there, one of which is TimeLib. We probably don't want to reinvent the wheel. That means that, when in doubt, look at what the other libs are doing.
    TimeLib does have at least one flaw: the timezone is an integer.

  2. DST switches over on specific dates, and these dates are different for different countries. Not only that, but some countries change the official dates every so often (example in point: my own country, just ask any IT here how much they love the government). This seriously complicates trying to implement automatic changeover of DST to give correct time. As a result, most embedded devices don't implement this.

  3. Implementing the time zone strings with #defines of const char strings will increase mem usage. I would suggest not showing that as an example. Or to anyone. The strings should always be in flash.
    I consider the whole string and offset thing to be complex enough that I would implement a table of some kind that can be queried (what is the time offset for this string? what is the string for this time offset? what is the time offset for this index? etc). Personally, I would put the whole thing in a file on SPIFFS like a nano database.
    Foremost, I am thinking of the memory reduction project, so I would like to reduce keeping any strings in memory where at all possible. If a time string is needed, then build it on the fly when requested, and return it, but don't keep any pieces in mem.

Do you want me to spend some time looking into the implementation, so that I can provide more detailed feedback? Maybe we can look into incorporating some of the TimeLib stuff here, making that lib superflous.

@5chufti
Copy link
Contributor

5chufti commented Nov 24, 2017

As we are in the "core", it should only provide 1a & 1b.
As you say, 1c - 4 are "next layer" but - fortunately - allready provided within newlib, so even more "arduinish" --> user don't have to find the "most compatible" TZlib, the core provides full standards compatible functions; so why hide it?

@devyte
Copy link
Collaborator

devyte commented Nov 24, 2017

@5chufti our core can provide 1a and 1b in favor of arduino compatibility, but we can also provide 1c as our own lib, similar to our other ESP8266* libs.
Please don't confuse arduino compatibility with arduino style. We are striving for compatibility, so that apps based on arduino libs can be ported to the ESP easily. We are not striving for arduino style. In general terms, there are so many things wrong with the arduino usage design, that I sometimes seriously think about taking a trip to their HQ just to yell at their devs and slap them in the face.
Robin: "hey I just implemented this new global singleton..."
Batman: "NO!" Slap!

@devyte
Copy link
Collaborator

devyte commented Nov 24, 2017

@d-a-v I'll try to take a look at the current time/ntp code, contrast against the arduino docs and against what I'm using, and provide feedback at that point. I'll try to come up with a way to get the best of all worlds. Please don't spend more time on this until then.
In the meantime, I could use your help elsewhere, to move towards 2.4 final!

@d-a-v
Copy link
Collaborator

d-a-v commented Nov 25, 2017

I will not enter into details. What I proposed was quite simple and, I believe, coherent.

  • we already have configTime(tz, dst, ntpsservers)
  • we also have newlib and its powerful tzset taking into acount tz, dst
  • we can overload configTime as follow (in a separate file.cpp so not everything is linked if not used)
void configTime (const char* tz, const char* ntp_server)
{
  setenv("TZ", tz, 1/*overwrite*/);
  tzset();
  configTime(0, 0, ntp_server);
}

with some defines which are not stored into ram/flash like the TZ_*country above, only one would be used in sketches (maybe they are already defined somewhere, I did not check). Maybe they would have to change from time to time because of specific politics per country, but they remain only defines. They can be living in their separate .h file, PRs can change them if needed, they are just harmless helpers.

We would then have one arduinish simple line per sketch that would configure in the most simple way accurate local time including DST for those who would like it, with no harm for others.

That's all what I suggested :)
(I was not aware of newlib and these powerful tzset settings before this thread, I'm glad we have it)

@d-a-v
Copy link
Collaborator

d-a-v commented Nov 25, 2017

I need to know, for low powered sketches wanting to keep accurate NTP time, if the sntp_force_request() proposed above, along with a settimeofday() callback (example) can be useful to go back to low-power mode as soon as correct time is set and logs stored.

@5chufti
Copy link
Contributor

5chufti commented Nov 25, 2017

Hi,
thanks again for your interest. As you will see from following data, these functions are very helpfull for energy efficiency. The tests were performed with following sketch and either LwIP V2 or precompiled_gcc (1.4?)

#define VER 1                    // old=0 new=1
#define PER 1                    // persistent n=0 y=1

#include <ESP8266WiFi.h>
#include <time.h>
#if VER
#include <coredecls.h>                  // settimeofday_cb() / sntp_force_request()
#endif
// to get sntp
extern "C"
{
#include "sntp.h"
}

#define SSID "open"
#define WPWD ""
IPAddress ip(192, 168, 22, 5);
IPAddress gw(192, 168, 22, 123);
IPAddress nm(255, 255, 255, 0);
IPAddress mc(255, 255, 255, 255);

time_t t = 0;

void time_is_set (void)
{
  time(&t);
  Serial.println("got time (@" + String(millis()) + "ms) " + ctime(&t));
  ESP.deepSleep(15000000);
  delay(10);
}

void setup() {
  Serial.begin(74880);
  Serial.println("setup(): " + String(millis()));
#if VER
  settimeofday_cb(time_is_set);
  configTime(0, 0, "at.pool.ntp.org");
#else
  sntp_stop();
  sntp_setservername(0, "at.pool.ntp.org");
  sntp_setservername(1, "de.pool.ntp.org");
  sntp_set_timezone(0);
  sntp_init();
#endif
  WiFi.persistent(PER);
  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gw, nm, gw, gw);
  WiFi.begin(SSID, WPWD);
  //  WiFi.begin();
  while (WiFi.status() != WL_CONNECTED) delay(1);
  Serial.println("WiFi connected: " + String(millis()));
#if !PER
  ESP.eraseConfig();
#endif
#if VER
  sntp_force_request();
}
#else
  while (t == 0) {
    t = sntp_get_current_timestamp();
    delay(1);
  }
  Serial.println("got time (@" + String(millis()) + "ms) " + ctime(&t));
  Serial.println(ctime(&t));
  ESP.deepSleep(15000000);
  delay(10);
}
#endif

void loop() {
  yield();
}

The results show that with LwIP V2 time until first valid timestamp was considerably longer than with old version.

#################### LwIP2, persisted WiFi conn. #############

setup(): 197
WiFi connected: 343
got time: 6414

setup(): 206
WiFi connected: 348
got time: 6441

setup(): 203
WiFi connected: 357
got time: 6449

setup(): 194
WiFi connected: 339
got time: 6365

#################### LwIP2, w/o persisted WiFi conn. ##############

setup(): 303
WiFi connected: 3344
got time: 7518

setup(): 307
WiFi connected: 3349
got time: 7369

setup(): 302
WiFi connected: 3351
got time: 7465

setup(): 305
WiFi connected: 3349
got time: 7491

#################### LwIP, persisted WiFi conn. ###############

setup(): 191
WiFi connected: 338
got time: 1123

setup(): 209
WiFi connected: 351
got time: 1055

setup(): 197
WiFi connected: 341
got time: 1118

setup(): 193
WiFi connected: 338
got time: 1137


#################### LwIP, w/o persisted WiFi conn. ###############

setup(): 307
WiFi connected: 3348
got time: 4568

setup(): 293
WiFi connected: 3334
got time: 4346

setup(): 306
WiFi connected: 3345
got time: 4463

setup(): 301
WiFi connected: 3377
got time: 4397

Using "sntp_force_request()" this is now considerably shortened, especially with persistent WiFi connection !!!

#################### LwIP2, force, persisted WiFi conn. #############

setup(): 206
WiFi connected: 351
got time (@397ms) Sat Nov 25 19:57:36 2017

setup(): 197
WiFi connected: 343
got time (@379ms) Sat Nov 25 19:57:51 2017

setup(): 199
WiFi connected: 347
got time (@369ms) Sat Nov 25 19:58:06 2017

setup(): 203
WiFi connected: 352
got time (@398ms) Sat Nov 25 19:58:21 2017

#################### LwIP2, force, w/o persisted WiFi conn. #############

setup(): 304
WiFi connected: 3348
got time (@3533ms) Sat Nov 25 19:53:08 2017

setup(): 306
WiFi connected: 3346
got time (@3537ms) Sat Nov 25 19:54:03 2017

setup(): 307
WiFi connected: 3345
got time (@3535ms) Sat Nov 25 19:54:21 2017

setup(): 314
WiFi connected: 3355
got time (@3538ms) Sat Nov 25 19:54:39 2017

so, again, thank you for your effort

@d-a-v
Copy link
Collaborator

d-a-v commented Nov 26, 2017

Thanks for testing !
I'll try to have a look into lwip2's sntp init(boot time)/reinit(dhcp) to get a faster ntp update once wifi link is up.
For coherency, lwip2 should also be configured to allow 3 ntp servers like lwip1.4 (instead of one).

@d-a-v
Copy link
Collaborator

d-a-v commented Nov 29, 2017

#3889 @BrandonLWhite
Do you think is is easy to take into account settimeofday()'s Usec and integrate it in system time ?

@BrandonLWhite
Copy link
Contributor

BrandonLWhite commented Nov 29, 2017

@d-a-v , yes for sure. I believe what should happen is to remove setting s_bootTimeSet in settimeofday (that can go back to non-extern I think), and call a new function in time.c for setting the s_bootTime_us. So something like this:

void setBootTime(uint64_t now_us)
{
     s_bootTime_us = now_us - micros64();
     s_bootTimeSet = true;
}

ensureBootTimeIsSet then becomes (to stay DRY)

static void ensureBootTimeIsSet()
{
....
        if (now_s)
        {
            setBootTime(now_s * 1000000ULL);
        }
    }
}

then over in settimeofday

if (tv) /* after*/
    {
        sntp_set_system_time(tv->tv_sec);
        // reset time subsystem
        setBootTime(tv->tv_sec * 1000000ULL | tv->tv_usec);
    }

Another thing I will throw out there, is that I think "boot time" should be renamed. It is really just an offset from micros64 that gets you the current REALTIME.

@5chufti
Copy link
Contributor

5chufti commented Nov 29, 2017

...
Another thing I will throw out there, is that I think "boot time" should be renamed. It is really just an offset from micros64 that gets you the current REALTIME.
...

:) my words ...

@d-a-v
Copy link
Collaborator

d-a-v commented Dec 20, 2017

@BrandonLWhite @5chufti can you please check #4001 ?

@5chufti
Copy link
Contributor

5chufti commented Dec 20, 2017

as soon as I'm back from holidays...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet