microbit-dal/source/MicroBitSystemTimer.cpp

139 lines
4.0 KiB
C++
Raw Normal View History

/**
* Definitions for the MicroBit system timer.
*
* This module provides:
*
* 1) a concept of global system time since power up
* 2) a simple periodic multiplexing API for the underlying mbed implementation.
*
* The latter is useful to avoid costs associated with multiple mbed Ticker instances
* in microbit-dal components, as each incurs a significant additional RAM overhead (circa 80 bytes).
*/
#include "MicroBit.h"
/*
* Time since power on. Measured in milliseconds.
* When stored as an unsigned long, this gives us approx 50 days between rollover, which is ample. :-)
*/
static unsigned long ticks = 0;
static unsigned int tick_period = 0;
// Array of components which are iterated during a system tick
static MicroBitComponent* systemTickComponents[MICROBIT_SYSTEM_COMPONENTS];
// Periodic callback interrupt
static Ticker timer;
/**
* Initialises the system wide timer.
* This must be called before any components register to receive periodic periodic callbacks.
*
* @param timer_period The initial period between interrupts, in millseconds.
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if period is illegal.
*/
int system_timer_init(int period)
{
return system_timer_set_period(period);
}
/*
* Reconfigures the system wide timer to the given period in milliseconds.
*
* @param period the new period of the timer in milliseconds
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if period < 1
*/
int system_timer_set_period(int period)
{
if (period < 1)
return MICROBIT_INVALID_PARAMETER;
// If a timer is already running, ensure it is disabled before reconfiguring.
if (tick_period)
timer.detach();
// register a period callback to drive the scheduler and any other registered components.
tick_period = period;
timer.attach_us(system_timer_tick, period * 1000);
return MICROBIT_OK;
}
/*
* Provides the current tick period in milliseconds
* @return the current tick period in milliseconds
*/
int system_timer_get_period()
{
return tick_period;
}
/*
* Determines the time since the device was powered on.
* @return the current time since poweron in milliseconds
*/
unsigned long system_timer_current_time()
{
return ticks;
}
/**
* Timer callback. Called from interrupt context, once per period.
* Simply checks to determine if any fibers blocked on the sleep queue need to be woken up
* and made runnable.
*/
void system_timer_tick()
{
// increment our real-time counter.
ticks += system_timer_get_period();
// Update any components registered for a callback
for(int i = 0; i < MICROBIT_SYSTEM_COMPONENTS; i++)
if(systemTickComponents[i] != NULL)
systemTickComponents[i]->systemTick();
}
/**
* Add a component to the array of system components. This component will then receive
* period callbacks, once every tick period.
*
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
*/
int system_timer_add_component(MicroBitComponent *component)
{
int i = 0;
while(systemTickComponents[i] != NULL && i < MICROBIT_SYSTEM_COMPONENTS)
i++;
if(i == MICROBIT_SYSTEM_COMPONENTS)
return MICROBIT_NO_RESOURCES;
systemTickComponents[i] = component;
return MICROBIT_OK;
}
/**
* remove a component from the array of system components. this component will no longer receive
* period callbacks.
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added.
*/
int system_timer_remove_component(MicroBitComponent *component)
{
int i = 0;
while(systemTickComponents[i] != component && i < MICROBIT_SYSTEM_COMPONENTS)
i++;
if(i == MICROBIT_SYSTEM_COMPONENTS)
return MICROBIT_INVALID_PARAMETER;
systemTickComponents[i] = NULL;
return MICROBIT_OK;
}