From c489123e0622eed96e3042f102b3184b4a5022a8 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Wed, 27 Feb 2019 22:40:58 +0100 Subject: [PATCH] timekeeper fixes (experimental) --- src/dcf77.cpp | 2 ++ src/gpsread.cpp | 12 ++++---- src/main.cpp | 4 +-- src/timekeeper.cpp | 76 +++++++++++++++++++++------------------------- 4 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/dcf77.cpp b/src/dcf77.cpp index 1c27235e..7a1e5ab3 100644 --- a/src/dcf77.cpp +++ b/src/dcf77.cpp @@ -22,6 +22,8 @@ void DCF77_Pulse(time_t t, uint8_t const *DCFpulse) { TickType_t startTime = xTaskGetTickCount(); uint8_t sec = second(t); + ESP_LOGD (TAG, "DCF second %d", sec); + // induce 10 pulses for (uint8_t pulse = 0; pulse <= 9; pulse++) { diff --git a/src/gpsread.cpp b/src/gpsread.cpp index 9c34049d..c0c67292 100644 --- a/src/gpsread.cpp +++ b/src/gpsread.cpp @@ -92,14 +92,14 @@ time_t get_gpstime(void) { time_t t = 0; - if ((gps.time.age() < gpsDelay_ms) && (gps.time.isValid())) { + if ((gps.time.age() < gpsDelay_ms) && (gps.time.isValid()) && (gps.date.isValid())) { - ESP_LOGD(TAG, "GPS time age: %dms, is valid: %s", gps.time.age(), - gps.time.isValid() ? "yes" : "no"); + ESP_LOGD(TAG, "GPS time age: %dms, second: %d, is valid: %s", gps.time.age(), gps.time.second(), + gps.time.isValid() ? "yes" : "no"); - t = tmConvert(gps.date.year(), gps.date.month(), gps.date.day(), - gps.time.hour(), gps.time.minute(), gps.time.second()); - } + t = tmConvert(gps.date.year(), gps.date.month(), gps.date.day(), + gps.time.hour(), gps.time.minute(), gps.time.second()); + } return TimeIsValid(t); } // get_gpstime() diff --git a/src/main.cpp b/src/main.cpp index eb04d063..ea1ea917 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,11 +27,11 @@ Uused tasks and timers: Task Core Prio Purpose ==================================================================================== -clockloop 0 4 generates realtime telegrams for external clock ledloop 0 3 blinks LEDs spiloop 0 2 reads/writes data on spi interface IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer +clockloop 1 4 generates realtime telegrams for external clock looptask 1 1 arduino core -> runs the LMIC LoRa stack irqhandler 1 1 executes tasks triggered by hw irq, see table below gpsloop 1 2 reads data from GPS via serial or i2c @@ -362,7 +362,6 @@ void setup() { ESP_LOGI(TAG, "Starting Timekeeper..."); assert(timepulse_init()); // setup timepulse timepulse_start(); - timeSync(); // start wifi in monitor mode and start channel rotation timer ESP_LOGI(TAG, "Starting Wifi..."); @@ -417,6 +416,7 @@ void setup() { #if defined HAS_IF482 || defined HAS_DCF77 ESP_LOGI(TAG, "Starting Clock Controller..."); + timeSync(); clock_init(); #endif diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index c1a54de1..33efe357 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -8,7 +8,6 @@ const char timeSetSymbols[] = {'G', 'R', 'L', '?'}; getExternalTime TimeSourcePtr; // pointer to time source function - // syncs systime from external time source and sets/reads RTC, called by // cyclic.cpp void timeSync(void) { @@ -16,47 +15,36 @@ void timeSync(void) { time_t t = 0; #ifdef HAS_GPS - // do we have a valid GPS time? - if (get_gpstime()) { // then let's sync GPS time on top of second - - xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)); // wait for pps - vTaskDelay(gpsDelay_ticks); - t = get_gpstime(); // fetch time from recent NEMA record - if (t) { - t++; // gps time concerns past second, so we add one - xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)); // wait for pps - setTime(t); + xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1100)); // wait for pps + t = get_gpstime(); // fetch recent time from last NEMA record + if (t) { + / t++; // last NMEA record concerns past second, so we add one + ESP_LOGD(TAG, "millis: %d, second: %d", millis(), second(t)); + setTime(t); #ifdef HAS_RTC - set_rtctime(t); // calibrate RTC + set_rtctime(t); // calibrate RTC #endif - timeSource = _gps; - goto exit; - } - } + timeSource = _gps; + return; + } #endif // no GPS -> fallback to RTC time while trying lora sync #ifdef HAS_RTC - t = get_rtctime(); - if (t) { - setTime(t); - timeSource = _rtc; - } else - ESP_LOGW(TAG, "no confident RTC time"); + t = get_rtctime(); + if (t) { + setTime(t); + timeSource = _rtc; + } #endif // try lora sync if we have #if defined HAS_LORA && defined TIME_SYNC_LORA - LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime); + LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime); #endif -exit: - - if (t) - ESP_LOGD(TAG, "Time was set by %c to %02d:%02d:%02d", - timeSetSymbols[timeSource], hour(t), minute(t), second(t)); - else - timeSource = _unsynced; + if (!t) + timeSource = _unsynced; } // timeSync() @@ -66,7 +54,7 @@ uint8_t timepulse_init() { // use time pulse from GPS as time base with fixed 1Hz frequency #ifdef GPS_INT - // setup external interupt pin for GPS INT output + // setup external interupt pin for rising edge GPS INT pinMode(GPS_INT, INPUT_PULLDOWN); // setup external rtc 1Hz clock as pulse per second clock ESP_LOGI(TAG, "Timepulse: external (GPS)"); @@ -75,7 +63,7 @@ uint8_t timepulse_init() { // use pulse from on board RTC chip as time base with fixed frequency #elif defined RTC_INT - // setup external interupt pin for active low RTC INT output + // setup external interupt pin for falling edge RTC INT pinMode(RTC_INT, INPUT_PULLUP); // setup external rtc 1Hz clock as pulse per second clock @@ -114,12 +102,15 @@ void timepulse_start(void) { // interrupt service routine triggered by either pps or esp32 hardware timer void IRAM_ATTR CLOCKIRQ(void) { + if (ClockTask != NULL) - xTaskNotifyFromISR(ClockTask, xTaskGetTickCountFromISR(), eSetBits, NULL); + xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits, NULL); + #if defined GPS_INT || defined RTC_INT - xSemaphoreGiveFromISR(TimePulse, NULL); + xSemaphoreGiveFromISR(TimePulse, &xHigherPriorityTaskWoken); TimePulseTick = !TimePulseTick; // flip ticker #endif + portYIELD_FROM_ISR(); } @@ -181,7 +172,7 @@ void clock_init(void) { (void *)1, // task parameter 4, // priority of the task &ClockTask, // task handle - 0); // CPU core + 1); // CPU core assert(ClockTask); // has clock task started? } // clock_init @@ -191,10 +182,11 @@ void clock_loop(void *pvParameters) { // ClockTask configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check TickType_t wakeTime; + uint32_t ppstime; time_t t; -#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 +#define t1(t) (t + DCF77_FRAME_SIZE + 1) // future minute for next DCF77 frame +#define t2(t) (t + 1) // future second after sync with 1pps trigger // preload first DCF frame before start #ifdef HAS_DCF77 @@ -204,14 +196,14 @@ void clock_loop(void *pvParameters) { // ClockTask // output time telegram for second following sec beginning with timepulse for (;;) { - xTaskNotifyWait(0x00, ULONG_MAX, &wakeTime, + xTaskNotifyWait(0x00, ULONG_MAX, &ppstime, portMAX_DELAY); // wait for timepulse // no confident time -> suppress clock output if (timeStatus() == timeNotSet) continue; - t = now(); // payload to send to clock + t = time_t(ppstime); #if defined HAS_IF482 @@ -222,8 +214,10 @@ void clock_loop(void *pvParameters) { // ClockTask if (second(t) == DCF77_FRAME_SIZE - 1) // is it time to load new frame? DCFpulse = DCF77_Frame(t1(t)); // generate next frame - if (DCFpulse[DCF77_FRAME_SIZE] == - minute(t1(t))) // have recent frame? (pulses could be missed!) + if (DCFpulse[DCF77_FRAME_SIZE] != + minute(t1(t))) // have recent frame? (timepulses could be missed!) + continue; + else DCF77_Pulse(t2(t), DCFpulse); // then output next second of this frame #endif