timemanager reworked
This commit is contained in:
		
							parent
							
								
									feda8dd938
								
							
						
					
					
						commit
						98797c0fe1
					
				| @ -5,7 +5,7 @@ | |||||||
| #include "senddata.h" | #include "senddata.h" | ||||||
| #include "rcommand.h" | #include "rcommand.h" | ||||||
| #include "spislave.h" | #include "spislave.h" | ||||||
| #include "timemanager.h" | #include "timekeeper.h" | ||||||
| #include <lmic.h> | #include <lmic.h> | ||||||
| 
 | 
 | ||||||
| #ifdef HAS_BME | #ifdef HAS_BME | ||||||
|  | |||||||
| @ -108,13 +108,12 @@ extern uint8_t volatile channel;              // wifi channel rotation counter | |||||||
| extern uint16_t volatile macs_total, macs_wifi, macs_ble, | extern uint16_t volatile macs_total, macs_wifi, macs_ble, | ||||||
|     batt_voltage; // display values
 |     batt_voltage; // display values
 | ||||||
| extern bool volatile TimePulseTick; // one-pulse-per-second flags set by GPS or RTC
 | extern bool volatile TimePulseTick; // one-pulse-per-second flags set by GPS or RTC
 | ||||||
| extern bool TimeIsSynced; |  | ||||||
| extern hw_timer_t *sendCycle, *displaytimer, *clockCycle; | extern hw_timer_t *sendCycle, *displaytimer, *clockCycle; | ||||||
| extern SemaphoreHandle_t I2Caccess, TimePulse; | extern SemaphoreHandle_t I2Caccess, TimePulse; | ||||||
| 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 lastSyncTime, userUTCTime; | extern time_t userUTCTime; | ||||||
| 
 | 
 | ||||||
| // application includes
 | // application includes
 | ||||||
| #include "led.h" | #include "led.h" | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "globals.h" | #include "globals.h" | ||||||
| #include "rcommand.h" | #include "rcommand.h" | ||||||
|  | #include "timekeeper.h" | ||||||
| 
 | 
 | ||||||
| // LMIC-Arduino LoRaWAN Stack
 | // LMIC-Arduino LoRaWAN Stack
 | ||||||
| #include <lmic.h> | #include <lmic.h> | ||||||
| @ -10,7 +11,6 @@ | |||||||
| #include <SPI.h> | #include <SPI.h> | ||||||
| #include <arduino_lmic_hal_boards.h> | #include <arduino_lmic_hal_boards.h> | ||||||
| #include "loraconf.h" | #include "loraconf.h" | ||||||
| #include "rtctime.h" |  | ||||||
| 
 | 
 | ||||||
| // Needed for 24AA02E64, does not hurt anything if included and not used
 | // Needed for 24AA02E64, does not hurt anything if included and not used
 | ||||||
| #ifdef MCP_24AA02E64_I2C_ADDRESS | #ifdef MCP_24AA02E64_I2C_ADDRESS | ||||||
|  | |||||||
| @ -17,5 +17,5 @@ | |||||||
| #include "led.h" | #include "led.h" | ||||||
| #include "spislave.h" | #include "spislave.h" | ||||||
| #include "lorawan.h" | #include "lorawan.h" | ||||||
| #include "timemanager.h" | #include "timekeeper.h" | ||||||
| #endif | #endif | ||||||
| @ -2,7 +2,7 @@ | |||||||
| #define _RTCTIME_H | #define _RTCTIME_H | ||||||
| 
 | 
 | ||||||
| #include "globals.h" | #include "globals.h" | ||||||
| #include "timemanager.h" | #include "timekeeper.h" | ||||||
| #include <Wire.h> // must be included here so that Arduino library object file references work | #include <Wire.h> // must be included here so that Arduino library object file references work | ||||||
| #include <RtcDS3231.h> | #include <RtcDS3231.h> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #ifndef _timemanager_H | #ifndef _timekeeper_H | ||||||
| #define _timemanager_H | #define _timekeeper_H | ||||||
| 
 | 
 | ||||||
| #include "globals.h" | #include "globals.h" | ||||||
| #include "rtctime.h" | #include "rtctime.h" | ||||||
| @ -15,17 +15,17 @@ | |||||||
| 
 | 
 | ||||||
| enum timesources { pps, rtc, lora, unsynced }; | enum timesources { pps, rtc, lora, unsynced }; | ||||||
| 
 | 
 | ||||||
|  | void IRAM_ATTR CLOCKIRQ(void); | ||||||
| void clock_init(void); | void clock_init(void); | ||||||
| void clock_loop(void *pvParameters); | void clock_loop(void *pvParameters); | ||||||
| void time_sync(void); | void time_sync(void); | ||||||
| int wait_for_pulse(void); |  | ||||||
| int syncTime(time_t const t, uint8_t const timesource); |  | ||||||
| void IRAM_ATTR CLOCKIRQ(void); |  | ||||||
| int timepulse_init(void); |  | ||||||
| void timepulse_start(void); | void timepulse_start(void); | ||||||
| int TimeIsValid(time_t const t); | uint8_t wait_for_pulse(void); | ||||||
|  | uint8_t syncTime(time_t const t, uint8_t const caller); | ||||||
|  | uint8_t timepulse_init(void); | ||||||
|  | uint8_t TimeIsValid(time_t const t); | ||||||
| time_t compiledUTC(void); | time_t compiledUTC(void); | ||||||
| time_t tmConvert(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh, | time_t tmConvert(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh, | ||||||
|                    uint8_t mm, uint8_t ss); |                    uint8_t mm, uint8_t ss); | ||||||
| 
 | 
 | ||||||
| #endif // _timemanager_H
 | #endif // _timekeeper_H
 | ||||||
| @ -131,8 +131,7 @@ void init_display(const char *Productname, const char *Version) { | |||||||
| void refreshtheDisplay() { | void refreshtheDisplay() { | ||||||
| 
 | 
 | ||||||
|   uint8_t msgWaiting; |   uint8_t msgWaiting; | ||||||
|   char timeIsSet, timeState; |   char timeState, buff[16]; | ||||||
|   char buff[16]; // 16 chars line buffer
 |  | ||||||
|   time_t t; |   time_t t; | ||||||
| 
 | 
 | ||||||
|   // block i2c bus access
 |   // block i2c bus access
 | ||||||
| @ -218,8 +217,7 @@ void refreshtheDisplay() { | |||||||
|     u8x8.printf("%-16s", display_line6); |     u8x8.printf("%-16s", display_line6); | ||||||
| #else // we want a systime display instead LoRa status
 | #else // we want a systime display instead LoRa status
 | ||||||
|     t = myTZ.toLocal(now()); |     t = myTZ.toLocal(now()); | ||||||
|     timeIsSet = (timeStatus() == timeNotSet) ? '#' : timeSource; |     timeState = TimePulseTick ? ' ' : timeSource; | ||||||
|     timeState = TimePulseTick ? ' ' : timeIsSet; |  | ||||||
|     TimePulseTick = false; |     TimePulseTick = false; | ||||||
|     u8x8.printf("%02d:%02d:%02d%c %2d.%3s", hour(t), minute(t), second(t), |     u8x8.printf("%02d:%02d:%02d%c %2d.%3s", hour(t), minute(t), second(t), | ||||||
|                 timeState, day(t), printmonth[month(t)]); |                 timeState, day(t), printmonth[month(t)]); | ||||||
|  | |||||||
| @ -473,10 +473,6 @@ void user_request_network_time_callback(void *pVoidUserUTCTime, | |||||||
| 
 | 
 | ||||||
|   // Update system time with time read from the network
 |   // Update system time with time read from the network
 | ||||||
|   if (syncTime(*pUserUTCTime, lora)) { // have we got a valid time?
 |   if (syncTime(*pUserUTCTime, lora)) { // have we got a valid time?
 | ||||||
| #ifdef HAS_RTC |  | ||||||
|     if (TimeIsSynced) |  | ||||||
|       set_rtctime(now()); // UTC time
 |  | ||||||
| #endif |  | ||||||
|     ESP_LOGI(TAG, "LORA has set the system time"); |     ESP_LOGI(TAG, "LORA has set the system time"); | ||||||
|   } else |   } else | ||||||
|     ESP_LOGI(TAG, "Unable to sync system time with LORA"); |     ESP_LOGI(TAG, "Unable to sync system time with LORA"); | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/main.cpp
									
									
									
									
									
								
							| @ -71,8 +71,7 @@ hw_timer_t *sendCycle = NULL, *homeCycle = NULL, *clockCycle = NULL, | |||||||
| TaskHandle_t irqHandlerTask, ClockTask; | TaskHandle_t irqHandlerTask, ClockTask; | ||||||
| SemaphoreHandle_t I2Caccess, TimePulse; | SemaphoreHandle_t I2Caccess, TimePulse; | ||||||
| bool volatile TimePulseTick = false; | bool volatile TimePulseTick = false; | ||||||
| bool TimeIsSynced = false; | time_t userUTCTime = 0; | ||||||
| time_t lastSyncTime = 0, userUTCTime = 0; |  | ||||||
| 
 | 
 | ||||||
| // container holding unique MAC address hashes with Memory Alloctor using PSRAM,
 | // container holding unique MAC address hashes with Memory Alloctor using PSRAM,
 | ||||||
| // if present
 | // if present
 | ||||||
| @ -358,13 +357,12 @@ void setup() { | |||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|   // start pps timepulse
 |   // start pps timepulse and timekeepr
 | ||||||
|   ESP_LOGI(TAG, "Starting Timepulse..."); |   ESP_LOGI(TAG, "Starting Timekeeper..."); | ||||||
|   if (timepulse_init()) // setup timepulse
 |   assert(timepulse_init()); // setup timepulse
 | ||||||
|     timepulse_start();  // start pulse
 |   timepulse_start(); | ||||||
|   else |   time_sync();                              // sync time
 | ||||||
|     ESP_LOGE(TAG, "No timepulse, time will not be synced!"); |   setSyncInterval(TIME_SYNC_INTERVAL * 60); // controls timeStatus()
 | ||||||
|   time_sync(); |  | ||||||
| 
 | 
 | ||||||
|   // start wifi in monitor mode and start channel rotation timer
 |   // start wifi in monitor mode and start channel rotation timer
 | ||||||
|   ESP_LOGI(TAG, "Starting Wifi..."); |   ESP_LOGI(TAG, "Starting Wifi..."); | ||||||
|  | |||||||
| @ -81,10 +81,9 @@ | |||||||
| #define OTA_MIN_BATT                    3600    // minimum battery level for OTA [millivolt] | #define OTA_MIN_BATT                    3600    // minimum battery level for OTA [millivolt] | ||||||
| #define RESPONSE_TIMEOUT_MS             60000   // firmware binary server connection timeout [milliseconds] | #define RESPONSE_TIMEOUT_MS             60000   // firmware binary server connection timeout [milliseconds] | ||||||
| 
 | 
 | ||||||
| // settings for syncing time of node and external time sources | // settings for syncing time of node with external time source | ||||||
| #define TIME_SYNC_INTERVAL              10       // sync time each .. minutes from external time source (GPS/LORA) [default = 10], comment out means off           | #define TIME_SYNC_INTERVAL              10       // sync time each .. minutes from time source (GPS/LORA) [default = 10], comment out means off           | ||||||
| #define TIME_SYNC_TIMEOUT               30       // fallback to rtc for timesync after .. minutes no sync with external time source | #define TIME_SYNC_LORA                1        // use LORA network as time source, comment out means off [default = off] | ||||||
| #define TIME_SYNC_LORA                1        // use LORA network for timesync, comment out means off [default = off] |  | ||||||
| 
 | 
 | ||||||
| // time zone, see https://github.com/JChristensen/Timezone/blob/master/examples/WorldClock/WorldClock.ino | // time zone, see https://github.com/JChristensen/Timezone/blob/master/examples/WorldClock/WorldClock.ino | ||||||
| #define DAYLIGHT_TIME                   {"CEST", Last, Sun, Mar, 2, 120}     // Central European Summer Time | #define DAYLIGHT_TIME                   {"CEST", Last, Sun, Mar, 2, 120}     // Central European Summer Time | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ int rtc_init(void) { | |||||||
|       Rtc.SetIsRunning(true); |       Rtc.SetIsRunning(true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /*
 | ||||||
|         RtcDateTime tt = Rtc.GetDateTime(); |         RtcDateTime tt = Rtc.GetDateTime(); | ||||||
|         time_t t = tt.Epoch32Time(); // sec2000 -> epoch
 |         time_t t = tt.Epoch32Time(); // sec2000 -> epoch
 | ||||||
| 
 | 
 | ||||||
| @ -32,6 +33,7 @@ int rtc_init(void) { | |||||||
|           Rtc.SetDateTime( |           Rtc.SetDateTime( | ||||||
|               RtcDateTime(compiledUTC() - SECS_YR_2000)); // epoch -> sec2000
 |               RtcDateTime(compiledUTC() - SECS_YR_2000)); // epoch -> sec2000
 | ||||||
|         } |         } | ||||||
|  |     */ | ||||||
| 
 | 
 | ||||||
|     I2C_MUTEX_UNLOCK(); // release i2c bus access
 |     I2C_MUTEX_UNLOCK(); // release i2c bus access
 | ||||||
|     ESP_LOGI(TAG, "RTC initialized"); |     ESP_LOGI(TAG, "RTC initialized"); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "timemanager.h" | #include "timekeeper.h" | ||||||
| 
 | 
 | ||||||
| // Local logging tag
 | // Local logging tag
 | ||||||
| static const char TAG[] = "main"; | static const char TAG[] = "main"; | ||||||
| @ -9,66 +9,57 @@ void time_sync() { | |||||||
| 
 | 
 | ||||||
| #ifdef TIME_SYNC_INTERVAL | #ifdef TIME_SYNC_INTERVAL | ||||||
| 
 | 
 | ||||||
|   static time_t ageOfTime = 0; |   if (timeStatus() == timeSet) | ||||||
| 
 |     return; | ||||||
|   ageOfTime = now() - lastSyncTime; // check if a sync is due
 |  | ||||||
| 
 |  | ||||||
|   // is it time to sync with external source or did we never sync yet?
 |  | ||||||
|   if ((ageOfTime >= (TIME_SYNC_INTERVAL * 60000)) || !lastSyncTime) { |  | ||||||
| 
 | 
 | ||||||
| #ifdef HAS_GPS | #ifdef HAS_GPS | ||||||
|     syncTime(get_gpstime(), pps); // attempt sync with GPS time
 |   if (syncTime(get_gpstime(), pps)) | ||||||
|  |     return; // attempt sync with GPS time
 | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if defined HAS_LORA && defined TIME_SYNC_LORA | // no GPS -> fallback to RTC time
 | ||||||
|     if (!TimeIsSynced) // no GPS sync -> try lora sync
 |  | ||||||
|       LMIC_requestNetworkTime(user_request_network_time_callback, |  | ||||||
|                               &userUTCTime); |  | ||||||
| #endif |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| #ifdef HAS_RTC | #ifdef HAS_RTC | ||||||
|   if (TimeIsSynced) { // recalibrate RTC, if we have one
 |  | ||||||
|     set_rtctime(now()); |  | ||||||
|   } else { // we switch to fallback time after a while
 |  | ||||||
|     if ((ageOfTime >= (TIME_SYNC_TIMEOUT * 60000)) || |  | ||||||
|         !lastSyncTime) { // sync is still due -> use RTC as fallback source
 |  | ||||||
|   if (!syncTime(get_rtctime(), rtc)) // sync with RTC time
 |   if (!syncTime(get_rtctime(), rtc)) // sync with RTC time
 | ||||||
|         ESP_LOGW(TAG, "no valid time"); |     ESP_LOGW(TAG, "no confident RTC time"); | ||||||
|       TimeIsSynced = false; | #endif | ||||||
|     } | 
 | ||||||
|   } | // try lora sync if we have
 | ||||||
|  | #if defined HAS_LORA && defined TIME_SYNC_LORA | ||||||
|  |   LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #endif // TIME_SYNC_INTERVAL
 | #endif // TIME_SYNC_INTERVAL
 | ||||||
| } // time_sync()
 | } // time_sync()
 | ||||||
| 
 | 
 | ||||||
| // helper function to sync time on start of next second
 | // helper function to sync time on start of next second
 | ||||||
| int syncTime(time_t const t, uint8_t const timesource) { | uint8_t syncTime(time_t const t, uint8_t const caller) { | ||||||
| 
 | 
 | ||||||
|   // symbol to display current time source
 |   // symbol to display current time source
 | ||||||
|   const char timeSetSymbols[] = {'G', 'R', 'L', '~'}; |   const char timeSetSymbols[] = {'G', 'R', 'L', '?'}; | ||||||
| 
 | 
 | ||||||
|   if (TimeIsValid(t)) { |   if (TimeIsValid(t)) { | ||||||
|     TimeIsSynced = wait_for_pulse(); // wait for next 1pps timepulse
 |     uint8_t const TimeIsPulseSynced = | ||||||
|  |         wait_for_pulse(); // wait for next 1pps timepulse
 | ||||||
|     setTime(t); |     setTime(t); | ||||||
|     adjustTime(1); // forward time to next second
 |     adjustTime(1); // forward time to next second
 | ||||||
|     lastSyncTime = now(); // store time of this sync
 |     timeSource = timeSetSymbols[caller]; | ||||||
|     timeSource = timeSetSymbols[timesource]; |  | ||||||
|     ESP_LOGD(TAG, "Time source %c set time to %02d:%02d:%02d", timeSource, |     ESP_LOGD(TAG, "Time source %c set time to %02d:%02d:%02d", timeSource, | ||||||
|              hour(t), minute(t), second(t)); |              hour(t), minute(t), second(t)); | ||||||
|  | #ifdef HAS_RTC | ||||||
|  |     if ((TimeIsPulseSynced) && (caller != rtc)) | ||||||
|  |       set_rtctime(now()); | ||||||
|  | #endif | ||||||
|     return 1; // success
 |     return 1; // success
 | ||||||
|  | 
 | ||||||
|   } else { |   } else { | ||||||
|  |     ESP_LOGD(TAG, "Time source %c sync attempt failed", timeSetSymbols[caller]); | ||||||
|     timeSource = timeSetSymbols[unsynced]; |     timeSource = timeSetSymbols[unsynced]; | ||||||
|     TimeIsSynced = false; |     return 0; // failure
 | ||||||
|     ESP_LOGD(TAG, "Time source %c sync attempt failed", timeSource); |  | ||||||
|     return 0; |  | ||||||
|   } |   } | ||||||
|   // failure
 | } // syncTime()
 | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| // helper function to sync moment on timepulse
 | // helper function to sync moment on timepulse
 | ||||||
| int wait_for_pulse(void) { | uint8_t wait_for_pulse(void) { | ||||||
|   // sync on top of next second with 1pps timepulse
 |   // sync on top of next second with 1pps timepulse
 | ||||||
|   if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1010)) == pdTRUE) |   if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1010)) == pdTRUE) | ||||||
|     return 1; // success
 |     return 1; // success
 | ||||||
| @ -77,7 +68,7 @@ int wait_for_pulse(void) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // helper function to setup a pulse per second for time synchronisation
 | // helper function to setup a pulse per second for time synchronisation
 | ||||||
| int timepulse_init() { | uint8_t timepulse_init() { | ||||||
| 
 | 
 | ||||||
| // use time pulse from GPS as time base with fixed 1Hz frequency
 | // use time pulse from GPS as time base with fixed 1Hz frequency
 | ||||||
| #ifdef GPS_INT | #ifdef GPS_INT | ||||||
| @ -140,7 +131,7 @@ void IRAM_ATTR CLOCKIRQ(void) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // helper function to check plausibility of a time
 | // helper function to check plausibility of a time
 | ||||||
| int TimeIsValid(time_t const t) { | uint8_t TimeIsValid(time_t const t) { | ||||||
|   // is it a time in the past? we use compile date to guess
 |   // is it a time in the past? we use compile date to guess
 | ||||||
|   ESP_LOGD(TAG, "t=%d, tt=%d, valid: %s", t, compiledUTC(), |   ESP_LOGD(TAG, "t=%d, tt=%d, valid: %s", t, compiledUTC(), | ||||||
|            (t >= compiledUTC()) ? "yes" : "no"); |            (t >= compiledUTC()) ? "yes" : "no"); | ||||||
| @ -202,9 +193,9 @@ void clock_loop(void *pvParameters) { // ClockTask | |||||||
| #define t1(t) (t + DCF77_FRAME_SIZE + 1) // future time for next DCF77 frame
 | #define t1(t) (t + DCF77_FRAME_SIZE + 1) // future time for next DCF77 frame
 | ||||||
| #define t2(t) (t + 1) // future time for sync with 1pps trigger
 | #define t2(t) (t + 1) // future time for sync with 1pps trigger
 | ||||||
| 
 | 
 | ||||||
| // preload first DCF frame before start
 |   // preload first DCF frame before start
 | ||||||
| #ifdef HAS_DCF77 | #ifdef HAS_DCF77 | ||||||
|   uint8_t *DCFpulse; |   uint8_t *DCFpulse; // pointer on array with DCF pulse bits
 | ||||||
|   DCFpulse = DCF77_Frame(t1(now())); |   DCFpulse = DCF77_Frame(t1(now())); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| @ -213,7 +204,7 @@ void clock_loop(void *pvParameters) { // ClockTask | |||||||
|     xTaskNotifyWait(0x00, ULONG_MAX, &wakeTime, |     xTaskNotifyWait(0x00, ULONG_MAX, &wakeTime, | ||||||
|                     portMAX_DELAY); // wait for timepulse
 |                     portMAX_DELAY); // wait for timepulse
 | ||||||
| 
 | 
 | ||||||
|     if (timeStatus() == timeNotSet) // do we have valid time?
 |     if (timeStatus() != timeSet) // no confident time -> no output to clock
 | ||||||
|       continue; |       continue; | ||||||
| 
 | 
 | ||||||
|     t = now(); // payload to send to clock
 |     t = now(); // payload to send to clock
 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user