New 5-byte time sync protocol
This commit is contained in:
parent
11f184e67a
commit
dd661254b5
@ -7,11 +7,11 @@
|
|||||||
#include "timekeeper.h"
|
#include "timekeeper.h"
|
||||||
|
|
||||||
//#define TIME_SYNC_TRIGGER 100 // threshold for time sync [milliseconds]
|
//#define TIME_SYNC_TRIGGER 100 // threshold for time sync [milliseconds]
|
||||||
#define TIME_SYNC_FRAME_LENGTH 0x06 // timeserver answer frame length [bytes]
|
#define TIME_SYNC_FRAME_LENGTH 0x05 // timeserver answer frame length [bytes]
|
||||||
#define TIME_SYNC_FIXUP 6 // calibration to fixup processing time [milliseconds]
|
#define TIME_SYNC_FIXUP 6 // calibration to fixup processing time [milliseconds]
|
||||||
|
|
||||||
void send_timesync_req(void);
|
void send_timesync_req(void);
|
||||||
int recv_timesync_ans(uint8_t buf[], uint8_t buf_len);
|
int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len);
|
||||||
void process_timesync_req(void *taskparameter);
|
void process_timesync_req(void *taskparameter);
|
||||||
void store_time_sync_req(uint32_t t_millisec);
|
void store_time_sync_req(uint32_t t_millisec);
|
||||||
void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec);
|
void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec);
|
||||||
|
File diff suppressed because one or more lines are too long
@ -256,16 +256,24 @@ void onEvent(ev_t ev) {
|
|||||||
sprintf(display_line6, "RSSI %d SNR %d", LMIC.rssi, LMIC.snr / 4);
|
sprintf(display_line6, "RSSI %d SNR %d", LMIC.rssi, LMIC.snr / 4);
|
||||||
|
|
||||||
if (LMIC.txrxFlags & TXRX_PORT) { // FPort -> use to switch
|
if (LMIC.txrxFlags & TXRX_PORT) { // FPort -> use to switch
|
||||||
|
|
||||||
switch (LMIC.frame[LMIC.dataBeg - 1]) {
|
switch (LMIC.frame[LMIC.dataBeg - 1]) {
|
||||||
#if (TIME_SYNC_LORASERVER)
|
|
||||||
case TIMEPORT: // timesync answer -> call timesync processor
|
|
||||||
recv_timesync_ans(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case RCMDPORT: // opcode -> call rcommand interpreter
|
case RCMDPORT: // opcode -> call rcommand interpreter
|
||||||
rcommand(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
|
rcommand(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // unknown port -> display info
|
default: // unknown port -> display info
|
||||||
|
|
||||||
|
#if (TIME_SYNC_LORASERVER)
|
||||||
|
// timesync answer -> call timesync processor
|
||||||
|
if ((LMIC.frame[LMIC.dataBeg - 1] >= TIMEANSWERPORT_MIN) &&
|
||||||
|
(LMIC.frame[LMIC.dataBeg - 1] <= TIMEANSWERPORT_MAX)) {
|
||||||
|
recv_timesync_ans(LMIC.frame[LMIC.dataBeg - 1],
|
||||||
|
LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ESP_LOGI(TAG, "Received data on unsupported port #%d",
|
ESP_LOGI(TAG, "Received data on unsupported port #%d",
|
||||||
LMIC.frame[LMIC.dataBeg - 1]);
|
LMIC.frame[LMIC.dataBeg - 1]);
|
||||||
break;
|
break;
|
||||||
|
@ -91,7 +91,9 @@
|
|||||||
#define BEACONPORT 6 // beacon alarms
|
#define BEACONPORT 6 // beacon alarms
|
||||||
#define BMEPORT 7 // BME680 sensor
|
#define BMEPORT 7 // BME680 sensor
|
||||||
#define BATTPORT 8 // battery voltage
|
#define BATTPORT 8 // battery voltage
|
||||||
#define TIMEPORT 9 // time
|
#define TIMEPORT 9 // time query
|
||||||
|
#define TIMEANSWERPORT_MIN 0xA0 // time answer, start of port range
|
||||||
|
#define TIMEANSWERPORT_MAX 0xDF // time answer, end of port range
|
||||||
#define SENSOR1PORT 10 // user sensor #1
|
#define SENSOR1PORT 10 // user sensor #1
|
||||||
#define SENSOR2PORT 11 // user sensor #2
|
#define SENSOR2PORT 11 // user sensor #2
|
||||||
#define SENSOR3PORT 12 // user sensor #3
|
#define SENSOR3PORT 12 // user sensor #3
|
||||||
|
@ -20,7 +20,7 @@ static const char TAG[] = __FILE__;
|
|||||||
|
|
||||||
TaskHandle_t timeSyncReqTask;
|
TaskHandle_t timeSyncReqTask;
|
||||||
|
|
||||||
static uint8_t time_sync_seqNo = 0;
|
static uint8_t time_sync_seqNo = TIMEANSWERPORT_MIN;
|
||||||
static bool lora_time_sync_pending = false;
|
static bool lora_time_sync_pending = false;
|
||||||
|
|
||||||
typedef std::chrono::system_clock myClock;
|
typedef std::chrono::system_clock myClock;
|
||||||
@ -75,9 +75,6 @@ void process_timesync_req(void *taskparameter) {
|
|||||||
// enqueue timestamp samples in lora sendqueue
|
// enqueue timestamp samples in lora sendqueue
|
||||||
for (uint8_t i = 0; i < TIME_SYNC_SAMPLES; i++) {
|
for (uint8_t i = 0; i < TIME_SYNC_SAMPLES; i++) {
|
||||||
|
|
||||||
// wrap around seqNo 0 .. 254
|
|
||||||
time_sync_seqNo = (time_sync_seqNo < 255) ? time_sync_seqNo + 1 : 0;
|
|
||||||
|
|
||||||
// send sync request to server
|
// send sync request to server
|
||||||
payload.reset();
|
payload.reset();
|
||||||
payload.addByte(time_sync_seqNo);
|
payload.addByte(time_sync_seqNo);
|
||||||
@ -96,6 +93,11 @@ void process_timesync_req(void *taskparameter) {
|
|||||||
time_offset_ms += time_point_cast<milliseconds>(time_sync_rx[k]) -
|
time_offset_ms += time_point_cast<milliseconds>(time_sync_rx[k]) -
|
||||||
time_point_cast<milliseconds>(time_sync_tx[k]);
|
time_point_cast<milliseconds>(time_sync_tx[k]);
|
||||||
|
|
||||||
|
// wrap around seqNo keeping it in time port range
|
||||||
|
time_sync_seqNo = (time_sync_seqNo < TIMEANSWERPORT_MAX)
|
||||||
|
? time_sync_seqNo + 1
|
||||||
|
: TIMEANSWERPORT_MIN;
|
||||||
|
|
||||||
if (i < TIME_SYNC_SAMPLES - 1) {
|
if (i < TIME_SYNC_SAMPLES - 1) {
|
||||||
// wait until next cycle
|
// wait until next cycle
|
||||||
vTaskDelay(pdMS_TO_TICKS(TIME_SYNC_CYCLE * 1000));
|
vTaskDelay(pdMS_TO_TICKS(TIME_SYNC_CYCLE * 1000));
|
||||||
@ -149,19 +151,21 @@ error:
|
|||||||
// called from lorawan.cpp after time_sync_req was sent
|
// called from lorawan.cpp after time_sync_req was sent
|
||||||
void store_time_sync_req(uint32_t timestamp) {
|
void store_time_sync_req(uint32_t timestamp) {
|
||||||
|
|
||||||
uint8_t k = time_sync_seqNo % TIME_SYNC_SAMPLES;
|
if (lora_time_sync_pending) {
|
||||||
|
|
||||||
time_sync_tx[k] += milliseconds(timestamp);
|
uint8_t k = time_sync_seqNo % TIME_SYNC_SAMPLES;
|
||||||
|
time_sync_tx[k] += milliseconds(timestamp);
|
||||||
|
|
||||||
ESP_LOGD(TAG, "[%0.3f] Timesync request #%d sent at %d.%03d",
|
ESP_LOGD(TAG, "[%0.3f] Timesync request #%d sent at %d.%03d",
|
||||||
millis() / 1000.0, time_sync_seqNo, timestamp / 1000,
|
millis() / 1000.0, time_sync_seqNo, timestamp / 1000,
|
||||||
timestamp % 1000);
|
timestamp % 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// process timeserver timestamp answer, called from lorawan.cpp
|
// process timeserver timestamp answer, called from lorawan.cpp
|
||||||
int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) {
|
int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len) {
|
||||||
|
|
||||||
// if no timesync handshake is pending or spurious buffer then exit
|
// if no timesync handshake is pending then exit
|
||||||
if (!lora_time_sync_pending)
|
if (!lora_time_sync_pending)
|
||||||
return 0; // failure
|
return 0; // failure
|
||||||
|
|
||||||
@ -178,18 +182,18 @@ int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) {
|
|||||||
|
|
||||||
else { // we received a probably valid time frame
|
else { // we received a probably valid time frame
|
||||||
|
|
||||||
uint8_t seq_no = buf[0], k = seq_no % TIME_SYNC_SAMPLES;
|
uint8_t k = seq_no % TIME_SYNC_SAMPLES;
|
||||||
uint16_t timestamp_msec; // convert 1/250th sec fractions to ms
|
uint16_t timestamp_msec; // convert 1/250th sec fractions to ms
|
||||||
uint32_t timestamp_sec;
|
uint32_t timestamp_sec;
|
||||||
|
|
||||||
// fetch timeserver time from 4 bytes containing the UTC seconds since
|
// fetch timeserver time from 4 bytes containing the UTC seconds since
|
||||||
// unix epoch. Octet order is big endian. Casts are necessary, because buf
|
// unix epoch. Octet order is big endian. Casts are necessary, because buf
|
||||||
// is an array of single byte values, and they might overflow when shifted
|
// is an array of single byte values, and they might overflow when shifted
|
||||||
timestamp_sec = ((uint32_t)buf[4]) | (((uint32_t)buf[3]) << 8) |
|
timestamp_sec = ((uint32_t)buf[3]) | (((uint32_t)buf[2]) << 8) |
|
||||||
(((uint32_t)buf[2]) << 16) | (((uint32_t)buf[1]) << 24);
|
(((uint32_t)buf[1]) << 16) | (((uint32_t)buf[0]) << 24);
|
||||||
|
|
||||||
// the 5th byte contains the fractional seconds in 2^-8 second steps
|
// the 5th byte contains the fractional seconds in 2^-8 second steps
|
||||||
timestamp_msec = 4 * buf[5];
|
timestamp_msec = 4 * buf[4];
|
||||||
|
|
||||||
// construct the timepoint when message was seen on gateway
|
// construct the timepoint when message was seen on gateway
|
||||||
time_sync_rx[k] += seconds(timestamp_sec) + milliseconds(timestamp_msec);
|
time_sync_rx[k] += seconds(timestamp_sec) + milliseconds(timestamp_msec);
|
||||||
|
Loading…
Reference in New Issue
Block a user