timemanager reworked

This commit is contained in:
Klaus K Wilting 2019-02-24 01:44:55 +01:00
parent feda8dd938
commit 98797c0fe1
12 changed files with 68 additions and 85 deletions

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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)]);

View File

@ -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");

View File

@ -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...");

View File

@ -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

View File

@ -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");

View File

@ -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