servertimesync (experimental)
This commit is contained in:
parent
a6663d44b5
commit
85f629b662
4
.gitignore
vendored
4
.gitignore
vendored
@ -10,6 +10,4 @@
|
||||
.clang_complete
|
||||
.gcc-flags.json
|
||||
src/loraconf.h
|
||||
src/ota.conf
|
||||
src/DBtimesync.cpp
|
||||
include/DBtimesync.h
|
||||
src/ota.conf
|
@ -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
|
||||
|
@ -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
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]
|
||||
; 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
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
|
||||
|
||||
// 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);
|
||||
|
Loading…
Reference in New Issue
Block a user