Dependents: rtest LeonardoMbos OS_test Labo_TRSE_Drone ... more
mbos.cpp
- Committer:
- AndrewL
- Date:
- 2012-01-09
- Revision:
- 6:cf660b28b2a4
- Parent:
- 5:6eef5e47e154
File content as of revision 6:cf660b28b2a4:
/*********************************************************************************** * 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].priostate < READY){ 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); }