big timesync code sanitization

This commit is contained in:
Klaus K Wilting 2020-03-04 21:54:26 +01:00
parent 3f2c08432d
commit 2cf52f1af6
8 changed files with 88 additions and 87 deletions

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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