From 98797c0fe1142de55d25dab167df4788b15001dd Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 24 Feb 2019 01:44:55 +0100 Subject: [PATCH] timemanager reworked --- include/cyclic.h | 2 +- include/globals.h | 3 +- include/lorawan.h | 2 +- include/main.h | 2 +- include/rtctime.h | 2 +- include/{timemanager.h => timekeeper.h} | 16 +++--- src/display.cpp | 6 +- src/lorawan.cpp | 4 -- src/main.cpp | 18 +++--- src/paxcounter.conf | 7 +-- src/rtctime.cpp | 16 +++--- src/{timemanager.cpp => timekeeper.cpp} | 75 +++++++++++-------------- 12 files changed, 68 insertions(+), 85 deletions(-) rename include/{timemanager.h => timekeeper.h} (69%) rename src/{timemanager.cpp => timekeeper.cpp} (78%) diff --git a/include/cyclic.h b/include/cyclic.h index 7e80637f..89ccb240 100644 --- a/include/cyclic.h +++ b/include/cyclic.h @@ -5,7 +5,7 @@ #include "senddata.h" #include "rcommand.h" #include "spislave.h" -#include "timemanager.h" +#include "timekeeper.h" #include #ifdef HAS_BME diff --git a/include/globals.h b/include/globals.h index 17c485c2..349e61bd 100644 --- a/include/globals.h +++ b/include/globals.h @@ -108,13 +108,12 @@ extern uint8_t volatile channel; // wifi channel rotation counter extern uint16_t volatile macs_total, macs_wifi, macs_ble, batt_voltage; // display values extern bool volatile TimePulseTick; // one-pulse-per-second flags set by GPS or RTC -extern bool TimeIsSynced; extern hw_timer_t *sendCycle, *displaytimer, *clockCycle; extern SemaphoreHandle_t I2Caccess, TimePulse; extern TaskHandle_t irqHandlerTask, ClockTask; extern TimerHandle_t WifiChanTimer; extern Timezone myTZ; -extern time_t lastSyncTime, userUTCTime; +extern time_t userUTCTime; // application includes #include "led.h" diff --git a/include/lorawan.h b/include/lorawan.h index 30620dc5..76a57397 100644 --- a/include/lorawan.h +++ b/include/lorawan.h @@ -3,6 +3,7 @@ #include "globals.h" #include "rcommand.h" +#include "timekeeper.h" // LMIC-Arduino LoRaWAN Stack #include @@ -10,7 +11,6 @@ #include #include #include "loraconf.h" -#include "rtctime.h" // Needed for 24AA02E64, does not hurt anything if included and not used #ifdef MCP_24AA02E64_I2C_ADDRESS diff --git a/include/main.h b/include/main.h index 44f2279d..b60ab7b9 100644 --- a/include/main.h +++ b/include/main.h @@ -17,5 +17,5 @@ #include "led.h" #include "spislave.h" #include "lorawan.h" -#include "timemanager.h" +#include "timekeeper.h" #endif \ No newline at end of file diff --git a/include/rtctime.h b/include/rtctime.h index a4788c22..e9c58b27 100644 --- a/include/rtctime.h +++ b/include/rtctime.h @@ -2,7 +2,7 @@ #define _RTCTIME_H #include "globals.h" -#include "timemanager.h" +#include "timekeeper.h" #include // must be included here so that Arduino library object file references work #include diff --git a/include/timemanager.h b/include/timekeeper.h similarity index 69% rename from include/timemanager.h rename to include/timekeeper.h index 16e7276a..d627e10d 100644 --- a/include/timemanager.h +++ b/include/timekeeper.h @@ -1,5 +1,5 @@ -#ifndef _timemanager_H -#define _timemanager_H +#ifndef _timekeeper_H +#define _timekeeper_H #include "globals.h" #include "rtctime.h" @@ -15,17 +15,17 @@ enum timesources { pps, rtc, lora, unsynced }; +void IRAM_ATTR CLOCKIRQ(void); void clock_init(void); void clock_loop(void *pvParameters); void time_sync(void); -int wait_for_pulse(void); -int syncTime(time_t const t, uint8_t const timesource); -void IRAM_ATTR CLOCKIRQ(void); -int timepulse_init(void); void timepulse_start(void); -int TimeIsValid(time_t const t); +uint8_t wait_for_pulse(void); +uint8_t syncTime(time_t const t, uint8_t const caller); +uint8_t timepulse_init(void); +uint8_t TimeIsValid(time_t const t); time_t compiledUTC(void); time_t tmConvert(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh, uint8_t mm, uint8_t ss); -#endif // _timemanager_H \ No newline at end of file +#endif // _timekeeper_H \ No newline at end of file diff --git a/src/display.cpp b/src/display.cpp index 41a58010..54e6f1ad 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -131,8 +131,7 @@ void init_display(const char *Productname, const char *Version) { void refreshtheDisplay() { uint8_t msgWaiting; - char timeIsSet, timeState; - char buff[16]; // 16 chars line buffer + char timeState, buff[16]; time_t t; // block i2c bus access @@ -218,8 +217,7 @@ void refreshtheDisplay() { u8x8.printf("%-16s", display_line6); #else // we want a systime display instead LoRa status t = myTZ.toLocal(now()); - timeIsSet = (timeStatus() == timeNotSet) ? '#' : timeSource; - timeState = TimePulseTick ? ' ' : timeIsSet; + timeState = TimePulseTick ? ' ' : timeSource; TimePulseTick = false; u8x8.printf("%02d:%02d:%02d%c %2d.%3s", hour(t), minute(t), second(t), timeState, day(t), printmonth[month(t)]); diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 40f2d1e8..7c4ead8e 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -473,10 +473,6 @@ void user_request_network_time_callback(void *pVoidUserUTCTime, // Update system time with time read from the network if (syncTime(*pUserUTCTime, lora)) { // have we got a valid time? -#ifdef HAS_RTC - if (TimeIsSynced) - set_rtctime(now()); // UTC time -#endif ESP_LOGI(TAG, "LORA has set the system time"); } else ESP_LOGI(TAG, "Unable to sync system time with LORA"); diff --git a/src/main.cpp b/src/main.cpp index e4056af0..3bbac73f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -71,8 +71,7 @@ hw_timer_t *sendCycle = NULL, *homeCycle = NULL, *clockCycle = NULL, TaskHandle_t irqHandlerTask, ClockTask; SemaphoreHandle_t I2Caccess, TimePulse; bool volatile TimePulseTick = false; -bool TimeIsSynced = false; -time_t lastSyncTime = 0, userUTCTime = 0; +time_t userUTCTime = 0; // container holding unique MAC address hashes with Memory Alloctor using PSRAM, // if present @@ -96,7 +95,7 @@ void setup() { char features[100] = ""; - // create some semaphores for syncing / mutexing tasks + // create some semaphores for syncing / mutexing tasks I2Caccess = xSemaphoreCreateMutex(); // for access management of i2c bus if (I2Caccess) xSemaphoreGive(I2Caccess); // Flag the i2c bus available for use @@ -358,13 +357,12 @@ void setup() { #endif #endif - // start pps timepulse - ESP_LOGI(TAG, "Starting Timepulse..."); - if (timepulse_init()) // setup timepulse - timepulse_start(); // start pulse - else - ESP_LOGE(TAG, "No timepulse, time will not be synced!"); - time_sync(); + // start pps timepulse and timekeepr + ESP_LOGI(TAG, "Starting Timekeeper..."); + assert(timepulse_init()); // setup timepulse + timepulse_start(); + time_sync(); // sync time + setSyncInterval(TIME_SYNC_INTERVAL * 60); // controls timeStatus() // start wifi in monitor mode and start channel rotation timer ESP_LOGI(TAG, "Starting Wifi..."); diff --git a/src/paxcounter.conf b/src/paxcounter.conf index e1f48b01..0579e8b5 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -81,10 +81,9 @@ #define OTA_MIN_BATT 3600 // minimum battery level for OTA [millivolt] #define RESPONSE_TIMEOUT_MS 60000 // firmware binary server connection timeout [milliseconds] -// settings for syncing time of node and external time sources -#define TIME_SYNC_INTERVAL 10 // sync time each .. minutes from external time source (GPS/LORA) [default = 10], comment out means off -#define TIME_SYNC_TIMEOUT 30 // fallback to rtc for timesync after .. minutes no sync with external time source -#define TIME_SYNC_LORA 1 // use LORA network for timesync, comment out means off [default = off] +// settings for syncing time of node with external time source +#define TIME_SYNC_INTERVAL 10 // sync time each .. minutes from time source (GPS/LORA) [default = 10], comment out means off +#define TIME_SYNC_LORA 1 // use LORA network as time source, comment out means off [default = off] // time zone, see https://github.com/JChristensen/Timezone/blob/master/examples/WorldClock/WorldClock.ino #define DAYLIGHT_TIME {"CEST", Last, Sun, Mar, 2, 120} // Central European Summer Time diff --git a/src/rtctime.cpp b/src/rtctime.cpp index a3bf3fcf..f626e390 100644 --- a/src/rtctime.cpp +++ b/src/rtctime.cpp @@ -24,14 +24,16 @@ int rtc_init(void) { Rtc.SetIsRunning(true); } - RtcDateTime tt = Rtc.GetDateTime(); - time_t t = tt.Epoch32Time(); // sec2000 -> epoch + /* + RtcDateTime tt = Rtc.GetDateTime(); + time_t t = tt.Epoch32Time(); // sec2000 -> epoch - if (!Rtc.IsDateTimeValid() || !TimeIsValid(t)) { - ESP_LOGW(TAG, "RTC has no recent time, setting to compilation date"); - Rtc.SetDateTime( - RtcDateTime(compiledUTC() - SECS_YR_2000)); // epoch -> sec2000 - } + if (!Rtc.IsDateTimeValid() || !TimeIsValid(t)) { + ESP_LOGW(TAG, "RTC has no recent time, setting to compilation date"); + Rtc.SetDateTime( + RtcDateTime(compiledUTC() - SECS_YR_2000)); // epoch -> sec2000 + } + */ I2C_MUTEX_UNLOCK(); // release i2c bus access ESP_LOGI(TAG, "RTC initialized"); diff --git a/src/timemanager.cpp b/src/timekeeper.cpp similarity index 78% rename from src/timemanager.cpp rename to src/timekeeper.cpp index 47f1d7c2..6a1c46ec 100644 --- a/src/timemanager.cpp +++ b/src/timekeeper.cpp @@ -1,4 +1,4 @@ -#include "timemanager.h" +#include "timekeeper.h" // Local logging tag static const char TAG[] = "main"; @@ -9,66 +9,57 @@ void time_sync() { #ifdef TIME_SYNC_INTERVAL - static time_t ageOfTime = 0; - - ageOfTime = now() - lastSyncTime; // check if a sync is due - - // is it time to sync with external source or did we never sync yet? - if ((ageOfTime >= (TIME_SYNC_INTERVAL * 60000)) || !lastSyncTime) { + if (timeStatus() == timeSet) + return; #ifdef HAS_GPS - syncTime(get_gpstime(), pps); // attempt sync with GPS time + if (syncTime(get_gpstime(), pps)) + return; // attempt sync with GPS time #endif -#if defined HAS_LORA && defined TIME_SYNC_LORA - if (!TimeIsSynced) // no GPS sync -> try lora sync - LMIC_requestNetworkTime(user_request_network_time_callback, - &userUTCTime); -#endif - } - +// no GPS -> fallback to RTC time #ifdef HAS_RTC - if (TimeIsSynced) { // recalibrate RTC, if we have one - set_rtctime(now()); - } else { // we switch to fallback time after a while - if ((ageOfTime >= (TIME_SYNC_TIMEOUT * 60000)) || - !lastSyncTime) { // sync is still due -> use RTC as fallback source - if (!syncTime(get_rtctime(), rtc)) // sync with RTC time - ESP_LOGW(TAG, "no valid time"); - TimeIsSynced = false; - } - } + if (!syncTime(get_rtctime(), rtc)) // sync with RTC time + ESP_LOGW(TAG, "no confident RTC time"); +#endif + +// try lora sync if we have +#if defined HAS_LORA && defined TIME_SYNC_LORA + LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime); #endif #endif // TIME_SYNC_INTERVAL } // time_sync() // helper function to sync time on start of next second -int syncTime(time_t const t, uint8_t const timesource) { +uint8_t syncTime(time_t const t, uint8_t const caller) { // symbol to display current time source - const char timeSetSymbols[] = {'G', 'R', 'L', '~'}; + const char timeSetSymbols[] = {'G', 'R', 'L', '?'}; if (TimeIsValid(t)) { - TimeIsSynced = wait_for_pulse(); // wait for next 1pps timepulse + uint8_t const TimeIsPulseSynced = + wait_for_pulse(); // wait for next 1pps timepulse setTime(t); - adjustTime(1); // forward time to next second - lastSyncTime = now(); // store time of this sync - timeSource = timeSetSymbols[timesource]; + adjustTime(1); // forward time to next second + timeSource = timeSetSymbols[caller]; ESP_LOGD(TAG, "Time source %c set time to %02d:%02d:%02d", timeSource, hour(t), minute(t), second(t)); +#ifdef HAS_RTC + if ((TimeIsPulseSynced) && (caller != rtc)) + set_rtctime(now()); +#endif return 1; // success + } else { + ESP_LOGD(TAG, "Time source %c sync attempt failed", timeSetSymbols[caller]); timeSource = timeSetSymbols[unsynced]; - TimeIsSynced = false; - ESP_LOGD(TAG, "Time source %c sync attempt failed", timeSource); - return 0; + return 0; // failure } - // failure -} +} // syncTime() // helper function to sync moment on timepulse -int wait_for_pulse(void) { +uint8_t wait_for_pulse(void) { // sync on top of next second with 1pps timepulse if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1010)) == pdTRUE) return 1; // success @@ -77,7 +68,7 @@ int wait_for_pulse(void) { } // helper function to setup a pulse per second for time synchronisation -int timepulse_init() { +uint8_t timepulse_init() { // use time pulse from GPS as time base with fixed 1Hz frequency #ifdef GPS_INT @@ -140,7 +131,7 @@ void IRAM_ATTR CLOCKIRQ(void) { } // helper function to check plausibility of a time -int TimeIsValid(time_t const t) { +uint8_t TimeIsValid(time_t const t) { // is it a time in the past? we use compile date to guess ESP_LOGD(TAG, "t=%d, tt=%d, valid: %s", t, compiledUTC(), (t >= compiledUTC()) ? "yes" : "no"); @@ -202,9 +193,9 @@ void clock_loop(void *pvParameters) { // ClockTask #define t1(t) (t + DCF77_FRAME_SIZE + 1) // future time for next DCF77 frame #define t2(t) (t + 1) // future time for sync with 1pps trigger -// preload first DCF frame before start + // preload first DCF frame before start #ifdef HAS_DCF77 - uint8_t *DCFpulse; + uint8_t *DCFpulse; // pointer on array with DCF pulse bits DCFpulse = DCF77_Frame(t1(now())); #endif @@ -213,7 +204,7 @@ void clock_loop(void *pvParameters) { // ClockTask xTaskNotifyWait(0x00, ULONG_MAX, &wakeTime, portMAX_DELAY); // wait for timepulse - if (timeStatus() == timeNotSet) // do we have valid time? + if (timeStatus() != timeSet) // no confident time -> no output to clock continue; t = now(); // payload to send to clock