microbit: Refactor of periodc timer callbacks
- Factored periodic timer funcitonality out of fiber scheduler and into a new SystemTimer module module. - Enapsulated "ticks" variable within SystemTimer module, with accessor funciton. - Added accessor/mutator functions to get and set the tick period. - Added a class wrapper to permit periodic callbacks to both C and C++ functions. - Updated all references in microbit-dal to use this refactored API.
This commit is contained in:
parent
8a06a4e3be
commit
9218e647e0
13 changed files with 269 additions and 162 deletions
|
@ -7,6 +7,7 @@
|
|||
#include "MicroBitHeapAllocator.h"
|
||||
#include "MicroBitPanic.h"
|
||||
#include "ErrorNo.h"
|
||||
#include "MicroBitSystemTimer.h"
|
||||
#include "Matrix4.h"
|
||||
#include "MicroBitCompat.h"
|
||||
#include "MicroBitComponent.h"
|
||||
|
|
|
@ -88,8 +88,8 @@
|
|||
|
||||
// Scheduling quantum (milliseconds)
|
||||
// Also used to drive the micro:bit runtime system ticker.
|
||||
#ifndef FIBER_TICK_PERIOD_MS
|
||||
#define FIBER_TICK_PERIOD_MS 6
|
||||
#ifndef SYSTEM_TICK_PERIOD_MS
|
||||
#define SYSTEM_TICK_PERIOD_MS 6
|
||||
#endif
|
||||
|
||||
//
|
||||
|
|
|
@ -79,21 +79,6 @@ extern Fiber *currentFiber;
|
|||
*/
|
||||
void scheduler_init(MicroBitMessageBus *_messageBus);
|
||||
|
||||
/*
|
||||
* Reconfigures the system wide timer to the given period in milliseconds.
|
||||
*
|
||||
* @param speedMs the new period of the timer in milliseconds
|
||||
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedMs < 1
|
||||
*
|
||||
* @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick()
|
||||
*/
|
||||
int scheduler_set_tick_period(int speedMs);
|
||||
|
||||
/*
|
||||
* Returns the currently used tick speed in milliseconds
|
||||
*/
|
||||
int scheduler_get_tick_period();
|
||||
|
||||
/**
|
||||
* Determines if the fiber scheduler is operational.
|
||||
* @return 1 if the fber scheduler is running, 0 otherwise.
|
||||
|
@ -163,7 +148,7 @@ void schedule();
|
|||
void fiber_sleep(unsigned long t);
|
||||
|
||||
/**
|
||||
* Timer callback. Called from interrupt context, once every FIBER_TICK_PERIOD_MS milliseconds.
|
||||
* Timer callback. Called from interrupt context, once every SYSTEM_TICK_PERIOD_MS milliseconds by default.
|
||||
* Simply checks to determine if any fibers blocked on the sleep queue need to be woken up
|
||||
* and made runnable.
|
||||
*/
|
||||
|
@ -265,21 +250,6 @@ void idle();
|
|||
*/
|
||||
void idle_task();
|
||||
|
||||
/**
|
||||
* add a component to the array of system components which invocate the systemTick member function during a systemTick
|
||||
*
|
||||
* @param component The component to add.
|
||||
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
|
||||
*/
|
||||
int fiber_add_system_component(MicroBitComponent *component);
|
||||
|
||||
/**
|
||||
* remove a component from the array of system components
|
||||
* @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 fiber_remove_system_component(MicroBitComponent *component);
|
||||
|
||||
/**
|
||||
* add a component to the array of of idle thread components.
|
||||
* isIdleCallbackNeeded is polled during a systemTick to determine if the idle thread should jump to the front of the queue
|
||||
|
@ -313,10 +283,4 @@ extern "C" void save_context(Cortex_M0_TCB *tcb, uint32_t stack);
|
|||
extern "C" void save_register_context(Cortex_M0_TCB *tcb);
|
||||
extern "C" void restore_register_context(Cortex_M0_TCB *tcb);
|
||||
|
||||
/**
|
||||
* Time since power on. Measured in milliseconds.
|
||||
* When stored as an unsigned long, this gives us approx 50 days between rollover, which is ample. :-)
|
||||
*/
|
||||
extern unsigned long ticks;
|
||||
|
||||
#endif
|
||||
|
|
97
inc/MicroBitSystemTimer.h
Normal file
97
inc/MicroBitSystemTimer.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* 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).
|
||||
*/
|
||||
|
||||
#ifndef MICROBIT_SYSTEM_TIMER_H
|
||||
#define MICROBIT_SYSTEM_TIMER_H
|
||||
|
||||
#include "mbed.h"
|
||||
#include "MicroBitConfig.h"
|
||||
#include "MicroBitComponent.h"
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int system_timer_init(int 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);
|
||||
|
||||
/*
|
||||
* Provides the current tick period in milliseconds
|
||||
* @return the current tick period in milliseconds
|
||||
*/
|
||||
int system_timer_get_period();
|
||||
|
||||
/*
|
||||
* Determines the time since the device was powered on.
|
||||
* @return the current time since poweron in milliseconds
|
||||
*/
|
||||
unsigned long system_timer_current_time();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* A simple C/C++ wrapper to allow periodic callbacks to standard C functions transparently.
|
||||
*/
|
||||
class MicroBitSystemTimerCallback : MicroBitComponent
|
||||
{
|
||||
void (*fn)(void);
|
||||
|
||||
/**
|
||||
* Creates an object that receives periodic callbacks from the system timer,
|
||||
* and, in turn, calls a plain C function as provided as a parameter.
|
||||
*/
|
||||
public:
|
||||
MicroBitSystemTimerCallback(void (*function)(void))
|
||||
{
|
||||
fn = function;
|
||||
system_timer_add_component(this);
|
||||
}
|
||||
|
||||
void systemTick()
|
||||
{
|
||||
fn();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -16,6 +16,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
|
|||
"MicroBitCompass.cpp"
|
||||
"MicroBitEvent.cpp"
|
||||
"MicroBitFiber.cpp"
|
||||
"MicroBitSystemTimer.cpp"
|
||||
"ManagedString.cpp"
|
||||
"Matrix4.cpp"
|
||||
"MicroBitAccelerometer.cpp"
|
||||
|
|
|
@ -112,8 +112,12 @@ void MicroBit::init()
|
|||
// Bring up the heap allocator, and reclaim as much memory from SoftDevice as possible.
|
||||
microbit_heap_init();
|
||||
|
||||
// Bring up fiber scheduler. Wait a little while for state to stabilise.
|
||||
// Bring up the system timer.
|
||||
system_timer_init(SYSTEM_TICK_PERIOD_MS);
|
||||
|
||||
// Bring up fiber scheduler.
|
||||
scheduler_init(&messageBus);
|
||||
|
||||
// Load any stored calibration data from persistent storage.
|
||||
MicroBitStorage s = MicroBitStorage();
|
||||
MicroBitConfigurationBlock *b = s.getConfigurationBlock();
|
||||
|
@ -536,7 +540,7 @@ void MicroBit::seedRandom(uint32_t seed)
|
|||
*/
|
||||
int MicroBit::addSystemComponent(MicroBitComponent *component)
|
||||
{
|
||||
return fiber_add_system_component(component);
|
||||
return system_timer_add_component(component);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -547,7 +551,7 @@ int MicroBit::addSystemComponent(MicroBitComponent *component)
|
|||
*/
|
||||
int MicroBit::removeSystemComponent(MicroBitComponent *component)
|
||||
{
|
||||
return fiber_remove_system_component(component);
|
||||
return system_timer_remove_component(component);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -581,7 +585,7 @@ int MicroBit::removeIdleComponent(MicroBitComponent *component)
|
|||
*/
|
||||
unsigned long MicroBit::systemTime()
|
||||
{
|
||||
return ticks;
|
||||
return system_timer_current_time();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ MicroBitButton::MicroBitButton(uint16_t id, PinName name, MicroBitButtonEventCon
|
|||
this->eventConfiguration = eventConfiguration;
|
||||
this->downStartTime = 0;
|
||||
this->sigma = 0;
|
||||
fiber_add_system_component(this);
|
||||
system_timer_add_component(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,7 +84,7 @@ void MicroBitButton::systemTick()
|
|||
MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_DOWN);
|
||||
|
||||
//Record the time the button was pressed.
|
||||
downStartTime=ticks;
|
||||
downStartTime = system_timer_current_time();
|
||||
}
|
||||
|
||||
// Check to see if we have on->off state change.
|
||||
|
@ -96,7 +96,7 @@ void MicroBitButton::systemTick()
|
|||
if (eventConfiguration == MICROBIT_BUTTON_ALL_EVENTS)
|
||||
{
|
||||
//determine if this is a long click or a normal click and send event
|
||||
if((ticks - downStartTime) >= MICROBIT_BUTTON_LONG_CLICK_TIME)
|
||||
if((system_timer_current_time() - downStartTime) >= MICROBIT_BUTTON_LONG_CLICK_TIME)
|
||||
MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_LONG_CLICK);
|
||||
else
|
||||
MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_CLICK);
|
||||
|
@ -104,7 +104,7 @@ void MicroBitButton::systemTick()
|
|||
}
|
||||
|
||||
//if button is pressed and the hold triggered event state is not triggered AND we are greater than the button debounce value
|
||||
if((status & MICROBIT_BUTTON_STATE) && !(status & MICROBIT_BUTTON_STATE_HOLD_TRIGGERED) && (ticks - downStartTime) >= MICROBIT_BUTTON_HOLD_TIME)
|
||||
if((status & MICROBIT_BUTTON_STATE) && !(status & MICROBIT_BUTTON_STATE_HOLD_TRIGGERED) && (system_timer_current_time() - downStartTime) >= MICROBIT_BUTTON_HOLD_TIME)
|
||||
{
|
||||
//set the hold triggered event flag
|
||||
status |= MICROBIT_BUTTON_STATE_HOLD_TRIGGERED;
|
||||
|
@ -128,5 +128,5 @@ int MicroBitButton::isPressed()
|
|||
*/
|
||||
MicroBitButton::~MicroBitButton()
|
||||
{
|
||||
fiber_remove_system_component(this);
|
||||
system_timer_remove_component(this);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) :
|
|||
if (!this->defaultDisplay)
|
||||
this->defaultDisplay = this;
|
||||
|
||||
fiber_add_system_component(this);
|
||||
system_timer_add_component(this);
|
||||
|
||||
status |= MICROBIT_COMPONENT_RUNNING;
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ void MicroBitDisplay::render()
|
|||
|
||||
//timer does not have enough resolution for brightness of 1. 23.53 us
|
||||
if(brightness != MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS && brightness > MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS)
|
||||
renderTimer.attach_us(this, &MicroBitDisplay::renderFinish, (((brightness * 950) / (MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS)) * scheduler_get_tick_period()));
|
||||
renderTimer.attach_us(this, &MicroBitDisplay::renderFinish, (((brightness * 950) / (MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS)) * system_timer_get_period()));
|
||||
|
||||
//this will take around 23us to execute
|
||||
if(brightness <= MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS)
|
||||
|
@ -247,7 +247,7 @@ MicroBitDisplay::animationUpdate()
|
|||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
return;
|
||||
|
||||
animationTick += FIBER_TICK_PERIOD_MS;
|
||||
animationTick += system_timer_get_period();
|
||||
|
||||
if(animationTick >= animationDelay)
|
||||
{
|
||||
|
@ -939,17 +939,12 @@ void MicroBitDisplay::setDisplayMode(DisplayMode mode)
|
|||
if(mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE)
|
||||
{
|
||||
//to reduce the artifacts on the display - increase the tick
|
||||
if(scheduler_get_tick_period() != MICROBIT_LIGHT_SENSOR_TICK_PERIOD)
|
||||
scheduler_set_tick_period(MICROBIT_LIGHT_SENSOR_TICK_PERIOD);
|
||||
if(system_timer_get_period() != MICROBIT_LIGHT_SENSOR_TICK_PERIOD)
|
||||
system_timer_set_period(MICROBIT_LIGHT_SENSOR_TICK_PERIOD);
|
||||
}
|
||||
|
||||
if(this->mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE && mode != DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE)
|
||||
{
|
||||
|
||||
//if we previously were in light sense mode - return to our default.
|
||||
if(scheduler_get_tick_period() != FIBER_TICK_PERIOD_MS)
|
||||
scheduler_set_tick_period(FIBER_TICK_PERIOD_MS);
|
||||
|
||||
delete this->lightSensor;
|
||||
|
||||
this->lightSensor = NULL;
|
||||
|
@ -1216,5 +1211,5 @@ int MicroBitDisplay::readLightLevel()
|
|||
*/
|
||||
MicroBitDisplay::~MicroBitDisplay()
|
||||
{
|
||||
fiber_remove_system_component(this);
|
||||
system_timer_remove_component(this);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ MicroBitEvent::MicroBitEvent(uint16_t source, uint16_t value, MicroBitEventLaunc
|
|||
{
|
||||
this->source = source;
|
||||
this->value = value;
|
||||
this->timestamp = ticks;
|
||||
this->timestamp = system_timer_current_time();
|
||||
|
||||
if(mode != CREATE_ONLY)
|
||||
this->fire(mode);
|
||||
|
@ -34,7 +34,7 @@ MicroBitEvent::MicroBitEvent()
|
|||
{
|
||||
this->source = 0;
|
||||
this->value = 0;
|
||||
this->timestamp = ticks;
|
||||
this->timestamp = system_timer_current_time();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,13 +25,6 @@ static Fiber *sleepQueue = NULL; // The list of blocked fibers
|
|||
static Fiber *waitQueue = NULL; // The list of blocked fibers waiting on an event.
|
||||
static Fiber *fiberPool = NULL; // Pool of unused fibers, just waiting for a job to do.
|
||||
|
||||
/*
|
||||
* Time since power on. Measured in milliseconds.
|
||||
* When stored as an unsigned long, this gives us approx 50 days between rollover, which is ample. :-)
|
||||
*/
|
||||
unsigned long ticks = 0;
|
||||
static unsigned int tickPeriod = FIBER_TICK_PERIOD_MS;
|
||||
|
||||
/*
|
||||
* Scheduler wide flags
|
||||
*/
|
||||
|
@ -43,15 +36,9 @@ static uint8_t fiber_flags = 0;
|
|||
*/
|
||||
static MicroBitMessageBus *messageBus = NULL;
|
||||
|
||||
// Array of components which are iterated during a system tick
|
||||
static MicroBitComponent* systemTickComponents[MICROBIT_SYSTEM_COMPONENTS];
|
||||
|
||||
// Array of components which are iterated during idle thread execution, isIdleCallbackNeeded is polled during a systemTick.
|
||||
static MicroBitComponent* idleThreadComponents[MICROBIT_IDLE_COMPONENTS];
|
||||
|
||||
// Periodic callback interrupt
|
||||
static Ticker fiberSchedulerTicker;
|
||||
|
||||
/**
|
||||
* Utility function to add the currenty running fiber to the given queue.
|
||||
* Perform a simple add at the head, to avoid complexity,
|
||||
|
@ -190,39 +177,11 @@ void scheduler_init(MicroBitMessageBus *_messageBus)
|
|||
}
|
||||
|
||||
// register a period callback to drive the scheduler and any other registered components.
|
||||
fiberSchedulerTicker.attach_us(scheduler_tick, tickPeriod * 1000);
|
||||
new MicroBitSystemTimerCallback(scheduler_tick);
|
||||
|
||||
fiber_flags |= MICROBIT_SCHEDULER_RUNNING;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reconfigures the system wide timer to the given period in milliseconds.
|
||||
*
|
||||
* @param speedMs the new period of the timer in milliseconds
|
||||
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedMs < 1
|
||||
*
|
||||
* @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick()
|
||||
*/
|
||||
int scheduler_set_tick_period(int speedMs)
|
||||
{
|
||||
if(speedMs < 1)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
tickPeriod = speedMs;
|
||||
fiberSchedulerTicker.detach();
|
||||
fiberSchedulerTicker.attach_us(scheduler_tick, tickPeriod * 1000);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the currently used tick speed in milliseconds
|
||||
*/
|
||||
int scheduler_get_tick_period()
|
||||
{
|
||||
return tickPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the fiber scheduler is operational.
|
||||
* @return 1 if the fber scheduler is running, 0 otherwise.
|
||||
|
@ -236,7 +195,7 @@ int fiber_scheduler_running()
|
|||
}
|
||||
|
||||
/**
|
||||
* Timer callback. Called from interrupt context, once every FIBER_TICK_PERIOD_MS milliseconds, by default.
|
||||
* Timer callback. Called from interrupt context, once every SYSTEM_TICK_PERIOD_MS milliseconds, by default.
|
||||
* Simply checks to determine if any fibers blocked on the sleep queue need to be woken up
|
||||
* and made runnable.
|
||||
*/
|
||||
|
@ -245,15 +204,12 @@ void scheduler_tick()
|
|||
Fiber *f = sleepQueue;
|
||||
Fiber *t;
|
||||
|
||||
// increment our real-time counter.
|
||||
ticks += scheduler_get_tick_period();
|
||||
|
||||
// Check the sleep queue, and wake up any fibers as necessary.
|
||||
while (f != NULL)
|
||||
{
|
||||
t = f->next;
|
||||
|
||||
if (ticks >= f->context)
|
||||
if (system_timer_current_time() >= f->context)
|
||||
{
|
||||
// Wakey wakey!
|
||||
dequeue_fiber(f);
|
||||
|
@ -262,11 +218,6 @@ void scheduler_tick()
|
|||
|
||||
f = t;
|
||||
}
|
||||
|
||||
// Update any components registered for a callback
|
||||
for(int i = 0; i < MICROBIT_SYSTEM_COMPONENTS; i++)
|
||||
if(systemTickComponents[i] != NULL)
|
||||
systemTickComponents[i]->systemTick();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -355,7 +306,7 @@ void fiber_sleep(unsigned long t)
|
|||
}
|
||||
|
||||
// Calculate and store the time we want to wake up.
|
||||
f->context = ticks + t;
|
||||
f->context = system_timer_current_time() + t;
|
||||
|
||||
// Remove fiber from the run queue
|
||||
dequeue_fiber(f);
|
||||
|
@ -785,50 +736,6 @@ void schedule()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a component to to the collection of those invoked when the scheduler's periodic timer is triggered.
|
||||
* The given component is called on each interrupt, within interrupt context.
|
||||
*
|
||||
* @param component The component to add.
|
||||
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
|
||||
* @note this will be converted into a dynamic list of components
|
||||
*/
|
||||
int fiber_add_system_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 components
|
||||
* @param component The component to remove.
|
||||
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added.
|
||||
* @note this will be converted into a dynamic list of components
|
||||
*/
|
||||
int fiber_remove_system_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* add a component to the array of components which invocate the systemTick member function during a systemTick
|
||||
* @param component The component to add.
|
||||
|
|
|
@ -265,7 +265,7 @@ int MicroBitMessageBus::isIdleCallbackNeeded()
|
|||
*
|
||||
* Example:
|
||||
* @code
|
||||
* MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_DOWN,ticks,CREATE_ONLY);
|
||||
* MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_DOWN,CREATE_ONLY);
|
||||
* evt.fire();
|
||||
*
|
||||
* //OR YOU CAN DO THIS...
|
||||
|
|
138
source/MicroBitSystemTimer.cpp
Normal file
138
source/MicroBitSystemTimer.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -98,12 +98,12 @@ void MicroBitThermometer::idleTick()
|
|||
}
|
||||
|
||||
/**
|
||||
* Determines if we're due to take another temeoratur reading
|
||||
* Determines if we're due to take another temperature reading
|
||||
* @return 1 if we're due to take a temperature reading, 0 otherwise.
|
||||
*/
|
||||
int MicroBitThermometer::isSampleNeeded()
|
||||
{
|
||||
return ticks >= sampleTime;
|
||||
return system_timer_current_time() >= sampleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,7 +167,7 @@ void MicroBitThermometer::updateTemperature()
|
|||
temperature = processorTemperature / 4;
|
||||
|
||||
// Schedule our next sample.
|
||||
sampleTime = ticks + samplePeriod;
|
||||
sampleTime = system_timer_current_time() + samplePeriod;
|
||||
|
||||
// Send an event to indicate that we'e updated our temperature.
|
||||
MicroBitEvent e(id, MICROBIT_THERMOMETER_EVT_UPDATE);
|
||||
|
|
Loading…
Reference in a new issue