Testing [Andrew L] mbos RTOS for mbed Simply by copying code for main.cpp from mbos.h-comments

Dependencies:   mbed

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);
}