![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Testing [Andrew L] mbos RTOS for mbed Simply by copying code for main.cpp from mbos.h-comments
Revision 0:a61d29450691, committed 2011-05-05
- Comitter:
- chalikias
- Date:
- Thu May 05 07:34:12 2011 +0000
- Commit message:
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Thu May 05 07:34:12 2011 +0000 @@ -0,0 +1,86 @@ + // 2011.05.05 NX + // This a test of [Andrew L] mbos + // main.c copied from mbos.h comments + // ** A 3d task added ** + + + //* A typical simple example with two tasks, and one timer, might look like this: + //* @code + // mbos Blinky demonstration. + // Task 1 toggles LED1 every second, under control of a timer. It then posts an event to + // task 2 which flashed LED2 briefly. + #include "mbed.h" + #include "mbos.h" + + #define TASK1_ID 1 // Id for task 1 (idle task is 0) + #define TASK1_PRIO 50 // priority for task 1 + #define TASK1_STACK_SZ 32 // stack size for task 1 in words + + #define TASK2_ID 2 // Id for task 2 + #define TASK2_PRIO 60 // priority for task 2 + #define TASK2_STACK_SZ 32 // stack size for task 2 in words + + #define TASK3_ID 3 // Id for task 3 + #define TASK3_PRIO 70 // priority for task 3 + #define TASK3_STACK_SZ 32 // stack size for task 2 in words + + #define TIMER0_ID 0 // Id for timer 0 + #define TIMER0_PERIOD 1000 // Time period in milliseconds + #define TIMER0_EVENT 1 // Event flag (1 << 0) + + #define T1_TO_T2_EVENT 2 // Event flag (1 << 1) + #define T2_TO_T3_EVENT 2 // Event flag (1 << 1) + + void task1(void); // task function prototypes + void task2(void); + void task3(void); + + DigitalOut led1(LED1); + DigitalOut led2(LED2); + DigitalOut led3(LED3); + mbos os(3, 1); // Instantiate mbos with 3 tasks & 1 timer + + int main(void) + { + // Configure tasks and timers + os.CreateTask(TASK1_ID, TASK1_PRIO, TASK1_STACK_SZ, task1); + os.CreateTask(TASK2_ID, TASK2_PRIO, TASK2_STACK_SZ, task2); + + os.CreateTask(TASK3_ID, TASK3_PRIO, TASK3_STACK_SZ, task3); + + os.CreateTimer(TIMER0_ID, TIMER0_EVENT, TASK1_ID); + // Start mbos + os.Start(); + // never return! + } + + void task1(void) + { + os.SetTimer(TIMER0_ID, TIMER0_PERIOD, TIMER0_PERIOD); + while(1){ + os.WaitEvent(TIMER0_EVENT); + led1 = !led1; + os.SetEvent(T1_TO_T2_EVENT, TASK2_ID); + } + } + + void task2(void) + { + while(1){ + os.WaitEvent(T1_TO_T2_EVENT); + led2 = 1; + wait_ms(100); + led2 = 0; + os.SetEvent(T2_TO_T3_EVENT, TASK3_ID); + } + } + + void task3(void) + { + while(1){ + os.WaitEvent(T2_TO_T3_EVENT); + led3 = 1; + wait_ms(100); + led3 = 0; + } + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Thu May 05 07:34:12 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbos.cpp Thu May 05 07:34:12 2011 +0000 @@ -0,0 +1,347 @@ +/*********************************************************************************** + * m b o s R T O S F O R m b e d (ARM CORTEX M3) + * + * Copyright (c) 2010 - 2011 Andrew Levido + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "mbos.h" +#include "mbed.h" + +#define MAX_PRIO 99 // maximum priority +#define READY MAX_PRIO + 1 // always > MAX_PRIO +#define WAITING 0 // aways 0 +#define DEFAULT_IDLE_STACK_SZ 32 // in words +#define MAX_TASKS 99 // tasks 0.. 99 including idle +#define MAX_TIMERS 99 // timers 0..99 +#define MAX_RESOURCES 99 // resources 0..99 +#define MIN_STACKSZ 32 // enough to run an empty function +#define TICKS_PER_SECOND 1000 // 1ms Ticks + +typedef struct _tcb{ // task control block + uint id; + uint *stack; + uint priostate; + uint eventlist; + uint eventmask; + uint *stacklimit; +}_tcb_t; + +typedef struct _timer{ // timer cotrol block + uint timer; + uint reload; + uint event; + uint task; +}_timer_t; + +typedef struct _rcb{ // resource control block + uint lock; + uint priority; + uint taskprio; +}_resource_t; + +extern "C" void _startos(void); // Assembly routine to start the scheduler +extern "C" void _swap(void); // Assembly routine to set PendSV exception +extern "C" void SysTick_Handler(void); // Override weak declaration in startup file +extern "C" void _stackerror(uint task); // Stack error function called by assembler + +extern void __attribute__((__weak__)) mbosIdleTask(void); // Allow user to write their own idle task + +// Static Variables +uint _hardstacklimit; // stack limit +_tcb_t **_tasklist; // pointer to task list +_tcb_t *_tasks; // pointer to task control block 0 +_timer_t *_timers; // pointer to timer control block 0 +_resource_t *_resources; // pointer to resource control block 0 +uint _numtasks; // number of tasks (including idle) +uint _numtimers; // number of timers +uint _numresources; // number of resources +uint _tasklistsize; // task list length in bytes + +// Default Idle Task ------------------------------------------------------------------- +void _idletask(void) { while(1); } // Default idle task + +// Constructor ------------------------------------------------------------------------- +mbos::mbos(uint ntasks, uint ntimers, uint nresources) +{ + uint i; + + ntasks += 1; + // Create the tcblist, zero initialised + if(ntasks > MAX_TASKS || ntasks < 1) error("mbos::mbos - %i is an invalid number of tasks\n", ntasks); + _tasklist = (_tcb_t**)calloc(sizeof(_tcb_t*), ntasks); + if(_tasklist == 0) error("mbos::mbos - Insufficient memory to create Tasklist\n"); + + // Create the tcbs + _tasklist[0] = (_tcb_t*)calloc(sizeof(_tcb_t), ntasks); + if(_tasklist[0] == 0) error("mbos::mbos - Insufficient memory to create TCBs\n"); + for(i = 1; i < ntasks; i++){ + _tasklist[i] = _tasklist[i - 1] + 1; + } + // Create the timers and clear them + if(ntimers > MAX_TIMERS + 1) error("mbos::mbos - %i is an invalid number of Timers\n", ntimers); + _timers = (_timer_t*)calloc(sizeof(_timer_t), ntimers); + if(_timers == 0) error("mbos::mbos - Insufficient memory to create Timers"); + + // create the resources & clear them + if(nresources > MAX_RESOURCES + 1) error("mbos::mbos - %i is an invalid number of Resources\n", nresources); + _resources = (_resource_t*)calloc(sizeof(_resource_t), nresources); + if(_resources == 0) error("mbos::mbos - Insufficient memory to create Resources"); + _hardstacklimit = (uint)malloc(1); + if(_hardstacklimit == 0) error("mbos::mbos - Insufficient memory to create HardStackLimit"); + _numtasks = ntasks; + _numtimers = ntimers; + _numresources = nresources; + _tasks = _tasklist[0]; +} +// Create Tasks Function -------------------------------------------------------------- +void mbos::CreateTask(uint id, uint priority, uint stacksz, void (*fun)(void)) +{ + uint* stackbase; + + // check bounds + if(id >= _numtasks || id < 1) error("mbos::CreateTask - %i is an invalid task id\n", id); + if(priority > MAX_PRIO) error("mbos::CreateTask - %i is an invalid priority for Task %i\n", priority, id); + if(stacksz < MIN_STACKSZ) stacksz = MIN_STACKSZ; + + // fill tcb + if(_tasks[id].id == 0) _tasks[id].id = id; + else error("mbos::CreateTask - Task %i already created\n", id); + _tasks[id].priostate = READY + priority; + _tasks[id].eventlist = 0; + _tasks[id].eventmask = 0; + stackbase = (uint*)malloc(stacksz * 4); + if(stackbase == 0) error("mbos::CreateTask - Insufficient memory to create Task %i\n", id); + _tasks[id].stacklimit = stackbase; + _tasks[id].stack = _initstack(stackbase + stacksz, fun); +} +// Start OS function ------------------------------------------------------------------- +void mbos::Start(uint stacksize) +{ + uint * stackbase; + + // Fill idle tcb and initialise idle stack + _tasks[0].priostate = READY; + _tasks[0].id = 0; + _tasks[0].eventlist = 0; + _tasks[0].eventmask = 0; + if(mbosIdleTask){ + if(stacksize < MIN_STACKSZ) stacksize = MIN_STACKSZ; + stackbase = (uint*)malloc(stacksize * 4); + if(stackbase == 0) error("mbos::Start - Insufficient memory to create idle task\n"); + _tasks[0].stacklimit = stackbase; + _tasks[0].stack = _initstack(stackbase + stacksize, mbosIdleTask); + } + else { + stackbase = (uint*)malloc(DEFAULT_IDLE_STACK_SZ * 4); + if(stackbase == 0) error("mbos::Start - Insufficient memory to create idle task\n"); + _tasks[0].stacklimit = stackbase; + _tasks[0].stack = _initstack(stackbase + DEFAULT_IDLE_STACK_SZ, _idletask); + } + _tasklistsize = 4 * (_numtasks - 1); + SysTick_Config(SystemCoreClock / TICKS_PER_SECOND); + NVIC_SetPriority(SysTick_IRQn, 0); + _startos(); + + while(1); +} +// OS Tick Function ------------------------------------------------------------------- +void SysTick_Handler(void) +{ + uint i; + + __disable_irq(); + + for(i = 0; i < _numtimers; i++){ + if(_timers[i].timer){ + _timers[i].timer--; + if(_timers[i].timer == 0){ + _timers[i].timer = _timers[i].reload; + if(_tasks[_timers[i].task].eventmask & _timers[i].event){ + _tasks[_timers[i].task].eventlist |= _timers[i].event; + _tasks[_timers[i].task].priostate += READY; + } + } + } + } + if((__return_address() & 0x08) == 0) { // called from Handler, so swap later + __enable_irq(); + return; + } + _swap(); + __enable_irq(); +} +// Get Task id Function ----------------------------------------------------------------- +uint mbos::GetTask(void) +{ + return _tasklist[0]->id; +} +// Set Priority Function ---------------------------------------------------------------- +void mbos::SetPriority(uint priority) +{ + if(_tasklist[0]->id == 0) return; + if(priority > MAX_PRIO) error("mbos::SetPriority - %i is an invalid priority\n", priority); + _tasklist[0]->priostate = priority + READY; +} +// Get Priority Function ---------------------------------------------------------------- +uint mbos::GetPriority(void) +{ + return _tasklist[0]->priostate - READY; +} +// Wait Event Function ------------------------------------------------------------------ +void mbos::WaitEvent(uint event) +{ + if(_tasklist[0]->id == 0) return; + if(event == 0) return; + __disable_irq(); + _tasklist[0]->eventlist = 0; + _tasklist[0]->eventmask = event; + _tasklist[0]->priostate -= READY; + _swap(); + __enable_irq(); +} +// Set Event Function -------------------------------------------------------------------- +void mbos::SetEvent(uint event, uint task) +{ + // check bounds + if(task >= _numtasks || (task < 1)) return; + + __disable_irq(); + if(_tasks[task].eventmask & event){ + _tasks[task].eventlist |= event; + _tasks[task].priostate += READY; + } + else{ + __enable_irq(); + return; + } + _swap(); + __enable_irq(); +} +// Get event Function ----------------------------------------------------------------- +uint mbos::GetEvent(void) +{ + return _tasklist[0]->eventlist; +} +// Create Timer Function -------------------------------------------------------------- +void mbos::CreateTimer(uint id, uint task, uint event) +{ + // check bounds + if(id >= _numtimers) error("mbos::CreateTimer - %i is an invalid timer id\n", id); + if(task < 1|| task >= _numtasks) error("mbos::CreateTimer - %i is an invalid task id for Timer %i\n", task, id); + if(event == 0) error("mbos::CreateTimer - Can't use null event for Timer %i\n", id); + + // fill tcb + _timers[id].timer = 0; + _timers[id].reload = 0; + _timers[id].task = task; + _timers[id].event = event; +} +// Set Timer Function ------------------------------------------------------------------- +void mbos::SetTimer(uint id, uint time, uint reload) +{ + // check bounds + if(id >= _numtimers) error("mbos::SetTimer - %i is an invalid timer id\n", id); + + __disable_irq(); + _timers[id].timer = time; + _timers[id].reload = reload; + __enable_irq(); +} +// Redirect Timer Function ----------------------------------------------------------------- +void mbos::RedirectTimer(uint id, uint task, uint event) +{ + // check bounds + if(id >= _numtimers) error("mbos::RedirectTimer - %i is an invalid timer id\n", id); + if(task < 1|| task >= _numtasks) error("mbos::RedirectTimer - %i is an invalid task id for Timer %i\n", task, id); + if(event == 0) error("mbos::RedirectTimer - Can't use null event for Timer %i\n", id); + + __disable_irq(); + if( _timers[id].timer == 0){ + _timers[id].task = task; + _timers[id].event = event; + } + __enable_irq(); +} +// Clear Timer Function ------------------------------------------------------------------- +void mbos::ClearTimer(uint id) +{ + // check bounds + if(id >= _numtimers) error("mbos::ClearTimer - %i is an invalid timer id\n", id); + + __disable_irq(); + _timers[id].timer = 0; + _timers[id].reload = 0; + __enable_irq(); +} +// Create resources Function -------------------------------------------------------------- +void mbos::CreateResource(uint id, uint priority) +{ + // check bounds + if(id >= _numresources) error("mbos::CreateResource - %i is an invalid resource id\n", id); + if(priority > MAX_PRIO) error("mbos::CreateResource - %i is an invalid priority for Resource %i\n", priority, id); + + // fill rcb + _resources[id].priority = priority; + _resources[id].lock = 0; +} +// Lock Resource Function -------------------------------------------------------------- +uint mbos::LockResource(uint id) +{ + // check bounds + if(id >= _numresources) error("mbos::LockResource - %i is an invalid resource id\n", id); + if(_tasklist[0]->id == 0 ||_resources[id].lock != 0) return _resources[id].lock; + + __disable_irq(); + _resources[id].lock = _tasklist[0]->id; + _resources[id].taskprio = _tasklist[0]->priostate; + _tasklist[0]->priostate = _resources[id].priority + READY; + __enable_irq(); + return 0; +} +// Test Resource Function -------------------------------------------------------------- +uint mbos::TestResource(uint id) +{ + // check bounds + if(id >= _numresources) error("mbos::TestResource - %i is an invalid resource id\n", id); + return(_resources[id].lock); +} +// Free Resource Function -------------------------------------------------------------- +uint mbos::FreeResource(uint id) +{ + // check bounds + if(id >= _numresources) error("mbos::FreeResource - %i is an invalid resource id\n", id); + if(_tasklist[0]->id == 0 || _tasklist[0]->id != _resources[id].lock) return _resources[id].lock; + + __disable_irq(); + _resources[id].lock = 0; + _tasklist[0]->priostate = _resources[id].taskprio; + __enable_irq(); + return 0; +} +// Initialise stack function ----------------------------------------------------------- +uint* mbos::_initstack(uint *stack, void (*fun)()) +{ + stack -= 3; // leave a spare word + *stack = 0x01000000; // Initial xPSR (reset value) + stack--; + *stack = (uint)fun - 1; // Start address of the task corrected + stack--; + *stack = 0; // LR + stack -= 5; // R12, R3, R2, R1, R0 + stack -= 8; // R11, R10, R9, R8, R7, R6, R5, R4 + return stack; +} +// Stack Error function ---------------------------------------------------------------- +void _stackerror(uint task) +{ + error("Stack Overflow on Task %i\n", task); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbos.h Thu May 05 07:34:12 2011 +0000 @@ -0,0 +1,251 @@ +/*********************************************************************************** + * m b o s R T O S F O R m b e d (ARM CORTEX M3) + * + * Copyright (c) 2010 - 2011 Andrew Levido + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef MBOS_H +#define MBOS_H + +typedef unsigned int uint; + +/**A pre-emptive, mutlitasking real-time operating system for mbed applications. + * + * Allows the user to write their application in the form of independant tasks. + * The operating system manages a completely separate processor context for each + * task (processor registers and stack) and swaps between the tasks according to a + * simple scheduling algorithm. + * + * Tasks are allocated a priority, and the scheduler ensures that the task + * that with the highest priority that is not waiting for an event, has control of + * the processor. If more than one task shares the highest priority, they will be + * run sequentially in round-robin fashion. + * + * Each task may wait for one or more of up to 32 different events, each represented by + * one bit in the event flags word. Events may be posted by another task, by a mbos + * timer, or in response to some asynchronous event such as an peripheral interrupt. + * + * mbos implements the SysTick timer to generate a System Tick every millisecond. + * Scheduling occurs once every Tick, or whenever a task blocks or an event is posted. + * The user may create one-shot or continuous timers to post events to tasks. + * + * mbos implements a simple ceiling protocol resource locking mechanism To manage access + * to system resources. Tasks may take exclusive ownership of resources for a period. + * + * A typical simple example with two tasks, and one timer, might look like this: + * @code + * // mbos Blinky demonstration. + * // Task 1 toggles LED1 every second, under control of a timer. It then posts an event to + * // task 2 which flashed LED2 briefly. + * #include "mbed.h" + * #include "mbos.h" + * + * #define TASK1_ID 1 // Id for task 1 (idle task is 0) + * #define TASK1_PRIO 50 // priority for task 1 + * #define TASK1_STACK_SZ 32 // stack size for task 1 in words + * #define TASK2_ID 2 // Id for task 2 + * #define TASK2_PRIO 60 // priority for task 2 + * #define TASK2_STACK_SZ 32 // stack size for task 2 in words + * #define TIMER0_ID 0 // Id for timer 0 + * #define TIMER0_PERIOD 1000 // Time period in milliseconds + * #define TIMER0_EVENT 1 // Event flag (1 << 0) + * #define T1_TO_T2_EVENT 2 // Event flag (1 << 1) + * + * void task1(void); // task function prototypes + * void task2(void); + * + * DigitalOut led1(LED1); + * DigitalOut led2(LED2); + * mbos os(2, 1); // Instantiate mbos with 2 tasks & 1 timer + * + * int main(void) + * { + * // Configure tasks and timers + * os.CreateTask(TASK1_ID, TASK1_PRIO, TASK1_STACK_SZ, task1); + * os.CreateTask(TASK2_ID, TASK2_PRIO, TASK2_STACK_SZ, task2); + * os.CreateTimer(TIMER0_ID, TIMER0_EVENT, TASK1_ID); + * // Start mbos + * os.Start(); + * // never return! + * } + * + * void task1(void) + * { + * os.SetTimer(TIMER0_ID, TIMER0_PERIOD, TIMER0_PERIOD); + * while(1){ + * os.WaitEvent(TIMER0_EVENT); + * led1 = !led1; + * os.SetEvent(T1_TO_T2_EVENT, TASK2_ID); + * } + * } + * + * void task2(void) + * { + * while(1){ + * os.WaitEvent(T1_TO_T2_EVENT); + * led2 = 1; + * wait_ms(100); + * led2 = 0; + * } + * } + * @endcode + */ + +class mbos { +public: + /** Create an mbos object. Instantiate mbos and define the number of tasks, timers + * and resources. + * + * @param ntasks The number of user tasks (1 .. 99). + * @param ntimers Optional number of timers (0 .. 100). + * @param nresources Optional number of resources (0 .. 100). + */ + mbos(uint ntasks, uint ntimers = 0, uint nresources = 0); + + /** Start mbos. Optionally specify the size of the stack for a user-written idle task. + * All tasks, timers and resources must be created before calling Start. + * + * @param idlestacksize Size in words (>= 32) of the user-written idle task if present. + * @returns Never returns + */ + void Start(uint idlestacksize = 32); + + /** Create an mbos task. Allocates and initialises data structures for the task. + * + * @param taskid Unique ID for the task. (1 .. ntasks). + * @param priority Priority (0 .. 99) of the task. Tasks may share the same priority. + * @param stacksize Size in words (>= 32) of the task's stack. + * @param fun Pointer to the task function. Function must be of type static void, + * and must return nothing. + */ + void CreateTask(uint taskid, uint priority, uint stacksz, void (*fun)(void)); + + /** Get the ID of the current task. + * + * @returns The ID (0 .. 99) of the calling task. + */ + uint GetTask(void); + + /** Set the priority of the current task. Does nothing if called from the idle task. + * + * @param priority Priority (0 .. 99) to apply to the calling task. + */ + void SetPriority(uint priority); + + /** Get the priority of the current task. + * + * @returns The priority (0 .. 99) of the calling task. + */ + uint GetPriority(void); + + /** Wait for an event or events. Causes the current task to block, waiting for the + * specified event. Does nothing if called from the idle task, or if the event is NULL. + * + * @param event Event flag(s) to wait for. + */ + void WaitEvent(uint event); + + /** Post an event or events to a task. + * Posts the nominated event(s) to the specified task. Forces a context switch if the events + * are posted successfully. Does nothing if the task is not waiting, or is not waiting for + * the posted event. + * + * @param event Event flag(s) to post. + * @param task The ID of the task to which to post the event(s). May not be idle task. + */ + void SetEvent(uint event, uint task); + + /** Returns the event flag(s) which last caused the task to unblock. + * + * @returns The event flags. + */ + uint GetEvent(void); + + /** Create a mbos timer. Allocates and initialises the data structures for the timer. + * + * @param timerid Unique ID for the timer (0 .. ntimers - 1). + * @param taskid The ID of the task to which the timer will post events. May not be + * the idle task. + * @param event The event flag(s) that the timer should post on timeout. May not be NULL. + */ + void CreateTimer(uint timerid, uint taskid, uint event); + + /** Starts an mbos timer. If the reload time is zero or omitted, the timer will be reset + * once it has posted a single event, after time milliseconds. If the reload time is + * non-zero, this value will be loaded into the timer on time-out, and the timer will + * continue indefinitely. In this case the interval to the first event will be time, + * and the interval between subsequent events will be reloadtime. + * + * @param timerid The ID of the timer. + * @param time The period in milliseconds before the timer times out. + * @param reload The optional time to reload into the timer when it times out. + */ + void SetTimer(uint timerid, uint time, uint reload = 0); + + /** Redirects an mbos timer. Changes the task and event associated with a timer. If the timer + * is running, the fun ction has no effect. + * + * @param timerid The ID of the timer. + * @param taskid The ID of the task to which the timer will post events. May not be + * the idle task. + * @param event The event flag(s) that the timer should post on timeout. May not be NULL. + */ + void RedirectTimer(uint timerid, uint taskid, uint event); + + /** Stops and clears an mbos timer. + * + * @param timerid The ID of the timer to clear. + */ + void ClearTimer(uint timerid); + + /** Creates an mbos resource. Allocates and initialises the data structures for the Resource. + * + * @param resourceid Unique ID for the resource (0 .. nresource). + * @param priority Priority of the resource (normally > than that of any task using the + * resource). + */ + void CreateResource(uint resourceid, uint priority); + + /** Locks an mbos resource and temporarily allocates the resource's priority to the calling + * task. + * Does nothing if the resource is already locked, or if called from the idle task. + * + * @param resourceid The ID of the resource to lock. + * @returns Zero if the resource was locked successfully, or the ID of the task that is + * currently locking the resource, if not. + */ + uint LockResource(uint resourceid); + + /** Tests whether a resource is locked or free, without changing its state. + * + * @param resourceid The ID of the resouce to test. + * @returns Zero if the resource is free, or the ID of the task that is currently + * locking the resouce , if not. + + */ + uint TestResource(uint resourceid); + + /** Frees a resource + * Frees an mbos resource and restores the calling task's original priority. Does nothing + * if the resource is already free, if called from the idle task, or the resource was + * locked by a different task. + * + * @param resourceid The ID of the resource t free. + * @returns Zero if the resource was freed successfully, or the ID of the task that is + * locking the resource, if not. + */ + uint FreeResource(uint resource); + +private: + uint* _initstack(uint *stack, void (*fun)()); +}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbos_asm.s Thu May 05 07:34:12 2011 +0000 @@ -0,0 +1,121 @@ +;*********************************************************************************** +; m b o s R T O S F O R m b e d (ARM CORTEX M3) +; +; Copyright (c) 2010 - 2011 Andrew Levido +; +; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED +; WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +; SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +; OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + EXPORT _startos + EXPORT SVC_Handler + EXPORT PendSV_Handler + EXPORT _swap + + EXTERN _tasklist + EXTERN _tasklistsize + EXTERN _stackerror + EXTERN _hardstacklimit + +ID_OFFSET equ 0 ; 0 word (0byte) offset +STACK_OFFSET equ 4 ; 1 word (4byte) offset +PRIO_OFFSET equ 8 ; 2 word (8byte) offset +LIMIT_OFFSET equ 20 ; 5 word (20byte) offset + + AREA |.text|, CODE, READONLY, ALIGN=3 + PRESERVE8 + +; Function to invoke an SVC exception to start 1st task ---------------------------------- +_startos + svc 0 ; Initiate a system call to start the first task + bx lr ; Return (should never happen!) + ALIGN + +; Function to initiate a SetPend Exception to swap tasks --------------------------------- +_swap + mov r0, #0xe000e000 ; Base address of ICSR + ldr r1, [r0, #0x0d04] ; Read ICSR + orr r1, #0x10000000 ; Set setPend bit + str r1, [r0, #0xd04] ; write back to ICSR + bx lr + ALIGN + +; Main task switching and scheduling functions ------------------------------------------- +PendSV_Handler ; entered here as handler for context switch + cpsid i ; disable interrupts + ; save context of running task (that not saved by exception entry) + mrs r0, msp + stmdb r0!, {r4-r11} +; store the sp in the tcb + ldr r1, =_tasklist + ldr r1, [r1] + ldr r1, [r1] + str r0, [r1, #STACK_OFFSET] +; check for stack overflow against task limit + ldr r2, [r1, #LIMIT_OFFSET] + cmp r0, r2 + bls stackerror +; check for stack overflow against hard limit + ldr r2, =_hardstacklimit + ldr r2, [r2] + cmp r0, r2 + bls stackerror +SVC_Handler ; entered here as handler for 1st task start + cpsid i ; Disable interrupts +; sort the task list + ldr r5, =_tasklist ; r5 = _tasklist[i] where i = 0 + ldr r5, [r5] + ldr r9, =_tasklistsize ; byte offset of last item in tasklist + ldr r9, [r9] + add r9, r5 ; outer loop limit + sub r10, r9, #4 ; inner loop limit +outerloop + ldr r1, [r5] ; r8 = _tasklist[i]->priostate + ldr r8, [r1, #PRIO_OFFSET] + mov r7, r5 ; k = i + add r6, r5, #4 ; j = i + 1 +innerloop + ldr r0, [r6] ; r0 = _tasklist[j]->priostate + ldr r0, [r0, #PRIO_OFFSET] + cmp r0, r8 ; r0 - r8 + bcc innerlooptest ; branch if r8 higher +; found bigger or same! + mov r7, r6 ; k = j + mov r8, r0 ; r8 = _tasklist[j]->priostate +innerlooptest + add r6, #4 ; j++ + cmp r6, r9 ; r6 - r9 (j - inner limit) + bls innerloop ; branch if r9 lower or same +; swap + ldr r0, [r5] + ldr r1, [r7] + str r1, [r5] + str r0, [r7] +outerlooptest + add r5, #4 ; i++ + cmp r5, r10 ; r5 - r10 (i - outer limit) + bls outerloop ; branch if r10 is lower or same + ; restore the context (that not restored by the exception exit) --------------------- + ldr r0, =_tasklist ; get the sp from the TCB + ldr r0, [r0] + ldr r0, [r0] + ldr r0, [r0, #STACK_OFFSET] + ldmia r0!,{r4-r11} ; pop the stack + msr msp, r0 ; and put the sp away + cpsie i ; re-enable interrupts +; Force a return from exception and the restoration of the rest of the regs + bx lr +; A stack error has occurred +stackerror + ldr r0, [r1, #ID_OFFSET] ; get id of task into r0 + bl.w _stackerror ; call the C function +_donothing + bl _donothing + ALIGN + END \ No newline at end of file