timemanager fixes

This commit is contained in:
Klaus K Wilting 2019-02-22 22:28:35 +01:00
parent 3d26f737be
commit 0c1c95d868
10 changed files with 95 additions and 90 deletions

View File

@ -115,7 +115,6 @@ extern TaskHandle_t irqHandlerTask, ClockTask;
extern TimerHandle_t WifiChanTimer; extern TimerHandle_t WifiChanTimer;
extern Timezone myTZ; extern Timezone myTZ;
extern time_t LastSyncTime; extern time_t LastSyncTime;
extern RtcDateTime compiled;
// application includes // application includes
#include "led.h" #include "led.h"

View File

@ -13,14 +13,18 @@
#include "dcf77.h" #include "dcf77.h"
#endif #endif
time_t tmConvert_t(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh,
uint8_t mm, uint8_t ss);
void clock_init(void); void clock_init(void);
void clock_loop(void *pvParameters); void clock_loop(void *pvParameters);
void time_sync(void); void time_sync(void);
bool wait_for_pulse(void); int wait_for_pulse(void);
int syncTime(time_t); int syncTime(time_t);
int syncTime(uint32_t t); int syncTime(uint32_t t);
void IRAM_ATTR CLOCKIRQ(void); void IRAM_ATTR CLOCKIRQ(void);
int timepulse_init(void); int timepulse_init(void);
void timepulse_start(void); void timepulse_start(void);
int TimeIsValid(time_t t);
time_t compiledUTC(void);
#endif // _timemanager_H #endif // _timemanager_H

View File

@ -7,7 +7,7 @@
// Local logging tag // Local logging tag
static const char TAG[] = "main"; static const char TAG[] = "main";
time_t userUTCTime; // Seconds since the UTC epoch time_t userUTCTime; // Seconds since the UTC in seconds GPS time starting 1.1.2000
// do all housekeeping // do all housekeeping
void doHousekeeping() { void doHousekeeping() {

View File

@ -134,8 +134,7 @@ void init_display(const char *Productname, const char *Version) {
u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%d", cfg.rssilimit); u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%d", cfg.rssilimit);
I2C_MUTEX_UNLOCK(); // release i2c bus access I2C_MUTEX_UNLOCK(); // release i2c bus access
} } // mutex
} // init_display } // init_display
void refreshtheDisplay() { void refreshtheDisplay() {
@ -155,8 +154,10 @@ void refreshtheDisplay() {
} }
// if display is switched off we don't refresh it to relax cpu // if display is switched off we don't refresh it to relax cpu
if (!DisplayState) if (!DisplayState) {
I2C_MUTEX_UNLOCK(); // release i2c bus access
return; return;
}
// update counter (lines 0-1) // update counter (lines 0-1)
snprintf( snprintf(
@ -226,12 +227,11 @@ void refreshtheDisplay() {
u8x8.printf("%-16s", display_line6); u8x8.printf("%-16s", display_line6);
#else // we want a systime display instead LoRa status #else // we want a systime display instead LoRa status
t = myTZ.toLocal(now()); t = myTZ.toLocal(now());
timePulse = (timeStatus() == timeSet) ? timePulseSymbol : timeNoPulseSymbol; timePulse = TimeIsSynced ? timePulseSymbol : timeNoPulseSymbol;
timeState = TimePulseTick ? timeSync : ' '; timeState = TimePulseTick ? timePulse : ' ';
TimePulseTick = false; TimePulseTick = false;
u8x8.printf("%02d:%02d%c%02d%c %2d.%3s", hour(t), minute(t), u8x8.printf("%02d:%02d:%02d%c %2d.%3s", hour(t), minute(t), second(t),
TimeIsSynced ? ':' : '.', second(t), timeState, day(t), timeState, day(t), printmonth[month(t)]);
printmonth[month(t)]);
#endif #endif
// update LMiC event display (line 7) // update LMiC event display (line 7)
@ -250,8 +250,7 @@ void refreshtheDisplay() {
#endif // HAS_LORA #endif // HAS_LORA
I2C_MUTEX_UNLOCK(); // release i2c bus access I2C_MUTEX_UNLOCK(); // release i2c bus access
} } // mutex
} // refreshDisplay() } // refreshDisplay()
#endif // HAS_DISPLAY #endif // HAS_DISPLAY

View File

@ -73,19 +73,6 @@ void gps_read() {
gps.passedChecksum(), gps.failedChecksum(), gps.sentencesWithFix()); gps.passedChecksum(), gps.failedChecksum(), gps.sentencesWithFix());
} }
// helper function to convert gps date/time into time_t
time_t tmConvert_t(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh,
uint8_t mm, uint8_t ss) {
tmElements_t tm;
tm.Year = YYYY - 1970; // note year argument is offset from 1970 in time.h
tm.Month = MM;
tm.Day = DD;
tm.Hour = hh;
tm.Minute = mm;
tm.Second = ss;
return makeTime(tm);
}
// function to fetch current time from gps // function to fetch current time from gps
time_t get_gpstime(void) { time_t get_gpstime(void) {
// !! never call now() or delay in this function, this would break this // !! never call now() or delay in this function, this would break this
@ -93,8 +80,10 @@ time_t get_gpstime(void) {
time_t t = 0; time_t t = 0;
if ((gps.time.age() < 900) && (gps.time.isValid()) && if ((gps.time.age() < 950) && (gps.time.isValid())) {
(gps.date.year() >= compiled.Year())) {
ESP_LOGD(TAG, "GPS time age: %dms, is valid: %s", gps.time.age(),
gps.time.isValid() ? "yes" : "no");
// use recent gps time // use recent gps time
t = tmConvert_t(gps.date.year(), gps.date.month(), gps.date.day(), t = tmConvert_t(gps.date.year(), gps.date.month(), gps.date.day(),

View File

@ -22,7 +22,7 @@
//#define LMIC_USE_INTERRUPTS //#define LMIC_USE_INTERRUPTS
//time sync via LoRaWAN network, is not yet supported by TTN (LoRaWAN spec v1.0.3) //time sync via LoRaWAN network, is not yet supported by TTN (LoRaWAN spec v1.0.3)
//#define LMIC_ENABLE_DeviceTimeReq 1 #define LMIC_ENABLE_DeviceTimeReq 1
// 16 μs per tick // 16 μs per tick
// LMIC requires ticks to be 15.5μs - 100 μs long // LMIC requires ticks to be 15.5μs - 100 μs long

View File

@ -459,7 +459,8 @@ void user_request_network_time_callback(void *pVoidUserUTCTime,
} }
// Update userUTCTime, considering the difference between the GPS and UTC // Update userUTCTime, considering the difference between the GPS and UTC
// epoch, and the leap seconds // time, and the leap seconds
// !!! DANGER !!! This code will expire in the year when next leap second happenes
*pUserUTCTime = lmicTimeReference.tNetwork + 315964800; *pUserUTCTime = lmicTimeReference.tNetwork + 315964800;
// Current time, in ticks // Current time, in ticks
ostime_t ticksNow = os_getTime(); ostime_t ticksNow = os_getTime();
@ -474,7 +475,7 @@ void user_request_network_time_callback(void *pVoidUserUTCTime,
if (syncTime(*pUserUTCTime)) { // do we have a valid time? if (syncTime(*pUserUTCTime)) { // do we have a valid time?
#ifdef HAS_RTC #ifdef HAS_RTC
if (TimeIsSynced) if (TimeIsSynced)
set_rtctime(now()); // epoch time set_rtctime(now()); // UTC time
#endif #endif
LastSyncTime = now(); // remember time of this sync event LastSyncTime = now(); // remember time of this sync event
ESP_LOGI(TAG, "LORA has set the system time"); ESP_LOGI(TAG, "LORA has set the system time");

View File

@ -65,7 +65,8 @@ uint8_t volatile channel = 0; // channel rotation counter
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0, uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
batt_voltage = 0; // globals for display batt_voltage = 0; // globals for display
hw_timer_t *sendCycle = NULL, *homeCycle = NULL, *clockCycle = NULL, *displaytimer = NULL; hw_timer_t *sendCycle = NULL, *homeCycle = NULL, *clockCycle = NULL,
*displaytimer = NULL;
TaskHandle_t irqHandlerTask, ClockTask; TaskHandle_t irqHandlerTask, ClockTask;
SemaphoreHandle_t I2Caccess, TimePulse; SemaphoreHandle_t I2Caccess, TimePulse;
@ -73,8 +74,6 @@ bool volatile TimePulseTick = false;
bool TimeIsSynced = false; bool TimeIsSynced = false;
time_t LastSyncTime = 0; time_t LastSyncTime = 0;
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
// container holding unique MAC address hashes with Memory Alloctor using PSRAM, // container holding unique MAC address hashes with Memory Alloctor using PSRAM,
// if present // if present
std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs; std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
@ -82,7 +81,7 @@ std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
// initialize payload encoder // initialize payload encoder
PayloadConvert payload(PAYLOAD_BUFFER_SIZE); PayloadConvert payload(PAYLOAD_BUFFER_SIZE);
// set Time Zone, fetch user setting from paxcounter.conf // set Time Zone for user setting from paxcounter.conf
TimeChangeRule myDST = DAYLIGHT_TIME; TimeChangeRule myDST = DAYLIGHT_TIME;
TimeChangeRule mySTD = STANDARD_TIME; TimeChangeRule mySTD = STANDARD_TIME;
Timezone myTZ(myDST, mySTD); Timezone myTZ(myDST, mySTD);
@ -97,7 +96,7 @@ void setup() {
char features[100] = ""; 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 I2Caccess = xSemaphoreCreateMutex(); // for access management of i2c bus
if (I2Caccess) if (I2Caccess)
xSemaphoreGive(I2Caccess); // Flag the i2c bus available for use xSemaphoreGive(I2Caccess); // Flag the i2c bus available for use

View File

@ -10,63 +10,52 @@ RtcDS3231<TwoWire> Rtc(Wire); // RTC hardware i2c interface
// initialize RTC // initialize RTC
int rtc_init(void) { int rtc_init(void) {
// return = 0 -> error / return = 1 -> success if (I2C_MUTEX_LOCK()) { // block i2c bus access
// block i2c bus access
if (I2C_MUTEX_LOCK()) {
Wire.begin(HAS_RTC); Wire.begin(HAS_RTC);
Rtc.Begin(); Rtc.Begin();
if (!Rtc.IsDateTimeValid()) { // configure RTC chip
ESP_LOGW(TAG, Rtc.Enable32kHzPin(false);
"RTC has no valid RTC date/time, setting to compilation date"); Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
Rtc.SetDateTime(compiled);
}
if (!Rtc.GetIsRunning()) { if (!Rtc.GetIsRunning()) {
ESP_LOGI(TAG, "RTC not running, starting now"); ESP_LOGI(TAG, "RTC not running, starting now");
Rtc.SetIsRunning(true); Rtc.SetIsRunning(true);
} }
RtcDateTime now = Rtc.GetDateTime(); RtcDateTime tt = Rtc.GetDateTime();
time_t t = tt.Epoch32Time(); // sec2000 -> epoch
if (now < compiled) { if (!Rtc.IsDateTimeValid() || !TimeIsValid(t)) {
ESP_LOGI(TAG, "RTC date/time is older than compilation date, updating"); ESP_LOGW(TAG, "RTC has no recent time, setting to compilation date");
Rtc.SetDateTime(compiled); Rtc.SetDateTime(
RtcDateTime(compiledUTC() - SECS_YR_2000)); // epoch -> sec2000
} }
// configure RTC chip I2C_MUTEX_UNLOCK(); // release i2c bus access
Rtc.Enable32kHzPin(false); ESP_LOGI(TAG, "RTC initialized");
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone); return 1; // success
} else { } else {
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error"); ESP_LOGE(TAG, "RTC initialization error, I2C bus busy");
goto error; return 0; // failure
} }
I2C_MUTEX_UNLOCK(); // release i2c bus access
ESP_LOGI(TAG, "RTC initialized");
return 1;
error:
I2C_MUTEX_UNLOCK(); // release i2c bus access
return 0;
} // rtc_init() } // rtc_init()
int set_rtctime(time_t t) { // t is seconds epoch time starting 1.1.1970 int set_rtctime(time_t t) { // t is UTC in seconds epoch time
if (I2C_MUTEX_LOCK()) { if (I2C_MUTEX_LOCK()) {
Rtc.SetDateTime(RtcDateTime(t)); Rtc.SetDateTime(RtcDateTime(t - SECS_YR_2000)); // epoch -> sec2000
I2C_MUTEX_UNLOCK(); // release i2c bus access I2C_MUTEX_UNLOCK();
ESP_LOGI(TAG, "RTC time synced"); ESP_LOGI(TAG, "RTC time synced");
return 1; // success return 1; // success
} } else {
ESP_LOGE(TAG, "RTC set time failure"); ESP_LOGE(TAG, "RTC set time failure");
return 0; // failure return 0;
} // failure
} // set_rtctime() } // set_rtctime()
int set_rtctime(uint32_t t) { // t is epoch seconds starting 1.1.1970 int set_rtctime(uint32_t t) { // t is UTC in seconds epoch time
return set_rtctime(static_cast<time_t>(t)); return set_rtctime(static_cast<time_t>(t));
// set_rtctime() // set_rtctime()
} }
@ -74,25 +63,23 @@ int set_rtctime(uint32_t t) { // t is epoch seconds starting 1.1.1970
time_t get_rtctime(void) { time_t get_rtctime(void) {
// !! never call now() or delay in this function, this would break this // !! never call now() or delay in this function, this would break this
// function to be used as SyncProvider for Time.h // function to be used as SyncProvider for Time.h
time_t t = 0; // 0 effects calling SyncProvider() to not set time time_t t = 0;
// block i2c bus access
if (I2C_MUTEX_LOCK()) { if (I2C_MUTEX_LOCK()) {
if (Rtc.IsDateTimeValid() && Rtc.GetIsRunning()) { if (Rtc.IsDateTimeValid() && Rtc.GetIsRunning()) {
RtcDateTime tt = Rtc.GetDateTime(); RtcDateTime tt = Rtc.GetDateTime();
t = tt.Epoch32Time(); t = tt.Epoch32Time(); // sec2000 -> epoch
} }
I2C_MUTEX_UNLOCK(); // release i2c bus access I2C_MUTEX_UNLOCK();
} }
return t; return t;
} // get_rtctime() } // get_rtctime()
float get_rtctemp(void) { float get_rtctemp(void) {
// block i2c bus access
if (I2C_MUTEX_LOCK()) { if (I2C_MUTEX_LOCK()) {
RtcTemperature temp = Rtc.GetTemperature(); RtcTemperature temp = Rtc.GetTemperature();
I2C_MUTEX_UNLOCK(); // release i2c bus access I2C_MUTEX_UNLOCK();
return temp.AsFloatDegC(); return temp.AsFloatDegC();
} // while }
return 0; return 0;
} // get_rtctemp() } // get_rtctemp()

View File

@ -5,7 +5,7 @@ static const char TAG[] = "main";
void time_sync() { void time_sync() {
// synchonization of systime with external time source (GPS/LORA) // synchonization of systime with external time source (GPS/LORA)
// function is frequently called from cyclic.cpp // frequently called from cyclic.cpp
#ifdef TIME_SYNC_INTERVAL #ifdef TIME_SYNC_INTERVAL
@ -25,12 +25,11 @@ void time_sync() {
#ifdef HAS_RTC #ifdef HAS_RTC
if (TimeIsSynced) { // recalibrate RTC, if we have one if (TimeIsSynced) { // recalibrate RTC, if we have one
set_rtctime(now()); set_rtctime(now());
} } else { // we switch to fallback time after a while
else { // we switch to fallback time after a while
if ((lastTimeSync >= (TIME_SYNC_TIMEOUT * 60000)) || if ((lastTimeSync >= (TIME_SYNC_TIMEOUT * 60000)) ||
!LastSyncTime) { // sync stil due -> use RTC as fallback source !LastSyncTime) { // sync is still due -> use RTC as fallback source
syncTime(get_rtctime()); // sync with RTC time syncTime(get_rtctime()); // sync with RTC time
TimeIsSynced = false; // TimeIsSynced = false;
} }
} }
#endif #endif
@ -40,33 +39,33 @@ void time_sync() {
// helper function to sync time on start of next second // helper function to sync time on start of next second
int syncTime(time_t t) { int syncTime(time_t t) {
if (t) { if (TimeIsValid(t)) {
TimeIsSynced = wait_for_pulse(); // wait for next 1pps timepulse TimeIsSynced = wait_for_pulse(); // wait for next 1pps timepulse
setTime(t); setTime(t);
adjustTime(1); // forward time to next second adjustTime(1); // forward time to next second
LastSyncTime = now(); // store time of this sync LastSyncTime = now(); // store time of this sync
ESP_LOGD(TAG, "System time was set to %02d:%02d:%02d", hour(t), minute(t), ESP_LOGD(TAG, "Time was set to %02d:%02d:%02d", hour(t), minute(t),
second(t)); second(t));
return 1; // success return 1; // success
} else { } else {
ESP_LOGD(TAG, "System time sync attempt failed"); ESP_LOGD(TAG, "Time sync attempt failed");
TimeIsSynced = false; TimeIsSynced = false;
return 0; return 0;
} }
// failure // failure
} }
int syncTime(uint32_t t) { // t is epoch seconds starting 1.1.1970 int syncTime(uint32_t t) { // t is UTC time in seconds epoch
return syncTime(static_cast<time_t>(t)); return syncTime(static_cast<time_t>(t));
} }
// helper function to sync moment on timepulse // helper function to sync moment on timepulse
bool wait_for_pulse(void) { int wait_for_pulse(void) {
// sync on top of next second with 1pps timepulse // sync on top of next second with 1pps timepulse
if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)) == pdTRUE) if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)) == pdTRUE)
return true; // success return 1; // success
ESP_LOGD(TAG, "Missing timepulse"); ESP_LOGD(TAG, "Missing timepulse");
return false; return 0; // failure
} }
// helper function to setup a pulse per second for time synchronisation // helper function to setup a pulse per second for time synchronisation
@ -95,7 +94,7 @@ int timepulse_init() {
ESP_LOGI(TAG, "Timepulse: external (RTC)"); ESP_LOGI(TAG, "Timepulse: external (RTC)");
return 1; // success return 1; // success
} else { } else {
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error"); ESP_LOGE(TAG, "RTC initialization error, I2C bus busy");
return 0; // failure return 0; // failure
} }
return 1; // success return 1; // success
@ -132,6 +131,34 @@ void IRAM_ATTR CLOCKIRQ(void) {
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();
} }
// helper function to check plausibility of a time
int TimeIsValid(time_t 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");
return (t >= compiledUTC());
}
// helper function to convert compile time to UTC time
time_t compiledUTC(void) {
time_t t = RtcDateTime(__DATE__, __TIME__).Epoch32Time();
return myTZ.toUTC(t);
}
// helper function to convert gps date/time into time_t
time_t tmConvert_t(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh,
uint8_t mm, uint8_t ss) {
tmElements_t tm;
tm.Year =
CalendarYrToTm(YYYY); // year offset from 1970 in time.h
tm.Month = MM;
tm.Day = DD;
tm.Hour = hh;
tm.Minute = mm;
tm.Second = ss;
return makeTime(tm);
}
#if defined HAS_IF482 || defined HAS_DCF77 #if defined HAS_IF482 || defined HAS_DCF77
#if defined HAS_DCF77 && defined HAS_IF482 #if defined HAS_DCF77 && defined HAS_IF482