view src/cs/riviera/rvf/rvf_buffer.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents 4e78acac3d88
children
line wrap: on
line source

/****************************************************************************/
/*                                                                          */
/*  Name        rvf_buffer.c                                                */
/*                                                                          */
/*  Function    this file contains rvf buffer handling functions            */
/*                                                                          */
/*  Version		0.1															*/
/*																			*/
/* 	Date       	Modification												*/
/*  ------------------------------------									*/
/*  3/12/99		Create														*/
/*  10/27/1999	remove all non-nucleus sections (#ifdef)					*/
/*	30/11/1999	compliant to RV coding guidelines							*/
/*  12/23/1999	change buffer management, add memory bank handling and		*/
/*				remove useless functions									*/
/*  07/12/2000	implement dynamic memory allocation.						*/
/*																			*/
/*	Author		David Lamy-Charrier (dlamy@tif.ti.com)						*/
/*																			*/
/* (C) Copyright 1999 by Texas Instruments Incorporated, All Rights Reserved*/
/****************************************************************************/

#ifndef _WINDOWS
#include "config/board.cfg"
#endif

#include "nucleus.h"
#include "rvm/rvm_use_id_list.h"
#include "rvf/rvf_api.h"
#include "rvf/rvf_i.h"
#include "support/exception.h"
#include "rvf/rvf_pool_size.h"

#include <string.h>
#include <stdio.h>


#if RVF_ENABLE_STATS	/* conditional inclusion of stdio.h for sprintf() function */
#ifdef _WINDOWS
#include <stdio.h>
#endif
#endif

#include "rv/rv_defined_swe.h"

#ifdef RVM_DAR_SWE
	#include "dar/dar_api.h"
#endif
#define RVF_INVALID_MD_ID_ERRROR  ("RVF: Invalid MB ID")

#define INC_END_INITIALIZE		2
#define RVF_INVALID_INDEX		0xFFFF

/************* TASK MAILBOXES *******************/
/* chained lists for task mailboxes			*/
T_RVF_INTERNAL_BUF *OSTaskQFirst[1][1]; //[MAX_RVF_TASKS][RVF_NUM_TASK_MBOX]; 
T_RVF_INTERNAL_BUF *OSTaskQLast [1][1]; //[MAX_RVF_TASKS][RVF_NUM_TASK_MBOX];

extern INC_Initialize_State;

T_RVF_RT_ADDR_ID_DATA*	pRtAddrIdTable[MAX_RVF_G_ADDR_ID]; 


/******** MEMORY POOLS ******************/
/* Define the buffer pools */
extern T_RVF_POOL		_rvf_pools[];

/*********** MEMORY BANKS ***********/
/* array of memory bank				*/
static T_RVF_MB			rvf_banks[RVF_MAX_REAL_MB];

/* array of waiting buffers */
static T_RVF_BUFFER *	waiting_buffers[RVF_MAX_WAITING_BUF];
static UINT16			next_buffer[RVF_MAX_WAITING_BUF];
static UINT16			first_free_element;

/* array of memory bank name and id*/
static T_RVF_MB_NAME_ID rvf_name_id[RVF_MAX_TOTAL_MB] = RVF_MB_MAPPING;


/* variable for statistics */
#if RVF_ENABLE_STATS
static UINT32 required_size = 0;
static UINT32 obtained_size = 0;
static UINT32 used_size		= 0;
static UINT32 mem_in_use	= 0;
#endif

/* lists of free buffers */
static T_RVF_INTERNAL_BUF * lists[RVF_NB_FREE_LISTS];

/* last split-off buffer */
T_RVF_INTERNAL_BUF * last_remainder = NULL;

/* allocated static buffer pools */
extern UINT8 Buf0[];
extern UINT8 Buf1[];

/********Internal windows function used to display memory status *******/
#ifdef _WINDOWS
extern void AddNewState(void *s,char *name,
				unsigned long  current,unsigned long  peak,
				unsigned long  water,unsigned long  bank);
#endif


/*******************************************************************************
**
** Function         _rvf_init_free_queue
**
** Description      Function called at startup to initialize a free
**                  pool (statically or dynamically allocated). 
**					It is called once for each free pool.
**
** Returns          void
**
*******************************************************************************/
void _rvf_init_free_queue (UINT8 id, UINT32 size, void *p_mem)
{
   T_RVF_INTERNAL_BUF	*hdr;
	UINT8 list_idx;

    /* round to up size to a multiple of 4 */
    size = (size + 3) & ~0x0003;

    /* store pool start address and size */
	_rvf_pools[id].start_address	= p_mem;

    _rvf_pools[id].pool_size		= size;
   
	/* Initialize the pool as a big free buffer */
	hdr = (T_RVF_INTERNAL_BUF *) p_mem;
	hdr->buf_size = size - sizeof(T_RVF_INTERNAL_BUF) - sizeof(UINT32); /* last 4 bytes of the pool losts*/ 
	hdr->header.p_prev = NULL;
	RVF_SET_PREV_IN_USE(hdr);

	NEXTCHUNK(hdr)->buf_size = 0;
	
	ENDSIZE(hdr) = hdr->buf_size;

	
	/* get the corresponding list and insert the buffer */
	list_idx		= RVF_BUF_LIST_INDEX( hdr->buf_size);
	hdr->p_next		= lists[list_idx];
	lists[list_idx] = hdr;

	last_remainder	= hdr;

}

void rvf_mbox_buffer_init(T_RVF_RT_ADDR_ID_DATA* pRtAddrIdElement) {
   UINT8   task_num, mbox_num;
    /* Initialize all mailboxes queues of all tasks*/
    for (task_num = 0; task_num < MAX_RVF_TASKS; task_num++) {
        for (mbox_num = 0; mbox_num < RVF_NUM_TASK_MBOX; mbox_num++) {
			pRtAddrIdElement->OSTaskQFirst[mbox_num] = NULL;
			pRtAddrIdElement->OSTaskQLast[mbox_num] = NULL;
        }
    }
}
/*******************************************************************************
**
** Function         _rvf_buffer_init
**
** Description      Called once internally by rvf at startup to initialize all
**                  buffers and free buffer pools.
**
** Returns          void
**
*******************************************************************************/
void _rvf_buffer_init(void)
{
    UINT8   list_num;
	UINT16	memory_bank_num;

    /* Initialize all mailboxes queues of all tasks*/
    /*  for (task_num = 0; task_num < MAX_RVF_TASKS; task_num++)
    {
        for (mbox_num = 0; mbox_num < RVF_NUM_TASK_MBOX; mbox_num++)
        {
            OSTaskQFirst[task_num][mbox_num] = NULL;
            OSTaskQLast [task_num][mbox_num] = NULL;
			//pRtAddrIdTable[task_num]->OSTaskQFirst[mbox_num] = NULL; // only if static
			//pRtAddrIdTable[task_num]->OSTaskQLast[mbox_num] = NULL; // only if static
        }
    } */

   /* initialize free lists */
   for (list_num = 0; list_num < RVF_NB_FREE_LISTS; list_num++)
   {
      lists[list_num] = NULL;
   }


   /* initialize buffer pools */
   _rvf_init_mem_pool();

	/* Initialize real memory banks */
	for (memory_bank_num = 0; memory_bank_num < RVF_MAX_REAL_MB; memory_bank_num++)
	{	
		rvf_banks[memory_bank_num].cur_memory_used		= 0;
		rvf_banks[memory_bank_num].watermark			= 0;
		rvf_banks[memory_bank_num].max					= 0;
		rvf_banks[memory_bank_num].first_buffer_index	= RVF_INVALID_INDEX;
		rvf_banks[memory_bank_num].last_buffer_index	= RVF_INVALID_INDEX;
		rvf_banks[memory_bank_num].func					= 0;
		rvf_banks[memory_bank_num].returned_red			= FALSE;
#if RVF_ENABLE_STATS
		rvf_banks[memory_bank_num].max_reached			= 0;
		rvf_banks[memory_bank_num].required_size		= 0;
		rvf_banks[memory_bank_num].num_buf				= 0;
#endif
	}

	/* Initialize total memory banks */
	for (memory_bank_num = 0; memory_bank_num < RVF_MAX_TOTAL_MB; memory_bank_num++)
	{	
		rvf_name_id[memory_bank_num].mb_params.size			= 0;
		rvf_name_id[memory_bank_num].mb_params.watermark	= 0;
	}


	/* initialize array of waiting buffers */
	first_free_element = 0;
	for( memory_bank_num = 0; memory_bank_num < RVF_MAX_WAITING_BUF; memory_bank_num++)
	{	waiting_buffers[memory_bank_num] = NULL;
		next_buffer[memory_bank_num] = memory_bank_num + 1;
	}
	next_buffer[RVF_MAX_WAITING_BUF-1] = RVF_INVALID_INDEX;
}

/*******************************************************************************
**
** Function         _rvf_send_msg_to_mbox
**
** Description      Called by applications to send a buffer to a SWE.
**                  (Temporary internal use - DO NOT USE IT !)
**					(Presently, only for Christophe          )
** Returns			RVF_OK if successful, else an error code.
**
*******************************************************************************/
T_RVF_RET _rvf_send_msg_to_mbox (T_RVF_G_ADDR_ID addr_id, UINT8 mbox,void *msg){
	return rvf_adapt_send_msg(addr_id, msg, mbox);
}

/*T_RVF_RET _rvf_send_msg_to_mbox (T_RVF_ADDR_ID addr_id, UINT8 mbox,void *msg)
{
    T_RVF_INTERNAL_BUF    *p_hdr;
	UINT8 task_id = (UINT8)addr_id;

    
    if ((task_id >= MAX_RVF_TASKS) )
    {
        rvf_send_trace( "RVF: rvf_send_msg(): invalid taskid", 35, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
        rvf_free_buf (msg);
        return RVF_INVALID_PARAMETER;
    }

#if RVF_ENABLE_BUF_CORRUPTION_CHECK	

	if (_rvf_chk_buf_damage(msg) == TRUE)
    {	rvf_send_trace( "RVF: rvf_send_msg(): buffer corrupted", 37, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
	}
#endif

	
	((T_RV_HDR *)msg)->dest_addr_id = addr_id;
	p_hdr = USER2MEM(msg);

#if RVF_ENABLE_BUF_LINKAGE_CHECK
  
	if ( RVF_BUF_IS_LINKED( p_hdr) )
	{
		rvf_send_trace( "RVF: rvf_send_msg(): buffer already enqueued", 44, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
        return RVF_MEMORY_ERR;
    }
#endif

    rvf_disable(8);		

	
    if (OSTaskQFirst[task_id][mbox])	
	{	OSTaskQLast[task_id][mbox]->p_next = p_hdr;
	}
    else
	{	OSTaskQFirst[task_id][mbox] = p_hdr;
	}
    OSTaskQLast[task_id][mbox] = p_hdr;

	p_hdr->p_next = NULL;

	if (pRtAddrIdTable[task_id]->OSTaskQFirst[mbox]) {
		pRtAddrIdTable[task_id]->OSTaskQLast[mbox]->p_next = p_hdr;
	} else {
		pRtAddrIdTable[task_id]->OSTaskQFirst[mbox] = p_hdr;
	}
    pRtAddrIdTable[task_id]->OSTaskQLast[mbox] = p_hdr;

	p_hdr->p_next = NULL;

#if RVF_ENABLE_BUF_LINKAGE_CHECK
	RVF_SET_BUF_LINKED(p_hdr);	
#endif

    rvf_enable();		

    rvf_send_event(task_id, (UINT16) (EVENT_MASK(mbox)) );
	return RVF_OK;
}*/

/*******************************************************************************
**
** Function         rvf_read_mbox
**
** Description      Called by applications to read a buffer from one of
**                  the task mailboxes.
**
** Returns          NULL if the mailbox was empty, else the address of a buffer
**
*******************************************************************************/
void * rvf_read_mbox (UINT8 mbox) {   
	T_RVF_G_ADDR_ID  task_id	= rvf_get_taskid();

	return rvf_read_addr_mbox (task_id, mbox) ;   
}
void * rvf_read_addr_mbox (T_RVF_G_ADDR_ID  task_id, UINT8 mbox) {   
    void * p_buf	= NULL;
    T_RVF_INTERNAL_BUF * p_hdr;

	mbox=resolveHostAddrId(mbox);

    if ((task_id >= MAX_RVF_TASKS) || (mbox >= RVF_NUM_TASK_MBOX))
    {   rvf_send_trace( "RVF: rvf_read_mbox(): invalid taskid or mbox", 44, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
        return NULL;
    } 

    rvf_disable(9);		/* enter critical section */

	/* if the chained list is not empty */
    /*if ( OSTaskQFirst[task_id][mbox] )	
    {   p_hdr = OSTaskQFirst[task_id][mbox];
        OSTaskQFirst[task_id][mbox] = p_hdr->p_next;

        p_hdr->p_next = NULL;*/
	if ( pRtAddrIdTable[task_id]->OSTaskQFirst[mbox] )	{
        p_hdr = pRtAddrIdTable[task_id]->OSTaskQFirst[mbox];
        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);	/* change buffer status */
#endif
        p_buf = (UINT8 *)p_hdr + sizeof(T_RVF_INTERNAL_BUF);
    }
 
	rvf_enable();		/* exit critical section */

    return (p_buf);
}

/*******************************************************************************
**
** Function         rvf_enqueue
**
** Description      Enqueue a buffer at the tail of the queue
**
** Returns          RVF_OK if successful, else an error code.
**
*******************************************************************************/
T_RVF_RET rvf_enqueue (T_RVF_BUFFER_Q *p_q, void *p_buf)
{
    T_RVF_INTERNAL_BUF *p_hdr;

#if RVF_ENABLE_BUF_CORRUPTION_CHECK
    if ( _rvf_chk_buf_damage(p_buf) )
    {	rvf_send_trace( "RVF: rvf_enqueue(): buffer corrupted", 36, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID);
    }
#endif

   	/* check if the buffer has been already enqueued */
    p_hdr = USER2MEM(p_buf);

#if RVF_ENABLE_BUF_LINKAGE_CHECK
	if( RVF_BUF_IS_LINKED(p_hdr) )
	{
		rvf_send_trace( "RVF: rvf_enqueue(): buffer already enqueued", 43, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID);
        return RVF_MEMORY_ERR;
    }
#endif

    rvf_disable(10);	/* enter critical section */

    /* Since the queue is exposed (C vs C++), keep the pointers in exposed format */
	/* p_q->p_last and p_q->p_first point to the user buffer, since p_hdr->p_next points to the T_RVF_INTERNAL_BUF */
    if (p_q->p_first)	/* if the queue is not empty */
    {
		T_RVF_INTERNAL_BUF * p_last_hdr = (T_RVF_INTERNAL_BUF *) ((UINT8 *)p_q->p_last - sizeof(T_RVF_INTERNAL_BUF) );
        p_last_hdr->p_next = p_hdr;
    }
    else
        p_q->p_first = p_buf;

    p_q->p_last = p_buf;
    p_q->count++;

    p_hdr->p_next = NULL;
#if RVF_ENABLE_BUF_LINKAGE_CHECK
    RVF_SET_BUF_LINKED(p_hdr);	/* change buffer status */
#endif

    rvf_enable();		/* exit critical section */
	return RVF_OK;
}



/*******************************************************************************
**
** Function         rvf_dequeue
**
** Description      Dequeue a buffer from the head of a queue
**
** Returns          NULL if queue is empty, else buffer
**
*******************************************************************************/
void * rvf_dequeue (T_RVF_BUFFER_Q *p_q)
{
    T_RVF_INTERNAL_BUF    *p_hdr;

    if (!p_q->count)	/* if the queue is empty */
        return (NULL);

    rvf_disable(12);	/* enter critical section */

    p_hdr = USER2MEM(p_q->p_first );


    /* Keep buffers such that RVF header is invisible */
    if (p_hdr->p_next)
        p_q->p_first = ((UINT8 *)p_hdr->p_next + sizeof(T_RVF_INTERNAL_BUF));
    else
    {
        p_q->p_first = NULL;
        p_q->p_last  = NULL;
    }

    p_q->count--;

    p_hdr->p_next = NULL;

#if RVF_ENABLE_BUF_LINKAGE_CHECK
    RVF_SET_BUF_UNLINKED(p_hdr);	/* change buffer status */
#endif

    rvf_enable();		/* exit critical section */

    return (MEM2USER(p_hdr) );
}



/*******************************************************************************
**
** Function         rvf_enqueue_head
**
** Description      Enqueue a buffer at the head of the queue
**
** Returns          RVF_OK if successful, else an error code.
**
*******************************************************************************/
T_RVF_RET rvf_enqueue_head (T_RVF_BUFFER_Q *p_q, void *p_buf)
{
    T_RVF_INTERNAL_BUF    *p_hdr;

#if RVF_ENABLE_BUF_CORRUPTION_CHECK
    if ( _rvf_chk_buf_damage(p_buf) )
    {	rvf_send_trace( "RVF: rvf_enqueue_head(): buffer corrupted", 41, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
    }
#endif

    p_hdr = USER2MEM(p_buf);

#if RVF_ENABLE_BUF_LINKAGE_CHECK
	if( RVF_BUF_IS_LINKED(p_hdr) )
    {	rvf_send_trace( "RVF: rvf_enqueue_head(): buffer already enqueued", 48, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
        return RVF_MEMORY_ERR;
    }
#endif

    rvf_disable(11);		/* enter critical section */

    if (p_q->p_first)		/* if the queue is not empty */
    {   p_hdr->p_next = (T_RVF_INTERNAL_BUF *)((UINT8 *)p_q->p_first - sizeof(T_RVF_INTERNAL_BUF) );
        p_q->p_first = p_buf;
    }
    else
    {    p_q->p_first = p_buf;
        p_q->p_last  = p_buf;
        p_hdr->p_next = NULL;
    }
    p_q->count++;

#if RVF_ENABLE_BUF_LINKAGE_CHECK
	RVF_SET_BUF_LINKED(p_hdr);	/* change buffer status */
#endif
		

    rvf_enable();		/* exit critical section */
	
	return RVF_OK;
}



/*******************************************************************************
**
** Function         rvf_get_buf_size
**
** Description      Called by an application to get the size of a buffer.
**
** Returns          the size of the buffer or 0 if the address is invalid.
**
*******************************************************************************/
INLINE UINT32 rvf_get_buf_size (void *bptr)
{
    T_RVF_INTERNAL_BUF *p_hdr;

    p_hdr = (T_RVF_INTERNAL_BUF *)((UINT8 *) bptr - sizeof(T_RVF_INTERNAL_BUF) );

    if ((UINT32)p_hdr & 1) return 0; /* invalid pointer: odd address*/

    return (GETSIZE(p_hdr) - RVF_CORRUPT_OVERHEAD) ;
}


/*******************************************************************************
**
** Function         _rvf_chk_buf_damage
**
** Description      Called internally by rvf to check for buffer corruption.
**
** Returns          TRUE if there is a problem, else FALSE
**
*******************************************************************************/
#if RVF_ENABLE_BUF_CORRUPTION_CHECK
BOOLEAN _rvf_chk_buf_damage(void *bptr)
{
   UINT32 *lg;
	T_RVF_INTERNAL_BUF * p_hdr;
	
	if((UINT32)bptr & 1)	/* odd address */
	{	return TRUE;
	}

	p_hdr = USER2MEM(bptr);	/* get the internal header */

    lg = (UINT32*)( (UINT8*)bptr +  GETSIZE(p_hdr) - sizeof(UINT32) );

	 if (lg == 0)
		 return TRUE;

    if(*lg == GETSIZE(p_hdr) )
    {
        return FALSE;
    }
    return TRUE;
}
#endif



/*******************************************************************************
**
** Function         _find_buf
**
** Description      Internal function which is in charge of finding a free buffer
**					of the requested size in one of the lists.
**
** Returns          A pointer to the buffer header, or NULL if none available
**
*******************************************************************************/
INLINE void * _find_buf (UINT32 size)
{    
	T_RVF_INTERNAL_BUF * p_hdr;
	UINT8 idx;

    if (size == 0)	/* if user requires a 0 byte buffer !! */
    {    return (NULL);
	}

	/* add the overhead for buffer corruption check */
	size = REQ2SIZE(size);

	/* find the corresponding list */
	idx = RVF_BUF_LIST_INDEX(size);

	/* 1. try in the bin corresponding to the requested size. */
	/* 2. try to use the last_remainder chunk. */
	/* 3. try in the others bins of greater size. */

	if( (lists[idx] == NULL) || ( GETSIZE(lists[idx]) < size) )  
	/* if the first buffer in the appropriate bin is not big enough. */
	{
		rvf_disable(4);		/* enter critical section */

		if( last_remainder != NULL)
		{
			p_hdr = last_remainder;

			/* if the last remainder is big enough */
			if( GETSIZE(p_hdr) >= size )
			{

				if( GETSIZE(p_hdr) >= (size + RVF_MIN_USABLE_SIZE ) ) /* if the free part may be used */
				{	/* create a new free buffer and link it in the appropriate list*/

					T_RVF_INTERNAL_BUF * new_buf;
					UINT8 new_idx;
					
					new_buf = (T_RVF_INTERNAL_BUF *) ((UINT8*)p_hdr + size + sizeof(T_RVF_INTERNAL_BUF));
					new_buf->buf_size =  GETSIZE(p_hdr) - size - sizeof(T_RVF_INTERNAL_BUF);
					ENDSIZE(new_buf) = new_buf->buf_size;

					/* remove the used buffer from the list */
					if( p_hdr->header.p_prev != NULL)
					{	(p_hdr->header.p_prev)->p_next = p_hdr->p_next;
					}
					else
					{	lists[ RVF_BUF_LIST_INDEX( GETSIZE(p_hdr) )] = p_hdr->p_next;
					}
					if( p_hdr->p_next != NULL)
					{	(p_hdr->p_next)->header.p_prev = p_hdr->header.p_prev;
					}
					p_hdr->p_next = NULL;

					SETSIZE(p_hdr, size);
					ENDSIZE(p_hdr) = size;  /* to CHANGE */

					/* insert the new buffer in the appropriate list */
					new_idx = RVF_BUF_LIST_INDEX(new_buf->buf_size);
					new_buf->p_next = lists[new_idx];
					lists[new_idx] = new_buf;
					new_buf->header.p_prev = NULL;
					if( new_buf->p_next != NULL)
					{	(new_buf->p_next)->header.p_prev = new_buf;
					}
					RVF_SET_PREV_IN_USE(new_buf);
						
					last_remainder = new_buf;

					rvf_enable();		/* exit critical section */
					return p_hdr;				

				}
				else	/* return the entire buffer */
				{
					/* remove the used buffer from the list */
					if( p_hdr->header.p_prev != NULL)
					{	(p_hdr->header.p_prev)->p_next = p_hdr->p_next;
					}
					else
					{	lists[ RVF_BUF_LIST_INDEX( GETSIZE(p_hdr) )] = p_hdr->p_next;
					}
					if( p_hdr->p_next != NULL)
					{	(p_hdr->p_next)->header.p_prev = p_hdr->header.p_prev;
					}
					p_hdr->p_next = NULL;

					RVF_SET_PREV_IN_USE( NEXTCHUNK(p_hdr) );

					last_remainder = NULL;
				
					rvf_enable();		/* exit critical section */
					return p_hdr;
				}
			}
			else /* the last remainder is too small */
			{
				/* clear the last remainder */
				last_remainder = NULL;
			}
			
		}
		rvf_enable();		/* exit critical section */
	}

	while( idx < RVF_NB_FREE_LISTS )
	{
		rvf_disable(4);		/* enter critical section */

		if( lists[idx] != NULL )  /*if the list is not empty */
		{	/* remove the first buffer from the list */

			p_hdr = lists[idx];
			if( GETSIZE(p_hdr) >= size)
			{
				if( GETSIZE(p_hdr) >= (size + RVF_MIN_USABLE_SIZE ) ) /* if the free part may be used */
				{	/* create a new free buffer and link it in the appropriate list*/

					T_RVF_INTERNAL_BUF * new_buf;
					UINT8 new_idx;
					
					new_buf = (T_RVF_INTERNAL_BUF *) ((UINT8*)p_hdr + size + sizeof(T_RVF_INTERNAL_BUF));
					new_buf->buf_size =  GETSIZE( p_hdr) - size - sizeof(T_RVF_INTERNAL_BUF);
					ENDSIZE(new_buf) = new_buf->buf_size;

					/* remove the used buffer from the list */
					lists[idx] = p_hdr->p_next;
					if( p_hdr->p_next != NULL)
					{	(p_hdr->p_next)->header.p_prev = NULL;
					}
					p_hdr->p_next = NULL;

					SETSIZE(p_hdr, size);
					ENDSIZE(p_hdr) = size;

					/* insert the new buffer in the appropriate list */
					new_idx = RVF_BUF_LIST_INDEX(new_buf->buf_size);
					new_buf->p_next = lists[new_idx];
					lists[new_idx] = new_buf;
					new_buf->header.p_prev = NULL;
					if( new_buf->p_next != NULL)
					{	(new_buf->p_next)->header.p_prev = new_buf;
					}
					RVF_SET_PREV_IN_USE(new_buf);

					last_remainder = new_buf; /* set this new buffer as the last remainder */

					rvf_enable();		/* exit critical section */
					return p_hdr;				

				}
				else	/* return the entire buffer */
				{	lists[idx] = p_hdr->p_next;
					if( p_hdr->p_next != NULL)
					{	(p_hdr->p_next)->header.p_prev = NULL;
					}
					p_hdr->p_next = NULL;
					RVF_SET_PREV_IN_USE( NEXTCHUNK(p_hdr) );
					
					if( last_remainder == p_hdr) /* if it was the last_remainder, clear it. */
					{
						last_remainder = NULL;
					}

					rvf_enable();		/* exit critical section */
					return p_hdr;
				}
			}
		}

		rvf_enable();		/* exit critical section */

		idx++;	/* search in the next list */
	}

    return NULL;
}


/*******************************************************************************
**
** Function         _release_buf
**
** Description      Internal function called to release a buffer after use.
**					The parameter points to the beginning of the header.
**
** Returns          BOOLEAN: TRUE if successful, else FALSE
**
*******************************************************************************/
INLINE BOOLEAN _release_buf (T_RVF_INTERNAL_BUF *p_hdr)
{	UINT8 idx;

#if RVF_ENABLE_BUF_CORRUPTION_CHECK		/* check for buffer corruption:i.e. if user wrote data after the end of the buffer */
    if ( _rvf_chk_buf_damage( MEM2USER(p_hdr) ) )
    {	rvf_send_trace( "RVF: _release_buf(): buffer corrupted", 37, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
		return FALSE;
    }

	/* check if the buffer has been already freed */
	if ( RVF_IS_PREV_FREE( NEXTCHUNK(p_hdr) ) )	/* check buffer status */
    {	rvf_send_trace( "RVF: _release_buf(): buffer already freed", 41, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
        return FALSE;
    }

#endif

#if RVF_ENABLE_BUF_LINKAGE_CHECK		/* check for buffer linkage */
    if ( RVF_BUF_IS_LINKED(p_hdr) )	/* check buffer status */
    {	rvf_send_trace( "RVF: _release_buf(): free buf buffer linked", 43, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
        return FALSE;
    }
#endif


	rvf_disable(6);		/* enter critical section */

	/* try to coalesce the buffer with its neighbors (left and right) */

	if( RVF_IS_PREV_FREE(p_hdr) )
	{	/* merge the buffer with its left neighbor */
		UINT32 left_buf_size = *((UINT32*)((UINT8*)p_hdr - sizeof(UINT32) ) );
		T_RVF_INTERNAL_BUF * left_buf = (T_RVF_INTERNAL_BUF *) ((UINT8 *)p_hdr - left_buf_size - sizeof(T_RVF_INTERNAL_BUF) );

		/* remove the left buffer from its list */
		if( left_buf->header.p_prev == NULL)
		{	lists[ RVF_BUF_LIST_INDEX(left_buf_size)] = left_buf->p_next;
		}
		else
		{	(left_buf->header.p_prev)->p_next = left_buf->p_next;
		}
		if( left_buf->p_next != NULL)
		{
			(left_buf->p_next)->header.p_prev = left_buf->header.p_prev;
		}
		/* set the size of the newly created buffer */
		SETSIZE(left_buf, (left_buf_size + GETSIZE(p_hdr) + sizeof(T_RVF_INTERNAL_BUF) ) );
		/* set the current buffer as free to allow check for double free */
		RVF_SET_PREV_FREE( NEXTCHUNK(p_hdr) );

		p_hdr = left_buf;
	}

	/* check for pool limits */
	if( GETSIZE( NEXTCHUNK(p_hdr) ) != 0)
	{	T_RVF_INTERNAL_BUF * right_buf = NEXTCHUNK(p_hdr);
		/* merge the buffer with its right neighbor */
		
		if( RVF_IS_PREV_FREE( NEXTCHUNK(right_buf) ) )
		{	/* remove the right buffer from its list */
			UINT32 right_buf_size = GETSIZE( right_buf);
	
			if( right_buf->header.p_prev == NULL)
			{	lists[ RVF_BUF_LIST_INDEX(right_buf_size)] = right_buf->p_next;
			}
			else
			{	(right_buf->header.p_prev)->p_next = right_buf->p_next;
			}
			if( right_buf->p_next != NULL)
			{	(right_buf->p_next)->header.p_prev = right_buf->header.p_prev;
			}
			
			right_buf_size += GETSIZE(p_hdr);
			SETSIZE(p_hdr, (right_buf_size + sizeof(T_RVF_INTERNAL_BUF) ) );

			if( last_remainder == right_buf) /* keep as last_remainder */
			{	last_remainder = p_hdr;
			}
		}
	}
	
	/* enqueue the free buffer in the appropriate list */
	idx = RVF_BUF_LIST_INDEX( GETSIZE(p_hdr) );
	p_hdr->header.p_prev = NULL;
	p_hdr->p_next = lists[idx];
	lists[idx] = p_hdr;
	if( p_hdr->p_next != NULL)
	{	(p_hdr->p_next)->header.p_prev = p_hdr;
	}

	ENDSIZE(p_hdr) = GETSIZE(p_hdr);
	RVF_SET_PREV_FREE( NEXTCHUNK(p_hdr) );

    rvf_enable();		/* exit critical section */
	return TRUE;
}


/*******************************************************************************
** Function         _str_cmp
**
** Description      Internal function which compares two null-terminated string.
**					Returns TRUE if they are equal, else FALSE.
*******************************************************************************/
BOOLEAN _str_cmp( char *str1, char * str2)
{	UINT8 i;
	for ( i = 0; (str1[i] == str2[i]) && (str1[i] != 0) && (str2[i] != 0) && (i < RVF_MAX_MB_LEN); i++ );
	if ( i == RVF_MAX_MB_LEN)
	{	return TRUE;
	}
	
	if ( (str1[i] == 0) && (str2[i] == 0) )
	{	return TRUE;
	}
	return FALSE;
}

/******************************************************************************
**
**						MEMORY BANK RELATED FUNCTIONS
**
******************************************************************************/

/*******************************************************************************
**
** Function         _remove_from_list
**
** Description      Internal function called to remove a buffer from the list of
**					buffer waiting to be counted on the memory bank.
**					The parameter points to the beginning of the header.
**
** Returns          BOOLEAN: TRUE if successful, else FALSE
**
*******************************************************************************/
BOOLEAN _remove_from_list (void *bptr, T_RVF_MB * mb)
{	UINT16 * index;
	UINT16 free_elem, prec;

	/* check all elements of the list */	
	index = &(mb->first_buffer_index);
	prec = RVF_INVALID_INDEX;

	while ( (*index != RVF_INVALID_INDEX) && (waiting_buffers[*index]!=bptr) )
	{	prec = *index;
		index = &(next_buffer[*index]);
	}
	
	if (waiting_buffers[*index] == bptr)
	{	free_elem = *index;
		*index = next_buffer[free_elem]; /* link preceding element to the next one */
		
		if (next_buffer[free_elem] == RVF_INVALID_INDEX ) /* last element in the list */
		{	mb->last_buffer_index = prec;
		}

		waiting_buffers[free_elem] = NULL;
		next_buffer[free_elem] = first_free_element; /* link free elements */
		first_free_element = free_elem;
		return TRUE;
	}
	return FALSE; /* buffer not found */
}


/*******************************************************************************
**
** Function         _add_to_list
**
** Description      Internal function called to add a buffer to the list of
**					buffer waiting to be counted on the memory bank.
**					The parameter points to the beginning of the header.
**
** Returns          BOOLEAN: TRUE if successful, else FALSE
**
*******************************************************************************/
BOOLEAN _add_to_list (void *bptr, T_RVF_MB * mb)
{	UINT16 index = first_free_element;
	
	first_free_element = next_buffer[index];
	
	waiting_buffers[index] = bptr;
	next_buffer[index] = RVF_INVALID_INDEX;

	if ( mb->last_buffer_index == RVF_INVALID_INDEX) /* empty list */
	{	mb->first_buffer_index	= index;
		mb->last_buffer_index	= index;
	}
	else
	{	next_buffer[mb->last_buffer_index] = index;
		mb->last_buffer_index = index;
	}
	
	return TRUE;
}


/*******************************************************************************
**
** Function         rvf_create_mb
**
** Description      Called by an application to create a memory bank
**
** Parameters:		memory bank name, memory bank param
**					(return) memory bank id
**
** Returns          T_RVF_RET: RVF_OK if success
**
*******************************************************************************/
T_RVF_RET		rvf_create_mb(T_RVF_MB_NAME mb_name, T_RVF_MB_PARAM mb_param, T_RVF_MB_ID *mb_id)
{	UINT8 num_mb;
	T_RVF_MB * mb;
	UINT32 available_mem = 0;
	UINT32 required_mem = 0;

	/* find the mb name in the array */
	for ( num_mb = 0; (num_mb < RVF_MAX_TOTAL_MB) && (!_str_cmp(mb_name, rvf_name_id[num_mb].mb_name) ); num_mb++);

	if ( num_mb == RVF_MAX_TOTAL_MB ) /* mb name not found */
	{	
		/* DLC added for dynamic memory bank creation*/

		/* search the first available place in the array */
		T_RVF_MB_ID first_available_mb_id = 0;
		BOOLEAN mb_id_found = FALSE; 

		for ( num_mb = 0; (num_mb < RVF_MAX_TOTAL_MB) && (rvf_name_id[num_mb].mb_name[0] != 0) ; num_mb++)
		{	if( rvf_name_id[num_mb].mb_id == first_available_mb_id)
			{	first_available_mb_id ++;
			}
		}
		
		while( (first_available_mb_id < RVF_MAX_REAL_MB) &&  (mb_id_found == FALSE) )
		{	
			for ( num_mb = 0; (num_mb < RVF_MAX_TOTAL_MB) && (rvf_name_id[num_mb].mb_name[0] != 0) && (rvf_name_id[num_mb].mb_id != first_available_mb_id) ; num_mb++);
			if ( rvf_name_id[num_mb].mb_id != first_available_mb_id)
			{	/* available mb id found */
				mb_id_found = TRUE;
			}
			else
			{	/* try the next one */
				first_available_mb_id++;
			}
		}

		if ( (num_mb == RVF_MAX_TOTAL_MB) || (first_available_mb_id + 1 >= RVF_MAX_REAL_MB ) ) /* no available space in the array */

	{	*mb_id = RVF_INVALID_MB_ID;
		return RVF_INVALID_PARAMETER;
	}

	if(INC_Initialize_State==INC_END_INITIALIZE) rvf_disable(20);		/* enter critical section */

		/* create the new mb name and id */
		strcpy( rvf_name_id[num_mb].mb_name, mb_name);
		rvf_name_id[num_mb].mb_id = first_available_mb_id;
		
		/* initialize the next one */
		rvf_name_id[num_mb+1].mb_name[0]	= 0;
		rvf_name_id[num_mb+1].mb_id			= 0;

	if(INC_Initialize_State==INC_END_INITIALIZE) rvf_enable();		/* exit critical section */
	}

	/* check if the memory bank has been already created */
	if ( rvf_name_id[ num_mb].mb_params.size != 0) 
	{	*mb_id = RVF_INVALID_MB_ID;
		return RVF_INTERNAL_ERR;
	}

	rvf_get_available_mem( &available_mem, &required_mem);

	if ( ( (required_mem + mb_param.size)*100) > ( available_mem * _rvf_get_mem_usage_ratio()) )	/* if there is not enough available memory to create this mb */
	{	*mb_id = RVF_INVALID_MB_ID;				/* In a next version: try to create a dynamic pool */
		return RVF_MEMORY_ERR;
	}

	rvf_disable(20);		/* enter critical section */

	/* save the mb parameters for deletion */
	rvf_name_id[num_mb].mb_params.size = mb_param.size;
	rvf_name_id[num_mb].mb_params.watermark = mb_param.watermark;

	* mb_id = rvf_name_id[num_mb].mb_id;
	mb = &rvf_banks[ *mb_id ];
	/* initialize the memory bank structure */
	mb->watermark				+= mb_param.watermark;
	mb->max						+= mb_param.size;
	
	rvf_enable();		/* exit critical section */

	return RVF_OK;
}


/*******************************************************************************
**
** Function         rvf_get_mb_id
**
** Description      Called by an application to get the memory bank id from its name
**
** Parameters:		memory bank name
**					(return) memory bank id
**
** Returns          T_RVF_RET: RVF_OK if success
**
*******************************************************************************/
T_RVF_RET		rvf_get_mb_id(T_RVF_MB_NAME mb_name, T_RVF_MB_ID *mb_id)
{	UINT8 num_mb;
	

	/* find the mb name in the array */
	for ( num_mb = 0; (num_mb < RVF_MAX_TOTAL_MB) && (!_str_cmp(mb_name, rvf_name_id[num_mb].mb_name) ); num_mb++);
	if ( num_mb == RVF_MAX_TOTAL_MB ) /* mb name not found */
	{	*mb_id = RVF_INVALID_MB_ID;
		return RVF_INVALID_PARAMETER;
	}
	if ( rvf_banks[ rvf_name_id[num_mb].mb_id ].max == 0 )
	{	/* the memory bank has not been created */
		*mb_id = RVF_INVALID_MB_ID;
		return 	RVF_NOT_READY;
	}
	*mb_id = rvf_name_id[num_mb].mb_id;
	return RVF_OK;
}


/*******************************************************************************
**
** Function         rvf_delete_mb
**
** Description      Called by an application to delete a memory bank
**
** Parameters:		memory bank name
**
** Returns          T_RVF_RET: RVF_OK if success
**
*******************************************************************************/
T_RVF_RET		rvf_delete_mb(T_RVF_MB_NAME mb_name)
{	UINT8 num_mb;
	T_RVF_MB * mb;

	/* find the mb name in the array */
	for ( num_mb = 0; (num_mb < RVF_MAX_TOTAL_MB) && (!_str_cmp(mb_name, rvf_name_id[num_mb].mb_name) ); num_mb++);
	if ( num_mb == RVF_MAX_TOTAL_MB ) /* mb name not found */
	{	return RVF_INVALID_PARAMETER;
	}
	mb = &rvf_banks[ rvf_name_id[num_mb].mb_id ];

	/* check if the mb is used more than once or not */
	if ( mb->max == rvf_name_id[num_mb].mb_params.size )
	{	/* mb is used only once, check if cur_memory_used > 0 */
		if ( mb->cur_memory_used > 0)
		{	rvf_send_trace( "RVF: rvf_delete_mb(): not all buffers have been freed", 53, NULL_PARAM, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
			return RVF_MEMORY_ERR;
			/*	free all buffers ????? -> NOT POSSIBLE */
		}
		/* initialize mb params */
		mb->max					= 0;
		mb->first_buffer_index	= RVF_INVALID_INDEX;
		mb->last_buffer_index	= RVF_INVALID_INDEX;
		mb->watermark			= 0;
		mb->returned_red		= FALSE;
		mb->func				= 0;
#if RVF_ENABLE_STATS
	mb->max_reached				= 0;			
	mb->required_size			= 0;			
	mb->num_buf					= 0;				
#endif

	}
	else	/* mb is still used by another entity */
	{	/* change mb params */
		mb->max			-= rvf_name_id[num_mb].mb_params.size;
		mb->watermark	-= rvf_name_id[num_mb].mb_params.watermark;
	}
	
	rvf_name_id[num_mb].mb_params.size = 0;
	rvf_name_id[num_mb].mb_params.watermark = 0;

	return RVF_OK;
}

T_RVF_RET		rvf_mb_is_used(T_RVF_MB_NAME mb_name, UINT8* isUsed) 	{
	UINT8 num_mb;
	T_RVF_MB * mb;

	*isUsed=0;

	/* find the mb name in the array */
	for ( num_mb = 0; (num_mb < RVF_MAX_TOTAL_MB) && (!_str_cmp(mb_name, rvf_name_id[num_mb].mb_name) ); num_mb++);
	if ( num_mb == RVF_MAX_TOTAL_MB ) {/* mb name not found */
		return RVF_INVALID_PARAMETER;
	}
	mb = &rvf_banks[ rvf_name_id[num_mb].mb_id ];

	/* check if the mb is used more than once or not */
	if ( mb->max == rvf_name_id[num_mb].mb_params.size ) {
		/* mb is used only once, check if cur_memory_used > 0 */
		if ( mb->cur_memory_used > 0) *isUsed=1;
	}
	return RVF_OK;
}



/*******************************************************************************
**
** Function         rvf_get_mb_status
**
** Description      Called by an application to get the status of a memory bank
**
** Parameters:		memory bank id
**
** Returns          T_RVF_MB_STATUS:	RVF_GREEN if everything is ok,
**										RVF_YELLOW if watermark limit has been reached,
**										RVF_RED if max size has been reached
**
*******************************************************************************/
T_RVF_MB_STATUS	rvf_get_mb_status(T_RVF_MB_ID mb_id)
{	T_RVF_MB * mb;

	/* checking for invalid memory bank IDs */
	if (mb_id >= RVF_MAX_REAL_MB)
	{
#ifdef RVM_DAR_SWE
		dar_diagnose_generate_emergency (RVF_INVALID_MD_ID_ERRROR,
										 DAR_ASCII_FORMAT,
										 RVM_USE_ID);
#else
		rvf_send_trace (RVF_INVALID_MD_ID_ERRROR,
						sizeof (RVF_INVALID_MD_ID_ERRROR) - 1,
						NULL_PARAM,
						RV_TRACE_LEVEL_ERROR,
						RVM_USE_ID);
#endif
		return RVF_RED;
	}
	mb = &rvf_banks[mb_id];
	
	if ( mb->returned_red == TRUE) /* if a previous count buf or get buf has failed */
	{	return RVF_RED;
	}

	if ( mb->cur_memory_used < mb->watermark )
	{	return RVF_GREEN;
	}
	else
	{	if ( mb->cur_memory_used < mb->max )
		{	return RVF_YELLOW;
		}
		else
		{	return RVF_RED; /* since max and cur_memory_used are set to 0 for not-created mb, it will return RED*/ 
		}
	}
}

/*******************************************************************************
**
** Function         rvf_get_mb_unused_mem
**
** Description      Called by an application to get the number of bytes available
**					until the memory bank size.
**
** Parameters:		memory bank id
**
** Returns          UINT32:	number of bytes available
**					returns 0 if the memory bank has not been created.
**
*******************************************************************************/
UINT32	rvf_get_mb_unused_mem(T_RVF_MB_ID mb_id)
{	T_RVF_MB * mb;
	mb = &rvf_banks[mb_id];
	
	if ( mb->returned_red == TRUE) /* if a previous count buf or get buf has failed */
	{	return 0;
	}

	return( mb->max - mb->cur_memory_used);
}

/*******************************************************************************
**
** Function         rvf_get_mb_unused_green_mem
**
** Description      Called by an application to get the number of bytes available
**					until the memory bank watermark.
**
** Parameters:		memory bank id
**
** Returns          UINT32:	number of bytes available
**					returns 0 if the memory bank has not been created.
**
*******************************************************************************/
UINT32	rvf_get_mb_unused_green_mem(T_RVF_MB_ID mb_id)
{	T_RVF_MB * mb;
	mb = &rvf_banks[mb_id];
	
	if ( mb->returned_red == TRUE) /* if a previous count buf or get buf has failed */
	{	return 0;
	}

	if( mb->cur_memory_used > mb->watermark)
	{	return 0;
	}

	return( mb->watermark - mb->cur_memory_used);
}

/*******************************************************************************
**
** Function         rvf_get_buf
**
** Description      Called by an application to get a buffer from a memory bank
**
** Parameters:		memory bank id, buffer size
**					(return) buffer pointer to the allocated buffer or null if 
**					mb status is RVF_RED
**
** Returns          T_RVF_MB_STATUS:	RVF_GREEN if everything is ok,
**										RVF_YELLOW if watermark limit has been reached,
**										RVF_RED if max size has been reached (does not return a buffer)
**
*******************************************************************************/
T_RVF_MB_STATUS rvf_get_buf(T_RVF_MB_ID mb_id, UINT32 buffer_size, T_RVF_BUFFER** p_buffer)
{	T_RVF_MB * mb;

	/* checking for invalid memory bank IDs */
	if (mb_id >= RVF_MAX_REAL_MB)
	{
#ifdef RVM_DAR_SWE
		dar_diagnose_generate_emergency (RVF_INVALID_MD_ID_ERRROR,
										 DAR_ASCII_FORMAT,
										 RVM_USE_ID);
#else
		rvf_send_trace (RVF_INVALID_MD_ID_ERRROR,
						sizeof (RVF_INVALID_MD_ID_ERRROR) - 1,
						NULL_PARAM,
						RV_TRACE_LEVEL_ERROR,
						RVM_USE_ID);
#endif
		return RVF_RED;
	}
	mb = &rvf_banks[ mb_id ];
	
	/* check memory usage */
	if ( ( mb->cur_memory_used + buffer_size) >  mb->max )
	{	/* over the limits, return RED and do not allocate a buffer */
		mb->returned_red = TRUE;
		*p_buffer = NULL;
		return RVF_RED;
	}
	
	/* find a buffer of the requested size */
	*p_buffer = _find_buf( buffer_size );
	if ( *p_buffer == NULL ) /* error during allocation, not enough memory */
	{	//rvf_send_trace( "RVF: rvf_get_buf(): not enough available physical memory", 56, NULL_PARAM, RV_TRACE_LEVEL_ERROR, TRACE_RVF_BUFFER );
		mb->returned_red = TRUE;
		return RVF_RED;
	}

#if RVF_ENABLE_STATS
	required_size	+= buffer_size;
	obtained_size	+= rvf_get_buf_size((UINT8*)(*p_buffer) + sizeof(T_RVF_INTERNAL_BUF));
	used_size		+= rvf_get_buf_size((UINT8*)(*p_buffer) + sizeof(T_RVF_INTERNAL_BUF)) + sizeof(T_RVF_INTERNAL_BUF) + RVF_CORRUPT_OVERHEAD;
	mem_in_use		+= rvf_get_buf_size((UINT8*)(*p_buffer) + sizeof(T_RVF_INTERNAL_BUF)) + sizeof(T_RVF_INTERNAL_BUF) + RVF_CORRUPT_OVERHEAD;
#endif

	if(INC_Initialize_State==INC_END_INITIALIZE) rvf_disable(20);		/* enter critical section */
#if RVF_ENABLE_BUF_LINKAGE_CHECK
	/* set as unlinked */
	RVF_SET_BUF_UNLINKED((T_RVF_INTERNAL_BUF*)(*p_buffer));
#endif

	/* increase memory use counter */
	mb->cur_memory_used += rvf_get_buf_size( (UINT8*)(*p_buffer) + sizeof(T_RVF_INTERNAL_BUF) );
	( (T_RVF_INTERNAL_BUF *) (*p_buffer))->header.external.mb_id = mb_id;
	( (T_RVF_INTERNAL_BUF *) (*p_buffer))->header.external.mb_expected = RVF_INVALID_MB_ID;
	
	*p_buffer = (UINT8*)(*p_buffer) + sizeof(T_RVF_INTERNAL_BUF);

#if RVF_ENABLE_STATS
	if ( mb->cur_memory_used > mb->max_reached )
	{	mb->max_reached = mb->cur_memory_used;
	}
	mb->required_size += buffer_size;
	mb->num_buf++;
#endif

	if(INC_Initialize_State==INC_END_INITIALIZE) rvf_enable();			/* exit critical section */

	/* return the correct flag */
	if ( mb->cur_memory_used > mb->watermark )
	{	return RVF_YELLOW;
	}
	else
	{	return RVF_GREEN;
	}
}

/*******************************************************************************
**
** Function         rvf_count_buf
**
** Description      Called by an application to change the memory bank on which a buffer is counted
**
** Parameters:		new memory bank id,
**					pointer to the buffer.
**
** Returns          T_RVF_MB_STATUS:	RVF_GREEN if everything is ok,
**										RVF_YELLOW if watermark limit has been reached,
**										RVF_RED if max size has been reached
**
*******************************************************************************/
T_RVF_MB_STATUS rvf_count_buf(T_RVF_MB_ID mb_id, T_RVF_BUFFER * p_buffer)
{	T_RVF_INTERNAL_BUF * buf;
	UINT32 buf_size;
	T_RVF_MB * new_mb;
	T_RVF_MB * old_mb;

	/* checking for invalid memory bank IDs */
	if (mb_id >= RVF_MAX_REAL_MB)
	{
#ifdef RVM_DAR_SWE
		dar_diagnose_generate_emergency (RVF_INVALID_MD_ID_ERRROR,
										 DAR_ASCII_FORMAT,
										 RVM_USE_ID);
#else
		rvf_send_trace (RVF_INVALID_MD_ID_ERRROR,
						sizeof (RVF_INVALID_MD_ID_ERRROR) - 1,
						NULL_PARAM,
						RV_TRACE_LEVEL_ERROR,
						RVM_USE_ID);
#endif
		return RVF_RED;
	}
	buf = (T_RVF_INTERNAL_BUF *) ( (UINT8 *) p_buffer - sizeof(T_RVF_INTERNAL_BUF) );
	new_mb = &rvf_banks[mb_id];
	old_mb = &rvf_banks[buf->header.external.mb_id];
		
	/* get the size of the buffer and try to count it on the new mb */
	buf_size = rvf_get_buf_size( p_buffer );
	
	if ( ( new_mb->cur_memory_used + buf_size ) < new_mb->max )
	{	/* there is enough memory in the new mb */
		
		if ( buf->header.external.mb_expected != RVF_INVALID_MB_ID )
		{	/* remove the buffer from the list of waiting buffers in mb expected */
			_remove_from_list( buf, &rvf_banks[buf->header.external.mb_expected] );
			buf->header.external.mb_expected = RVF_INVALID_MB_ID;
		}
		
		rvf_disable(20);		/* enter critical section */

		/* decrease the memory used in the old mb */
		old_mb->cur_memory_used -= buf_size;
	
		/* increase memory used in the new mb */
		new_mb->cur_memory_used += buf_size;

		rvf_enable();			/* exit critical section */

		/* call the callback function if state of the old mb switches to RVF_GREEN and there is no buffer waiting */
		if ( (old_mb->cur_memory_used < old_mb->watermark) && (old_mb->first_buffer_index == RVF_INVALID_INDEX) && (old_mb->returned_red == TRUE) && ( old_mb->func != NULL) )
		{	old_mb->returned_red = FALSE;
			old_mb->func( buf->header.external.mb_id);
		}
		else
		{	/* count as many waiting buffers as possible on the old mb */
			while( (old_mb->first_buffer_index != RVF_INVALID_INDEX) && (rvf_count_buf( buf->header.external.mb_id, (UINT8 *) (waiting_buffers[old_mb->first_buffer_index]) + sizeof(T_RVF_INTERNAL_BUF)) != RVF_RED) );
			if ( (old_mb->cur_memory_used < old_mb->watermark) && (old_mb->first_buffer_index == RVF_INVALID_INDEX) && (old_mb->returned_red == TRUE) && ( old_mb->func != NULL) )
			{	old_mb->returned_red = FALSE;
				old_mb->func( buf->header.external.mb_id);
			}
		}
		/* change mb_id of the buffer */
		buf->header.external.mb_id = mb_id;



#if RVF_ENABLE_STATS
	if ( new_mb->cur_memory_used > new_mb->max_reached )
	{	new_mb->max_reached = new_mb->cur_memory_used;
	}
#endif

		if ( new_mb->cur_memory_used > new_mb->watermark )
		{	return RVF_YELLOW;
		}
		else
		{	return RVF_GREEN;
		}
	}
	else
	{	/* there is not enough memory in the new mb_id */
		if ( buf->header.external.mb_expected != RVF_INVALID_MB_ID)	/* remove the buffer from old expected mb */
		{	_remove_from_list( buf, &rvf_banks[ buf->header.external.mb_expected] );
		}
		/* enqueue the buffer in the list of waiting buffer */
		buf->header.external.mb_expected = mb_id;
		_add_to_list( buf, new_mb );
		new_mb->returned_red = TRUE;
		return RVF_RED;
	}
}

/*******************************************************************************
**
** Function         rvf_free_buf
**
** Description      Called by an application to free a buffer
**
** Parameters:		buffer pointer
**
** Returns          T_RVF_RET:	T_RVF_OK if succesful,
**
*******************************************************************************/
T_RVF_RET rvf_free_buf( T_RVF_BUFFER * p_buffer)
{	T_RVF_INTERNAL_BUF * buf;
	T_RVF_MB * mb;
	T_RVF_MB_ID mb_id;
	UINT32 buf_size;
	
	
	buf = USER2MEM(p_buffer);

	mb_id = buf->header.external.mb_id;
	mb = &rvf_banks[mb_id];
	buf_size = rvf_get_buf_size(p_buffer);

	/* do not need to change the mb id of the buffer, since it will be overwritten by p_prev */

	/* free the buffer */
	if ( !_release_buf(buf) )
	{	return RVF_MEMORY_ERR;
	}

#if RVF_ENABLE_STATS
	mem_in_use		-= buf_size + sizeof(T_RVF_INTERNAL_BUF) + RVF_CORRUPT_OVERHEAD;
#endif

	rvf_disable(20);		/* enter critical section */

	/* decrease mb memory use */
	mb->cur_memory_used -= buf_size;

	rvf_enable();			/* exit critical section */


	/* call the callback function if state of the mb switches to RVF_GREEN and there is no buffer waiting */
	if ( (mb->returned_red == TRUE) && (mb->cur_memory_used < mb->watermark) && ( mb->first_buffer_index == RVF_INVALID_INDEX) && ( mb->func != NULL) )
		{	mb->returned_red = FALSE;
			mb->func( mb_id);
		}
		else
		{	/* count as many waiting buffers as possible on the mb */
			while( (mb->first_buffer_index != RVF_INVALID_INDEX) && (rvf_count_buf( mb_id, (UINT8 *) (waiting_buffers[mb->first_buffer_index]) + sizeof(T_RVF_INTERNAL_BUF)) != RVF_RED) );
			if ( (mb->cur_memory_used < mb->watermark) && ( mb->first_buffer_index == RVF_INVALID_INDEX) && (mb->returned_red == TRUE) && ( mb->func != NULL) )
			{	mb->returned_red = FALSE;
				mb->func( mb_id);
			}
		}

	return RVF_OK;
}


/*******************************************************************************
**
** Function         rvf_set_callback_func
**
** Description      Called the first time an application wants to set the callback
**					function associated to a memory bank.
**
** Parameters:		memory bank id, pointer to the callback function.
**
** Returns          T_RVF_RET:	T_RVF_OK if succesful,
**
*******************************************************************************/
T_RVF_RET		rvf_set_callback_func(T_RVF_MB_ID mb_id, MB_CALLBACK_FUNC func)
{	T_RVF_MB * mb;

	/* checking for invalid memory bank IDs */
	if (mb_id >= RVF_MAX_REAL_MB)
		return RVF_INVALID_PARAMETER;
	mb = &rvf_banks[mb_id];
	if ( (mb->max != 0) && (mb->func == NULL) )	/* if the mb has been created and the callback func has never been set */
	{	mb->func = func;
		return RVF_OK;
	}
	return RVF_INVALID_PARAMETER;	
}


/*******************************************************************************
**
** Function         rvf_change_callback_func
**
** Description      Called by an application to change the callback
**					function associated to a memory bank.
**					It means the callback function has to be set before.
**
** Parameters:		memory bank id, pointer to the callback function.
**
** Returns          T_RVF_RET:	T_RVF_OK if succesful,
**
*******************************************************************************/
T_RVF_RET		rvf_change_callback_func(T_RVF_MB_ID mb_id, MB_CALLBACK_FUNC func)
{	T_RVF_MB * mb;

	/* checking for invalid memory bank IDs */
	if (mb_id >= RVF_MAX_REAL_MB)
		return RVF_INVALID_PARAMETER;
	mb = &rvf_banks[mb_id];
	if ( (mb->max != 0) && (mb->func != NULL) )	/* if the mb has been created and the callback func has already been set */
	{	mb->func = func;
		return RVF_OK;
	}
	return RVF_INVALID_PARAMETER;	
}

#ifdef _WINDOWS_
/*******************************************************************************
**
** Function         _rvf_window_dump_mem
**
** Description      Called by a C++ object to update the graphical display of
**                  memory
**
** Parameters:		Opaque pointer to C++ object
**
** Returns          void
**
** WARNING          DON'T CHANGE THE SYNTAX OF DISPLAYED DATAS SINCE
**                  THEY ARE PARSED TO DISPLAY GRAPHICALLY THE MEMORY
**                  STATUS
**
*******************************************************************************/
void _rvf_window_dump_mem(void *m)
{

	
#if RVF_ENABLE_STATS	/* conditional compilation if stats are enabled */
	char mb_info[100];
	UINT16 num_mb, num_buf, index;
	UINT32 total_mem_size = 0;
	UINT32 total_max_used = 0;
	UINT32 total_cur_used = 0;
	T_RVF_MB * mb;


	for ( num_mb = 0; num_mb < RVF_MAX_TOTAL_MB; num_mb++ )
	{	
		/* trace the mb if it has been created*/
		if ( rvf_name_id[num_mb].mb_params.size > 0 )
		{	mb = &rvf_banks[ rvf_name_id[num_mb].mb_id ]; 
			num_buf = 0;
			index = mb->first_buffer_index;
			while ( index != RVF_INVALID_INDEX)
			{	num_buf++;
				index = next_buffer[index];
			}
			strcpy(mb_info,rvf_name_id[num_mb].mb_name);
			mb_info[10]='\0';
			AddNewState(m,mb_info,
				mb->cur_memory_used,mb->max_reached,mb->watermark,mb->max);
			
			
			total_mem_size += mb->max;
			total_max_used += mb->max_reached;
			total_cur_used += mb->cur_memory_used;
		}
	}
	
#endif /* RVF_ENABLE_STATS */
}

#endif

/*******************************************************************************
**
** Function         rvf_dump_mem
**
** Description      Called by an application to dump mb state and display statistics
**
** Parameters:		None
**
** Returns          void
**
** WARNING          DON'T CHANGE THE SYNTAX OF DISPLAYED DATAS SINCE
**                  THEY ARE PARSED TO DISPLAY GRAPHICALLY THE MEMORY
**                  STATUS
**
*******************************************************************************/
void rvf_dump_mem()
{
#if RVF_ENABLE_STATS	/* conditional compilation if stats are enabled */
	char mb_info[100];
	UINT16 num_mb, num_buf, index;
	UINT32 total_mem_size = 0;
	UINT32 total_max_used = 0;
	UINT32 total_cur_used = 0;
	T_RVF_MB * mb;


	/* display memory required, obtained and ratio */
	rvf_send_trace("MEM STAT: Total memory required", 31, required_size, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);
	rvf_send_trace("MEM STAT: Total memory obtained", 31, obtained_size, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);
	rvf_send_trace("MEM STAT: Total memory used    ", 31, used_size, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);
	sprintf( mb_info,"MEM STAT: Mem usage ratio      : %010f%%",  ( (double)(required_size) / (double)(obtained_size) ) *100 );
	rvf_send_trace(mb_info, 44, NULL_PARAM , RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);

	rvf_send_trace("*** START DUMPING MEMORY BANK ***", 33, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);
	/* for each mb, display its name, its id, its cur_size, its watermark, its limit, its max reached, the number of callback functions enqueued,
	(the requested size, the number of allocated buffer), the average buffer size for this mb */
	rvf_send_trace("**MB_NAME* Id Used_mem Watermark  Limit   Peak Nb_buff Avg_buf_size", 67, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);

	for ( num_mb = 0; num_mb < RVF_MAX_TOTAL_MB; num_mb++ )
	{	
		/* trace the mb if it has been created*/
		if ( rvf_name_id[num_mb].mb_params.size > 0 )
		{	mb = &rvf_banks[ rvf_name_id[num_mb].mb_id ]; 
			num_buf = 0;
			index = mb->first_buffer_index;
			while ( index != RVF_INVALID_INDEX)
			{	num_buf++;
				index = next_buffer[index];
			}
			sprintf( mb_info, "%10.10s %2d   %6d    %6d %6d %6d      %2d       %6d",
				rvf_name_id[num_mb].mb_name, rvf_name_id[num_mb].mb_id, 
				mb->cur_memory_used, mb->watermark, mb->max, mb->max_reached, num_buf,
				mb->num_buf == 0? 0:mb->required_size / mb->num_buf);

			rvf_send_trace( mb_info, 67, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);		

			total_mem_size += mb->max;
			total_max_used += mb->max_reached;
			total_cur_used += mb->cur_memory_used;
		}
	}
	sprintf(	mb_info, "TOTAL: ******** %6d********** %6d %6d",
				total_cur_used, total_mem_size, total_max_used );

	rvf_send_trace( mb_info, 46, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);		

#endif /* RVF_ENABLE_STATS */
}


/*******************************************************************************
**
** Function         rvf_get_available_mem
**
** Description      Called to get the total size of the memory and the used size.
**
** Parameters:		(return) UINT32 * total_size: contains the number of bytes in the memory.
**					(return) UINT32 * used_size:  contains the number of used bytes in the memory.
**
** Returns          T_RVF_RET: RVF_OK if successful, else a negative value.
**
*******************************************************************************/
T_RVF_RET rvf_get_available_mem( UINT32 * total_size, UINT32 * used_size )
{
	UINT16 count;
	*total_size = 0;
	*used_size	= 0;

	/* check if there is enough available physical memory (static or dynamic): if Sum(mb size) <= Sum(pool size)*/
	for ( count = 0; count < _rvf_get_number_of_pool(); count ++ )		/* sum the memory in pools */
	{	*total_size += _rvf_pools[count].pool_size;
	}
	/* sum the memory required by existing mb */
	for ( count = 0; count < RVF_MAX_REAL_MB; count ++ )
	{	*used_size	+= rvf_banks[count].max;
	}

	return RVF_OK;
}


/*******************************************************************************
**
** Function         rvf_get_mb_param
**
** Description      return the parameters of a specific memory bank 
**
** Parameters:		T_RVF_MB_NAME: name of the memory bank
**					(return) T_RVF_MB_PARAM*: parameter of the memory bank.
**
** Returns          T_RVF_RET: RVF_OK if successful, else a negative value.
**
*******************************************************************************/
T_RVF_RET rvf_get_mb_param( T_RVF_MB_NAME mb_name, T_RVF_MB_PARAM * param)
{	UINT8 num_mb;
	
	/* find the mb name in the array */
	for ( num_mb = 0; (num_mb < RVF_MAX_TOTAL_MB) && (!_str_cmp(mb_name, rvf_name_id[num_mb].mb_name) ); num_mb++);
	if ( num_mb == RVF_MAX_TOTAL_MB ) /* mb name not found */
	{	return RVF_INVALID_PARAMETER;
	}
	
	/* copy the parameters of the memory bank */
	*param = rvf_name_id[num_mb].mb_params;

	return RVF_OK;
}


/*******************************************************************************
**
** Function         rvf_set_mb_param
**
** Description      change the parameters of a specific memory bank 
**
** Parameters:		T_RVF_MB_NAME: name of the memory bank
**					T_RVF_MB_PARAM*: parameter of the memory bank.
**
** Returns          T_RVF_RET: RVF_OK if successful, else a negative value.
**
*******************************************************************************/
T_RVF_RET rvf_set_mb_param( T_RVF_MB_NAME mb_name, T_RVF_MB_PARAM * param)
{	UINT8 num_mb;
	T_RVF_MB_ID mb_id;
	T_RVF_MB * mb;

	/* find the mb name in the array */
	for ( num_mb = 0; (num_mb < RVF_MAX_TOTAL_MB) && (!_str_cmp(mb_name, rvf_name_id[num_mb].mb_name) ); num_mb++);
	if ( num_mb == RVF_MAX_TOTAL_MB ) /* mb name not found */
	{	return RVF_INVALID_PARAMETER;
	}

	mb_id = rvf_name_id[num_mb].mb_id;
	mb = &rvf_banks[ mb_id ];
	
	rvf_disable(20);		/* enter critical section */
	
	/* decrease the mb param by the old parameters */
	mb->watermark				-= rvf_name_id[num_mb].mb_params.watermark;
	mb->max						-= rvf_name_id[num_mb].mb_params.size;

	/* save the mb parameters */
	rvf_name_id[num_mb].mb_params.size = param->size;
	rvf_name_id[num_mb].mb_params.watermark = param->watermark;

	/* increase the mb param by the new parameters */
	mb->watermark				+= param->watermark;
	mb->max						+= param->size;
	
	rvf_enable();		/* exit critical section */

	/* dequeue callback functions if state switches to RVF_GREEN */

	return RVF_OK;
}




/*******************************************************************************
**
** Function         rvf_empty_mailboxes
**
** Description      Called by rvf_exit_task to empty a task's mailboxes before
**					killing it
**
** Parameters:		task_id: task of wich the mailboxes have to be emptied
**
** Returns          RV_OK
**
*******************************************************************************/
T_RV_RET _rvf_empty_mailboxes (T_RVF_G_ADDR_ID task_id)
{
    void * p_buf	= NULL;
    T_RVF_INTERNAL_BUF * p_hdr;
	UINT8 mbox_id = 0;

    if (task_id >= MAX_RVF_TASKS)
    {
		rvf_send_trace( "RVF: rvf_empty_mbox(): invalid taskid: ", 39, task_id, RV_TRACE_LEVEL_ERROR, RVM_USE_ID );
        return RVF_INVALID_PARAMETER;
    } 

	for (mbox_id = 0; mbox_id< RVF_NUM_TASK_MBOX; mbox_id++)
	{   /* while the chained list is not empty */
		/*while ( OSTaskQFirst[task_id][mbox_id] )
		{
		    rvf_disable(9);		

			p_hdr = OSTaskQFirst[task_id][mbox_id];
			OSTaskQFirst[task_id][mbox_id] = p_hdr->p_next;
		*/
		while ( pRtAddrIdTable[task_id]->OSTaskQFirst[mbox_id]  )
		{
		    rvf_disable(9);		

			p_hdr = pRtAddrIdTable[task_id]->OSTaskQFirst[mbox_id];
			pRtAddrIdTable[task_id]->OSTaskQFirst[mbox_id] = p_hdr->p_next;

#if RVF_ENABLE_BUF_LINKAGE_CHECK
			/* set as unlinked */
			RVF_SET_BUF_UNLINKED(p_hdr);
#endif

			p_buf = (UINT8 *)p_hdr + sizeof(T_RVF_INTERNAL_BUF);

			rvf_enable();		/* exit critical section */

			rvf_free_buf(p_buf);
		}
	}


    return (RV_OK);
}


/*******************************************************************************
**
** Function         rvf_scan_next
**
** Description      return the next item in the queue if any.
**					If the end of the queue is reached, returns NULL.
**					If current item is NULL, returns the first item in the queue.
**
** Returns          NULL if the end of the queue is reached, else a pointer to the buffer.
**
*******************************************************************************/
T_RVF_BUFFER *	rvf_scan_next (T_RVF_BUFFER_Q * p_q, T_RVF_BUFFER * p_buf)
{
    T_RVF_INTERNAL_BUF    *p_hdr;

    if (!p_q->count)	/* if the queue is empty */
        return (NULL);

	if (p_buf == NULL)  /* if current item == NULL, returns the first one */
	{
		return (T_RVF_BUFFER*)p_q->p_first;
	}

    rvf_disable(12);	/* enter critical section */

    p_hdr = (T_RVF_INTERNAL_BUF *)((UINT8 *)p_buf - sizeof(T_RVF_INTERNAL_BUF));
	p_hdr = p_hdr->p_next;
	if (p_hdr != NULL)
	{	p_hdr = (T_RVF_INTERNAL_BUF*) ((UINT8 *)p_hdr + sizeof(T_RVF_INTERNAL_BUF));
	}
	
	rvf_enable();

	return (T_RVF_BUFFER*)p_hdr;
}


/*******************************************************************************
**
** Function         rvf_remove_from_queue
**
** Description      remove a specific item from a queue
**
** Returns          RVF_OK if the item is removed, RVF_INTERNAL_ERR else.
**
*******************************************************************************/
T_RVF_RET		rvf_remove_from_queue (T_RVF_BUFFER_Q * p_q, T_RVF_BUFFER * p_buf)
{
    T_RVF_INTERNAL_BUF    *p_hdr;
	T_RVF_INTERNAL_BUF    *p_target;

	
    if (!p_q->count)	/* if the queue is empty */
        return (RVF_INTERNAL_ERR);

    rvf_disable(12);	/* enter critical section */

	/* find the specific item in the queue */
	p_target = USER2MEM((UINT8*)p_buf);
	p_hdr = USER2MEM( (UINT8 *)p_q->p_first);
	
	if( p_hdr == p_target )
	{	/* the specific item is the first one */
		rvf_dequeue( p_q);
		rvf_enable();
		return (RVF_OK);
	}
	
	while( (p_hdr->p_next != p_target) && (p_hdr->p_next != NULL) )
	{	p_hdr = p_hdr->p_next;
	}
	
	if( p_hdr->p_next == NULL) /* item not found */
	{	rvf_enable();
		return (RVF_INTERNAL_ERR);
	}


	p_hdr->p_next = p_target->p_next;
	p_q->count--;
    
    /* if we removed the last buffer */
    if (p_q->p_last == p_buf)
	{	p_q->p_last = p_hdr + sizeof(T_RVF_INTERNAL_BUF);
	}   

    p_target->p_next = NULL;

#if RVF_ENABLE_BUF_LINKAGE_CHECK
	/* set as unlinked */
	RVF_SET_BUF_UNLINKED(p_target);
#endif

    rvf_enable();		/* exit critical section */

    return (RVF_OK);
}

/*******************************************************************************
**
** Function         rvf_dump_pool
**
** Description      Called by an application to dump memory pool usage
**
** Parameters:		None
**
** Returns          void
**
*******************************************************************************/
void rvf_dump_pool()
{
#if RVF_ENABLE_STATS	/* conditional compilation if stats are enabled */
	
	UINT16 num_pool;
	UINT32 total_mem = 0;

	/* display memory stats */
	rvf_send_trace("*** START DUMPING MEMORY ***", 28, NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);

	/* display the total amount of memory available in the system */
	/* and the total amount of memory currently in use */
	for( num_pool = 0; num_pool < _rvf_get_number_of_pool(); num_pool++)
	{	total_mem	+= _rvf_pools[num_pool].pool_size;
	}
		
	rvf_send_trace( "Total memory available ", 23, total_mem, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);		
	rvf_send_trace( "Memory currently in use", 23, mem_in_use, RV_TRACE_LEVEL_DEBUG_HIGH, RVM_USE_ID);		

#endif /* RVF_ENABLE_STATS */
}

static void rvf_free_protected_buf(void *buf)
{
	rvf_free_buf(buf);
}

void rvf_get_protected_buf(T_RVF_MB_ID mb_id, UINT32 buffer_size, T_RVF_BUFFER** p_buffer)
{
   T_RVF_MB_STATUS err;
   err=rvf_get_buf(mb_id,buffer_size,p_buffer);
   if (err==RVF_GREEN)
   {
	   struct _protectedPtr_ *ptr;
	   struct _exceptionContext_ *context;

	   context=_currentExceptionContext_[rvf_get_taskid()];
	   err=rvf_get_buf(mb_id,sizeof(struct _protectedPtr_),(void*)&ptr);
	   ptr->next=NULL;
	   ptr->previous=NULL;
	   ptr->ptr=*p_buffer;
	   ptr->func=rvf_free_protected_buf;

	   if (err==RVF_GREEN)
	   {
          if (context->stack==NULL)
		  {
			  context->stack=ptr;
		  }
		  else
		  {
			  ptr->previous=context->stack;
			  context->stack->next=ptr;
			  context->stack=ptr;
		  }
	   }
	   else
	   {
		   rvf_free_buf(*p_buffer);
	   }
   }
   if (err!=RVF_GREEN)
	   throw(E_not_enough_memory);
}

//TISHMMS Project
/* add by xmzhou_trace_string to trace debug trace message */
void xmzhou_trace_string(char * string2trace)
{
rvf_send_trace(string2trace,strlen(string2trace),NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, RVM_USE_ID);
}

void xmzhou_trace_string_value(char * string2trace,UINT32 value)
{
rvf_send_trace(string2trace,strlen(string2trace),value, RV_TRACE_LEVEL_DEBUG_LOW, RVM_USE_ID);
}

static void mychar2hex(char ch, char *str)
{
    unsigned char   h_nibble = (ch >> 4) & 0x0F;
    unsigned char   l_nibble = ch & 0x0F;

    if (h_nibble < 10)
        str[0] = 48 + h_nibble;
    else
        str[0] = 55 + h_nibble;

    if (l_nibble < 10)
        str[1] = 48 + l_nibble;
    else
        str[1] = 55 + l_nibble;
}

void xmzhou_trace_n_bytes(char * buffer0, UINT32 len)
{
int i;
int traced_len=0;
char mybuffer[40];
char *tracebuffer;

if(buffer0==NULL) return;

xmzhou_trace_string_value("xmzhou dumping data length=",len);
xmzhou_trace_string("-------");
	

while(traced_len<len){

	if((len-traced_len)>=16){
	  tracebuffer=mybuffer;
	  for (i = 0; i < 16; i++) {
    	mychar2hex (buffer0[traced_len+i], tracebuffer);
	    tracebuffer += 2;
  	  }
	  traced_len+=16;
	  *tracebuffer = '\0';
  	  rvf_send_trace(mybuffer,strlen(mybuffer),NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, RVM_USE_ID);
  	  rvf_delay(20);
	}else{
      tracebuffer=mybuffer;
	  for(i=0;i<(len-traced_len);i++)
	  	{
	    	mychar2hex (buffer0[traced_len+i], tracebuffer);
		    tracebuffer += 2;
	  	}
	  *tracebuffer = '\0';
  	  rvf_send_trace(mybuffer,strlen(mybuffer),NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW, RVM_USE_ID);
      rvf_delay(20);
	  break;
	}

}
}