nikos chalikias
/
mbos_test
Testing [Andrew L] mbos RTOS for mbed Simply by copying code for main.cpp from mbos.h-comments
Diff: mbos.cpp
- Revision:
- 0:a61d29450691
diff -r 000000000000 -r a61d29450691 mbos.cpp --- /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); +}