AceTime  0.8
Date and time classes for Arduino that support timezones from the TZ Database, and a system clock that can synchronize from an NTP server or an RTC chip.
Public Member Functions | Protected Member Functions | Protected Attributes | Friends | List of all members
ace_time::clock::SystemClock Class Reference

A Clock that uses the Arduino millis() function to advance the time returned to the user. More...

#include <SystemClock.h>

Inheritance diagram for ace_time::clock::SystemClock:
Inheritance graph
[legend]
Collaboration diagram for ace_time::clock::SystemClock:
Collaboration graph
[legend]

Public Member Functions

void setup ()
 Attempt to retrieve the time from the backupClock if it exists. More...
 
acetime_t getNow () const override
 Return the number of seconds since the AceTime epoch (2000-01-01T00:00:00Z). More...
 
void setNow (acetime_t epochSeconds) override
 Set the time to the indicated seconds. More...
 
void forceSync ()
 Force a sync with the mReferenceClock. More...
 
acetime_t getLastSyncTime () const
 Return the time (seconds since Epoch) of the last valid sync() call. More...
 
bool isInit () const
 Return true if initialized by setNow() or syncNow(). More...
 
- Public Member Functions inherited from ace_time::clock::Clock
virtual ~Clock ()
 Virtual destructor. More...
 
virtual void sendRequest () const
 Send a time request asynchronously. More...
 
virtual bool isResponseReady () const
 Return true if a response is ready. More...
 
virtual acetime_t readResponse () const
 Returns number of seconds since AceTime epoch (2000-01-01). More...
 

Protected Member Functions

 SystemClock (const SystemClock &)=delete
 
SystemClockoperator= (const SystemClock &)=delete
 
 SystemClock (Clock *referenceClock, Clock *backupClock)
 Constructor. More...
 
virtual unsigned long clockMillis () const
 Return the Arduino millis(). More...
 
void keepAlive ()
 Call this (or getNow() every 65.535 seconds or faster to keep the internal counter in sync with millis().
 
void backupNow (acetime_t nowSeconds)
 Write the nowSeconds to the backupClock (which can be an RTC that has non-volatile memory, or simply flash memory which emulates a backupClock.
 
void syncNow (acetime_t epochSeconds)
 Similar to setNow() except that backupNow() is called only if the backupClock is different from the referenceClock. More...
 

Protected Attributes

Clock *const mReferenceClock
 
Clock *const mBackupClock
 
acetime_t mEpochSeconds = kInvalidSeconds
 
acetime_t mLastSyncTime = kInvalidSeconds
 
uint16_t mPrevMillis = 0
 
bool mIsInit = false
 

Friends

class ::SystemClockLoopTest
 
class ::SystemClockCoroutineTest
 
class ::SystemClockLoopTest_syncNow
 

Additional Inherited Members

- Static Public Attributes inherited from ace_time::clock::Clock
static const acetime_t kInvalidSeconds = LocalTime::kInvalidSeconds
 

Detailed Description

A Clock that uses the Arduino millis() function to advance the time returned to the user.

It has 2 major features:

1) The built-in millis() is not accurate, so this class allows a periodic sync using the (presumably) more accurate referenceClock. 2) The current time can be periodically backed up into the backupClock which is expected to be an RTC chip that continues to keep time during power loss. Upon (re)start, SystemClock::setup() reads back the time from the backupClock if it exists.

There are 2 maintenance tasks which this class must perform peridicallly:

1) The value of the previous system time millis() is stored internally as a uint16_t. That has 2 advantages: 1) it saves memory, 2) the upper bound of the execution time of getNow() limited to 65 iterations. The disadvantage is the that internal counter will rollover within 65.535 milliseconds. To prevent that, keepAlive() must be called more frequently than every 65.536 seconds. 2) The current time can be synchronized to the referenceClock peridically. Some reference clocks can take hundreds or thousands of milliseconds to return, so it's important that the non-block methods of Clock are used to synchronize to the reference clock.

Two subclasses of SystemClock expose 2 different ways of performing these maintenance tasks.

1) Call SystemClockCoroutine::runCoroutine using the framework of the AceRoutine library in the global loop() function. 2) Call the SystemClockLoop::loop() method from the global loop() function.

Definition at line 53 of file SystemClock.h.

Constructor & Destructor Documentation

◆ SystemClock()

ace_time::clock::SystemClock::SystemClock ( Clock referenceClock,
Clock backupClock 
)
inlineexplicitprotected

Constructor.

Parameters
referenceClockThe authoritative source of the time. If this is null, object relies just on clockMillis() and the user to set the proper time using setNow().
backupClockAn RTC chip which continues to keep time even when power is lost. Can be null.

Definition at line 116 of file SystemClock.h.

Member Function Documentation

◆ clockMillis()

virtual unsigned long ace_time::clock::SystemClock::clockMillis ( ) const
inlineprotectedvirtual

Return the Arduino millis().

Override for unit testing. Named 'clockMillis()' to avoid conflict with Coroutine::millis().

Definition at line 126 of file SystemClock.h.

◆ forceSync()

void ace_time::clock::SystemClock::forceSync ( )
inline

Force a sync with the mReferenceClock.

Definition at line 83 of file SystemClock.h.

◆ getLastSyncTime()

acetime_t ace_time::clock::SystemClock::getLastSyncTime ( ) const
inline

Return the time (seconds since Epoch) of the last valid sync() call.

Returns kInvalidSeconds if never synced.

Definition at line 92 of file SystemClock.h.

◆ getNow()

acetime_t ace_time::clock::SystemClock::getNow ( ) const
inlineoverridevirtual

Return the number of seconds since the AceTime epoch (2000-01-01T00:00:00Z).

Returns kInvalidSeconds if an error has occured.

This is a blocking call. Some clocks (e.g. NTP client) this may take many seconds. On those clocks, use the asynchronous methods (sendRequest(), isResponseReady(), and readResponse()) instead.

Implements ace_time::clock::Clock.

Definition at line 63 of file SystemClock.h.

◆ isInit()

bool ace_time::clock::SystemClock::isInit ( ) const
inline

Return true if initialized by setNow() or syncNow().

Definition at line 97 of file SystemClock.h.

◆ setNow()

void ace_time::clock::SystemClock::setNow ( acetime_t  )
inlineoverridevirtual

Set the time to the indicated seconds.

Calling with a value of kInvalidSeconds indicates an error condition, so the method should do nothing. Some clocks do not support this feature, for example, NTP or GPS clocks and this method will be a no-op.

Reimplemented from ace_time::clock::Clock.

Definition at line 73 of file SystemClock.h.

◆ setup()

void ace_time::clock::SystemClock::setup ( )
inline

Attempt to retrieve the time from the backupClock if it exists.

Definition at line 57 of file SystemClock.h.

◆ syncNow()

void ace_time::clock::SystemClock::syncNow ( acetime_t  epochSeconds)
inlineprotected

Similar to setNow() except that backupNow() is called only if the backupClock is different from the referenceClock.

This prevents us from retrieving the time from the RTC, then saving it right back again, with a drift each time it is saved back.

TODO: Implement a more graceful syncNow() algorithm which shifts only a few milliseconds per iteration, and which guarantees that the clock never goes backwards in time.

Definition at line 156 of file SystemClock.h.


The documentation for this class was generated from the following file: