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");
|
||||||
|
18
src/main.cpp
18
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
|
||||||
@ -96,7 +95,7 @@ void setup() {
|
|||||||
|
|
||||||
char features[100] = "";
|
char features[100] = "";
|
||||||
|
|
||||||
// create some semaphores for syncing / mutexing tasks
|
// create some semaphores for syncing / mutexing tasks
|
||||||
I2Caccess = xSemaphoreCreateMutex(); // for access management of i2c bus
|
I2Caccess = xSemaphoreCreateMutex(); // for access management of i2c bus
|
||||||
if (I2Caccess)
|
if (I2Caccess)
|
||||||
xSemaphoreGive(I2Caccess); // Flag the i2c bus available for use
|
xSemaphoreGive(I2Caccess); // Flag the i2c bus available for use
|
||||||
@ -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,14 +24,16 @@ int rtc_init(void) {
|
|||||||
Rtc.SetIsRunning(true);
|
Rtc.SetIsRunning(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
RtcDateTime tt = Rtc.GetDateTime();
|
/*
|
||||||
time_t t = tt.Epoch32Time(); // sec2000 -> epoch
|
RtcDateTime tt = Rtc.GetDateTime();
|
||||||
|
time_t t = tt.Epoch32Time(); // sec2000 -> epoch
|
||||||
|
|
||||||
if (!Rtc.IsDateTimeValid() || !TimeIsValid(t)) {
|
if (!Rtc.IsDateTimeValid() || !TimeIsValid(t)) {
|
||||||
ESP_LOGW(TAG, "RTC has no recent time, setting to compilation date");
|
ESP_LOGW(TAG, "RTC has no recent time, setting to compilation date");
|
||||||
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
|
if (!syncTime(get_rtctime(), rtc)) // sync with RTC time
|
||||||
set_rtctime(now());
|
ESP_LOGW(TAG, "no confident RTC time");
|
||||||
} else { // we switch to fallback time after a while
|
#endif
|
||||||
if ((ageOfTime >= (TIME_SYNC_TIMEOUT * 60000)) ||
|
|
||||||
!lastSyncTime) { // sync is still due -> use RTC as fallback source
|
// try lora sync if we have
|
||||||
if (!syncTime(get_rtctime(), rtc)) // sync with RTC time
|
#if defined HAS_LORA && defined TIME_SYNC_LORA
|
||||||
ESP_LOGW(TAG, "no valid time");
|
LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime);
|
||||||
TimeIsSynced = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#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