diff --git a/include/display.h b/include/display.h index d4a873c2..38d503a9 100644 --- a/include/display.h +++ b/include/display.h @@ -5,7 +5,6 @@ #include "cyclic.h" extern uint8_t DisplayState; -extern timesource_t timeSource; extern HAS_DISPLAY u8x8; diff --git a/include/globals.h b/include/globals.h index 24d34865..72036687 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 @@ -108,8 +108,8 @@ 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 +extern bool volatile TimePulseTick; // 1sec pps flag set by GPS or RTC +extern timesource_t timeSource; 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 e96e2531..62eb1a15 100644 --- a/include/gpsread.h +++ b/include/gpsread.h @@ -9,10 +9,14 @@ #include #endif +#define NMEA_FRAME_SIZE 80 // NEMA has a maxium of 80 bytes per record +#define NMEA_BUFFERTIME 50 // 50ms safety time regardless + extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe extern gpsStatus_t gps_status; // Make struct for storing gps data globally available extern TaskHandle_t GpsTask; +extern TickType_t const gpsDelay_ticks; // time to NMEA arrival int gps_init(void); void gps_read(void); diff --git a/include/irqhandler.h b/include/irqhandler.h index cc8d15ac..64cb12fe 100644 --- a/include/irqhandler.h +++ b/include/irqhandler.h @@ -9,6 +9,7 @@ #include "globals.h" #include "cyclic.h" #include "senddata.h" +#include "timekeeper.h" void irqHandler(void *pvParameters); void IRAM_ATTR homeCycleIRQ(); diff --git a/include/payload.h b/include/payload.h index d8fe468b..159dcfc4 100644 --- a/include/payload.h +++ b/include/payload.h @@ -1,7 +1,8 @@ #ifndef _PAYLOAD_H_ #define _PAYLOAD_H_ -// MyDevices CayenneLPP channels for dynamic sensor payload format +// MyDevices CayenneLPP 1.0 channels for Synamic sensor payload format +// all payload goes out on LoRa FPort 1 #if (PAYLOAD_ENCODER == 3) #define LPP_GPS_CHANNEL 20 @@ -19,7 +20,7 @@ #endif -// MyDevices CayenneLPP types +// MyDevices CayenneLPP 2.0 types for Packed Sensor Payload, not using channels, but different FPorts #define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01m #define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed MSB #define LPP_DIGITAL_INPUT 0 // 1 byte diff --git a/include/timekeeper.h b/include/timekeeper.h index b4afb1b7..ae58df3d 100644 --- a/include/timekeeper.h +++ b/include/timekeeper.h @@ -18,7 +18,7 @@ extern const char timeSetSymbols[]; void IRAM_ATTR CLOCKIRQ(void); void clock_init(void); void clock_loop(void *pvParameters); -time_t time_sync(void); +void timeSync(void); void timepulse_start(void); uint8_t timepulse_init(void); time_t TimeIsValid(time_t const t); diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 3d170eb1..c9341f03 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -5,7 +5,7 @@ #include "cyclic.h" // Local logging tag -static const char TAG[] = "main"; +static const char TAG[] = __FILE__; // do all housekeeping void doHousekeeping() { @@ -17,8 +17,12 @@ void doHousekeeping() { if (cfg.runmode == 1) do_reset(); +#ifdef HAS_SPI spi_housekeeping(); +#endif +#ifdef HAS_LORA lora_housekeeping(); +#endif // task storage debugging // ESP_LOGD(TAG, "IRQhandler %d bytes left | Taskstate = %d", diff --git a/src/dcf77.cpp b/src/dcf77.cpp index be5a1b0b..1c27235e 100644 --- a/src/dcf77.cpp +++ b/src/dcf77.cpp @@ -14,7 +14,7 @@ https://github.com/udoklein/dcf77 #include "dcf77.h" // Local logging tag -static const char TAG[] = "main"; +static const char TAG[] = __FILE__; // triggered by second timepulse to ticker out DCF signal void DCF77_Pulse(time_t t, uint8_t const *DCFpulse) { diff --git a/src/display.cpp b/src/display.cpp index d5e2b382..047c233e 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -46,7 +46,6 @@ const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; uint8_t DisplayState = 0; -timesource_t timeSource = _unsynced; // helper function, prints a hex key on display void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) { diff --git a/src/gpsread.cpp b/src/gpsread.cpp index 2ef5d84d..9c34049d 100644 --- a/src/gpsread.cpp +++ b/src/gpsread.cpp @@ -3,7 +3,7 @@ #include "globals.h" // Local logging tag -static const char TAG[] = "main"; +static const char TAG[] = __FILE__; TinyGPSPlus gps; gpsStatus_t gps_status; @@ -11,6 +11,10 @@ TaskHandle_t GpsTask; #ifdef GPS_SERIAL HardwareSerial GPS_Serial(1); // use UART #1 +TickType_t const gpsDelay_ticks = pdMS_TO_TICKS(1000 - NMEA_BUFFERTIME) - + tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL); +#else +TickType_t const gpsDelay_ticks = pdMS_TO_TICKS(1000 - NMEA_BUFFERTIME); #endif // initialize and configure GPS @@ -23,6 +27,13 @@ int gps_init(void) { return 0; } +// set timeout for reading recent time from GPS +#ifdef GPS_SERIAL // serial GPS + +#else // I2C GPS + +#endif + #if defined GPS_SERIAL GPS_Serial.begin(GPS_SERIAL); ESP_LOGI(TAG, "Using serial GPS"); @@ -76,20 +87,12 @@ 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 + // set time to wait for arrive next recent NMEA time record + static const uint32_t gpsDelay_ms = gpsDelay_ticks / portTICK_PERIOD_MS; time_t t = 0; -// 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())) { + if ((gps.time.age() < gpsDelay_ms) && (gps.time.isValid())) { ESP_LOGD(TAG, "GPS time age: %dms, is valid: %s", gps.time.age(), gps.time.isValid() ? "yes" : "no"); diff --git a/src/if482.cpp b/src/if482.cpp index a0d93182..a532fdaa 100644 --- a/src/if482.cpp +++ b/src/if482.cpp @@ -82,19 +82,19 @@ not evaluated by model BU-190 #include "if482.h" // Local logging tag -static const char TAG[] = "main"; +static const char TAG[] = __FILE__; HardwareSerial IF482(2); // use UART #2 (note: #1 may be in use for serial GPS) -// triggered by timepulse to ticker out DCF signal +// triggered by timepulse to send IF482 signal void IF482_Pulse(time_t t) { static const TickType_t txDelay = pdMS_TO_TICKS(IF482_PULSE_LENGTH - tx_Ticks(IF482_FRAME_SIZE, HAS_IF482)); - TickType_t startTime = xTaskGetTickCount(); - - vTaskDelayUntil(&startTime, txDelay); // wait until moment to fire + //TickType_t startTime = xTaskGetTickCount(); + //vTaskDelayUntil(&startTime, txDelay); // wait until moment to fire + vTaskDelay(txDelay); // wait until moment to fire IF482.print(IF482_Frame(t + 1)); // note: if482 telegram for *next* second } diff --git a/src/irqhandler.cpp b/src/irqhandler.cpp index 3f680702..1236225c 100644 --- a/src/irqhandler.cpp +++ b/src/irqhandler.cpp @@ -1,7 +1,7 @@ #include "irqhandler.h" // Local logging tag -static const char TAG[] = "main"; +static const char TAG[] = __FILE__; // irq handler task, handles all our application level interrupts void irqHandler(void *pvParameters) { @@ -12,11 +12,10 @@ void irqHandler(void *pvParameters) { // task remains in blocked state until it is notified by an irq for (;;) { - xTaskNotifyWait( - 0x00, // Don't clear any bits on entry - ULONG_MAX, // Clear all bits on exit - &InterruptStatus, // Receives the notification value - portMAX_DELAY); // wait forever + xTaskNotifyWait(0x00, // Don't clear any bits on entry + ULONG_MAX, // Clear all bits on exit + &InterruptStatus, // Receives the notification value + portMAX_DELAY); // wait forever // button pressed? #ifdef HAS_BUTTON @@ -31,8 +30,10 @@ void irqHandler(void *pvParameters) { #endif // are cyclic tasks due? - if (InterruptStatus & CYCLIC_IRQ) + if (InterruptStatus & CYCLIC_IRQ) { doHousekeeping(); + timeSync(); + } // is time to send the payload? if (InterruptStatus & SENDCOUNTER_IRQ) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 36ffa3ad..df73da4f 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -358,12 +358,7 @@ void lora_send(osjob_t *job) { lora_send); } -#endif // HAS_LORA - esp_err_t lora_stack_init() { -#ifndef HAS_LORA - return ESP_OK; // continue main program -#else assert(SEND_QUEUE_SIZE); LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t)); if (LoraSendQueue == 0) { @@ -401,12 +396,10 @@ esp_err_t lora_stack_init() { } return ESP_OK; // continue main program -#endif // HAS_LORA } void lora_enqueuedata(MessageBuffer_t *message, sendprio_t prio) { // enqueue message in LORA send queue -#ifdef HAS_LORA BaseType_t ret; switch (prio) { case prio_high: @@ -423,27 +416,26 @@ void lora_enqueuedata(MessageBuffer_t *message, sendprio_t prio) { } else { ESP_LOGW(TAG, "LORA sendqueue is full"); } -#endif } -void lora_queuereset(void) { -#ifdef HAS_LORA - xQueueReset(LoraSendQueue); -#endif -} +void lora_queuereset(void) { xQueueReset(LoraSendQueue); } void lora_housekeeping(void) { -#ifdef HAS_LORA -// ESP_LOGD(TAG, "loraloop %d bytes left", -// uxTaskGetStackHighWaterMark(LoraTask)); -#endif + // ESP_LOGD(TAG, "loraloop %d bytes left", + // uxTaskGetStackHighWaterMark(LoraTask)); } void user_request_network_time_callback(void *pVoidUserUTCTime, int flagSuccess) { -#ifdef HAS_LORA // 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) { @@ -473,11 +465,12 @@ void user_request_network_time_callback(void *pVoidUserUTCTime, // Update system time with time read from the network if (TimeIsValid(*pUserUTCTime)) { - setTime(*pUserUTCTime); + xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)); // wait for pps + setTime(*pUserUTCTime + 1); timeSource = _lora; ESP_LOGI(TAG, "Received recent time from LoRa"); - } - else + } else ESP_LOGI(TAG, "Invalid time received from LoRa"); -#endif // HAS_LORA -} // user_request_network_time_callback \ No newline at end of file +} // user_request_network_time_callback + +#endif // HAS_LORA \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a2a807ab..eb04d063 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,7 +52,7 @@ ESP32 hardware irq timers RTC hardware timer (if present) ================================ - triggers IF482 clock signal + triggers pps 1 sec impulse */ @@ -72,6 +72,7 @@ TaskHandle_t irqHandlerTask, ClockTask; SemaphoreHandle_t I2Caccess, TimePulse; bool volatile TimePulseTick = false; time_t userUTCTime = 0; +timesource_t timeSource = _unsynced; // container holding unique MAC address hashes with Memory Alloctor using PSRAM, // if present @@ -86,7 +87,7 @@ TimeChangeRule mySTD = STANDARD_TIME; Timezone myTZ(myDST, mySTD); // local Tag for logging -static const char TAG[] = "main"; +static const char TAG[] = __FILE__; void setup() { @@ -283,14 +284,14 @@ void setup() { // initialize LoRa #ifdef HAS_LORA strcat_P(features, " LORA"); -#endif assert(lora_stack_init() == ESP_OK); +#endif // initialize SPI #ifdef HAS_SPI strcat_P(features, " SPI"); -#endif assert(spi_init() == ESP_OK); +#endif #ifdef VENDORFILTER strcat_P(features, " OUIFLT"); @@ -361,10 +362,7 @@ void setup() { ESP_LOGI(TAG, "Starting Timekeeper..."); assert(timepulse_init()); // setup timepulse timepulse_start(); -#ifdef TIME_SYNC_INTERVAL - setSyncInterval(TIME_SYNC_INTERVAL * 60); // controls timeStatus() via Time.h - setSyncProvider(time_sync); // is called by Time.h -#endif + timeSync(); // start wifi in monitor mode and start channel rotation timer ESP_LOGI(TAG, "Starting Wifi..."); diff --git a/src/rtctime.cpp b/src/rtctime.cpp index 730d4d98..bea2f277 100644 --- a/src/rtctime.cpp +++ b/src/rtctime.cpp @@ -1,7 +1,7 @@ #include "rtctime.h" // Local logging tag -static const char TAG[] = "main"; +static const char TAG[] = __FILE__; #ifdef HAS_RTC // we have hardware RTC diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index 5a1bcae1..c1a54de1 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -1,57 +1,64 @@ #include "timekeeper.h" // Local logging tag -static const char TAG[] = "main"; +static const char TAG[] = __FILE__; // symbol to display current time source const char timeSetSymbols[] = {'G', 'R', 'L', '?'}; getExternalTime TimeSourcePtr; // pointer to time source function -time_t time_sync() { - // check synchonization of systime, called by cyclic.cpp + +// syncs systime from external time source and sets/reads RTC, called by +// cyclic.cpp +void timeSync(void) { time_t t = 0; #ifdef HAS_GPS - 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 + // do we have a valid GPS time? + if (get_gpstime()) { // then let's sync GPS time on top of second + + xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)); // wait for pps + vTaskDelay(gpsDelay_ticks); + t = get_gpstime(); // fetch time from recent NEMA record + if (t) { + t++; // gps time concerns past second, so we add one + xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)); // wait for pps + setTime(t); #ifdef HAS_RTC - set_rtctime(t); // calibrate RTC + set_rtctime(t); // calibrate RTC #endif - timeSource = _gps; - goto exit; - } + timeSource = _gps; + goto exit; + } + } #endif // no GPS -> fallback to RTC time while trying lora sync #ifdef HAS_RTC - t = get_rtctime(); - if (t) - timeSource = _rtc; - else - ESP_LOGW(TAG, "no confident RTC time"); + t = get_rtctime(); + if (t) { + setTime(t); + timeSource = _rtc; + } else + ESP_LOGW(TAG, "no confident RTC time"); #endif // try lora sync if we have #if defined HAS_LORA && defined TIME_SYNC_LORA - LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime); + LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime); #endif 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; + 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; -} // time_sync() +} // timeSync() // helper function to setup a pulse per second for time synchronisation uint8_t timepulse_init() { @@ -119,8 +126,6 @@ void IRAM_ATTR CLOCKIRQ(void) { // helper function to check plausibility of a time 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() ? t : 0); }