big timesync code sanitization
This commit is contained in:
parent
3f2c08432d
commit
2cf52f1af6
@ -127,7 +127,6 @@ extern SemaphoreHandle_t I2Caccess;
|
|||||||
extern TaskHandle_t irqHandlerTask, ClockTask;
|
extern TaskHandle_t irqHandlerTask, ClockTask;
|
||||||
extern TimerHandle_t WifiChanTimer;
|
extern TimerHandle_t WifiChanTimer;
|
||||||
extern Timezone myTZ;
|
extern Timezone myTZ;
|
||||||
extern time_t userUTCTime;
|
|
||||||
extern RTC_DATA_ATTR runmode_t RTC_runmode;
|
extern RTC_DATA_ATTR runmode_t RTC_runmode;
|
||||||
|
|
||||||
// application includes
|
// application includes
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
#include "rcommand.h"
|
#include "rcommand.h"
|
||||||
#include "timekeeper.h"
|
#include "timekeeper.h"
|
||||||
#include <driver/rtc_io.h>
|
#include <driver/rtc_io.h>
|
||||||
#if (TIME_SYNC_LORASERVER)
|
|
||||||
#include "timesync.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// LMIC-Arduino LoRaWAN Stack
|
// LMIC-Arduino LoRaWAN Stack
|
||||||
#include <lmic.h>
|
#include <lmic.h>
|
||||||
@ -54,9 +51,4 @@ const char *getSfName(rps_t rps);
|
|||||||
const char *getBwName(rps_t rps);
|
const char *getBwName(rps_t rps);
|
||||||
const char *getCrName(rps_t rps);
|
const char *getCrName(rps_t rps);
|
||||||
|
|
||||||
#if (TIME_SYNC_LORAWAN)
|
|
||||||
void user_request_network_time_callback(void *pVoidUserUTCTime,
|
|
||||||
int flagSuccess);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -5,6 +5,7 @@
|
|||||||
#include "rtctime.h"
|
#include "rtctime.h"
|
||||||
#include "TimeLib.h"
|
#include "TimeLib.h"
|
||||||
#include "irqhandler.h"
|
#include "irqhandler.h"
|
||||||
|
#include "timesync.h"
|
||||||
|
|
||||||
#if (HAS_GPS)
|
#if (HAS_GPS)
|
||||||
#include "gpsread.h"
|
#include "gpsread.h"
|
||||||
|
@ -1,30 +1,31 @@
|
|||||||
#ifndef _TIMESYNC_H
|
#ifndef _TIMESYNC_H
|
||||||
#define _TIMESYNC_H
|
#define _TIMESYNC_H
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "irqhandler.h"
|
#include "irqhandler.h"
|
||||||
#include "timekeeper.h"
|
#include "timekeeper.h"
|
||||||
|
|
||||||
//#define TIME_SYNC_TRIGGER 100 // threshold for time sync [milliseconds]
|
|
||||||
#define TIME_SYNC_FRAME_LENGTH 0x07 // timeserver answer frame length [bytes]
|
#define TIME_SYNC_FRAME_LENGTH 0x07 // timeserver answer frame length [bytes]
|
||||||
#define TIME_SYNC_FIXUP 16 // empirical calibration to fixup processing time [milliseconds]
|
#define TIME_SYNC_FIXUP 16 // compensation for processing time [milliseconds]
|
||||||
#define TIMEREQUEST_MAX_SEQNO 0xfe // threshold for wrap around seqno
|
#define TIMEREQUEST_MAX_SEQNO 0xfe // threshold for wrap around seqno
|
||||||
#define TIMEREQUEST_FINISH \
|
#define TIMEREQUEST_FINISH \
|
||||||
(TIMEREQUEST_MAX_SEQNO + 1) // marker for end of timesync handshake
|
(TIMEREQUEST_MAX_SEQNO + 1) // marker for end of timesync handshake
|
||||||
|
#define GPS_UTC_DIFF 315964800
|
||||||
|
|
||||||
enum timesync_t {
|
enum timesync_t {
|
||||||
timesync_tx,
|
timesync_tx,
|
||||||
timesync_rx,
|
timesync_rx,
|
||||||
gwtime_sec,
|
gwtime_sec,
|
||||||
gwtime_msec,
|
gwtime_msec,
|
||||||
|
gwtime_tzsec,
|
||||||
no_of_timestamps
|
no_of_timestamps
|
||||||
};
|
};
|
||||||
|
|
||||||
void timesync_init(void);
|
void timesync_init(void);
|
||||||
void send_timesync_req(void);
|
void send_timesync_req(void);
|
||||||
int recv_timesync_ans(const uint8_t buf[], uint8_t buf_len);
|
int recv_timesync_ans(const uint8_t buf[], uint8_t buf_len);
|
||||||
void process_timesync_req(void *taskparameter);
|
|
||||||
void store_timestamp(uint32_t timestamp, timesync_t timestamp_type);
|
void store_timestamp(uint32_t timestamp, timesync_t timestamp_type);
|
||||||
|
void IRAM_ATTR process_timesync_req(void *taskparameter);
|
||||||
|
void IRAM_ATTR process_timesync_req(void *pVoidUserUTCTime, int flagSuccess);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -381,56 +381,6 @@ void lora_enqueuedata(MessageBuffer_t *message) {
|
|||||||
|
|
||||||
void lora_queuereset(void) { xQueueReset(LoraSendQueue); }
|
void lora_queuereset(void) { xQueueReset(LoraSendQueue); }
|
||||||
|
|
||||||
#if (TIME_SYNC_LORAWAN)
|
|
||||||
void IRAM_ATTR user_request_network_time_callback(void *pVoidUserUTCTime,
|
|
||||||
int flagSuccess) {
|
|
||||||
// Explicit conversion from void* to uint32_t* to avoid compiler errors
|
|
||||||
time_t *pUserUTCTime = (time_t *)pVoidUserUTCTime;
|
|
||||||
|
|
||||||
// A struct that will be populated by LMIC_getNetworkTimeReference.
|
|
||||||
// It contains the following fields:
|
|
||||||
// - tLocal: the value returned by os_GetTime() when the time
|
|
||||||
// request was sent to the gateway, and
|
|
||||||
// - tNetwork: the seconds between the GPS epoch and the time
|
|
||||||
// the gateway received the time request
|
|
||||||
lmic_time_reference_t lmicTimeReference;
|
|
||||||
|
|
||||||
if (flagSuccess != 1) {
|
|
||||||
ESP_LOGW(TAG, "LoRaWAN network did not answer time request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate lmic_time_reference
|
|
||||||
flagSuccess = LMIC_getNetworkTimeReference(&lmicTimeReference);
|
|
||||||
if (flagSuccess != 1) {
|
|
||||||
ESP_LOGW(TAG, "LoRaWAN time request failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mask application irq to ensure accurate timing
|
|
||||||
mask_user_IRQ();
|
|
||||||
|
|
||||||
// Update userUTCTime, considering the difference between the GPS and UTC
|
|
||||||
// time, and the leap seconds until year 2019
|
|
||||||
*pUserUTCTime = lmicTimeReference.tNetwork + 315964800;
|
|
||||||
// Current time, in ticks
|
|
||||||
ostime_t ticksNow = os_getTime();
|
|
||||||
// Time when the request was sent, in ticks
|
|
||||||
ostime_t ticksRequestSent = lmicTimeReference.tLocal;
|
|
||||||
// Add the delay between the instant the time was transmitted and
|
|
||||||
// the current time
|
|
||||||
time_t requestDelaySec = osticks2ms(ticksNow - ticksRequestSent) / 1000;
|
|
||||||
|
|
||||||
// Update system time with time read from the network
|
|
||||||
setMyTime(*pUserUTCTime + requestDelaySec, 0, _lora);
|
|
||||||
|
|
||||||
finish:
|
|
||||||
// end of time critical section: release app irq lock
|
|
||||||
unmask_user_IRQ();
|
|
||||||
|
|
||||||
} // user_request_network_time_callback
|
|
||||||
#endif // TIME_SYNC_LORAWAN
|
|
||||||
|
|
||||||
// LMIC lorawan stack task
|
// LMIC lorawan stack task
|
||||||
void lmictask(void *pvParameters) {
|
void lmictask(void *pvParameters) {
|
||||||
configASSERT(((uint32_t)pvParameters) == 1);
|
configASSERT(((uint32_t)pvParameters) == 1);
|
||||||
|
@ -87,7 +87,6 @@ hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL, *matrixDisplayIRQ = NULL;
|
|||||||
TaskHandle_t irqHandlerTask = NULL, ClockTask = NULL;
|
TaskHandle_t irqHandlerTask = NULL, ClockTask = NULL;
|
||||||
SemaphoreHandle_t I2Caccess;
|
SemaphoreHandle_t I2Caccess;
|
||||||
bool volatile TimePulseTick = false;
|
bool volatile TimePulseTick = false;
|
||||||
time_t userUTCTime = 0;
|
|
||||||
timesource_t timeSource = _unsynced;
|
timesource_t timeSource = _unsynced;
|
||||||
|
|
||||||
// container holding unique MAC address hashes with Memory Alloctor using PSRAM,
|
// container holding unique MAC address hashes with Memory Alloctor using PSRAM,
|
||||||
|
@ -37,12 +37,9 @@ void calibrateTime(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// kick off asychronous Lora timeserver timesync if we have
|
// kick off asychronous lora timesync if we have
|
||||||
#if (HAS_LORA) && (TIME_SYNC_LORASERVER)
|
#if (HAS_LORA) && (TIME_SYNC_LORASERVER) || (TIME_SYNC_LORAWAN)
|
||||||
send_timesync_req();
|
send_timesync_req();
|
||||||
// kick off asychronous lora network sync if we have
|
|
||||||
#elif (HAS_LORA) && (TIME_SYNC_LORAWAN)
|
|
||||||
LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// no time from GPS -> fallback to RTC time while trying lora sync
|
// no time from GPS -> fallback to RTC time while trying lora sync
|
||||||
@ -233,7 +230,7 @@ void clock_init(void) {
|
|||||||
pinMode(HAS_DCF77, OUTPUT);
|
pinMode(HAS_DCF77, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
userUTCTime = now();
|
time_t userUTCTime = now();
|
||||||
|
|
||||||
xTaskCreatePinnedToCore(clock_loop, // task function
|
xTaskCreatePinnedToCore(clock_loop, // task function
|
||||||
"clockloop", // name of task
|
"clockloop", // name of task
|
||||||
|
@ -1,31 +1,37 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
///--> IMPORTANT LICENSE NOTE for this file <--///
|
///--> IMPORTANT LICENSE NOTE for timesync option 1 in this file <--///
|
||||||
|
|
||||||
PLEASE NOTE: There is a patent filed for the time sync algorithm used in the
|
PLEASE NOTE: There is a patent filed for the time sync algorithm used in the
|
||||||
code of this file. The shown implementation example is covered by the
|
code of this file. The shown implementation example is covered by the
|
||||||
repository's licencse, but you may not be eligible to deploy the applied
|
repository's licencse, but you may not be eligible to deploy the applied
|
||||||
algorithm in applications without granted license by the patent holder.
|
algorithm in applications without granted license by the patent holder.
|
||||||
|
|
||||||
|
You may use timesync option 2 if you do not want or cannot accept this.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if (TIME_SYNC_LORASERVER) && (HAS_LORA)
|
|
||||||
|
|
||||||
#include "timesync.h"
|
#include "timesync.h"
|
||||||
|
|
||||||
|
#if (TIME_SYNC_LORASERVER) && (TIME_SYNC_LORAWAN) && (HAS_LORA)
|
||||||
|
#error Duplicate timesync method selected. You must select either LORASERVER or LORAWAN timesync.
|
||||||
|
#endif
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = __FILE__;
|
static const char TAG[] = __FILE__;
|
||||||
|
|
||||||
TaskHandle_t timeSyncReqTask = NULL;
|
// timesync option 1: use external timeserver (for LoRAWAN < 1.0.3)
|
||||||
|
|
||||||
|
#if (TIME_SYNC_LORASERVER) && (HAS_LORA)
|
||||||
|
|
||||||
|
static TaskHandle_t timeSyncReqTask = NULL;
|
||||||
|
static bool timeSyncPending = false;
|
||||||
static uint8_t time_sync_seqNo = (uint8_t)random(TIMEREQUEST_MAX_SEQNO);
|
static uint8_t time_sync_seqNo = (uint8_t)random(TIMEREQUEST_MAX_SEQNO);
|
||||||
static uint8_t sample_idx = 0;
|
static uint8_t sample_idx = 0;
|
||||||
static bool timeSyncPending = false;
|
|
||||||
static uint32_t timesync_timestamp[TIME_SYNC_SAMPLES][no_of_timestamps] = {0};
|
static uint32_t timesync_timestamp[TIME_SYNC_SAMPLES][no_of_timestamps] = {0};
|
||||||
|
|
||||||
// send time request message
|
// send time request message
|
||||||
void send_timesync_req() {
|
void send_timesync_req(void) {
|
||||||
|
|
||||||
// if a timesync handshake is pending then exit
|
// if a timesync handshake is pending then exit
|
||||||
if (timeSyncPending)
|
if (timeSyncPending)
|
||||||
return;
|
return;
|
||||||
@ -37,7 +43,7 @@ void send_timesync_req() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// task for sending time sync requests
|
// task for sending time sync requests
|
||||||
void process_timesync_req(void *taskparameter) {
|
void IRAM_ATTR process_timesync_req(void *taskparameter) {
|
||||||
|
|
||||||
uint32_t rcv_seq_no = TIMEREQUEST_FINISH, time_offset_ms;
|
uint32_t rcv_seq_no = TIMEREQUEST_FINISH, time_offset_ms;
|
||||||
|
|
||||||
@ -175,22 +181,24 @@ int recv_timesync_ans(const uint8_t buf[], const uint8_t buf_len) {
|
|||||||
|
|
||||||
else { // we received a probably valid time frame
|
else { // we received a probably valid time frame
|
||||||
|
|
||||||
// pointers to 4 bytes containing UTC seconds since unix epoch, msb
|
// pointers to 4 bytes msb order
|
||||||
uint32_t timestamp_sec, *timestamp_ptr;
|
uint32_t timestamp_sec, *timestamp_ptr;
|
||||||
|
|
||||||
// extract 1 byte timezone from payload (one step being 15min * 60s = 900s)
|
// extract 1 byte containing timezone offset
|
||||||
// uint32_t timezone_sec = buf[0] * 900; // for future use
|
// one step being 15min * 60sec = 900sec
|
||||||
|
uint32_t timestamp_tzsec = buf[0] * 900; // timezone offset in secs
|
||||||
buf++;
|
buf++;
|
||||||
|
|
||||||
// extract 4 bytes timestamp from payload
|
// extract 4 bytes containing gateway time in UTC seconds since unix
|
||||||
// and convert it to uint32_t, octet order is big endian
|
// epoch and convert it to uint32_t, octet order is big endian
|
||||||
timestamp_ptr = (uint32_t *)buf;
|
timestamp_ptr = (uint32_t *)buf;
|
||||||
// swap byte order from msb to lsb, note: this is platform dependent
|
// swap byte order from msb to lsb, note: this is a platform dependent hack
|
||||||
timestamp_sec = __builtin_bswap32(*timestamp_ptr);
|
timestamp_sec = __builtin_bswap32(*timestamp_ptr);
|
||||||
buf += 4;
|
buf += 4;
|
||||||
// extract 1 byte fractional seconds in 2^-8 second steps
|
|
||||||
// (= 1/250th sec), we convert this to ms
|
// extract 1 byte containing fractional seconds in 2^-8 second steps
|
||||||
uint16_t timestamp_msec = 4 * buf[0];
|
// one step being 1/250th sec * 1000 = 4msec
|
||||||
|
uint16_t timestamp_msec = buf[0] * 4;
|
||||||
// calculate absolute time received from gateway
|
// calculate absolute time received from gateway
|
||||||
time_t t = timestamp_sec + timestamp_msec / 1000;
|
time_t t = timestamp_sec + timestamp_msec / 1000;
|
||||||
|
|
||||||
@ -202,6 +210,7 @@ int recv_timesync_ans(const uint8_t buf[], const uint8_t buf_len) {
|
|||||||
// store time received from gateway
|
// store time received from gateway
|
||||||
store_timestamp(timestamp_sec, gwtime_sec);
|
store_timestamp(timestamp_sec, gwtime_sec);
|
||||||
store_timestamp(timestamp_msec, gwtime_msec);
|
store_timestamp(timestamp_msec, gwtime_msec);
|
||||||
|
store_timestamp(timestamp_tzsec, gwtime_tzsec);
|
||||||
|
|
||||||
// inform processing task
|
// inform processing task
|
||||||
xTaskNotify(timeSyncReqTask, seq_no, eSetBits);
|
xTaskNotify(timeSyncReqTask, seq_no, eSetBits);
|
||||||
@ -227,3 +236,56 @@ void timesync_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// timesync option 2: use LoRAWAN network time (requires LoRAWAN >= 1.0.3)
|
||||||
|
|
||||||
|
#if (TIME_SYNC_LORAWAN) && (HAS_LORA)
|
||||||
|
|
||||||
|
static time_t networkUTCTime;
|
||||||
|
|
||||||
|
// send time request message
|
||||||
|
void send_timesync_req(void) {
|
||||||
|
LMIC_requestNetworkTime(process_timesync_req, &networkUTCTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR process_timesync_req(void *pVoidUserUTCTime, int flagSuccess) {
|
||||||
|
// Explicit conversion from void* to uint32_t* to avoid compiler errors
|
||||||
|
time_t *pUserUTCTime = (time_t *)pVoidUserUTCTime;
|
||||||
|
|
||||||
|
// A struct that will be populated by LMIC_getNetworkTimeReference.
|
||||||
|
// It contains the following fields:
|
||||||
|
// - tLocal: the value returned by os_GetTime() when the time
|
||||||
|
// request was sent to the gateway, and
|
||||||
|
// - tNetwork: the seconds between the GPS epoch and the time
|
||||||
|
// the gateway received the time request
|
||||||
|
lmic_time_reference_t lmicTimeReference;
|
||||||
|
|
||||||
|
if (flagSuccess != 1) {
|
||||||
|
ESP_LOGW(TAG, "LoRaWAN network did not answer time request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate lmic_time_reference
|
||||||
|
flagSuccess = LMIC_getNetworkTimeReference(&lmicTimeReference);
|
||||||
|
if (flagSuccess != 1) {
|
||||||
|
ESP_LOGW(TAG, "LoRaWAN time request failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mask application irq to ensure accurate timing
|
||||||
|
mask_user_IRQ();
|
||||||
|
|
||||||
|
// Update networkUTCTime, considering the difference between GPS and UTC time
|
||||||
|
*pUserUTCTime = lmicTimeReference.tNetwork + GPS_UTC_DIFF;
|
||||||
|
// Add delay between the instant the time was transmitted and the current time
|
||||||
|
uint16_t requestDelaymSec =
|
||||||
|
osticks2ms(os_getTime() - lmicTimeReference.tLocal);
|
||||||
|
|
||||||
|
// Update system time with time read from the network
|
||||||
|
setMyTime(*pUserUTCTime, requestDelaymSec, _lora);
|
||||||
|
|
||||||
|
// end of time critical section: release app irq lock
|
||||||
|
unmask_user_IRQ();
|
||||||
|
|
||||||
|
} // user_request_network_time_callback
|
||||||
|
#endif // TIME_SYNC_LORAWAN
|
Loading…
Reference in New Issue
Block a user