servertimesync (experimental)
This commit is contained in:
parent
a6663d44b5
commit
85f629b662
4
.gitignore
vendored
4
.gitignore
vendored
@ -10,6 +10,4 @@
|
|||||||
.clang_complete
|
.clang_complete
|
||||||
.gcc-flags.json
|
.gcc-flags.json
|
||||||
src/loraconf.h
|
src/loraconf.h
|
||||||
src/ota.conf
|
src/ota.conf
|
||||||
src/DBtimesync.cpp
|
|
||||||
include/DBtimesync.h
|
|
@ -4,8 +4,8 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "rcommand.h"
|
#include "rcommand.h"
|
||||||
#include "timekeeper.h"
|
#include "timekeeper.h"
|
||||||
#if(DBTIMESYNC)
|
#if(ServertimeSYNC)
|
||||||
#include "DBtimesync.h"
|
#include "Servertimesync.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// LMIC-Arduino LoRaWAN Stack
|
// LMIC-Arduino LoRaWAN Stack
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#include <rom/rtc.h>
|
#include <rom/rtc.h>
|
||||||
#include "cyclic.h"
|
#include "cyclic.h"
|
||||||
#include "timekeeper.h"
|
#include "timekeeper.h"
|
||||||
#if(DBTIMESYNC)
|
#if(ServertimeSYNC)
|
||||||
#include "DBtimesync.h"
|
#include "Servertimesync.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// table of remote commands and assigned functions
|
// table of remote commands and assigned functions
|
||||||
|
27
include/servertimesync.h
Normal file
27
include/servertimesync.h
Normal 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
|
@ -30,7 +30,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
|
|||||||
|
|
||||||
[common]
|
[common]
|
||||||
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
; 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!
|
; 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
|
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
||||||
debug_level = 3
|
debug_level = 3
|
||||||
|
@ -225,7 +225,7 @@ void onEvent(ev_t ev) {
|
|||||||
|
|
||||||
case EV_TXCOMPLETE:
|
case EV_TXCOMPLETE:
|
||||||
|
|
||||||
#if(DBTIMESYNC)
|
#if(ServertimeSYNC)
|
||||||
if (!(LMIC.txrxFlags & TXRX_ACK) && time_sync_seqNo)
|
if (!(LMIC.txrxFlags & TXRX_ACK) && time_sync_seqNo)
|
||||||
time_sync_messages[time_sync_seqNo - 1] = LMIC.txend;
|
time_sync_messages[time_sync_seqNo - 1] = LMIC.txend;
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,8 +67,8 @@
|
|||||||
|
|
||||||
// settings for syncing time of node with external time source
|
// 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_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 TIME_SYNC_LORA 0 // set to 1 to use LORA network as time source, 0 means off [default = 0]
|
||||||
#define DBTIMESYNC 0 // set to 1 to use DB LORA timeserver with patented sync algorithm [default = off]
|
#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
|
// 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
|
#define DAYLIGHT_TIME {"CEST", Last, Sun, Mar, 2, 120} // Central European Summer Time
|
||||||
|
@ -306,10 +306,10 @@ cmd_t table[] = {{0x01, set_rssi, 1, true},
|
|||||||
{0x84, get_gps, 0, false},
|
{0x84, get_gps, 0, false},
|
||||||
{0x85, get_bme, 0, false},
|
{0x85, get_bme, 0, false},
|
||||||
{0x86, get_time, 0, false}
|
{0x86, get_time, 0, false}
|
||||||
#if(DBTIMESYNC)
|
#if(ServertimeSYNC)
|
||||||
,
|
,
|
||||||
{TIME_ANS_OPCODE, recv_DBtime_ans, 0, false},
|
{TIME_ANS_OPCODE, recv_Servertime_ans, 5, false},
|
||||||
{TIME_SYNC_OPCODE, force_DBtime_sync, 0, false}
|
{TIME_SYNC_OPCODE, force_Servertime_sync, 0, false}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
133
src/servertimesync.cpp
Normal file
133
src/servertimesync.cpp
Normal 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
|
@ -36,8 +36,8 @@ time_t timeProvider(void) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// kick off asychronous DB timesync if we have
|
// kick off asychronous DB timesync if we have
|
||||||
#if(DBTIMESYNC)
|
#if(ServertimeSYNC)
|
||||||
send_DBtime_req();
|
send_Servertime_req();
|
||||||
// kick off asychronous lora sync if we have
|
// kick off asychronous lora sync if we have
|
||||||
#elif defined HAS_LORA && (TIME_SYNC_LORA)
|
#elif defined HAS_LORA && (TIME_SYNC_LORA)
|
||||||
LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime);
|
LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime);
|
||||||
|
Loading…
Reference in New Issue
Block a user