diff src/cs/services/atp/atp_services.c @ 0:92470e5d0b9e

src: partial import from FC Selenite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 15 May 2020 01:28:16 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cs/services/atp/atp_services.c	Fri May 15 01:28:16 2020 +0000
@@ -0,0 +1,3016 @@
+/*******************************************************************************
+*
+* File Name : atp_services.c
+*
+* Functions gathering all the functions defined in BT9901
+*
+* (C) Texas Instruments, all rights reserved
+*
+* Version number	: 0.1      Date : 28-Feb-2000
+*					  0.9      Updated and reviewed : 10-May-2000
+*
+* History			: 0.1  - Created by E. Baissus
+*
+*
+* Author			: Eric Baissus : e-baissus@ti.com
+*
+*   (C) Copyright 2000 by Texas Instruments Incorporated, All Rights Reserved		
+******************************************************************************/
+#include "rv/rv_general.h"
+#include "rvf/rvf_api.h"
+#include "atp/atp_api.h"
+#include "atp/atp_i.h"
+#include "atp/atp_config.h"
+#include "atp/atp_messages.h"
+#include "atp/atp_cmd.h"
+#include "rvm/rvm_use_id_list.h"
+
+#include <string.h>
+
+#define ATP_DEBUG_MSG_ENABLED
+//#define ATP_HEX_DUMP_ENABLED
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+	#include <stdio.h>
+
+	static char  gbl_debug_message[100] = "";
+#endif
+
+static T_ATP_RET atp_interpret_data(T_ATP_PORT_STRUCT	*port_p,T_ATP_SW_NB spp_sw_nb, 
+									T_ATP_SW_NB appli_sw_nb);
+
+static void atp_mb_call_back(T_RVF_MB_ID mb);
+
+
+#ifdef ATP_HEX_DUMP_ENABLED
+
+/******************************************************************************
+* Function name: atp_sprint_int_as_hex
+*
+* Description : Convert bytes to hexadecimal strings.
+*
+* Return     :	Length.
+*
+******************************************************************************/
+int atp_sprint_int_as_hex(char *buf, unsigned int n, int width, char padding)
+{
+    unsigned int m = n; // MUST be unsigned because it will be right shifted
+    int size = 0;
+    int i;
+    char digit;
+    char *buf_start = buf;
+
+    // Count number of digits in <n>
+    do {
+        size++;
+    } while (m >>= 4);
+
+    // Shift significant part of <n> into the top-most bits
+    n <<= 4 * (8 - size);
+
+    // Pad output buffer with <padding>
+    if (0 < width && width <= 8) {
+        width = (width > size ? width - size : 0);
+        while (width--)
+            *buf++ = padding;
+    }
+
+    // Convert <n>, outputting the hex digits
+    for (i = 0; i < size; i++) {
+        digit  = (n >> 28) & 0xF;
+        digit += (digit < 10 ? '0' : 'A' - 10);
+        *buf++ = digit;
+        n <<= 4;
+    }
+
+    // Null terminate
+    *buf = 0;
+
+    return buf - buf_start;
+}
+
+
+/******************************************************************************
+* Function name: atp_hexdump_buf
+*
+* Description : Display buffers as hexadecimal strings.
+*
+* Return     :	None.
+*
+******************************************************************************/
+void atp_hexdump_buf(char *buf, int size)
+{
+    int n, i, multiline;
+    char string[(8+1) + (16+1) + (3<<4) + 1];
+    char *s;
+    
+    multiline = (size > 16);
+
+    while (size > 0)
+    {
+        s = string;
+        n = (size > 16 ? 16 : size);
+
+        // Print address
+        if (multiline) {
+            s += atp_sprint_int_as_hex(s, (unsigned int) buf, 8, ' ');
+            *s++ = ' ';
+        }
+
+        // Print the textual representation
+        for (i = 0; i < n; i++)
+            *s++ = (buf[i] >= ' ' && buf[i] < 127 ? buf[i] : '.');
+
+        // Pad textual representation with spaces
+        if (multiline)
+            for (i = 0; i < 16 - n; i++)
+                *s++ = ' ';
+
+        // Print hexedecimal bytes
+        for (i = 0; i < n; i++) {
+            *s++ = ' ';
+            s += atp_sprint_int_as_hex(s, (unsigned int) buf[i] & 0xFF, 2, '0');
+        }
+
+        *s = 0;
+		rvf_send_trace (string,
+						strlen (string),
+						NULL_PARAM,
+						RV_TRACE_LEVEL_DEBUG_LOW,
+						ATP_USE_ID);
+        buf  += 16;
+        size -= 16;
+    }
+}
+#endif
+
+/******************************************************************************
+* Function name: atp_open_port_rqst
+*
+* Description : Initialise a port creation
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id (atrget or initiator was wrong)
+*					RV_MEMORY_ERR : not enough memory in ATP PRIM MB to create a new port
+*
+* History			: 0.1 (1-Marsh-2000) - Created
+*					: 0.9  (5-May-2000) - Reviewed
+******************************************************************************/
+T_ATP_RET atp_open_port_rqst(T_ATP_SW_ENTITY_ID initiator_id, T_ATP_SW_ENTITY_ID target_id, 
+							 T_ATP_PORT_NB port_nb, T_ATP_PORT_INFO port_info,
+							 T_ATP_NO_COPY_INFO no_copy_info, T_ATP_CUSTOM_INFO * cust_info_p)
+{
+	T_ATP_PORT_STRUCT       *new_port_p        = NULL;
+	T_ATP_OPEN_PORT_IND     *open_port_event_p = NULL;
+	T_ATP_SW_ENTITY_STRUCT  *initiator_p       = NULL;
+	T_ATP_SW_ENTITY_STRUCT  *target_p          = NULL;
+
+	/* Check for invalid parameters and get the pointers on the structures that */
+	/* gather information about the initiator and target SW entities */
+	if ((initiator_id > ATP_MAX_NB_SW_ENTITY) || \
+		(target_id > ATP_MAX_NB_SW_ENTITY) || \
+		((initiator_p = atp_sw_entity_table_p[initiator_id]) == NULL) || \
+		((target_p = atp_sw_entity_table_p[target_id]) == NULL))
+	{
+		atp_error_switch (ATP_ERROR_FAILED_TO_OPEN_A_PORT,
+						  ATP_PARAM_ERROR,
+						  NULL);
+		return (RV_INVALID_PARAMETER);
+	}
+
+	/* Then, check whether ATP is started */
+	if (atp_swe_state != ATP_STARTED)
+	{
+		atp_error_switch (ATP_ERROR_FAILED_TO_OPEN_A_PORT,
+						  ATP_ISSUED_IN_A_WRONG_STATE_ERROR,
+						  NULL);
+		return (RV_NOT_SUPPORTED);
+	}
+
+	/* Create an instance gathering the port information and initialise it */
+	/* (refer to atp_init_port ()) */
+	if (atp_create_port (&new_port_p) != RV_OK)
+	{ 
+		atp_error_switch (ATP_ERROR_FAILED_TO_OPEN_A_PORT,
+						  ATP_MEMORY_ERROR,
+						  NULL);
+		return (RV_MEMORY_ERR);
+	}
+
+	/* Increase the number of port currently in use */
+	initiator_p->nb_open_port++;
+	target_p->nb_open_port++;
+	
+	/* Update information about the initiator */
+	new_port_p->cmd_info.state             = READY_FOR_NEW_CMD;
+	new_port_p->port_state                 = ATP_OPEN_PENDING;
+	(new_port_p->port_info[0]).sw_id       = initiator_id;
+	(new_port_p->port_info[0]).port_nb     = port_nb;
+	(new_port_p->port_info[0]).ring_type   = port_info.ring_type;
+	(new_port_p->port_info[0]).signal_mask = (T_ATP_SIGNAL_MASK) (port_info.signal_mask & (ATP_ALL_THE_SIGNAL_UNMASK));
+
+	/* Update information about the target */
+	(new_port_p->port_info[1]).sw_id = target_id;
+
+	/* Store the requested port configuration */
+	if ((initiator_p->mode).cmd_support_mode == CMD_SUPPORT_OFF)
+	{
+
+		/* Check for invalid configuration */
+		if (port_info.port_config > NOT_DEFINED_CONFIG)
+		{
+			atp_error_switch (ATP_ERROR_FAILED_TO_OPEN_A_PORT,
+							  ATP_PARAM_ERROR,
+							  NULL);
+
+			/* Withdraw the instance gathering the port information */
+			atp_delete_port (new_port_p);
+				
+			/* Decrease number of port currently in use */
+			initiator_p->nb_open_port--;
+			target_p->nb_open_port--;
+			return (RV_INVALID_PARAMETER);
+		}
+		new_port_p->port_config = port_info.port_config;
+	}
+
+	/* Get settings related the COPY_OFF mode */
+	if ((initiator_p->mode).cp_mode == COPY_OFF)
+	{
+
+		/* Get the number of bytes left free for the RX header and trailer */
+		if (no_copy_info.rx_head_mode == RX_HEADER_ON)
+		{
+			((new_port_p->port_info[0]).no_copy_info).rx_head_size  = no_copy_info.rx_head_size;
+			((new_port_p->port_info[0]).no_copy_info).rx_trail_size = no_copy_info.rx_trail_size;
+		}
+
+		/* Get the number of bytes left free for the TX header and trailer */
+		if (no_copy_info.tx_head_mode == TX_HEADER_ON)
+		{
+			((new_port_p->port_info[0]).no_copy_info).tx_head_size  = no_copy_info.tx_head_size;
+			((new_port_p->port_info[0]).no_copy_info).tx_trail_size = no_copy_info.tx_trail_size;
+		}
+
+		/* Get memory bank information */
+		(new_port_p->port_info[0]).tx_mb = no_copy_info.tx_mb;
+		(new_port_p->port_info[0]).rx_mb = no_copy_info.rx_mb;
+
+		/* Copy those information on both sides. Of course TX -> RX and RX -> TX */
+		(new_port_p->port_info[1]).tx_mb = no_copy_info.rx_mb;
+		(new_port_p->port_info[1]).rx_mb = no_copy_info.tx_mb;
+
+		/* Get the packet mode (i.e. SEGMENTED_PACKET) */
+		((new_port_p->port_info[0]).no_copy_info).packet_mode = no_copy_info.packet_mode;
+	}
+	
+	/* At last, send an ATP_OPEN_PORT_IND event to the target */
+	switch (rvf_get_buf (atp_mb_prim, \
+						 sizeof (T_ATP_OPEN_PORT_IND), \
+						 (T_RVF_BUFFER **) &open_port_event_p))
+	{
+		case RVF_GREEN:
+			{
+				(open_port_event_p->rv_hdr).msg_id   = ATP_OPEN_PORT_IND;
+				open_port_event_p->initiator_id      = initiator_id;
+				open_port_event_p->initiator_port_nb = port_nb;
+				open_port_event_p->custom_info_p     = cust_info_p;
+				break;
+			}
+
+		/* Insufficient resources */
+		case RVF_YELLOW:
+			{
+				rvf_free_buf ((T_RVF_BUFFER *) open_port_event_p);
+			}
+		default:
+			{
+
+				/* Withdraw the instance gathering the port information */
+				atp_delete_port (new_port_p);
+				
+				/* Decrease number of port currently in use */
+				initiator_p->nb_open_port--;
+				target_p->nb_open_port--;
+				atp_error_switch (ATP_ERROR_FAILED_TO_OPEN_A_PORT,
+								  ATP_MEMORY_ERROR,
+								  NULL);
+				return (RV_MEMORY_ERR);
+			}
+	}
+	return (atp_send_message (target_p->return_path, \
+							  (T_ATP_MESSAGE *) open_port_event_p));
+}
+
+
+/******************************************************************************
+* Function name: atp_open_port_rsp
+*
+* Description : Response from the target to a open port request
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*					RV_NOT_SUPPORTED : port already open 
+*					RV_INTERNAL_ERR : Error generated because bad initialisation of MB
+*
+*					atp_error can be called if MB is RED 
+* 
+* History			: 0.1 (1-Marsh-2000) - Created
+*					: 0.9  (5-May-2000) - Reviewed
+******************************************************************************/
+
+T_ATP_RET atp_open_port_rsp(T_ATP_SW_ENTITY_ID initiator_id, T_ATP_PORT_NB initiator_port_nb,
+							T_ATP_SW_ENTITY_ID target_id, T_ATP_PORT_NB target_port_nb, 
+							T_ATP_PORT_INFO port_info, T_ATP_NO_COPY_INFO no_copy_info, 
+							T_ATP_CUSTOM_INFO * custom_info_p, T_ATP_OPEN_PORT_RESULT result)
+							
+{
+	T_ATP_SW_NB             sw_nb                  = 0;
+	T_ATP_PORT_STRUCT       *port_p                = NULL;
+	T_ATP_OPEN_PORT_CFM     *open_port_cfm_event_p = NULL;
+	T_ATP_SW_ENTITY_STRUCT  *initiator_p           = NULL;
+	T_ATP_SW_ENTITY_STRUCT  *target_p              = NULL;
+	
+	/* Check for invalid parameters, get the pointers on the structures that */
+	/* gather information about the initiator and remote SW entities and get */
+	/* the port associated with initiator SW entity */
+	if ((initiator_id > ATP_MAX_NB_SW_ENTITY) || \
+		(target_id > ATP_MAX_NB_SW_ENTITY) || \
+		((initiator_p = atp_sw_entity_table_p[initiator_id]) == NULL) || \
+		((target_p = atp_sw_entity_table_p[target_id]) == NULL) || \
+		(atp_get_port (initiator_id, \
+					   initiator_port_nb, \
+					   &port_p, \
+					   &sw_nb) != RV_OK))
+	{
+		atp_error_switch (ATP_ERROR_FAILED_TO_ACCEPT_A_PORT,
+						  ATP_PARAM_ERROR,
+						  NULL);
+		return (RV_INVALID_PARAMETER);
+	}
+
+	/* Check whether the port is waiting for an ATP_OPEN_PORT_CFM event */
+	if (port_p->port_state != ATP_OPEN_PENDING)
+	{
+		atp_error_switch (ATP_ERROR_FAILED_TO_ACCEPT_A_PORT,
+						  ATP_ISSUED_IN_A_WRONG_STATE_ERROR,
+						  NULL);
+		return (RV_NOT_SUPPORTED);
+	}
+
+	/* Fill in the ATP_OPEN_PORT_CFM event to be sent back to the initiator */
+    if (rvf_get_buf (atp_mb_prim, \
+					 sizeof (T_ATP_OPEN_PORT_CFM), \
+					 (T_RVF_BUFFER **) &open_port_cfm_event_p) == RVF_RED)
+	{
+
+		/* Withdraw the instance gathering the port information */
+		atp_delete_port (port_p);
+		atp_error (ATP_ERROR_MB_PRIM_RED);
+		return (RV_MEMORY_ERR);
+	}
+	(open_port_cfm_event_p->rv_hdr).msg_id	 = ATP_OPEN_PORT_CFM;
+	open_port_cfm_event_p->initiator_port_nb = initiator_port_nb;
+	open_port_cfm_event_p->custom_info_p	 = custom_info_p;
+
+	/* Send a negative ATP_OPEN_PORT_CFM event right now whether the target */
+	/* denies opening the port */
+	if ((open_port_cfm_event_p->result = result) != OPEN_PORT_OK)
+	{
+
+		/* Withdraw the instance gathering the port information */
+		atp_delete_port (port_p);
+				
+		/* Decrease number of port currently in use */
+		initiator_p->nb_open_port--;
+		target_p->nb_open_port--;
+
+		/* Send a negative ATP_OPEN_PORT_CFM event to the initiator */
+		atp_send_message (initiator_p->return_path,
+						  (T_ATP_MESSAGE *) open_port_cfm_event_p);
+		return (RV_OK);
+	}
+	
+	/* By default, set the port in 'Command Mode'. Hence, the port is ready */
+	/* to exchange AT commands */
+	port_p->port_state = ATP_CMD_MODE;
+
+	/* Update information about the target */
+	(port_p->port_info[1]).port_nb     = target_port_nb;
+	(port_p->port_info[1]).ring_type   = port_info.ring_type;
+	(port_p->port_info[1]).signal_mask = (T_ATP_SIGNAL_MASK) (port_info.signal_mask & ATP_ALL_THE_SIGNAL_UNMASK);
+
+	/* One of the SW entity is a transport layer that does not handle AT commands */
+	if ((port_p->port_config == NOT_DEFINED_CONFIG) && \
+		((target_p->mode).cmd_support_mode == CMD_SUPPORT_OFF))
+	{
+		
+		/* Check for an invalid configuration */
+		if (port_info.port_config > NOT_DEFINED_CONFIG)
+		{
+			atp_error_switch (ATP_ERROR_FAILED_TO_OPEN_A_PORT,
+							  ATP_PARAM_ERROR,
+							  NULL);
+
+			/* Clean up */
+			rvf_free_buf ((T_RVF_BUFFER *) open_port_cfm_event_p);
+			return (RV_INVALID_PARAMETER);
+		}
+
+		/* Update the port configuration */
+		port_p->port_config = port_info.port_config;
+	}
+
+	/* Get settings related the COPY_OFF mode */
+	if ((target_p->mode).cp_mode == COPY_OFF)
+	{
+
+		/* Get the number of bytes left free for the RX header and trailer */
+		if (no_copy_info.rx_head_mode == RX_HEADER_ON)
+		{
+			((port_p->port_info[1]).no_copy_info).rx_head_size  = no_copy_info.rx_head_size;
+			((port_p->port_info[1]).no_copy_info).rx_trail_size = no_copy_info.rx_trail_size;
+		}
+
+		/* Get the number of bytes left free for the TX header and trailer */
+		if (no_copy_info.tx_head_mode == TX_HEADER_ON)
+		{
+			((port_p->port_info[1]).no_copy_info).tx_head_size  = no_copy_info.tx_head_size;
+			((port_p->port_info[1]).no_copy_info).tx_trail_size = no_copy_info.tx_trail_size;
+		}
+
+		/* Get memory bank information */
+		if (no_copy_info.rx_mb != RVF_INVALID_MB_ID)
+		{
+			(port_p->port_info[1]).rx_mb = no_copy_info.rx_mb;
+		}
+		if (no_copy_info.tx_mb != RVF_INVALID_MB_ID)
+		{
+			(port_p->port_info[1]).tx_mb = no_copy_info.tx_mb;
+		}
+
+		/* Get the packet mode (i.e. SEGMENTED_PACKET) */
+		((port_p->port_info[1]).no_copy_info).packet_mode = no_copy_info.packet_mode;
+	}
+
+	/* If only one of the SW entities has provided valid memory banks, */
+	/* copy those information on both sides. Of course TX -> RX and RX -> TX */
+	if ((port_p->port_info[0]).rx_mb == RVF_INVALID_MB_ID)
+	{
+		(port_p->port_info[0]).rx_mb = (port_p->port_info[1]).tx_mb;
+	}
+	if ((port_p->port_info[0]).tx_mb == RVF_INVALID_MB_ID)
+	{
+		(port_p->port_info[0]).tx_mb = (port_p->port_info[1]).rx_mb;
+	}
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+			(void) sprintf (gbl_debug_message,
+							"ATP: Init (RX: 0x%.4X TX: 0x%.4X), Target (RX: 0x%.4X TX: 0x%.4X) ",
+							port_p->port_info[0].rx_mb,
+							port_p->port_info[0].tx_mb,
+							port_p->port_info[1].rx_mb,
+							port_p->port_info[1].tx_mb);
+			rvf_send_trace (gbl_debug_message,
+							(UINT8) strlen (gbl_debug_message),
+							NULL_PARAM,
+							RV_TRACE_LEVEL_DEBUG_MEDIUM,
+							ATP_USE_ID);
+#endif
+
+	/* At the end, no memory banks should be invalid */
+	if ((port_p->port_info[0].tx_mb == RVF_INVALID_MB_ID) || \
+		(port_p->port_info[0].rx_mb == RVF_INVALID_MB_ID) || \
+		(port_p->port_info[1].tx_mb == RVF_INVALID_MB_ID) || \
+		(port_p->port_info[1].rx_mb == RVF_INVALID_MB_ID))
+	{
+		ATP_SEND_TRACE ("ATP: Some memory banks not specified ",
+						RV_TRACE_LEVEL_ERROR);
+		atp_error_switch (ATP_ERROR_FAILED_TO_ACCEPT_A_PORT,
+						  ATP_PARAM_ERROR,
+						  NULL);
+
+		/* Clean up */
+		rvf_free_buf ((T_RVF_BUFFER *) open_port_cfm_event_p);
+		return (RV_INTERNAL_ERR);
+	}
+
+	/* If needed, allocate a buffer for DCE or DTE information */
+	if (((initiator_p->mode).cmd_support_mode == CMD_SUPPORT_OFF) || \
+		((target_p->mode).cmd_support_mode == CMD_SUPPORT_OFF))
+	{
+		switch (port_p->port_config)
+		{
+			case DCE_CONFIG:
+			case DTE_CONFIG:
+				{
+					T_ATP_DCE_INFO  *dce_info_p = NULL;
+					
+					ATP_SEND_TRACE ("ATP: A port has been open with DCE/DTE mode activated",
+									RV_TRACE_LEVEL_DEBUG_LOW);
+
+					/* Allocate a buffer for DCE or DTE information */
+					if (rvf_get_buf (atp_mb_prim, \
+									 sizeof (T_ATP_DCE_INFO), \
+									 (T_RVF_BUFFER **) &dce_info_p) == RVF_RED)
+					{
+						atp_error_switch (ATP_ERROR_FAILED_TO_ACCEPT_A_PORT,
+										  ATP_MEMORY_ERROR,
+										  NULL);
+
+						/* Clean up */
+						rvf_free_buf ((T_RVF_BUFFER *) open_port_cfm_event_p);
+						return (RV_MEMORY_ERR);
+					}
+
+					/* Initialize DCE or DTE information */
+					atp_cmd_init_dce_info (dce_info_p);
+					port_p->dce_info_p = dce_info_p;
+					break;
+				}
+			case DATA_CONFIG:
+				{
+
+					/* The port is plugged on a transport layer */
+					port_p->port_state = ATP_DATA_MODE;
+					break;
+				}
+			default:
+				{
+					ATP_SEND_TRACE ("ATP: Failed to open a port (port configuration not specified)",
+									RV_TRACE_LEVEL_ERROR);
+					atp_error_switch (ATP_ERROR_FAILED_TO_ACCEPT_A_PORT,
+									  ATP_PARAM_ERROR,
+									  NULL);
+
+					/* Clean up */
+					rvf_free_buf ((T_RVF_BUFFER *) open_port_cfm_event_p);
+					return (RV_INTERNAL_ERR);
+				}
+		}
+	}
+
+	/* At last, send an ATP_OPEN_PORT_CFM event to the initiator */
+	return (atp_send_message (initiator_p->return_path, \
+							  (T_ATP_MESSAGE *) open_port_cfm_event_p));
+}
+
+
+
+
+/******************************************************************************
+* Function name: atp_close_port
+*
+* Description : Close a port
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*
+*					atp_error can be called if MB is RED 
+* 
+* History			: 0.1 (1-Marsh-2000) - Created
+*					: 0.9  (5-May-2000) - Reviewed
+******************************************************************************/
+T_ATP_RET atp_close_port(T_ATP_SW_ENTITY_ID closer_sw_id, T_ATP_PORT_NB closer_port_nb)
+{
+	T_ATP_SW_ENTITY_STRUCT * closer_sw_id_p, * other_sw_id_p;
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB closer_sw_nb,other_sw_nb;
+	T_ATP_PORT_CLOSED * port_closed_event_p;
+	
+	/* Get the pointer on the port structure */
+	if(atp_get_port(closer_sw_id,closer_port_nb,&port_p,&closer_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_CLOSE_A_PORT,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	
+	other_sw_nb= (T_ATP_SW_NB) (! closer_sw_nb);
+	
+	
+	
+	/* Send an event to the other sw entity indicating the port has been closed */
+    if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_PORT_CLOSED),(void **) &port_closed_event_p)==RVF_RED)
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_CLOSE_A_PORT,ATP_MEMORY_ERROR,NULL);
+		return RV_MEMORY_ERR;
+	}
+	
+	port_closed_event_p->rv_hdr.msg_id	= ATP_PORT_CLOSED;
+	port_closed_event_p->port_nb		= port_p->port_info[other_sw_nb].port_nb;
+	port_closed_event_p->closer_port_nb = closer_port_nb;
+	port_closed_event_p->closer_sw_id	= closer_sw_id;
+
+	/* Get pointer on the other sw entity data structure */
+	other_sw_id_p=atp_sw_entity_table_p[port_p->port_info[other_sw_nb].sw_id];
+	closer_sw_id_p = atp_sw_entity_table_p[closer_sw_id];
+
+	/* Send the event and update open port nb */
+	
+	atp_send_message(other_sw_id_p->return_path,(T_ATP_MESSAGE *) port_closed_event_p);
+	
+	/* Decrease number of port for each SW entity */
+	other_sw_id_p->nb_open_port--;
+	closer_sw_id_p->nb_open_port--;
+
+	atp_delete_port(port_p);
+	
+	
+	return RV_OK;
+}
+
+
+
+
+
+/******************************************************************************
+* Function name: atp_send_cmd
+*
+* Description : Send a command
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*					RV_NOT_SUPPORTED : command needed to be translated and was unknow by ATP
+*
+*					atp_error can be called if MB is RED 
+*
+* History		: 0.1 (1-Marsh-2000) - Created
+*				: 0.9  (5-May-2000) - Reviewed
+*
+* Note :		Sender SW Entity cannot in DCE_ON
+*				
+******************************************************************************/
+T_ATP_RET atp_send_cmd(T_ATP_SW_ENTITY_ID sender_sw_id, T_ATP_PORT_NB sender_port_nb,
+					   T_ATP_CMD_TYPE cmd_type,T_ATP_CMD_NB cmd_nb, T_ATP_CMD  * cmd_info_p)
+{
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB sender_sw_nb, other_sw_nb;
+	T_ATP_CMD_RDY * cmd_ready_event_p;
+	T_ATP_TXT_CMD_RDY * txt_cmd_ready_event_p;
+	T_ATP_SW_ENTITY_STRUCT * other_sw_entity_p;
+	T_ATP_TXT_CMD  text_p;
+	UINT16 length;
+	T_ATP_BUFFER atp_buffer_p;
+	T_ATP_NO_COPY_DATA_RDY * no_copy_data_ready_p;
+	T_ATP_RET return_status;
+	
+	/* Get the pointer on the port structure */
+	if(atp_get_port(sender_sw_id,sender_port_nb,&port_p,&sender_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	other_sw_nb=(T_ATP_SW_NB) (! sender_sw_nb);
+	
+	if (port_p->port_state == ATP_OPEN_PENDING)
+	{
+		/* Port is not completely open */
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_ISSUED_IN_A_WRONG_STATE_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	/* get pointer on the other SW entity data structure in order to get info */
+	other_sw_entity_p=atp_sw_entity_table_p[port_p->port_info[other_sw_nb].sw_id];
+		
+	/* Check if the port is available */
+	if ( (port_p->cmd_info.state != READY_FOR_NEW_CMD) &&
+		(cmd_type == AT_CMD))
+	{	// A new command cannot been sent if a result code has not been previously received */
+		rvf_send_trace("ATP : Refused to send a new command on a port which was waiting for a result ",77,
+			NULL_PARAM,RV_TRACE_LEVEL_WARNING, ATP_USE_ID); 		
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_WAITING_FOR_RESULT,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	if (cmd_type == AT_CMD)
+	{
+		port_p->cmd_info.state = WAITING_FOR_RESULT; // Prevent any new command entry
+	}
+	
+	
+	
+	if (other_sw_entity_p->mode.cmd_support_mode == CMD_SUPPORT_OFF)
+	{
+		/* Other SW entity does not support to get command directly */
+		if ( (port_p->port_config == DATA_CONFIG) ||
+			 (port_p->port_state == ATP_DATA_MODE) )
+		{
+			ATP_SEND_TRACE ("ATP: A command cannot be sent on a DATA_ONLY configuration port",RV_TRACE_LEVEL_WARNING);
+			atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_WAITING_FOR_RESULT,NULL);
+			return RV_NOT_SUPPORTED;
+		}
+		
+		/* DCE or DTE emulation is ON */
+		/* Must translate the command and put it into a buffer of data */
+		
+		/* Check if the answer is a result code from a ON_GOING interpretation of a raw data buffer 
+		containing several commands */
+		if ((cmd_type == RESULT_CODE) && (port_p->cmd_info.status == ON_GOING) && (cmd_nb == ATP_OK_NB))
+		{	
+			// Then interpret data. Either sends result to peer device or resend a command to appli
+			// START SEMAPHORE 
+			port_p->cmd_info.state=READY_FOR_NEW_CMD;
+			return_status=atp_interpret_data(port_p,other_sw_nb,sender_sw_nb);
+			// STOP SEMAPHORE
+			// other = transport layer , sender = appli
+			
+			if (return_status == RV_MEMORY_ERR)
+			{
+				atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_MEMORY_ERROR,NULL);
+				return RV_MEMORY_ERR;
+			}
+			
+			return RV_OK;
+		}		   
+		
+		/* Otherwise can be : result code was not OK -> so re-init cmd_info and send the result code to peer
+		normal command to send
+		final result to send -> so re-init cmd_info and send the result code to peer
+		
+		/* Obtain buffer with command translated into data buffer ready for TX*/
+		if(atp_create_data_buffer_from_cmd(INTERPRETED_MODE,
+			port_p->port_info[other_sw_nb].no_copy_info.rx_head_size,
+			port_p->port_info[other_sw_nb].no_copy_info.rx_trail_size,
+			(T_ATP_DCE_INFO *) port_p->dce_info_p,
+			port_p->port_info[other_sw_nb].rx_mb,
+			cmd_type,
+			cmd_nb,NULL,cmd_info_p,
+			&atp_buffer_p,&length)!=RV_OK)
+		{
+			atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_CANNOT_TRANSLATE_CMD,NULL);
+			return RV_NOT_SUPPORTED;
+		}
+		
+		/* Send it to the other SW entity via an ATP_NO_COPY_DATA_RDY */
+		/* Note: it is assumed that only COPY OFF instance can be DCE ON */
+		if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_NO_COPY_DATA_RDY),(void **) &no_copy_data_ready_p)==RVF_RED)
+		{
+			atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_MEMORY_ERROR,NULL);
+			return RV_MEMORY_ERR;
+		}		
+		
+		no_copy_data_ready_p->rv_hdr.msg_id	= ATP_NO_COPY_DATA_RDY;
+		no_copy_data_ready_p->port_nb		= port_p->port_info[other_sw_nb].port_nb;
+		no_copy_data_ready_p->buffer_size	= length-port_p->port_info[other_sw_nb].no_copy_info.rx_head_size
+						-port_p->port_info[other_sw_nb].no_copy_info.rx_trail_size;
+		no_copy_data_ready_p->atp_buffer_p	= atp_buffer_p;
+		
+		/* Re-accept to deal with any new command */
+		if (cmd_type == RESULT_CODE)
+		{
+			atp_init_cmd_info_struct(port_p); /* Re-initilalise all the cmd_info structure */
+		}
+		else 
+		{
+			if(cmd_type == AT_CMD) 
+			{
+				port_p->cmd_info.state=WAITING_FOR_RESULT;
+			}
+		}
+		atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *) no_copy_data_ready_p);
+			
+		return RV_OK;	
+		
+	} /* End of the DCE case */
+	
+	
+	
+	
+	
+	if(other_sw_entity_p->mode.cmd_mode==TXT_MODE)
+	{
+		/* Other SW entity wants command in text format */
+		if (atp_translate_cmd_to_txt(cmd_type,cmd_nb,cmd_info_p,
+			port_p->port_info[other_sw_nb].rx_mb,&text_p,&length)==RV_OK)
+		{
+			/* The command has been properly translated */
+			/* Send an event to the other sw entity with the text buffer*/	
+			if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_TXT_CMD_RDY),(void **) &txt_cmd_ready_event_p)==RVF_RED)
+			{
+				atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_MEMORY_ERROR,NULL);
+				return RV_MEMORY_ERR;
+			}
+			
+			txt_cmd_ready_event_p->rv_hdr.msg_id	= ATP_TXT_CMD_RDY;	
+			txt_cmd_ready_event_p->cmd_type			= cmd_type;
+			txt_cmd_ready_event_p->txt_cmd_p		= text_p;
+			txt_cmd_ready_event_p->port_nb			= port_p->port_info[other_sw_nb].port_nb;
+			
+			/* Re-accept to deal with any new command */
+			if (cmd_type == RESULT_CODE) { port_p->cmd_info.state=READY_FOR_NEW_CMD;}
+			
+			/* Send the event */
+			atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *) txt_cmd_ready_event_p);
+			return RV_OK;
+		}
+		
+		/* This command cannot be translated into text */
+		/* Send a command event without text translation */
+		rvf_send_trace("ATP : CMD coult not be translated into text format ",51,NULL_PARAM,
+			RV_TRACE_LEVEL_WARNING, ATP_USE_ID); 
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_CANNOT_TRANSLATE_CMD,NULL);
+		return RV_NOT_SUPPORTED;
+		
+	}
+	
+	/* Otherwise, means that target SWE is also in CMD format */
+	/* Other SW entity will have command in same format (command format) */
+	/* Send an event to the other sw entity forwarding the command */	
+	if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_CMD_RDY),(void **) &cmd_ready_event_p)==RVF_RED)
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_MEMORY_ERROR,NULL);
+		return RV_MEMORY_ERR;
+	}
+	
+	cmd_ready_event_p->rv_hdr.msg_id	= ATP_CMD_RDY;	
+	cmd_ready_event_p->cmd_type			= cmd_type;
+	cmd_ready_event_p->cmd_nb			= cmd_nb;
+	cmd_ready_event_p->cmd_info_p		= cmd_info_p;
+	cmd_ready_event_p->port_nb			= port_p->port_info[other_sw_nb].port_nb;
+	
+	/* Re-accept to deal with any new command */
+	if (cmd_type == RESULT_CODE) { port_p->cmd_info.state=READY_FOR_NEW_CMD;}
+	
+	/* Send the event */
+	atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *) cmd_ready_event_p);
+	return RV_OK;
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+* Function name: atp_send_txt_cmd
+*
+* Description : Send a command in text format
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*
+*					atp_error can be called if MB is RED 
+*					If the cmd needed to be translated and was unknown by ATP, the cmd is sent
+*					in text format
+*
+* History		: 0.1 (1-Marsh-2000) - Created
+*				: 0.9  (5-May-2000) - Reviewed
+******************************************************************************/
+T_ATP_RET atp_send_txt_cmd(T_ATP_SW_ENTITY_ID sender_sw_id, T_ATP_PORT_NB sender_port_nb,
+						   T_ATP_CMD_TYPE cmd_type, T_ATP_TXT_CMD txt_p)
+{
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB sender_sw_nb, other_sw_nb;
+	T_ATP_CMD_RDY * cmd_ready_event_p;
+	T_ATP_TXT_CMD_RDY * txt_cmd_ready_event_p;
+	T_ATP_SW_ENTITY_STRUCT * other_sw_entity_p;
+	T_ATP_NO_COPY_DATA_RDY * no_copy_data_ready_p;
+	T_ATP_CMD * cmd_info_p;
+	T_ATP_CMD_TYPE found_cmd_type;
+	T_ATP_CMD_NB found_cmd_nb;
+	T_ATP_BUFFER atp_buffer_p;
+	T_ATP_RET return_status;
+	
+	UINT16 length;
+	void * dummy_p = NULL;
+	
+	
+	/* Get the pointer on the port structure */
+	if(atp_get_port(sender_sw_id,sender_port_nb,&port_p,&sender_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	other_sw_nb=(T_ATP_SW_NB) (! sender_sw_nb);
+	
+	/* get pointer on the other SW entity data structure in order to get info */
+	other_sw_entity_p=atp_sw_entity_table_p[port_p->port_info[other_sw_nb].sw_id];
+	
+	if (port_p->port_state == ATP_OPEN_PENDING)
+	{
+		/* Port is not completely open */
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_ISSUED_IN_A_WRONG_STATE_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	if ( (other_sw_entity_p->mode.cmd_support_mode==CMD_SUPPORT_OFF) &&
+		(port_p->port_state != ATP_CMD_MODE))
+	{
+		ATP_SEND_TRACE ("ATP : Refused to send a command to a SWE in data mode ",
+			RV_TRACE_LEVEL_WARNING); 		
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_WAITING_FOR_RESULT,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	
+	/* Check if the port is available */
+	if ( (port_p->cmd_info.state != READY_FOR_NEW_CMD) &&
+		(cmd_type == AT_CMD))
+	{	// A new command cannot been sent if a result code has not been previously received */
+		rvf_send_trace("ATP : Refused to send a new command on a port which was waiting for a result ",77,
+			NULL_PARAM,RV_TRACE_LEVEL_WARNING, ATP_USE_ID); 
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_WAITING_FOR_RESULT,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	if (cmd_type == AT_CMD)
+	{
+		port_p->cmd_info.state = WAITING_FOR_RESULT; // Prevent any new command entry
+	}
+	
+	
+	
+	
+	if (other_sw_entity_p->mode.cmd_support_mode==CMD_SUPPORT_OFF)
+	{
+		/* Other SW entity does not support to get command directly */
+		if (port_p->port_config == DATA_CONFIG)
+		{
+			ATP_SEND_TRACE ("ATP: A command cannot be sent on a DATA_ONLY configuration port",RV_TRACE_LEVEL_WARNING);
+			atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_WAITING_FOR_RESULT,NULL);
+			return RV_NOT_SUPPORTED;
+		}
+		
+		/* DCE or DTE emulation is ON */
+		/* Must translate the command and put it into a buffer of data */
+		found_cmd_type = cmd_type;
+		found_cmd_nb = 0xFF;
+		
+		if ((found_cmd_type == UNKNOWN) || (found_cmd_type == RESULT_CODE))
+		{
+			// Check if the answer is a RESULT_CODE with OK or ERROR
+			atp_translate_txt_to_cmd(txt_p,cmd_type,&found_cmd_type,&found_cmd_nb,
+				port_p->port_info[other_sw_nb].rx_mb,
+				(T_ATP_CMD **) &dummy_p); // => found_cmd_type and found_cmd_nb may be updated now
+		}
+		
+		/* Check if the answer is a result code from a ON_GOING interpretation of a raw data buffer 
+		containing several commands */
+		if ((found_cmd_type == RESULT_CODE) && (port_p->cmd_info.status == ON_GOING) && (found_cmd_nb == ATP_OK_NB))
+		{	
+			rvf_free_buf(txt_p);
+			// Then interpret data. Either sends result to peer device or resend a command to appli
+			// START SEMAPHORE 
+			port_p->cmd_info.state=READY_FOR_NEW_CMD;
+			return_status=atp_interpret_data(port_p,other_sw_nb,sender_sw_nb);
+			// STOP SEMAPHORE
+			// other = transport layer , sender = appli
+			
+			if (return_status == RV_MEMORY_ERR)
+			{
+				atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_MEMORY_ERROR,NULL);
+				return RV_MEMORY_ERR;
+			}
+			
+			return RV_OK;
+		}		   
+		
+		
+		/* Otherwise can be : result code was not OK -> so re-init cmd_info and send the result code to peer
+		normal command to send
+		final result to send -> so re-init cmd_info and send the result code to peer */
+		
+		
+		/* Obtain buffer with command translated into data buffer ready for TX*/
+		if(atp_create_data_buffer_from_cmd(TXT_MODE,
+			port_p->port_info[other_sw_nb].no_copy_info.rx_head_size,
+			port_p->port_info[other_sw_nb].no_copy_info.rx_trail_size,
+			port_p->dce_info_p,
+			port_p->port_info[other_sw_nb].rx_mb,
+			found_cmd_type,0,txt_p,NULL,
+			&atp_buffer_p,&length)!=RV_OK)
+		{
+			rvf_free_buf(txt_p);
+			atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_CANNOT_TRANSLATE_CMD,NULL);
+			return RV_NOT_SUPPORTED;
+		}
+		
+		/* Send it to the other SW entity via an ATP_NO_COPY_DATA_RDY */
+		/* Note: it is assumed that only COPY OFF instance can be DCE ON */
+		if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_NO_COPY_DATA_RDY),(void **) &no_copy_data_ready_p)==RVF_RED)
+		{
+			atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_MEMORY_ERROR,NULL);
+			return RV_MEMORY_ERR;
+		}		
+		
+		no_copy_data_ready_p->rv_hdr.msg_id	= ATP_NO_COPY_DATA_RDY;
+		no_copy_data_ready_p->port_nb		= port_p->port_info[other_sw_nb].port_nb;
+		no_copy_data_ready_p->buffer_size	= length-port_p->port_info[other_sw_nb].no_copy_info.rx_head_size
+			-port_p->port_info[other_sw_nb].no_copy_info.rx_trail_size;
+		no_copy_data_ready_p->atp_buffer_p	= atp_buffer_p;
+		
+		
+		/* Re-accept to deal with any new command */
+		if (found_cmd_type == RESULT_CODE)
+		{
+			atp_init_cmd_info_struct(port_p); /* Re-initilalise all the cmd_info structure */
+		}
+		else 
+		{
+			if(found_cmd_type == AT_CMD) 
+			{
+				port_p->cmd_info.state=WAITING_FOR_RESULT;
+			}
+		}		atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *) no_copy_data_ready_p);
+		
+		return RV_OK;				
+	}
+	
+	
+	if(other_sw_entity_p->mode.cmd_mode==INTERPRETED_MODE)
+	{	
+		/* Other SW entity will have command in interpreted format  */
+		if (atp_translate_txt_to_cmd((T_ATP_TXT_CMD) txt_p,cmd_type,&found_cmd_type,
+			&found_cmd_nb,port_p->port_info[other_sw_nb].rx_mb,
+			&cmd_info_p)==RV_OK)
+		{
+			/* The command has been properly translated into command format*/
+			/* Release text buffer */
+			rvf_free_buf(txt_p);
+			
+			/* Send an event to the other sw entity with the command buffer*/	
+			if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_CMD_RDY),(void **) &cmd_ready_event_p)==RVF_RED)
+			{
+				atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_MEMORY_ERROR,NULL);
+				return RV_MEMORY_ERR;
+			}
+			
+			cmd_ready_event_p->rv_hdr.msg_id=ATP_CMD_RDY;	
+			cmd_ready_event_p->cmd_type=found_cmd_type;
+			cmd_ready_event_p->cmd_nb=found_cmd_nb;
+			cmd_ready_event_p->cmd_info_p=cmd_info_p;
+			cmd_ready_event_p->port_nb=port_p->port_info[other_sw_nb].port_nb;
+			
+			/* Re-accept to deal with any new command */
+			if (found_cmd_type == RESULT_CODE) { port_p->cmd_info.state=READY_FOR_NEW_CMD;}
+
+			/* Send the event */
+			atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *) cmd_ready_event_p);			
+			return RV_OK;
+		}
+		/* Otherwise, the text has not been translated properly
+		Forward to the SW entity in text format */
+	}
+	
+	
+	
+	/* Send Command in text format */
+	/* Send an event to the other sw entity with the text buffer*/	
+	if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_TXT_CMD_RDY),(void **) &txt_cmd_ready_event_p)==RVF_RED)
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_MEMORY_ERROR,NULL);
+		return RV_MEMORY_ERR;
+	}
+	
+	txt_cmd_ready_event_p->rv_hdr.msg_id=ATP_TXT_CMD_RDY;	
+	txt_cmd_ready_event_p->cmd_type=cmd_type;
+	txt_cmd_ready_event_p->txt_cmd_p=txt_p;
+	txt_cmd_ready_event_p->port_nb=port_p->port_info[other_sw_nb].port_nb;
+	
+	/* Re-accept to deal with any new command */
+	if ( (cmd_type == RESULT_CODE) ||
+	     (cmd_type == UNKNOWN)) // This case is to deal with the case of TXT SWE 1 sending a result code with cmd_type = UNKNOW
+								// to another TXT SWE  
+	{ port_p->cmd_info.state=READY_FOR_NEW_CMD;}
+
+	/* Send the event */
+	atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *) txt_cmd_ready_event_p);
+			
+	return RV_OK;
+}
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* Function name: atp_send_data
+*
+* Description : Send data on a port
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*
+*					atperror can be called if MB is RED 
+*
+* History		: 0.1 (1-Marsh-2000) - Created
+*				: 0.9  (5-May-2000) - Reviewed
+******************************************************************************/
+T_ATP_RET atp_send_data(T_ATP_SW_ENTITY_ID sender_sw_id, T_ATP_PORT_NB sender_port_nb,
+						void * data_buffer_p, UINT32 buffer_size, UINT32 *nb_bytes_left_p)
+{
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB sender_sw_nb;
+	T_ATP_SW_ENTITY_STRUCT * other_sw_entity_p;
+	UINT32 real_buffer_size;
+	T_ATP_NO_COPY_DATA_RDY *no_copy_data_ready_p;
+	T_ATP_DATA_RDY *data_ready_p;
+	T_ATP_RX_PACKET *rx_packet_p;
+	UINT32 i,offset;
+	T_ATP_BUFFER rvf_buffer_p;
+	T_ATP_PORT_END_STRUCT * other_port_info_p;
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+	(void) sprintf (gbl_debug_message,
+					"ATP: send_data invoked (Size: %d, Port: %d) ",
+					buffer_size,
+					sender_port_nb);
+	rvf_send_trace (gbl_debug_message,
+					(UINT8) strlen (gbl_debug_message),
+					NULL_PARAM,
+					RV_TRACE_LEVEL_DEBUG_MEDIUM,
+					ATP_USE_ID);
+#endif
+
+#ifdef ATP_HEX_DUMP_ENABLED
+	atp_hexdump_buf (data_buffer_p,
+					 buffer_size);
+#endif
+
+	/* Bytes left to be sent: sender should wait and retransmit later on if needed */
+	*nb_bytes_left_p=buffer_size;
+
+	/* Get the pointer on the port structure */
+	if(atp_get_port(sender_sw_id,sender_port_nb,&port_p,&sender_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	
+	if (port_p->port_state == ATP_OPEN_PENDING)
+	{
+		/* Port is not completely open */
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_ISSUED_IN_A_WRONG_STATE_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	/* Get other port */
+	if ((port_p->redirect_mode==ATP_REDIRECT_ON) && 
+		(port_p->port_state==ATP_DATA_MODE)) /* redirection is activated */
+	{
+		other_port_info_p= & (port_p->redirect_port_p->port_info[port_p->redirect_port_end_nb]);
+	}
+	else
+	{
+		other_port_info_p= & (port_p->port_info[(! sender_sw_nb)]);
+	}
+	
+	
+	/* get pointer on the other SW entity data structure in order to get info */
+	other_sw_entity_p=atp_sw_entity_table_p[(* other_port_info_p).sw_id];
+	
+	
+	/* Get a buffer to send or store the data */
+	/* real_buffer_size is the size of the buffer to transmit */
+	if(other_sw_entity_p->mode.cp_mode==COPY_OFF)
+	{	/* In this case, need to eventually add header and trailer sizes*/
+		real_buffer_size=buffer_size+other_port_info_p->no_copy_info.rx_head_size
+			+ other_port_info_p->no_copy_info.rx_trail_size;
+	}
+	else
+	{
+		real_buffer_size=buffer_size;
+	}
+
+	if (rvf_get_buf(other_port_info_p->rx_mb,real_buffer_size,(void **) &rvf_buffer_p)==RVF_RED)
+	{ /* No memory available to store the data */
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+		(void) sprintf (gbl_debug_message,
+						"ATP: send_data. Insufficient memory (Bytes left: %d, Bank: %d) ",
+						*nb_bytes_left_p,
+						other_port_info_p->rx_mb);
+		rvf_send_trace (gbl_debug_message,
+						(UINT8) strlen (gbl_debug_message),
+						NULL_PARAM,
+						RV_TRACE_LEVEL_WARNING,
+						ATP_USE_ID);
+#endif
+		
+		/* Sends a signal to stop the TX FLOW CONTROL of the sender 
+		ie the receiver set its RX_FLOW_CTRL to OFF  */
+		atp_set_signal(other_port_info_p->sw_id,other_port_info_p->port_nb,
+			ATP_RX_FLOW_OFF,ATP_RX_FLOW_UNMASK); 
+		return RV_NOT_SUPPORTED;
+	}
+	
+	
+	/* Copy data into RVF buffer */
+	offset=other_port_info_p->no_copy_info.rx_head_size;
+	for(i=0;i<buffer_size;i++)
+	{
+		rvf_buffer_p[i+offset]=((UINT8 *) data_buffer_p)[i];
+	}
+	
+	
+	switch (other_sw_entity_p->mode.cp_mode)
+	{
+		case COPY_OFF:
+		{	
+			/* Send a ATP_NO_COPY_DATA_RDY event */
+			if (rvf_get_buf(other_port_info_p->rx_mb,sizeof(T_ATP_NO_COPY_DATA_RDY),(void **) &no_copy_data_ready_p)==RVF_RED)
+			{
+#ifdef ATP_DEBUG_MSG_ENABLED
+				(void) sprintf (gbl_debug_message,
+								"ATP: send_data. Insufficient memory (Bytes left: %d, Bank: %d) ",
+								*nb_bytes_left_p,
+								other_port_info_p->rx_mb);
+				rvf_send_trace (gbl_debug_message,
+								(UINT8) strlen (gbl_debug_message),
+								NULL_PARAM,
+								RV_TRACE_LEVEL_WARNING,
+								ATP_USE_ID);
+#endif
+			
+				/* Sends a signal to stop the TX FLOW CONTROL of the sender 
+				ie the receiver set its RX_FLOW_CTRL to OFF  */
+				atp_set_signal(other_port_info_p->sw_id,other_port_info_p->port_nb,
+					ATP_RX_FLOW_OFF,ATP_RX_FLOW_UNMASK); 
+
+				rvf_free_buf (rvf_buffer_p);
+				return RV_NOT_SUPPORTED;
+			}		
+			
+			no_copy_data_ready_p->rv_hdr.msg_id=ATP_NO_COPY_DATA_RDY;
+			no_copy_data_ready_p->port_nb=other_port_info_p->port_nb;
+			no_copy_data_ready_p->buffer_size=buffer_size; /* Indicate only length of payload ! */
+			no_copy_data_ready_p->atp_buffer_p=rvf_buffer_p;
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+			(void) sprintf (gbl_debug_message,
+							"ATP: NO_COPY_DATA_RDY sent (Port: %d, Size: %d) ",
+							no_copy_data_ready_p->port_nb,
+							no_copy_data_ready_p->buffer_size);
+			rvf_send_trace (gbl_debug_message,
+							(UINT8) strlen (gbl_debug_message),
+							NULL_PARAM,
+							RV_TRACE_LEVEL_DEBUG_MEDIUM,
+							ATP_USE_ID);
+#endif
+
+			/* Send the event */
+			atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *) no_copy_data_ready_p);
+			*nb_bytes_left_p=0;
+			return RV_OK;
+		}
+		case COPY_ON:
+		{	
+
+		   /* Queue the packet and send an ATP_DATA_RDY event */		
+		   /* Get enqueue header */
+		   if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_RX_PACKET),(void **) &rx_packet_p)==RVF_RED)
+		   {
+			   rvf_free_buf (rvf_buffer_p);
+			   atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_MEMORY_ERROR,NULL);
+			   return RV_MEMORY_ERR;
+		   }
+		   rx_packet_p->first_byte=0;
+		   rx_packet_p->last_byte=real_buffer_size-1;
+		   rx_packet_p->atp_buffer_p=rvf_buffer_p;
+		   rx_packet_p->next_byte_to_read=rx_packet_p->first_byte;
+
+		   /* Get an ATP_DATA_RDY event */
+		   if (rvf_get_buf(other_port_info_p->rx_mb,sizeof(T_ATP_DATA_RDY),(void **) &data_ready_p)==RVF_RED)
+		   {
+#ifdef ATP_DEBUG_MSG_ENABLED
+				(void) sprintf (gbl_debug_message,
+								"ATP: send_data. Insufficient memory (Bytes left: %d, Bank: %d) ",
+								*nb_bytes_left_p,
+								other_port_info_p->rx_mb);
+				rvf_send_trace (gbl_debug_message,
+								(UINT8) strlen (gbl_debug_message),
+								NULL_PARAM,
+								RV_TRACE_LEVEL_WARNING,
+								ATP_USE_ID);
+#endif
+			
+				/* Sends a signal to stop the TX FLOW CONTROL of the sender 
+				ie the receiver set its RX_FLOW_CTRL to OFF  */
+				atp_set_signal(other_port_info_p->sw_id,other_port_info_p->port_nb,
+					ATP_RX_FLOW_OFF,ATP_RX_FLOW_UNMASK); 
+
+				rvf_free_buf (rx_packet_p);
+				rvf_free_buf (rvf_buffer_p);
+				return RV_NOT_SUPPORTED;
+		   }		
+		   data_ready_p->rv_hdr.msg_id=ATP_DATA_RDY;
+		   data_ready_p->port_nb=other_port_info_p->port_nb;
+		   data_ready_p->nb_bytes=real_buffer_size;
+ 
+		   /* Queue the packet */
+		   rvf_enqueue (&(other_port_info_p->rx_queue), rx_packet_p);
+		   other_port_info_p->rx_data_left += real_buffer_size;
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+			(void) sprintf (gbl_debug_message,
+							"ATP: DATA_RDY sent (Port: %d, Size [Packet]: %d, Left [Overall]: %d) ",
+							data_ready_p->port_nb,
+							data_ready_p->nb_bytes,
+							other_port_info_p->rx_data_left);
+			rvf_send_trace (gbl_debug_message,
+							(UINT8) strlen (gbl_debug_message),
+							NULL_PARAM,
+							RV_TRACE_LEVEL_DEBUG_MEDIUM,
+							ATP_USE_ID);
+#endif
+
+		   /* Send the event */
+		   if (atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *)data_ready_p) != RV_OK)
+		   {
+				atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_PARAM_ERROR,NULL);
+				return RV_INTERNAL_ERR;
+		   }
+		   *nb_bytes_left_p=0;
+		   return RV_OK;
+		}
+		default:
+		{
+			break;
+		}
+	}
+	atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_OTHER_SWE_NOT_IN_PROPER_MODE,NULL);
+	rvf_free_buf (rvf_buffer_p);
+	return RV_NOT_SUPPORTED;
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+* Function name: atp_no_copy_send_data
+*
+* Description : Send data on a port.
+*
+* Parameters :  see BT9901 : 
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*
+*					atp_error can be called if MB is RED 
+*
+* History		: 0.1 (1-Marsh-2000) - Created
+*				: 0.9  (5-May-2000) - Pas au point !!!!!!!
+******************************************************************************/
+T_ATP_RET atp_no_copy_send_data(T_ATP_SW_ENTITY_ID sender_sw_id, T_ATP_PORT_NB sender_port_nb,
+								T_ATP_BUFFER atp_buffer_p, UINT32 payload_size)
+{
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB sender_sw_nb;
+	T_ATP_SW_ENTITY_STRUCT * other_sw_entity_p;
+	T_ATP_NO_COPY_DATA_RDY * no_copy_data_ready_p;
+	T_ATP_DATA_RDY *data_ready_p;
+	T_ATP_RX_PACKET *rx_packet_p;
+	UINT32 rx_head,tx_head,rx_trail,tx_trail,tx_data_size,i,data_length,tx_buffer_size;
+	T_ATP_BUFFER tx_buffer_p;
+	T_ATP_PORT_END_STRUCT * other_port_info_p;
+	T_RVF_MB_STATUS mb_status;
+	UINT8 switch_memory;
+	T_ATP_SW_NB other_sw_nb;
+	T_ATP_ESCAPE_SEQUENCE_STATUS escape_status; // status indicating if the escape sequence has been found in the data flow
+	UINT8 nb_escape_extra_character; // Number of character of the escape sequence which has been already found
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+	(void) sprintf (gbl_debug_message,
+					"ATP: no_copy_send_data invoked (Size: %d, Port: %d) ",
+					payload_size,
+					sender_port_nb);
+	rvf_send_trace (gbl_debug_message,
+					(UINT8) strlen (gbl_debug_message),
+					NULL_PARAM,
+					RV_TRACE_LEVEL_DEBUG_MEDIUM,
+					ATP_USE_ID);
+#endif
+
+	/* Get the pointer on the port structure */
+	if(atp_get_port(sender_sw_id,sender_port_nb,&port_p,&sender_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	other_sw_nb=(T_ATP_SW_NB) (! sender_sw_nb);
+	
+	if (port_p->port_state == ATP_OPEN_PENDING)
+	{
+		/* Port is not completely open */
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_ISSUED_IN_A_WRONG_STATE_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	/* Get other port */
+	if ((port_p->redirect_mode==ATP_REDIRECT_ON) && 
+		(port_p->port_state==ATP_DATA_MODE)) /* redirection is activated */
+	{
+		other_port_info_p= & (port_p->redirect_port_p->port_info[port_p->redirect_port_end_nb]);
+	}
+	else
+	{
+		other_port_info_p= & (port_p->port_info[(! sender_sw_nb)]);
+	}
+	
+	
+	/* get pointer on the other SW entity data structure in order to get info */
+	other_sw_entity_p=atp_sw_entity_table_p[(* other_port_info_p).sw_id];
+	
+	/* Get info on rx and tx value => to make the code more readable */
+	rx_head=other_port_info_p->no_copy_info.rx_head_size;
+	rx_trail=other_port_info_p->no_copy_info.rx_trail_size;
+	tx_head=port_p->port_info[sender_sw_nb].no_copy_info.tx_head_size;
+	tx_trail=port_p->port_info[sender_sw_nb].no_copy_info.tx_trail_size;
+	
+	
+	
+	/* If sender is a transport layer and if ATP needs to emulate DCE or DTE 
+	then interpret the data and send proper command to other SWE */
+	if ((atp_sw_entity_table_p[sender_sw_id]->mode.cmd_support_mode == CMD_SUPPORT_OFF) &&
+		 ( (port_p->port_state!=ATP_DATA_MODE) && (port_p->port_config != DATA_CONFIG)))
+	{ 
+		T_RV_RET return_status;
+		T_ATP_CMD_BUFFER_RDY is_ready;		
+		
+		/* Allocate text buffer */
+		if (rvf_get_buf(other_port_info_p->rx_mb,payload_size+1,(void **) &tx_buffer_p)==RVF_RED)
+		{
+			atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_MEMORY_ERROR,NULL);
+			return RV_MEMORY_ERR;
+		}
+		
+		/* And update txt buffer with the data contained in the received packet */
+		/* Packet in segment mode (cf L2CAP) ? */
+		if (port_p->port_info[sender_sw_nb].no_copy_info.packet_mode==SEGMENTED_PACKET)
+		{
+			tx_data_size=payload_size+1; /* + 1 for 0 at the end */
+			atp_copy_buffer_from_l2cap((void *) atp_buffer_p,(void *) tx_buffer_p,payload_size,0);
+			tx_buffer_p[payload_size]=0; /* End of the String */
+			atp_free_l2cap_buffer((UINT8 *)atp_buffer_p);
+		}
+		else
+		{
+			tx_data_size=payload_size;
+			atp_copy_buffer(&atp_buffer_p[tx_head],tx_buffer_p,(UINT32) tx_data_size);
+			rvf_free_buf(atp_buffer_p); /* Release data buffer : text is now pointed by txt_cmd_p */
+			
+		}
+		
+		/* Command is stored in tx_buffer_p . tx_length (without 0 at end) = payload_size */
+
+		if (port_p->port_config == DCE_CONFIG) // ATP is emulating DCE 
+		{
+			// DCE accept several AT commands to be assembled on the same line 
+			// In case ATP DCE receives new commands where ATP has not finished to provide
+			// all the commands to SWE -> ignore new command
+			if (port_p->cmd_info.status == ON_GOING)
+			{ 
+				ATP_SEND_TRACE ("ATP/DCE : Receives new commands from DTE whereas previous line has not been processed : ignore ",RV_TRACE_LEVEL_WARNING);
+				//				port_p->cmd_info.status = FINISHED;
+				//				if (port_p->cmd_info.cmd_txt_p != NULL)
+				//				{
+				//					rvf_free_buf(port_p->cmd_info.cmd_txt_p);
+				//				}
+				//				port_p->cmd_info.cmd_txt_p=NULL;
+				//				port_p->cmd_info.next_position=ATP_CMD_INVALID_POSITION;
+				//				port_p->cmd_info.cmd_txt_length=0;
+				
+				// SHALL WE SEND A RESULT TO DTE ???????
+				rvf_free_buf((UINT8 *) tx_buffer_p);
+				return RV_OK;
+			}
+			
+			
+			/* Check if mode Echo is ON */
+			/* In case ECHO mode is activated and DCE , re-send the packet to sender */
+			if (port_p->dce_info_p->echo_mode == ECHO_ON)
+			{
+				if (atp_send_data(other_port_info_p->sw_id,other_port_info_p->port_nb,
+					tx_buffer_p,strlen((char *) tx_buffer_p),&data_length) != RV_OK)
+				{
+					ATP_SEND_TRACE ("ATP : Failed to send command back in echo mode",
+						RV_TRACE_LEVEL_ERROR);
+				}
+			}
+		} /* End of if ATP = DCE */
+			
+			
+		/* Update internal cmd buffer: especially, in case cmd is sent character per character */
+		/* In this case, this function gathers the caracter . is_ready = ATP_CMD_BUFFER_IS _RDY	*/
+		/* once a complete command has been received . In this case, the command and related information */
+		/* is available in port_p->cmd_info structure. */
+		return_status = atp_update_cmd_buffer(port_p,tx_buffer_p,(UINT16) payload_size,&is_ready);
+
+		/* Error in the data received. Sends an error to the remote device. */
+		if (return_status != RV_OK)
+		{
+			port_p->cmd_info.status=FINISHED; // will not get any new command
+			atp_send_cmd(port_p->port_info[other_sw_nb].sw_id,port_p->port_info[other_sw_nb].port_nb,
+				RESULT_CODE,ATP_ERROR_NB,NULL);
+			atp_init_cmd_info_struct(port_p);
+			return RV_OK;
+		}
+
+		if (is_ready == ATP_CMD_BUFFER_IS_NOT_RDY)
+		{
+			/* Wait for following characters */
+			return RV_OK;
+		}
+
+
+		/* Let's start to process the command  */
+		return_status = atp_interpret_data(port_p,sender_sw_nb,other_sw_nb); // sender = transport layer , other = appli
+						  
+		if (return_status == RV_MEMORY_ERR)
+		{
+			atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_MEMORY_ERROR,NULL);
+			return RV_MEMORY_ERR;
+		}
+		
+		return RV_OK;		
+	} /* End of DCE Emu part */
+	
+	
+	
+				
+	
+	
+	/* Data copy */
+	/*---------------------------------------------------------------------*/
+	
+	   /* First case: Target needs a copy */
+	   data_length=payload_size; /* Nb of bytes of the real data (not including header...) */
+
+	   /* Check ESCAPE SEQUENCE if DCE mode enabled */
+	   if ( (atp_sw_entity_table_p[sender_sw_id]->mode.cmd_support_mode == CMD_SUPPORT_OFF) &&
+		   (port_p->port_config == DCE_CONFIG))
+	   {
+		   // In this case, need to check escape sequence 
+		   escape_status = atp_escape_sequence_process(port_p,atp_buffer_p,data_length,
+			   port_p->port_info[sender_sw_nb].no_copy_info.packet_mode);
+		   nb_escape_extra_character = port_p->dce_info_p->nb_plus_received; // Number of escape sequence character already received
+
+		   if (escape_status == ATP_ESCAPE_SEQUENCE_SUCCESS)
+		   {
+			   // Escape sequence has been found
+			   ATP_SEND_TRACE ("ATP: An escape sequence has been found. Send CMD_ABORT ",RV_TRACE_LEVEL_DEBUG_LOW);
+			   atp_send_cmd(sender_sw_id,sender_port_nb,CMD_ABORT,0,NULL);
+			   atp_reset_escape_sequence(port_p); // Delete all buffer including current atp_buffer_p 			   
+		   }
+		   if (escape_status != ATP_ESCAPE_SEQUENCE_FAILED)
+		   {
+			   return RV_OK; // If SUCCESS or WAIT, no data need to be forwarded
+		   }
+	   }
+	   else
+	   {
+		   nb_escape_extra_character = 0; 
+	   }
+		   
+
+
+
+	   if(other_sw_entity_p->mode.cp_mode==COPY_ON)
+	   {
+		   /* So Queue the packet and send an ATP_DATA_RDY event */		
+		   /* Get enqueue header */
+		   if (rvf_get_buf(other_port_info_p->rx_mb,sizeof(T_ATP_RX_PACKET),(void **) &rx_packet_p)==RVF_RED)
+		   {
+			   atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_MEMORY_ERROR,NULL);
+				return RV_MEMORY_ERR;
+		   }		
+		   
+		   if (nb_escape_extra_character > 0)
+		   {
+			 atp_pipe_extra_character(port_p,other_port_info_p); // 	send in the pipe the character that has been 
+	
+			 // Reset internal structure but does not release data buffer !
+			 port_p->dce_info_p->nb_plus_received = 0;
+			 for(i=0;i<MAX_NB_OF_CHARACTER_FOR_END_SEQUENCE;i++)
+			 {
+				 port_p->dce_info_p->escape_sequence_tmp_buffer_p[i] = NULL;
+				 port_p->dce_info_p->length_of_escape_sequence_tmp_buffer_p[i] = 0;
+			 }
+		   }
+			   
+		   rx_packet_p->first_byte=tx_head;
+		   rx_packet_p->last_byte=tx_head+payload_size-1;
+		   rx_packet_p->atp_buffer_p=atp_buffer_p;
+		   rx_packet_p->next_byte_to_read=rx_packet_p->first_byte;
+
+		   /* Queue the packet */
+		   rvf_enqueue (&(other_port_info_p->rx_queue), rx_packet_p);
+		   other_port_info_p->rx_data_left+=payload_size;
+		   
+		   /* Get a ATP_DATA_RDY event */
+		   if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_DATA_RDY),(void **) &data_ready_p)==RVF_RED)
+		   {
+			   atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_MEMORY_ERROR,NULL);
+				return RV_MEMORY_ERR;
+		   }		
+		   
+		   data_ready_p->rv_hdr.msg_id=ATP_DATA_RDY;
+		   data_ready_p->port_nb=other_port_info_p->port_nb;
+		   data_ready_p->nb_bytes=payload_size;
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+			(void) sprintf (gbl_debug_message,
+							"ATP: DATA_RDY sent (Port: %d, Size [Packet]: %d, Left [Overall]: %d) ",
+							data_ready_p->port_nb,
+							data_ready_p->nb_bytes,
+							other_port_info_p->rx_data_left);
+			rvf_send_trace (gbl_debug_message,
+							(UINT8) strlen (gbl_debug_message),
+							NULL_PARAM,
+							RV_TRACE_LEVEL_DEBUG_MEDIUM,
+							ATP_USE_ID);
+#endif
+ 
+		   /* Send the event */
+		   if (atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *)data_ready_p) != RV_OK)
+		   {
+				atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_PARAM_ERROR,NULL);
+				return RV_INTERNAL_ERR;
+		   }
+		   return RV_OK;
+	   }
+	   
+	   
+	   
+	   
+	   /* Second case : Target is COPY OFF but packet features are not compatible => needs a copy */
+	   if( (tx_head!=rx_head) || (tx_trail!=rx_trail) ||
+		   ( (port_p->port_info[sender_sw_nb].no_copy_info.packet_mode ==  SEGMENTED_PACKET) &&
+		   (other_port_info_p->no_copy_info.packet_mode !=  SEGMENTED_PACKET) )  ) 
+	   {		
+		   tx_data_size=payload_size+nb_escape_extra_character;
+		   tx_buffer_size=tx_data_size+rx_head+rx_trail;
+		   
+		   
+		   /* Data will be copied into a buffer which will be forwarded to upper layers  */
+		   /* Get this buffer from the port MB. If not enough memory available then use 
+		   ATP_MB, make the copy , release the initial buffer and try to re-switch the buffer
+		   into the port MB (use of swicth_memory for that purpose */
+		   
+		   switch_memory=0; /* Ie no needs to switch from ATP_MB to port MB */
+		   mb_status=rvf_get_buf(other_port_info_p->rx_mb,tx_buffer_size,(void **) &tx_buffer_p);
+		   if (mb_status==RVF_RED)
+		   {
+			   /* Then use own atp_prim MB.... for temporary work ! */
+			   mb_status=rvf_get_buf(atp_mb_prim,tx_buffer_size,(void **) &tx_buffer_p);
+			   switch_memory=1; /* Switch is needed */
+			   if (mb_status==RVF_YELLOW)
+			   {
+				   /* Then , sender should definitely stop to send data !!!  */
+				   atp_set_signal(other_port_info_p->sw_id,other_port_info_p->port_nb,
+					   ATP_TX_FLOW_OFF,ATP_TX_FLOW_UNMASK);
+			   }
+			   
+			   if (mb_status==RVF_RED)
+			   {
+				   /* Even no memory enough in atp_mb_prim -> big problem */
+				   rvf_send_trace("ATP : not enough memeory for temporary copy from COPY_OFF to COPY OFF SWEs (atp_no_copy_send_data ft)  ",
+					   103,
+					   NULL_PARAM,
+					   RV_TRACE_LEVEL_ERROR,
+					   ATP_USE_ID);
+				   
+				   atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_MEMORY_ERROR,NULL);
+				   return RV_MEMORY_ERR;
+				   
+			   }
+			   
+		   }
+		   
+		   if (nb_escape_extra_character>0)
+		   {
+			   // Add character that has been removed due to escape sequence scanning
+			   memcpy(&tx_buffer_p[rx_head],port_p->dce_info_p->escape_sequence,
+				   nb_escape_extra_character);
+			   atp_reset_escape_sequence(port_p);  
+		   }
+		   
+		   if (port_p->port_info[sender_sw_nb].no_copy_info.packet_mode==NORMAL_PACKET)
+		   {   /* Packet is not a L2CAP segmented packet */
+			   atp_copy_buffer(&atp_buffer_p[tx_head],&tx_buffer_p[rx_head+nb_escape_extra_character]
+				   ,(tx_data_size-nb_escape_extra_character));
+			   rvf_free_buf(atp_buffer_p);
+			   
+		   }
+		   else
+		   {	/* Sender Packet was in segmented */
+			   atp_copy_buffer_from_l2cap((void *)atp_buffer_p,(void *) &tx_buffer_p[rx_head+nb_escape_extra_character],
+				   (UINT32)(tx_data_size-nb_escape_extra_character),0);
+			   atp_free_l2cap_buffer( (UINT8 *)atp_buffer_p);
+			   
+		   }
+		   
+		   /* Copy dummy byte */
+		   for(i=0;i<rx_head;i++)
+		   {
+			   tx_buffer_p[i]=0x00;
+		   }
+		   
+		   for(i=tx_data_size+rx_head;i<tx_buffer_size;i++)
+		   {
+			   tx_buffer_p[i]=0x00;
+		   }
+		   
+		   /* Release previous buffer */
+		   atp_buffer_p=tx_buffer_p; /* Update to send the data */
+		   data_length=tx_data_size;	
+		   
+		   /* And switch to port MB if possible */
+		   if (switch_memory==1)
+		   {
+			   rvf_count_buf(other_port_info_p->rx_mb,tx_buffer_p);
+		   }
+		   
+		   
+	   }
+	   else
+	   {
+		   /* else => a single forward is possible if same packet requirements (RVF/header/trailer/packet mode)*/
+
+		   if (nb_escape_extra_character>0)
+		   {
+			   // Send characters that has been removed due to escape sequence scanning
+			   UINT8 * buffer_p;
+			   
+			   if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_NO_COPY_DATA_RDY),(void **) &no_copy_data_ready_p)==RVF_RED)
+			   {
+				   atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_MEMORY_ERROR,NULL);
+				   return RV_MEMORY_ERR;
+			   }		
+			   if (rvf_get_buf(atp_mb_prim,nb_escape_extra_character,(void **) &buffer_p)==RVF_RED)
+			   {
+				   rvf_free_buf (no_copy_data_ready_p);
+				   atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_MEMORY_ERROR,NULL);
+				   return RV_MEMORY_ERR;
+			   }
+			   // Copy data into the buffer
+			   memcpy(buffer_p,port_p->dce_info_p->escape_sequence,nb_escape_extra_character);
+			   
+			   // And send
+			   no_copy_data_ready_p->rv_hdr.msg_id=ATP_NO_COPY_DATA_RDY;
+			   no_copy_data_ready_p->port_nb=other_port_info_p->port_nb;
+			   no_copy_data_ready_p->buffer_size=nb_escape_extra_character;
+			   no_copy_data_ready_p->atp_buffer_p=buffer_p;
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+				(void) sprintf (gbl_debug_message,
+								"ATP: NO_COPY_DATA_RDY sent (Port: %d, Size: %d) ",
+								no_copy_data_ready_p->port_nb,
+								no_copy_data_ready_p->buffer_size);
+				rvf_send_trace (gbl_debug_message,
+								(UINT8) strlen (gbl_debug_message),
+								NULL_PARAM,
+								RV_TRACE_LEVEL_DEBUG_MEDIUM,
+								ATP_USE_ID);
+#endif
+
+			   /* Send the event */
+			   atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *) no_copy_data_ready_p);
+			   
+			   // Reset temporary data used by the escape sequence algo
+			   atp_reset_escape_sequence(port_p);  
+		   }
+	   }
+
+
+
+
+	   /* Send a ATP_NO_COPY_DATA_RDY event with the data*/
+	   if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_NO_COPY_DATA_RDY),(void **) &no_copy_data_ready_p)==RVF_RED)
+	   {
+		   atp_error_switch(ATP_ERROR_FAILED_TO_SEND_DATA,ATP_MEMORY_ERROR,NULL);
+		   return RV_MEMORY_ERR;
+	   }		
+	   
+	   no_copy_data_ready_p->rv_hdr.msg_id=ATP_NO_COPY_DATA_RDY;
+	   no_copy_data_ready_p->port_nb=other_port_info_p->port_nb;
+	   no_copy_data_ready_p->buffer_size=data_length;
+	   no_copy_data_ready_p->atp_buffer_p=atp_buffer_p;
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+		(void) sprintf (gbl_debug_message,
+						"ATP: NO_COPY_DATA_RDY sent (Port: %d, Size: %d) ",
+						no_copy_data_ready_p->port_nb,
+						no_copy_data_ready_p->buffer_size);
+		rvf_send_trace (gbl_debug_message,
+						(UINT8) strlen (gbl_debug_message),
+						NULL_PARAM,
+						RV_TRACE_LEVEL_DEBUG_MEDIUM,
+						ATP_USE_ID);
+#endif
+	   
+	   /* Send the event */
+	   atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *) no_copy_data_ready_p);
+	   return RV_OK;			
+}
+
+
+
+
+/******************************************************************************
+* Function name: atp_get_data
+*
+* Description : Copy data in the SW entity buffer
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*
+*					atp_error can be called if MB is RED 
+*
+* History		: 0.1 (1-Marsh-2000) - Created
+*				: 0.9  (5-May-2000) - Added L2CAP packet support from sender
+******************************************************************************/
+T_ATP_RET atp_get_data(T_ATP_SW_ENTITY_ID receiver_sw_id, T_ATP_PORT_NB receiver_port_nb,
+					   UINT8 * data_buffer, UINT32 nb_to_read, UINT32 *nb_read_p, 
+					   UINT32 *nb_left_p)
+{
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB receiver_sw_nb;
+	T_ATP_RX_PACKET *rx_packet_p;
+	UINT32 start_index,nb_to_copy;
+    T_ATP_PACKET_MODE packet_mode;
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+	(void) sprintf (gbl_debug_message,
+					"ATP: get_data invoked (Size: %d, Port: %d) ",
+					nb_to_read,
+					receiver_port_nb);
+	rvf_send_trace (gbl_debug_message,
+					(UINT8) strlen (gbl_debug_message),
+					NULL_PARAM,
+					RV_TRACE_LEVEL_DEBUG_MEDIUM,
+					ATP_USE_ID);
+#endif
+
+	/* Get the pointer on the port structure */
+	if(atp_get_port(receiver_sw_id,receiver_port_nb,&port_p,&receiver_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_GET_DATA,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	
+	if (port_p->port_state == ATP_OPEN_PENDING)
+	{
+		/* Port is not completely open */
+		atp_error_switch(ATP_ERROR_FAILED_TO_GET_DATA,ATP_ISSUED_IN_A_WRONG_STATE_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	/* Get information on the format of the data to copy */
+	if ((port_p->redirect_mode==ATP_REDIRECT_ON) && 
+		(port_p->port_state==ATP_DATA_MODE)) /* redirection is activated */
+	{
+		packet_mode= port_p->redirect_port_p->port_info[port_p->redirect_port_end_nb].no_copy_info.packet_mode;
+	}
+	else
+	{
+		packet_mode=port_p->port_info[(! receiver_sw_nb)].no_copy_info.packet_mode; /* packet mode of the sender */
+	}
+	*nb_read_p=0; // No data has been copied yet 
+
+	/* Check number of data available */
+	if ((port_p->port_info[receiver_sw_nb].rx_data_left == 0) || \
+		(RVF_IS_QUEUE_EMPTY((port_p->port_info[receiver_sw_nb].rx_queue))))
+	{   /* No pending packet are available in the RX queue */
+		*nb_left_p=0;
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+	(void) sprintf (gbl_debug_message,
+					"ATP: get_data (Read: %d, Left [Packet]: %d, Left [Overall]: %d) ",
+					*nb_read_p,
+					*nb_left_p,
+					port_p->port_info[receiver_sw_nb].rx_data_left);
+	rvf_send_trace (gbl_debug_message,
+					(UINT8) strlen (gbl_debug_message),
+					NULL_PARAM,
+					RV_TRACE_LEVEL_DEBUG_MEDIUM,
+					ATP_USE_ID);
+#endif
+		return RV_OK;
+	}
+
+	// TO UPDATE IN ORDER TO COPE WITH L2CAP PACKETS !!!!!
+	rx_packet_p=(T_ATP_RX_PACKET *) rvf_dequeue (&(port_p->port_info[receiver_sw_nb].rx_queue));
+	start_index=rx_packet_p->next_byte_to_read; /* Next byte can start at [0] */
+	nb_to_copy=Min(rx_packet_p->last_byte-start_index+1,nb_to_read); /* Number of byte from this packet to copy */
+
+	if (packet_mode==NORMAL_PACKET)
+	{ /* Stored Data is in a single buffer */
+		atp_copy_buffer(&(rx_packet_p->atp_buffer_p[start_index]),&(data_buffer[*nb_read_p]),nb_to_copy);
+	}
+	else
+	{
+		atp_copy_buffer_from_l2cap(rx_packet_p->atp_buffer_p,&data_buffer[*nb_read_p],nb_to_copy,start_index);
+	}
+			
+	/* Update counters */
+	port_p->port_info[receiver_sw_nb].rx_data_left-=nb_to_copy;	/* Overall number of bytes */
+																/* left to be read */
+	rx_packet_p->next_byte_to_read=rx_packet_p->next_byte_to_read+nb_to_copy;
+
+	*nb_read_p=nb_to_copy; /* Number of byte read */
+	*nb_left_p=rx_packet_p->last_byte+1-rx_packet_p->next_byte_to_read;	/* Number of bytes left */
+																		/* to be read */
+
+#ifdef ATP_DEBUG_MSG_ENABLED
+	(void) sprintf (gbl_debug_message,
+					"ATP: get_data (Read: %d, Left [Packet]: %d, Left [Overall]: %d) ",
+					*nb_read_p,
+					*nb_left_p,
+					port_p->port_info[receiver_sw_nb].rx_data_left);
+	rvf_send_trace (gbl_debug_message,
+					(UINT8) strlen (gbl_debug_message),
+					NULL_PARAM,
+					RV_TRACE_LEVEL_DEBUG_MEDIUM,
+					ATP_USE_ID);
+#endif
+
+	if (*nb_left_p < 1)
+	{
+		/* Buffer has been entirely copied : free buffer */
+		if (packet_mode==NORMAL_PACKET)
+		{
+			rvf_free_buf(rx_packet_p->atp_buffer_p);
+		}
+		else
+		{
+			atp_free_l2cap_buffer ((UINT8 *) rx_packet_p->atp_buffer_p);
+		}
+		rvf_free_buf(rx_packet_p);
+		return RV_OK;
+	}
+
+	/* In this case, still some data need to be read from the RX packet */
+	/* Re-enqueue the buffer and go out of the while  loop */
+	rvf_enqueue_head(&(port_p->port_info[receiver_sw_nb].rx_queue),rx_packet_p);
+	return RV_OK;
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+* Function name: atp_set_mode
+*
+* Description : Change the mode of the port
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*
+*					atp_error can be called if MB is RED 
+*
+* History		: 0.1 (09-May-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_set_mode(T_ATP_SW_ENTITY_ID sender_sw_id, T_ATP_PORT_NB sender_port_nb,
+					   T_ATP_PORT_MODE mode)
+{
+	
+	
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB sender_sw_nb, other_sw_nb;
+	T_ATP_SW_ENTITY_STRUCT * other_sw_entity_p;
+	T_ATP_PORT_MODE_CHANGED * mode_changed_p;
+	
+	
+	/* Get the pointer on the port structure */
+	if(atp_get_port(sender_sw_id,sender_port_nb,&port_p,&sender_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_HANDLE_MODE,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	other_sw_nb=(T_ATP_SW_NB) (! sender_sw_nb);
+	
+	if (port_p->port_state == ATP_OPEN_PENDING)
+	{
+		/* Port is not completely open */
+		atp_error_switch(ATP_ERROR_FAILED_TO_HANDLE_MODE,ATP_ISSUED_IN_A_WRONG_STATE_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	/* get pointer on the other SW entity data structure in order to get info */
+	other_sw_entity_p=atp_sw_entity_table_p[port_p->port_info[other_sw_nb].sw_id];
+	
+	
+	/* Change the mode of the port */
+	if (mode==ATP_PORT_DATA_MODE)
+	{
+		port_p->port_state=ATP_DATA_MODE;
+	}
+	else
+	{
+		port_p->port_state=ATP_CMD_MODE;
+		// And reset the cmd_info field
+		atp_init_cmd_info_struct(port_p);		
+	}
+	
+	
+	
+	/* And send an event to the other SW entity if the other is not a TL ie does not support commands  
+	(otherwise, mode switch is completely transmparent ...*/
+	if (other_sw_entity_p->mode.cmd_support_mode != CMD_SUPPORT_OFF)
+	{
+		if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_PORT_MODE_CHANGED),(void **) &mode_changed_p)==RVF_RED)
+		{
+			atp_error(ATP_ERROR_MB_PRIM_RED);
+			return (RV_MEMORY_ERR);
+		}		
+		
+		mode_changed_p->rv_hdr.msg_id=ATP_PORT_MODE_CHANGED;
+		mode_changed_p->port_nb=port_p->port_info[other_sw_nb].port_nb;
+		mode_changed_p->mode=mode;
+		
+		
+		/* Send the event */
+		atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *)mode_changed_p);
+	}
+	else
+	{
+		// Other SWE does not support command : So, is a DCE ?
+		if (port_p->port_config == DCE_CONFIG)
+		{
+			// Reset fields used by the escape sequence algorithm 
+			atp_reset_escape_sequence(port_p);
+		}
+	}
+	
+	return RV_OK;
+}
+
+/******************************************************************************
+* Function name: atp_set_signal
+*
+* Description : Set signal value of the port
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*
+*					atp_error can be called if MB is RED 
+*
+* History		: 0.1 (1-Marsh-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_set_signal(T_ATP_SW_ENTITY_ID sender_sw_id, T_ATP_PORT_NB sender_port_nb,
+						 T_ATP_PORT_SIGNAL set_signal, T_ATP_SIGNAL_CHANGE_MASK set_mask)
+{
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB sender_sw_nb, other_sw_nb;
+	T_ATP_SW_ENTITY_STRUCT * other_sw_entity_p;
+	UINT8  signal_changed;
+	T_ATP_SIGNAL_CHANGED *  signal_changed_p;
+	T_ATP_PORT_SIGNAL sender_signal,other_signal,set_signal_value;
+	T_ATP_SIGNAL_CHANGE_MASK get_mask,new_mask; /* Mask on the signal changed for the other SW entity */
+	T_ATP_PORT_END_STRUCT * other_port_info_p;
+	BOOLEAN  wait_for_mb_callback;
+
+	/* Get the pointer on the port structure */
+	if(atp_get_port(sender_sw_id,sender_port_nb,&port_p,&sender_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_HANDLE_SIGNAL,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+
+	/* Get pointer on the other SW entity data structure in order to get info */
+	/* Get other port taking care on redirection*/
+	if ((port_p->redirect_mode==ATP_REDIRECT_ON) && 
+		(port_p->port_state==ATP_DATA_MODE)) /* redirection is activated */
+	{
+		other_port_info_p= & (port_p->redirect_port_p->port_info[port_p->redirect_port_end_nb]);
+		other_sw_nb=(T_ATP_SW_NB) (port_p->redirect_port_end_nb);
+	}
+	else
+	{
+		other_port_info_p= & (port_p->port_info[(! sender_sw_nb)]);
+		other_sw_nb=(T_ATP_SW_NB) (! sender_sw_nb);
+	}
+
+	/* Get pointer on the other SW entity data structure in order to get info */
+	other_sw_entity_p=atp_sw_entity_table_p[(* other_port_info_p).sw_id];
+
+	if (port_p->port_state == ATP_OPEN_PENDING)
+	{
+		/* Port is not completely open */
+		atp_error_switch(ATP_ERROR_FAILED_TO_HANDLE_SIGNAL,ATP_ISSUED_IN_A_WRONG_STATE_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	sender_signal=port_p->port_info[sender_sw_nb].signal;
+	other_signal=other_port_info_p->signal;
+	
+	get_mask=0;
+	wait_for_mb_callback=FALSE;
+	
+	/* Set RX flow control signal ? */
+	if ((set_mask & ATP_RX_FLOW_UNMASK)!=0) /* Sender wants to set its RX flow */
+	{	/* Get sender RX bit value */
+		set_signal_value = (T_ATP_SIGNAL_MASK)( set_signal &  ATP_RX_FLOW_UNMASK );
+
+		/* set_signal = ATP_RX_FLOW_ON or ATP_RX_FLOW_OFF */
+		if (set_signal_value == ATP_RX_FLOW_ON)
+		{	/* Caller wants to set ATP_RX_FLOW_CTRL */
+			/* Set it into sender signal status and set TX_FLOW_ON on the other port */
+			sender_signal |= ATP_RX_FLOW_ON;
+			rvf_send_trace ("ATP: RX FLOW set to ON. Port ",
+							29,
+							sender_port_nb,
+							RV_TRACE_LEVEL_DEBUG_LOW,
+							ATP_USE_ID);
+			if (( other_signal & ATP_TX_FLOW_UNMASK) == ATP_TX_FLOW_OFF) 
+			{  /* TX_FLOW_CTRL was OFF for the other entity : set it */
+				other_signal |= ATP_TX_FLOW_ON;
+
+				/* A signal will be generated even if it has been issue earlier */
+				get_mask |= ATP_TX_FLOW_UNMASK;
+			}
+		}
+		else
+		{	/* Caller wants to clear ATP_RX_FLOW_CTRL => RX_FLOW = OFF */
+			/* Clear RX bit on the sender */
+			sender_signal &= (~ ATP_RX_FLOW_UNMASK);
+			rvf_send_trace ("ATP: RX FLOW set to OFF. Port ",
+							30,
+							sender_port_nb,
+							RV_TRACE_LEVEL_DEBUG_LOW,
+							ATP_USE_ID);
+			wait_for_mb_callback = TRUE;
+
+			/* Other TX bit value = OFF */
+			if (( other_signal & ATP_TX_FLOW_UNMASK) == ATP_TX_FLOW_ON)
+			{	/* TX_FLOW_CTRL was ON for the other entity : clear it */
+				other_signal &= (~ ATP_TX_FLOW_UNMASK);
+
+				/* A signal will be generated even if it has been issue earlier */
+				get_mask |= ATP_TX_FLOW_UNMASK; 
+			}
+		}
+	}
+
+	/* Set TX flow control signal ? */
+	if ((set_mask & ATP_TX_FLOW_UNMASK)!=0) /* Sender wants to set the TX flow */
+	{	/* Get sender TX bit value */
+		set_signal_value = (T_ATP_SIGNAL_MASK) (set_signal &  ATP_TX_FLOW_UNMASK);
+
+		/* set_signal = ATP_TX_FLOW_ON or ATP_TX_FLOW_OFF */
+		if (set_signal_value == ATP_TX_FLOW_ON)
+		{	/* Caller wants to set ATP_TX_FLOW_CTRL */
+			/* Set it into sender signal status and set RX_FLOW_ON on the other port */
+			sender_signal |= ATP_TX_FLOW_ON;
+			rvf_send_trace ("ATP: TX FLOW set to ON. Port ",
+							29,
+							sender_port_nb,
+							RV_TRACE_LEVEL_DEBUG_LOW,
+							ATP_USE_ID);
+			if (( other_signal & ATP_RX_FLOW_UNMASK) == ATP_RX_FLOW_OFF) 
+			{  /* RX_FLOW_CTRL was OFF for the other entity : set it */
+				other_signal |= ATP_RX_FLOW_ON;
+				get_mask |= ATP_RX_FLOW_UNMASK;
+			}
+		}
+		else
+		{	/* Caller wants to clear ATP_TX_FLOW_CTRL */
+			/* Clear TX bit on the sender */
+			sender_signal &= (~ ATP_TX_FLOW_UNMASK);
+			rvf_send_trace ("ATP: TX FLOW set to OFF. Port ",
+							30,
+							sender_port_nb,
+							RV_TRACE_LEVEL_DEBUG_LOW,
+							ATP_USE_ID);
+
+			/* Other TX bit value = OFF */
+			if (( other_signal & ATP_RX_FLOW_UNMASK) == ATP_RX_FLOW_ON)
+			{  /* RX_FLOW_CTRL was ON for the other entity : clear it*/
+				other_signal &= (~ ATP_RX_FLOW_UNMASK);
+				get_mask |= ATP_RX_FLOW_UNMASK;
+			}
+		}
+	}
+
+	/* Set other signals */
+	/* Other signals to handle */
+	new_mask= (T_ATP_SIGNAL_MASK) (set_mask & ATP_NON_RX_TX_SIGNAL_UNMASK);
+
+	/* Take only the good signals */
+	signal_changed= (T_ATP_SIGNAL_MASK) (set_signal & new_mask);
+	
+	port_p->port_info->signal= (T_ATP_SIGNAL_MASK) ((sender_signal & (~ new_mask)) | signal_changed);
+	other_port_info_p->signal = (T_ATP_SIGNAL_MASK) ((other_signal & (~ new_mask)) | signal_changed);
+	get_mask |= new_mask;
+
+	/* Set the callback function to send signal TX_ON later on */
+	if (wait_for_mb_callback)
+	{
+
+		/* Getting the sendee. */
+		port_p->port_waiting_for_mb_callback = sender_sw_nb;
+		if (rvf_set_callback_func(port_p->port_info[sender_sw_nb].rx_mb,atp_mb_call_back))
+		{
+			rvf_change_callback_func( (T_RVF_MB_ID) (port_p->port_info[sender_sw_nb].rx_mb),atp_mb_call_back);
+		}
+	}
+	if (get_mask !=0)
+	{	/* Send a ATP_SIGNAL_CHANGED event */
+		if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_SIGNAL_CHANGED),(void **) &signal_changed_p)==RVF_RED)
+		{
+			atp_error(ATP_ERROR_MB_PRIM_RED);
+			return (RV_MEMORY_ERR);
+		}		
+		
+		signal_changed_p->rv_hdr.msg_id=ATP_SIGNAL_CHANGED;
+		signal_changed_p->mask=get_mask;
+		signal_changed_p->port_nb=other_port_info_p->port_nb;
+		signal_changed_p->signal=other_port_info_p->signal;
+		signal_changed_p->mb=other_port_info_p->tx_mb;
+
+		/* Send the event */
+		atp_send_message(other_sw_entity_p->return_path,(T_ATP_MESSAGE *)signal_changed_p);
+	}
+	return RV_OK;	
+}
+
+
+
+
+/******************************************************************************
+* Function name: atp_get_signal
+*
+* Description : Get signal value of the port
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*
+*					atp_error can be called if MB is RED 
+*
+* History		: 0.1 (1-Marsh-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_get_signal(T_ATP_SW_ENTITY_ID sw_id, T_ATP_PORT_NB port_nb,
+						 T_ATP_PORT_SIGNAL * signal_p)
+{
+	
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB sw_nb;
+	
+	/* Get the pointer on the port structure */
+	if(atp_get_port(sw_id,port_nb,&port_p,&sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_HANDLE_SIGNAL,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	
+	if (port_p->port_state == ATP_OPEN_PENDING)
+	{
+		/* Port is not completely open */
+		atp_error_switch(ATP_ERROR_FAILED_TO_HANDLE_SIGNAL,ATP_ISSUED_IN_A_WRONG_STATE_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	*signal_p=port_p->port_info[sw_nb].signal;
+	
+	return RV_OK;	
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+* Function name: atp_flow_redirect
+*
+* Description : Redirect the flow from one port to another one
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*
+*					atp_error can be called if MB is RED 
+*
+* History		: 0.1 (22-May-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_flow_redirect(T_ATP_SW_ENTITY_ID sw_id, T_ATP_PORT_NB port_nb_1,
+							T_ATP_PORT_NB port_nb_2, T_ATP_REDIRECT_MODE redirect_mode)
+{
+	
+	T_ATP_SW_NB sw_nb_1,sw_nb_2,other_sw_nb_1,other_sw_nb_2;
+	T_ATP_PORT_STRUCT *port_1_p,*port_2_p;
+	
+	
+	
+	/* Find port information */
+	
+	/* Get the pointer on the port structure related to the port number 1 */
+	if(atp_get_port(sw_id,port_nb_1,&port_1_p,&sw_nb_1) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_HANDLE_FLOW_REDIRECTION,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	other_sw_nb_1=(T_ATP_SW_NB) (! sw_nb_1);
+	
+	/* Get the pointer on the port structure related to the port number 2 */
+	if(atp_get_port(sw_id,port_nb_2,&port_2_p,&sw_nb_2) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_HANDLE_FLOW_REDIRECTION,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	other_sw_nb_2=(T_ATP_SW_NB) (! sw_nb_2);
+	
+	
+	// START SEMAPHORE 
+	if (redirect_mode == ATP_REDIRECT_ON)
+	{
+		port_1_p->redirect_mode=ATP_REDIRECT_ON;
+		port_2_p->redirect_mode=ATP_REDIRECT_ON;
+		
+		port_1_p->redirect_port_p=port_2_p;
+		port_2_p->redirect_port_p=port_1_p;
+		
+		port_1_p->redirect_port_end_nb=other_sw_nb_2;
+		port_2_p->redirect_port_end_nb=other_sw_nb_1;
+		
+		// END SEMAPHORE 
+		
+		return RV_OK;
+	}
+	
+	
+	/* Else, pass from REDIRECT_ON to REDIRECT_OFF */
+	port_1_p->redirect_mode=ATP_REDIRECT_OFF;
+	port_2_p->redirect_mode=ATP_REDIRECT_OFF;
+	
+	port_1_p->redirect_port_p=NULL;
+	port_2_p->redirect_port_p=NULL;
+	
+	port_1_p->redirect_port_end_nb=0;
+	port_2_p->redirect_port_end_nb=0;
+	
+	
+	// END SEMAPHORE 
+	
+	return RV_OK;
+}
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* Function name: atp_free_message
+*
+* Description : Generic function service provided to SW entity to free an ATP buffer
+*
+* Parameters :  pointer on the buffer
+*
+* Return     :   return of the rvf_free_buf function
+*
+* History			: 0.1 (1-Marsh-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_free_message(void * buffer_p)
+
+{
+	return rvf_free_buf(buffer_p);
+}
+
+
+
+/******************************************************************************
+* Function name: atp_free_buffer
+*
+* Description : Generic function service provided to SW entity to free an ATP buffer
+*
+* Parameters :  pointer on the buffer
+*
+* Return     :   return of the rvf_free_buf function
+*
+* History			: 0.1 (1-Marsh-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_free_buffer(void * buffer_p)
+
+{
+	if (buffer_p != NULL)
+	{
+		return rvf_free_buf(buffer_p);
+	}
+	return RV_OK;
+}
+
+
+
+/******************************************************************************
+* Function name: atp_get_buffer
+*
+* Description : Generic function service provided to SW entity to free an ATP buffer
+*
+* Parameters :  pointer on the buffer
+*
+* Return     :   return of the rvf_free_buf function
+*
+* History			: 0.1 (1-Marsh-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_get_buffer(UINT32 buffer_size,void ** buffer_pp)
+
+{
+	if ( rvf_get_buf(atp_mb_prim,buffer_size,(void **) buffer_pp) == RVF_RED)
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_GET_MEMORY,ATP_MEMORY_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	return RV_OK;
+}
+
+
+/******************************************************************************
+* Function name: atp_get_buffer_from_tx_mb
+*
+* Description : Function used to get memory from the tx memory bank of the SWE
+*
+* Parameters :  
+*
+* Return     :   return of the rvf_free_buf function
+*
+* History			: 0.1 (1-Marsh-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_get_buffer_from_tx_mb(T_ATP_SW_ENTITY_ID sender_sw_id,T_ATP_PORT_NB sender_port_nb,
+									UINT32 buffer_size,void ** buffer_pp)
+
+{
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB sender_sw_nb;
+	T_ATP_PORT_END_STRUCT * other_port_info_p;
+	
+	/* Get the pointer on the port structure */
+	if(atp_get_port(sender_sw_id,sender_port_nb,&port_p,&sender_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_GET_MEMORY,ATP_MEMORY_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	other_port_info_p= & (port_p->port_info[(! sender_sw_nb)]);
+
+	if ( rvf_get_buf(port_p->port_info[sender_sw_nb].tx_mb,buffer_size,buffer_pp)
+		== RVF_RED)
+	{		
+		/* Sends a signal to stop the TX FLOW CONTROL of the sender 
+		ie the receiver set its RX_FLOW_CTRL to OFF  */
+		atp_set_signal(other_port_info_p->sw_id,other_port_info_p->port_nb,
+			ATP_RX_FLOW_OFF,ATP_RX_FLOW_UNMASK); 
+		return RV_NOT_SUPPORTED;
+	}
+	return RV_OK;
+}
+
+
+/******************************************************************************
+* Function name: atp_update_cmd_buffer
+* Description : This function gathers data used to transmit buffer into
+*				the port internal buffer before sending it to interpretation.
+*				Especially usefull for character per character AT command 
+*				transmission
+*
+* Parameters :	is_ready indicates if the txt_buffer is ready for interpretation  
+* Return     :   return RV_OK if 
+*				 or RV_MEMORY_ERR
+*
+* History			: 0.1 (8-Nov-2000) - Created - Eric
+*
+******************************************************************************/
+T_ATP_RET atp_update_cmd_buffer(T_ATP_PORT_STRUCT	* port_p,
+								UINT8 * new_txt_cmd_buffer_p, UINT16 txt_cmd_buffer_length,
+								T_ATP_CMD_BUFFER_RDY * is_ready_p)
+{
+	UINT16 i,j;
+	UINT8 position;		
+	
+	
+	/* Check if a full command is available in the new buffer */
+	*is_ready_p = ATP_CMD_BUFFER_IS_NOT_RDY;
+	for(i=0;i<txt_cmd_buffer_length;i++)
+	{
+		
+		/* Is there a CR characrter ??*/
+		if (new_txt_cmd_buffer_p[i] == port_p->dce_info_p->cr_character)  // cr character has been found in the txt command
+		{
+			if ( (i != 0 ) || (port_p->cmd_info.next_position != 0) ) // and cr is not the first character of the command line
+			{
+				*is_ready_p = ATP_CMD_BUFFER_IS_RDY; // OK for interpretation
+				break;
+			}
+			
+		}
+	}
+	
+	
+	/* Check that buffer is not only <lf> with no previously sent character */
+	j=0;
+	if ( (new_txt_cmd_buffer_p[0] == port_p->dce_info_p->lf_character) &&
+		(port_p->cmd_info.next_position == 0))
+	{
+		j=1; // skip lf if it is the first caracter of a chain ie the last...
+	}
+	
+	/* Process data  */
+	if ((txt_cmd_buffer_length - j ) > 0) // there is something to copy
+	{
+		/* if buffer does not exist, create it */
+		if (port_p->cmd_info.cmd_txt_p == NULL)
+		{
+			if ( rvf_get_buf(atp_mb_prim,ATP_MAX_CMD_LENGTH,(void **) &port_p->cmd_info.cmd_txt_p) == RVF_RED)
+			{
+				atp_error_switch(ATP_ERROR_FAILED_TO_ACCEPT_A_PORT,ATP_MEMORY_ERROR,NULL);
+				return RV_MEMORY_ERR;
+			}
+		}
+		
+		/* Copy buffer */
+		position = 	(UINT8) port_p->cmd_info.next_position; // is next position to write on
+		
+		for(i=j;i<txt_cmd_buffer_length;i++)
+		{
+			if ( (new_txt_cmd_buffer_p[i] == 	port_p->dce_info_p->bs_character) && // Back space character 
+				 (port_p->port_config == DCE_CONFIG)) // And ATP emulates a DCE 
+			{
+				/* A backspace character has been sent */
+				if (position > 0)
+				{
+					position--;
+					port_p->cmd_info.cmd_txt_p[position] = 	' ';
+				}
+				
+			}
+			else
+			{
+				port_p->cmd_info.cmd_txt_p[position] = 	new_txt_cmd_buffer_p[i];		
+				if (++position == ATP_MAX_CMD_LENGTH)
+				{
+					ATP_SEND_TRACE ("ATP : The command received by ATP is too long versus ATP buffer length",RV_TRACE_LEVEL_WARNING);
+					return RV_NOT_SUPPORTED;
+				}
+			}
+		}
+		
+		if (*is_ready_p == ATP_CMD_BUFFER_IS_RDY)
+		{
+			
+			port_p->cmd_info.cmd_txt_p[position] = 0; // Set 0 at the end of the chain
+			ATP_SEND_TRACE ("ATP CMD : cmd buffer is ready to be interpreted = ",RV_TRACE_LEVEL_DEBUG_MEDIUM);
+			rvf_send_trace(port_p->cmd_info.cmd_txt_p,(UINT8) strlen(port_p->cmd_info.cmd_txt_p),NULL_PARAM,
+				RV_TRACE_LEVEL_DEBUG_MEDIUM,ATP_USE_ID);
+			
+			// Ready for interpretation
+			port_p->cmd_info.cmd_txt_length = (UINT8) (position); 
+			port_p->cmd_info.next_position = 0; 
+			port_p->cmd_info.status = NOT_STARTED;
+		}
+		else
+		{
+			// Waiting for new characters
+			port_p->cmd_info.next_position = (UINT8) (position); 
+			
+			// Tracing
+			port_p->cmd_info.cmd_txt_p[port_p->cmd_info.next_position] = 0;
+			ATP_SEND_TRACE ("ATP CMD : cmd buffer in the pipe = ",RV_TRACE_LEVEL_DEBUG_LOW);
+			rvf_send_trace(port_p->cmd_info.cmd_txt_p,(UINT8) strlen(port_p->cmd_info.cmd_txt_p),NULL_PARAM,
+				RV_TRACE_LEVEL_DEBUG_LOW,ATP_USE_ID);
+		}
+		
+		
+	}
+	
+	
+	
+	rvf_free_buf(new_txt_cmd_buffer_p);
+	
+	return RV_OK;
+}
+
+
+
+
+
+
+/******************************************************************************
+* Function name: atp_interpret_data
+* Description : This function is called when DATA received on a transport layer
+*				must be interpreted in order to emelate a DCE behaviour
+*				The command are either interpreted directly by DCE
+*				or sent in INTERPRETED or TXT format to the appli
+*				If end of the buffer to interpret is reached, send a OK result
+*				code to remote DTE
+*				If an error is encountered in the buffer, send a ERROR result
+*				code to the remote DTE
+*
+* Parameters :  pointer on port structure 
+*				memory bank to use
+*				spp_sw_id = sw id of the transport layer SW entity
+*				spp_port_nb = port_nb related to spp_sw_id
+*				appli_sw_id = sw id of the appli SW entity
+*				appli_port_nb = port_nb related to appli_sw_id
+*
+* Return     :   return RV_OK
+*				 or RV_MEMORY_ERR
+*
+* History			: 0.1 (1-Marsh-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_interpret_data(T_ATP_PORT_STRUCT	*port_p,
+							 T_ATP_SW_NB spp_sw_nb, T_ATP_SW_NB appli_sw_nb)
+							 
+{
+	T_ATP_TXT_CMD new_txt_cmd_p;
+	UINT16  txt_length;
+	T_ATP_CMD_TYPE	cmd_type;
+	T_ATP_CMD_NB	cmd_nb;
+	T_ATP_CMD	*cmd_info_p;
+	T_ATP_RET return_status;
+	
+	return_status = atp_interpret_raw_data(port_p,port_p->port_info[appli_sw_nb].rx_mb,
+		&cmd_type,&cmd_nb,&cmd_info_p,&new_txt_cmd_p,&txt_length);
+	
+	
+	if (return_status == RV_MEMORY_ERR)
+	{
+		return RV_MEMORY_ERR;
+	}
+	
+	if (return_status == RV_OK)
+	{
+		// Check if a command need to be sent
+		if ((cmd_type != UNKNOWN) && (new_txt_cmd_p == NULL))
+		{
+			if ( (port_p->port_config == DTE_CONFIG) && (cmd_type == AT_CMD))
+			{
+				/* If the command is a AT_CMD whereas ATP is emulating a DTE, then it is certainly 
+				because it is the echo of the command that DTE sent previously */
+				atp_send_cmd(port_p->port_info[spp_sw_nb].sw_id,port_p->port_info[spp_sw_nb].port_nb,
+				PRELIMINARY_RESULT_CODE,cmd_nb,cmd_info_p);
+			}
+			else
+			{
+				atp_send_cmd(port_p->port_info[spp_sw_nb].sw_id,port_p->port_info[spp_sw_nb].port_nb,
+				cmd_type,cmd_nb,cmd_info_p);
+			}
+		}
+		else
+		{
+			if (new_txt_cmd_p != NULL)
+			{
+				atp_send_txt_cmd(port_p->port_info[spp_sw_nb].sw_id,port_p->port_info[spp_sw_nb].port_nb,
+					cmd_type,new_txt_cmd_p);
+			}
+			else
+			{
+				// In this case, last command has been properly interpreted by DCE and
+				// status has been set to FINISHED by interprete raw data
+				// DCE must sends a result OK to remote device
+				if (port_p->cmd_info.status != FINISHED)
+				{
+					rvf_send_trace("ATP : status state invalid from interpret_raw_data function ",60,
+						NULL_PARAM,RV_TRACE_LEVEL_WARNING,ATP_USE_ID);
+					
+					port_p->cmd_info.status = FINISHED;
+				}
+				
+				atp_send_cmd(port_p->port_info[appli_sw_nb].sw_id,port_p->port_info[appli_sw_nb].port_nb,
+					RESULT_CODE,ATP_OK_NB,NULL);
+			}
+		}
+	}
+	else
+	{
+		// Error in the data received 
+		// Sends an error to the remote device
+		port_p->cmd_info.status=FINISHED; // will not get any new command
+		atp_send_cmd(port_p->port_info[appli_sw_nb].sw_id,port_p->port_info[appli_sw_nb].port_nb,
+			RESULT_CODE,ATP_ERROR_NB,NULL);
+	}
+	
+	/// IS IT OK ?
+	if (port_p->cmd_info.status==FINISHED)
+	{
+		atp_init_cmd_info_struct(port_p);
+	}
+	
+	
+	return RV_OK;
+}
+
+
+
+
+/******************************************************************************
+* Function name: atp_init_cmd_info_struct
+* Description : Initialise field of the icmd_info structure.
+*
+* Parameters :  port_p -> pointer on the port structure
+*
+* Return     :   return RV_OK
+*
+* History			: 0.1 (1-September-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_init_cmd_info_struct(T_ATP_PORT_STRUCT * port_p)
+{
+	// START SEMAPHORE ??
+	port_p->cmd_info.cmd_txt_length=0;
+	if (port_p->cmd_info.cmd_txt_p != NULL)
+	{ 
+		rvf_free_buf (port_p->cmd_info.cmd_txt_p);
+	}
+	port_p->cmd_info.cmd_txt_p = NULL;
+	port_p->cmd_info.next_position=0;
+	port_p->cmd_info.state = READY_FOR_NEW_CMD;
+	port_p->cmd_info.status = NOT_STARTED;
+	// STOP SEMAPHORE ??
+	return RV_OK;
+}
+
+
+
+/******************************************************************************
+* Function name: atp_error_switch
+* Description : This function send ERROR events
+*
+* Parameters :  
+*
+* Return     :   return RV_OK
+*				 or RV_MEMORY_ERR
+*
+* History			: 0.1 (1-September-2000) - Created
+*
+******************************************************************************/
+T_ATP_RET atp_error_switch(T_ATP_ERROR_MAIN_REASON main_reason,
+						   T_ATP_ERROR_TYPE error_type,T_RV_RETURN * return_path_p)
+{
+	T_ATP_ERROR * error_p;
+	
+
+	switch(main_reason)
+	{
+	case ATP_ERROR_FAILED_TO_OPEN_A_PORT:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to open a new port", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_ERROR_FAILED_TO_ACCEPT_A_PORT:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to accept a new port", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_ERROR_FAILED_TO_SEND_CMD:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to send a command on a port ", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_ERROR_FAILED_TO_CLOSE_A_PORT:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to close a port",RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_ERROR_FAILED_TO_SEND_DATA:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to send data", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_ERROR_FAILED_TO_GET_DATA:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to get data ", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_ERROR_FAILED_TO_HANDLE_MODE:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to handle mode related function", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_ERROR_FAILED_TO_HANDLE_SIGNAL:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to handle signal related function", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_ERROR_FAILED_TO_HANDLE_FLOW_REDIRECTION:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to redirect flow ", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	
+	case ATP_ERROR_FAILED_TO_HANDLE_REGISTRATION:
+		{	
+			ATP_SEND_TRACE ("ATP :  Failed to register or deregister or get info on an other SWE ", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	default:
+		{
+			ATP_SEND_TRACE ("ATP :  Failed with an unkown main reason", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+		
+	}
+	
+	switch(error_type)
+	{
+	case ATP_MEMORY_ERROR:
+		{
+			ATP_SEND_TRACE ("ATP :  Memory Issue . ATP PRIM memory bank is RED !", RV_TRACE_LEVEL_ERROR);
+			atp_error(ATP_ERROR_MB_PRIM_RED);			
+			break;
+		}
+	case ATP_PARAM_ERROR:
+		{
+			ATP_SEND_TRACE ("ATP :  Function has been called with wrong parameter value(s) ", RV_TRACE_LEVEL_WARNING);
+			break;
+		}	
+	case ATP_ISSUED_IN_A_WRONG_STATE_ERROR:
+		{
+			ATP_SEND_TRACE ("ATP :  Function has been called in a wrong state (port still not open or ATP not ready) ", RV_TRACE_LEVEL_WARNING);
+			break;
+		}	
+	case ATP_WAITING_FOR_RESULT:
+		{
+			ATP_SEND_TRACE ("ATP :  Tried to send a new AT_CMD whereas the previous one did not ge any result yet", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_CANNOT_TRANSLATE_CMD:
+		{
+			ATP_SEND_TRACE ("ATP :  Failed to translate a command (interprete mode <-> text or data mode) ", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_OTHER_SWE_NOT_IN_PROPER_MODE:
+		{
+			ATP_SEND_TRACE ("ATP :  The other SWE is not in proper mode (COPY_ON/OFF, DCE ON/OFF ...)", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_SAME_ACTION_ALREADY_DONE:
+		{
+			ATP_SEND_TRACE ("ATP :  This action has already been performed earlier ", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	case ATP_NO_MORE_RESSOURCE:
+		{
+			ATP_SEND_TRACE ("ATP :  There is no more ressource to handle this action", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	default:
+		{
+			ATP_SEND_TRACE ("ATP :  Failed with an unkown error reason", RV_TRACE_LEVEL_WARNING);
+			break;
+		}
+	}
+	
+	/* Get the primitive and sends it */
+	if(return_path_p != NULL)
+	{
+		if (rvf_get_buf(atp_mb_prim,sizeof(T_ATP_ERROR),(void **) &error_p)==RVF_RED)
+		{
+			atp_error(ATP_ERROR_MB_PRIM_RED);
+		}		
+		
+		error_p->rv_hdr.msg_id = ATP_ERROR;
+		error_p->main_reason = main_reason;
+		error_p->error_type = error_type;
+		
+		/* Send the event */
+		return atp_send_message(*return_path_p,(T_ATP_MESSAGE *)error_p);
+	}
+	
+	return RV_OK;				
+}
+
+
+
+
+
+/******************************************************************************
+* Function name: atp_get_info_on_port_end
+*
+* Description : Provide information on the other end of the port 
+* (for example, which format of data the other SW entity is expecting ) 
+*
+* Parameters :  see BT9901
+*
+* Return     :		RV_OK
+*					RV_INVALID_PARAMETER : one of the id or port_nb was wrong : ignore call
+*					RV_NOT_SUPPORTED : command needed to be translated and was unknow by ATP
+*
+*					atp_error can be called if MB is RED 
+*
+* History		: 0.1 19-Dec-2001
+*				
+******************************************************************************/
+T_ATP_RET atp_get_info_on_port_end (T_ATP_SW_ENTITY_ID requester_sw_id, T_ATP_PORT_NB requester_port_nb,
+					   T_ATP_OTHER_PORT_END_INFO * other_info_p)
+{
+	T_ATP_PORT_STRUCT * port_p;
+	T_ATP_SW_NB requester_sw_nb, other_sw_nb;
+	T_ATP_SW_ENTITY_STRUCT * other_sw_entity_p;
+	
+	/* Get the pointer on the port structure */
+	if(atp_get_port(requester_sw_id,requester_port_nb,&port_p,&requester_sw_nb) != RV_OK) 
+	{
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_PARAM_ERROR,NULL);
+		return RV_INVALID_PARAMETER; /* This port does not exist */
+	}
+	other_sw_nb=(T_ATP_SW_NB) (! requester_sw_nb);
+	
+	if (port_p->port_state == ATP_OPEN_PENDING)
+	{
+		/* Port is not completely open yet */
+		atp_error_switch(ATP_ERROR_FAILED_TO_SEND_CMD,ATP_ISSUED_IN_A_WRONG_STATE_ERROR,NULL);
+		return RV_NOT_SUPPORTED;
+	}
+	
+	/* get pointer on the other SW entity data structure in order to get info */
+	other_sw_entity_p=atp_sw_entity_table_p[port_p->port_info[other_sw_nb].sw_id];
+
+	/* Copy information */
+	strcpy((char *) other_info_p->name,(char *) other_sw_entity_p->sw_entity_name);
+	other_info_p->mode = other_sw_entity_p->mode;
+	other_info_p->no_copy_info = (port_p->port_info[other_sw_nb]).no_copy_info;
+	
+return OK;
+}
+
+
+
+/******************************************************************************
+* Function name: atp_mb_call_back
+*
+* Description : Indicate to a SW entity that the mb has ran GREEN again
+*				 This function is called when a RX_MB which was RED 
+*				(so TX_FLOW_OFF has been sent to the other SWE) 
+*				, has been switched to GREEN . In this case, a TX_FLOW_ON has
+*				to be sent to the SWE which was sending the data.
+*
+* Return     :		RV_OK if the signal has been sent to the proper SWE 
+*				    Otherwise, RV_NOT_SUPPORTED
+*
+* History		: 0.1 27-05-2002
+*				
+******************************************************************************/
+void atp_mb_call_back(T_RVF_MB_ID  mb)
+{
+	T_ATP_SW_NB        sw_nb   = ATP_MAX_SW_NB;
+	T_ATP_PORT_STRUCT  *port_p = NULL;
+
+	/* Searching for the ports whose RX memory bank matches with 'mb'. */
+	for (port_p = atp_first_port_p;
+		 port_p != NULL;
+		 port_p = port_p->next_p)
+	{
+
+		/* Setting the flow control to ATP_RX_FLOW_ON. */
+		if (((sw_nb = port_p->port_waiting_for_mb_callback) != ATP_MAX_SW_NB) && \
+			((port_p->port_info[sw_nb]).rx_mb == mb))
+		{
+
+			/* Setting the sendee to an invalid value. */
+			port_p->port_waiting_for_mb_callback = ATP_MAX_SW_NB;
+
+			/* Setting the flow control to ATP_RX_FLOW_ON. */
+			atp_set_signal ((port_p->port_info[sw_nb]).sw_id,
+							(port_p->port_info[sw_nb]).port_nb,
+							ATP_RX_FLOW_ON,
+							ATP_RX_FLOW_UNMASK);
+		}
+	}
+}