embassy-time-driver

Crates

git

Versions

default

Flavors

embassy_time_driver

Trait Driver

source
pub trait Driver:
    Send
    + Sync
    + 'static {
    // Required methods
    fn now(&self) -> u64;
    unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>;
    fn set_alarm_callback(
        &self,
        alarm: AlarmHandle,
        callback: fn(_: *mut ()),
        ctx: *mut (),
    );
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool;
}
Expand description

Time driver

Required Methods§

source

fn now(&self) -> u64

Return the current timestamp in ticks.

Implementations MUST ensure that:

  • This is guaranteed to be monotonic, i.e. a call to now() will always return a greater or equal value than earlier calls. Time can’t “roll backwards”.
  • It “never” overflows. It must not overflow in a sufficiently long time frame, say in 10_000 years (Human civilization is likely to already have self-destructed 10_000 years from now.). This means if your hardware only has 16bit/32bit timers you MUST extend them to 64-bit, for example by counting overflows in software, or chaining multiple timers together.
source

unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>

Try allocating an alarm handle. Returns None if no alarms left. Initially the alarm has no callback set, and a null ctx pointer.

§Safety

It is UB to make the alarm fire before setting a callback.

source

fn set_alarm_callback( &self, alarm: AlarmHandle, callback: fn(_: *mut ()), ctx: *mut (), )

Set the callback function to be called when the alarm triggers. The callback may be called from any context (interrupt or thread mode).

source

fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool

Set an alarm at the given timestamp.

§Behavior

If timestamp is in the future, set_alarm schedules calling the callback function at that time, and returns true.

If timestamp is in the past, set_alarm has two allowed behaviors. Implementations can pick whether to:

  • Schedule calling the callback function “immediately”, as if the requested timestamp was “now+epsilon” and return true, or
  • Not schedule the callback, and return false.

Callers must ensure to behave correctly with either behavior.

When callback is called, it is guaranteed that now() will return a value greater than or equal to timestamp.

§Reentrancy

Calling the callback from set_alarm synchronously is not allowed. If the implementation chooses the first option above, it must still call the callback from another context (i.e. an interrupt handler or background thread), it’s not allowed to call it synchronously in the context set_alarm is running.

The reason for the above is callers are explicitly permitted to do both of:

  • Lock a mutex in the alarm callback.
  • Call set_alarm while having that mutex locked.

If set_alarm called the callback synchronously, it’d cause a deadlock or panic because it’d cause the mutex to be locked twice reentrantly in the same context.

§Overwriting alarms

Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any.

§Unsetting the alarm

There is no unset_alarm API. Instead, callers can call set_alarm with timestamp set to u64::MAX.

This allows for more efficient implementations, since they don’t need to distinguish between the “alarm set” and “alarm not set” cases, thanks to the fact “Alarm set for u64::MAX” is effectively equivalent for “alarm not set”.

This means implementations need to be careful to avoid timestamp overflows. The recommendation is to make timestamp be in the same units as hardware ticks to avoid any conversions, which makes avoiding overflow easier.

Implementors§