timesync (experimental)

This commit is contained in:
Verkehrsrot committed 2019-03-09 15:25:44 +01:00
1 parent 669d05a1b4
commit c64f087faa
10 files changed
+149 -73

No files matched your search

+5 -2
View File
@@ -35,8 +35,11 @@ void irqHandler(void *pvParameters) {
#if (TIME_SYNC_INTERVAL)
// is time to be synced?
if (InterruptStatus & TIMESYNC_IRQ)
setTime(timeProvider());
if (InterruptStatus & TIMESYNC_IRQ) {
time_t t = timeProvider();
if (timeIsValid(t))
setTime(t);
}
#endif
// is time to send the payload?
+7 -8
View File
@@ -175,6 +175,8 @@ void showLoraKeys(void) {
void onEvent(ev_t ev) {
char buff[24] = "";
uint32_t now_micros;
switch (ev) {
case EV_SCAN_TIMEOUT:
@@ -227,11 +229,10 @@ void onEvent(ev_t ev) {
#if (TIME_SYNC_TIMESERVER)
// if last packet sent was a timesync request was sent, store TX timestamp
if (LMIC.pendTxPort == TIMEPORT) {
time_sync_messages[time_sync_seqNo] = osticks2ms(LMIC.txend);
ESP_LOGD(TAG, "Timeserver request #%d was sent at %d",
time_sync_seqNo, time_sync_messages[time_sync_seqNo]);
}
if ((LMIC.pendTxPort == TIMEPORT) &&
(LMIC.pendTxData[0] == TIME_SYNC_REQ_OPCODE))
store_time_sync_req(now(now_micros), now_micros);
// maybe using more precise osticks2ms(LMIC.txend) here?
#endif
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED_ACK")
@@ -247,7 +248,6 @@ void onEvent(ev_t ev) {
if ((LMIC.txrxFlags & TXRX_PORT) &&
(LMIC.frame[LMIC.dataBeg - 1] == RCMDPORT))
rcommand(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
}
break;
@@ -462,8 +462,7 @@ void user_request_network_time_callback(void *pVoidUserUTCTime,
}
// Update userUTCTime, considering the difference between the GPS and UTC
// time, and the leap seconds
// !!! DANGER !!! This code will expire in next year with leap second
// time, and the leap seconds until year 2019
*pUserUTCTime = lmicTimeReference.tNetwork + 315964800;
// Current time, in ticks
ostime_t ticksNow = os_getTime();
+1 -1
View File
@@ -106,7 +106,7 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) {
blink_LED(COLOR_WHITE, 2000);
#endif
payload.reset();
payload.add2Bytes(rssi, beaconID);
payload.addAlarm(rssi, beaconID);
SendPayload(BEACONPORT, prio_high);
}
};
+1 -1
View File
@@ -68,7 +68,7 @@
// settings for syncing time of node with external time source
#define TIME_SYNC_INTERVAL 60 // sync time attempt each .. minutes from time source (GPS/LORA/RTC) [default = 60], 0 means off
#define TIME_SYNC_LORAWAN 0 // set to 1 to use LORA network as time source, 0 means off [default = 0]
#define TIME_SYNC_TIMESERVER 0 // set to 1 to use LORA timeserver as time source, 0 means off [default = 0]
#define TIME_SYNC_TIMESERVER 1 // set to 1 to use LORA timeserver as time source, 0 means off [default = 0]
// time zone, see https://github.com/JChristensen/Timezone/blob/master/examples/WorldClock/WorldClock.ino
#define DAYLIGHT_TIME {"CEST", Last, Sun, Mar, 2, 120} // Central European Summer Time
+24 -3
View File
@@ -18,12 +18,19 @@ uint8_t *PayloadConvert::getBuffer(void) { return buffer; }
#if PAYLOAD_ENCODER == 1
void PayloadConvert::addByte(uint8_t value) { buffer[cursor++] = (value); }
void PayloadConvert::addWord(uint16_t value) {
buffer[cursor++] = lowByte(value);
buffer[cursor++] = highByte(value);
}
void PayloadConvert::addCount(uint16_t value, uint8_t snifftype) {
buffer[cursor++] = highByte(value);
buffer[cursor++] = lowByte(value);
}
void PayloadConvert::add2Bytes(int8_t rssi, uint8_t msg) {
void PayloadConvert::addAlarm(int8_t rssi, uint8_t msg) {
buffer[cursor++] = rssi;
buffer[cursor++] = msg;
}
@@ -141,11 +148,15 @@ void PayloadConvert::addTime(time_t value) {
#elif PAYLOAD_ENCODER == 2
void PayloadConvert::addByte(uint8_t value) { writeUint8(value); }
void PayloadConvert::addWord(uint16_t value) { writeUint16(value); }
void PayloadConvert::addCount(uint16_t value, uint8_t snifftype) {
writeUint16(value);
}
void PayloadConvert::add2Bytes(int8_t rssi, uint8_t msg) {
void PayloadConvert::addAlarm(int8_t rssi, uint8_t msg) {
writeUint8(rssi);
writeUint8(msg);
}
@@ -299,6 +310,16 @@ void PayloadConvert::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f,
#elif (PAYLOAD_ENCODER == 3 || PAYLOAD_ENCODER == 4)
void PayloadConvert::addByte(uint8_t value) {
/*
not implemented
*/ }
void PayloadConvert::addWord(uint16_t value) {
/*
not implemented
*/ }
void PayloadConvert::addCount(uint16_t value, uint8_t snifftype) {
switch (snifftype) {
case MAC_SNIFF_WIFI:
@@ -322,7 +343,7 @@ void PayloadConvert::addCount(uint16_t value, uint8_t snifftype) {
}
}
void PayloadConvert::add2Bytes(int8_t rssi, uint8_t msg) {
void PayloadConvert::addAlarm(int8_t rssi, uint8_t msg) {
#if (PAYLOAD_ENCODER == 3)
buffer[cursor++] = LPP_ALARM_CHANNEL;
#endif
+1 -1
View File
@@ -308,7 +308,7 @@ cmd_t table[] = {{0x01, set_rssi, 1, true},
{0x86, get_time, 0, false}
#if(TIME_SYNC_TIMESERVER)
,
{TIME_SYNC_ANS_OPCODE, recv_Servertime_ans, 5, false},
{TIME_SYNC_ANS_OPCODE, recv_Servertime_ans, 6, false},
{TIME_SYNC_START_OPCODE, force_Servertime_sync, 0, false}
#endif
};
+84 -42
View File
@@ -18,10 +18,11 @@ patent holder.
static const char TAG[] = __FILE__;
TaskHandle_t timeSyncReqTask, timeSyncAnsTask;
uint32_t time_sync_messages[TIME_SYNC_SAMPLES +
1] = {0},
time_sync_answers[TIME_SYNC_SAMPLES + 1] = {0};
uint8_t volatile time_sync_seqNo = 0; // used in lorawan.cpp to store timestamp
time_sync_message_t
time_sync_messages[TIME_SYNC_SAMPLES + 1] = {0},
time_sync_answers[TIME_SYNC_SAMPLES +
1] = {0};
uint8_t time_sync_seqNo = 0; // used in lorawan.cpp to store timestamp
// send time request message
void send_Servertime_req() {
@@ -35,9 +36,12 @@ void send_Servertime_req() {
// clear timestamp array
for (uint8_t i = 0; i <= TIME_SYNC_SAMPLES + 1; i++) {
time_sync_messages[i] = time_sync_answers[i] = 0;
time_sync_messages[i].seconds = time_sync_answers[i].seconds = 0;
time_sync_messages[i].fractions = time_sync_answers[i].fractions = 0;
}
time_sync_seqNo = 0;
// create temporary task for processing sync answers if not already active
if (!timeSyncAnsTask)
xTaskCreatePinnedToCore(process_Servertime_sync_ans, // task function
@@ -68,14 +72,16 @@ void recv_Servertime_ans(uint8_t val[]) {
return;
uint8_t seq_no = val[0];
uint32_t timestamp = 0;
uint32_t timestamp_sec = 0, timestamp_ms = 0;
for (int i = 1; i <= 4; i++)
timestamp = (timestamp << 8) | val[i];
time_sync_answers[seq_no] = timestamp;
for (int i = 1; i <= 4; i++) {
timestamp_sec = (timestamp_sec << 8) | val[i];
time_sync_answers[seq_no].seconds = timestamp_sec;
}
time_sync_answers[seq_no].fractions = val[5];
ESP_LOGD(TAG, "Timeserver timestamp #%d received: time=%d", seq_no,
timestamp);
ESP_LOGD(TAG, "Timeserver timestamp #%d received: time=%d.%d", seq_no,
timestamp_sec, timestamp_ms);
// inform processing task
if (timeSyncAnsTask)
@@ -88,59 +94,95 @@ void process_Servertime_sync_req(void *taskparameter) {
for (uint8_t i = 1; i <= TIME_SYNC_SAMPLES; i++) {
time_sync_seqNo++;
payload.reset();
payload.add2Bytes(TIME_SYNC_REQ_OPCODE, i);
payload.addWord(TIME_SYNC_REQ_OPCODE | time_sync_seqNo << 8);
SendPayload(TIMEPORT, prio_high);
ESP_LOGD(TAG, "Timeserver request #%d sent", i);
ESP_LOGD(TAG, "Timeserver request #%d sent", time_sync_seqNo);
// Wait for the next cycle
vTaskDelay(pdMS_TO_TICKS(TIME_SYNC_CYCLE * 1000));
}
payload.reset();
payload.addByte(TIME_SYNC_STOP_OPCODE);
SendPayload(TIMEPORT, prio_high); // necessary to receive last timestamp
timeSyncReqTask = NULL;
vTaskDelete(NULL); // end task
}
// task for processing a timesync handshake
void process_Servertime_sync_ans(void *taskparameter) {
uint32_t seq_no = 0;
uint32_t NetworkTime = 0;
int32_t time_diff = 0;
uint8_t ans_counter = TIME_SYNC_SAMPLES;
uint32_t seq_no = 0, time_diff_sec = 0, time_diff_ms = 0;
time_t time_to_set = 0;
float time_offset = 0.0f;
// collect incoming timestamp samples notified by rcommand
for (uint8_t i = 1; i <= TIME_SYNC_SAMPLES; i++) {
if (xTaskNotifyWait(0x00, ULONG_MAX, &seq_no,
(TIME_SYNC_CYCLE + TIME_SYNC_TIMEOUT) * 1000 /
portTICK_PERIOD_MS) == pdFALSE)
continue; // no answer received before timeout
if ((xTaskNotifyWait(0x00, ULONG_MAX, &seq_no,
(TIME_SYNC_CYCLE + TIME_SYNC_TIMEOUT) * 1000 /
portTICK_PERIOD_MS) == pdFALSE) ||
(seq_no != i)) {
ESP_LOGW(TAG, "Timesync handshake timeout");
goto finish; // no valid sequence received before timeout
} else // calculate time diff from set of collected timestamps
{
time_diff_sec += time_sync_messages[seq_no].seconds -
time_sync_answers[seq_no].seconds;
time_diff_ms += 4 * (time_sync_messages[seq_no].fractions -
time_sync_answers[seq_no].fractions);
}
} // for
time_diff += time_sync_messages[seq_no] - time_sync_answers[seq_no];
ans_counter--;
}
time_offset = (time_diff_sec + time_diff_ms / 1000.0) / TIME_SYNC_SAMPLES;
if (ans_counter) {
ESP_LOGW(TAG, "Timesync handshake timeout");
} else {
// calculate time diff from set of collected timestamps
if (time_diff / TIME_SYNC_SAMPLES) {
NetworkTime = now() + time_diff;
ESP_LOGI(TAG, "Timesync finished, time offset=%d seconds", time_diff);
// Update system time with time read from the network
if (timeIsValid(NetworkTime)) {
setTime(NetworkTime);
timeSource = _lora;
timesyncer.attach(TIME_SYNC_INTERVAL * 60,
timeSync); // set to regular repeat
ESP_LOGI(TAG, "Recent time received from timeserver");
} else
ESP_LOGW(TAG, "Invalid time received from timeserver");
ESP_LOGD(TAG, "Timesync finished, time offset=%.4f seconds", time_offset);
// check time diff and if necessary set time
if (time_offset >= TIME_SYNC_THRESHOLD) {
// wait until top of second
if (time_diff_ms > 0) {
vTaskDelay(1000 - time_diff_ms); // clock is fast
time_diff_sec--;
} else if (time_diff_ms < 0) { // clock is stale
vTaskDelay(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);
// Update system time with time read from the network
if (timeIsValid(time_to_set)) {
setTime(time_to_set);
SyncToPPS();
timeSource = _lora;
timesyncer.attach(TIME_SYNC_INTERVAL * 60,
timeSync); // set to regular repeat
ESP_LOGI(TAG, "Timesync finished, time was adjusted");
} else
ESP_LOGI(TAG, "Timesync finished, time is up to date");
} // if (ans_counter)
ESP_LOGW(TAG, "Invalid time received from timeserver");
} else
ESP_LOGI(TAG, "Timesync finished, time is up to date");
finish:
time_sync_seqNo = 0;
timeSyncAnsTask = NULL;
vTaskDelete(NULL); // end task
}
// called from lorawan.cpp when tine_sync_req was sent
void store_time_sync_req(time_t secs, uint32_t micros) {
time_sync_messages[time_sync_seqNo].seconds = secs;
time_sync_messages[time_sync_seqNo].fractions =
micros / 250; // 4ms resolution
ESP_LOGD(TAG, "Timeserver request #%d was sent at %d.%d", time_sync_seqNo,
time_sync_messages[time_sync_seqNo].seconds,
time_sync_messages[time_sync_seqNo].fractions);
}
void force_Servertime_sync(uint8_t val[]) {
ESP_LOGI(TAG, "Timesync requested by timeserver");
timeSync();