From 4f8d92ea7e77032b8c456247bf577eab657a88be Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 7 Apr 2019 16:13:04 +0200 Subject: [PATCH] timesync tasking restructured --- include/timesync.h | 3 +- src/lorawan.cpp | 10 +-- src/main.cpp | 15 ++-- src/timesync.cpp | 188 +++++++++++++++++++++++---------------------- 4 files changed, 113 insertions(+), 103 deletions(-) diff --git a/include/timesync.h b/include/timesync.h index bcdc6871..81ef723b 100644 --- a/include/timesync.h +++ b/include/timesync.h @@ -10,8 +10,7 @@ #define TIME_SYNC_FRAME_LENGTH 0x05 // timeserver answer frame length [bytes] #define TIME_SYNC_FIXUP 6 // calibration to fixup processing time [milliseconds] -extern TaskHandle_t timeSyncReqTask; - +void timesync_init(void); void send_timesync_req(void); int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len); void process_timesync_req(void *taskparameter); diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 14d61bdd..e9307640 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -224,9 +224,8 @@ void onEvent(ev_t ev) { ESP_LOGI(TAG, "ADR=%d, SF=%d, TXPOWER=%d", cfg.adrmode, cfg.lorasf, cfg.txpower); #if (TIME_SYNC_LORASERVER) - // kick off timesync task if pending - if (timeSyncReqTask) - xTaskNotifyGive(timeSyncReqTask); + // kickoff first time sync + send_timesync_req(); #endif break; @@ -316,8 +315,9 @@ void onEvent(ev_t ev) { if (!(LMIC.opmode & OP_JOINING)) #if (TIME_SYNC_LORASERVER) // if last packet sent was a timesync request, store TX time - if ((LMIC.pendTxPort == TIMEPORT) && timeSyncReqTask) - strcpy_P(buff, PSTR("SYNCING TIME")); + // if ((LMIC.pendTxPort == TIMEPORT) && timeSyncPending) + if (LMIC.pendTxPort == TIMEPORT) + strcpy_P(buff, PSTR("TX TIMESYNC")); else #endif strcpy_P(buff, PSTR("TX START")); diff --git a/src/main.cpp b/src/main.cpp index 7871328c..3971ee57 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 -timesync_req 1 4 temporary task for processing time sync requests +timesync_req 1 4 processes realtime time sync requests clockloop 1 3 generates realtime telegrams for external clock irqhandler 1 2 display, timesync, etc. tasks triggered by timer gpsloop 1 2 reads data from GPS via serial or i2c @@ -411,16 +411,23 @@ void setup() { #endif // HAS_BUTTON #if (TIME_SYNC_INTERVAL) -#if (!defined(TIME_SYNC_LORAWAN) && !defined(TIME_SYNC_LORASERVER) && \ - !defined HAS_GPS && !defined HAS_RTC) +#if (!(TIME_SYNC_LORAWAN) && !(TIME_SYNC_LORASERVER) && !defined HAS_GPS && \ + !defined HAS_RTC) #warning you did not specify a time source, time will not be synched #endif + // start pps timepulse ESP_LOGI(TAG, "Starting Timekeeper..."); assert(timepulse_init()); // setup timepulse timepulse_start(); timeSync(); // init systime timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync); + +#if (TIME_SYNC_LORASERVER) + // create time sync task + timesync_init(); +#endif + #endif #if defined HAS_IF482 || defined HAS_DCF77 @@ -442,6 +449,4 @@ void loop() { delay(2); // yield to CPU #endif } - - vTaskDelete(NULL); // shoud never be reached } diff --git a/src/timesync.cpp b/src/timesync.cpp index da8d6084..6440f34c 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -13,145 +13,141 @@ algorithm in applications without granted license by the patent holder. #include "timesync.h" -using namespace std::chrono; - // Local logging tag static const char TAG[] = __FILE__; -TaskHandle_t timeSyncReqTask = NULL; - -static uint8_t time_sync_seqNo = TIMEANSWERPORT_MIN; +using namespace std::chrono; typedef std::chrono::system_clock myClock; typedef myClock::time_point myClock_timepoint; typedef std::chrono::duration> myClock_msecTick; -myClock_timepoint time_sync_tx[TIME_SYNC_SAMPLES]; -myClock_timepoint time_sync_rx[TIME_SYNC_SAMPLES]; +TaskHandle_t timeSyncReqTask = NULL; + +static uint8_t time_sync_seqNo = TIMEANSWERPORT_MIN; +static bool timeSyncPending = false; +static myClock_timepoint time_sync_tx[TIME_SYNC_SAMPLES]; +static myClock_timepoint time_sync_rx[TIME_SYNC_SAMPLES]; // send time request message void send_timesync_req() { - // if a timesync handshake is pending then exit - if (timeSyncReqTask) { - ESP_LOGD(TAG, "Timeserver sync request already pending"); + // if a timesync handshake is pending or we are not joined then exit + if (timeSyncPending || !LMIC.devaddr) return; - } else { + // else unblock timesync task + else { + timeSyncPending = true; ESP_LOGI(TAG, "[%0.3f] Timeserver sync request started", millis() / 1000.0); - - // clear timestamp array - for (uint8_t i = 0; i < TIME_SYNC_SAMPLES; i++) - time_sync_tx[i] = time_sync_rx[i] = myClock_timepoint(); - - // kick off temporary task for timeserver handshake processing - if (!timeSyncReqTask) - xTaskCreatePinnedToCore(process_timesync_req, // task function - "timesync_req", // name of task - 4096, // stack size of task - (void *)1, // task parameter - 4, // priority of the task - &timeSyncReqTask, // task handle - 1); // CPU core + xTaskNotifyGive(timeSyncReqTask); } } // task for sending time sync requests void process_timesync_req(void *taskparameter) { - uint8_t k = 0; + uint8_t k; uint16_t time_to_set_fraction_msec; - uint32_t seq_no = 0, time_to_set; + uint32_t seq_no, time_to_set; auto time_offset_ms = myClock_msecTick::zero(); - // wait until we are joined - if (!LMIC.devaddr) + while (1) { + + // clear timestamp array before next sync run + time_offset_ms = myClock_msecTick::zero(); + for (uint8_t i = 0; i < TIME_SYNC_SAMPLES; i++) + time_sync_tx[i] = time_sync_rx[i] = myClock_timepoint(); + + // wait for kickoff ulTaskNotifyTake(pdFALSE, portMAX_DELAY); - // enqueue timestamp samples in lora sendqueue - for (uint8_t i = 0; i < TIME_SYNC_SAMPLES; i++) { - // send sync request to server - payload.reset(); - payload.addByte(time_sync_seqNo); - SendPayload(TIMEPORT, prio_high); + // collect timestamp samples + for (uint8_t i = 0; i < TIME_SYNC_SAMPLES; i++) { + // send sync request to server + payload.reset(); + payload.addByte(time_sync_seqNo); + SendPayload(TIMEPORT, prio_high); - // 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)) - goto error; // no valid sequence received before timeout + // 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)) + goto error; // no valid sequence received before timeout - else { // calculate time diff from collected timestamps - k = seq_no % TIME_SYNC_SAMPLES; + else { // calculate time diff from collected timestamps + k = seq_no % TIME_SYNC_SAMPLES; - // cumulate timepoint diffs - time_offset_ms += time_point_cast(time_sync_rx[k]) - - time_point_cast(time_sync_tx[k]); + // cumulate timepoint diffs + time_offset_ms += time_point_cast(time_sync_rx[k]) - + time_point_cast(time_sync_tx[k]); - // wrap around seqNo keeping it in time port range - time_sync_seqNo = (time_sync_seqNo < TIMEANSWERPORT_MAX) - ? time_sync_seqNo + 1 - : TIMEANSWERPORT_MIN; + // wrap around seqNo keeping it in time port range + time_sync_seqNo = (time_sync_seqNo < TIMEANSWERPORT_MAX) + ? time_sync_seqNo + 1 + : TIMEANSWERPORT_MIN; - if (i < TIME_SYNC_SAMPLES - 1) { - // wait until next cycle - vTaskDelay(pdMS_TO_TICKS(TIME_SYNC_CYCLE * 1000)); - } else { // before sending last time sample... - // ...send flush to open a receive window for last time_sync_answer - payload.reset(); - payload.addByte(0x99); - SendPayload(RCMDPORT, prio_high); - // ...send a alive open a receive window for last time_sync_answer - //LMIC_sendAlive(); + if (i < TIME_SYNC_SAMPLES - 1) { + // wait until next cycle + vTaskDelay(pdMS_TO_TICKS(TIME_SYNC_CYCLE * 1000)); + } else { // before sending last time sample... + // ...send flush to open a receive window for last time_sync_answer + payload.reset(); + payload.addByte(0x99); + SendPayload(RCMDPORT, prio_high); + // ...send a alive open a receive window for last time_sync_answer + // LMIC_sendAlive(); + } } - } - } // for + } // end for() collect timestamp samples - // begin of time critical section: lock I2C bus to ensure accurate timing - if (!mask_user_IRQ()) - goto error; // failure + // begin of time critical section: lock I2C bus to ensure accurate timing + if (!mask_user_IRQ()) + goto error; // failure - // average time offset from collected diffs - time_offset_ms /= TIME_SYNC_SAMPLES; + // average time offset from collected diffs + time_offset_ms /= TIME_SYNC_SAMPLES; - // calculate time offset with millisecond precision using LMIC's time base, - // since we use LMIC's ostime_t txEnd as tx timestamp. - // Finally apply calibration const for processing time. - time_offset_ms += - milliseconds(osticks2ms(os_getTime())) + milliseconds(TIME_SYNC_FIXUP); + // calculate time offset with millisecond precision using LMIC's time base, + // since we use LMIC's ostime_t txEnd as tx timestamp. + // Finally apply calibration const for processing time. + time_offset_ms += + milliseconds(osticks2ms(os_getTime())) + milliseconds(TIME_SYNC_FIXUP); - // calculate absolute time in UTC epoch: convert to whole seconds, round to - // ceil, and calculate fraction milliseconds - time_to_set = (uint32_t)(time_offset_ms.count() / 1000) + 1; - // calculate fraction milliseconds - time_to_set_fraction_msec = (uint16_t)(time_offset_ms.count() % 1000); + // calculate absolute time in UTC epoch: convert to whole seconds, round to + // ceil, and calculate fraction milliseconds + time_to_set = (uint32_t)(time_offset_ms.count() / 1000) + 1; + // calculate fraction milliseconds + time_to_set_fraction_msec = (uint16_t)(time_offset_ms.count() % 1000); - setMyTime(time_to_set, time_to_set_fraction_msec); + setMyTime(time_to_set, time_to_set_fraction_msec); - // end of time critical section: release I2C bus - unmask_user_IRQ(); + // end of time critical section: release I2C bus + unmask_user_IRQ(); - goto finish; // end task + goto finish; -error: - ESP_LOGW(TAG, "[%0.3f] Timeserver error: handshake timed out", - millis() / 1000.0); + error: + ESP_LOGW(TAG, "[%0.3f] Timeserver error: handshake timed out", + millis() / 1000.0); -finish: - vTaskDelete(NULL); // end task + finish: + timeSyncPending = false; + + } // infinite while(1) } // called from lorawan.cpp after time_sync_req was sent void store_time_sync_req(uint32_t timestamp) { - if (timeSyncReqTask) { + if (timeSyncPending) { uint8_t k = time_sync_seqNo % TIME_SYNC_SAMPLES; time_sync_tx[k] += milliseconds(timestamp); ESP_LOGD(TAG, "[%0.3f] Timesync request #%d sent at %d.%03d", - millis() / 1000.0, k, timestamp / 1000, - timestamp % 1000); + millis() / 1000.0, k, timestamp / 1000, timestamp % 1000); } } @@ -159,7 +155,7 @@ void store_time_sync_req(uint32_t timestamp) { int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len) { // if no timesync handshake is pending then exit - if (!timeSyncReqTask) + if (!timeSyncPending) return 0; // failure // if no time is available or spurious buffer then exit @@ -197,8 +193,7 @@ int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len) { millis() / 1000.0, k, timestamp_sec, timestamp_msec); // inform processing task - if (timeSyncReqTask) - xTaskNotify(timeSyncReqTask, seq_no, eSetBits); + xTaskNotify(timeSyncReqTask, seq_no, eSetBits); return 1; // success } else { @@ -245,4 +240,15 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec) { millis() / 1000.0); } +void timesync_init() { + // create task for timeserver handshake processing, called from main.cpp + xTaskCreatePinnedToCore(process_timesync_req, // task function + "timesync_req", // name of task + 2048, // stack size of task + (void *)1, // task parameter + 4, // priority of the task + &timeSyncReqTask, // task handle + 1); // CPU core +} + #endif \ No newline at end of file