2019-01-20 22:38:53 +01:00
|
|
|
#include "rtctime.h"
|
2019-01-19 17:53:21 +01:00
|
|
|
|
|
|
|
// Local logging tag
|
|
|
|
static const char TAG[] = "main";
|
|
|
|
|
2019-02-07 23:05:26 +01:00
|
|
|
hw_timer_t *clockCycle = NULL;
|
2019-02-14 23:01:20 +01:00
|
|
|
|
2019-02-15 14:08:27 +01:00
|
|
|
// helper function to setup a pulse per second for time synchronisation
|
|
|
|
int timepulse_init() {
|
2019-02-14 23:01:20 +01:00
|
|
|
|
|
|
|
// use time pulse from GPS as time base with fixed 1Hz frequency
|
2019-02-15 14:08:27 +01:00
|
|
|
#ifdef GPS_INT
|
2019-02-14 23:01:20 +01:00
|
|
|
|
|
|
|
// setup external interupt for active low RTC INT pin
|
|
|
|
pinMode(GPS_INT, INPUT_PULLDOWN);
|
|
|
|
// setup external rtc 1Hz clock as pulse per second clock
|
2019-02-16 15:02:07 +01:00
|
|
|
ESP_LOGI(TAG, "Time base: external (GPS)");
|
2019-02-14 23:01:20 +01:00
|
|
|
return 1; // success
|
|
|
|
|
|
|
|
// use pulse from on board RTC chip as time base with fixed frequency
|
2019-02-15 14:08:27 +01:00
|
|
|
#elif defined RTC_INT
|
2019-02-14 23:01:20 +01:00
|
|
|
|
|
|
|
// setup external interupt for active low RTC INT pin
|
|
|
|
pinMode(RTC_INT, INPUT_PULLUP);
|
2019-02-15 14:08:27 +01:00
|
|
|
|
2019-02-14 23:01:20 +01:00
|
|
|
// setup external rtc 1Hz clock as pulse per second clock
|
|
|
|
if (I2C_MUTEX_LOCK()) {
|
2019-02-15 14:08:27 +01:00
|
|
|
Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz);
|
2019-02-14 23:01:20 +01:00
|
|
|
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock);
|
|
|
|
I2C_MUTEX_UNLOCK();
|
2019-02-16 15:02:07 +01:00
|
|
|
ESP_LOGI(TAG, "Time base: external (RTC)");
|
2019-02-15 14:08:27 +01:00
|
|
|
return 1; // success
|
2019-02-14 23:01:20 +01:00
|
|
|
} else {
|
|
|
|
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
|
|
|
|
return 0; // failure
|
|
|
|
}
|
|
|
|
return 1; // success
|
|
|
|
|
|
|
|
#else
|
|
|
|
// use ESP32 hardware timer as time base with adjustable frequency
|
2019-02-15 14:08:27 +01:00
|
|
|
clockCycle = timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec
|
|
|
|
timerAlarmWrite(clockCycle, 10000, true); // 1000ms
|
2019-02-16 15:02:07 +01:00
|
|
|
ESP_LOGI(TAG, "Time base: internal (ESP32 hardware timer)");
|
2019-02-14 23:01:20 +01:00
|
|
|
return 1; // success
|
|
|
|
|
|
|
|
#endif
|
2019-02-15 14:08:27 +01:00
|
|
|
} // timepulse_init
|
2019-02-14 23:01:20 +01:00
|
|
|
|
|
|
|
void timepulse_start(void) {
|
|
|
|
#ifdef GPS_INT // start external clock gps pps line
|
|
|
|
attachInterrupt(digitalPinToInterrupt(GPS_INT), CLOCKIRQ, RISING);
|
|
|
|
#elif defined RTC_INT // start external clock rtc
|
|
|
|
attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING);
|
|
|
|
#else // start internal clock esp32 hardware timer
|
2019-02-16 15:02:07 +01:00
|
|
|
timerAttachInterrupt(clockCycle, &CLOCKIRQ, true);
|
2019-02-14 23:01:20 +01:00
|
|
|
timerAlarmEnable(clockCycle);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-02-17 19:21:08 +01:00
|
|
|
// interrupt service routine triggered by either pps or esp32 hardware timer
|
|
|
|
void IRAM_ATTR CLOCKIRQ(void) {
|
|
|
|
if (ClockTask != NULL)
|
|
|
|
xTaskNotifyFromISR(ClockTask, xTaskGetTickCountFromISR(), eSetBits, NULL);
|
|
|
|
#if defined GPS_INT || defined RTC_INT
|
|
|
|
xSemaphoreGiveFromISR(TimePulse, NULL);
|
|
|
|
TimePulseTick = !TimePulseTick; // flip ticker
|
|
|
|
#endif
|
|
|
|
portYIELD_FROM_ISR();
|
|
|
|
}
|
|
|
|
|
2019-02-16 15:02:07 +01:00
|
|
|
// helper function to sync systime on start of next second
|
|
|
|
int sync_SysTime(time_t t) {
|
2019-02-17 19:21:08 +01:00
|
|
|
if (sync_TimePulse() && (t)) { // wait for start of next second by timepulse
|
2019-02-16 15:02:07 +01:00
|
|
|
setTime(t + 1);
|
2019-02-17 19:21:08 +01:00
|
|
|
ESP_LOGD(TAG, "Systime synced on second");
|
2019-02-16 15:02:07 +01:00
|
|
|
return 1; // success
|
|
|
|
} else
|
|
|
|
return 0; // failure
|
|
|
|
}
|
|
|
|
|
2019-02-17 19:21:08 +01:00
|
|
|
int sync_SysTime(uint32_t t) { // t is epoch seconds starting 1.1.1970
|
|
|
|
return sync_SysTime(static_cast<time_t>(t));
|
|
|
|
}
|
|
|
|
|
2019-02-16 15:02:07 +01:00
|
|
|
// helper function to sync moment on timepulse
|
|
|
|
int sync_TimePulse(void) {
|
2019-02-14 23:01:20 +01:00
|
|
|
// sync on top of next second by timepulse
|
2019-02-17 19:21:08 +01:00
|
|
|
if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1100)) == pdTRUE) {
|
2019-02-16 15:02:07 +01:00
|
|
|
return 1;
|
|
|
|
} // success
|
2019-02-15 14:08:27 +01:00
|
|
|
else
|
2019-02-16 15:02:07 +01:00
|
|
|
ESP_LOGW(TAG, "Missing timepulse, time not synced");
|
|
|
|
return 0; // failure
|
2019-02-14 23:01:20 +01:00
|
|
|
}
|
|
|
|
|
2019-02-17 22:12:14 +01:00
|
|
|
// helper function to fetch current second from most precise time source
|
|
|
|
time_t best_time(void) {
|
|
|
|
|
|
|
|
time_t t;
|
|
|
|
|
|
|
|
#ifdef HAS_GPS // gps is our primary time source if present
|
|
|
|
t = get_gpstime();
|
|
|
|
if (t) // did we get a valid time?
|
|
|
|
return t;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
// Reading RTC time from chip take too long on i2c bus, causes jitter
|
|
|
|
#ifdef HAS_RTC // rtc is our secondary time source if present
|
|
|
|
t = get_rtctime();
|
|
|
|
if (t)
|
|
|
|
return t;
|
|
|
|
#endif
|
|
|
|
*/
|
|
|
|
|
|
|
|
// else we use systime as fallback source
|
|
|
|
return now();
|
|
|
|
}
|
|
|
|
|
2019-02-08 22:19:44 +01:00
|
|
|
#ifdef HAS_RTC // we have hardware RTC
|
|
|
|
|
|
|
|
RtcDS3231<TwoWire> Rtc(Wire); // RTC hardware i2c interface
|
|
|
|
|
2019-01-19 17:53:21 +01:00
|
|
|
// initialize RTC
|
2019-01-21 16:16:39 +01:00
|
|
|
int rtc_init(void) {
|
2019-01-19 17:53:21 +01:00
|
|
|
|
|
|
|
// return = 0 -> error / return = 1 -> success
|
|
|
|
|
|
|
|
// block i2c bus access
|
2019-01-26 12:32:17 +01:00
|
|
|
if (I2C_MUTEX_LOCK()) {
|
2019-01-19 17:53:21 +01:00
|
|
|
|
|
|
|
Wire.begin(HAS_RTC);
|
|
|
|
Rtc.Begin();
|
|
|
|
|
|
|
|
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
|
|
|
|
|
|
|
|
if (!Rtc.IsDateTimeValid()) {
|
2019-01-20 22:38:53 +01:00
|
|
|
ESP_LOGW(TAG,
|
|
|
|
"RTC has no valid RTC date/time, setting to compilation date");
|
2019-01-19 17:53:21 +01:00
|
|
|
Rtc.SetDateTime(compiled);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Rtc.GetIsRunning()) {
|
|
|
|
ESP_LOGI(TAG, "RTC not running, starting now");
|
|
|
|
Rtc.SetIsRunning(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
RtcDateTime now = Rtc.GetDateTime();
|
|
|
|
|
|
|
|
if (now < compiled) {
|
2019-01-28 00:38:31 +01:00
|
|
|
ESP_LOGI(TAG, "RTC date/time is older than compilation date, updating");
|
2019-01-19 17:53:21 +01:00
|
|
|
Rtc.SetDateTime(compiled);
|
|
|
|
}
|
|
|
|
|
|
|
|
// configure RTC chip
|
|
|
|
Rtc.Enable32kHzPin(false);
|
|
|
|
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
|
2019-01-25 22:49:26 +01:00
|
|
|
|
2019-01-19 17:53:21 +01:00
|
|
|
} else {
|
|
|
|
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-01-26 12:32:17 +01:00
|
|
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
2019-01-19 17:53:21 +01:00
|
|
|
ESP_LOGI(TAG, "RTC initialized");
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
error:
|
2019-01-26 12:32:17 +01:00
|
|
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
2019-01-19 17:53:21 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
} // rtc_init()
|
|
|
|
|
2019-02-11 23:37:45 +01:00
|
|
|
int set_rtctime(time_t t) { // t is seconds epoch time starting 1.1.1970
|
2019-01-26 12:32:17 +01:00
|
|
|
if (I2C_MUTEX_LOCK()) {
|
2019-02-14 23:01:20 +01:00
|
|
|
Rtc.SetDateTime(RtcDateTime(t));
|
2019-01-26 12:32:17 +01:00
|
|
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
2019-02-11 23:37:45 +01:00
|
|
|
ESP_LOGI(TAG, "RTC calibrated");
|
|
|
|
return 1; // success
|
2019-01-20 22:38:53 +01:00
|
|
|
}
|
2019-02-17 19:21:08 +01:00
|
|
|
ESP_LOGE(TAG, "RTC set time failure");
|
2019-01-29 22:54:16 +01:00
|
|
|
return 0; // failure
|
2019-01-20 22:38:53 +01:00
|
|
|
} // set_rtctime()
|
2019-01-19 17:53:21 +01:00
|
|
|
|
2019-02-02 09:15:31 +01:00
|
|
|
int set_rtctime(uint32_t t) { // t is epoch seconds starting 1.1.1970
|
|
|
|
return set_rtctime(static_cast<time_t>(t));
|
|
|
|
// set_rtctime()
|
|
|
|
}
|
2019-01-29 22:54:16 +01:00
|
|
|
|
2019-01-21 16:16:39 +01:00
|
|
|
time_t get_rtctime(void) {
|
2019-02-16 15:02:07 +01:00
|
|
|
// !! never call now() or delay in this function, this would break this
|
|
|
|
// function to be used as SyncProvider for Time.h
|
2019-02-17 22:12:14 +01:00
|
|
|
time_t t = 0; // 0 effects calling SyncProvider() to not set time
|
2019-01-19 17:53:21 +01:00
|
|
|
// block i2c bus access
|
2019-01-26 12:32:17 +01:00
|
|
|
if (I2C_MUTEX_LOCK()) {
|
2019-01-28 23:59:52 +01:00
|
|
|
if (Rtc.IsDateTimeValid()) {
|
|
|
|
RtcDateTime tt = Rtc.GetDateTime();
|
|
|
|
t = tt.Epoch32Time();
|
2019-01-21 16:16:39 +01:00
|
|
|
}
|
2019-01-26 12:32:17 +01:00
|
|
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
2019-01-20 22:38:53 +01:00
|
|
|
}
|
2019-01-28 23:59:52 +01:00
|
|
|
return t;
|
2019-01-21 16:16:39 +01:00
|
|
|
} // get_rtctime()
|
2019-01-19 17:53:21 +01:00
|
|
|
|
2019-01-21 16:16:39 +01:00
|
|
|
float get_rtctemp(void) {
|
2019-01-19 17:53:21 +01:00
|
|
|
// block i2c bus access
|
2019-01-26 12:32:17 +01:00
|
|
|
if (I2C_MUTEX_LOCK()) {
|
2019-01-19 17:53:21 +01:00
|
|
|
RtcTemperature temp = Rtc.GetTemperature();
|
2019-01-26 12:32:17 +01:00
|
|
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
2019-01-19 17:53:21 +01:00
|
|
|
return temp.AsFloatDegC();
|
|
|
|
} // while
|
|
|
|
return 0;
|
2019-01-28 23:59:52 +01:00
|
|
|
} // get_rtctemp()
|
2019-01-19 17:53:21 +01:00
|
|
|
|
2019-02-14 23:01:20 +01:00
|
|
|
#endif // HAS_RTC
|