Testing [Andrew L] mbos RTOS for mbed Simply by copying code for main.cpp from mbos.h-comments
mbos.cpp
- Committer:
- chalikias
- Date:
- 2011-05-05
- Revision:
- 0:a61d29450691
File content as of revision 0:a61d29450691:
/***********************************************************************************
* 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);
}