line source
/****************************************************************************/
/* */
/* Name rvf_task.c */
/* */
/* Function this file contains \rvf task related functions */
/* */
/* Version 0.1 */
/* */
/* Date Modification */
/* ------------------------------------ */
/* 3/12/99 Create */
/* 10/27/99 remove all non-nucleus sections (#ifdef) */
/* change tasks priority and time_slicing */
/* 11/17/1999 change RVF_create_task and RVF_get_taskid functions */
/* 30/11/99 compliant to RV coding guidelines */
/* 28/08/2000 add mutex related functions. */
/* */
/* Author David Lamy-Charrier (dlamy@tif.ti.com) */
/* */
/* (C) Copyright 1999 by Texas Instruments Incorporated, All Rights Reserved*/
/****************************************************************************/
#ifndef _WINDOWS
#include "config/rv.cfg"
#endif
#include "nucleus.h"
#include "rv/rv_general.h"
#include "rvf/rvf_api.h"
#include "rvf/rvf_i.h"
#include "rvm/rvm_i.h" /* ONLY for Task Codes */
#include "rvm/rvm_use_id_list.h"
#include <stdio.h>
#include <string.h>
/* include the rvtool_trace.h file only in the RivieraTool */
#ifdef _WINDOWS
#ifndef _CONSOLE
// #include "rvtool_trace.h"
#endif
#include <windows.h>
#endif
#define RVF_STATIC_ALLOC_NB 1
/**********************************************************************
** Nucleus specific definitions
*/
typedef void (*NU_TASK_ENTRY)(UNSIGNED, VOID *); //
/* array of tasks */
/**********************************************************************
* Note: if dynamic mem alloc of "pOSTCB" creates too much fragentation
* The origianl way me be utilised and pointed to by a addr_id table
* structure, which is proposed for type 2 support.
***********************************************************************/
#define _RALLOC_TASK_CNTRL_BLK(tb) rvf_get_buf(rvm_sys_mem_bank, sizeof(NU_TASK), tb)
#define _RALLOC_TASK_EVT_GRP(tb) rvf_get_buf(rvm_sys_mem_bank, sizeof(NU_EVENT_GROUP), tb)
#define _RALLOC_TASK_RT_ADDR_DATA(tb) rvf_get_buf(rvm_sys_mem_bank, sizeof(T_RVF_RT_ADDR_ID_DATA), tb)
//#define _RALLOC_TASK_RT_TM(tb) rvf_get_buf(rvm_sys_mem_bank, sizeof(T_RVF_TIMER_LIST_Q), tb)
/*static NU_TASK bOSTCB[RVF_STATIC_ALLOC_NB];
static NU_EVENT_GROUP bOSEvtGrp[RVF_STATIC_ALLOC_NB];
static UINT8 *bOSStack;
static UINT16 bOSStackSize;
static char bOSTName[RVF_STATIC_ALLOC_NB][RVF_STATIC_ALLOC_NB];
*/
static UINT8 task_counter = 0;
static INT16 OSDisableNesting = 0;
static BOOL OSInterruptAlreadyMasked = FALSE;
static INT32 OSLastIntLevel;
static T_RVF_G_ADDR_ID _RDV=RVF_INVALID_ADDR_ID;
T_RVF_RET _initSysRtData(void);
/*******************************************************************************
**
** Function rvf_AllocTaskXyz()
**
** Description
**
**
** Returns T_RVF_MB_STATUS
**
*******************************************************************************/
T_RVF_RET _initSysRtData(void) { /*A-M-E-N-D-E-D!*/
int i=0;
for (i=0; i < MAX_RVF_G_ADDR_ID; i++) pRtAddrIdTable[i]=NULL;
// pOSTCB[0]=&OSTCB[0];
return RVF_OK;
}
/*******************************************************************************
**
** Function rvf_init
**
** Description This function is called once at startup to initialize
** all the rvf (timer, buffer...).
**
** Returns void
**
*******************************************************************************/
void rvf_init(void) {
/* UINT8 i; */
/* Initialize RVF variables */
/*for (i = 0; i < MAX_RVF_TASKS; i++) {
OSStack[i] = 0;
OSStackSize[i] = 0;
OSTName[i][0] = 0;
memset( &OSTCB[i], 0, sizeof(NU_TASK) );
memset( &OSEvtGrp[i], 0, sizeof(NU_EVENT_GROUP) );
}
// for (i = 0; i < 1; i++) memset( &OSTCB[i], 0, sizeof(NU_TASK) );
*/
_initSysRtData();
_rvf_buffer_init();
_rvf_timers_init();
}
/*******************************************************************************
**
** Function _rvf_name_cpy
**
** Description Internal function which copy a string in a buffer.
** The string may be null-terminated or length bytes long.
**
** Returns void
**
*******************************************************************************/
void _rvf_name_cpy(char * dest, char * source, UINT8 length) {
UINT8 cpt;
for( cpt = 0; cpt < length ; cpt++) {
dest[cpt] = source[cpt];
if (source[cpt] == 0) { return;}
}
}
T_RVF_G_ADDR_ID rvf_get_context() {
T_RVF_G_ADDR_ID gid=rvf_get_taskid();
if(pRtAddrIdTable[gid]->type_code==ET2_HOST_TASK) {
return pRtAddrIdTable[gid]->virtualContext;
} else {
return pRtAddrIdTable[gid]->host_addr_id;
}
}
void rvf_setRDV(T_RVF_G_ADDR_ID tid,T_RVF_G_ADDR_ID vid) {
if(pRtAddrIdTable[tid]) pRtAddrIdTable[tid]->virtualContext=vid;
}
/**************************************************************
* Function _rvf_name_cpy
*
***************************************************************/
T_RVF_G_ADDR_ID rvf_allocate_task_id(UINT8 isRealTask) {
T_RVF_G_ADDR_ID i=0;
UINT8 isTask=1;
/* Note: differentiation is made between REAL and VIRTUAL IDs
* to provide for backwards compatabible LEGACY timer implementations
* The Real task ids should be in sync with:
* "static rvf_Timer[MAX_RVF_TASKS][RVF_NUM_TASK_TIMERS]",
* defined in "rvf_time.c". In the future, one NU_Timer blk will
* be pointed to in the rt global addr table. Hence, eliminating
* the large resource of "rvf_Timer[][]"
*/
if(!pRtAddrIdTable[i]) return RVF_INVALID_ADDR_ID;
if(isRealTask) {
/* REAL TASK */
for(i=0; pRtAddrIdTable[i]!=NULL && i<MAX_RVF_TASKS; i++);
if (i < MAX_RVF_TASKS) { /* alloc. and init. */
if(_RALLOC_TASK_RT_ADDR_DATA((T_RVF_BUFFER**)&pRtAddrIdTable[i])) return RVF_INVALID_TASK;
memset( pRtAddrIdTable[i], 0, sizeof(T_RVF_RT_ADDR_ID_DATA) );
rvf_mbox_buffer_init(pRtAddrIdTable[i]);
} else return RVF_INVALID_ADDR_ID;
} else {
/* VIRTUAL TASK */
for(i=MAX_RVF_TASKS; pRtAddrIdTable[i]!=NULL && i<MAX_RVF_G_ADDR_ID; i++);
if (i < MAX_RVF_G_ADDR_ID) { /* alloc. and init. */
if(_RALLOC_TASK_RT_ADDR_DATA((T_RVF_BUFFER**)&pRtAddrIdTable[i])) return RVF_INVALID_TASK;
memset( pRtAddrIdTable[i], 0, sizeof(T_RVF_RT_ADDR_ID_DATA) );
rvf_mbox_buffer_init(pRtAddrIdTable[i]);
} else return RVF_INVALID_ADDR_ID;
}
return i;
}
/* MUST RESOLVE ERROR CODES '1' is just for P of C */
T_RVF_RET rvf_setRtAddrSweIndex(T_RVF_G_ADDR_ID id, UINT8 sweIndex) {
if(id>=MAX_RVF_G_ADDR_ID) return 1;
pRtAddrIdTable[id]->swe_db_index=sweIndex;
// pRtAddrIdTable[id]->type_code=tcode; /* allows type to be set if not in swe */
return RVF_OK;
}
T_RVF_RET rvf_setHostTaskStackPtr(T_RVF_G_ADDR_ID id, UINT8* pStack) { /* deprecated ! */
if(id>=MAX_RVF_TASKS) return 1;
pRtAddrIdTable[id]->p_os_stack=pStack;
return RVF_OK;
}
T_RVF_RET rvf_isHostingTaskIdle(T_RVF_G_ADDR_ID id, UINT8* status) { /* deprecated ! */
if(id>=MAX_RVF_TASKS) return RVF_INVALID_PARAMETER;
if(!pRtAddrIdTable[id]) return RVF_INVALID_PARAMETER;
if(pRtAddrIdTable[id]->type_code!=ET2_HOST_TASK) return RVF_INVALID_PARAMETER;
if(pRtAddrIdTable[id]->hosting_count==0) *status=1;
return RVF_OK;
}
/* convenience/helper fnc. */
T_RVF_G_ADDR_ID resolveHostAddrId(T_RVF_G_ADDR_ID id) {
if(!pRtAddrIdTable[id]) return RVF_INVALID_ADDR_ID;
return pRtAddrIdTable[id]->host_addr_id;
}
/* HostingCounter enables one to deduce if task can be terminated */
/* ERROR return val must be revised */
T_RVF_RET rvf_registerToHost(T_RVF_G_ADDR_ID host_id, T_RVF_G_ADDR_ID eid) {
UINT8 i;
if (host_id >= MAX_RVF_TASKS || eid >= MAX_RVF_G_ADDR_ID ) return RV_INVALID_PARAMETER;;
for(i=0;pRtAddrIdTable[host_id]->parasites[i]!=0 && i < MAX_PARASITES; i++);
pRtAddrIdTable[host_id]->parasites[i]=eid;
pRtAddrIdTable[host_id]->hosting_count++;
return RVF_OK;
}
T_RVF_RET rvf_unregisterFromHost(T_RVF_G_ADDR_ID host_id, T_RVF_G_ADDR_ID pid) {
UINT8 i=0;
if (pRtAddrIdTable[host_id]->hosting_count !=0) {
for(i=0; i<MAX_PARASITES || pRtAddrIdTable[host_id]->parasites[i]==pid; i++);
pRtAddrIdTable[host_id]->parasites[i]=0;
pRtAddrIdTable[host_id]->hosting_count--;
} else return RV_INVALID_PARAMETER;
return RVF_OK;
}
T_RVF_RET rvf_associateGrpToHost(T_RVF_G_ADDR_ID host_id, T_RVF_GD_ID gd_id) {
if (host_id >= MAX_RVF_TASKS ) return RV_INVALID_PARAMETER;
pRtAddrIdTable[host_id]->gdHost=gd_id;
return RVF_OK;
}
/*T_RVF_RET rvf_unregisterGrpFromHost(T_RVF_G_ADDR_ID host_id, T_RVF_G_ADDR_ID pid) {
if (pRtAddrIdTable[host_id]->hosting_count !=0) {
pRtAddrIdTable[host_id]->parasites[pid]=0;
pRtAddrIdTable[host_id]->hosting_count--;
} else return RV_INVALID_PARAMETER;
return RVF_OK;
}*/
T_RVF_G_ADDR_ID rvf_resolveHostingAddrId(T_RVM_GROUP_DIRECTIVE gd) {
int i=0;
for(i=1; i<MAX_RVF_TASKS; i++) { // i=1 by-pass RVM task
if(pRtAddrIdTable[i]!=NULL) {
if( pRtAddrIdTable[i]->type_code==ET2_HOST_TASK &&
// pRtAddrIdTable[i]->priority==priority && // to do ...
// pRtAddrIdTable[i]->os_stack_size>=stack_size
pRtAddrIdTable[i]->gdHost==gd.group_directive &&
pRtAddrIdTable[i]->hosting_count<MAX_PARASITES ) return i; // def. 10 A+ .
}
}
return RVF_INVALID_ADDR_ID; /* nothing found ret. param must be invalid*/
}
/*********************************************************************
* start() and stop() should be added to params, due to defered calling
* Allow for parasites to be added at RT and their start to be called.
*********************************************************************/
T_RVF_RET rvf_create_virtual_task (T_RV_RET (* handle_message)(T_RV_HDR * msg),
T_RV_RET (* handle_timer)(T_RV_HDR * msg),
T_RVF_G_ADDR_ID task_id, T_RVF_G_ADDR_ID host_task_id, char *taskname,
UINT8 priority, UINT8 tcode) {
if(!pRtAddrIdTable[task_id]) { /* allow for static init. or previous dyn init, eg. idle*/
if(_RALLOC_TASK_RT_ADDR_DATA((T_RVF_BUFFER**)&pRtAddrIdTable[task_id])) return RVF_INTERNAL_ERR;
memset( pRtAddrIdTable[task_id], 0, sizeof(T_RVF_RT_ADDR_ID_DATA) );
rvf_mbox_buffer_init(pRtAddrIdTable[task_id]);
} /*else printf("RVF: task rt addr %d already alloc'ed\n", task_id); */
pRtAddrIdTable[task_id]->host_addr_id=host_task_id;
pRtAddrIdTable[task_id]->symbolic_name=taskname;
pRtAddrIdTable[task_id]->handle_message=handle_message;
pRtAddrIdTable[task_id]->handle_timer=handle_timer;
pRtAddrIdTable[task_id]->type_code=tcode;
pRtAddrIdTable[task_id]->pOSTCB=NULL; /* init to NULL for res.'free' */
pRtAddrIdTable[task_id]->pOSEvtGrp=NULL;
pRtAddrIdTable[task_id]->p_os_stack=NULL;
// pRtAddrIdTable[task_id]->p_tm_q=NULL;
// rvf_registerToHost(host_task_id, task_id);
return RVF_OK;
}
T_RVF_RET rvf_register_t3_handlers (T_RVF_G_ADDR_ID task_id,
T_RV_RET (* handle_message)(T_RV_HDR * msg),
T_RV_RET (* handle_timer)(T_RV_HDR * msg) ) {
pRtAddrIdTable[task_id]->handle_message=handle_message;
pRtAddrIdTable[task_id]->handle_timer=handle_timer;
return RVF_OK;
}
/* RVM must create a stack with its MB and pass as params to task create */
/*T_RVF_RET rvf_create_host_task (T_RV_RET (* proxy)(void), T_RVF_G_ADDR_ID task_id,
char *taskname, UINT8 *stack, UINT16 stacksize,
UINT8 priority, UINT8 tcode, UINT8 time_slicing, T_RVF_TASK_STATE suspend) {
return rvf_create_task( (TASKPTR)proxy, task_id, taskname, stack, stacksize,\
priority, tcode, time_slicing, suspend ) ;
}*/
/*******************************************************************************
**
** Function rvf_create_task
**
** Description This function is called to create a new rvf task.
** time_slice represents the number of Nucleus ticks before a task is interrupted.
** 0 for no time-slicing.
**
** Returns RVF_OK if successful, else an error code
**
*******************************************************************************/
T_RVF_RET rvf_create_legacy_task (TASKPTR task_entry, UINT8 task_id, char *taskname, UINT8 *stack, UINT16 stacksize, UINT8 priority, UINT8 time_slicing, T_RVF_TASK_STATE is_suspend) {
return rvf_create_task(task_entry,task_id,taskname,stack,stacksize,priority,ET4_TASK,time_slicing,is_suspend);
}
T_RVF_RET rvf_create_task (TASKPTR task_entry, T_RVF_G_ADDR_ID task_id, char *taskname, UINT8 *stack, UINT16 stacksize,
UINT8 priority, UINT8 tcode, UINT8 time_slicing, T_RVF_TASK_STATE suspend) {
/*if (task_id >= MAX_RVF_TASKS) { return 1; } */
if (task_counter >= MAX_RVF_TASKS) { return 1; }
/* fill the task stack with a 0xFE pattern to allow use with stack monitoring tool */
memset( stack, 0xFE, stacksize );
/* allow for immediate task creation, eg. no alloc taskId(), but #defined task No. Dangerous!*/
if(!pRtAddrIdTable[task_id]) {
if(_RALLOC_TASK_RT_ADDR_DATA((T_RVF_BUFFER**)&pRtAddrIdTable[task_id])) return RVF_INTERNAL_ERR;
memset( pRtAddrIdTable[task_id], 0, sizeof(T_RVF_RT_ADDR_ID_DATA) );
rvf_mbox_buffer_init(pRtAddrIdTable[task_id]);
} /*else printf("RVF: task rt addr %d already alloc'ed\n", task_id); */
/*if(_RALLOC_TASK_RT_TM((T_RVF_BUFFER**)&pRtAddrIdTable[task_id]->p_tm_q)) {
rvf_free_buf(pRtAddrIdTable[task_id]);
pRtAddrIdTable[task_id]=NULL;
return RVF_INTERNAL_ERR;
} else pRtAddrIdTable[task_id]->p_tm_q->timerCnt=0;*/
pRtAddrIdTable[task_id]->hosting_count=0;
pRtAddrIdTable[task_id]->host_addr_id=task_id;
pRtAddrIdTable[task_id]->symbolic_name=taskname;
pRtAddrIdTable[task_id]->priority=priority;
pRtAddrIdTable[task_id]->type_code=tcode;
memset(&pRtAddrIdTable[task_id]->parasites, 0, (sizeof(T_RVF_G_ADDR_ID)*MAX_PARASITES));
if (stack) {
pRtAddrIdTable[task_id]->p_os_stack = (UINT8 *)stack;// - stacksize;
pRtAddrIdTable[task_id]->os_stack_size = stacksize;
} else {
// rvf_free_buf(pRtAddrIdTable[task_id]->p_tm_q);
rvf_free_buf(pRtAddrIdTable[task_id]);
pRtAddrIdTable[task_id]=NULL;
return RVF_INTERNAL_ERR;
}
if(_RALLOC_TASK_CNTRL_BLK((T_RVF_BUFFER**)&pRtAddrIdTable[task_id]->pOSTCB)) {
rvf_free_buf(stack);
// rvf_free_buf(pRtAddrIdTable[task_id]->p_tm_q);
rvf_free_buf(pRtAddrIdTable[task_id]);
pRtAddrIdTable[task_id]=NULL;
return RVF_INTERNAL_ERR;
}
memset( pRtAddrIdTable[task_id]->pOSTCB, 0, sizeof(NU_TASK) );
if(_RALLOC_TASK_EVT_GRP((T_RVF_BUFFER**)&pRtAddrIdTable[task_id]->pOSEvtGrp)) {
rvf_free_buf(pRtAddrIdTable[task_id]->pOSTCB);
rvf_free_buf(stack);
// rvf_free_buf(pRtAddrIdTable[task_id]->p_tm_q);
rvf_free_buf(pRtAddrIdTable[task_id]);
pRtAddrIdTable[task_id]=NULL;
return RVF_INTERNAL_ERR;
}
memset( pRtAddrIdTable[task_id]->pOSEvtGrp, 0, sizeof(NU_EVENT_GROUP) );
/* Create one Event Group for this task */
if( NU_SUCCESS != \
NU_Create_Event_Group (pRtAddrIdTable[task_id]->pOSEvtGrp,\
taskname) ) {
return RVF_INTERNAL_ERR;
}
//}
/* Create Task */
if ( NU_SUCCESS !=
NU_Create_Task (pRtAddrIdTable[task_id]->pOSTCB, /* Task Control Block */
taskname, /*taskname,*/ /* Task Name */
(NU_TASK_ENTRY )task_entry, /* Task Entry Function */
0, /* why prev. task_id ??? */ /* ARGC A-M-E-N-D-E-D! */
NULL, /* ARGV */
pRtAddrIdTable[task_id]->p_os_stack, /* Begining of Stack */
pRtAddrIdTable[task_id]->os_stack_size, /* Stack size */
priority, /* Priority */
time_slicing, /* Time Slicing Period*/
NU_PREEMPT, /* Preemption allowed */
(OPTION)(suspend == RUNNING ? NU_START : NU_NO_START) )/* Start the task or suspend it */
) {
return RVF_INTERNAL_ERR;
}
task_counter++; /* MUST 'DEC' ON TASK TERMINATION */
return RVF_OK;
}
/* to be called from func. 'create_tasks()' of module "create_RVtasks.c"
* utilises static alloated system variables */
/*T_RVF_RET rvf_create_boot_task (TASKPTR task_entry, UINT8 task_id, char *taskname, UINT8 *stack, UINT16 stacksize, UINT8 priority, UINT8 time_slicing, T_RVF_TASK_STATE suspend) {
if (task_id >= MAX_RVF_TASKS) { return 1;}
if (stack) {
bOSStack = (UINT8 *)stack;// - stacksize;
bOSStackSize = stacksize;
}
// copy the task name into an internal buffer
_rvf_name_cpy( &(bOSTName[0][0]), taskname, RVF_MAX_TASK_LEN);
// fill the task stack with a 0xFE pattern to allow use with stack monitoring tool
memset( stack, 0xFE, stacksize );
// Create one Event Group for this task
if( NU_SUCCESS != NU_Create_Event_Group (&bOSEvtGrp[0], taskname) ){
return RVF_INTERNAL_ERR;
}
// Create Task
if ( NU_SUCCESS !=
NU_Create_Task (&bOSTCB[0], // (reserved)Task Control Block
taskname, // Task Name
(NU_TASK_ENTRY )task_entry, // Task Entry Function
task_id, // ARGC
NULL, // ARGV
bOSStack, // Begining of Stack
stacksize, // Stack size
priority, // Priority
time_slicing, // Time Slicing Period
NU_PREEMPT, // Preemption allowed
(OPTION)(suspend == RUNNING ? NU_START : NU_NO_START) )// Start the task or suspend it
)
{ return RVF_INTERNAL_ERR;
}
task_counter++;
return RVF_OK;
}*/
/* Later timer blk must be added, once made dynamic */
T_RVF_RET rvf_free_sys_resources(T_RVF_G_ADDR_ID gid, UINT8 rm) {
if(!pRtAddrIdTable[gid]) return RVF_INTERNAL_ERR;
if(rm==1 || rm==2) {
if(pRtAddrIdTable[gid]->pOSTCB)rvf_free_buf(pRtAddrIdTable[gid]->pOSTCB);
if(pRtAddrIdTable[gid]->pOSEvtGrp)rvf_free_buf(pRtAddrIdTable[gid]->pOSEvtGrp);
if(pRtAddrIdTable[gid]->p_os_stack)rvf_free_buf(pRtAddrIdTable[gid]->p_os_stack);
task_counter--;
}
if(rm==0 || rm==2) {
if(pRtAddrIdTable[gid])rvf_free_buf(pRtAddrIdTable[gid]);
pRtAddrIdTable[gid]=NULL;
}
return RVF_OK;
}
/*******************************************************************************
**
** Function rvf_exit_task
**
** Description This function is called to stop a rvf task.
** A task can kill another task or itself.
**
** Returns void
**
*******************************************************************************/
void rvf_exit_task (T_RVF_G_ADDR_ID task_id)
{
if(!pRtAddrIdTable[task_id]) return;
/*
** Empty task's mail box
*/
_rvf_empty_mailboxes(task_id);
/*
** Terminate task
*/
NU_Terminate_Task(pRtAddrIdTable[task_id]->pOSTCB); /*&OSTCB[task_id]);*/
NU_Delete_Task(pRtAddrIdTable[task_id]->pOSTCB);
/*
** Delete related event group
*/
NU_Delete_Event_Group (pRtAddrIdTable[task_id]->pOSEvtGrp);
pRtAddrIdTable[task_id]->p_os_stack=0;
//OSStack[task_id] = 0;
}
/*******************************************************************************
**
** Function rvf_suspend_task
**
** Description This function is called to suspend a rvf task.
** A task can suspend another task or itself.
**
** Returns void
**
*******************************************************************************/
T_RVF_RET rvf_suspend_task (T_RVF_G_ADDR_ID task_id)
{
if(!pRtAddrIdTable[task_id]) return RVF_INVALID_PARAMETER;
NU_Suspend_Task(pRtAddrIdTable[task_id]->pOSTCB); // A-M-E-N-D-E-D!
return RVF_OK;
}
/*******************************************************************************
**
** Function rvf_wait
**
** Description This function is called by tasks to wait for a specific
** event or set of events. The task may specify the duration
** that it wants to wait for, or 0 if infinite.
**
** Returns the event mask of received events or zero if timeout
**
*******************************************************************************/
UINT16 rvf_wait (UINT16 flag, UINT32 timeout) {
T_RVF_G_ADDR_ID rtask = rvf_get_taskid();
if (!timeout) timeout = 0xFFFFFFFFL;
return rvf_evt_wait(rtask, flag, timeout);
}
UINT16 rvf_evt_wait(T_RVF_G_ADDR_ID rtask, UINT16 flag, UINT32 timeout) {
#define RVF_RET_TIME_OUT 0
UINT16 mbxEvt = 0;
UNSIGNED evt = 0;
UNSIGNED clear = 0;
STATUS status_ret;
/* Check if anything in any of the mailboxes. Possible race condition. */
if (rtask>=MAX_RVF_TASKS || !pRtAddrIdTable[rtask]) {
RVM_TRACE_WARNING_PARAM("RVF: Illegal MBOX or MBOX not ready!", rtask);
return (UINT16) RVF_RET_TIME_OUT;
}
if (pRtAddrIdTable[rtask] && pRtAddrIdTable[rtask]->OSTaskQFirst[0])
mbxEvt |= RVF_TASK_MBOX_0_EVT_MASK;
if (pRtAddrIdTable[rtask] && pRtAddrIdTable[rtask]->OSTaskQFirst[1])
mbxEvt |= RVF_TASK_MBOX_1_EVT_MASK;
if (pRtAddrIdTable[rtask] && pRtAddrIdTable[rtask]->OSTaskQFirst[2])
mbxEvt |= RVF_TASK_MBOX_2_EVT_MASK;
if (pRtAddrIdTable[rtask] && pRtAddrIdTable[rtask]->OSTaskQFirst[3])
mbxEvt |= RVF_TASK_MBOX_3_EVT_MASK;
/* If any valid event if pending, return immediately */
if (mbxEvt & flag)
{
/* Return only those bits which user wants... */
evt = (UINT16) (mbxEvt & flag);
/* clear the nucleus event(s) for mailboxes */
if ( mbxEvt & 0x000F ) /* a mailbox event is signaled*/
{ NU_Retrieve_Events (pRtAddrIdTable[rtask]->pOSEvtGrp, (UNSIGNED) mbxEvt & 0x000F, NU_AND_CONSUME,
(UNSIGNED *)&clear, NU_NO_SUSPEND);
}
return ((UINT16) evt);
}
if(pRtAddrIdTable[rtask]) {
status_ret = NU_Retrieve_Events (pRtAddrIdTable[rtask]->pOSEvtGrp,
(UNSIGNED) flag, NU_OR_CONSUME,
(UNSIGNED *)&evt, timeout );
if ( status_ret == NU_SUCCESS) {
return (UINT16) evt;
} else { /* timeout or error case */
return (UINT16) RVF_RET_TIME_OUT;
}
} return (UINT16) RVF_RET_TIME_OUT;
}
/*******************************************************************************
**
** Function rvf_wait_for_specific_msg
**
** Description This function is called by tasks to wait for a specific
** message in the specified mailbox. The task may specify the duration
** that it wants to wait for, or 0 if infinite.
**
** Returns A pointer to the message, NULL in case of time-out.
**
*******************************************************************************/
T_RVF_BUFFER * rvf_wait_for_specific_msg(UINT16 msg_code, UINT8 mbox, UINT32 timeout)
{
T_RVF_G_ADDR_ID task_id = rvf_get_taskid();
T_RVF_BUFFER * p_buf = NULL;
T_RVF_INTERNAL_BUF * p_hdr;
UNSIGNED clear = 0;
STATUS status_ret;
UINT32 wait_time;
UINT32 init_time = rvf_get_tick_count();
/* check input parameter */
if ( mbox >= RVF_NUM_TASK_MBOX) /* NOTE: must be def to 2 max */
{ rvf_send_trace( "RVF: rvf_wait_for_specific_msg(): invalid mailbox id", 52, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID);
return p_buf;
}
if(!timeout)
timeout = 0xFFFFFFFFL;
wait_time = timeout;
while( (rvf_get_tick_count() - init_time) < timeout )
{
/* test all messages in the mailbox */
if( pRtAddrIdTable[task_id]->OSTaskQFirst[mbox] )
{
rvf_disable(9);
p_hdr = pRtAddrIdTable[task_id]->OSTaskQFirst[mbox];
p_buf = MEM2USER(p_hdr);
/* test the first one */
if ( ((T_RV_HDR *)p_buf)->msg_id == msg_code )
{ /* message found, return it */
pRtAddrIdTable[task_id]->OSTaskQFirst[mbox] = p_hdr->p_next;
p_hdr->p_next = NULL;
#if RVF_ENABLE_BUF_LINKAGE_CHECK
RVF_SET_BUF_UNLINKED(p_hdr);
#endif
/* clear the Nucleus Event for this mailbox */
NU_Retrieve_Events( pRtAddrIdTable[task_id]->pOSEvtGrp, EVENT_MASK(mbox), NU_AND_CONSUME,
(UNSIGNED *)&clear, NU_NO_SUSPEND);
rvf_enable();
return p_buf;
}
while(p_hdr->p_next != NULL)
{
p_buf = MEM2USER(p_hdr->p_next);
if ( ((T_RV_HDR *)p_buf)->msg_id == msg_code )
{ /* remove it from the list */
p_hdr->p_next = ( (T_RVF_INTERNAL_BUF *) USER2MEM(p_buf))->p_next;
/* check if it the last one */
if ( pRtAddrIdTable[task_id]->OSTaskQLast[mbox] == USER2MEM(p_buf) )
{ pRtAddrIdTable[task_id]->OSTaskQLast[mbox] = p_hdr;
}
((T_RVF_INTERNAL_BUF *) USER2MEM(p_buf))->p_next = NULL;
#if RVF_ENABLE_BUF_LINKAGE_CHECK
RVF_SET_BUF_UNLINKED(USER2MEM(p_buf));
#endif
rvf_enable();
return p_buf;
}
p_hdr = p_hdr->p_next;
}
rvf_enable();
}
/* here, the message has not been found, so wait for a new message */
if ((wait_time != 0xFFFFFFFFL) &&
(timeout > rvf_get_tick_count() - init_time))
{
/* NU_Retrieve_Events bug: cannot call function with a parameter with F in MSB */
wait_time = (timeout - (rvf_get_tick_count() - init_time)) & 0x0FFFFFFFL;
}
status_ret = NU_Retrieve_Events( pRtAddrIdTable[task_id]->pOSEvtGrp, EVENT_MASK(mbox), NU_OR_CONSUME,
(UNSIGNED *)&clear, wait_time);
if( status_ret != NU_SUCCESS) /* time out */
{ return NULL;
}
}
return NULL;
}
/*******************************************************************************
**
** Function rvf_delay
**
** Description This function is called by tasks to sleep unconditionally
** for a specified amount of time.
**
** Returns void
**
*******************************************************************************/
void rvf_delay (UINT32 timeout)
{
if (timeout == 0)
{ timeout = 1;
}
NU_Sleep(timeout);
}
/*******************************************************************************
**
** Function rvf_send_event
**
** Description This function is called by tasks to send events to other
** tasks. Tasks can also send events to themselves.
**
** Returns 0 if all OK, else 1
**
*******************************************************************************/
UINT8 rvf_send_event (T_RVF_G_ADDR_ID task_id, UINT16 event) {
if (task_id >= MAX_RVF_TASKS || !pRtAddrIdTable[task_id] ) return 1;
NU_Set_Events (pRtAddrIdTable[task_id]->pOSEvtGrp, (UNSIGNED)event, NU_OR);
return 0;
}
/*******************************************************************************
**
** Function rvf_get_taskid
**
** Description This function gets the currently running task ID.
**
** Returns task ID
**
*******************************************************************************/
T_RVF_G_ADDR_ID rvf_get_taskid(void) { /* Retrieve the taskid using index of the task pointer in the OSTCB array */
NU_TASK * currTask=0;
T_RVF_G_ADDR_ID taskId=RVF_INVALID_ADDR_ID;
currTask = NU_Current_Task_Pointer();
if( currTask != NU_NULL) {
/* find the task pointer in the OSTCB array */
for ( taskId = 0; taskId < MAX_RVF_TASKS; taskId++) {
if( (pRtAddrIdTable[taskId]!= NULL) &&
((pRtAddrIdTable[taskId]->pOSTCB)) == currTask) return taskId;
}
return RVF_INVALID_ADDR_ID;
} else {
return RVF_INVALID_ADDR_ID; /* error case, must return an error code */
}
}
/*******************************************************************************
**
** Function rvf_get_taskname
**
** Description This function gets the currently running task name.
**
** Returns pointer to task name or NULL if error
**
*******************************************************************************/
char* rvf_get_taskname(void)
{ T_RVF_G_ADDR_ID id = rvf_get_taskid();
if (id == 0xFF) return NULL; /* return NULL if rvf_get_taskid returns 0xFF */
return pRtAddrIdTable[id]->symbolic_name; /*(OSTName[ id ]);*/
}
/*******************************************************************************
**
** Function rvf_enable
**
** Description This function enables interrupts.
**
** Returns void
**
*******************************************************************************/
void rvf_enable(void)
{
if( --OSDisableNesting == 0) /* Control nesting interrupt */
{
if( OSInterruptAlreadyMasked == TRUE) /* check if interrupts have been disabled outside RVF,
in that case, do not enable interrupts */
{ OSInterruptAlreadyMasked = FALSE;
}
else
{ NU_Control_Interrupts(OSLastIntLevel);
}
}
}
#ifdef _WINDOWS
/*******************************************************************************
**
** Function INT_Check_IRQ_Mask()
**
** Description This function checks if the IRQ are disabled (outside RVF).
**
** Returns IRQ mask
**
*******************************************************************************/
UINT32 INT_Check_IRQ_Mask(void)
{
return 0;
}
#else
/*-------------------------------------------------------*/
/* INT_Check_IRQ_Mask() */
/*-------------------------------------------------------*/
/* */
/* Description: check in the CPSR register if the IRQ */
/* are masked out or not. */
/* ------------ */
/* */
/*-------------------------------------------------------*/
/* Declaration of ASM INT_Check_IRQ_Mask function */
UINT32 INT_Check_IRQ_Mask(void);
asm(" .def $INT_Check_IRQ_Mask");
asm("$INT_Check_IRQ_Mask ");
asm(" .ref _INT_32_Check_IRQ_Mask");
asm(".state16");
asm(" ADR r0,_INT_32_Check_IRQ_Mask ");
asm(" BX r0 ");
asm(" .align");
asm(" .state32");
asm(" .def _INT_32_Check_IRQ_Mask");
asm("_INT_32_Check_IRQ_Mask ");
asm(" MRS r0,CPSR "); // pick up CPSR
asm(" BX lr "); // return to caller
#endif
/*******************************************************************************
**
** Function rvf_disable
**
** Description This function disables interrupts.
**
** Returns void
**
*******************************************************************************/
#define RVF_IRQ_DISABLED_MASK 0x00000080
void rvf_disable(UINT8 who)
{
/* Control interrupt nesting ourselves */
if (OSDisableNesting == 0)
{
if ( INT_Check_IRQ_Mask() & RVF_IRQ_DISABLED_MASK) /* if IRQ are disabled (outside RVF) */
{ OSInterruptAlreadyMasked = TRUE;
}
else
{ OSLastIntLevel = NU_Control_Interrupts(NU_DISABLE_INTERRUPTS);
}
}
OSDisableNesting++;
}
/*******************************************************************************
**
** Function rvf_used_stack
**
** Description This function tries to calculate the amount of
** stack used by looking for a zero.
**
** Returns the number of non-zero bytes on the stack
**
*******************************************************************************/
UINT16 rvf_used_stack(T_RVF_G_ADDR_ID task)
{
UINT16 j, stacksize;
UINT8 *p;
if(!pRtAddrIdTable[task]) return 0;
stacksize = pRtAddrIdTable[task]->os_stack_size; /*OSStackSize[task];*/
p = pRtAddrIdTable[task]->p_os_stack; /*OSStack[task];*/
for(j = 0; (j < stacksize) && (*p++ == 0xFE); j++);
return ((UINT16)(stacksize - j));
}
/*******************************************************************************
**
** Function rvf_dump_tasks
**
** Description This function dump all the rvf tasks.
**
** Returns void
**
*******************************************************************************/
void rvf_dump_tasks()
{ UINT8 num_task;
char task_info[100];
rvf_send_trace("*** START DUMPING TASKS ***", 27, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);
/* for each task, display its name, its id, its stack size*/
rvf_send_trace("*TASK_NAME Id Stack_size Used_stack", 35, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);
for ( num_task = 0; num_task < MAX_RVF_G_ADDR_ID; num_task++ )
{
/* trace the task if it has been created*/
if (pRtAddrIdTable[num_task] != 0 ) {
sprintf( task_info, "%10.10s %2d %5d %5d",
pRtAddrIdTable[num_task]->symbolic_name /*OSTName[num_task]*/,
num_task,
pRtAddrIdTable[num_task]->os_stack_size,
rvf_used_stack( num_task) );
rvf_send_trace( task_info, 35, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);
}
}
/* find a way to track task stack usage and display it */
/* using NU_Check_Stack, NU_Task_Information or finding the first non-zero value in the stack */
}
/****************************************************************************/
/* For Big Endian Processors swap the bytes */
#if defined(__BIG_ENDIAN)
UINT16 ntohs(UINT16 n)
{
register UINT8 tmp;
register UINT8 *p=(UINT8 *)&n;
tmp = p[0];
p[0] = p[1];
p[1] = tmp;
return n;
}
UINT32 ntohl(UINT32 n)
{
register UINT8 tmp;
register UINT8 *p=(UINT8 *)&n;
tmp = p[0];
p[0] = p[3];
p[3] = tmp;
tmp = p[1];
p[1] = p[2];
p[2] = tmp;
return n;
}
#endif /* __BIG_ENDIAN*/
/******************************************************************************
**
** Function rvf_send_trace
**
** Description This function displays a message essentially for debug purposes.
** It displays the msg_length characters of the string pointed by msg
** and the value of val.
**
** Returns void
**
******************************************************************************/
#ifdef _WINDOWS
#ifndef _CONSOLE
void rvf_send_trace1( INT8 * msg, UINT8 msg_length, UINT32 val, UINT8 TRACE_LEVEL, UINT32 swe_use_id)
{
/* Function to display trace message for Tool */
UINT32 trace_type = swe_use_id;
Trace( msg, msg_length, val, TRACE_LEVEL, trace_type);
}
#endif
#endif
#ifdef _CONSOLE /* CONSOLE */
void rvf_send_trace1( INT8 * msg, UINT8 msg_length, UINT32 val, UINT8 TRACE_LEVEL, UINT32 swe_use_id) {
const int MAX = 1000;
static int l = 0;
char buf[100];
HANDLE out = 0;
int nb;
if(!out)out=GetStdHandle(STD_OUTPUT_HANDLE);
rvf_disable(25);
sprintf(buf,"%s %d\n", msg, val);
WriteConsole(out, buf, strlen(buf), &nb, NULL);
if(l>=MAX) {
system("cls");
l=0;
} else l++;
rvf_enable();
}
#endif /* CONSOLE */
/*******************************************************************************
**
** Function rvf_resume_task
**
** Description This function is called to resume a rvf task which is in a suspend state.
**
** Returns RVF_OK if successful, else an error code
**
*******************************************************************************/
T_RVF_RET rvf_resume_task( T_RVF_G_ADDR_ID taskid)
{
if(!pRtAddrIdTable[taskid]) return RVF_INVALID_PARAMETER;
if(!pRtAddrIdTable[taskid]->pOSTCB) return RVF_INVALID_PARAMETER;
/* resume the task */
if ( NU_INVALID_TASK == NU_Resume_Task( pRtAddrIdTable[taskid]->pOSTCB) ) {// A-M-E-N-D-E-D!
return RVF_INTERNAL_ERR; //RVF_INVALID_PARAMETER;
}
return RVF_OK;
}
/*******************************************************************************
**
** Function rvf_initialize_mutex
**
** Description This function initialize a mutex structure, which will be used
** to protect shared variables against simultaneous access.
**
** Returns RVF_OK if successful, else an error code
**
*******************************************************************************/
T_RVF_RET rvf_initialize_mutex( T_RVF_MUTEX * mutex)
{
/* initializes the mutex structure */
if( NU_Create_Semaphore( (NU_SEMAPHORE *)mutex, "RVF", 1, NU_PRIORITY ) != NU_SUCCESS)
{ return RVF_INTERNAL_ERR;
}
return RVF_OK;
}
/*******************************************************************************
**
** Function rvf_lock_mutex
**
** Description This function locks a mutex to avoid simultaneous access.
** If the mutex is already locked, the task is suspended
** until the mutex is unlocked.
**
** Returns RVF_OK if successful, else an error code
**
*******************************************************************************/
T_RVF_RET rvf_lock_mutex( T_RVF_MUTEX * mutex)
{
if( NU_Obtain_Semaphore( (NU_SEMAPHORE *)mutex, NU_SUSPEND ) != NU_SUCCESS)
{ return RVF_INTERNAL_ERR;
}
return RVF_OK;
}
/*******************************************************************************
**
** Function rvf_unlock_mutex
**
** Description This function unlocks a mutex to avoid simultaneous access.
**
** Returns RVF_OK if successful, else an error code
**
*******************************************************************************/
T_RVF_RET rvf_unlock_mutex( T_RVF_MUTEX * mutex)
{
if( NU_Release_Semaphore( (NU_SEMAPHORE *)mutex ) != NU_SUCCESS)
{ return RVF_INTERNAL_ERR;
}
return RVF_OK;
}
/*******************************************************************************
**
** Function rvf_delete_mutex
**
** Description This function deletes a previously created mutex.
**
** Returns RVF_OK if successful, else an error code
**
*******************************************************************************/
T_RVF_RET rvf_delete_mutex( T_RVF_MUTEX * mutex)
{
if( NU_Delete_Semaphore( (NU_SEMAPHORE *)mutex ) != NU_SUCCESS)
{ return RVF_INTERNAL_ERR;
}
return RVF_OK;
}
void rvf_yield() { NU_Relinquish(); }
/* convenience function */
UINT8 rvf_isType2() {
if(pRtAddrIdTable[rvf_get_taskid()]->type_code==ET2_HOST_TASK) return 1;
else return 0;
}