nrfcxx  0.1.0
C++-17 Framework for Nordic nRF5 Devices
Public Types | Public Member Functions | Static Public Member Functions | Data Fields | Protected Member Functions | Protected Attributes | Static Protected Attributes
nrfcxx::clock::alarm Class Reference

Class supporting an alarm with custom callback and repeatability. More...

#include <nrfcxx/clock.hpp>

Public Types

enum  state_type {
  ST_unscheduled, ST_scheduled, ST_ready, ST_in_callback,
  ST_cancelled
}
 Constants identifying the alarm state. More...
 
using mutex_type = uptime::mutex_type
 An RAII type for mutex access blocking changes to alarm state.
 
using callback_type = std::function< bool(alarm &alarm)>
 The signature of an alarm callback function. More...
 

Public Member Functions

state_type state () const
 The current state of the alarm.
 
bool active () const
 Return true if the alarm state is one of ST_scheduled, ST_ready, or ST_in_callback. More...
 
 alarm (const alarm &)=delete
 
alarmoperator= (const alarm &)=delete
 
 alarm (alarm &&)=delete
 
alarmoperator= (alarm &&)=delete
 
 alarm (callback_type callback, unsigned int interval=0, void *md=0)
 Standard alarm constructor. More...
 
 alarm (callback_type callback, void *md)
 Overload for common case of configuring with static callback. More...
 
template<typename DurT , typename DurT::rep = 0>
constexpr alarm (callback_type callback, DurT interval, void *md=0)
 Duration-specified alarm constructor. More...
 
 ~alarm ()
 On destruction the alarm is cancelled.
 
void schedule ()
 Queue the alarm to execute at its current deadline(). More...
 
void schedule_offset (int offset)
 Queue the alarm to execute at offset ticks from the current time. More...
 
template<typename DurT >
void schedule_offset (DurT offset)
 Schedule an alarm using a std::chrono duration. More...
 
state_type cancel ()
 Cancel a potentially-scheduled alarm. More...
 
unsigned int interval () const
 An offset added to deadline() prior to invoking the callback when the alarm fires.
 
alarmset_interval (unsigned int interval)
 Set the interval() in uptime ticks. More...
 
template<typename DurT , typename DurT::rep = 0>
alarmset_interval (DurT interval)
 Set the interval() using a given duration.
 
unsigned int deadline () const
 The value of (the low 32 bits of) uptime::now() at which the alarm should fire.
 
alarmset_deadline (unsigned int deadline)
 Set the deadline for the alarm to fire. More...
 

Static Public Member Functions

template<event_set::event_type EVT, bool reschedule = false>
static alarm for_event (event_set &events)
 Factory producing an alarm with a callback that sets an event. More...
 

Data Fields

void *const metadata
 Pointer to arbitrary data associated with the alarm. More...
 

Protected Member Functions

int ordinal_ (unsigned int now) const noexcept
 Calculate an ordinal for the alarm using the distance from now until its deadline.
 

Protected Attributes

callback_type const callback_
 
unsigned int deadline_ = 0
 
unsigned int interval_
 
state_type volatile state_ = ST_unscheduled
 
alarmnext_ = nullptr
 

Static Protected Attributes

static alarm_queue queue_
 

Detailed Description

Class supporting an alarm with custom callback and repeatability.

This capability supports an unbounded number of alarms multiplexed onto a capture/compare register in the clock::uptime infrastructure. Alarms are given a deadline(), which is normally specified relative to the time at which they are scheduled but can be absolute.

They may have a non-zero interval() which is used to support periodic alarms.

They generally have a callback which is invoked from the uptime interrupt handler performs alarm-specific actions, as well as controlling whether the alarm is rescheduled.

Note
Several member functions are only safe to use when alarms are unscheduled. Alarms are unscheduled during their callbacks; these functions (including set_interval() and set_deadline()) are safe to use in that context.

Member Typedef Documentation

◆ callback_type

using nrfcxx::clock::alarm::callback_type = std::function<bool(alarm& alarm)>

The signature of an alarm callback function.

In addition to performing other operations the callback may change the deadline() of the alarm and, through the return value, control whether the alarm is rescheduled. If interval() is not zero the deadline() when the callback is invoked is interval() ticks past the deadline that caused the callback to be invoked.

Parameters
alarmreference to the alarm associated with the callback. This may be cast to a subclass type to access callback/alarm-specific data.
Returns
true if the alarm should be rescheduled, otherwise false.
Warning
Callbacks are invoked from the uptime RTC FLIH, so should do their thing and exit as fast as possible. Interrupts are not disabled while alarm callbacks are being processed.

Member Enumeration Documentation

◆ state_type

Constants identifying the alarm state.

Enumerator
ST_unscheduled 

Alarm has been constructed but has either not yet been scheduled or has completed.

Transitions to ST_scheduled on a schedule() operation.

ST_scheduled 

Alarm is in the queue to execute at some point in the future.

Transitions to ST_ready (asynchronously) or ST_cancelled (through cancel()).

ST_ready 

Alarm deadline has been reached and the callback will soon be invoked.

If any alarm is in this state the uptime FLIH is executing.

Transitions to ST_in_callback (asynchronously) or ST_cancelled (through cancel()).

ST_in_callback 

The callback is being invoked.

If any alarm is in this state the uptime FLIH is executing.

Transitions to ST_scheduled or ST_unscheduled based on callback_type return value.

ST_cancelled 

The alarm has been cancelled.

No transitions unless schedule() is re-invoked.

Constructor & Destructor Documentation

◆ alarm() [1/3]

nrfcxx::clock::alarm::alarm ( callback_type  callback,
unsigned int  interval = 0,
void *  md = 0 
)
inline

Standard alarm constructor.

Parameters
callbackthe function to be invoked when the alarm fires.
intervalan interval that is added to the previous deadline() prior to invoking callback, to simplify rescheduling repeating alarms. The effect of #no_callback is to reschedule the alarm if and only if interval() is not zero.
mdoptional pointer stored as metadata.

◆ alarm() [2/3]

nrfcxx::clock::alarm::alarm ( callback_type  callback,
void *  md 
)
inline

Overload for common case of configuring with static callback.

The alarm is configured without an initial interval.

Parameters
callbackas usual
mdas usual

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

◆ alarm() [3/3]

template<typename DurT , typename DurT::rep = 0>
constexpr nrfcxx::clock::alarm::alarm ( callback_type  callback,
DurT  interval,
void *  md = 0 
)
inlineconstexpr

Duration-specified alarm constructor.

Parameters
aswith the standard construtor.
intervalan interval specified as a C++ standard duration.
mdoptional pointer stored as metadata.

Member Function Documentation

◆ active()

bool nrfcxx::clock::alarm::active ( ) const
inline

Return true if the alarm state is one of ST_scheduled, ST_ready, or ST_in_callback.

If false the alarm must be scheduled.

◆ cancel()

state_type nrfcxx::clock::alarm::cancel ( )

Cancel a potentially-scheduled alarm.

If the alarm is found in the scheduled or ready queue its state() will be updated to ST_cancelled.

Returns
The state() of the alarm prior to its being cancelled.
Note
You may cancel an alarm in any state or context, but if the returned state is ST_in_callback the cancellation will be superseded by the callback return value. The application should either re-issue the cancel or somehow communicate its desires to the callback so it does not request that the alarm be rescheduled.

◆ for_event()

template<event_set::event_type EVT, bool reschedule = false>
static alarm nrfcxx::clock::alarm::for_event ( event_set events)
inlinestatic

Factory producing an alarm with a callback that sets an event.

This is a fairly common need. While you can do this with:

alarm clock::alarm{[&events](auto&) {
  events.set(EVT);
  return true;
}};

that's pretty verbose. Attempts to push the lambda construction down into a constructor end up pulling in malloc because the resulting object requires external storage either for the values it captures (reference to events, value of event, return value) or because it has to make copy of the function object rather than construct it in place (even if the constant values are captured in template constructor parameters).

The following has the same efficiency and is a little cleaner:

auto alarm = alarm::for_event<EVT, true>(events);

Template Parameters
EVTthe event that is to be set.
reschedulethe value to be returned from the synthesized alarm callback.
Parameters
eventsreference to the event set to which EVT will be added when the alarm fires.
Returns
a new alarm instance with the required callback

◆ schedule()

void nrfcxx::clock::alarm::schedule ( )

Queue the alarm to execute at its current deadline().

Note
This operational is behaviorally identical to invoking schedule_offset() with the signed parameter that would produce deadline(). Consequently if the signed difference between current time and deadline appears negative, the alarm may fire "immediately".
Warning
Invoking this function when the alarm is in states ST_scheduled, ST_ready, or ST_in_callback will result in undefined behavior.

◆ schedule_offset() [1/2]

template<typename DurT >
void nrfcxx::clock::alarm::schedule_offset ( DurT  offset)
inline

Schedule an alarm using a std::chrono duration.

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

◆ schedule_offset() [2/2]

void nrfcxx::clock::alarm::schedule_offset ( int  offset)

Queue the alarm to execute at offset ticks from the current time.

This atomically sets the deadline to the current time plus offset and invokes schedule(). If the offset is negative the deadline will appear to be in the past and the alarm will fire immediately (possibly before this function returns, if interrupts are enabled).

Note
Alarms with a signed offset from current time that is less than two ticks may be delayed up to two ticks to ensure reliable timer configuration. This delay is not reflected in the alarm deadline().
Parameters
offsetthe time until the alarm should go off.
Warning
This function is subject to the state() constraints of schedule().
See also
schedule()

◆ set_deadline()

alarm& nrfcxx::clock::alarm::set_deadline ( unsigned int  deadline)
inline

Set the deadline for the alarm to fire.

This function is generally invoked only from within a callback_type, to change the deadline of an alarm that will be rescheduled.

It may also be used to set the deadline of an unscheduled alarm prior to invoking schedule(), as in the case where alarms do not automatically reschedule and the desired interval must be offset from the last deadline rather than the current time as with schedule_offset().

Parameters
deadlinethe counter value at which the alarm will fire, nominally when the low 32 bits of uptime::now() increment to deadline. Although this is an absolute value, the difference from the current time will be interpreted as signed value when schedule() is invoked (explicitly or implicitly).
Warning
Invoking this function when the alarm is in states ST_scheduled or ST_ready will result in undefined behavior.

◆ set_interval()

alarm& nrfcxx::clock::alarm::set_interval ( unsigned int  interval)
inline

Set the interval() in uptime ticks.

Warning
Invoking this function when the alarm is in states ST_scheduled or ST_ready will result in undefined behavior.

Field Documentation

◆ metadata

void* const nrfcxx::clock::alarm::metadata

Pointer to arbitrary data associated with the alarm.

This exists because in modern C++ you can't generally pull the trick of using offsetof(struct, field) to derive a pointer to a structure from a pointer to a member of that structure. Such a cast is only allowed when the structure is a POD or has standard layout, which excludes anything that has non-static data members that are references. As callbacks are passed pointers to alarms, and the operation of the callback may require access to sibling members, casting this pointer instead provides a solution:

bool my_callback (clock::alarm& alarm)
{
   auto self = static_cast<my_container*>(alarm.metadata);
   self->events.set(self.event);
   return false;
}

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