Example code
For starters: a simple application
#include <pxdef.h>
/* Priority of the Inittask after initialisation */
#define MIN_PRIO 31
/* Priority of Task1 */
#define TASK1_PRIO 4
/* We do not allocate any storage for object names */
#define PXROS_NAMESIZE 0
/* Number of PXROS-HR objects (free objects in system object pool) */
#define NUM_OF_PXOBJS 200
/* Size of system default memory class in bytes */
#define SYSMEMSIZE (8 * 1024)
/* Size of task default memory class in bytes */
#define TASKMEMSIZE (32 * 1024)
/* Stack sizes in bytes for Inittask and Task1 */
#define INITTASK_STACKSIZE 1024
#define INITTASK_INTSTACKSIZE 1024
#define TASK1_STACKSIZE 1024
#define TASK1_INTSTACKSIZE 256
/* Memory block for System Object Pool (PxOpoolSystemdefault) */
#define PX_OBJMEMSIZE ((NUM_OF_PXOBJS * PXOBJ_SIZE) + (PXROS_NAMESIZE * PXOBJ_SIZE))
PxUChar_t PxObjmem[PX_OBJMEMSIZE] \
__attribute__ ((section(".systemmemory"), aligned(PXOBJ_SIZE)));
/* Memory block for System Default Memory class (PXMcSystemDefault) */
#define SYSMEMSIZE (PXMEM_ADJUST(NUM_OF_TASKS * PXTASK_SIZE))
PxMemAligned_t Sysmem[SYSMEMSIZE / sizeof(PxMemAligned_t)] \
__attribute__ ((section(".systemmemory"), aligned(PXMEM_ALIGN)));
/* Memory block for Task Default Memory class (PxMcTaskdefault) */
PxMemAligned_t Taskmem[PXMEM_ADJUST(TASKMEMSIZE) / sizeof(PxMemAligned_t)] \
__attribute__ ((section(".taskmemory"), aligned(TASKMEMSIZE)));
/* Function prototypes needed in configuration structures */
/* 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);
/* System memory region for read-only data */
#define ARM_CODE_SEGMENT_BEGIN 0x00000000
#define ARM_CODE_SEGMENT_END 0x20000000
#define _SYS_RO_PROTECTION \
{ \
.lowerBound = ARM_CODE_SEGMENT_BEGIN, \
.upperBound = ARM_CODE_SEGMENT_END, \
.mattr = READONLY_CODE_MEMORY_ATTRIBUTES() \
}
/* PXROS-HR access rights for Inittask */
#define INITTASK_PXACCESS \
PXACCESS_HANDLERS \
| PXACCESS_INSTALL_HANDLERS \
| PXACCESS_INSTALL_SERVICES \
| PXACCESS_REGISTERS \
| PXACCESS_SYSTEMDEFAULT \
| PXACCESS_RESOURCES \
| PXACCESS_NEW_RESOURCES \
| PXACCESS_SYSTEM_CONTROL \
| PXACCESS_MODEBITS \
| PXACCESS_OVERRIDE_ABORT_EVENTS \
| 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 \
| PXACCESS_GLOBAL_OBJECTS
/* Inittask's extended memory regions - not used */
static const PxProtectRegion_T InitTaskRegions[] =
{
{ 0, 0, MEMORY_ATTRIBUTES(NoAccessPermission) }
};
/* Stack memory allocation for Inittask */
PxStackAligned_t inittask_stack[INITTASK_STACK_ARRAYSIZE] \
__attribute__ ((section(".InitTaskStack")));
PxStackAligned_t inittask_interrupt_stack[INITTASK_INTERRUPTSTACK_ARRAYSIZE] \
__attribute__ ((section(".InitTaskStack")));
/* Inittask's context */
static const PxTaskContext_T InitTaskContext =
{
.protection[0] = /* Inittask's stack memory */
{
.lowerBound = (unsigned int) INITTASK_STACK_BEGIN,
.upperBound = (unsigned int) INITTASK_STACK_END,
.mattr = MEMORY_ATTRIBUTES(RWPermission)
}
.protection[1] = /* Unused region */
{
.lowerBound = -1,
.upperBound = -1,
.mattr = MEMORY_ATTRIBUTES(NoAccessPermission)
},
};
/* Inittask configuration structure */
const PxTaskSpec_T InitTaskSpec =
{
.ts_name = (const PxChar_t *) "InitTask",
.ts_fun = InitTask_Func,
.ts_mc = PXMcTaskdefaultInit,
.ts_opool = PXOpoolSystemdefaultInit,
.ts_privileges = PXUserPrivilege,
.ts_accessrights = INITTASK_PXACCESS,
.ts_context = &InitTaskContext,
.ts_protect_region = InitTaskRegions,
.ts_taskstack =
{
.stk_type = PXStackFall,
.stk_size = INITTASK_STACK_SIZE_BYTES,
.stk_src.stk = &inittask_stack[INITTASK_STACK_ARRAYSIZE]
},
.ts_inttaskstack =
{
.stk_type = PXStackFall,
.stk_size = INITTASK_INTERRUPTSTACK_SIZE_BYTES,
.stk_src.stk = &inittask_interrupt_stack[INITTASK_INTERRUPTSTACK_ARRAYSIZE]
}
};
/* Task1 context */
static const PxTaskContext_T task_Context =
{
.protection[0] = /* Unused region */
{
.lowerBound = -1,
.upperBound = -1,
.mattr = MEMORY_ATTRIBUTES(NoAccessPermission)
},
.protection[1] = /* Unused region */
{
.lowerBound = -1,
.upperBound = -1,
.mattr = MEMORY_ATTRIBUTES(NoAccessPermission)
}
};
/* Task1 extended memory regions (empty) */
static const PxProtectRegion_T taskAPRegions[] =
{
{0, 0, MEMORY_ATTRIBUTES(NoAccessPermission)}
};
/* 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 InitSpec
* Note that structure members which are not explicitly initialized are set to 0. */
static const PxInitSpec_T InitSpec =
{
/* System Default Memory Class */
.is_sysmc_type = PXMcVarsizedAdjusted,
.is_sysmc_size = PXMEM_ALIGN,
.is_sysmc_blk = Sysmem,
.is_sysmc_blksize = SYSMEMSIZE,
/* Task Default Memory Class */
.is_taskmc_type = PXMcBuddyMemory,
.is_taskmc_size = PXMEM_ALIGN,
.is_taskmc_blk = Taskmem,
.is_taskmc_blksize = TASKMEMSIZE,
/* Memory block for System Default Object Pool */
.is_objmc_blk = (PxMemAligned_t *)PxObjmem,
.is_objmc_blksize = PX_OBJMEMSIZE,
/* System Default Object Pool parameters */
.is_obj_number = NUM_OF_PXOBJS,
.is_obj_namelength = PXROS_NAMESIZE,
/* InitTask specification */
.is_inittask = &InitTaskSpec,
/* Memory protection settings */
.is_sys_ro_protection[0] = _SYS_RO_PROTECTION,
};
/* InitSpecsArray needed by 'PxInit()' function. */
const PxInitSpecsArray_t InitSpecsArray =
{
[0] = &InitSpec
};
/* Inittask's task function */
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) ;
}
/* Task1's task function */
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;
/* Initialize the ARM Cortex-M interrupt and trap system. */
IrqInit();
/* Initialize the Trap Vector Table */
PxTrapInitVectab(IrqSystemInstall);
/* Initialize the Interrupt Vector Table */
PxIntInitVectab(IrqGetMaxIrqNum(), IrqInstall, IrqSystemInstall);
/* Start the PXROS kernel */
error = PxInit(InitSpecsArray, 1 /* number of cores */ );
if (error != PXERR_NOERROR)
{
PxPanic();
}
/* We should never reach this line */
while(1);
}
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));
/* protection[0] region provides R+W access to Task1 object */
context.protection[0].lowerBound = (unsigned int)this;
context.protection[0].upperBound = ((unsigned int)this) + sizeof(Task1);
context.protection[0].mattr = MEMORY_ATTRIBUTES(RWPermission)
/* protection[1] region in not used */
context.protection[1].lowerBound = -1;
context.protection[1].upperBound = -1;
context.protection[1].mattr = MEMORY_ATTRIBUTES(NoAccessPermission),
ts.ts_name = (const PxChar_t *)"Task1";
ts.ts_fun = TaskEntry;
ts.ts_mc = memClass;
ts.ts_opool = objPool;
ts.ts_privileges = PXUserPrivilege;
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:
-
Terminate the task
-
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);
}