view src/cs/services/atp/atp_spp_api.c @ 303:f76436d19a7a default tip

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

/*******************************************************************************
*
* File Name : atp_spp_apif.c
*
* Functions Handling the interface between ATP and SPP SW entity
*
* (C) Texas Instruments, all rights reserved
*
* Version number	: 0.1      Date : 16-Marsh-2000
*
* History			: 0.1  - Created by E. Baissus
*					  0.9 - Updated based on new SPP version and reviewed
*
* 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_i.h"
#include "atp/atp_api.h"
#include "spp_general.h"
#include "atp/atp_config.h"
#include "atp/atp_spp_api.h"
#include "atp/atp_messages.h"
#include "spp_structs.h"
#include "spp_messages.h"
#include "spp_up_interface.h"
#include "atp/atp_spp_api_i.h"
#include "l2cap_data_hdlr.h" /* For L2CAP data handling */
#include "rvm/rvm_use_id_list.h"
#include <string.h>

/* Local variable */
static T_ATP_SW_ENTITY_ID atp_spp_sw_id;
static T_RVF_MB_ID spp_if_mb;
static T_RVF_ADDR_ID spp_addr_id = RVF_INVALID_ADDR_ID;
static T_ATP_SPP_PENDING_PORT_INFO pending_port_info[ATP_SPP_MAX_PENDING_PORT]; /* contains intermediate information during open port procedure */



/******************************************************************************
* Function name: atp_spp_from_spp_if_ft
*
* Description : Main function used to split the events coming from SPP
* and to forward to ATP
* 
*
* Parameters :  * message 
*
* Return     :   Standard error 
*				 RV_OK if  OK
*
* History			: 0.1 (17-Marsh-2000) 
*
******************************************************************************/
void atp_spp_from_spp_if_ft(void * message_p)
{
	
	T_RV_RET error;
	
	error = RV_OK;

	switch(((T_RV_HDR *)message_p)->msg_id)
	{
	case SPP_OPEN_PORT_CFM_EVT : 
		{	
			rvf_send_trace("ATP/SPP : Received a SPP_OPEN_PORT_CFM from SPP   ",50,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			
			error=atp_spp_open_port_rsp((void *) message_p,ATP_SPP_IS_CFM); 
			/* RV_OK or MEMORY ERROR or RV_NOT_SUPPORTED*/
			
			break;
		};
		
		
	case SPP_OPEN_PORT_IND_EVT : 
		{	
			rvf_send_trace("ATP/SPP : Received a SPP_OPEN_PORT_IND from SPP   ",50,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			
			error=atp_spp_open_port_rsp((void *) message_p,ATP_SPP_IS_IND); 
			/* RV_OK or RV_MEMORY_ERR or RV_NOT_SUPPORTED*/
			
			break;
		};
		
		
	case SPP_CLOSE_PORT_IND_EVT : 
		{
			
			rvf_send_trace("ATP/SPP : Received a SPP_CLOSE_PORT_IND from SPP   ",50,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			
			error=atp_close_port(atp_spp_sw_id,(T_ATP_PORT_NB) (((T_SPP_CLOSE_PORT_IND *) message_p)->handle)); 
			/* RV_OK or MEMORY ERROR or NOT_SUPPORTED*/

			/* Close server in case the port has been open is server mode */
			if (  ( ((T_SPP_CLOSE_PORT_IND *) message_p)->handle & SPP_HANDLE_TYPE) == SPP_SERVER_HANDLE_FLAG)
			{
				T_SPP_CLOSE_SERV * close_server_p;

				if (rvf_get_buf (spp_if_mb,sizeof(T_SPP_CLOSE_SERV),(void **) &close_server_p)==RVF_RED)
				{
					error = RV_MEMORY_ERR;
				}
				close_server_p->handle = ((T_ATP_CMD_RDY *) message_p)->port_nb;
				close_server_p->os_hdr.msg_id = SPP_CLOSE_SERV_EVT;
				
				rvf_send_trace("ATP/SPP : Send a SPP_CLOSE_SERV to SPP  ",40,
					NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
				
				rvf_send_msg (spp_addr_id,close_server_p);		
			}
			
			break;
		};
		
	case SPP_CLOSE_PORT_CFM_EVT : /* Acknowledge the port has been actually closed */
		{
			
			rvf_send_trace("ATP/SPP : Received a SPP_CLOSE_PORT_CFM from SPP   ",50,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID);
			
			/* Close server in case the port has been open is server mode */
			if (  ( ((T_ATP_PORT_CLOSED *) message_p)->port_nb & SPP_HANDLE_TYPE) == SPP_SERVER_HANDLE_FLAG)
			{
				
				T_SPP_CLOSE_SERV *	close_server_p;
				
				if (rvf_get_buf (spp_if_mb,sizeof(T_SPP_CLOSE_SERV),(void **) &close_server_p)==RVF_RED)
				{
					error = RV_MEMORY_ERR;
				}
				close_server_p->handle = ((T_SPP_CLOSE_PORT_CFM *) message_p)->handle;
				close_server_p->os_hdr.msg_id = SPP_CLOSE_SERV_EVT;
				
				rvf_send_trace("ATP/SPP : Send a SPP_CLOSE_SERV to SPP  ",40,
					NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
				
				rvf_send_msg (spp_addr_id,close_server_p);		
			}
			
			break;
		};

		

	case SPP_RECV_DATA_EVT : 
		{
			rvf_send_trace("ATP/SPP : Received a SPP_RECV_DATA_EVT from SPP   ",50,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			error=atp_no_copy_send_data(atp_spp_sw_id,
				(T_ATP_PORT_NB) ((T_SPP_RECV_DATA_NC *) message_p)->handle,
				(T_ATP_BUFFER)(((T_SPP_RECV_DATA_NC *) message_p)->l2cap_acl_data),
				((UINT32) ((T_SPP_RECV_DATA_NC *) message_p)->l2cap_acl_data->len));
			/* RV_OK or MEMORY ERROR */
			break;
		};
		
	case SPP_RETURN_MAX_PAYLOAD_EVT:
		{
			UINT16 * max_payload_p;

			rvf_send_trace("ATP/SPP : Received a SPP_RETURN_MAX_PAYLOAD_EVT from SPP ",57,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			rvf_send_trace("ATP/SPP : Send custom command ATP_FROM_SPP_MAX_PAYLOAD_IND_CMD to ATP ",70,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			
			if (rvf_get_buf (spp_if_mb,sizeof(UINT32),(void **) &max_payload_p)==RVF_RED)
			{
				error=RV_MEMORY_ERR;
			}
			else
			{
				*max_payload_p = ((T_SPP_RETURN_MAX_PAYLOAD *) message_p)->max_payload_length;
				error=atp_send_cmd(atp_spp_sw_id,
					(T_ATP_PORT_NB) ((T_SPP_RETURN_MAX_PAYLOAD *) message_p)->handle,
					CUSTOM_CMD,ATP_FROM_SPP_MAX_PAYLOAD_IND_CMD,max_payload_p);
			}
			break;
		}
		
		
	case SPP_RETURN_ERROR_EVT:
		{
			rvf_send_trace("ATP/SPP : Received a SPP_RETURN_ERROR_EVT from SPP ",51,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			rvf_send_trace("ATP/SPP : This event is not taken into account yet by ATP   ",60,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 			
			break;
		}
		
		
	case SPP_RETURN_MODEM_PARAM_EVT:
		{
			rvf_send_trace("ATP/SPP : Received a SPP_RETURN_MODEM_PARAM_EVT from SPP ",57,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			rvf_send_trace("ATP/SPP : This event is not taken into account yet by ATP   ",60,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			break;
		}
		
	case SPP_RETURN_LINE_STS_EVT:
		{
			rvf_send_trace("ATP/SPP : Received a SPP_RETURN_LINE_STS_EVT from SPP ",54,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			error=atp_spp_set_atp_signals(( T_SPP_LINE_STS *) message_p);			
			break;
		}
		
		
	default:
		{
			rvf_send_trace("ATP/SPP : A message received from ATP by ATP_SPP has been ignored ",66,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_HIGH, ATP_USE_ID); 
			break;
		};
	}
	
	/* Release SPP message buffer */
	rvf_free_buf(message_p);
	
	if (error != RV_OK)
	{
		rvf_send_trace("ATP/SPP : An error has been encountered when processing a message from SPP ",75,
			NULL_PARAM,RV_TRACE_LEVEL_WARNING, ATP_USE_ID); 
	}
	
}




/******************************************************************************
* Function name: atp_spp_to_spp_if_ft
*
* Description : Main function used to split the events coming from ATP
* and forwarded to SPP
* 
*
* Parameters :  * message 
*
* Return     :   Standard error 
*				 RV_OK if  OK
*
* History			: 0.1 (17-Marsh-2000) 
*
******************************************************************************/
void atp_spp_to_spp_if_ft( void * message_p)
{

	T_RV_RET error;

	error = RV_OK;

	
	switch(((T_ATP_MESSAGE *) message_p)->msg_id)
	{
	case ATP_OPEN_PORT_IND : 
		{
			rvf_send_trace("ATP/SPP : Received a ATP_OPEN_PORT_IND from ATP   ",50,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 


			error=atp_spp_open_port_rqst((T_ATP_OPEN_PORT_IND *) message_p); 
			/* RV_OK or MEMORY ERROR */
			
			break;
		};
		
		
	case ATP_PORT_CLOSED : 
		{
			rvf_send_trace("ATP/SPP : Received a ATP_PORT_CLOSED  from ATP    ",50,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			
			error=atp_spp_port_closed_from_atp((T_ATP_PORT_CLOSED *) message_p); 
		
			break;
		};
		
	case ATP_CMD_RDY : 
		{
			
			rvf_send_trace("ATP/SPP : Received a ATP_CMD_RDY  from ATP    ",50,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			
			rvf_send_trace("ATP/SPP : Command has been ignored ",35,
				NULL_PARAM,RV_TRACE_LEVEL_WARNING, ATP_USE_ID); 
			break;
		};
		
	case ATP_SIGNAL_CHANGED : 
		{
			error = atp_spp_set_spp_signals ((T_ATP_SIGNAL_CHANGED *) message_p);		
			break;
		};
		
		
		
	case ATP_ERROR : 
		{
			rvf_send_trace("ATP/SPP : Received a ATP_ERROR  from ATP ",41,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			rvf_send_trace("ATP/SPP : This event is not taken into account yet by ATP   ",60,
				NULL_PARAM,RV_TRACE_LEVEL_WARNING, ATP_USE_ID); 						
			break;
		};
		
	case ATP_NO_COPY_DATA_RDY : 
		{
			rvf_send_trace("ATP/SPP : Received a ATP_NO_COPY_DATA_RDY from ATP",50,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
			
			error=atp_spp_send_to_spp_buffer_nc((T_ATP_NO_COPY_DATA_RDY *) message_p); 
			
			/* RV_OK or MEMORY ERROR */
			
			break;
		};
		
	default:
		{
			rvf_send_trace("ATP/SPP : A message received from ATP by ATP_SPP has been ignored ",66,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_HIGH, ATP_USE_ID); 
			break;
		};
	}
	
	/* Release ATP message buffer */
	atp_free_message(message_p);
	
	if (error != RV_OK)
	{
		rvf_send_trace("ATP/SPP : An error has been encountered when processing a message from ATP ",75,
			NULL_PARAM,RV_TRACE_LEVEL_WARNING, ATP_USE_ID); 
	}
		
}





/*********************************************************************************
*	
*	Function name: atp_spp_reg
*
*	Description: Used to register spp to ATP 
*
*	Parameters: None 
*
*	Return:  
*
*	History: 0.1 (11-Aug-2000) 
*
*********************************************************************************/
T_RV_RET atp_spp_reg(void)
{
	T_ATP_ENTITY_MODE mode;
	T_ATP_SW_ENTITY_NAME name;
	T_ATP_CALLBACK return_path;

	/* Register SPP to ATP */
	strcpy((char *) name,ATP_SPP_NAME);
	return_path.callback_func = atp_spp_to_spp_if_ft;
	mode.cmd_mode=INTERPRETED_MODE; /* Do not care : DCE EMU is ON */
	mode.cp_mode=COPY_OFF;
	mode.cmd_support_mode=CMD_SUPPORT_OFF; // SPP does not support command....only data
	
	if(atp_reg(name,return_path,mode,&atp_spp_sw_id)!=RV_OK)
	{
		rvf_send_trace("ATP_SPP: SPP entity registration failed ",39, NULL_PARAM ,
			RV_TRACE_LEVEL_WARNING,ATP_USE_ID); 
		return RV_INTERNAL_ERR;	
	}
	return RV_OK;
}


/******************************************************************************
* Function name: atp_spp_init
*
* Description : This function is called to initialise SPP with ATP
* 
*
* Parameters :  None
*
* Return     :   Standard error 
*				RV_OK if  OK
*
* History			: 0.1 (17-Marsh-2000) 
*
******************************************************************************/
T_RV_RET atp_spp_init(T_RVF_ADDR_ID addr_id, T_RVF_MB_ID mb_id)
{
	UINT8 i;

	/* Initialisation */
	spp_addr_id=addr_id; /* Mail box and task number to send primitive to SPP */
	spp_if_mb=mb_id;	/* Use SPP PRIM MB as working mb */

	for(i=0;i<ATP_SPP_MAX_PENDING_PORT;i++)
	{
		pending_port_info[i].port_nb=0;
		pending_port_info[i].initiator_id=ATP_INVALID_SWE_ID; /* Indicates that the field is free */
		pending_port_info[i].handle=0;
	}

	return RV_OK;
}



/******************************************************************************
* Function name: atp_spp_start
*
* Description : This function is called to register SPP to ATP
* 
*
* Parameters :  None
*
* Return     :   Standard error 
*				RV_OK if  OK
*
* History			: 0.1 (29-Oct-2001) 
*
******************************************************************************/
T_RV_RET atp_spp_start(void)
{
	if (atp_spp_reg() != RV_OK)
	{
		ATP_SEND_TRACE("ATP: Normal warning if ATP should not be started along with SPP",
			RV_TRACE_LEVEL_WARNING);
	}
	return RV_OK;
}




/******************************************************************************
* Function name: atp_spp_open_port_rqst
*
* Description : Translate ATP_OPEN_PORT_IND into SPP_OPEN_PORT_RQST
* 
*
* Parameters :  Message pointer
*
* Return     :   Standard error 
*				RV_OK if  OK
*
* History			: 0.1 (20-Marsh-2000) 
*
******************************************************************************/
T_RV_RET atp_spp_open_port_rqst(T_ATP_OPEN_PORT_IND * open_port_ind_p)
{	

	T_SPP_OPEN_PORT_RQST * spp_open_port_rqst_p;
	T_ATP_CUSTOM_TO_SPP_INFO * spp_custom_info_p;
	UINT8 i,j;
	
	if (open_port_ind_p->custom_info_p == NULL)
	{
		rvf_send_trace("ATP_SPP: Received an open port request from ATP without SPP information ",72, NULL_PARAM ,
			RV_TRACE_LEVEL_WARNING,ATP_USE_ID); 
		rvf_send_trace("ATP_SPP: =>  the ATP open port request has been ignored ",56, NULL_PARAM ,
			RV_TRACE_LEVEL_WARNING,ATP_USE_ID); 
		return RV_NOT_SUPPORTED;	
	}
	
	if (rvf_get_buf (spp_if_mb,sizeof(T_SPP_OPEN_PORT_RQST),(void **) &spp_open_port_rqst_p)!=RVF_RED)
	{
		
	/* Find an empty field in the pending_port_info array 
		and store intermediate value before getting a CFM or IND */
		i=0;
		while((pending_port_info[i].initiator_id!=ATP_INVALID_SWE_ID) &&
			(i<ATP_SPP_MAX_PENDING_PORT))
		{
			i++;
		}
		if (i==ATP_SPP_MAX_PENDING_PORT)
		{
			rvf_send_trace("ATP/SPP : Cannot open a new port : max authorized reached",57,
				NULL_PARAM,RV_TRACE_LEVEL_WARNING, ATP_USE_ID); 
			// SHOULD SEND A IGNORE MESSAGE TO ATP 
			rvf_free_buf(spp_open_port_rqst_p);
			return RV_NOT_SUPPORTED; 
			
		}
		pending_port_info[i].port_nb=open_port_ind_p->initiator_port_nb;
		pending_port_info[i].initiator_id=open_port_ind_p->initiator_id; 
		/* pending_port_info[i].handle address is provided later on to SPP for update */
		
		spp_custom_info_p = (T_ATP_CUSTOM_TO_SPP_INFO *) open_port_ind_p->custom_info_p;
		
		/* Update field for SPP event */
		spp_open_port_rqst_p->appli_rx_mb = spp_custom_info_p->rx_mb;
		if (spp_custom_info_p->max_payload_length_reneg_en == ATP_PAYLOAD_LENGTH_RENEG_ON)
		{
			spp_open_port_rqst_p->max_payload_reneg= SPP_ENABLE_MAX_PAYLOAD_RENEG;
		}
		else
		{
			spp_open_port_rqst_p->max_payload_reneg= SPP_DISABLE_MAX_PAYLOAD_RENEG;
		}
		spp_open_port_rqst_p->max_payload_length = spp_custom_info_p->max_payload_length;
		if (spp_custom_info_p->is_server==ATP_IS_SERVER)
		{
			spp_open_port_rqst_p->server_mode=SPP_SERVER;
		}
		else
		{
			spp_open_port_rqst_p->server_mode=SPP_CLIENT;
		}	
		
		if (spp_custom_info_p->flow_ctrl_mode==ATP_AUTOMATIC_FLOW_CTRL_OFF)
		{
			spp_open_port_rqst_p->rx_flow_ctrl=SPP_MANUAL_FLOW_CTRL;
		}
		else
		{
			spp_open_port_rqst_p->rx_flow_ctrl=SPP_AUTOMATIC_FLOW_CTRL;
		}	
		spp_open_port_rqst_p->serv_channel = (T_SERVER_CHANNEL) spp_custom_info_p->server_channel;
		spp_open_port_rqst_p->os_hdr.callback_func = atp_spp_from_spp_if_ft;
		spp_open_port_rqst_p->os_hdr.dest_addr_id = RVF_INVALID_ADDR_ID;
		for (j=0 ; j<sizeof(T_BD_ADDR) ; j++)
		{spp_open_port_rqst_p->bd_addr[j] = spp_custom_info_p->bd_addr[j];	}
		
		spp_open_port_rqst_p->modem_accept = AUTO_ACCEPT;
			
		spp_open_port_rqst_p->handle=&(pending_port_info[i].handle);
		spp_open_port_rqst_p->os_hdr.msg_id = SPP_OPEN_PORT_RQST_EVT;
		
		/* Free the custom info buffer */
		rvf_free_buf(spp_custom_info_p);
		
		rvf_send_msg (spp_addr_id,spp_open_port_rqst_p);		
		return (RV_OK);
	}
	else 
	{
		return(RV_MEMORY_ERR);
	}
}




/******************************************************************************
* Function name: atp_spp_open_port_rsp
*
* Description : Translate SPP_OPEN_PORT_CFM and IND to atp_open_port_rsp
* 
*
* Parameters :  Message pointer
*
* Return     :   Standard error 
*				RV_OK if  OK
*
* History			: 0.1 (20-Marsh-2000) 
*
******************************************************************************/
T_RV_RET atp_spp_open_port_rsp(void * spp_open_port_rsp_p,T_ATP_SPP_IS_IND_OR_CFM cfm_or_ind)
{
	T_ATP_OPEN_PORT_RESULT result;
	T_ATP_PORT_INFO port_info;
	T_ATP_NO_COPY_INFO no_copy_info;
	UINT8 i;
	T_RV_RET return_status;
	T_SPP_HANDLE handle;
	T_ATP_CUSTOM_FROM_SPP_INFO * custom_info_p;
	

	
	if (rvf_get_buf (spp_if_mb,sizeof(T_ATP_CUSTOM_FROM_SPP_INFO),(void **) &custom_info_p)==RVF_RED)
	{
		return RV_MEMORY_ERR;
	}

	if (cfm_or_ind==ATP_SPP_IS_CFM)
	{
		/* Result translation */
		if (((T_SPP_OPEN_PORT_CFM *) spp_open_port_rsp_p)->result!=SPP_OPEN_PORT_SUCCESS)
		{
			result=OPEN_PORT_NOK;
		}
		else
		{
			result=OPEN_PORT_OK;
		}
		handle=((T_SPP_OPEN_PORT_CFM *) spp_open_port_rsp_p)->handle;
		custom_info_p->max_payload_length = ((T_SPP_OPEN_PORT_CFM *) spp_open_port_rsp_p)->max_payload_length;
		memcpy(custom_info_p->bd_addr,"000000",BD_ADDR_LEN);
	}
	else
	{
		result=OPEN_PORT_OK;
		handle=((T_SPP_OPEN_PORT_IND *) spp_open_port_rsp_p)->handle;
		custom_info_p->max_payload_length = ((T_SPP_OPEN_PORT_IND *) spp_open_port_rsp_p)->max_payload_length;
		memcpy(custom_info_p->bd_addr,((T_SPP_OPEN_PORT_IND *) spp_open_port_rsp_p)->bd_addr,BD_ADDR_LEN);
		
		/* Create custom info field and update values */
	}
	
	custom_info_p->custom_type=ATP_FROM_SPP_INFO;
	
	/* Get field from pending_port_info */ 
	i=0;
	while(  ((pending_port_info[i].handle!=handle) || 
		(pending_port_info[i].initiator_id==ATP_INVALID_SWE_ID))       &&
		(i<ATP_SPP_MAX_PENDING_PORT))
	{
		i++;
	}
	if (i==ATP_SPP_MAX_PENDING_PORT)
	{
		rvf_send_trace("ATP/SPP : Port handle from SPP not found ",57,
			NULL_PARAM,RV_TRACE_LEVEL_WARNING, ATP_USE_ID);
		if (cfm_or_ind==ATP_SPP_IS_IND)
		{
			rvf_send_trace("ATP/SPP : SPP may have send a PORT_IND whereas no port has been created first as a server ",90,
			NULL_PARAM,RV_TRACE_LEVEL_WARNING, ATP_USE_ID);
		}	
		rvf_free_buf(custom_info_p);
		return RV_NOT_SUPPORTED; /* Ignore command */
	}
	
	/* Port info */
	port_info.port_config = NOT_DEFINED_CONFIG;
	port_info.dce_mask[0]=0x0000; /* Command to interpret by ATP are not fixed on SPP side */
	port_info.ring_type=ATP_NO_RING_TYPE;
	port_info.signal_mask=ATP_ALL_THE_SIGNAL_UNMASK; /* Get all the signals */
	
	/* No copy info */
	no_copy_info.packet_mode=SEGMENTED_PACKET;
	no_copy_info.tx_head_mode=TX_HEADER_ON;/* Do not care */
	no_copy_info.tx_head_size=0;/* Do not care because SEGMENTED*/
	no_copy_info.tx_trail_size=0; /* Do not care */
	no_copy_info.rx_head_mode=RX_HEADER_ON; /* RX = DATA received by SPP from ATP */
	no_copy_info.rx_head_size=SPP_RX_HEAD_SIZE;
	no_copy_info.rx_trail_size=SPP_RX_TRAIL_SIZE;
	no_copy_info.rx_mb=RVF_INVALID_MB_ID; /* Not set by SPP */
	no_copy_info.tx_mb=RVF_INVALID_MB_ID; /* Not set by SPP */
		
	return_status=atp_open_port_rsp(pending_port_info[i].initiator_id, pending_port_info[i].port_nb,atp_spp_sw_id,
		(T_ATP_PORT_NB) handle,port_info,no_copy_info, (T_ATP_CUSTOM_INFO*) custom_info_p,result);
	
	pending_port_info[i].initiator_id = ATP_INVALID_SWE_ID;

	return return_status;
}




/******************************************************************************
* Function name: atp_spp_port_closed_from_atp
*
* Description : Translate ATP_PORT_CLOSED into SPP_CLOSE_PORT
* 
*
* Parameters :  Message pointer
*
* Return     :   Standard error 
*				RV_OK if  OK
*
* History			: 0.1 (20-Marsh-2000) 
*
******************************************************************************/
T_RV_RET atp_spp_port_closed_from_atp(T_ATP_PORT_CLOSED * close_port_p)
{
	
	T_SPP_CLOSE_PORT * spp_close_port_p;
	T_ATP_PORT_NB handle;
	UINT8 i;
	
	handle = close_port_p->port_nb;

	/* Check that this port was not in opening mode */
	/* If it was in opening mode, then find it in the pending port array  */
	i=0;
	while(  ((pending_port_info[i].port_nb!=close_port_p->closer_port_nb) || 
		(pending_port_info[i].initiator_id!=close_port_p->closer_sw_id))       &&
		(i<ATP_SPP_MAX_PENDING_PORT))
	{
		i++;
	}

	if (i!=ATP_SPP_MAX_PENDING_PORT)
	{
		/* In this case, the port handle was in the pending port array */
		/* That means that the port has not been completely open (only RQST sent) */
		/* RV_OK or MEMORY ERROR */
		
		handle = pending_port_info[i].handle;
		pending_port_info[i].initiator_id = ATP_INVALID_SWE_ID; // Refresh value
		
		if (  (handle & SPP_HANDLE_TYPE) == SPP_SERVER_HANDLE_FLAG)
		{
			// Port was open in server mode 
			// So close server
			T_SPP_CLOSE_SERV *	close_server_p;		
			if (rvf_get_buf (spp_if_mb,sizeof(T_SPP_CLOSE_SERV),(void **) &close_server_p)==RVF_RED)
			{
				return RV_MEMORY_ERR;
			}
			close_server_p->handle = handle;
			close_server_p->os_hdr.msg_id = SPP_CLOSE_SERV_EVT;	
			rvf_send_trace("ATP/SPP : Send a SPP_CLOSE_SERV to SPP  ",40,
				NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 			
			rvf_send_msg (spp_addr_id,close_server_p);
			return RV_OK;
		}
	}


	if (rvf_get_buf (spp_if_mb,sizeof(T_SPP_CLOSE_PORT),(void **) &spp_close_port_p)!=RVF_RED)
	{		
		spp_close_port_p->handle=handle;		
		spp_close_port_p->os_hdr.msg_id=SPP_CLOSE_PORT_EVT;		
		rvf_send_msg (spp_addr_id,spp_close_port_p);	
		return (RV_OK);
	}
	else 
	{
		return(RV_MEMORY_ERR);
	}
}








/******************************************************************************
* Function name: atp_spp_send_to_spp_buffer_nc
*
* Description : Translate ATP_NO_COPY_DATA_RDY into SPP_SEND_BUFFER_NC_EVT
* 
*
* Parameters :  Message pointer
*
* Return     :   Standard error 
*				RV_OK if  OK
*
* History			: 0.1 (20-Marsh-2000) 
*
******************************************************************************/
T_RV_RET atp_spp_send_to_spp_buffer_nc(T_ATP_NO_COPY_DATA_RDY * atp_no_copy_p)
{
	
	T_SPP_SEND_BUFFER_NC * spp_no_copy_p;
	
	if (rvf_get_buf (spp_if_mb,sizeof(T_SPP_SEND_BUFFER_NC),(void **) &spp_no_copy_p)!=RVF_RED)
	{
		
		spp_no_copy_p->handle=(T_SPP_HANDLE) atp_no_copy_p->port_nb;
		spp_no_copy_p->buffer=atp_no_copy_p->atp_buffer_p;
		spp_no_copy_p->length=(UINT16) atp_no_copy_p->buffer_size;
		
		
		spp_no_copy_p->os_hdr.msg_id=SPP_SEND_BUFFER_NC_EVT;
		
		rvf_send_msg (spp_addr_id,spp_no_copy_p);
		
		return (RV_OK);
	}
	else 
	{
		return(RV_MEMORY_ERR);
	}
}


/******************************************************************************
* Function name: atp_spp_set_spp_signals
*
* Description : Based on a ATP_SIGNAL_CHANGED signal, set SPP signals
* 
*
* Parameters :  Message pointer
*
* Return     :   Standard error 
*				RV_OK if  OK
*
* History			: 0.1 (20-Marsh-2000) 
*
******************************************************************************/
T_RV_RET atp_spp_set_spp_signals(T_ATP_SIGNAL_CHANGED * message_p)
{	
	T_SPP_LINE_STS * line_sts_p;

	/* Get Signals of the port on ATP side */

	
	ATP_SEND_TRACE("ATP/SPP : Received a ATP_SIGNAL_CHANGED  from ATP ",
		RV_TRACE_LEVEL_DEBUG_LOW); 

	rvf_send_trace("ATP/SPP : Signal value =  ",26,
		(UINT32) message_p->signal,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
	
	if (rvf_get_buf (spp_if_mb,sizeof(T_SPP_LINE_STS),(void **) &line_sts_p)==RVF_RED)
	{
		return RV_MEMORY_ERR;
	}
	
	line_sts_p->handle =((T_ATP_SIGNAL_CHANGED *) message_p)->port_nb;
	line_sts_p->mask =OTHER_SIGNALS;
	line_sts_p->os_hdr.msg_id =SPP_SET_LINE_STS_EVT;
	line_sts_p->fc_flow =FC_FLOW_ON; // Should be do not care 
	
	/* DCD */
	if ( (message_p->signal & ATP_DCD_UNMASK) == ATP_DCD_0)
	{
		line_sts_p->dv = DCD_0;
	}
	else
	{
		line_sts_p->dv = DCD_1;
	}
	
	/* RI */
	if ( (message_p->signal & ATP_RI_UNMASK) == ATP_RI_0)
	{
		line_sts_p->ic = RI_0;
	}
	else
	{
		line_sts_p->ic = RI_1;
	}
	
	
	/* DTR/DSR */
	if ( (message_p->signal & ATP_DTR_DSR_UNMASK) == ATP_DTR_DSR_0)
	{
		line_sts_p->rtc = DTRDSR_0;
	}
	else
	{
		line_sts_p->rtc = DTRDSR_1;
	}
	
	/* RTS CTS */
	if ( (message_p->signal & ATP_RTS_CTS_UNMASK) == ATP_RTS_CTS_0)
	{
		line_sts_p->rtr = RTSCTS_0;
	}
	else
	{
		line_sts_p->rtr = RTSCTS_1;
	}
	
	rvf_send_trace("ATP/SPP : Send a SPP_SET_LINE_STS to SPP  ",42,
		NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
	
	return rvf_send_msg (spp_addr_id,line_sts_p);					
}



/******************************************************************************
* Function name: atp_spp_set_atp_signals
*
* Description : Based on a SPP_LINE_STS 
* 
*
* Parameters :  Message pointer
*
* Return     :   Standard error 
*				RV_OK if  OK
*
* History			: 0.1 (20-Marsh-2000) 
*
******************************************************************************/
T_RV_RET atp_spp_set_atp_signals(T_SPP_LINE_STS * message_p)
{
	T_ATP_PORT_SIGNAL signal,old_signal;
	T_ATP_SIGNAL_CHANGE_MASK  mask = 0;
	
	rvf_send_trace("ATP/SPP : Received a LINE_STS event from SPP ",45,
		NULL_PARAM,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
	
	atp_get_signal(atp_spp_sw_id,(T_ATP_PORT_NB) ((T_SPP_LINE_STS *) message_p)->handle,
		&old_signal);
	
	signal=old_signal;
	
	/* DCD */
	if ( (message_p->dv  == DCD_0) && ( (old_signal & ATP_DCD_UNMASK) == ATP_DCD_1))
	{
		/* DCD changed to 0 */
		mask |= ATP_DCD_UNMASK;
		signal &= (~ ATP_DCD_UNMASK); // clear DCD
		ATP_SEND_TRACE("ATP : DCD has been set to 0",RV_TRACE_LEVEL_DEBUG_LOW);
	}
	else
	{
		if ( (message_p->dv  == DCD_1) && ( (old_signal & ATP_DCD_UNMASK) == ATP_DCD_0))
		{
			/* DCD changed to 1 */
			mask |= ATP_DCD_UNMASK;
			signal |= ATP_DCD_1;
			ATP_SEND_TRACE("ATP : DCD has been set to 1",RV_TRACE_LEVEL_DEBUG_LOW);
		}
	}
	
	/* RI */
	if ( (message_p->ic  == RI_0) && ( (old_signal & ATP_RI_UNMASK) == ATP_RI_1))
	{
		/* RI changed to 0 */
		mask |= ATP_RI_UNMASK;
		signal &= (~ ATP_RI_UNMASK); // clear RI
		ATP_SEND_TRACE("ATP : RI has been set to 0",RV_TRACE_LEVEL_DEBUG_LOW);
	}
	else
	{
		if ( (message_p->ic  == RI_1) && ( (old_signal & ATP_RI_UNMASK) == ATP_RI_0))
		{
			/* RIchanged to 1 */
			mask |= ATP_RI_UNMASK;
			signal |= ATP_RI_1;
			ATP_SEND_TRACE("ATP : RI has been set to 1",RV_TRACE_LEVEL_DEBUG_LOW);
		}
	}
	
	
	/* DTR/DSR */
	if ( (message_p->rtc  == DTRDSR_0) && ( (old_signal & ATP_DTR_DSR_UNMASK) == ATP_DTR_DSR_1))
	{
		/* DTR/DSR changed to 0 */
		mask |= ATP_DTR_DSR_UNMASK;
		signal &= (~ ATP_DTR_DSR_UNMASK); // clear DTR/DSR
		ATP_SEND_TRACE("ATP : DTR/DSR has been set to 0",RV_TRACE_LEVEL_DEBUG_LOW);
	}
	else
	{
		if ( (message_p->rtc  == DTRDSR_1) && ( (old_signal & ATP_DTR_DSR_UNMASK) == ATP_DTR_DSR_0))
		{
			/* DCD changed to 0 */
			mask |= ATP_DTR_DSR_UNMASK;
			signal |= ATP_DTR_DSR_1;
			ATP_SEND_TRACE("ATP : DTR/DSR has been set to 1",RV_TRACE_LEVEL_DEBUG_LOW);
		}
	}
	
	
	/* RTS CTS */
	if ( (message_p->rtr  == RTSCTS_0) && ( (old_signal & ATP_RTS_CTS_UNMASK) == ATP_RTS_CTS_1))
	{
		/* DTR/DSR changed to 0 */
		mask |= ATP_RTS_CTS_UNMASK;
		signal &= (~ ATP_RTS_CTS_UNMASK); // clear DTR/DSR
		ATP_SEND_TRACE("ATP : RTS/CTS has been set to 0",RV_TRACE_LEVEL_DEBUG_LOW);
	}
	else
	{
		if ( (message_p->rtr  == RTSCTS_1) && ( (old_signal & ATP_RTS_CTS_UNMASK) == ATP_RTS_CTS_0))
		{
			/* DCD changed to 0 */
			mask |= ATP_RTS_CTS_UNMASK;
			signal |= ATP_RTS_CTS_1;
			ATP_SEND_TRACE("ATP : RTS/CTS has been set to 1",RV_TRACE_LEVEL_DEBUG_LOW);
		}
	}
	
	
	rvf_send_trace("ATP/SPP : Signal Value = ",25,
		(UINT32) signal ,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
	rvf_send_trace("ATP/SPP : Mask  Value = ",24,
		(UINT32) mask ,RV_TRACE_LEVEL_DEBUG_LOW, ATP_USE_ID); 
	
	return atp_set_signal(atp_spp_sw_id, (T_ATP_PORT_NB) ((T_SPP_LINE_STS *) message_p)->handle,
		signal,mask);
}