Example code

For starters: a simple application for TC2x

#include <pxdef.h>

#undef _STRINGIFY
#define _STRINGIFY(x)   #x
#define _DEF_SYM(n,v)                       \
    __asm (".global       " #n );           \
    __asm (".set  " #n "," _STRINGIFY(v));  \
    __asm (".type " #n ",STT_OBJECT")

#define DEF_SYM(name,val)   _DEF_SYM(name,val)


// Priority of the Inittask after initialisation
#define MIN_PRIO       31

// Priority of Task1
#define TASK1_PRIO      4


#define PXROS_NAMESIZE          12
#define NUM_OF_PXOBJS           100
#define SYSMEMSIZE              2000
#define TASKMEMSIZE            10000

#define INITTASK_STACKSIZE      200
#define INITTASK_INTSTACKSIZE   0

#define TASK1_STACKSIZE         200
#define TASK1_INTSTACKSIZE      32

/* define the symbol __PXROS_NAMESIZE__
 * to make the object name size accessible by the linker
 */
DEF_SYM(__PXROS_NAMESIZE__, PXROS_NAMESIZE);

/* declaration of object pool sizes (for linker) */
DEF_SYM(__NUM_OF_PXOBJS__CPU0_, NUM_OF_PXOBJS);


/* start address for slave cores (started by master core) */
extern void _start(void);

/* data area description for the system */
/* these symbols are defined in the system linker script Multi.ld */

/* PXROS object memory for each CPU */
extern PxMemAligned_t  PxObjmem_CPU0_[];
extern unsigned int PX_OBJMEMSIZE_CPU0_[];

/* description of system stack (for each CPU) */
extern const PxUInt_t PXROS_SYSTEM_STACK_BEGIN_CPU0_[];
extern const PxUInt_t PXROS_SYSTEM_STACK_SIZE_CPU0_[];

/* memory class for system objects */
#pragma section ".CPU0.systemmemory" awBc0 8
static PxMemAligned_t Sysmem[(SYSMEMSIZE + sizeof(PxMemAligned_t) - 1) / sizeof(PxMemAligned_t)] PXMEM_ALIGNED;
#pragma section

#pragma section ".CPU0.taskmemory" awBc0 8
/* memory class for task this will also be defined as PXMcTaskdefault to the inittask */
static PxMemAligned_t Taskmem[(TASKMEMSIZE + sizeof(PxMemAligned_t) - 1) / sizeof(PxMemAligned_t)] PXMEM_ALIGNED;
#pragma section

// Function prototypes

// Task function of the Inittask
static void InitTask_Func(PxTask_t myID,
                          PxMbx_t myMailbox,
                          PxEvents_t myActivationEvents);


// Task function of Task1
static void Task1_Func(PxTask_t myID,
                       PxMbx_t myMailbox,
                       PxEvents_t myActivationEvents);


// Code Area
extern PxUInt_t __TEXT_BEGIN[];
extern PxUInt_t __TEXT_END[];

// context save area
extern PxUInt_t __CSA_BEGIN_CPU0[];
extern PxUInt_t __CSA_END_CPU0[];

// System data areas
extern PxUInt_t	  PxTricSystemRodataLowerBound[];
extern PxUInt_t	  PxTricSystemRodataUpperBound[];

extern PxUInt_t	  PxTricSystemDataLowerBound_CPU0_[];
extern PxUInt_t	  PxTricSystemDataUpperBound_CPU0_[];


/* CPU0 Protection description */
const PxCodeProtectSet_T _cpu0_sys_code_protection =
{
    /* Range 0 the complete text section */
    .cpr[0].s = {(PxUInt_t)__TEXT_BEGIN,     (PxUInt_t)__TEXT_END,},
    .cpmr.cpxe.bits =
    {
        .dp0 = 1,       /* the CPXE 0 executable */
    }
};

const PxCodeProtectSet_T _cpu0_task_code_protection =
{
    /* Range 0 the complete text section */
    .cpr[0].s = {(PxUInt_t)__TEXT_BEGIN, (PxUInt_t)__TEXT_END,},
    .cpmr.cpxe.bits =
    {
        .dp0 = 1,       /* the CPXE 0 executable */
    }
};

const PxDataProtectSetInit_T _cpu0_sys_data_protection =
{
    /* Range 0: read only data */
    .dpr[0].s = {(PxUInt_t)PxTricSystemRodataLowerBound,
                 (PxUInt_t)PxTricSystemRodataUpperBound,},
    /* Range 1: the CSA area of CPU0 (global address) */
    .dpr[1].s = {(PxUInt_t)__CSA_BEGIN_CPU0_,
                 (PxUInt_t)__CSA_END_CPU0_,},
    /* Range 2: the KERNEL data area of CPU0 (global address) */
    .dpr[2].s = {(PxUInt_t)PxTricSystemDataLowerBound_CPU0_,
                 (PxUInt_t)PxTricSystemDataUpperBound_CPU0_},
    /* Range 3: the SFR area */
    .dpr[3].s = {(PxUInt_t)PERIPHERAL_MEM_BASE,
                 (PxUInt_t)PERIPHERAL_MEM_END,},
    /* Range 4: the supervisor stack */
    .dpr[4].s = {(PxUInt_t)PXROS_SYSTEM_STACK_BEGIN_CPU0_,
                 (PxUInt_t)PXROS_SYSTEM_STACK_CPU0_,},
    /* Range 7: used dynamically by system
                used to get access to memory before PXROS is started
                - especially used for copy and clear functions
    */
    .dpr[7].s = {0,0},
    /* the DPRE 0..4,7 readable */
    .dpmr.kernel.dpre.bits =
    {
        .dp0 = 1, .dp1 = 1, .dp2 = 1, .dp3 = 1,
        .dp4 = 1, .dp5 = 0, .dp6 = 0, .dp7 = 1
    },
    /* the DPWE 1..4,7 writable */
    .dpmr.kernel.dpwe.bits =
    {
        .dp0 = 0, .dp1 = 1, .dp2 = 1, .dp3 = 1,
        .dp4 = 1, .dp5 = 0, .dp6 = 0, .dp7 = 1
    },
    /* the DPRE 0,3,4 readable */
    .dpmr.system.dpre.bits =
    {
        .dp0 = 1, .dp1 = 0, .dp2 = 0, .dp3 = 1,
        .dp4 = 1, .dp5 = 0, .dp6 = 0, .dp7 = 0
    },
    /* the DPWE 3,4 writable */
    .dpmr.system.dpwe.bits =
    {
        .dp0 = 0, .dp1 = 0, .dp2 = 0, .dp3 = 1,
        .dp4 = 1, .dp5 = 0, .dp6 = 0, .dp7 = 0
    },
};

#define INITTASK_ACCESS_RIGHTS  PXACCESS_HANDLERS               \
                          | PXACCESS_INSTALL_HANDLERS           \
                          | PXACCESS_INSTALL_SERVICES           \
                          | PXACCESS_REGISTERS                  \
                          | PXACCESS_SYSTEMDEFAULT              \
                          | PXACCESS_RESOURCES                  \
                          | PXACCESS_NEW_RESOURCES              \
                          | PXACCESS_SYSTEM_CONTROL             \
                          | PXACCESS_MODEBITS                   \
                          | PXACCESS_TASK_CREATE                \
                          | PXACCESS_TASK_CREATE_HIGHER_PRIO    \
                          | PXACCESS_TASK_SET_HIGHER_PRIO       \
                          | PXACCESS_CHANGE_PRIO                \
                          | PXACCESS_TASK_RESTORE_ACCESS_RIGHTS \
                          | PXACCESS_TASK_CREATE_HIGHER_ACCESS



// Memory context of Inittask
static const PxTaskContext_T InitTaskContext =
{
	.protection[0].lowerBound = (PxUInt_t)&PxTricSystemRodataLowerBound,
	.protection[0].upperBound = (PxUInt_t)&PxTricSystemRodataUpperBound,
	.protection[0].prot       = ReadProtection,

	.protection[1].lowerBound = 0,
	.protection[1].upperBound = 0,
	.protection[1].prot       = NoAccessProtection,
};


// Specification of Inittask
static const PxTaskSpec_T InitTaskSpec =
{
	.ts_name                     = "InitTask",
	.ts_fun                      = InitTask_Func,
	.ts_mc                       = PXMcTaskdefault,
	.ts_opool                    = PXOpoolSystemdefault,
	.ts_prio                     = 0,
	.ts_privileges               = PXUser1Privilege,
	.ts_context                  = &InitTaskContext,
	.ts_taskstack.stk_type       = PXStackAlloc,
	.ts_taskstack.stk_size       = INITTASK_STACKSIZE,
	.ts_taskstack.stk_src.mc     = PXMcTaskdefault,
	.ts_abortstacksize           = 0.
    .ts_accessrights             = INITTASK_ACCESS_RIGHTS,
};


// Memory context of Task1
static const PxTaskContext_T Task1Context =
{
	.protection[0].lowerBound = 0,
	.protection[0].upperBound = 0,
	.protection[0].prot       = NoAccessProtection,

	.protection[1].lowerBound = 0,
	.protection[1].upperBound = 0,
	.protection[1].prot       = NoAccessProtection,
};

// Specification of Task1
static const PxTaskSpec_T Task1Spec =
{
	.ts_name                     = "Task1",
	.ts_fun                      = Task1_Func,
	.ts_mc                       = PXMcTaskdefault,
	.ts_opool                    = PXOpoolTaskdefault,
	.ts_prio                     = 0,
	.ts_privileges               = PXUser0Privilege,
	.ts_context                  = &Task1Context,
	.ts_taskstack.stk_type 	     = PXStackAlloc,
	.ts_taskstack.stk_size	     = TASK1_STACKSIZE,
	.ts_taskstack.stk_src.mc     = PXMcTaskdefault
	.ts_abortstacksize           = 0
};


// PXROS-HR system specification
static const PxInitSpec_T InitSpec =
{
	.is_sysmc_type          = PXMcVarsized,
	.is_sysmc_size          = 0,
	.is_sysmc_blk           = Sysmem,
	.is_sysmc_blksize       = SYSMEMSIZE,
    .is_obj_number      = NUM_OF_PXOBJS_CORE0,
    .is_obj_namelength  = PXROS_NAMESIZE,
    .is_inittask        = &InitTaskSpec_CORE0,

    .is_objmc_type      = PXMcVarsizedAligned,
    .is_objlmc_size     = 8,
    .is_objmc_blk       = PxObjmem_CPU0_,
    .is_objmc_blksize   = (PxSize_t)PX_OBJMEMSIZE_CPU0_,

    .is_taskmc_type     = PXMcVarsizedAdjusted,
    .is_taskmc_size     = 8,
    .is_taskmc_blk      = Taskmem,
    .is_taskmc_blksize  = TASKMEMSIZE,

    /* the system stack */
    .is_system_stack = PXROS_SYSTEM_STACK_BEGIN_CPU0_,
    .is_system_stack_size = (PxUInt_t)PXROS_SYSTEM_STACK_SIZE_CPU0_,

    /* the protection definition */
    .is_sys_code = &_cpu0_sys_code_protection,
    .is_sys_data = &_cpu0_sys_data_protection,
    .is_task_code = &_cpu0_task_code_protection,
};

static const PxInitSpecsArray_t InitSpecsArray =
{
    &InitSpec,
    0,
    0,
};



// Code of Inittask
static void InitTask_Func(PxTask_t myID,
                          PxMbx_t myMailbox,
                          PxEvents_t myActivationEvents)
{
    /* create task1 */
    PxTask_t taskID = PxTaskCreate(PXOpoolSystemdefault,
                                   &Task1Spec,
                                   TASK1_PRIO,
                                   0);
    /* minimize own priority */
    PxTaskSetPrio(myID,MIN_PRIO);

    /* loop forever */
    while(1) ;
}



// Code of Task function Task1_Func
static void Task1_Func(PxTask_t myID,
                       PxMbx_t myMailbox,
                       PxEvents_t myActivationEvents)
{
  // Declarations and initialisation
    int foo = 0;
    int bar;

    if(myActivationEvents == EV_ACT_EV1)
    {
        bar = 1;
    }
    else
    {
        bar = 42;
    }


    //  Main loop
    while(1)
    {
      // parallel waiting for events and messages
        PxMsgEvent_t msgev;
        msgev = PxMsgReceive_EvWait(myMailbox,EV_EVENT_MASK);
        if(PxMsgIdIsValid(msgev.msg))
        {
          // message received
            do_sth_with_msg(msgev.msg);
        }

        if(msgev.events != 0)
        {
          // event received
            do_sth_with_events(msgev.events);
        }
    }
}


int main(void)
{
    PxError_t error;

    error = PxInit(&InitSpecArray, 1);
    if (error != PXERR_NOERROR)
    {
      PxPanic();
      return 1;
    }
    return 0;
}

Data exchange between Handler and Task

struct
{
    PxTask_t   commTask;  // TaskID
    PxEvents_t commEv;    // Data-Ready event
    PxUChar    commMem[100];  // Memory areas of the communication structure
} TaskHandlerComm;

#define MY_HANDLER_EVENT	1

#define COMM_BUFFER_SIZE	512

void HandlerFunc(PxArg_t arg);


TaskFunc(PxTask_t myID, PxMbx_t myMailbox, PxEvents_t myActivationEvents)
{
    struct TaskHandlerComm myTaskHandlerComm;

...

    // Initialising the communication object
    myTaskHandlerComm.commTask = myID;
    MyTaskHandlerComm.commEv   = MY_HANDLER_EVENT;


    // Installing Handler with communication structure
    // as an argument
    PxIntInstallFastContextHandler(COMM_INTERRUPT,
                                   HandlerFunc,
                                   &myTaskHandlerComm);

    while (1)
    {
...
        if (ev & MY_HANDLER_EVENT)
        {
          //  Handler has received data and entered
          //  them in communication structure
          ProcessInputData(myTaskHandlerComm);
        }
...
    }
}


void HandlerFunc(PxArg_t arg)
{
    struct TaskHandlerComm *myTaskHandlerComm;
    PxUChar_t byte;

    myTaskHandlerComm  = (struct TaskHandlerComm *) arg;

     // Store input data in communication structure
     byte = GetInputByte();
     StoreInputData(myTaskHandlerComm->commMem);

     if (DataReadyForTask())
     {
        // Complete set of data received, Task is
        // informed
        PxTaskSignalEvents_Hnd(myTaskHandlerComm->commTask,
                               myTaskHandlerComm->commEv);
      }
}

Messagepools

Creating a Messagepool

//  creates a new Mailbox as a Messagepool
//  and enters "cnt" new Messages with data buffers
//  of "size" bytes size in this Mailbox
//  Objects are extracted from "srcpool", memory from "srcmc"
//  Messages have "poolmbx" as their release Mailbox,
//  i.e. they are stored here after release.

PxMbx_t MsgPoolCreate(PxUInt_t cnt,
                     PxSize_t size,
                     PxMc_t srcmc,
                     PxOpool_t srcopool)
{
   PxMbx_t    poolmbx;
   PxError_t  err;
   PxTmode_t  oldmode;
   PxMsg_t    msg;

   //	Avoid interruptions
   oldmode = PxSetModebits(PXTmodeDisableAborts);

   //	Create new Mailbox
   poolmbx = PxMbxRequest_NoWait(srcopool);

   if (!PxMbxIdIsValid(Poolmbx))
   {
       // Creation error
       PxSetError(poolmbx.error);
       PxClearModebits(~oldmode);
       return poolmbx;
   }

   //	Request "cnt" Messages and store in Mailbox
   while (cnt--)
   {
       // Request Message
       msg = PxMsgRequest_NoWait(size, srcmc, srcopool);
       if (PxMsgIdIsValid(msg))
       {
           // Install release Mailbox
           PxMsgInstallRelmbx(msg, poolmbx);

           // Message is stored in Messagepool
           PxMsgSend(msg, poolmbx);
       }
       else
       {
           // Error has occurred, Messagepool is
           // deleted
           err             = msg.error;

           // Release existing Messages
           poolmbx         = MsgPoolDelete(Poolmbx);
           poolmbx.error   = err;
           PxSetError(poolmbx.error);
           break;
       }
   }

   // 	Reset mode bits
   PxClearModebits(~oldmode);

   //	Return Messagepool
   return poolmbx;
}

Deleting a Messagepool

//  Deletes a Messagepool, which was created via
// MsgPoolCreate. All concerned Messages must
//  be present within the Messagepool.
//  If a pool Message is deleted after
//  deletion of the Messagepool, a
//  "PXERR_MBX_ILLMBX" will occur.
//  Tasks may not wait at this Mailbox,
// otherwise Mailbox cannot be deleted.
PxMbx_t MsgPoolDelete(PxMbx_t poolmbx)
{
    PxMsg_t      msg;
    PxTmode_t    oldmode;

    // Avoid interruptions
    oldmode = PxSetModebits(PXTmodeDisableAborts);

    // Release all messages
    for (msg = PxMsgReceive_NoWait(poolmbx); PxMsgIdIsValid(msg); )
    {
        PxMsgInstallRelmbx(msg, PxMbxIdInvalidate());
        PxMsgRelease(msg);
    }

    // Reset mode bits
    PxClearModebits(~oldmode);

    // Delete Mailbox
    return PxMbxRelease(poolmbx);
}

Dynamical creation of a C++ task

To create a C++ task dynamically a class describing the task object must be defined.

extern "C" {
void Task1_Entry(PxTask_t myID, PxMbx_t myMailbox, PxEvents_t myActivationEvents);
}
/*
The Class of Task1
This class defines all data and functions of the task Task1
*/
class Task1
{
    PxStackAligned_t TaskStack[(TASK_STACKSIZE / (sizeof(PxStackAligned_t) / sizeof(PxInt_t)))];
    // add 6 dummy bytes to avoid protection disruption by using "st.d" at the end of the data area
    // normaly an access to this pad bytes will lead to an protection fault
    // this 6 byte have to be always the last elements in the data area of a task
    // don't at any members behind this protection pad
    PxChar_t    __protectionPad[PXALLOC_SECURITY_PAD] PXMEM_ALIGNED;
public:
    PxTask_t TaskCreate(PxPrio_t prio, PxEvents_t actev);
    friend PxTask_t CreateTask1(PxPrio_t prio, PxEvents_t actevents);
    friend void Task1_Entry(PxTask_t myID, PxMbx_t myMailbox, PxEvents_t myActivationEvents);
} __attribute__ ((aligned(64)));

The task has to provide an API function to create it:

PxTask_t TaskCreate(PxPrio_t prio, PxEvents_t events)
{
    return Task1Obj.TaskCreate(prio, events);
}

The task creation is almost the same as the static task creation. The only difference is that the second entry in the task context must cover the task’s object:

PxTask_t TaskCreate (PxPrio_t prio, PxEvents_t events, PxMc_t memClass, PxOpool_t objPool)
{
    PxTaskSpec_T    ts;
    PxTaskContext_T context;

    memset((PxUChar_t *)&ts, 0, sizeof(ts));

    context.protection[0].lowerBound    = 0;
    context.protection[0].upperBound    = 0;
    context.protection[0].prot          = NoAccessProtection,
    context.protection[1].lowerBound    = (unsigned int)this;
    context.protection[1].upperBound    = ((unsigned int)this) + sizeof(Task1);
    context.protection[1].prot          = WRProtection;

    ts.ts_name                          = (const PxChar_t *)"Task1";
    ts.ts_fun                           = TaskEntry;
    ts.ts_mc                            = memClass;
    ts.ts_opool                         = objPool;
    ts.ts_privileges                    = PXUser1Privilege;
    ts.ts_accessrights                  = THISTASK_PXACCESS;
    ts.ts_context                       = &context;
    ts.ts_protect_region                = 0;

    /* Specify the task's stack. */
    ts.ts_taskstack.stk_type            = PXStackFall;
    ts.ts_taskstack.stk_size            = TASK_STACKSIZE;
    ts.ts_taskstack.stk_src.stk         = &TaskStack[(TASK_STACKSIZE / (sizeof(PxStackAligned_t) / sizeof(PxInt_t)))];

    return PxTaskCreate (PXOpoolTaskdefault, &ts, prio, events);
}

The creating task must allocate the memory needed for the task object. The easiest method is to request memory from default memory class. The pointer to the allocated memory block is stored in a task variable to be able to release the memory when the task is removed. Then the API function to create the task is called:

PxMemAligned_t *taskArea;
PxTask_t CreateTask1(PxPrio_t prio, PxEvents_t actEv)
{
    Task1 *Task1Ptr;
    PxTask_t taskId = PxTaskIdInvalidate();

    taskArea = (PxMemAligned_t *)PxMcTakeBlk(PXMcTaskdefault,sizeof(Task1));
    if (taskArea == 0)
    {
        PxTaskIdSetError(taskId, PXERR_MC_NOMEM;
        return taskId;
    }
    memset ((void *)taskArea, 0, sizeof(Task1));
    Task1Ptr = (Task1 *)taskArea;
    taskId = Task1Ptr->TaskCreate (prio, actEv, PXMcTaskdefault, PXOpoolTaskdefault);
    if (PxTaskIdError(taskId) != PXERR_NOERROR)
    {
        PxMcReturnBlk(PXMcTaskdefault, taskArea);
    }
    return taskId;
}

Remove a dynamically created task

There are only 2 steps necessary to remove a dynamically created task:

  1. Terminate the task

  2. Release the memory used by the task

PxError_t err;
PxTask_t taskId;

    err = PxTaskForceTermination(taskId);
    if (err == PXERR_NOERROR)
    {
        taskId = PxTaskIdInvalidate();
        taskArea = PxMcReturnBlk(PXMcTaskdefault, taskArea);
    }