From 8c581ec32f78ccccfc68eb902e5c8a6dc52af008 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 25 Mar 2019 19:06:54 +0100 Subject: [PATCH] sanitized time adjust code --- README.md | 2 +- include/timesync.h | 1 + src/lorawan.cpp | 13 +---- src/main.cpp | 2 +- src/timekeeper.cpp | 2 +- src/timesync.cpp | 123 ++++++++++++++++++++++++--------------------- 6 files changed, 72 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 2abf80e3..217dcfc5 100644 --- a/README.md +++ b/README.md @@ -389,7 +389,7 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. 0x86 get time/date - Device answers with it's local time/date (UTC Unix epoch) on Port 9. + Device answers with it's local time/date (UTC Unix epoch) on Port 2. 0x87 set time/date diff --git a/include/timesync.h b/include/timesync.h index 3d5cb059..9df72171 100644 --- a/include/timesync.h +++ b/include/timesync.h @@ -14,5 +14,6 @@ void send_timesync_req(void); int recv_timesync_ans(uint8_t buf[], uint8_t buf_len); void process_timesync_req(void *taskparameter); void store_time_sync_req(uint32_t t_millisec); +int adjustTime(uint32_t t_sec, uint16_t t_msec); #endif \ No newline at end of file diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 55c6785f..672e4fa8 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -497,19 +497,10 @@ void user_request_network_time_callback(void *pVoidUserUTCTime, // Add the delay between the instant the time was transmitted and // the current time time_t requestDelaySec = osticks2ms(ticksNow - ticksRequestSent) / 1000; - *pUserUTCTime += requestDelaySec; // Update system time with time read from the network - if (timeIsValid(*pUserUTCTime)) { - setTime(*pUserUTCTime); -#ifdef HAS_RTC - set_rtctime(*pUserUTCTime, do_mutex); // calibrate RTC if we have one -#endif - timeSource = _lora; - timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync); // regular repeat - ESP_LOGI(TAG, "Received recent time from LoRa"); - } else - ESP_LOGI(TAG, "Invalid time received from LoRa"); + adjustTime(*pUserUTCTime + requestDelaySec, 0); + } // user_request_network_time_callback #endif // HAS_LORA diff --git a/src/main.cpp b/src/main.cpp index dd6eab68..1d0b82f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,7 +31,7 @@ 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 +clockloop 1 3 generates realtime telegrams for external clock 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 diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index 8ba94b0b..53907a98 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -196,7 +196,7 @@ void clock_init(void) { "clockloop", // name of task 2048, // stack size of task (void *)&userUTCTime, // start time as task parameter - 4, // priority of the task + 3, // priority of the task &ClockTask, // task handle 1); // CPU core diff --git a/src/timesync.cpp b/src/timesync.cpp index 8ecea0cd..2fbe6957 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -53,7 +53,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 } @@ -62,10 +62,8 @@ void send_timesync_req() { // task for sending time sync requests void process_timesync_req(void *taskparameter) { - uint8_t k = 0, i = 0; - uint16_t time_to_set_fraction_msec; + uint8_t k = 0; uint32_t seq_no = 0; - time_t time_to_set; auto time_offset_ms = myClock_msecTick::zero(); // wait until we are joined @@ -87,12 +85,8 @@ void process_timesync_req(void *taskparameter) { // process answer, wait for notification from recv_timesync_ans() if ((xTaskNotifyWait(0x00, ULONG_MAX, &seq_no, pdMS_TO_TICKS(TIME_SYNC_TIMEOUT * 1000)) == pdFALSE) || - (seq_no != time_sync_seqNo)) { - - ESP_LOGW(TAG, "[%0.3f] Timeserver error: handshake timed out", - millis() / 1000.0); - goto finish; - } // no valid sequence received before timeout + (seq_no != time_sync_seqNo)) + goto error; // no valid sequence received before timeout else { // calculate time diff from collected timestamps k = seq_no % TIME_SYNC_SAMPLES; @@ -115,9 +109,6 @@ void process_timesync_req(void *taskparameter) { } } // for - // begin of time critical section: lock I2C bus to ensure accurate timing - I2C_MUTEX_LOCK(); - // average time offset from collected diffs time_offset_ms /= TIME_SYNC_SAMPLES; @@ -127,63 +118,31 @@ void process_timesync_req(void *taskparameter) { time_offset_ms += milliseconds(osticks2ms(os_getTime())) + 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 = (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)) { - - // wait until top of second with 4ms precision - vTaskDelay(pdMS_TO_TICKS(1000 - time_to_set_fraction_msec)); - -#ifdef HAS_RTC - time_to_set++; // advance time 1 sec wait time - // set RTC time and calibrate RTC_INT pulse on top of second - set_rtctime(time_to_set, no_mutex); -#endif - -#if (!defined GPS_INT && !defined RTC_INT) - // sync pps timer to top of second - timerRestart(ppsIRQ); // reset pps timer - CLOCKIRQ(); // fire clock pps, advances time 1 sec -#endif - - setTime(time_to_set); // set the time on top of second - - // end of time critical section: release I2C bus - I2C_MUTEX_UNLOCK(); - - timeSource = _lora; - timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync); // regular repeat - ESP_LOGI(TAG, "[%0.3f] Timesync finished, time was adjusted", - millis() / 1000.0); - } else - ESP_LOGW(TAG, "[%0.3f] Timesync failed, outdated time calculated", - millis() / 1000.0); + // calculate absolute time in UTC epoch: convert to whole seconds, round to + // floor, and calculate fraction milliseconds + adjustTime(time_offset_ms.count() / 1000 + 1, time_offset_ms.count() % 1000); finish: - lora_time_sync_pending = false; timeSyncReqTask = NULL; vTaskDelete(NULL); // end task + +error: + ESP_LOGW(TAG, "[%0.3f] Timeserver error: handshake timed out", + millis() / 1000.0); + goto finish; } // called from lorawan.cpp after time_sync_req was sent -void store_time_sync_req(uint32_t t_txEnd_ms) { +void store_time_sync_req(uint32_t timestamp) { uint8_t k = time_sync_seqNo % TIME_SYNC_SAMPLES; - time_sync_tx[k] += milliseconds(t_txEnd_ms); + time_sync_tx[k] += milliseconds(timestamp); 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); + millis() / 1000.0, time_sync_seqNo, timestamp / 1000, + timestamp % 1000); } // process timeserver timestamp answer, called from lorawan.cpp @@ -240,4 +199,54 @@ int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) { } } +// adjust system time, calibrate RTC and RTC_INT pps +int adjustTime(uint32_t t_sec, uint16_t t_msec) { + + time_t time_to_set = (time_t)t_sec; + + // begin of time critical section: lock I2C bus to ensure accurate timing + if (!I2C_MUTEX_LOCK()) + goto error; // failure + + ESP_LOGD(TAG, "[%0.3f] Calculated UTC epoch time: %d.%03d sec", + millis() / 1000.0, time_to_set, t_msec); + + if (timeIsValid(time_to_set)) { + + // wait until top of second with millisecond precision + vTaskDelay(pdMS_TO_TICKS(1000 - t_msec)); + +#ifdef HAS_RTC + time_to_set++; // advance time 1 sec wait time + // set RTC time and calibrate RTC_INT pulse on top of second + set_rtctime(time_to_set, no_mutex); +#endif + +#if (!defined GPS_INT && !defined RTC_INT) + // sync pps timer to top of second + timerRestart(ppsIRQ); // reset pps timer + CLOCKIRQ(); // fire clock pps, advances time 1 sec +#endif + + setTime(time_to_set); // set the time on top of second + + // end of time critical section: release I2C bus + I2C_MUTEX_UNLOCK(); + + timeSource = _lora; + timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync); // regular repeat + ESP_LOGI(TAG, "[%0.3f] Timesync finished, time was adjusted", + millis() / 1000.0); + } else + ESP_LOGW(TAG, "[%0.3f] Timesync failed, outdated time calculated", + millis() / 1000.0); + + return 0; // success + +error: + ESP_LOGW(TAG, "[%0.3f] Timesync failed, handshake timed out", + millis() / 1000.0); + return 1; +} + #endif \ No newline at end of file