clock time handling modifications (still experimental)
This commit is contained in:
		
							parent
							
								
									42971b60cd
								
							
						
					
					
						commit
						1ac176075a
					
				@ -102,7 +102,6 @@ extern uint16_t volatile macs_total, macs_wifi, macs_ble,
 | 
				
			|||||||
    batt_voltage; // display values
 | 
					    batt_voltage; // display values
 | 
				
			||||||
extern hw_timer_t *sendCycle, *displaytimer;
 | 
					extern hw_timer_t *sendCycle, *displaytimer;
 | 
				
			||||||
extern SemaphoreHandle_t I2Caccess, TimePulse;
 | 
					extern SemaphoreHandle_t I2Caccess, TimePulse;
 | 
				
			||||||
extern bool volatile BitsPending;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
 | 
					extern std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
 | 
				
			||||||
extern std::array<uint64_t, 0xff>::iterator it;
 | 
					extern std::array<uint64_t, 0xff>::iterator it;
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ extern RtcDS3231<TwoWire> Rtc; // make RTC instance globally available
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern TaskHandle_t ClockTask;
 | 
					extern TaskHandle_t ClockTask;
 | 
				
			||||||
extern hw_timer_t *clockCycle;
 | 
					extern hw_timer_t *clockCycle;
 | 
				
			||||||
 | 
					extern bool volatile TimePulseTick;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int rtc_init(void);
 | 
					int rtc_init(void);
 | 
				
			||||||
int set_rtctime(uint32_t t);
 | 
					int set_rtctime(uint32_t t);
 | 
				
			||||||
@ -23,6 +24,6 @@ float get_rtctemp(void);
 | 
				
			|||||||
void IRAM_ATTR CLOCKIRQ();
 | 
					void IRAM_ATTR CLOCKIRQ();
 | 
				
			||||||
int timepulse_init(uint32_t pps_freq);
 | 
					int timepulse_init(uint32_t pps_freq);
 | 
				
			||||||
void timepulse_start();
 | 
					void timepulse_start();
 | 
				
			||||||
time_t sync_clock(time_t t);
 | 
					void sync_clock(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // _RTCTIME_H
 | 
					#endif // _RTCTIME_H
 | 
				
			||||||
@ -17,6 +17,8 @@ https://www-user.tu-chemnitz.de/~heha/viewzip.cgi/hs/Funkuhr.zip/
 | 
				
			|||||||
// Local logging tag
 | 
					// Local logging tag
 | 
				
			||||||
static const char TAG[] = "main";
 | 
					static const char TAG[] = "main";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool volatile BitsPending = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DCF77_FRAME_SIZE (60)
 | 
					#define DCF77_FRAME_SIZE (60)
 | 
				
			||||||
#define DCF77_PULSE_DURATION (100)
 | 
					#define DCF77_PULSE_DURATION (100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -35,8 +37,6 @@ uint8_t DCFtimeframe[DCF77_FRAME_SIZE];
 | 
				
			|||||||
// initialize and configure DCF77 output
 | 
					// initialize and configure DCF77 output
 | 
				
			||||||
int dcf77_init(void) {
 | 
					int dcf77_init(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BitsPending = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinMode(HAS_DCF77, OUTPUT);
 | 
					  pinMode(HAS_DCF77, OUTPUT);
 | 
				
			||||||
  set_DCF77_pin(dcf_low);
 | 
					  set_DCF77_pin(dcf_low);
 | 
				
			||||||
  timepulse_init(PPS); // setup timepulse
 | 
					  timepulse_init(PPS); // setup timepulse
 | 
				
			||||||
@ -70,7 +70,7 @@ void DCF_Out(uint8_t startOffset_sec) {
 | 
				
			|||||||
    if ((timeStatus() == timeSet) || (timeStatus() == timeNeedsSync)) {
 | 
					    if ((timeStatus() == timeSet) || (timeStatus() == timeNeedsSync)) {
 | 
				
			||||||
      // prepare frame to send for next minute
 | 
					      // prepare frame to send for next minute
 | 
				
			||||||
      generateTimeframe(now() + DCF77_FRAME_SIZE + 1);
 | 
					      generateTimeframe(now() + DCF77_FRAME_SIZE + 1);
 | 
				
			||||||
      // start blinking symbol on display and kick off timer
 | 
					      // kick off output of telegram
 | 
				
			||||||
      BitsPending = true;
 | 
					      BitsPending = true;
 | 
				
			||||||
    } else
 | 
					    } else
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
@ -103,7 +103,7 @@ void DCF_Out(uint8_t startOffset_sec) {
 | 
				
			|||||||
// recalibrate clock after a fixed timespan, do this in 59th second
 | 
					// recalibrate clock after a fixed timespan, do this in 59th second
 | 
				
			||||||
#ifdef TIME_SYNC_INTERVAL_DCF
 | 
					#ifdef TIME_SYNC_INTERVAL_DCF
 | 
				
			||||||
        if ((millis() >= nextDCFsync)) {
 | 
					        if ((millis() >= nextDCFsync)) {
 | 
				
			||||||
          sync_clock(now()); // waiting for second 59
 | 
					          sync_clock(); // waiting for second 59
 | 
				
			||||||
          nextDCFsync = millis() + TIME_SYNC_INTERVAL_DCF *
 | 
					          nextDCFsync = millis() + TIME_SYNC_INTERVAL_DCF *
 | 
				
			||||||
                                       60000; // set up next time sync period
 | 
					                                       60000; // set up next time sync period
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -221,15 +221,12 @@ void refreshtheDisplay() {
 | 
				
			|||||||
    // update LoRa status display (line 6)
 | 
					    // update LoRa status display (line 6)
 | 
				
			||||||
    u8x8.printf("%-16s", display_line6);
 | 
					    u8x8.printf("%-16s", display_line6);
 | 
				
			||||||
#else // we want a time display instead LoRa status
 | 
					#else // we want a time display instead LoRa status
 | 
				
			||||||
    // update time/date display (line 6)
 | 
					 | 
				
			||||||
    time_t t = myTZ.toLocal(now());
 | 
					    time_t t = myTZ.toLocal(now());
 | 
				
			||||||
    char timeState =
 | 
					    char timeState =
 | 
				
			||||||
        timeStatus() == timeSet ? timesyncSymbol : timeNosyncSymbol;
 | 
					        (timeStatus() == timeSet) ? timesyncSymbol : timeNosyncSymbol;
 | 
				
			||||||
    // make timestatus symbol blinking if pps line
 | 
					    char timePulse = TimePulseTick ? '.' : ':';
 | 
				
			||||||
    if ((BitsPending) && (second(t) % 2))
 | 
					    u8x8.printf("%02d:%02d%c%02d%c %2d.%3s", hour(t), minute(t), timePulse,
 | 
				
			||||||
      timeState = ' ';
 | 
					                second(t), timeState, day(t), printmonth[month(t)]);
 | 
				
			||||||
    u8x8.printf("%02d:%02d:%02d%c %2d.%3s", hour(t), minute(t), second(t),
 | 
					 | 
				
			||||||
                timeState, day(t), printmonth[month(t)]);
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // update LMiC event display (line 7)
 | 
					    // update LMiC event display (line 7)
 | 
				
			||||||
 | 
				
			|||||||
@ -88,28 +88,23 @@ time_t tmConvert_t(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// function to fetch current time from gps
 | 
					// function to fetch current time from gps
 | 
				
			||||||
time_t get_gpstime(void) {
 | 
					time_t get_gpstime(void) {
 | 
				
			||||||
  // never call now() in this function, this would break this function
 | 
					  // !! never call now() in this function, this would break this function
 | 
				
			||||||
  // to use as SyncProvider due to recursive call to now()
 | 
					  // to be used as SyncProvider due to recursive call to now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  time_t t;
 | 
					 | 
				
			||||||
  if ((gps.time.age() < 1500) && (gps.time.isValid())) {
 | 
					  if ((gps.time.age() < 1500) && (gps.time.isValid())) {
 | 
				
			||||||
    t = tmConvert_t(gps.date.year(), gps.date.month(), gps.date.day(),
 | 
					    // get current gps time
 | 
				
			||||||
 | 
					    time_t t =
 | 
				
			||||||
 | 
					        tmConvert_t(gps.date.year(), gps.date.month(), gps.date.day(),
 | 
				
			||||||
                    gps.time.hour(), gps.time.minute(), gps.time.second());
 | 
					                    gps.time.hour(), gps.time.minute(), gps.time.second());
 | 
				
			||||||
    ESP_LOGD(TAG, "GPS time: %4d/%02d/%02d %02d:%02d:%02d", year(t), month(t),
 | 
					    ESP_LOGD(TAG, "GPS time: %4d/%02d/%02d %02d:%02d:%02d", year(t), month(t),
 | 
				
			||||||
             day(t), hour(t), minute(t), second(t));
 | 
					             day(t), hour(t), minute(t), second(t));
 | 
				
			||||||
 | 
					    // sync on top of next second by timepulse
 | 
				
			||||||
 | 
					    sync_clock();
 | 
				
			||||||
 | 
					    return t + 1;
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    ESP_LOGW(TAG, "GPS has no confident time");
 | 
					    ESP_LOGW(TAG, "GPS has no confident time");
 | 
				
			||||||
    return 0;
 | 
					    return 0; // sync failure, 0 effects calling SyncProvider() to not set time
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  // sync on top of next second bv timepulse
 | 
					 | 
				
			||||||
  if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)) == pdTRUE)
 | 
					 | 
				
			||||||
    return t;
 | 
					 | 
				
			||||||
  else {
 | 
					 | 
				
			||||||
    ESP_LOGW(TAG, "No GPS timepulse, thus time can't be synced by GPS");
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
  } // failure
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // get_gpstime()
 | 
					} // get_gpstime()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GPS serial feed FreeRTos Task
 | 
					// GPS serial feed FreeRTos Task
 | 
				
			||||||
 | 
				
			|||||||
@ -161,16 +161,11 @@ void if482_loop(void *pvParameters) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  TickType_t wakeTime;
 | 
					  TickType_t wakeTime;
 | 
				
			||||||
  const TickType_t tTx = tx_time(HAS_IF482); // duration of telegram transmit
 | 
					  const TickType_t tTx = tx_time(HAS_IF482); // duration of telegram transmit
 | 
				
			||||||
  BitsPending = true;                        // start blink in display
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // phase 1: sync task on top of second
 | 
					  // phase 1: sync task on top of second
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const TickType_t t0 = xTaskGetTickCount(); // moment of start top of second
 | 
					  const TickType_t t0 = xTaskGetTickCount(); // moment of start top of second
 | 
				
			||||||
 | 
					  sync_clock(); // delay until top of second
 | 
				
			||||||
  sync_clock(now()); // delay until top of second
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // const TickType_t t0 = xTaskGetTickCount(); // moment of start top of second
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  timepulse_start(); // start timepulse
 | 
					  timepulse_start(); // start timepulse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  xTaskNotifyWait(
 | 
					  xTaskNotifyWait(
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										26
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								src/main.cpp
									
									
									
									
									
								
							@ -65,7 +65,6 @@ char display_line6[16], display_line7[16]; // display buffers
 | 
				
			|||||||
uint8_t volatile channel = 0;              // channel rotation counter
 | 
					uint8_t volatile channel = 0;              // channel rotation counter
 | 
				
			||||||
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
 | 
					uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
 | 
				
			||||||
                  batt_voltage = 0; // globals for display
 | 
					                  batt_voltage = 0; // globals for display
 | 
				
			||||||
bool volatile BitsPending = false;  // DCF77 or IF482 ticker indicator
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
hw_timer_t *sendCycle = NULL, *homeCycle = NULL;
 | 
					hw_timer_t *sendCycle = NULL, *homeCycle = NULL;
 | 
				
			||||||
#ifdef HAS_DISPLAY
 | 
					#ifdef HAS_DISPLAY
 | 
				
			||||||
@ -97,14 +96,12 @@ void setup() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  char features[100] = "";
 | 
					  char features[100] = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  TimePulse = xSemaphoreCreateMutex(); // for time pulse flip
 | 
					  TimePulse = xSemaphoreCreateBinary(); // as signal that shows time pulse flip
 | 
				
			||||||
  if (TimePulse)
 | 
					 | 
				
			||||||
    xSemaphoreTake(TimePulse, (TickType_t)10);
 | 
					 | 
				
			||||||
    // Block TimePulse since we have no pulse yet
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // disable brownout detection
 | 
					  // disable brownout detection
 | 
				
			||||||
#ifdef DISABLE_BROWNOUT
 | 
					#ifdef DISABLE_BROWNOUT
 | 
				
			||||||
@ -146,10 +143,21 @@ void setup() {
 | 
				
			|||||||
           ESP.getChipRevision(), ESP.getCpuFreqMHz(), ESP.getSdkVersion());
 | 
					           ESP.getChipRevision(), ESP.getCpuFreqMHz(), ESP.getSdkVersion());
 | 
				
			||||||
  ESP_LOGI(TAG, "Flash Size %d, Flash Speed %d", ESP.getFlashChipSize(),
 | 
					  ESP_LOGI(TAG, "Flash Size %d, Flash Speed %d", ESP.getFlashChipSize(),
 | 
				
			||||||
           ESP.getFlashChipSpeed());
 | 
					           ESP.getFlashChipSpeed());
 | 
				
			||||||
  ESP_LOGI(TAG, "Wifi/BT software coexist version: %s", esp_coex_version_get());
 | 
					  ESP_LOGI(TAG, "Wifi/BT software coexist version %s", esp_coex_version_get());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAS_LORA
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "IBM LMIC version %d.%d.%d", LMIC_VERSION_MAJOR,
 | 
				
			||||||
 | 
					           LMIC_VERSION_MINOR, LMIC_VERSION_BUILD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Arduino LMIC version %d.%d.%d.%d",
 | 
				
			||||||
 | 
					           ARDUINO_LMIC_VERSION_GET_MAJOR(ARDUINO_LMIC_VERSION),
 | 
				
			||||||
 | 
					           ARDUINO_LMIC_VERSION_GET_MINOR(ARDUINO_LMIC_VERSION),
 | 
				
			||||||
 | 
					           ARDUINO_LMIC_VERSION_GET_PATCH(ARDUINO_LMIC_VERSION),
 | 
				
			||||||
 | 
					           ARDUINO_LMIC_VERSION_GET_LOCAL(ARDUINO_LMIC_VERSION));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAS_GPS
 | 
					#ifdef HAS_GPS
 | 
				
			||||||
  ESP_LOGI(TAG, "TinyGPS+ v%s", TinyGPSPlus::libraryVersion());
 | 
					  ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion());
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // verbose
 | 
					#endif // verbose
 | 
				
			||||||
@ -330,7 +338,7 @@ void setup() {
 | 
				
			|||||||
#ifdef HAS_RTC
 | 
					#ifdef HAS_RTC
 | 
				
			||||||
  strcat_P(features, " RTC");
 | 
					  strcat_P(features, " RTC");
 | 
				
			||||||
  assert(rtc_init());
 | 
					  assert(rtc_init());
 | 
				
			||||||
  setSyncProvider(&get_rtctime);
 | 
					  setSyncProvider(&get_rtctime); // sync time now and then
 | 
				
			||||||
  if (timeStatus() != timeSet)
 | 
					  if (timeStatus() != timeSet)
 | 
				
			||||||
    ESP_LOGI(TAG, "Unable to sync system time with RTC");
 | 
					    ESP_LOGI(TAG, "Unable to sync system time with RTC");
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
@ -408,7 +416,7 @@ void setup() {
 | 
				
			|||||||
#endif // HAS_BUTTON
 | 
					#endif // HAS_BUTTON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAS_GPS
 | 
					#ifdef HAS_GPS
 | 
				
			||||||
  setSyncProvider(&get_gpstime);
 | 
					  setSyncProvider(&get_gpstime); // sync time now and then
 | 
				
			||||||
  if (timeStatus() != timeSet)
 | 
					  if (timeStatus() != timeSet)
 | 
				
			||||||
    ESP_LOGI(TAG, "Unable to sync system time with GPS");
 | 
					    ESP_LOGI(TAG, "Unable to sync system time with GPS");
 | 
				
			||||||
  else {
 | 
					  else {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										225
									
								
								src/rtctime.cpp
									
									
									
									
									
								
							
							
						
						
									
										225
									
								
								src/rtctime.cpp
									
									
									
									
									
								
							@ -7,104 +7,7 @@ static const char TAG[] = "main";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
TaskHandle_t ClockTask;
 | 
					TaskHandle_t ClockTask;
 | 
				
			||||||
hw_timer_t *clockCycle = NULL;
 | 
					hw_timer_t *clockCycle = NULL;
 | 
				
			||||||
 | 
					bool volatile TimePulseTick = false;
 | 
				
			||||||
#ifdef HAS_RTC // we have hardware RTC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RtcDS3231<TwoWire> Rtc(Wire); // RTC hardware i2c interface
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// initialize RTC
 | 
					 | 
				
			||||||
int rtc_init(void) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // return = 0 -> error / return = 1 -> success
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // block i2c bus access
 | 
					 | 
				
			||||||
  if (I2C_MUTEX_LOCK()) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Wire.begin(HAS_RTC);
 | 
					 | 
				
			||||||
    Rtc.Begin();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!Rtc.IsDateTimeValid()) {
 | 
					 | 
				
			||||||
      ESP_LOGW(TAG,
 | 
					 | 
				
			||||||
               "RTC has no valid RTC date/time, setting to compilation date");
 | 
					 | 
				
			||||||
      Rtc.SetDateTime(compiled);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!Rtc.GetIsRunning()) {
 | 
					 | 
				
			||||||
      ESP_LOGI(TAG, "RTC not running, starting now");
 | 
					 | 
				
			||||||
      Rtc.SetIsRunning(true);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    RtcDateTime now = Rtc.GetDateTime();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (now < compiled) {
 | 
					 | 
				
			||||||
      ESP_LOGI(TAG, "RTC date/time is older than compilation date, updating");
 | 
					 | 
				
			||||||
      Rtc.SetDateTime(compiled);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // configure RTC chip
 | 
					 | 
				
			||||||
    Rtc.Enable32kHzPin(false);
 | 
					 | 
				
			||||||
    Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
 | 
					 | 
				
			||||||
    goto error;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "RTC initialized");
 | 
					 | 
				
			||||||
  return 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error:
 | 
					 | 
				
			||||||
  I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
					 | 
				
			||||||
  return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // rtc_init()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int set_rtctime(time_t t) { // t is seconds epoch time starting 1.1.1970
 | 
					 | 
				
			||||||
  if (I2C_MUTEX_LOCK()) {
 | 
					 | 
				
			||||||
    time_t tt = sync_clock(t); // wait for top of second
 | 
					 | 
				
			||||||
    Rtc.SetDateTime(RtcDateTime(tt));
 | 
					 | 
				
			||||||
    I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
					 | 
				
			||||||
    ESP_LOGI(TAG, "RTC calibrated");
 | 
					 | 
				
			||||||
    return 1; // success
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return 0; // failure
 | 
					 | 
				
			||||||
} // set_rtctime()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int set_rtctime(uint32_t t) { // t is epoch seconds starting 1.1.1970
 | 
					 | 
				
			||||||
  return set_rtctime(static_cast<time_t>(t));
 | 
					 | 
				
			||||||
  // set_rtctime()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
time_t get_rtctime(void) {
 | 
					 | 
				
			||||||
  // never call now() in this function, this would cause a recursion!
 | 
					 | 
				
			||||||
  time_t t = 0;
 | 
					 | 
				
			||||||
  // block i2c bus access
 | 
					 | 
				
			||||||
  if (I2C_MUTEX_LOCK()) {
 | 
					 | 
				
			||||||
    if (Rtc.IsDateTimeValid()) {
 | 
					 | 
				
			||||||
      RtcDateTime tt = Rtc.GetDateTime();
 | 
					 | 
				
			||||||
      t = tt.Epoch32Time();
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      ESP_LOGW(TAG, "RTC has no confident time");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return t;
 | 
					 | 
				
			||||||
} // get_rtctime()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
float get_rtctemp(void) {
 | 
					 | 
				
			||||||
  // block i2c bus access
 | 
					 | 
				
			||||||
  if (I2C_MUTEX_LOCK()) {
 | 
					 | 
				
			||||||
    RtcTemperature temp = Rtc.GetTemperature();
 | 
					 | 
				
			||||||
    I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
					 | 
				
			||||||
    return temp.AsFloatDegC();
 | 
					 | 
				
			||||||
  } // while
 | 
					 | 
				
			||||||
  return 0;
 | 
					 | 
				
			||||||
} // get_rtctemp()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // HAS_RTC
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// helper function to setup a pulse for time synchronisation
 | 
					// helper function to setup a pulse for time synchronisation
 | 
				
			||||||
int timepulse_init(uint32_t pulse_period_ms) {
 | 
					int timepulse_init(uint32_t pulse_period_ms) {
 | 
				
			||||||
@ -170,29 +73,139 @@ pulse_period_error:
 | 
				
			|||||||
  return 0; // failure
 | 
					  return 0; // failure
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void timepulse_start() {
 | 
					void timepulse_start(void) {
 | 
				
			||||||
#ifdef GPS_INT // start external clock
 | 
					#ifdef GPS_INT // start external clock gps pps line
 | 
				
			||||||
  attachInterrupt(digitalPinToInterrupt(GPS_INT), CLOCKIRQ, RISING);
 | 
					  attachInterrupt(digitalPinToInterrupt(GPS_INT), CLOCKIRQ, RISING);
 | 
				
			||||||
#elif defined RTC_INT // start external clock
 | 
					#elif defined RTC_INT // start external clock rtc
 | 
				
			||||||
  attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING);
 | 
					  attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING);
 | 
				
			||||||
#else                 // start internal clock
 | 
					#else                 // start internal clock esp32 hardware timer
 | 
				
			||||||
  timerAlarmEnable(clockCycle);
 | 
					  timerAlarmEnable(clockCycle);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// helper function to sync time_t of top of next second
 | 
					// helper function to sync time_t of top of next second
 | 
				
			||||||
time_t sync_clock(time_t t) {
 | 
					void sync_clock(void) {
 | 
				
			||||||
 | 
					// do we have a second time pulse? Then wait for next pulse
 | 
				
			||||||
 | 
					#if defined(RTC_INT) || defined(GPS_INT)
 | 
				
			||||||
 | 
					  // sync on top of next second by timepulse
 | 
				
			||||||
 | 
					  if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)) == pdTRUE) {
 | 
				
			||||||
 | 
					    ESP_LOGI(TAG, "clock synced by timepulse");
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  } else
 | 
				
			||||||
 | 
					    ESP_LOGW(TAG, "Missing timepulse, thus clock can't be synced by second");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  // no external timepulse, thus we must use less precise internal system clock
 | 
				
			||||||
  while (millis() % 1000)
 | 
					  while (millis() % 1000)
 | 
				
			||||||
    ; // wait for milli seconds to be zero before setting new time
 | 
					    ; // wait for milli seconds to be zero before setting new time
 | 
				
			||||||
  return (now());
 | 
					  ESP_LOGI(TAG, "clock synced by systime");
 | 
				
			||||||
 | 
					  return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// interrupt service routine triggered by either rtc pps or esp32 hardware
 | 
					// interrupt service routine triggered by either rtc pps or esp32 hardware
 | 
				
			||||||
// timer
 | 
					// timer
 | 
				
			||||||
void IRAM_ATTR CLOCKIRQ() {
 | 
					void IRAM_ATTR CLOCKIRQ() {
 | 
				
			||||||
  xTaskNotifyFromISR(ClockTask, xTaskGetTickCountFromISR(), eSetBits, NULL);
 | 
					  xTaskNotifyFromISR(ClockTask, xTaskGetTickCountFromISR(), eSetBits, NULL);
 | 
				
			||||||
#ifdef GPS_INT
 | 
					#if defined(GPS_INT) || defined(RTC_INT)
 | 
				
			||||||
  xSemaphoreGiveFromISR(TimePulse, NULL);
 | 
					  xSemaphoreGiveFromISR(TimePulse, pdFALSE);
 | 
				
			||||||
 | 
					  TimePulseTick = !TimePulseTick; // flip ticker
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  portYIELD_FROM_ISR();
 | 
					  portYIELD_FROM_ISR();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAS_RTC // we have hardware RTC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RtcDS3231<TwoWire> Rtc(Wire); // RTC hardware i2c interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// initialize RTC
 | 
				
			||||||
 | 
					int rtc_init(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // return = 0 -> error / return = 1 -> success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // block i2c bus access
 | 
				
			||||||
 | 
					  if (I2C_MUTEX_LOCK()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Wire.begin(HAS_RTC);
 | 
				
			||||||
 | 
					    Rtc.Begin();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!Rtc.IsDateTimeValid()) {
 | 
				
			||||||
 | 
					      ESP_LOGW(TAG,
 | 
				
			||||||
 | 
					               "RTC has no valid RTC date/time, setting to compilation date");
 | 
				
			||||||
 | 
					      Rtc.SetDateTime(compiled);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!Rtc.GetIsRunning()) {
 | 
				
			||||||
 | 
					      ESP_LOGI(TAG, "RTC not running, starting now");
 | 
				
			||||||
 | 
					      Rtc.SetIsRunning(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RtcDateTime now = Rtc.GetDateTime();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (now < compiled) {
 | 
				
			||||||
 | 
					      ESP_LOGI(TAG, "RTC date/time is older than compilation date, updating");
 | 
				
			||||||
 | 
					      Rtc.SetDateTime(compiled);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // configure RTC chip
 | 
				
			||||||
 | 
					    Rtc.Enable32kHzPin(false);
 | 
				
			||||||
 | 
					    Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
 | 
				
			||||||
 | 
					    goto error;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "RTC initialized");
 | 
				
			||||||
 | 
					  return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
					  I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // rtc_init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int set_rtctime(time_t t) { // t is seconds epoch time starting 1.1.1970
 | 
				
			||||||
 | 
					  if (I2C_MUTEX_LOCK()) {
 | 
				
			||||||
 | 
					    sync_clock(); // wait for top of second
 | 
				
			||||||
 | 
					    Rtc.SetDateTime(RtcDateTime(t));
 | 
				
			||||||
 | 
					    I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
				
			||||||
 | 
					    ESP_LOGI(TAG, "RTC calibrated");
 | 
				
			||||||
 | 
					    return 1; // success
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return 0; // failure
 | 
				
			||||||
 | 
					} // set_rtctime()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int set_rtctime(uint32_t t) { // t is epoch seconds starting 1.1.1970
 | 
				
			||||||
 | 
					  return set_rtctime(static_cast<time_t>(t));
 | 
				
			||||||
 | 
					  // set_rtctime()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					time_t get_rtctime(void) {
 | 
				
			||||||
 | 
					  // never call now() in this function, this would cause a recursion!
 | 
				
			||||||
 | 
					  time_t t = 0;
 | 
				
			||||||
 | 
					  // block i2c bus access
 | 
				
			||||||
 | 
					  if (I2C_MUTEX_LOCK()) {
 | 
				
			||||||
 | 
					    if (Rtc.IsDateTimeValid()) {
 | 
				
			||||||
 | 
					      RtcDateTime tt = Rtc.GetDateTime();
 | 
				
			||||||
 | 
					      t = tt.Epoch32Time();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      ESP_LOGW(TAG, "RTC has no confident time");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return t;
 | 
				
			||||||
 | 
					} // get_rtctime()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float get_rtctemp(void) {
 | 
				
			||||||
 | 
					  // block i2c bus access
 | 
				
			||||||
 | 
					  if (I2C_MUTEX_LOCK()) {
 | 
				
			||||||
 | 
					    RtcTemperature temp = Rtc.GetTemperature();
 | 
				
			||||||
 | 
					    I2C_MUTEX_UNLOCK(); // release i2c bus access
 | 
				
			||||||
 | 
					    return temp.AsFloatDegC();
 | 
				
			||||||
 | 
					  } // while
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					} // get_rtctemp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // HAS_RTC
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user