timesync code refactored
This commit is contained in:
		
							parent
							
								
									85c342e3d7
								
							
						
					
					
						commit
						f5399d8108
					
				@ -5,12 +5,11 @@
 | 
			
		||||
#include "irqhandler.h"
 | 
			
		||||
#include "timekeeper.h"
 | 
			
		||||
 | 
			
		||||
#define TIME_SYNC_FRAME_LENGTH 0x07 // timeserver answer frame length [bytes]
 | 
			
		||||
#define TIME_SYNC_FRAME_LENGTH 6 // timeserver answer frame length [bytes]
 | 
			
		||||
#define TIME_SYNC_FIXUP 16 // compensation for processing time [milliseconds]
 | 
			
		||||
#define TIMEREQUEST_MAX_SEQNO 0xfe // threshold for wrap around seqno
 | 
			
		||||
#define TIMEREQUEST_END                                                        \
 | 
			
		||||
  (TIMEREQUEST_MAX_SEQNO + 1) // marker for end of timesync handshake
 | 
			
		||||
#define GPS_UTC_DIFF 315964800
 | 
			
		||||
#define TIMEREQUEST_MAX_SEQNO 0xfe // threshold for wrap around seqNo
 | 
			
		||||
#define TIMEREQUEST_END (TIMEREQUEST_MAX_SEQNO + 1) // end of handshake marker
 | 
			
		||||
#define GPS_UTC_DIFF 315964800 // seconds diff between gps and utc epoch
 | 
			
		||||
 | 
			
		||||
enum timesync_t {
 | 
			
		||||
  timesync_tx,
 | 
			
		||||
 | 
			
		||||
@ -472,7 +472,7 @@ void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
 | 
			
		||||
#if (TIME_SYNC_LORASERVER)
 | 
			
		||||
  case TIMEPORT:
 | 
			
		||||
    // get and store gwtime from payload
 | 
			
		||||
    timesync_serverAnswer(&pMsg, nMsg);
 | 
			
		||||
    timesync_serverAnswer(const_cast<uint8_t *>(pMsg), nMsg);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // decode any piggybacked downlink MAC commands if we want to print those
 | 
			
		||||
 | 
			
		||||
@ -3,11 +3,13 @@
 | 
			
		||||
///--> 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
 | 
			
		||||
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
 | 
			
		||||
algorithm in applications without granted license by the patent holder.
 | 
			
		||||
code of this file for timesync option TIME_SYNC_LORASERVER. The shown
 | 
			
		||||
implementation example is covered by the repository's licencse, but you may not
 | 
			
		||||
be eligible to deploy the applied 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.
 | 
			
		||||
You may use timesync option TIME_SYNC_LORAWAN if you do not want or cannot
 | 
			
		||||
accept this.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@ -27,9 +29,7 @@ static const char TAG[] = __FILE__;
 | 
			
		||||
static bool timeSyncPending = false;
 | 
			
		||||
static uint8_t time_sync_seqNo = (uint8_t)random(TIMEREQUEST_MAX_SEQNO),
 | 
			
		||||
               sample_idx;
 | 
			
		||||
static uint16_t timestamp_msec;
 | 
			
		||||
static uint32_t timestamp_sec,
 | 
			
		||||
    timesync_timestamp[TIME_SYNC_SAMPLES][no_of_timestamps];
 | 
			
		||||
static uint32_t timesync_timestamp[TIME_SYNC_SAMPLES][no_of_timestamps];
 | 
			
		||||
static TaskHandle_t timeSyncProcTask = NULL;
 | 
			
		||||
 | 
			
		||||
// create task for timeserver handshake processing, called from main.cpp
 | 
			
		||||
@ -89,31 +89,31 @@ void IRAM_ATTR timesync_processReq(void *taskparameter) {
 | 
			
		||||
 | 
			
		||||
// send timesync request to timeserver or networkserver
 | 
			
		||||
#if (TIME_SYNC_LORASERVER)
 | 
			
		||||
      // timesync option 1: use external timeserver (for LoRAWAN < 1.0.3)
 | 
			
		||||
      // ask timeserver
 | 
			
		||||
      // ask user's timeserver (for LoRAWAN < 1.0.3)
 | 
			
		||||
      payload.reset();
 | 
			
		||||
      payload.addByte(time_sync_seqNo);
 | 
			
		||||
      SendPayload(TIMEPORT, prio_high);
 | 
			
		||||
#elif (TIME_SYNC_LORAWAN)
 | 
			
		||||
      // timesync option 2: use LoRAWAN network time (requires LoRAWAN >= 1.0.3)
 | 
			
		||||
      // ask networkserver
 | 
			
		||||
      // ask network (requires LoRAWAN >= 1.0.3)
 | 
			
		||||
      LMIC_requestNetworkTime(timesync_serverAnswer, &time_sync_seqNo);
 | 
			
		||||
      // open a receive window to immediately get DevTimeAns
 | 
			
		||||
      LMIC_sendAlive();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
      // open a receive window to immediately get the answer (Class A device)
 | 
			
		||||
      LMIC_sendAlive();
 | 
			
		||||
      // LMIC_sendAlive();
 | 
			
		||||
 | 
			
		||||
      // wait until a timestamp was received
 | 
			
		||||
      if (xTaskNotifyWait(0x00, ULONG_MAX, &seqNo,
 | 
			
		||||
                          pdMS_TO_TICKS(TIME_SYNC_TIMEOUT * 1000)) == pdFALSE) {
 | 
			
		||||
        ESP_LOGW(TAG, "[%0.3f] Timesync handshake error: timeout",
 | 
			
		||||
                 millis() / 1000.0);
 | 
			
		||||
        ESP_LOGW(TAG, "[%0.3f] Timesync aborted: timed out", millis() / 1000.0);
 | 
			
		||||
        goto Fail; // no valid sequence received before timeout
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // check if we are in handshake with server
 | 
			
		||||
      if (seqNo != time_sync_seqNo) {
 | 
			
		||||
        ESP_LOGW(TAG, "[%0.3f] Timesync handshake aborted", millis() / 1000.0);
 | 
			
		||||
        ESP_LOGW(TAG, "[%0.3f] Timesync aborted: handshake out of sync",
 | 
			
		||||
                 millis() / 1000.0);
 | 
			
		||||
        goto Fail;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -178,6 +178,7 @@ void timesync_storeReq(uint32_t timestamp, timesync_t timestamp_type) {
 | 
			
		||||
 | 
			
		||||
// callback function to receive network time server answer
 | 
			
		||||
void IRAM_ATTR timesync_serverAnswer(void *pUserData, int flag) {
 | 
			
		||||
 | 
			
		||||
  // if no timesync handshake is pending then exit
 | 
			
		||||
  if (!timeSyncPending)
 | 
			
		||||
    return;
 | 
			
		||||
@ -186,34 +187,30 @@ void IRAM_ATTR timesync_serverAnswer(void *pUserData, int flag) {
 | 
			
		||||
  mask_user_IRQ();
 | 
			
		||||
 | 
			
		||||
  int rc = 0;
 | 
			
		||||
  uint32_t timestamp_sec;
 | 
			
		||||
  uint8_t seqNo = *(uint8_t *)pUserData;
 | 
			
		||||
  uint16_t timestamp_msec;
 | 
			
		||||
  uint32_t timestamp_sec;
 | 
			
		||||
 | 
			
		||||
#if (TIME_SYNC_LORASERVER)
 | 
			
		||||
 | 
			
		||||
  // store LMIC time when we received the timesync answer
 | 
			
		||||
  timesync_storeReq(osticks2ms(os_getTime()), timesync_rx);
 | 
			
		||||
 | 
			
		||||
  // pUserData: contains pointer to payload buffer
 | 
			
		||||
  // flag: length of buffer
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
    parse 6 byte timesync_answer:
 | 
			
		||||
  // store LMIC time when we received the timesync answer
 | 
			
		||||
  timesync_storeReq(osticks2ms(os_getTime()), timesync_rx);
 | 
			
		||||
 | 
			
		||||
    byte    meaning
 | 
			
		||||
    1       sequence number (taken from node's time_sync_req)
 | 
			
		||||
    2..5    current second (from epoch time 1970)
 | 
			
		||||
    6       1/250ths fractions of current second
 | 
			
		||||
    */
 | 
			
		||||
  //  parse timesync_answer:
 | 
			
		||||
  //  byte    meaning
 | 
			
		||||
  //  0       sequence number (taken from node's time_sync_req)
 | 
			
		||||
  //  1..4    current second (from UTC epoch)
 | 
			
		||||
  //  5       1/250ths fractions of current second
 | 
			
		||||
 | 
			
		||||
  // Explicit conversion from void* to uint8_t* to avoid compiler errors
 | 
			
		||||
  uint8_t *p = (uint8_t *)pUserData;
 | 
			
		||||
  // Get payload buffer from pUserData
 | 
			
		||||
  uint8_t *buf = p;
 | 
			
		||||
  // swap byte order from msb to lsb, note: this is a platform dependent hack
 | 
			
		||||
  timestamp_sec = __builtin_bswap32(*(uint32_t *)(pUserData + 1));
 | 
			
		||||
 | 
			
		||||
  // extract 1 byte timerequest sequence number from payload
 | 
			
		||||
  uint8_t seqNo = buf[0];
 | 
			
		||||
  buf++;
 | 
			
		||||
  // one step being 1/250th sec * 1000 = 4msec
 | 
			
		||||
  timestamp_msec = *(uint8_t *)(pUserData + 5);
 | 
			
		||||
  timestamp_msec *= 4;
 | 
			
		||||
 | 
			
		||||
  // if no time is available or spurious buffer then exit
 | 
			
		||||
  if (flag != TIME_SYNC_FRAME_LENGTH) {
 | 
			
		||||
@ -226,29 +223,12 @@ void IRAM_ATTR timesync_serverAnswer(void *pUserData, int flag) {
 | 
			
		||||
    goto Exit; // failure
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // pointer to 4 bytes msb order
 | 
			
		||||
  uint32_t *timestamp_ptr;
 | 
			
		||||
  // extract 4 bytes containing gateway time in UTC seconds since unix
 | 
			
		||||
  // epoch and convert it to uint32_t, octet order is big endian
 | 
			
		||||
  timestamp_ptr = (uint32_t *)buf;
 | 
			
		||||
  // swap byte order from msb to lsb, note: this is a platform dependent hack
 | 
			
		||||
  timestamp_sec = __builtin_bswap32(*timestamp_ptr);
 | 
			
		||||
  buf += 4;
 | 
			
		||||
  // extract 1 byte containing fractional seconds in 2^-8 second steps
 | 
			
		||||
  // one step being 1/250th sec * 1000 = 4msec
 | 
			
		||||
  timestamp_msec = buf[0] * 4;
 | 
			
		||||
 | 
			
		||||
  goto Finish;
 | 
			
		||||
 | 
			
		||||
#elif (TIME_SYNC_LORAWAN)
 | 
			
		||||
 | 
			
		||||
  // pUserData: contains pointer to SeqNo
 | 
			
		||||
  // flagSuccess: indicates if we got a recent time from the network
 | 
			
		||||
 | 
			
		||||
  // Explicit conversion from void* to uint8_t* to avoid compiler errors
 | 
			
		||||
  uint8_t *p = (uint8_t *)pUserData;
 | 
			
		||||
  // Get seqNo from pUserData
 | 
			
		||||
  uint8_t seqNo = *p;
 | 
			
		||||
  // flag: indicates if we got a recent time from the network
 | 
			
		||||
 | 
			
		||||
  if (flag != 1) {
 | 
			
		||||
    ESP_LOGW(TAG, "[%0.3f] Network did not answer time request",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user