servertimesync (experimental)

This commit is contained in:
cyberman54 2019-03-08 16:10:22 +01:00
parent a6663d44b5
commit 85f629b662
10 changed files with 174 additions and 16 deletions

2
.gitignore vendored
View File

@ -11,5 +11,3 @@
.gcc-flags.json
src/loraconf.h
src/ota.conf
src/DBtimesync.cpp
include/DBtimesync.h

View File

@ -4,8 +4,8 @@
#include "globals.h"
#include "rcommand.h"
#include "timekeeper.h"
#if(DBTIMESYNC)
#include "DBtimesync.h"
#if(ServertimeSYNC)
#include "Servertimesync.h"
#endif
// LMIC-Arduino LoRaWAN Stack

View File

@ -9,8 +9,8 @@
#include <rom/rtc.h>
#include "cyclic.h"
#include "timekeeper.h"
#if(DBTIMESYNC)
#include "DBtimesync.h"
#if(ServertimeSYNC)
#include "Servertimesync.h"
#endif
// table of remote commands and assigned functions

27
include/servertimesync.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef _ServertimeSYNC_H
#define _ServertimeSYNC_H
#include "globals.h"
#include "Servertimesync.h"
#include "timekeeper.h"
#define SYNC_SAMPLES 3
//#define SYNC_CYCLE 600 // seconds between two time sync requests
#define SYNC_CYCLE 20 // seconds between two time sync requests
#define SYNC_TIMEOUT \
(SYNC_SAMPLES * (SYNC_CYCLE + 60)) // timeout waiting for time sync answer
#define SYNC_THRESHOLD 0.01f // time deviation threshold triggering time sync
#define TIME_SYNC_OPCODE 0x90
#define TIME_REQ_OPCODE 0x92
#define TIME_ANS_OPCODE 0x93
extern uint32_t time_sync_messages[], time_sync_answers[];
extern uint8_t time_sync_seqNo;
void send_Servertime_req(void);
void recv_Servertime_ans(uint8_t val[]);
void process_Servertime_sync_req(void *taskparameter);
void process_Servertime_sync_ans(void *taskparameter);
void force_Servertime_sync(uint8_t val[]);
#endif

View File

@ -30,7 +30,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
[common]
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
release_version = 1.7.36
release_version = 1.7.361
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 3

View File

@ -225,7 +225,7 @@ void onEvent(ev_t ev) {
case EV_TXCOMPLETE:
#if(DBTIMESYNC)
#if(ServertimeSYNC)
if (!(LMIC.txrxFlags & TXRX_ACK) && time_sync_seqNo)
time_sync_messages[time_sync_seqNo - 1] = LMIC.txend;
#endif

View File

@ -67,8 +67,8 @@
// settings for syncing time of node with external time source
#define TIME_SYNC_INTERVAL 2 // sync time attempt each .. minutes from time source (GPS/LORA/RTC) [default = 60], comment out means off
#define TIME_SYNC_LORA 0 // set to 1 to use LORA network as time source, comment out means off [default = off]
#define DBTIMESYNC 0 // set to 1 to use DB LORA timeserver with patented sync algorithm [default = off]
#define TIME_SYNC_LORA 0 // set to 1 to use LORA network as time source, 0 means off [default = 0]
#define ServertimeSYNC 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

View File

@ -306,10 +306,10 @@ cmd_t table[] = {{0x01, set_rssi, 1, true},
{0x84, get_gps, 0, false},
{0x85, get_bme, 0, false},
{0x86, get_time, 0, false}
#if(DBTIMESYNC)
#if(ServertimeSYNC)
,
{TIME_ANS_OPCODE, recv_DBtime_ans, 0, false},
{TIME_SYNC_OPCODE, force_DBtime_sync, 0, false}
{TIME_ANS_OPCODE, recv_Servertime_ans, 5, false},
{TIME_SYNC_OPCODE, force_Servertime_sync, 0, false}
#endif
};

133
src/servertimesync.cpp Normal file
View File

@ -0,0 +1,133 @@
#ifdef ServertimeSYNC
#include "Servertimesync.h"
// Local logging tag
static const char TAG[] = __FILE__;
TaskHandle_t timeSyncReqTask, timeSyncAnsTask;
uint32_t time_sync_messages[SYNC_SAMPLES] = {0},
time_sync_answers[SYNC_SAMPLES] = {0};
uint8_t time_sync_seqNo = 0;
// send time request message
void send_Servertime_req() {
// if a running timesync handshake is pending then exit
if (time_sync_seqNo)
return;
// initalize sample arrays
for (uint8_t i = 0; i < SYNC_SAMPLES; i++)
time_sync_messages[i] = time_sync_answers[i] = 0;
// create temporary task sending sync requests
if (timeSyncReqTask != NULL)
xTaskCreatePinnedToCore(process_Servertime_sync_req, // task function
"timesync_req", // name of task
2048, // stack size of task
(void *)1, // task parameter
0, // priority of the task
&timeSyncReqTask, // task handle
1); // CPU core
// create temporary task for processing sync answers if not already active
if (timeSyncAnsTask != NULL)
xTaskCreatePinnedToCore(process_Servertime_sync_ans, // task function
"timesync_ans", // name of task
2048, // stack size of task
(void *)1, // task parameter
0, // priority of the task
&timeSyncAnsTask, // task handle
1); // CPU core
}
// handle time sync response, called from rcommanc.cpp
void recv_Servertime_ans(uint8_t val[]) {
uint8_t seq_no = val[0];
uint32_t timestamp = 0;
time_sync_seqNo--;
for (int i = 1; i <= 4; ++i)
timestamp = (timestamp << 8) | val[i];
time_sync_answers[seq_no - 1] = timestamp;
ESP_LOGI(TAG, "Timeserver timestamp received, sequence #%d: %d", seq_no,
timestamp);
// inform processing task
if (timeSyncAnsTask)
xTaskNotify(timeSyncAnsTask, seq_no, eSetBits);
}
void force_Servertime_sync(uint8_t val[]) {
ESP_LOGI(TAG, "Timesync forced by timeserver");
timeSync();
};
// task for sending time sync requests
void process_Servertime_sync_req(void *taskparameter) {
TickType_t startTime = xTaskGetTickCount();
// enqueue timestamp samples in lora sendqueue
for (uint8_t i = 0; i < SYNC_SAMPLES; i++) {
payload.reset();
payload.addAlarm(TIME_REQ_OPCODE, time_sync_seqNo);
SendPayload(TIMEPORT, prio_high);
time_sync_seqNo++;
// Wait for the next cycle
vTaskDelayUntil(&startTime, pdMS_TO_TICKS(SYNC_CYCLE * 1000));
}
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;
// collect incoming timestamp samples notified by rcommand
for (uint8_t i = 0; i < SYNC_SAMPLES; i++) {
if (xTaskNotifyWait(0x00, ULONG_MAX, &seq_no,
SYNC_TIMEOUT * 1000 / portTICK_PERIOD_MS) == pdTRUE)
time_sync_seqNo--;
}
if (time_sync_seqNo) {
ESP_LOGW(TAG, "Timesync handshake failed");
time_sync_seqNo = 0;
}
else {
// calculate time diff from set of collected timestamps
for (uint8_t i = 0; i < SYNC_SAMPLES; i++)
time_diff += time_sync_messages[i] - time_sync_answers[i];
if ((time_diff / SYNC_SAMPLES * 1.0f) > SYNC_THRESHOLD) {
NetworkTime = now() + time_diff;
ESP_LOGD(TAG, "Timesync handshake completed, time offset = %d",
time_diff);
} else
ESP_LOGD(TAG, "Timesync handshake completed, time is up to date");
// Update system time with time read from the network
if (timeIsValid(NetworkTime)) {
setTime(NetworkTime);
timeSource = _lora;
timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync); // regular repeat
ESP_LOGI(TAG, "Recent time received from timeserver");
} else
ESP_LOGW(TAG, "Invalid time received from timeserver");
}
vTaskDelete(NULL); // end task
}
#endif

View File

@ -36,8 +36,8 @@ time_t timeProvider(void) {
#endif
// kick off asychronous DB timesync if we have
#if(DBTIMESYNC)
send_DBtime_req();
#if(ServertimeSYNC)
send_Servertime_req();
// kick off asychronous lora sync if we have
#elif defined HAS_LORA && (TIME_SYNC_LORA)
LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime);