From bd8718f23fb5d3b3b140388ad4ca6d8aebda9fb6 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 11 Mar 2019 01:05:41 +0100 Subject: [PATCH] timeserver (experimental) --- include/timesync.h | 2 +- src/TTN/Nodered-Timeserver.json | 2 +- src/timesync.cpp | 72 ++++++++++++++++++++------------- 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/include/timesync.h b/include/timesync.h index 33d35462..866f5a4c 100644 --- a/include/timesync.h +++ b/include/timesync.h @@ -5,7 +5,7 @@ #include "timesync.h" #include "timekeeper.h" -#define TIME_SYNC_SAMPLES 1 // number of time requests for averaging +#define TIME_SYNC_SAMPLES 3 // number of time requests for averaging #define TIME_SYNC_CYCLE 30 // seconds between two time requests #define TIME_SYNC_TIMEOUT 120 // timeout seconds waiting for timeserver answer #define TIME_SYNC_TRIGGER 1.0f // time deviation threshold triggering time sync diff --git a/src/TTN/Nodered-Timeserver.json b/src/TTN/Nodered-Timeserver.json index 2ad5c54e..f2aac01c 100644 --- a/src/TTN/Nodered-Timeserver.json +++ b/src/TTN/Nodered-Timeserver.json @@ -131,7 +131,7 @@ "type": "function", "z": "449c1517.e25f4c", "name": "Time_Sync_Ans", - "func": "/* LoRaWAN Timeserver\n\nconstruct 6 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n0 sequence number (taken from node's time_sync_req)\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\n*/\n\n let buf = new ArrayBuffer(6);\n let timestamp = (+new Date(msg.payload.metadata.gateways[0].time));\n \n var seconds = Math.floor(timestamp/1000);\n var fractions = timestamp % 250;\n var seqno = msg.payload.payload_raw[0];\n\n new DataView(buf).setUint8(0, seqno);\n new DataView(buf).setUint32(1, seconds);\n new DataView(buf).setUint8(5, fractions);\n\n msg.payload = new Buffer(new Uint8Array(buf));\n \n return msg;", + "func": "/* LoRaWAN Timeserver\n\nconstruct 6 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n0 sequence number (taken from node's time_sync_req)\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\n*/\n\n let buf = new ArrayBuffer(6);\n let timestamp = (+new Date(msg.payload.metadata.gateways[0].time));\n \n var seconds = Math.floor(timestamp/1000);\n var fractions = (timestamp % 1000) / 4;\n var seqno = msg.payload.payload_raw[0];\n\n new DataView(buf).setUint8(0, seqno);\n new DataView(buf).setUint32(1, seconds);\n new DataView(buf).setUint8(5, fractions);\n\n msg.payload = new Buffer(new Uint8Array(buf));\n \n return msg;", "outputs": 1, "noerr": 0, "x": 400, diff --git a/src/timesync.cpp b/src/timesync.cpp index 26267b14..c6f9f5fe 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -19,8 +19,8 @@ static const char TAG[] = __FILE__; TaskHandle_t timeSyncReqTask; time_sync_message_t time_sync_messages[TIME_SYNC_SAMPLES] = {0}, time_sync_answers[TIME_SYNC_SAMPLES] = {0}; -uint8_t time_sync_seqNo = 0; -bool time_sync_pending = false; +static uint8_t time_sync_seqNo = 0; +static bool time_sync_pending = false; // send time request message void send_Servertime_req() { @@ -59,15 +59,18 @@ void recv_Servertime_ans(uint8_t buf[], uint8_t buf_len) { if ((!time_sync_pending) || (buf_len != TIME_SYNC_FRAME_LENGTH)) return; - uint8_t seq_no = buf[0]; - uint32_t timestamp_sec = 0, timestamp_ms = 0; + uint8_t seq_no = buf[0], k = seq_no % TIME_SYNC_SAMPLES; + uint32_t timestamp_sec = 0; - for (uint8_t i = 1; i <= 4; i++) - time_sync_answers[seq_no].seconds = (timestamp_sec <<= 8) |= buf[i]; - time_sync_answers[seq_no].fractions = timestamp_ms = 4 * buf[5]; + for (uint8_t i = 1; i <= 4; i++) { + time_sync_answers[k].seconds = (timestamp_sec <<= 8) |= buf[i]; + } + time_sync_answers[k].fractions = buf[5]; - ESP_LOGD(TAG, "Timeserver answer #%d received: timestamp=%d.%03d", seq_no, - timestamp_sec, timestamp_ms); + ESP_LOGD(TAG, "Timeserver answer:"); + + ESP_LOGD(TAG, "ans.sec(%d)=%d / ans.ms(%d)=%d", k, + time_sync_answers[k].seconds, k, time_sync_answers[k].fractions); // inform processing task if (timeSyncReqTask) @@ -77,11 +80,10 @@ void recv_Servertime_ans(uint8_t buf[], uint8_t buf_len) { // task for sending time sync requests void process_Servertime_sync_req(void *taskparameter) { - time_t time_to_set = 0; - uint32_t seq_no = 0; - int16_t time_diff_ms = 0; - int64_t time_diff_sec = 0; - float time_offset = 0.0f; + time_t t = 0, time_to_set = 0; + uint32_t seq_no = 0, k = 0; + int time_diff_frac = 0, time_diff_ms = 0; + long time_diff_sec = 0, time_offset = 0; // enqueue timestamp samples in lora sendqueue for (uint8_t i = 1; i <= TIME_SYNC_SAMPLES; i++) { @@ -94,10 +96,12 @@ void process_Servertime_sync_req(void *taskparameter) { payload.addByte(time_sync_seqNo); SendPayload(TIMEPORT, prio_high); + /* -> do we really need this? maybe for SF9 up? // send dummy packet to trigger receive answer - //payload.reset(); - //payload.addByte(0x99); // flush - //SendPayload(RCMDPORT, prio_low); // to open receive slot for answer + payload.reset(); + payload.addByte(0x99); // flush + SendPayload(RCMDPORT, prio_low); // to open receive slot for answer + */ // process answer if ((xTaskNotifyWait(0x00, ULONG_MAX, &seq_no, @@ -109,20 +113,29 @@ void process_Servertime_sync_req(void *taskparameter) { } // no valid sequence received before timeout else { // calculate time diff from set of collected timestamps - uint8_t k = seq_no % TIME_SYNC_SAMPLES; + + k = seq_no % TIME_SYNC_SAMPLES; + time_diff_sec += - (time_sync_messages[k].seconds - time_sync_answers[k].seconds); - time_diff_ms += (4 * (time_sync_messages[k].fractions - - time_sync_answers[k].fractions)); + ((time_sync_messages[k].seconds - time_sync_answers[k].seconds) / TIME_SYNC_SAMPLES); + + time_diff_frac += + ((time_sync_messages[k].fractions - time_sync_answers[k].fractions) / TIME_SYNC_SAMPLES); + + ESP_LOGD(TAG, "time_diff_sec=%d / time_diff_frac=%d", time_diff_sec, + time_diff_frac); } } // for // calculate time offset and set time if necessary - time_offset = (time_diff_sec + time_diff_ms / 1000.0f) / TIME_SYNC_SAMPLES; - ESP_LOGD(TAG, "Timesync time offset=%.3f", time_offset); - ESP_LOGD(TAG, "Timesync time_diff_ms=%03d", time_diff_ms); + time_diff_ms = 4 * time_diff_frac; + time_offset = (time_diff_sec + (long) (time_diff_ms / 1000)); - if (time_offset >= TIME_SYNC_TRIGGER) { + ESP_LOGD(TAG, "Timesync time offset=%d", time_offset); + + t = now(); + + if (labs(time_offset) >= (t + TIME_SYNC_TRIGGER)) { // wait until top of second if (time_diff_ms > 0) // clock is fast vTaskDelay(pdMS_TO_TICKS(time_diff_ms)); @@ -130,8 +143,8 @@ void process_Servertime_sync_req(void *taskparameter) { vTaskDelay(pdMS_TO_TICKS(1000 + time_diff_ms)); time_diff_sec++; - time_to_set = time_t(now() + time_diff_sec); - ESP_LOGD(TAG, "Time to set = %d", time_to_set); + time_to_set = t - time_t(time_diff_sec); + ESP_LOGD(TAG, "Now()=%d, Time to set = %d", t, time_to_set); // adjust system time if (timeIsValid(time_to_set)) { @@ -156,8 +169,9 @@ finish: // called from lorawan.cpp after time_sync_req was sent void store_time_sync_req(time_t secs, uint32_t micros) { uint8_t k = time_sync_seqNo % TIME_SYNC_SAMPLES; - time_sync_messages[k].seconds = secs; - time_sync_messages[k].fractions = micros / 250; // 4ms resolution + + time_sync_messages[k].seconds = (uint32_t) secs; + time_sync_messages[k].fractions = (uint8_t) (micros / 4000); // 4ms resolution ESP_LOGD(TAG, "Timeserver request #%d sent at %d.%03d", time_sync_seqNo, time_sync_messages[k].seconds, time_sync_messages[k].fractions);