Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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