removal of all time libs (inital commit)

This commit is contained in:
cyberman54 2022-01-13 23:30:18 +01:00
parent bbc9cc735b
commit df8d218c43
20 changed files with 208 additions and 136 deletions

View File

@ -569,17 +569,17 @@ Send for example `83` `86` as Downlink on Port 2 to get battery status and time/
bytes 1..4 = time/date in UTC epoch seconds (LSB) bytes 1..4 = time/date in UTC epoch seconds (LSB)
byte 5 = time source & status, see below byte 5 = time source & status, see below
bits 0..3 last seen time source bits 0..3 time source
0x00 = GPS 0x00 = GPS
0x01 = RTC 0x01 = RTC
0x02 = LORA 0x02 = LORA
0x03 = unsynched (never synched) 0x03 = unsynched
0x04 = set (source unknown) 0x04 = set (source unknown)
bits 4..7 time status bits 4..7 time status
0x00 = timeNotSet (never synched) 0x00 = unknown
0x01 = timeNeedsSync (last sync failed) 0x01 = time needs sync
0x02 = timeSet (synched) 0x02 = time synched
0x87 sync time/date 0x87 sync time/date

View File

@ -4,9 +4,6 @@
#include "globals.h" #include "globals.h"
#include "timekeeper.h" #include "timekeeper.h"
#define DCF77_FRAME_SIZE (60)
#define DCF77_PULSE_LENGTH (100)
#ifdef DCF77_ACTIVE_LOW #ifdef DCF77_ACTIVE_LOW
enum dcf_pinstate { dcf_high, dcf_low }; enum dcf_pinstate { dcf_high, dcf_low };
#else #else
@ -16,7 +13,7 @@ enum dcf_pinstate { dcf_low, dcf_high };
enum DCF77_Pulses { dcf_Z, dcf_0, dcf_1 }; enum DCF77_Pulses { dcf_Z, dcf_0, dcf_1 };
void DCF77_Pulse(time_t t, uint8_t const *DCFpulse); void DCF77_Pulse(time_t t, uint8_t const *DCFpulse);
uint8_t *IRAM_ATTR DCF77_Frame(time_t const t); uint8_t *IRAM_ATTR DCF77_Frame(time_t const tt);
uint8_t IRAM_ATTR dec2bcd(uint8_t const dec, uint8_t const startpos, uint8_t const endpos, uint8_t IRAM_ATTR dec2bcd(uint8_t const dec, uint8_t const startpos, uint8_t const endpos,
uint8_t *DCFpulse); uint8_t *DCFpulse);
uint8_t IRAM_ATTR setParityBit(uint8_t const p); uint8_t IRAM_ATTR setParityBit(uint8_t const p);

View File

@ -5,7 +5,6 @@
#include <Arduino.h> #include <Arduino.h>
// Time functions // Time functions
#include <ezTime.h>
#include <RtcDateTime.h> #include <RtcDateTime.h>
#include <Ticker.h> #include <Ticker.h>
@ -112,5 +111,6 @@ typedef struct {
} sdsStatus_t; } sdsStatus_t;
extern char clientId[20]; // unique clientID extern char clientId[20]; // unique clientID
extern time_t _COMPILETIME; // epoch build time
#endif #endif

View File

@ -21,6 +21,5 @@ bool gps_hasfix();
void gps_storelocation(gpsStatus_t *gps_store); void gps_storelocation(gpsStatus_t *gps_store);
void gps_loop(void *pvParameters); void gps_loop(void *pvParameters);
time_t get_gpstime(uint16_t *msec); time_t get_gpstime(uint16_t *msec);
time_t get_gpstime(void);
#endif #endif

View File

@ -10,7 +10,7 @@
#define MOBALINE_HEAD_PULSE_LENGTH (1500) #define MOBALINE_HEAD_PULSE_LENGTH (1500)
void MOBALINE_Pulse(time_t t, uint8_t const *DCFpulse); void MOBALINE_Pulse(time_t t, uint8_t const *DCFpulse);
uint8_t *IRAM_ATTR MOBALINE_Frame(time_t const t); uint8_t *IRAM_ATTR MOBALINE_Frame(time_t const tt);
void IRAM_ATTR dec2bcd(uint8_t const dec, uint8_t const startpos, void IRAM_ATTR dec2bcd(uint8_t const dec, uint8_t const startpos,
uint8_t const endpos, uint8_t *DCFpulse); uint8_t const endpos, uint8_t *DCFpulse);

View File

@ -9,13 +9,16 @@
#include "if482.h" #include "if482.h"
#include "dcf77.h" #include "dcf77.h"
#define SECS_YR_2000 (946684800UL) // the time at the start of y2k
#define GPS_UTC_DIFF 315964800UL // seconds diff between gps and utc epoch
#define LEAP_SECS_SINCE_GPSEPOCH 18UL // state of 2021
enum timesource_t { _gps, _rtc, _lora, _unsynced, _set }; enum timesource_t { _gps, _rtc, _lora, _unsynced, _set };
extern const char timeSetSymbols[]; extern const char timeSetSymbols[];
extern Ticker timesyncer; extern Ticker timesyncer;
extern timesource_t timeSource; extern timesource_t timeSource;
extern TaskHandle_t ClockTask; extern TaskHandle_t ClockTask;
extern Timezone myTZ;
extern bool volatile TimePulseTick; // 1sec pps flag set by GPS or RTC extern bool volatile TimePulseTick; // 1sec pps flag set by GPS or RTC
extern hw_timer_t *ppsIRQ; extern hw_timer_t *ppsIRQ;
@ -25,11 +28,12 @@ void clock_loop(void *pvParameters);
void timepulse_start(void); void timepulse_start(void);
void setTimeSyncIRQ(void); void setTimeSyncIRQ(void);
uint8_t timepulse_init(void); uint8_t timepulse_init(void);
time_t timeIsValid(time_t const t); bool timeIsValid(time_t const t);
void calibrateTime(void); void calibrateTime(void);
void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec,
timesource_t mytimesource); timesource_t mytimesource);
time_t compiledUTC(void); time_t compileTime(const String compile_date);
time_t mkgmtime(const struct tm *ptm);
TickType_t tx_Ticks(uint32_t framesize, unsigned long baud, uint32_t config, TickType_t tx_Ticks(uint32_t framesize, unsigned long baud, uint32_t config,
int8_t rxPin, int8_t txPins); int8_t rxPin, int8_t txPins);

View File

@ -9,8 +9,6 @@
#define TIME_SYNC_FIXUP 25 // compensation for processing time [milliseconds] #define TIME_SYNC_FIXUP 25 // compensation for processing time [milliseconds]
#define TIME_SYNC_MAX_SEQNO 0xfe // threshold for wrap around time_sync_seqNo #define TIME_SYNC_MAX_SEQNO 0xfe // threshold for wrap around time_sync_seqNo
#define TIME_SYNC_END_FLAG (TIME_SYNC_MAX_SEQNO + 1) // end of handshake marker #define TIME_SYNC_END_FLAG (TIME_SYNC_MAX_SEQNO + 1) // end of handshake marker
#define GPS_UTC_DIFF 315964800UL // seconds diff between gps and utc epoch
#define LEAP_SECS_SINCE_GPSEPOCH 18UL // state of 2021
enum timesync_t { enum timesync_t {
timesync_tx, timesync_tx,

View File

@ -20,9 +20,9 @@ static const char TAG[] = __FILE__;
void DCF77_Pulse(time_t t, uint8_t const *DCFpulse) { void DCF77_Pulse(time_t t, uint8_t const *DCFpulse) {
TickType_t startTime = xTaskGetTickCount(); TickType_t startTime = xTaskGetTickCount();
uint8_t sec = myTZ.second(t); uint8_t sec = t % 60;
ESP_LOGD(TAG, "[%s] DCF second: %d", myTZ.dateTime("H:i:s.v").c_str(), sec); ESP_LOGD(TAG, "[%0.3f] DCF second: %d", _seconds(), sec);
// induce a DCF Pulse // induce a DCF Pulse
for (uint8_t pulse = 0; pulse <= 2; pulse++) { for (uint8_t pulse = 0; pulse <= 2; pulse++) {
@ -46,51 +46,55 @@ void DCF77_Pulse(time_t t, uint8_t const *DCFpulse) {
} // switch } // switch
// pulse pause // pulse pause
vTaskDelayUntil(&startTime, pdMS_TO_TICKS(DCF77_PULSE_LENGTH)); vTaskDelayUntil(&startTime, pdMS_TO_TICKS(100));
} // for } // for
} // DCF77_Pulse() } // DCF77_Pulse()
uint8_t *IRAM_ATTR DCF77_Frame(time_t const t) { uint8_t *IRAM_ATTR DCF77_Frame(time_t const tt) {
// array of dcf pulses for one minute, secs 0..16 and 20 are never touched, so struct tm t = {0};
// we keep them statically to avoid same recalculation every minute localtime_r(&tt, &t); // convert to local time
static uint8_t DCFpulse[DCF77_FRAME_SIZE + 1] = { // array of dcf pulses for one minute
dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, // secs 0..15 and 20 are never changing, thus we keep them statically to avoid
dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, // same recalculation every minute
dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, dcf_1};
static uint8_t DCFpulse[61] = {dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, dcf_0,
dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, dcf_0,
dcf_0, dcf_0, dcf_0, dcf_0, dcf_0, dcf_0,
dcf_0, dcf_0, dcf_1};
uint8_t Parity; uint8_t Parity;
// ENCODE DST CHANGE ANNOUNCEMENT (Sec 16) // ENCODE DST CHANGE ANNOUNCEMENT (sec 16)
DCFpulse[16] = dcf_0; // not yet implemented DCFpulse[16] = dcf_0; // not yet implemented
// ENCODE DAYLIGHTSAVING (secs 17..18) // ENCODE DAYLIGHTSAVING (secs 17..18)
DCFpulse[17] = myTZ.isDST(t) ? dcf_1 : dcf_0; // "01" = MEZ / "10" = MESZ
DCFpulse[18] = myTZ.isDST(t) ? dcf_0 : dcf_1; DCFpulse[17] = (t.tm_isdst > 0) ? dcf_1 : dcf_0;
DCFpulse[18] = (t.tm_isdst > 0) ? dcf_0 : dcf_1;
// ENCODE MINUTE (secs 21..28) // ENCODE MINUTE (secs 21..28)
Parity = dec2bcd(myTZ.minute(t), 21, 27, DCFpulse); Parity = dec2bcd(t.tm_min, 21, 27, DCFpulse);
DCFpulse[28] = setParityBit(Parity); DCFpulse[28] = setParityBit(Parity);
// ENCODE HOUR (secs 29..35) // ENCODE HOUR (secs 29..35)
Parity = dec2bcd(myTZ.hour(t), 29, 34, DCFpulse); Parity = dec2bcd(t.tm_hour, 29, 34, DCFpulse);
DCFpulse[35] = setParityBit(Parity); DCFpulse[35] = setParityBit(Parity);
// ENCODE DATE (secs 36..58) // ENCODE DATE (secs 36..58)
Parity = dec2bcd(myTZ.day(t), 36, 41, DCFpulse); Parity = dec2bcd(t.tm_mday, 36, 41, DCFpulse);
Parity += dec2bcd((myTZ.weekday(t) - 1) ? (myTZ.weekday(t) - 1) : 7, 42, 44, Parity += dec2bcd((t.tm_wday == 0) ? 7 : t.tm_wday, 42, 44, DCFpulse);
DCFpulse); Parity += dec2bcd(t.tm_mon + 1, 45, 49, DCFpulse);
Parity += dec2bcd(myTZ.month(t), 45, 49, DCFpulse); Parity += dec2bcd(t.tm_year + 1900 - 2000, 50, 57, DCFpulse);
Parity += dec2bcd(myTZ.year(t) - 2000, 50, 57, DCFpulse);
DCFpulse[58] = setParityBit(Parity); DCFpulse[58] = setParityBit(Parity);
// ENCODE MARK (sec 59) // ENCODE MARK (sec 59)
DCFpulse[59] = dcf_Z; // !! missing code here for leap second !! DCFpulse[59] = dcf_Z; // !! missing code here for leap second !!
// timestamp this frame with it's minute // timestamp this frame with it's minute
DCFpulse[60] = myTZ.minute(t); DCFpulse[60] = t.tm_min;
return DCFpulse; return DCFpulse;

View File

@ -220,7 +220,10 @@ void dp_drawPage(bool nextpage) {
// nextpage = true -> flip 1 page // nextpage = true -> flip 1 page
static uint8_t DisplayPage = 0; static uint8_t DisplayPage = 0;
char timeState; char timeState, strftime_buf[64];
time_t now;
struct tm timeinfo = {0};
#if (HAS_GPS) #if (HAS_GPS)
static bool wasnofix = true; static bool wasnofix = true;
#endif #endif
@ -320,11 +323,15 @@ void dp_drawPage(bool nextpage) {
dp_println(); dp_println();
// line 6: time + date // line 6: time + date
// 27.Feb 2019 20:27:00* // Wed Jan 12 21:49:08 *
#if (TIME_SYNC_INTERVAL) #if (TIME_SYNC_INTERVAL)
timeState = TimePulseTick ? ' ' : timeSetSymbols[timeSource]; timeState = TimePulseTick ? ' ' : timeSetSymbols[timeSource];
TimePulseTick = false; TimePulseTick = false;
dp_printf("%s", myTZ.dateTime("d.M Y H:i:s").c_str()); time(&now);
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
dp_printf("%.20s", strftime_buf);
// display inverse timeState if clock controller is enabled // display inverse timeState if clock controller is enabled
#if (defined HAS_DCF77) || (defined HAS_IF482) #if (defined HAS_DCF77) || (defined HAS_IF482)
@ -442,7 +449,10 @@ void dp_drawPage(bool nextpage) {
dp_setFont(MY_FONT_LARGE); dp_setFont(MY_FONT_LARGE);
dp_setTextCursor(0, 4); dp_setTextCursor(0, 4);
dp_printf("%s", myTZ.dateTime("H:i:s").c_str()); time(&now);
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%T", &timeinfo);
dp_printf("%.8s", strftime_buf);
break; break;
// ---------- page 5: pax graph ---------- // ---------- page 5: pax graph ----------

View File

@ -89,7 +89,7 @@ bool gps_hasfix() {
gps.altitude.age() < 4000); gps.altitude.age() < 4000);
} }
// function to poll current time from GPS data; note: this is costly // function to poll UTC time from GPS NMEA data; note: this is costly
time_t get_gpstime(uint16_t *msec) { time_t get_gpstime(uint16_t *msec) {
// poll NMEA ZDA sentence // poll NMEA ZDA sentence
@ -104,26 +104,25 @@ time_t get_gpstime(uint16_t *msec) {
// did we get a current date & time? // did we get a current date & time?
if (gpstime.isValid()) { if (gpstime.isValid()) {
time_t t = 0;
tmElements_t tm;
uint32_t delay_ms = uint32_t delay_ms =
gpstime.age() + nmea_txDelay_ms + NMEA_COMPENSATION_FACTOR; gpstime.age() + nmea_txDelay_ms + NMEA_COMPENSATION_FACTOR;
uint32_t zdatime = atof(gpstime.value()); uint32_t zdatime = atof(gpstime.value());
// convert time to maketime format and make time // convert UTC time from gps NMEA ZDA sentence to tm format
tm.Second = zdatime % 100; // second struct tm gps_tm = {0};
tm.Minute = (zdatime / 100) % 100; // minute gps_tm.tm_sec = zdatime % 100; // second (UTC)
tm.Hour = zdatime / 10000; // hour gps_tm.tm_min = (zdatime / 100) % 100; // minute (UTC)
tm.Day = atoi(gpsday.value()); // day gps_tm.tm_hour = zdatime / 10000; // hour (UTC)
tm.Month = atoi(gpsmonth.value()); // month gps_tm.tm_mday = atoi(gpsday.value()); // day, 01 to 31
tm.Year = atoi(gpsyear.value()) - 1970; // year offset from 1970 gps_tm.tm_mon = atoi(gpsmonth.value()) - 1; // month, 01 to 12
t = makeTime(tm); gps_tm.tm_year = atoi(gpsyear.value()) - 1900; // year, YYYY
ESP_LOGD(TAG, "GPS date/time: %s", // convert UTC tm to time_t epoch
UTC.dateTime(t, "d.M Y H:i:s.v T").c_str()); gps_tm.tm_isdst = 0; // UTC has no DST
time_t t = mkgmtime(&gps_tm);
// add protocol delay with millisecond precision // add protocol delay with millisecond precision
t += delay_ms / 1000 - 1; // whole seconds t += (time_t)(delay_ms / 1000);
*msec = delay_ms % 1000; // fractional seconds *msec = delay_ms % 1000; // fractional seconds
return t; return t;
@ -135,11 +134,6 @@ time_t get_gpstime(uint16_t *msec) {
} // get_gpstime() } // get_gpstime()
time_t get_gpstime(void) {
uint16_t msec;
return get_gpstime(&msec);
}
// GPS serial feed FreeRTos Task // GPS serial feed FreeRTos Task
void gps_loop(void *pvParameters) { void gps_loop(void *pvParameters) {
@ -165,14 +159,14 @@ void gps_loop(void *pvParameters) {
// GPS time, we trigger a device time update to poll time from GPS // GPS time, we trigger a device time update to poll time from GPS
if ((timeSource == _unsynced || timeSource == _set) && if ((timeSource == _unsynced || timeSource == _set) &&
(gpstime.isUpdated() && gpstime.isValid() && gpstime.age() < 1000)) { (gpstime.isUpdated() && gpstime.isValid() && gpstime.age() < 1000)) {
now();
calibrateTime(); calibrateTime();
} }
} // if } // if
// show NMEA data in verbose mode, useful only for debugging GPS, very noisy // show NMEA data in verbose mode, useful only for debugging GPS, very
// ESP_LOGV(TAG, "GPS NMEA data: passed %u / failed: %u / with fix: %u", // noisy ESP_LOGV(TAG, "GPS NMEA data: passed %u / failed: %u / with fix:
// %u",
// gps.passedChecksum(), gps.failedChecksum(), // gps.passedChecksum(), gps.failedChecksum(),
// gps.sentencesWithFix()); // gps.sentencesWithFix());

View File

@ -88,11 +88,12 @@ String IRAM_ATTR IF482_Frame(time_t t) {
char mon, out[IF482_FRAME_SIZE + 1]; char mon, out[IF482_FRAME_SIZE + 1];
switch (timeStatus()) { // indicates if time has been set and recently synced switch (sntp_get_sync_status()) { // indicates if time has been set and recently synced
case timeSet: // time is set and is synced case SNTP_SYNC_STATUS_COMPLETED: // time is set and is synced
mon = 'A'; mon = 'A';
break; break;
case timeNeedsSync: // time had been set but sync attempt did not succeed case SNTP_SYNC_STATUS_IN_PROGRESS: // time had been set but sync attempt did not succeed
case SNTP_SYNC_STATUS_RESET:
mon = 'M'; mon = 'M';
break; break;
default: // unknown time status (should never be reached) default: // unknown time status (should never be reached)
@ -101,10 +102,10 @@ String IRAM_ATTR IF482_Frame(time_t t) {
} // switch } // switch
// generate IF482 telegram // generate IF482 telegram
snprintf(out, sizeof(out), "O%cL%s\r", mon, myTZ.dateTime(t, UTC_TIME, "ymdwHis").c_str()); // snprintf(out, sizeof(out), "O%cL%s\r", mon, myTZ.dateTime(t, UTC_TIME,
// "ymdwHis").c_str());
ESP_LOGD(TAG, "[%s] IF482 date/time: %s", myTZ.dateTime("H:i:s.v").c_str(), //ESP_LOGD(TAG, "[%s] IF482 date/time: %s", ctime(time(NULL), out);
out);
return out; return out;
} }

View File

@ -51,7 +51,6 @@ void irqHandler(void *pvParameters) {
#if (TIME_SYNC_INTERVAL) #if (TIME_SYNC_INTERVAL)
// is time to be synced? // is time to be synced?
if (irqSource & TIMESYNC_IRQ) { if (irqSource & TIMESYNC_IRQ) {
now(); // ensure sysTime is recent
calibrateTime(); calibrateTime();
} }
#endif #endif

View File

@ -12,7 +12,7 @@ static const char TAG[] = __FILE__;
uint8_t MatrixDisplayIsOn = 0; uint8_t MatrixDisplayIsOn = 0;
static uint8_t displaybuf[LED_MATRIX_WIDTH * LED_MATRIX_HEIGHT / 8] = {0}; static uint8_t displaybuf[LED_MATRIX_WIDTH * LED_MATRIX_HEIGHT / 8] = {0};
static unsigned long ulLastNumMacs = 0; static unsigned long ulLastNumMacs = 0;
static time_t ulLastTime = now(); static time_t ulLastTime = time(NULL);
hw_timer_t *matrixDisplayIRQ = NULL; hw_timer_t *matrixDisplayIRQ = NULL;
@ -116,11 +116,11 @@ void refreshTheMatrixDisplay(bool nextPage) {
case 1: case 1:
const time_t t = now(); const time_t t = time(NULL);
if (ulLastTime != t) { if (ulLastTime != t) {
ulLastTime = t; ulLastTime = t;
matrix.clear(); matrix.clear();
DrawNumber(myTZ.dateTime("H:i:s").c_str()); //DrawNumber(myTZ.dateTime("H:i:s").c_str());
} }
break; break;

View File

@ -126,6 +126,7 @@ void setup() {
snprintf(clientId, 20, "paxcounter_%08x", hashedmac); snprintf(clientId, 20, "paxcounter_%08x", hashedmac);
ESP_LOGI(TAG, "Starting %s v%s (runmode=%d / restarts=%d)", clientId, ESP_LOGI(TAG, "Starting %s v%s (runmode=%d / restarts=%d)", clientId,
PROGVERSION, RTC_runmode, RTC_restarts); PROGVERSION, RTC_runmode, RTC_restarts);
ESP_LOGI(TAG, "code build date: %d", _COMPILETIME);
// print chip information on startup if in verbose mode after coldstart // print chip information on startup if in verbose mode after coldstart
#if (VERBOSE) #if (VERBOSE)

View File

@ -18,10 +18,9 @@ static const char TAG[] = __FILE__;
void MOBALINE_Pulse(time_t t, uint8_t const *DCFpulse) { void MOBALINE_Pulse(time_t t, uint8_t const *DCFpulse) {
TickType_t startTime = xTaskGetTickCount(); TickType_t startTime = xTaskGetTickCount();
uint8_t sec = myTZ.second(t); uint8_t sec = t % 60;
ESP_LOGD(TAG, "[%s] MOBALINE sec: %d", myTZ.dateTime("H:i:s.v").c_str(), ESP_LOGD(TAG, "[%0.3f] MOBALINE sec: %d", _seconds(), sec);
sec);
// induce 3 pulses // induce 3 pulses
for (uint8_t pulse = 0; pulse <= 3; pulse++) { for (uint8_t pulse = 0; pulse <= 3; pulse++) {
@ -65,29 +64,30 @@ uint8_t *IRAM_ATTR MOBALINE_Frame(time_t const tt) {
// array of dcf pulses for one minute, secs 0..16 and 20 are never touched, so // array of dcf pulses for one minute, secs 0..16 and 20 are never touched, so
// we keep them statically to avoid same recalculation every minute // we keep them statically to avoid same recalculation every minute
static uint8_t DCFpulse[DCF77_FRAME_SIZE + 1]; static uint8_t DCFpulse[61];
time_t t = myTZ.tzTime(tt); // convert to local time struct tm t = {0};
localtime_r(&tt, &t); // convert to local time
// ENCODE HEAD (bit 0)) // ENCODE HEAD (bit 0))
DCFpulse[0] = dcf_Z; // not yet implemented DCFpulse[0] = dcf_Z; // not yet implemented
// ENCODE DAYLIGHTSAVING (bit 1) // ENCODE DAYLIGHTSAVING (bit 1)
DCFpulse[1] = myTZ.isDST(t) ? dcf_1 : dcf_0; DCFpulse[1] = (t.tm_isdst > 0) ? dcf_1 : dcf_0;
// ENCODE DATE (bits 2..20) // ENCODE DATE (bits 2..20)
dec2bcd(false, year(t) - 2000, 2, 9, DCFpulse); dec2bcd(false, t.tm_year + 1900 - 2000, 2, 9, DCFpulse);
dec2bcd(false, month(t), 10, 14, DCFpulse); dec2bcd(false, t.tm_mon + 1, 10, 14, DCFpulse);
dec2bcd(false, day(t), 15, 20, DCFpulse); dec2bcd(false, t.tm_mday, 15, 20, DCFpulse);
// ENCODE HOUR (bits 21..26) // ENCODE HOUR (bits 21..26)
dec2bcd2(false, hour(t), 21, 26, DCFpulse); dec2bcd2(false, t.tm_hour, 21, 26, DCFpulse);
// ENCODE MINUTE (bits 27..33) // ENCODE MINUTE (bits 27..33)
dec2bcd2(false, minute(t), 27, 33, DCFpulse); dec2bcd2(false, t.tm_min, 27, 33, DCFpulse);
// timestamp this frame with it's minute // timestamp this frame with it's minute
DCFpulse[34] = minute(t); DCFpulse[34] = t.tm_min;
return DCFpulse; return DCFpulse;

View File

@ -372,10 +372,10 @@ void get_batt(uint8_t val[]) {
void get_time(uint8_t val[]) { void get_time(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: get time"); ESP_LOGI(TAG, "Remote command: get time");
time_t t = now(); time_t t = time(NULL);
payload.reset(); payload.reset();
payload.addTime(t); payload.addTime(t);
payload.addByte(timeStatus() << 4 | timeSource); payload.addByte(sntp_get_sync_status() << 4 | timeSource);
SendPayload(TIMEPORT); SendPayload(TIMEPORT);
}; };

View File

@ -49,8 +49,9 @@ void do_after_reset(void) {
// set time zone to user value from paxcounter.conf // set time zone to user value from paxcounter.conf
#ifdef TIME_SYNC_TIMEZONE #ifdef TIME_SYNC_TIMEZONE
myTZ.setPosix(TIME_SYNC_TIMEZONE); setenv("TZ", TIME_SYNC_TIMEZONE, 1);
ESP_LOGD(TAG, "Timezone set to %s", myTZ.getPosix().c_str()); tzset();
ESP_LOGD(TAG, "Timezone set to %s", TIME_SYNC_TIMEZONE);
#endif #endif
switch (rtc_get_reset_reason(0)) { switch (rtc_get_reset_reason(0)) {
@ -75,8 +76,8 @@ void do_after_reset(void) {
RTC_millis += sleep_time_ms; // increment system monotonic time RTC_millis += sleep_time_ms; // increment system monotonic time
ESP_LOGI(TAG, "Time spent in deep sleep: %d ms", sleep_time_ms); ESP_LOGI(TAG, "Time spent in deep sleep: %d ms", sleep_time_ms);
// restore time // do we have a valid time? -> set global variable
setMyTime(RTC_time, sleep_time_ms, _set); timeSource = timeIsValid(sleep_stop_time.tv_sec) ? _set : _unsynced;
// set wakeup state, not if we have pending OTA update // set wakeup state, not if we have pending OTA update
if (RTC_runmode == RUNMODE_SLEEP) if (RTC_runmode == RUNMODE_SLEEP)
@ -196,7 +197,7 @@ void enter_deepsleep(const uint64_t wakeup_sec, gpio_num_t wakeup_gpio) {
// time stamp sleep start time and save system monotonic time. Deep sleep. // time stamp sleep start time and save system monotonic time. Deep sleep.
gettimeofday(&RTC_sleep_start_time, NULL); gettimeofday(&RTC_sleep_start_time, NULL);
RTC_millis += millis(); RTC_millis += millis();
RTC_time = now(); time(&RTC_time);
ESP_LOGI(TAG, "Going to sleep, good bye."); ESP_LOGI(TAG, "Going to sleep, good bye.");
esp_deep_sleep_start(); esp_deep_sleep_start();
} }

View File

@ -43,7 +43,7 @@ void sdcardWriteData(uint16_t noWifi, uint16_t noBle,
__attribute__((unused)) uint16_t noBleCWA) { __attribute__((unused)) uint16_t noBleCWA) {
static int counterWrites = 0; static int counterWrites = 0;
char tempBuffer[12 + 1]; char tempBuffer[12 + 1];
time_t t = now(); time_t t = time(NULL);
#if (HAS_SDS011) #if (HAS_SDS011)
sdsStatus_t sds; sdsStatus_t sds;
#endif #endif

View File

@ -8,20 +8,16 @@
#endif #endif
#endif #endif
#define _COMPILETIME compileTime()
// Local logging tag // Local logging tag
static const char TAG[] = __FILE__; static const char TAG[] = __FILE__;
// symbol to display current time source // symbol to display current time source
// G = GPS / R = RTC / L = LORA / ? = unsynced / <blank> = sync unknown // G = GPS / R = RTC / L = LORA / * = no sync / ? = never synced
const char timeSetSymbols[] = {'G', 'R', 'L', '?', ' '}; const char timeSetSymbols[] = {'G', 'R', 'L', '*', '?'};
// set Time Zone
Timezone myTZ;
bool volatile TimePulseTick = false; bool volatile TimePulseTick = false;
timesource_t timeSource = _unsynced; timesource_t timeSource = _unsynced;
time_t _COMPILETIME = compileTime(__DATE__);
TaskHandle_t ClockTask = NULL; TaskHandle_t ClockTask = NULL;
hw_timer_t *ppsIRQ = NULL; hw_timer_t *ppsIRQ = NULL;
@ -76,15 +72,17 @@ void calibrateTime(void) {
} // calibrateTime() } // calibrateTime()
// adjust system time, calibrate RTC and RTC_INT pps // set system time (UTC), calibrate RTC and RTC_INT pps
void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec,
timesource_t mytimesource) { timesource_t mytimesource) {
struct timeval tv = {0};
// called with invalid timesource? // called with invalid timesource?
if (mytimesource == _unsynced) if (mytimesource == _unsynced)
return; return;
// increment t_sec only if t_msec > 1000 // increment t_sec if t_msec > 1000
time_t time_to_set = (time_t)(t_sec + t_msec / 1000); time_t time_to_set = (time_t)(t_sec + t_msec / 1000);
// do we have a valid time? // do we have a valid time?
@ -97,8 +95,18 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec,
vTaskDelay(pdMS_TO_TICKS(1000 - t_msec % 1000)); vTaskDelay(pdMS_TO_TICKS(1000 - t_msec % 1000));
} }
ESP_LOGI(TAG, "[%0.3f] UTC time: %d.%03d sec", _seconds(), time_to_set, tv.tv_sec = time_to_set;
t_msec % 1000); tv.tv_usec = 0;
settimeofday(&tv, NULL);
ESP_LOGI(TAG, "[%0.3f] UTC time: %d.000 sec", _seconds(), time_to_set);
// if we have a software pps timer, shift it to top of second
if (ppsIRQ != NULL) {
timerWrite(ppsIRQ, 0); // reset pps timer
CLOCKIRQ(); // fire clock pps, this advances time 1 sec
}
// if we have got an external timesource, set RTC time and shift RTC_INT pulse // if we have got an external timesource, set RTC time and shift RTC_INT pulse
// to top of second // to top of second
@ -107,15 +115,9 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec,
set_rtctime(time_to_set); set_rtctime(time_to_set);
#endif #endif
// if we have a software pps timer, shift it to top of second
if (ppsIRQ != NULL) {
timerWrite(ppsIRQ, 0); // reset pps timer
CLOCKIRQ(); // fire clock pps, this advances time 1 sec
}
UTC.setTime(time_to_set); // set the time on top of second
timeSource = mytimesource; // set global variable timeSource = mytimesource; // set global variable
sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED);
timesyncer.attach(TIME_SYNC_INTERVAL * 60, setTimeSyncIRQ); timesyncer.attach(TIME_SYNC_INTERVAL * 60, setTimeSyncIRQ);
ESP_LOGD(TAG, "[%0.3f] Timesync finished, time was set | timesource=%d", ESP_LOGD(TAG, "[%0.3f] Timesync finished, time was set | timesource=%d",
_seconds(), mytimesource); _seconds(), mytimesource);
@ -196,7 +198,7 @@ void IRAM_ATTR CLOCKIRQ(void) {
// advance wall clock, if we have // advance wall clock, if we have
#if (defined HAS_IF482 || defined HAS_DCF77) #if (defined HAS_IF482 || defined HAS_DCF77)
xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits, xTaskNotifyFromISR(ClockTask, uint32_t(time(NULL)), eSetBits,
&xHigherPriorityTaskWoken); &xHigherPriorityTaskWoken);
#endif #endif
@ -213,9 +215,9 @@ void IRAM_ATTR CLOCKIRQ(void) {
} }
// helper function to check plausibility of a given epoch time // helper function to check plausibility of a given epoch time
time_t timeIsValid(time_t const t) { bool timeIsValid(time_t const t) {
// is it a time in the past? we use compile date to guess // is t a time in the past? we use compile time to guess
return (t < myTZ.tzTime(_COMPILETIME) ? 0 : t); return (t > _COMPILETIME);
} }
// helper function to calculate serial transmit time // helper function to calculate serial transmit time
@ -245,7 +247,7 @@ void clock_init(void) {
pinMode(HAS_DCF77, OUTPUT); pinMode(HAS_DCF77, OUTPUT);
#endif #endif
time_t userUTCTime = now(); time_t userUTCTime = time(NULL);
xTaskCreatePinnedToCore(clock_loop, // task function xTaskCreatePinnedToCore(clock_loop, // task function
"clockloop", // name of task "clockloop", // name of task
@ -263,17 +265,16 @@ void clock_loop(void *taskparameter) { // ClockTask
// caveat: don't use now() in this task, it will cause a race condition // caveat: don't use now() in this task, it will cause a race condition
// due to concurrent access to i2c bus when reading/writing from/to rtc chip! // due to concurrent access to i2c bus when reading/writing from/to rtc chip!
#define nextmin(t) (t + DCF77_FRAME_SIZE + 1) // next minute
#ifdef HAS_TWO_LED #ifdef HAS_TWO_LED
static bool led1_state = false; static bool led1_state = false;
#endif #endif
uint32_t printtime; uint32_t printtime;
time_t t = *((time_t *)taskparameter), last_printtime = 0; // UTC time seconds time_t t = *((time_t *)taskparameter); // UTC time seconds
time_t last_printtime = 0;
#ifdef HAS_DCF77 #ifdef HAS_DCF77
uint8_t *DCFpulse; // pointer on array with DCF pulse bits uint8_t *DCFpulse; // pointer on array with DCF pulse bits
DCFpulse = DCF77_Frame(nextmin(t)); // load first DCF frame before start DCFpulse = DCF77_Frame(t + 61); // load first DCF frame before start
#elif defined HAS_IF482 #elif defined HAS_IF482
static TickType_t txDelay = pdMS_TO_TICKS(1000 - IF482_SYNC_FIXUP) - static TickType_t txDelay = pdMS_TO_TICKS(1000 - IF482_SYNC_FIXUP) -
tx_Ticks(IF482_FRAME_SIZE, HAS_IF482); tx_Ticks(IF482_FRAME_SIZE, HAS_IF482);
@ -286,9 +287,15 @@ void clock_loop(void *taskparameter) { // ClockTask
xTaskNotifyWait(0x00, ULONG_MAX, &printtime, portMAX_DELAY); xTaskNotifyWait(0x00, ULONG_MAX, &printtime, portMAX_DELAY);
t = time_t(printtime); t = time_t(printtime);
/*
// no confident or no recent time -> suppress clock output // no confident or no recent time -> suppress clock output
if ((timeStatus() == timeNotSet) || !(timeIsValid(t)) || if ((sntp_get_sync_status() != SNTP_SYNC_STATUS_COMPLETED) ||
(t == last_printtime)) !(timeIsValid(t)) || (t == last_printtime))
continue;
*/
// no confident or no recent time -> suppress clock output
if (!(timeIsValid(t)) || (t == last_printtime))
continue; continue;
#if defined HAS_IF482 #if defined HAS_IF482
@ -304,11 +311,11 @@ void clock_loop(void *taskparameter) { // ClockTask
#elif defined HAS_DCF77 #elif defined HAS_DCF77
if (second(t) == DCF77_FRAME_SIZE - 1) // is it time to load new frame? if ((t % 60) == 59) // is it time to load new frame?
DCFpulse = DCF77_Frame(nextmin(t)); // generate frame for next minute DCFpulse = DCF77_Frame(t + 61); // generate frame for next minute
if (minute(nextmin(t)) == // do we still have a recent frame? if ((((t + 61) / 60) % 60) == // do we still have a recent frame?
DCFpulse[DCF77_FRAME_SIZE]) // (timepulses could be missed!) DCFpulse[60]) // (timepulses could be missed!)
DCF77_Pulse(t + 1, DCFpulse); // then output next second's pulse DCF77_Pulse(t + 1, DCFpulse); // then output next second's pulse
// else we have no recent frame, thus suppressing clock output // else we have no recent frame, thus suppressing clock output
@ -330,3 +337,63 @@ void clock_loop(void *taskparameter) { // ClockTask
} // clock_loop() } // clock_loop()
#endif // HAS_IF482 || defined HAS_DCF77 #endif // HAS_IF482 || defined HAS_DCF77
// Convert compile date to reference time "in the past"
time_t compileTime(const String compile_date) {
char s_month[5];
int year;
struct tm t = {0};
static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
// store compile time once it's calculated
static time_t secs = -1;
if (secs == -1) {
// determine month
sscanf(compile_date.c_str(), "%s %d %d", s_month, &t.tm_mday, &year);
t.tm_mon = (strstr(month_names, s_month) - month_names) / 3;
t.tm_year = year - 1900;
// convert to secs
secs = mkgmtime(&t);
}
return secs;
}
static bool IsLeapYear(short year) {
if (year % 4 != 0)
return false;
if (year % 100 != 0)
return true;
return (year % 400) == 0;
}
// convert UTC tm time to time_t epoch time
time_t mkgmtime(const struct tm *ptm) {
const int SecondsPerMinute = 60;
const int SecondsPerHour = 3600;
const int SecondsPerDay = 86400;
const int DaysOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
time_t secs = 0;
// tm_year is years since 1900
int year = ptm->tm_year + 1900;
for (int y = 1970; y < year; ++y) {
secs += (IsLeapYear(y) ? 366 : 365) * SecondsPerDay;
}
// tm_mon is month from 0..11
for (int m = 0; m < ptm->tm_mon; ++m) {
secs += DaysOfMonth[m] * SecondsPerDay;
if (m == 1 && IsLeapYear(year))
secs += SecondsPerDay;
}
secs += (ptm->tm_mday - 1) * SecondsPerDay;
secs += ptm->tm_hour * SecondsPerHour;
secs += ptm->tm_min * SecondsPerMinute;
secs += ptm->tm_sec;
return secs;
}

View File

@ -142,9 +142,6 @@ void IRAM_ATTR timesync_processReq(void *taskparameter) {
time_offset_sec = timesync_timestamp[sample_idx - 1][gwtime_sec]; time_offset_sec = timesync_timestamp[sample_idx - 1][gwtime_sec];
time_offset_sec += time_offset_ms / 1000; time_offset_sec += time_offset_ms / 1000;
ESP_LOGD(TAG, "LORA date/time: %s",
myTZ.dateTime(time_offset_sec, "d.M Y H:i:s.v T").c_str());
setMyTime(time_offset_sec, time_offset_ms, _lora); setMyTime(time_offset_sec, time_offset_ms, _lora);
// send timesync end char to show timesync was successful // send timesync end char to show timesync was successful