From cad13b72a14d9af954b276a2e5f70230937bbbce Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 24 Mar 2019 00:15:04 +0100 Subject: [PATCH] timesync fixes --- include/timesync.h | 4 +- src/irqhandler.cpp | 10 +---- src/main.cpp | 2 +- src/ota.cpp | 2 +- src/rtctime.cpp | 2 +- src/timekeeper.cpp | 20 +++++---- src/timesync.cpp | 102 ++++++++++++++++----------------------------- 7 files changed, 56 insertions(+), 86 deletions(-) diff --git a/include/timesync.h b/include/timesync.h index d428cad1..365c54c0 100644 --- a/include/timesync.h +++ b/include/timesync.h @@ -6,12 +6,12 @@ #include "timesync.h" #include "timekeeper.h" -#define TIME_SYNC_SAMPLES 2 // number of time requests for averaging +#define TIME_SYNC_SAMPLES 1 // number of time requests for averaging #define TIME_SYNC_CYCLE 20 // delay between two time samples [seconds] #define TIME_SYNC_TIMEOUT 120 // timeout waiting for timeserver answer [seconds] #define TIME_SYNC_TRIGGER 100 // deviation triggering a time sync [milliseconds] #define TIME_SYNC_FRAME_LENGTH 0x06 // timeserver answer frame length [bytes] -#define TIME_SYNC_FIXUP 0 // calibration to fixup processing time [milliseconds] +#define TIME_SYNC_FIXUP 30 // calibration to fixup processing time [milliseconds] void send_timesync_req(void); int recv_timesync_ans(uint8_t buf[], uint8_t buf_len); diff --git a/src/irqhandler.cpp b/src/irqhandler.cpp index 1fa349ab..11bc50f0 100644 --- a/src/irqhandler.cpp +++ b/src/irqhandler.cpp @@ -56,13 +56,10 @@ void irqHandler(void *pvParameters) { #ifdef HAS_DISPLAY void IRAM_ATTR DisplayIRQ() { - portENTER_CRITICAL_ISR(&mux); - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, &xHigherPriorityTaskWoken); - portEXIT_CRITICAL_ISR(&mux); if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR(); } @@ -70,13 +67,10 @@ void IRAM_ATTR DisplayIRQ() { #ifdef HAS_BUTTON void IRAM_ATTR ButtonIRQ() { - portENTER_CRITICAL_ISR(&mux); - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; xTaskNotifyFromISR(irqHandlerTask, BUTTON_IRQ, eSetBits, &xHigherPriorityTaskWoken); - portEXIT_CRITICAL_ISR(&mux); if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR(); diff --git a/src/main.cpp b/src/main.cpp index b50e56c4..fe605409 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -180,7 +180,7 @@ void setup() { strcat_P(features, " PSRAM"); #endif -// set external power mode to off +// set external power mode #ifdef EXT_POWER_SW pinMode(EXT_POWER_SW, OUTPUT); digitalWrite(EXT_POWER_SW, EXT_POWER_ON); diff --git a/src/ota.cpp b/src/ota.cpp index a2623702..fc1662bc 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -1,4 +1,4 @@ -#ifdef USE_OTA +#if (USE_OTA) /* Parts of this code: diff --git a/src/rtctime.cpp b/src/rtctime.cpp index 3a82d84e..ceabbb20 100644 --- a/src/rtctime.cpp +++ b/src/rtctime.cpp @@ -24,7 +24,7 @@ uint8_t rtc_init(void) { Rtc.SetIsRunning(true); } -#ifdef TIME_SYNC_COMPILEDATE +#if (TIME_SYNC_COMPILEDATE) // initialize a blank RTC without battery backup with compiled time RtcDateTime tt = Rtc.GetDateTime(); time_t t = tt.Epoch32Time(); // sec2000 -> epoch diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index 2573ccba..b425dc96 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -122,10 +122,9 @@ void timepulse_start(void) { void IRAM_ATTR CLOCKIRQ(void) { portENTER_CRITICAL_ISR(&mux); - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; - SyncToPPS(); // calibrates UTC systime, see microTime.h + SyncToPPS(); // calibrates UTC systime and advances it +1, see microTime.h if (ClockTask != NULL) xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits, @@ -215,7 +214,8 @@ void clock_loop(void *taskparameter) { // ClockTask #define nextmin(t) (t + DCF77_FRAME_SIZE + 1) // next minute uint32_t printtime; - time_t t = *((time_t *)taskparameter); // UTC time seconds + time_t t = *((time_t *)taskparameter), last_printtime = 0; // UTC time seconds + TickType_t startTime; #ifdef HAS_DCF77 uint8_t *DCFpulse; // pointer on array with DCF pulse bits @@ -228,18 +228,24 @@ void clock_loop(void *taskparameter) { // ClockTask // output the next second's pulse after timepulse arrived for (;;) { + // ensure the notification state is not already pending xTaskNotifyWait(0x00, ULONG_MAX, &printtime, portMAX_DELAY); // wait for timepulse + startTime = xTaskGetTickCount(); + t = time_t(printtime); // UTC time seconds - // no confident time -> suppress clock output - if ((timeStatus() == timeNotSet) || !(timeIsValid(t))) + // no confident or no recent time -> suppress clock output + if ((timeStatus() == timeNotSet) || !(timeIsValid(t)) || + (t == last_printtime)) continue; + last_printtime = t; + #if defined HAS_IF482 - vTaskDelay(txDelay); // wait until moment to fire + vTaskDelayUntil(&startTime, txDelay); // wait until moment to fire IF482.print(IF482_Frame(t + 1)); // note: if482 telegram for *next* second #elif defined HAS_DCF77 diff --git a/src/timesync.cpp b/src/timesync.cpp index 16385484..e90c2628 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -27,7 +27,6 @@ typedef std::chrono::system_clock myClock; typedef myClock::time_point myClock_timepoint; typedef std::chrono::duration> myClock_msecTick; -typedef std::chrono::duration myClock_secTick; myClock_timepoint time_sync_tx[TIME_SYNC_SAMPLES]; myClock_timepoint time_sync_rx[TIME_SYNC_SAMPLES]; @@ -63,11 +62,11 @@ void send_timesync_req() { // task for sending time sync requests void process_timesync_req(void *taskparameter) { - uint32_t seq_no = 0, time_to_set_us, time_to_set_ms; - uint16_t time_to_set_fraction_msec; uint8_t k = 0, i = 0; + uint16_t time_to_set_fraction_msec; + uint32_t seq_no = 0; time_t time_to_set; - auto time_offset = myClock_msecTick::zero(); + auto time_offset_ms = myClock_msecTick::zero(); // wait until we are joined while (!LMIC.devaddr) { @@ -98,81 +97,67 @@ void process_timesync_req(void *taskparameter) { else { // calculate time diff from collected timestamps k = seq_no % TIME_SYNC_SAMPLES; - auto t_tx = time_point_cast( - time_sync_tx[k]); // timepoint when node TX_completed - auto t_rx = time_point_cast( - time_sync_rx[k]); // timepoint when message was seen on gateway - - time_offset += t_rx - t_tx; // cumulate timepoint diffs + // cumulate timepoint diffs + time_offset_ms += time_point_cast(time_sync_rx[k]) - + time_point_cast(time_sync_tx[k]); if (i < TIME_SYNC_SAMPLES - 1) { // wait until next cycle vTaskDelay(pdMS_TO_TICKS(TIME_SYNC_CYCLE * 1000)); } else { // send flush to open a receive window for last time_sync_answer - // payload.reset(); - // payload.addByte(0x99); - // SendPayload(RCMDPORT, prio_high); - - // Send a payload-less message to open a receive window for last - // time_sync_answer - void LMIC_sendAlive(); + payload.reset(); + payload.addByte(0x99); + SendPayload(RCMDPORT, prio_high); + // Send a alive open a receive window for last time_sync_answer + // void LMIC_sendAlive(); } } } // for - // calculate time offset from collected diffs - time_offset /= TIME_SYNC_SAMPLES; - ESP_LOGD(TAG, "[%0.3f] avg time diff: %0.3f sec", millis() / 1000.0, - myClock_secTick(time_offset).count()); + // average time offset from collected diffs + time_offset_ms /= TIME_SYNC_SAMPLES; - // calculate absolute time offset with millisecond precision using time base + // calculate time offset with millisecond precision using time base // of LMIC os, since we use LMIC's ostime_t txEnd as tx timestamp - time_offset += milliseconds(osticks2ms(os_getTime())); - + time_offset_ms += milliseconds(osticks2ms(os_getTime())); // apply calibration factor for processing time - time_offset += milliseconds(TIME_SYNC_FIXUP); - // convert to whole seconds - time_to_set = static_cast(myClock_secTick(time_offset).count()); - // time_to_set = - // static_cast(duration_cast(time_offset).count()); + time_offset_ms += milliseconds(TIME_SYNC_FIXUP); + // calculate absolute time in UTC epoch + // convert to whole seconds, floor + time_to_set = (time_t)(time_offset_ms.count() / 1000) + 1; // calculate fraction milliseconds - time_to_set_fraction_msec = static_cast(time_offset.count() % 1000); + time_to_set_fraction_msec = (uint16_t)(time_offset_ms.count() % 1000); ESP_LOGD(TAG, "[%0.3f] Calculated UTC epoch time: %d.%03d sec", millis() / 1000.0, time_to_set, time_to_set_fraction_msec); // adjust system time if (timeIsValid(time_to_set)) { - if (abs(time_offset.count()) >= - TIME_SYNC_TRIGGER) { // milliseconds threshold - // wait until top of second - vTaskDelay(pdMS_TO_TICKS(1000 - time_to_set_fraction_msec)); - - time_to_set++; // advance time the one waited second + // wait until top of second + vTaskDelay(pdMS_TO_TICKS(1000 - time_to_set_fraction_msec)); + time_to_set++; // advance time 1 sec wait time #if (!defined GPS_INT && !defined RTC_INT) - // sync esp32 hardware timer based pps to top of second - timerRestart(ppsIRQ); // reset pps timer - CLOCKIRQ(); // fire clock pps interrupt + // sync esp32 hardware timer based pps to top of second + timerRestart(ppsIRQ); // reset pps timer + CLOCKIRQ(); // fire clock pps interrupt + +#elif defined HAS_RTC + // calibrate RTC and RTC_INT pulse on top of second + set_rtctime(time_to_set); #endif - setTime(time_to_set); // set the time on top of second + setTime(time_to_set); // set the time on top of second -#ifdef HAS_RTC - set_rtctime(time_to_set); // calibrate RTC if we have one -#endif + timeSource = _lora; + timesyncer.attach(TIME_SYNC_INTERVAL * 60, + timeSync); // set to regular repeat + ESP_LOGI(TAG, "[%0.3f] Timesync finished, time was adjusted", + millis() / 1000.0); - timeSource = _lora; - timesyncer.attach(TIME_SYNC_INTERVAL * 60, - timeSync); // set to regular repeat - ESP_LOGI(TAG, "[%0.3f] Timesync finished, time adjusted by %.3f sec", - millis() / 1000.0, myClock_secTick(time_offset).count()); - } else - ESP_LOGI(TAG, "[%0.3f] Timesync finished, time is up to date", - millis() / 1000.0); } else ESP_LOGW(TAG, "[%0.3f] Timesync failed, outdated time calculated", millis() / 1000.0); @@ -196,21 +181,6 @@ void store_time_sync_req(uint32_t t_txEnd_ms) { t_txEnd_ms % 1000); } -/* -// called from lorawan.cpp after time_sync_req was sent -void store_time_sync_req_pwm(void) { - - uint8_t k = time_sync_seqNo % TIME_SYNC_SAMPLES; - - time_sync_tx[k] += milliseconds(t_txEnd_ms); - - ESP_LOGD(TAG, "[%0.3f] Timesync request #%d sent at %d.%03d", - millis() / 1000.0, time_sync_seqNo, t_txEnd_ms / 1000, - t_txEnd_ms % 1000); -} -*/ - - // process timeserver timestamp answer, called from lorawan.cpp int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) {