diff --git a/include/globals.h b/include/globals.h index 5805af63..24d34865 100644 --- a/include/globals.h +++ b/include/globals.h @@ -41,13 +41,13 @@ #define SCREEN_MODE (0x80) // I2C bus access control -#define I2C_MUTEX_LOCK() \ - xSemaphoreTake(I2Caccess, (3 * DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) == \ - pdTRUE +#define I2C_MUTEX_LOCK() +xSemaphoreTake(I2Caccess, + (3 * DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) == pdTRUE #define I2C_MUTEX_UNLOCK() xSemaphoreGive(I2Caccess) -// Struct holding devices's runtime configuration -typedef struct { + // Struct holding devices's runtime configuration + typedef struct { uint8_t lorasf; // 7-12, lora spreadfactor uint8_t txpower; // 2-15, lora tx power uint8_t adrmode; // 0=disabled, 1=enabled @@ -107,8 +107,9 @@ extern configData_t cfg; // current device configuration extern char display_line6[], display_line7[]; // screen buffers extern uint8_t volatile channel; // wifi channel rotation counter extern uint16_t volatile macs_total, macs_wifi, macs_ble, - batt_voltage; // display values -extern bool volatile TimePulseTick; // one-pulse-per-second flags set by GPS or RTC + batt_voltage; // display values +extern bool volatile TimePulseTick; // one-pulse-per-second flags set by GPS or + // RTC extern hw_timer_t *sendCycle, *displaytimer, *clockCycle; extern SemaphoreHandle_t I2Caccess, TimePulse; extern TaskHandle_t irqHandlerTask, ClockTask; diff --git a/include/gpsread.h b/include/gpsread.h index e11c2644..e96e2531 100644 --- a/include/gpsread.h +++ b/include/gpsread.h @@ -3,6 +3,7 @@ #include // library for parsing NMEA data #include +#include "timekeeper.h" #ifdef GPS_I2C // Needed for reading from I2C Bus #include diff --git a/include/if482.h b/include/if482.h index db09eb35..d31f5d59 100644 --- a/include/if482.h +++ b/include/if482.h @@ -2,15 +2,14 @@ #define _IF482_H #include "globals.h" +#include "timekeeper.h" #define IF482_FRAME_SIZE (17) #define IF482_PULSE_LENGTH (1000) -extern HardwareSerial IF482; +extern HardwareSerial IF482; void IF482_Pulse(time_t t); String IRAM_ATTR IF482_Frame(time_t tt); -TickType_t tx_Ticks(unsigned long baud, uint32_t config, int8_t rxPin, - int8_t txPins); #endif \ No newline at end of file diff --git a/include/timekeeper.h b/include/timekeeper.h index 198d8987..b4afb1b7 100644 --- a/include/timekeeper.h +++ b/include/timekeeper.h @@ -20,12 +20,13 @@ void clock_init(void); void clock_loop(void *pvParameters); time_t time_sync(void); void timepulse_start(void); -time_t syncTime(getExternalTime getTimeFunction, timesource_t const caller); uint8_t timepulse_init(void); -uint8_t TimeIsValid(time_t const t); +time_t TimeIsValid(time_t const t); time_t syncProvider_CB(void); time_t compiledUTC(void); time_t tmConvert(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh, uint8_t mm, uint8_t ss); +TickType_t tx_Ticks(uint32_t framesize, unsigned long baud, uint32_t config, + int8_t rxPin, int8_t txPins); #endif // _timekeeper_H \ No newline at end of file diff --git a/src/gpsread.cpp b/src/gpsread.cpp index 514499f5..2ef5d84d 100644 --- a/src/gpsread.cpp +++ b/src/gpsread.cpp @@ -75,22 +75,29 @@ void gps_read() { // function to fetch current time from gps time_t get_gpstime(void) { + +#define NMEA_FRAME_SIZE 80 // NEMA has a maxium of 80 bytes per record +#define NMEA_BUFFER 50 // 50ms safety time regardless + time_t t = 0; - if ((gps.time.age() < 950) && (gps.time.isValid())) { +// set timeout for reading recent time from GPS +#ifdef GPS_SERIAL // serial GPS + static const TickType_t txDelay = + pdMS_TO_TICKS(1000 - NMEA_BUFFER - tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL)); +#else // I2C GPS + static const TickType_t txDelay = 1000 - NMEA_BUFFER; +#endif + + if ((gps.time.age() < txDelay) && (gps.time.isValid())) { ESP_LOGD(TAG, "GPS time age: %dms, is valid: %s", gps.time.age(), gps.time.isValid() ? "yes" : "no"); - // use recent gps time t = tmConvert(gps.date.year(), gps.date.month(), gps.date.day(), gps.time.hour(), gps.time.minute(), gps.time.second()); - - // ESP_LOGD(TAG, "GPS time: %02d.%02d.%04d %02d:%02d:%02d", gps.date.day(), - // gps.date.month(), gps.date.year(), gps.time.hour(), - // gps.time.minute(), gps.time.second()); } - return t; + return TimeIsValid(t); } // get_gpstime() // GPS serial feed FreeRTos Task diff --git a/src/if482.cpp b/src/if482.cpp index 9f21f7ac..a0d93182 100644 --- a/src/if482.cpp +++ b/src/if482.cpp @@ -90,7 +90,7 @@ HardwareSerial IF482(2); // use UART #2 (note: #1 may be in use for serial GPS) void IF482_Pulse(time_t t) { static const TickType_t txDelay = - pdMS_TO_TICKS(IF482_PULSE_LENGTH) - tx_Ticks(HAS_IF482); + pdMS_TO_TICKS(IF482_PULSE_LENGTH - tx_Ticks(IF482_FRAME_SIZE, HAS_IF482)); TickType_t startTime = xTaskGetTickCount(); @@ -124,17 +124,4 @@ String IRAM_ATTR IF482_Frame(time_t startTime) { return out; } -// calculate serial tx time from IF482 serial settings -TickType_t tx_Ticks(unsigned long baud, uint32_t config, int8_t rxPin, - int8_t txPins) { - - uint32_t databits = ((config & 0x0c) >> 2) + 5; - uint32_t stopbits = ((config & 0x20) >> 5) + 1; - uint32_t txTime = - (databits + stopbits + 2) * IF482_FRAME_SIZE * 1000.0 / baud; - // +2 ms margin for the startbit and the clock's processing time - - return pdMS_TO_TICKS(round(txTime)); -} - #endif // HAS_IF482 \ No newline at end of file diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 02503aba..36ffa3ad 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -474,6 +474,7 @@ void user_request_network_time_callback(void *pVoidUserUTCTime, // Update system time with time read from the network if (TimeIsValid(*pUserUTCTime)) { setTime(*pUserUTCTime); + timeSource = _lora; ESP_LOGI(TAG, "Received recent time from LoRa"); } else diff --git a/src/rtctime.cpp b/src/rtctime.cpp index ff542318..730d4d98 100644 --- a/src/rtctime.cpp +++ b/src/rtctime.cpp @@ -67,7 +67,7 @@ time_t get_rtctime(void) { } I2C_MUTEX_UNLOCK(); } - return t; + return TimeIsValid(t); } // get_rtctime() float get_rtctemp(void) { diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index 712fd09b..5a1bcae1 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -13,18 +13,26 @@ time_t time_sync() { time_t t = 0; -#ifdef TIME_SYNC_INTERVAL - #ifdef HAS_GPS - t = syncTime(get_gpstime, _gps); - if (t) - return t; // attempt sync with GPS time + xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)); // wait for pps + ESP_LOGD(TAG, "micros = %d", micros()); + t = get_gpstime(); + if (t) { + t++; // gps time concerns past second, so we add one second +#ifdef HAS_RTC + set_rtctime(t); // calibrate RTC +#endif + timeSource = _gps; + goto exit; + } #endif // no GPS -> fallback to RTC time while trying lora sync #ifdef HAS_RTC - t = syncTime(get_rtctime, _rtc); // sync with RTC time - if (!t) + t = get_rtctime(); + if (t) + timeSource = _rtc; + else ESP_LOGW(TAG, "no confident RTC time"); #endif @@ -33,45 +41,18 @@ time_t time_sync() { LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime); #endif -#endif // TIME_SYNC_INTERVAL +exit: + ESP_LOGD(TAG, "micros = %d", micros()); + if (t) + ESP_LOGD(TAG, "Time was set by %c to %02d:%02d:%02d", + timeSetSymbols[timeSource], hour(t), minute(t), second(t)); + else + timeSource = _unsynced; return t; + } // time_sync() -// sync time on start of next second from GPS or RTC -time_t syncTime(getExternalTime getTimeFunction, timesource_t const caller) { - - time_t t; - TimeSourcePtr = getTimeFunction; - if (!TimeSourcePtr) - goto error; - - xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)); // wait for pps - - t = TimeSourcePtr(); // get time from given timesource - - if (TimeIsValid(t)) { - if (caller == _gps) // gps time concerns past second - t++; - timeSource = caller; - ESP_LOGD(TAG, "Time source %c set time to %02d:%02d:%02d", - timeSetSymbols[timeSource], hour(t), minute(t), second(t)); - -#ifdef HAS_RTC - if (caller != _rtc) - set_rtctime(t); -#endif - - return t; // success - } - -error: - ESP_LOGD(TAG, "Time source %c sync attempt failed", timeSetSymbols[caller]); - timeSource = _unsynced; - return 0; // failure - -} // syncTime() - // helper function to setup a pulse per second for time synchronisation uint8_t timepulse_init() { @@ -136,11 +117,11 @@ void IRAM_ATTR CLOCKIRQ(void) { } // helper function to check plausibility of a time -uint8_t TimeIsValid(time_t const t) { +time_t TimeIsValid(time_t const t) { // is it a time in the past? we use compile date to guess ESP_LOGD(TAG, "t=%d, tt=%d, valid: %s", t, compiledUTC(), (t >= compiledUTC()) ? "yes" : "no"); - return (t >= compiledUTC()); + return (t >= compiledUTC() ? t : 0); } // helper function to convert compile time to UTC time @@ -162,6 +143,18 @@ time_t tmConvert(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh, uint8_t mm, return makeTime(tm); } +// helper function to calculate serial transmit time +TickType_t tx_Ticks(uint32_t framesize, unsigned long baud, uint32_t config, + int8_t rxPin, int8_t txPins) { + + uint32_t databits = ((config & 0x0c) >> 2) + 5; + uint32_t stopbits = ((config & 0x20) >> 5) + 1; + uint32_t txTime = (databits + stopbits + 2) * framesize * 1000.0 / baud; + // +1 ms margin for the startbit +1 ms for pending processing time + + return round(txTime); +} + #if defined HAS_IF482 || defined HAS_DCF77 #if defined HAS_DCF77 && defined HAS_IF482