sanitized time adjust code

This commit is contained in:
Verkehrsrot 2019-03-25 19:06:54 +01:00
parent 95b6947c73
commit 8c581ec32f
6 changed files with 72 additions and 71 deletions

View File

@ -389,7 +389,7 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts.
0x86 get time/date 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 0x87 set time/date

View File

@ -14,5 +14,6 @@ void send_timesync_req(void);
int recv_timesync_ans(uint8_t buf[], uint8_t buf_len); int recv_timesync_ans(uint8_t buf[], uint8_t buf_len);
void process_timesync_req(void *taskparameter); void process_timesync_req(void *taskparameter);
void store_time_sync_req(uint32_t t_millisec); void store_time_sync_req(uint32_t t_millisec);
int adjustTime(uint32_t t_sec, uint16_t t_msec);
#endif #endif

View File

@ -497,19 +497,10 @@ void user_request_network_time_callback(void *pVoidUserUTCTime,
// Add the delay between the instant the time was transmitted and // Add the delay between the instant the time was transmitted and
// the current time // the current time
time_t requestDelaySec = osticks2ms(ticksNow - ticksRequestSent) / 1000; time_t requestDelaySec = osticks2ms(ticksNow - ticksRequestSent) / 1000;
*pUserUTCTime += requestDelaySec;
// Update system time with time read from the network // Update system time with time read from the network
if (timeIsValid(*pUserUTCTime)) { adjustTime(*pUserUTCTime + requestDelaySec, 0);
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");
} // user_request_network_time_callback } // user_request_network_time_callback
#endif // HAS_LORA #endif // HAS_LORA

View File

@ -31,7 +31,7 @@ ledloop 0 3 blinks LEDs
spiloop 0 2 reads/writes data on spi interface spiloop 0 2 reads/writes data on spi interface
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer 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 looptask 1 1 arduino core -> runs the LMIC LoRa stack
irqhandler 1 1 executes tasks triggered by timer irq irqhandler 1 1 executes tasks triggered by timer irq
gpsloop 1 2 reads data from GPS via serial or i2c gpsloop 1 2 reads data from GPS via serial or i2c

View File

@ -196,7 +196,7 @@ void clock_init(void) {
"clockloop", // name of task "clockloop", // name of task
2048, // stack size of task 2048, // stack size of task
(void *)&userUTCTime, // start time as task parameter (void *)&userUTCTime, // start time as task parameter
4, // priority of the task 3, // priority of the task
&ClockTask, // task handle &ClockTask, // task handle
1); // CPU core 1); // CPU core

View File

@ -53,7 +53,7 @@ void send_timesync_req() {
"timesync_req", // name of task "timesync_req", // name of task
2048, // stack size of task 2048, // stack size of task
(void *)1, // task parameter (void *)1, // task parameter
4, // priority of the task 2, // priority of the task
&timeSyncReqTask, // task handle &timeSyncReqTask, // task handle
1); // CPU core 1); // CPU core
} }
@ -62,10 +62,8 @@ void send_timesync_req() {
// task for sending time sync requests // task for sending time sync requests
void process_timesync_req(void *taskparameter) { void process_timesync_req(void *taskparameter) {
uint8_t k = 0, i = 0; uint8_t k = 0;
uint16_t time_to_set_fraction_msec;
uint32_t seq_no = 0; uint32_t seq_no = 0;
time_t time_to_set;
auto time_offset_ms = myClock_msecTick::zero(); auto time_offset_ms = myClock_msecTick::zero();
// wait until we are joined // wait until we are joined
@ -87,12 +85,8 @@ void process_timesync_req(void *taskparameter) {
// process answer, wait for notification from recv_timesync_ans() // process answer, wait for notification from recv_timesync_ans()
if ((xTaskNotifyWait(0x00, ULONG_MAX, &seq_no, if ((xTaskNotifyWait(0x00, ULONG_MAX, &seq_no,
pdMS_TO_TICKS(TIME_SYNC_TIMEOUT * 1000)) == pdFALSE) || pdMS_TO_TICKS(TIME_SYNC_TIMEOUT * 1000)) == pdFALSE) ||
(seq_no != time_sync_seqNo)) { (seq_no != time_sync_seqNo))
goto error; // no valid sequence received before timeout
ESP_LOGW(TAG, "[%0.3f] Timeserver error: handshake timed out",
millis() / 1000.0);
goto finish;
} // no valid sequence received before timeout
else { // calculate time diff from collected timestamps else { // calculate time diff from collected timestamps
k = seq_no % TIME_SYNC_SAMPLES; k = seq_no % TIME_SYNC_SAMPLES;
@ -115,9 +109,6 @@ void process_timesync_req(void *taskparameter) {
} }
} // for } // for
// begin of time critical section: lock I2C bus to ensure accurate timing
I2C_MUTEX_LOCK();
// average time offset from collected diffs // average time offset from collected diffs
time_offset_ms /= TIME_SYNC_SAMPLES; time_offset_ms /= TIME_SYNC_SAMPLES;
@ -127,63 +118,31 @@ void process_timesync_req(void *taskparameter) {
time_offset_ms += time_offset_ms +=
milliseconds(osticks2ms(os_getTime())) + milliseconds(TIME_SYNC_FIXUP); milliseconds(osticks2ms(os_getTime())) + milliseconds(TIME_SYNC_FIXUP);
// calculate absolute time in UTC epoch // calculate absolute time in UTC epoch: convert to whole seconds, round to
// convert to whole seconds, floor // floor, and calculate fraction milliseconds
time_to_set = (time_t)(time_offset_ms.count() / 1000) + 1; adjustTime(time_offset_ms.count() / 1000 + 1, time_offset_ms.count() % 1000);
// 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);
finish: finish:
lora_time_sync_pending = false; lora_time_sync_pending = false;
timeSyncReqTask = NULL; timeSyncReqTask = NULL;
vTaskDelete(NULL); // end task 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 // 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; 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", ESP_LOGD(TAG, "[%0.3f] Timesync request #%d sent at %d.%03d",
millis() / 1000.0, time_sync_seqNo, t_txEnd_ms / 1000, millis() / 1000.0, time_sync_seqNo, timestamp / 1000,
t_txEnd_ms % 1000); timestamp % 1000);
} }
// process timeserver timestamp answer, called from lorawan.cpp // 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 #endif