diff --git a/include/if482.h b/include/if482.h index a787030d..235f320e 100644 --- a/include/if482.h +++ b/include/if482.h @@ -2,13 +2,9 @@ #define _IF482_H #include "globals.h" -#include "timekeeper.h" #define IF482_FRAME_SIZE (17) -extern HardwareSerial IF482; - -void IF482_Pulse(time_t t); String IRAM_ATTR IF482_Frame(time_t tt); #endif \ No newline at end of file diff --git a/include/timekeeper.h b/include/timekeeper.h index fc12e4a9..0d051a61 100644 --- a/include/timekeeper.h +++ b/include/timekeeper.h @@ -6,9 +6,10 @@ #include "TimeLib.h" #include "irqhandler.h" -#if(HAS_GPS) +#ifdef HAS_GPS #include "gpsread.h" #endif + #ifdef HAS_IF482 #include "if482.h" #elif defined HAS_DCF77 diff --git a/src/if482.cpp b/src/if482.cpp index 92151b5d..7511a821 100644 --- a/src/if482.cpp +++ b/src/if482.cpp @@ -84,18 +84,6 @@ not evaluated by model BU-190, use "F" instead for this model // Local logging tag static const char TAG[] = __FILE__; -HardwareSerial IF482(2); // use UART #2 (note: #1 may be in use for serial GPS) - -// triggered by timepulse to send IF482 signal -void IF482_Pulse(time_t t) { - - static const TickType_t txDelay = - pdMS_TO_TICKS(1000) - tx_Ticks(IF482_FRAME_SIZE, HAS_IF482); - - vTaskDelay(txDelay); // wait until moment to fire - IF482.print(IF482_Frame(t + 1)); // note: if482 telegram for *next* second -} - String IRAM_ATTR IF482_Frame(time_t printTime) { time_t t = myTZ.toLocal(printTime); diff --git a/src/irqhandler.cpp b/src/irqhandler.cpp index bbfdafca..1fa349ab 100644 --- a/src/irqhandler.cpp +++ b/src/irqhandler.cpp @@ -3,6 +3,8 @@ // Local logging tag static const char TAG[] = __FILE__; +static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; + // irq handler task, handles all our application level interrupts void irqHandler(void *pvParameters) { @@ -54,12 +56,13 @@ void irqHandler(void *pvParameters) { #ifdef HAS_DISPLAY void IRAM_ATTR DisplayIRQ() { + portENTER_CRITICAL_ISR(&mux); BaseType_t xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE; xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, &xHigherPriorityTaskWoken); - + portEXIT_CRITICAL_ISR(&mux); if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR(); } @@ -67,11 +70,13 @@ void IRAM_ATTR DisplayIRQ() { #ifdef HAS_BUTTON void IRAM_ATTR ButtonIRQ() { + portENTER_CRITICAL_ISR(&mux); BaseType_t xHigherPriorityTaskWoken; 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 0f87bbf5..b50e56c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,7 @@ looptask 1 1 arduino core -> runs the LMIC LoRa stack irqhandler 1 1 executes tasks triggered by timer irq gpsloop 1 2 reads data from GPS via serial or i2c bmeloop 1 1 reads data from BME sensor via i2c -timesync_req 1 4 temporary task for processing time sync requests +timesync_req 1 2 temporary task for processing time sync requests IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator Low priority numbers denote low priority tasks. diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index 1f2131a4..2573ccba 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -14,8 +14,14 @@ static const char TAG[] = __FILE__; // symbol to display current time source const char timeSetSymbols[] = {'G', 'R', 'L', '?'}; +#ifdef HAS_IF482 +HardwareSerial IF482(2); // use UART #2 (#1 may be in use for serial GPS) +#endif + Ticker timesyncer; +static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; + void timeSync() { xTaskNotify(irqHandlerTask, TIMESYNC_IRQ, eSetBits); } time_t timeProvider(void) { @@ -115,18 +121,22 @@ void timepulse_start(void) { // interrupt service routine triggered by either pps or esp32 hardware timer void IRAM_ATTR CLOCKIRQ(void) { + portENTER_CRITICAL_ISR(&mux); BaseType_t xHigherPriorityTaskWoken; - SyncToPPS(); // calibrates UTC systime, see microTime.h xHigherPriorityTaskWoken = pdFALSE; + SyncToPPS(); // calibrates UTC systime, see microTime.h + if (ClockTask != NULL) xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits, &xHigherPriorityTaskWoken); -#if defined GPS_INT || defined RTC_INT - TimePulseTick = !TimePulseTick; // flip ticker +#if (defined GPS_INT || defined RTC_INT) + TimePulseTick = !TimePulseTick; // flip pulse ticker #endif + portEXIT_CRITICAL_ISR(&mux); + // yield only if we should if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR(); @@ -163,8 +173,8 @@ TickType_t tx_Ticks(uint32_t framesize, unsigned long baud, uint32_t config, uint32_t databits = ((config & 0x0c) >> 2) + 5; uint32_t stopbits = ((config & 0x20) >> 5) + 1; - uint32_t txTime = (databits + stopbits + 2) * framesize * 1000.0 / baud; - // +1 ms margin for the startbit +1 ms for pending processing time + uint32_t txTime = (databits + stopbits + 1) * framesize * 1000.0 / baud; + // +1 for the startbit return round(txTime); } @@ -207,10 +217,13 @@ void clock_loop(void *taskparameter) { // ClockTask uint32_t printtime; time_t t = *((time_t *)taskparameter); // UTC time seconds - // preload first DCF frame before start #ifdef HAS_DCF77 - uint8_t *DCFpulse; // pointer on array with DCF pulse bits - DCFpulse = DCF77_Frame(nextmin(t)); + uint8_t *DCFpulse; // pointer on array with DCF pulse bits + DCFpulse = DCF77_Frame(nextmin(t)); // load first DCF frame before start +#elif defined HAS_IF482 + static TickType_t txDelay = + pdMS_TO_TICKS(1000 - 2) - tx_Ticks(IF482_FRAME_SIZE, HAS_IF482); + // 2ms margin for processing time #endif // output the next second's pulse after timepulse arrived @@ -226,7 +239,8 @@ void clock_loop(void *taskparameter) { // ClockTask #if defined HAS_IF482 - IF482_Pulse(t); + vTaskDelay(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 e88d9a21..16385484 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -54,7 +54,7 @@ void send_timesync_req() { "timesync_req", // name of task 2048, // stack size of task (void *)1, // task parameter - 4, // priority of the task + 2, // priority of the task &timeSyncReqTask, // task handle 1); // CPU core } @@ -129,10 +129,14 @@ void process_timesync_req(void *taskparameter) { // calculate absolute 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())); + // apply calibration factor for processing time time_offset += milliseconds(TIME_SYNC_FIXUP); - // convert to seconds + // convert to whole seconds time_to_set = static_cast(myClock_secTick(time_offset).count()); + // time_to_set = + // static_cast(duration_cast(time_offset).count()); + // calculate fraction milliseconds time_to_set_fraction_msec = static_cast(time_offset.count() % 1000); @@ -145,15 +149,14 @@ void process_timesync_req(void *taskparameter) { TIME_SYNC_TRIGGER) { // milliseconds threshold // wait until top of second - uint16_t const wait_ms = 1000 - time_to_set_fraction_msec; - ESP_LOGD(TAG, "[%0.3f] waiting %d ms", millis() / 1000.0, wait_ms); - vTaskDelay(pdMS_TO_TICKS(wait_ms)); + vTaskDelay(pdMS_TO_TICKS(1000 - time_to_set_fraction_msec)); -#if !defined(GPS_INT) && !defined(RTC_INT) + time_to_set++; // advance time the one waited second + +#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 - time_to_set++; // advance time 1 second #endif setTime(time_to_set); // set the time on top of second @@ -193,6 +196,21 @@ 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) { @@ -229,7 +247,7 @@ int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) { // construct the timepoint when message was seen on gateway time_sync_rx[k] += seconds(timestamp_sec) + milliseconds(timestamp_msec); - // guess if the timepoint is recent by comparing with code compile date + // guess timepoint is recent if newer than code compile date if (timeIsValid(myClock::to_time_t(time_sync_rx[k]))) { ESP_LOGD(TAG, "[%0.3f] Timesync request #%d rcvd at %d.%03d", millis() / 1000.0, seq_no, timestamp_sec, timestamp_msec);