/********************************************************************************
 *
 * File Name : atp_cmd.c
 *
 * Functions handling the command translation between txt and command
 * (and vice-versa)
 *
 * (C) Texas Instruments, all rights reserved
 *
 * Version number   : 0.1 - 03-03-2000
 *
 * History          : 0.1 - Created by E. Baissus
 *                    0.2 - Reviewed : More generic AT commands handling and
 *                                     copy optimization (especially on L2CAP
 *                                     buffers)
 *                    0.3 - '+CME ERROR' and '+CMS ERROR' support
 *
 * 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_cmd.h"
#include "rvm/rvm_use_id_list.h"
#include <string.h>

#ifdef BLUETOOTH
#include "l2cap_data_hdlr.h"	/* For L2CAP data handling.                     */
#endif

/********************************************************************************
* Function name	: dtoa
*
* Description   : Convert the digits of the given decimal value to a character 
*				  string
*
* Parameters    : decimal = decimal value to be converted
*                 ascii_p = string result
*
* Return        : Digit number
*
* Note          : digit and remainder declared as volatile to avoid bugs due to
*				  optimization.
*
* History       : 0.1 (25-August-2000) - Created
*
*********************************************************************************/
UINT8 dtoa (UINT16         decimal,
			T_ATP_TXT_CMD  ascii_p)
{
    /* Declare local variables.                                                 */
	T_ATP_TXT_CMD    str_p     = ascii_p;
	volatile UINT8   digit     = 0x00;
	volatile UINT16  remainder = decimal;

/***************************** dtoa function begins *****************************/

	/* Check to see if the string result is non-null.                           */
	if (str_p == NULL)
	{
		return (0x00);
	}

	/* Convert the fifth digit: remainder = [65535,9999[.                       */
	for (digit = 0x00;
		 remainder > 9999;
		 remainder -= 10000,
		 digit++)
	{
	}
	if (digit > 0x00)
	{
		*str_p++ = (INT8) ('0' + digit);
	}

	/* Convert the fourth digit: remainder = [9xxx,999[.                        */
	for (digit = 0x00;
		 remainder > 999;
		 remainder -= 1000,
		 digit++)
	{
	}
	if ((digit > 0x00) || (str_p != ascii_p))
	{
		*str_p++ = (INT8) ('0' + digit);
	}

	/* Convert the third digit: remainder = [9xx,99[.                           */
	for (digit = 0x00;
		 remainder > 99;
		 remainder -= 100,
		 digit++)
	{
	}
	if ((digit > 0x00) || (str_p != ascii_p))
	{
		*str_p++ = (INT8) ('0' + digit);
	}

	/* Convert the second digit: remainder = [9x,9[.                            */
	for (digit = 0x00;
		 remainder > 9;
		 remainder -= 10,
		 digit++)
	{
	}
	if ((digit > 0x00) || (str_p != ascii_p))
	{
		*str_p++ = (INT8) ('0' + digit);
	}

	/* Convert the last digit: remainder = [9,0].                               */
	*str_p++ = (INT8) ('0' + remainder);

	/* Return the length of the string.                                         */
	return ((UINT8) (str_p - ascii_p));

} /**************************** End of dtoa function ****************************/


/********************************************************************************
* Function name : atp_cmd_init_dce_info
*
* Description   : Initialize the whole of the information stored in the 'DCE 
*                 information' structure
*
* Parameter     : dce_info_p = pointer on the DCE information
*
* Return        : RV_OK
*
* History       : 0.1 (28-August-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_cmd_init_dce_info (T_ATP_DCE_INFO  *dce_info_p)
{
    /* Declare a local variable.                                                */
	UINT8  count = 0;

/********************* atp_cmd_init_dce_info function begins ********************/

	rvf_send_trace ("ATP : DCE information initialized ",
					34,
					NULL_PARAM,
					RV_TRACE_LEVEL_DEBUG_LOW,
					ATP_USE_ID);

	/* Define the default command line termination character (See ITU-T         */
	/* Recommendation V.250 ter page 21).                                       */
	dce_info_p->cr_character = ATP_CR_CHARACTER;

	/* Define the default response formatting character (See ITU-T              */
	/* Recommendation V.250 ter page 22).                                       */
	dce_info_p->lf_character = ATP_LF_CHARACTER;

	/* Define the default command line editing character (See ITU-T             */
	/* Recommendation V.250 ter page 22).                                       */
	dce_info_p->bs_character = ATP_BS_CHARACTER;

	/* Define the escape sequence (See ITU-T Recommendation V.250 ter page 24). */
	memcpy ((void *) (dce_info_p->escape_sequence),
			ATP_ESCAPE_SEQUENCE,
			MAX_NB_OF_CHARACTER_FOR_END_SEQUENCE);

	/* Define the command echo (See ITU-T Recommendation V.250 ter page 23).    */
	dce_info_p->echo_mode = ECHO_OFF;

	/* Define the result code suppression (See ITU-T Recommendation V.250 ter   */
	/* page 23).                                                                */
	dce_info_p->result_code_mode = RESULT_CODE_ON;

	/* Define the DCE response format (See ITU-T Recommendation V.250 ter page  */
	/* 24).                                                                     */
	dce_info_p->verbose_mode = ATP_VERBOSE_1;

	/* Initialize the masks associated with the commands executed by the ATP.   */
	memset ((void *) (dce_info_p->dce_mask),
			0x00,
			sizeof (T_ATP_DCE_MASK));

	/* Initialize pointers on temporary buffers containing the escape sequence. */
	for (count = 0;
		 count < MAX_NB_OF_CHARACTER_FOR_END_SEQUENCE;
		 count++)
	{

		/* Initialize the pointer on a temporary data buffer containing part of */
		/* the assumed escape sequence.                                         */
		dce_info_p->escape_sequence_tmp_buffer_p[count] = NULL;

		/* Initialize the number of data included in buffer hereinabove.        */
		dce_info_p->length_of_escape_sequence_tmp_buffer_p[count] = 0;
	}
	dce_info_p->nb_plus_received = 0;
	return (RV_OK);

} /******************** End of atp_cmd_init_dce_info function *******************/


/********************************************************************************
* Function name : atp_get_custom_info_from_txt
*
* Description   : Etract custom information from a text string
*
* Parameters    : text_pp = string containing the command (0-terminated)
*                 cmd_format = related structure
*                 mb_id = memory bank used to get the custom command information
*                         buffer
*                 termination_char = termination character ('\x00' or <CR>)
*
* Return        : cmd_info_pp and RV_OK if the command is found,
*                 RV_NOT_SUPPORTED
*
* Note          : Space characters are ignored and may be used freely for formatting
*                 purposes, unless they are embedded in numeric or string constants
*                 (See ITU-T Recommendation V.250 ter sections 5.4.2.1 or 5.4.2.2 on
*                 pages 6 and 7). The DCE shall be capable of accepting at least 40
*                 characters in the body.
*
* History       : 0.1 (29-August-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_get_custom_info_from_txt (T_ATP_TXT_CMD     *text_pp,
										T_ATP_CMD_FORMAT  cmd_format,
										T_RVF_MB_ID       mb_id,
										T_ATP_CMD         **cmd_info_pp,
										const char        termination_char)
{

/***************** atp_get_custom_info_from_txt function begins *****************/

	switch (cmd_format)
	{

		/* Basic syntax command does not expect any <number>.                   */
		case ATP_NO_PARAM:
			{
				*cmd_info_pp = NULL;
				return (RV_OK);
			}

		/* Basic syntax command.                                                */
		case ATP_BASIC_PARAM:
			{

				/* Allocate memory in order to store the <number> associated    */
				/* with basic syntax commands. If insufficient resources        */
				/* available, then report an internal memory error and abort.   */
				if (rvf_get_buf (mb_id, \
								 sizeof (T_ATP_BASIC_CMD), \
								 (void **) cmd_info_pp) == RVF_RED)
				{
					atp_error (ATP_ERROR_TX_MB_RED);
					return (RV_MEMORY_ERR);
				}

				/* Get the <number> of the basic syntax command (See ITU-T      */
				/* Recommendation V.250 ter page 5).                            */
				memset ((void *) (*cmd_info_pp),
						0x00,
						sizeof (T_ATP_BASIC_CMD));
				ATP_GET_NUMBER (*text_pp,
								&((*((T_ATP_BASIC_CMD **) cmd_info_pp))->number),
								'0');
				return (RV_OK);
			}

		/* Dial.                                                                */
		case ATP_DIAL_PARAM:
			{

				/* Allocate memory in order to store the <dial_string>          */
				/* associated with the dial. If insufficient resources          */
				/* available, then report an internal memory error and abort.   */
				if (rvf_get_buf (mb_id, \
								 sizeof (T_ATP_DIAL), \
								 (void **) cmd_info_pp) == RVF_RED)
				{
					atp_error (ATP_ERROR_TX_MB_RED);
					return (RV_MEMORY_ERR);
				}

				/* Get the <dial_string> of the dial (See ITU-T Recommendation  */
				/* V.250 ter page 31). All characters appearing on the same     */
				/* command line after D are considered part of the call         */
				/* addressing information to be signalled to the network, or    */
				/* modifiers used to control the signalling process, up to a    */
				/* semicolon character or the end of the command line. If the   */
				/* <dial_string> is terminated by a semicolon, the DCE does not */
				/* start the call origination procedure, but instead returns to */
				/* command state after completion of the signalling of call     */
				/* addressing information to the network.                       */
				memset ((void *) (*cmd_info_pp),
						0x00,
						sizeof (T_ATP_DIAL));
				ATP_GET_DIAL_STRING (*text_pp,
									 (*((T_ATP_DIAL **) cmd_info_pp))->dial_string_p,
									 &((*((T_ATP_DIAL **) cmd_info_pp))->dial_string_length),
									 &((*((T_ATP_DIAL **) cmd_info_pp))->call_type),
									 termination_char);
				return (RV_OK);
			}

		/* S-parameter.                                                         */
		case ATP_S_PARAM:
			{

				/* Allocate memory in order to store the <value> associated     */
				/* with S-parameters. If insufficient resources available, then */
				/* report an internal memory error and abort.                   */
				if (rvf_get_buf (mb_id, \
								 sizeof (T_ATP_S_PARAM), \
								 (void **) cmd_info_pp) == RVF_RED)
				{
					atp_error (ATP_ERROR_TX_MB_RED);
					return (RV_MEMORY_ERR);
				}

				/* Get the characters that immediately follow                   */
				/* <parameter_number>. "=" is used to set the indicated         */
				/* S-parameter to a new value (See ITU-T Recommendation V.250   */
				/* ter page 5). Note that if no value is given, the S-parameter */
				/* specified may be set to 0, or an ERROR result code issued    */
				/* and the stored value left unchanged. "?" is used to read the */
				/* current value of the indicated S-parameter (See ITU-T        */
				/* Recommendation V.250 ter page 5).                            */
				memset ((void *) (*cmd_info_pp),
						0x00,
						sizeof (T_ATP_S_PARAM));
				ATP_GET_PARAMETER_VALUE (*text_pp,
										 &((*((T_ATP_S_PARAM **) cmd_info_pp))->s_operator),
										 &((*((T_ATP_S_PARAM **) cmd_info_pp))->value));
				return (RV_OK);
			}

		/* Extended syntax command does not expect any <value>.                 */
		case ATP_NO_EXTENDED_PARAM:
			{

				/* Allocate memory in order to store the <value> associated     */
				/* with extended syntax commands. If insufficient resources     */
				/* available, then report an internal memory error and abort.   */
				if (rvf_get_buf (mb_id, \
								 sizeof (T_ATP_NO_SUBPARAMETER), \
								 (void **) cmd_info_pp) == RVF_RED)
				{
					atp_error (ATP_ERROR_TX_MB_RED);
					return (RV_MEMORY_ERR);
				}

				/* Get the characters that immediately follow <name>. "=?" is   */
				/* used to test whether the extended syntax command is          */
				/* implemented in the DCE (See ITU-T Recommendation V.250 ter   */
				/* page 9).                                                     */
				memset ((void *) (*cmd_info_pp),
						0x00,
						sizeof (T_ATP_NO_SUBPARAMETER));
				ATP_GET_OPERATOR (*text_pp,
								  &((*((T_ATP_NO_SUBPARAMETER **) cmd_info_pp))->extended_operator));
				return (RV_OK);
			}

		/* Extended syntax command whose subparameter is a numeric constant.    */
		case ATP_SINGLE_EXTENDED_PARAM:
			{

				/* Allocate memory in order to store the <value> associated     */
				/* with extended syntax commands. If insufficient resources     */
				/* available, then report an internal memory error and abort.   */
				if (rvf_get_buf (mb_id, \
								 sizeof (T_ATP_SINGLE_SUBPARAMETER), \
								 (void **) cmd_info_pp) == RVF_RED)
				{
					atp_error (ATP_ERROR_TX_MB_RED);
					return (RV_MEMORY_ERR);
				}

				/* Get the characters that immediately follow <name>. "=" is    */
				/* used to set the indicated extended syntax command to a new   */
				/* value (See ITU-T Recommendation V.250 ter page 8). Note that */
				/* if no value is given, the extended syntax command specified  */
				/* may be set to 0. "?" is used to read the current value of    */
				/* the indicated extended syntax command (See ITU-T             */
				/* Recommendation V.250 ter page 9). "=?" is used to test       */
				/* whether the extended syntax command is implemented in the    */
				/* DCE.                                                         */
				memset ((void *) (*cmd_info_pp),
						0x00,
						sizeof (T_ATP_SINGLE_SUBPARAMETER));
				ATP_GET_VALUE (*text_pp,
							   &((*((T_ATP_SINGLE_SUBPARAMETER **) cmd_info_pp))->extended_operator),
							   &((*((T_ATP_SINGLE_SUBPARAMETER **) cmd_info_pp))->value),
							   termination_char);
				return (RV_OK);
			}

		/* Keypad control command.                                              */
		case ATP_PLUS_CKPD_PARAM:
			{

				/* Allocate memory in order to store the <keys>,<time> and      */
				/* <pause> associated with +CKPD extended syntax command. If    */
				/* insufficient resources available, then report an internal    */
				/* memory error and abort.                                      */
				if (rvf_get_buf (mb_id, \
								 sizeof (T_ATP_PLUS_CKPD), \
								 (void **) cmd_info_pp) == RVF_RED)
				{
					atp_error (ATP_ERROR_TX_MB_RED);
					return (RV_MEMORY_ERR);
				}

				/* Get the <keys>,<time> and <pause> of the keypad control      */
				/* command. Note that <keys> shall consist of a string constant */
				/* and <time> and <pause> shall consist of numeric constants in */
				/* tenths of a second (See ETS 300 916 (GSM 07.07) Version      */
				/* 5.8.1 page 62). "=?" is used to test whether the extended    */
				/* syntax command is implemented in the DCE.                    */
				memset ((void *) (*cmd_info_pp),
						0x00,
						sizeof (T_ATP_PLUS_CKPD));
				ATP_GET_CKPD_PARAM (*text_pp,
									(*((T_ATP_PLUS_CKPD **) cmd_info_pp)),
									termination_char);
				return (RV_OK);
			}

		/* AT command undefined or not supported for now.                       */
		default:
			{
				break;
			}
	}
	return (RV_NOT_SUPPORTED);

} /**************** End of atp_get_custom_info_from_txt function ****************/


/********************************************************************************
* Function name : atp_translate_raw_data_to_cmd
*
* Description   : Translate raw data into an interpreted command
*
* Parameters    : dce_info_p = pointer on the port structure
*                 text_p = raw data containing the command (0-terminated)
*                 cmd_type = command type of the text
*                 cmd_type_p = type of the interpreted command
*                 cmd_nb_p = binary related code of the interpreted command
*                 skip_prefix = indicate whether the prefix shall be skipped in
*                               order to proceed the translation
*                 mb_id = memory bank used to get the custom command information
*                         buffer
*                 cmd_info_pp = pointer on the custom command information structure
*
* Return        : RV_OK,
*                 RV_NOT_SUPPORTED if the command is not recognized,
*                 RV_INVALID_PARAMETER
*
* Note          : A command line is made up of three elements: the prefix, the body,
*                 and the termination character. The command line prefix consists of
*                 the characters "AT" or "at", or, to repeat the execution of the 
*                 previous command line, the characters "A/" or "a/". The body is
*                 made up of individual commands. Space characters are ignored and
*                 may be used freely for formatting purposes, unless they are embedded
*                 in numeric or string constants (See ITU-T Recommendation V.250 ter
*                 sections 5.4.2.1 or 5.4.2.2 on pages 6 and 7). The termination
*                 character may not appear in the body. The DCE shall be capable of
*                 accepting at least 40 characters in the body. Note that the
*                 termination character may be selected by a user option (parameter
*                 S3), the default being CR.
*
* History       : 0.1 (25-August-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_translate_raw_data_to_cmd (T_ATP_PORT_STRUCT  *port_p,
										 T_ATP_TXT_CMD      *text_pp,
										 T_ATP_CMD_TYPE     cmd_type,
										 T_ATP_CMD_TYPE     *cmd_type_p,
										 T_ATP_CMD_NB       *cmd_nb_p,
										 T_RVF_MB_ID        mb_id,
										 T_ATP_CMD          **cmd_info_pp)
{
	/* Declare a local variable.                                                */
	BOOLEAN  equal = FALSE;

/***************** atp_translate_raw_data_to_cmd function begins ****************/

	/* Check to see if the text command line is valid.                          */
	if ((text_pp == NULL) || (*text_pp == NULL))
	{
		return (RV_INVALID_PARAMETER);
	}

	/* Initialize information for AT commands do not expect any number or       */
	/* value.                                                                   */
	*cmd_info_pp = NULL;

	/* DTE command lines (See ITU-T Recommendation V.250 ter page 4). By the    */
	/* way, note that the prefix consists of the characters "AT" or "at".       */
	if ((cmd_type == UNKNOWN) || (cmd_type == AT_CMD))
	{

		/* Declare a local block variable.                                      */
		UINT8  prefix_len = 0x00;

		/* Check to see whether the prefix shall be skipped in order to proceed */
		/* the translation.                                                     */
		if ((port_p == NULL) || ((port_p->cmd_info).status == NOT_STARTED))
		{
			prefix_len = ATP_AT_PREFIX_LEN;
		}

		/* If the prefix is either "AT" or "at", then the DCE shall proceed the */
		/* command line body (See ITU-T Recommendation V.250 ter page 4).       */
		ATP_MEM_I_CMP (ATP_AT_PREFIX,
					   *text_pp,
					   prefix_len,
					   &equal);
		if (equal == TRUE)
		{

			/* Declare local block variables.                                   */
			const char  *cmd_p  = NULL;
			UINT8       cmd_len = 0x00;
			
			for (*cmd_nb_p   = 0x00, \
				 *cmd_type_p = AT_CMD, \
				 equal       = FALSE, \
				 *text_pp    += prefix_len;
				 *cmd_nb_p < ATP_MAX_NB_OF_AT_COMMANDS;
				 (*cmd_nb_p)++)
			{

				/* If needed, skip this empty entry.                            */
				if (ATP_AT_INFO[*cmd_nb_p][ATP_AT_PARAM_COLUMN] == ATP_CMD_NOT_DEFINED)
				{
					continue;
				}

				/* Get the length of the remainder.                             */
				cmd_len = (UINT8) (ATP_AT_INFO[*cmd_nb_p + 0x01][ATP_AT_OFFSET_COLUMN] - ATP_AT_INFO[*cmd_nb_p][ATP_AT_OFFSET_COLUMN]);
				cmd_p   = &(ATP_AT_TXT_TABLE[ATP_AT_INFO[*cmd_nb_p][ATP_AT_OFFSET_COLUMN]]);
				ATP_MEM_SP_I_CMP (cmd_p,
								  *text_pp,
								  &cmd_len,
								  &equal);

				/* If both AT commands match, then get the custom information.  */
				if (equal == TRUE)
				{
					rvf_send_trace ("ATP : Translate an AT command from text to command ",
									51,
									NULL_PARAM,
									RV_TRACE_LEVEL_DEBUG_LOW,
									ATP_USE_ID);
					*text_pp += cmd_len;
					(void) atp_get_custom_info_from_txt (text_pp,
														 ATP_AT_INFO[*cmd_nb_p][ATP_AT_PARAM_COLUMN],
														 mb_id,
														 cmd_info_pp,
														 (const char) ((port_p == NULL) ? ('\x00') : ((port_p->dce_info_p)->cr_character)));
					return (RV_OK);
				}
			}
			return (RV_NOT_SUPPORTED);
		}
	}

	/* DCE responses (See ITU-T Recommendation V.250 ter page 10).              */
	if ((cmd_type == UNKNOWN) || (cmd_type == RESULT_CODE) || \
		(cmd_type == UNSOLICITED_RESULT))
	{

		/* Declare local block variables.                                       */
		const char  *result_code_p  = NULL;
		UINT8       header_len      = 0x00;
		UINT8       result_code_len = 0x00;

		/* If verbose responses are enabled, check to see whether leading <CR>  */
		/* and <LF> characters shall be skipped in order to proceed the         */
		/* translation.                                                         */
		if ((port_p != NULL) && ((port_p->dce_info_p)->verbose_mode == ATP_VERBOSE_1))
		{
			equal = TRUE;
			equal &= ((*text_pp)[0x00] == (port_p->dce_info_p)->cr_character);
			equal &= ((*text_pp)[0x01] == (port_p->dce_info_p)->lf_character);

			/* If leading characters do not match <CR><LF> headers of           */
			/* information responses, then abort (See ETS 300 916 (GSM 07.07)   */
			/* Version 4.1 page 13).                                            */
			if (equal == FALSE)
			{
				*cmd_type_p = UNKNOWN;
				return (RV_NOT_SUPPORTED);
			}
			header_len = ATP_RESULT_CODE_HEADER_LEN;
		}
		for (*cmd_nb_p   = 0x00, \
			 *cmd_type_p = RESULT_CODE, \
			 *text_pp    += header_len;
			 *cmd_nb_p < ATP_MAX_NB_OF_RESULT_CODES;
			 (*cmd_nb_p)++)
		{

			/* If needed, skip this empty entry.                                */
			if (ATP_RESULT_CODE_INFO[*cmd_nb_p][ATP_RESULT_PARAM_COLUMN] == ATP_RESULT_CODE_NOT_DEFINED)
			{
				continue;
			}

			/* If verbose responses are disabled, then get the length of the    */
			/* result code from the dedicated list.                             */
			if ((port_p != NULL) && ((port_p->dce_info_p)->verbose_mode == ATP_VERBOSE_0))
			{
				result_code_len = (UINT8) (ATP_RESULT_CODE_INFO[*cmd_nb_p + 0x01][ATP_RESULT_OFFSET_V0_COLUMN] - ATP_RESULT_CODE_INFO[*cmd_nb_p][ATP_RESULT_OFFSET_V0_COLUMN]);
				result_code_p   = &(ATP_RESULT_CODE_TXT_TABLE_V0[ATP_RESULT_CODE_INFO[*cmd_nb_p][ATP_RESULT_OFFSET_V0_COLUMN]]);
			}
			else
			{
				result_code_len = (UINT8) (ATP_RESULT_CODE_INFO[*cmd_nb_p + 0x01][ATP_RESULT_OFFSET_V1_COLUMN] - ATP_RESULT_CODE_INFO[*cmd_nb_p][ATP_RESULT_OFFSET_V1_COLUMN]);
				result_code_p   = &(ATP_RESULT_CODE_TXT_TABLE_V1[ATP_RESULT_CODE_INFO[*cmd_nb_p][ATP_RESULT_OFFSET_V1_COLUMN]]);
			}
			ATP_MEM_I_CMP (result_code_p,
						   *text_pp,
						   result_code_len,
						   &equal);
			if (equal == FALSE)
			{
				continue;
			}
			rvf_send_trace ("ATP : Translate a result from text to command ",
							46,
							NULL_PARAM,
							RV_TRACE_LEVEL_DEBUG_LOW,
							ATP_USE_ID);
			*text_pp += result_code_len;
			switch (ATP_RESULT_CODE_INFO[*cmd_nb_p][ATP_RESULT_PARAM_COLUMN])
			{

				/* Extended syntax result code.                                 */
				case ATP_EXTENDED_RESULT_CODE:
					{

						/* Allocate memory in order to store the <value>        */
						/* associated with extended syntax result codes. If     */
						/* insufficient resources available, then report an     */
						/* internal memory error and abort.                     */
						if (rvf_get_buf (mb_id, \
										 sizeof (T_ATP_SINGLE_RESULT_CODE_VALUE), \
										 (void **) cmd_info_pp) == RVF_RED)
						{
							atp_error (ATP_ERROR_TX_MB_RED);
							return (RV_MEMORY_ERR);
						}

						/* Get the value associated with the extended result    */
						/* codes (See Headset Specification, Section 4.7.3).    */
						memset ((void *) (*cmd_info_pp),
								0x00,
								sizeof (T_ATP_SINGLE_RESULT_CODE_VALUE));
						ATP_GET_RESULT_CODE_VALUE (*text_pp,
												   &((*((T_ATP_SINGLE_RESULT_CODE_VALUE **) cmd_info_pp))->value));
						break;
					}

				/* +CME ERROR: <error> and +CMS ERROR: <error> result codes.    */
				case ATP_PLUS_ERROR_RESULT_CODE:
					{

						/* Allocate memory in order to store the <error>        */
						/* associated with +CME ERROR or +CMS ERROR result      */
						/* codes. If insufficient resources available, then     */
						/* report an internal memory error and abort.           */
						if (rvf_get_buf (mb_id, \
										 sizeof (T_ATP_PLUS_ERROR_RESULT_CODE), \
										 (void **) cmd_info_pp) == RVF_RED)
						{
							atp_error (ATP_ERROR_TX_MB_RED);
							return (RV_MEMORY_ERR);
						}

						/* Get the <error> associated with the +CME ERROR or    */
						/* +CMS ERROR result codes.                             */
						memset ((void *) (*cmd_info_pp),
								0x00,
								sizeof (T_ATP_PLUS_ERROR_RESULT_CODE));
						ATP_PLUS_ERROR_STRING (*text_pp,
											   ((T_ATP_PLUS_ERROR_RESULT_CODE *) (*cmd_info_pp))->error_p,
											   &(((T_ATP_PLUS_ERROR_RESULT_CODE *) (*cmd_info_pp))->error_length),
											   '\x00');
						break;
					}
				default:
					{

						/* Check to see if any text is associated with the      */
						/* CONNECT result code.                                 */
						if (*cmd_nb_p == ATP_CONNECT_NB)
						{

							/* Declare a local block variable.                  */
							UINT16  connect_text = 0x0000;

							/* Get the <text> associated with the CONNECT       */
							/* result codes (See ITU-T Recommendation V.250 ter */
							/* page 11).                                        */
							ATP_GET_CONNECT_TXT (*text_pp,
												 &connect_text);

							/* If no <text> is associated with the CONNECT      */
							/* result code, then abort.                         */
							if (connect_text == 0x0000)
							{
								break;
							}

							/* Otherwise, allocate memory in order to store the */
							/* <text> associated with the CONNECT result code.  */
							/* If insufficient resources available, then report */
							/* an internal memory error and abort.              */
							if (rvf_get_buf (mb_id, \
											 sizeof (T_ATP_CONNECT_TXT_PARAM), \
											 (void **) cmd_info_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								return (RV_MEMORY_ERR);
							}

							/* Return the <text> associated with the CONNECT    */
							/* result code.                                     */
							(*((T_ATP_CONNECT_TXT_PARAM **) cmd_info_pp))->value = connect_text;
							*cmd_nb_p = ATP_CONNECT_TXT_NB;
						}
						break;
					}
			}
			return (RV_OK);
		}
	}
	*cmd_type_p = UNKNOWN;
	return (RV_NOT_SUPPORTED);

} /**************** End of atp_translate_raw_data_to_cmd function ***************/


/********************************************************************************
* Function name : atp_translate_txt_to_cmd
*
* Description   : Translate a text string into an interpreted command
*
* Parameters    : text_p = text string containing the command (0-terminated)
*                 cmd_type = command type of the text
*                 cmd_type_p = type of the interpreted command
*                 cmd_nb_p = binary related code of the interpreted command
*                 mb_id = memory bank used to get the custom command information
*                         buffer
*                 cmd_info_pp = pointer on the custom command information structure
*
* Return        : RV_OK,
*                 RV_NOT_SUPPORTED if the command is not recognized,
*                 RV_INVALID_PARAMETER
*
* History       : 0.1 (25-August-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_translate_txt_to_cmd (T_ATP_TXT_CMD   text_p,
									T_ATP_CMD_TYPE  cmd_type,
									T_ATP_CMD_TYPE  *cmd_type_p,
									T_ATP_CMD_NB    *cmd_nb_p,
									T_RVF_MB_ID     mb_id,
									T_ATP_CMD       **cmd_info_pp)
{
	/* Declare a local variable.                                                */
	T_ATP_RET  ret_status = RV_OK;
		
/******************* atp_translate_txt_to_cmd function begins *******************/

	ret_status = atp_translate_raw_data_to_cmd (NULL,
												&text_p,
												cmd_type,
												cmd_type_p,
												cmd_nb_p,
												mb_id,
												cmd_info_pp);
	return (ret_status);

} /****************** End of atp_translate_txt_to_cmd function ******************/


/********************************************************************************
* Function name : atp_interpret_raw_data
*
* Description   : Fetch and interpret (if applicable and DCE mode) a new command
*                 from the raw data buffer stored available in port_structure
*
* Parameters    : port_p = pointer on the port structure
*                 mb_id = memory bank which the text buffer should be counted on
*                 cmd_type_p = found command type (if UNKNOWN, should check text
*                              field)
*                 cmd_nb_p = found command number
*                 cmd_info_p = pointer on the custom command information structure
*                 text_pp = result of interpretation: contain next command to be
*                           sent by ATP in text format (0-terminated) or NULL if
*                           no command to be sent
*                 text_length_p = length of the text command, '\x00' not included
*
* Return        : RV_MEMORY_ERR in case 'memory bank' get RED,
*                 RV_NOT_SUPPORTED if the buffer does not contain proper data,
*                 RV_OK otherwise
*
* Note          : The first data that should be checked are:
*                 (port_p->cmd_info).cmd_txt_p[(port_p->cmd_info).next_position]
*                 if (port_p->cmd_info).status = NOT_STARTED, an 'AT' should be
*                 found
*                 if the function has processed all the chain, it should set state
*                 to FINISHED
*                 (port_p->cmd_info).next_position must be updated by the function
*
* History       : 0.1 (25-August-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_interpret_raw_data (T_ATP_PORT_STRUCT	 *port_p,
								  T_RVF_MB_ID        mb_id,
								  T_ATP_CMD_TYPE     *cmd_type_p,
								  T_ATP_CMD_NB       *cmd_nb_p,
								  T_ATP_CMD          **cmd_info_pp,
								  T_ATP_TXT_CMD      *text_pp,
								  UINT16             *text_length_p)
{
	/* Declare local variables.                                                 */
	T_ATP_RET      ret_status = RV_OK;
	T_ATP_TXT_CMD  text_p     = NULL;

/******************** atp_interpret_raw_data function begins ********************/

	rvf_send_trace ("ATP : Interpret raw data ",
					25,
					NULL_PARAM,
					RV_TRACE_LEVEL_DEBUG_LOW,
					ATP_USE_ID);

	*text_pp = NULL;

	/* Interpret all AT commands or result codes.                               */
	while (((port_p->cmd_info).status == NOT_STARTED) || \
		   (((port_p->cmd_info).status == ON_GOING) && \
		   ((port_p->cmd_info).cmd_txt_p[(port_p->cmd_info).next_position] != (port_p->dce_info_p)->cr_character) && \
		   ((port_p->cmd_info).next_position < (port_p->cmd_info).cmd_txt_length)))
	{
		text_p     = &((port_p->cmd_info).cmd_txt_p[(port_p->cmd_info).next_position]);
		ret_status = atp_translate_raw_data_to_cmd (port_p,
													&text_p,
													UNKNOWN,
													cmd_type_p,
													cmd_nb_p,
													mb_id,
													cmd_info_pp);
		
		/* If any memory error occurred, then abort.                            */
		if (ret_status == RV_MEMORY_ERR)
		{
			return (RV_MEMORY_ERR);
		}
		
		/* Backup the next character to be interpreted.                         */
		(port_p->cmd_info).status        = ON_GOING;
		(port_p->cmd_info).next_position = (UINT16) (text_p - (port_p->cmd_info).cmd_txt_p);
		
		/* Intrepret the extracted command.                                     */
		switch (*cmd_type_p)
		{
			
			/* Interpret the extracted AT command.                              */
			case AT_CMD:
				{

					/* Interpret AT commands only if ATP is acting as a DCE.	*/
					if (port_p->port_config != DCE_CONFIG)
					{
						break;
					}

					/* Set the result of interpretation to NULL.                */
					*text_pp = NULL;
					switch (*cmd_nb_p)
					{
						
						/* Answer. Note that any additional commands that       */
						/* appear after A on the same command line are ignored  */
						/* (See ITU-T Recommendation V.250 ter page 35).        */
						case ATP_ATA_NB:
						
						/* Dial. Note that all characters appearing on the same */
						/* command line after D are considered part of the call */
						/* addressing information to be signalled to the        */
						/* network, or modifiers used to control the signalling */
						/* process, up to a semicolon character or the end of   */
						/* the command line (See ITU-T Recommendation V.250 ter */
						/* page 31). Note also that the ITU-T Recommendation    */
						/* V.250 ter does not describe DCE behaviour in some    */
						/* situations. Thus, additional characters that appear  */
						/* on the same command line after a semicolon that      */
						/* terminates dial string are either ignored or         */
						/* processed as commands (See ITU-T Recommendation      */
						/* V.250 ter page 14). In our implementation, such      */
						/* additional characters are ignored.                   */
						case ATP_ATD_NB:
						
						/* Reset to default configuration. Note that any        */
						/* additional commands that appear on the same command  */
						/* line after Z are ignored (See ITU-T Recommendation   */
						/* V.250 ter page  15).                                 */
						case ATP_ATZ_NB:
							{
								(port_p->cmd_info).next_position = (port_p->cmd_info).cmd_txt_length;
								break;
							}
						
						/* Command echo.                                        */
						case ATP_ATE_NB:
							{
								
								/* Check to see if the specified value is valid */
								/* (See ITU-T Recommendation V.250 ter page     */
								/* 23).                                         */
								if (((*((T_ATP_ATE_PARAM **) cmd_info_pp))->number != ECHO_OFF) && \
									((*((T_ATP_ATE_PARAM **) cmd_info_pp))->number != ECHO_ON))
								{
									rvf_send_trace ("ATP : Command echo value invalid ",
													33,
													NULL_PARAM,
													RV_TRACE_LEVEL_WARNING,
													ATP_USE_ID);
									rvf_free_buf (*cmd_info_pp);
									*cmd_info_pp = NULL;
									return (RV_NOT_SUPPORTED);
								}
								rvf_send_trace ("ATP : Command echo updated ",
												27,
												NULL_PARAM,
												RV_TRACE_LEVEL_DEBUG_LOW,
												ATP_USE_ID);
								(port_p->dce_info_p)->echo_mode = (*((T_ATP_ATE_PARAM **) cmd_info_pp))->number;
								*cmd_type_p                     = UNKNOWN;
								rvf_free_buf (*cmd_info_pp);
								*cmd_info_pp = NULL;
								
								/* Interpret the next AT command or result code */
								/* to come.                                     */
								continue;
							}
							
						/* Result code suppression.                             */
						case ATP_ATQ_NB:
							{
								
								/* Check to see if the specified value is valid */
								/* (See ITU-T Recommendation V.250 ter page     */
								/* 23).                                         */
								if (((*((T_ATP_ATQ_PARAM **) cmd_info_pp))->number != RESULT_CODE_ON) && \
									((*((T_ATP_ATQ_PARAM **) cmd_info_pp))->number != RESULT_CODE_OFF))
								{
									rvf_send_trace ("ATP : Result code suppression value invalid ",
													44,
													NULL_PARAM,
													RV_TRACE_LEVEL_WARNING,
													ATP_USE_ID);
									rvf_free_buf (*cmd_info_pp);
									*cmd_info_pp = NULL;
									return (RV_NOT_SUPPORTED);
								}
								rvf_send_trace ("ATP : Result code suppression updated ",
												38,
												NULL_PARAM,
												RV_TRACE_LEVEL_DEBUG_LOW,
												ATP_USE_ID);
								(port_p->dce_info_p)->result_code_mode = (*((T_ATP_ATQ_PARAM **) cmd_info_pp))->number;
								*cmd_type_p                            = UNKNOWN;
								rvf_free_buf (*cmd_info_pp);
								*cmd_info_pp = NULL;
								
								/* Interpret the next AT command or result code */
								/* to come.                                     */
								continue;
							}
							
						/* DCE response format.                                 */
						case ATP_ATV_NB:
							{
								
								/* Check to see if the specified value is valid */
								/* (See ITU-T Recommendation V.250 ter page     */
								/* 24).                                         */
								if (((*((T_ATP_ATV_PARAM **) cmd_info_pp))->number != ATP_VERBOSE_0) && \
									((*((T_ATP_ATV_PARAM **) cmd_info_pp))->number != ATP_VERBOSE_1))
								{
									rvf_send_trace ("ATP : DCE response format value invalid ",
													40,
													NULL_PARAM,
													RV_TRACE_LEVEL_WARNING,
													ATP_USE_ID);
									rvf_free_buf (*cmd_info_pp);
									*cmd_info_pp = NULL;
									return (RV_NOT_SUPPORTED);
								}
								rvf_send_trace ("ATP : DCE response format updated ",
												34,
												NULL_PARAM,
												RV_TRACE_LEVEL_DEBUG_LOW,
												ATP_USE_ID);
								(port_p->dce_info_p)->verbose_mode = (*((T_ATP_ATV_PARAM **) cmd_info_pp))->number;
								*cmd_type_p                        = UNKNOWN;
								rvf_free_buf (*cmd_info_pp);
								*cmd_info_pp = NULL;
								
								/* Interpret the next AT command or result code */
								/* to come.                                     */
								continue;
							}
							
						/* Command line termination character.                  */
						case ATP_ATS3_NB:
							{
								
								/* Check to see if the specified value is valid */
								/* (See ITU-T Recommendation V.250 ter pages 21 */
								/* and 22).                                     */
								if ((((*((T_ATP_ATS3_PARAM **) cmd_info_pp))->s_operator != READ_S_PARAM) && \
									((*((T_ATP_ATS3_PARAM **) cmd_info_pp))->s_operator != SET_S_PARAM)) || \
									((*((T_ATP_ATS3_PARAM **) cmd_info_pp))->value > 0x007F))
								{
									rvf_send_trace ("ATP : Command line termination character invalid ",
													49,
													NULL_PARAM,
													RV_TRACE_LEVEL_WARNING,
													ATP_USE_ID);
									rvf_free_buf (*cmd_info_pp);
									*cmd_info_pp = NULL;
									return (RV_NOT_SUPPORTED);
								}
								rvf_send_trace ("ATP : Command line termination character updated ",
												49,
												NULL_PARAM,
												RV_TRACE_LEVEL_DEBUG_LOW,
												ATP_USE_ID);
								
								/* Check to see if the S-parameter is requested */
								/* to be set to a new value.                    */
								if ((*((T_ATP_ATS3_PARAM **) cmd_info_pp))->s_operator == SET_S_PARAM)
								{
									(port_p->dce_info_p)->cr_character = (char) ((*((T_ATP_ATS3_PARAM **) cmd_info_pp))->value);
									*cmd_type_p                        = UNKNOWN;
									rvf_free_buf (*cmd_info_pp);
									*cmd_info_pp = NULL;
									
									/* Interpret the next AT command or result  */
									/* code to come.                            */
									continue;
								}
								break;
							}
							
						/* Response formatting character.                       */
						case ATP_ATS4_NB:
							{
								
								/* Check to see if the specified value is valid */
								/* (See ITU-T Recommendation V.250 ter page     */
								/* 22).                                         */
								if ((((*((T_ATP_ATS4_PARAM **) cmd_info_pp))->s_operator != READ_S_PARAM) && \
									((*((T_ATP_ATS4_PARAM **) cmd_info_pp))->s_operator != SET_S_PARAM)) || \
									((*((T_ATP_ATS4_PARAM **) cmd_info_pp))->value > 0x007F))
								{
									rvf_send_trace ("ATP : Response formatting character invalid ",
													44,
													NULL_PARAM,
													RV_TRACE_LEVEL_WARNING,
													ATP_USE_ID);
									rvf_free_buf (*cmd_info_pp);
									*cmd_info_pp = NULL;
									return (RV_NOT_SUPPORTED);
								}
								rvf_send_trace ("ATP : Response formatting character updated ",
												44,
												NULL_PARAM,
												RV_TRACE_LEVEL_DEBUG_LOW,
												ATP_USE_ID);
								
								/* Check to see if the S-parameter is requested */
								/* to be set to a new value.                    */
								if ((*((T_ATP_ATS4_PARAM **) cmd_info_pp))->s_operator == SET_S_PARAM)
								{
									(port_p->dce_info_p)->lf_character = (char) ((*((T_ATP_ATS4_PARAM **) cmd_info_pp))->value);
									*cmd_type_p                        = UNKNOWN;
									rvf_free_buf (*cmd_info_pp);
									*cmd_info_pp = NULL;
									
									/* Interpret the next AT command or result  */
									/* code to come.                            */
									continue;
								}
								break;
							}
							
						/* Command line editing character.                      */
						case ATP_ATS5_NB:
							{
								
								/* Check to see if the specified value is valid */
								/* (See ITU-T Recommendation V.250 ter page     */
								/* 22).                                         */
								if ((((*((T_ATP_ATS5_PARAM **) cmd_info_pp))->s_operator != READ_S_PARAM) && \
									((*((T_ATP_ATS5_PARAM **) cmd_info_pp))->s_operator != SET_S_PARAM)) || \
									((*((T_ATP_ATS5_PARAM **) cmd_info_pp))->value > 0x007F))
								{
									rvf_send_trace ("ATP : Command line editing character invalid ",
													45,
													NULL_PARAM,
													RV_TRACE_LEVEL_WARNING,
													ATP_USE_ID);
									rvf_free_buf (*cmd_info_pp);
									*cmd_info_pp = NULL;
									return (RV_NOT_SUPPORTED);
								}
								rvf_send_trace ("ATP : Command line editing character updated ",
												45,
												NULL_PARAM,
												RV_TRACE_LEVEL_DEBUG_LOW,
												ATP_USE_ID);
								
								/* Check to see if the S-parameter is requested */
								/* to be set to a new value.                    */
								if ((*((T_ATP_ATS5_PARAM **) cmd_info_pp))->s_operator == SET_S_PARAM)
								{
									(port_p->dce_info_p)->bs_character = (char) ((*((T_ATP_ATS5_PARAM **) cmd_info_pp))->value);
									*cmd_type_p                        = UNKNOWN;
									rvf_free_buf (*cmd_info_pp);
									*cmd_info_pp = NULL;
									
									/* Interpret the next AT command or result  */
									/* code to come.                            */
									continue;
								}
								break;
							}

						/* AT command not recognized.                           */
						case ATP_MAX_NB_OF_AT_COMMANDS:
							{

								/* Get the length of the AT command to be       */
								/* returned, '\x00' not included.               */
								ATP_GET_UNKNOWN_AT_CMD_LEN (text_p,
															text_length_p,
															(port_p->dce_info_p)->cr_character);

								/* Allocate memory in order to return the AT    */
								/* command ('\x00' included). Note that the     */
								/* prefix must be taken into account. If        */
								/* insufficient resources available, then       */
								/* report an internal memory error and abort.   */
								if (rvf_get_buf (mb_id, \
												 ATP_AT_PREFIX_LEN + *text_length_p + 0x0001, \
												 (void **) text_pp) == RVF_RED)
								{
									atp_error (ATP_ERROR_TX_MB_RED);
									ret_status = RV_MEMORY_ERR;
									break;
								}

								/* Copy the prefix into the buffer (See ITU-T   */
								/* Recommendation V.250 ter page 4).            */
								memcpy ((void *) *text_pp,
										ATP_AT_PREFIX,
										ATP_AT_PREFIX_LEN);

								/* Then, copy the command line body into the    */
								/* buffer.                                      */
								memcpy ((void *) &((*text_pp)[ATP_AT_PREFIX_LEN]),
										(void *) text_p,
										*text_length_p);
								(*text_pp)[*text_length_p + ATP_AT_PREFIX_LEN] = '\x00';
								text_p                                         += *text_length_p;
								break;
							}

						/* Other recognized AT commands.                        */
						default:
							{
								break;
							}
					}

					/* If the extracted AT command is an extended syntax        */
					/* command, then update the position of the next character  */
					/* to be interpreted.                                       */
					switch (ATP_AT_INFO[*cmd_nb_p][ATP_AT_PARAM_COLUMN])
					{

						/* AT command undefined or not supported for now.       */
						case ATP_CMD_NOT_DEFINED:

						/* Extended syntax command does not expect any <value>. */
						case ATP_NO_EXTENDED_PARAM:

						/* Extended syntax command whose subparameter is a      */
						/* numeric constant.                                    */
						case ATP_SINGLE_EXTENDED_PARAM:

						/* Keypad control command.                              */
						case ATP_PLUS_CKPD_PARAM:
							{
								text_p                           += ((*text_p == (port_p->dce_info_p)->cr_character) ? (0x0000) : (0x0001));
								(port_p->cmd_info).next_position = (UINT16) (text_p - (port_p->cmd_info).cmd_txt_p);
							}
						default:
							{
								break;
							}
					}
					break;
				}

			/* Return raw data as received.									    */
			case UNKNOWN:
				{

					/* Get the length of raw data to be returned, '\x00' not    */
					/* included.                                                */
					ATP_GET_UNKNOWN_CMD_LEN (text_p,
											 text_length_p,
											 (port_p->dce_info_p)->cr_character);

					/* Allocate memory in order to return raw data ('\x00'      */
					/* included). If insufficient resources available, then     */
					/* report an internal memory error and abort.               */
					if (rvf_get_buf (mb_id, \
									 *text_length_p + 0x0001, \
									 (void **) text_pp) == RVF_RED)
					{
						atp_error (ATP_ERROR_TX_MB_RED);
						ret_status = RV_MEMORY_ERR;
						break;
					}

					/* Copy raw data into the buffer.                           */
					memcpy ((void *) *text_pp,
							(void *) text_p,
							*text_length_p);
					(*text_pp)[*text_length_p] = '\x00';
					text_p                     += *text_length_p;

					/* Backup the next character to be interpreted.             */
					(port_p->cmd_info).next_position = (UINT16) (text_p - (port_p->cmd_info).cmd_txt_p);
					break;
				}

			/* Else, result codes not supported.                                */
			case RESULT_CODE:
			case UNSOLICITED_RESULT:
			default:
				{
					break;
				}
		}
		break;
	}

	/* Then, check to see whether the interpretation is over.                   */
	if (((port_p->cmd_info).cmd_txt_p[(port_p->cmd_info).next_position] == (port_p->dce_info_p)->cr_character) || \
		((port_p->cmd_info).next_position >= (port_p->cmd_info).cmd_txt_length))
	{
		(port_p->cmd_info).status = FINISHED;
	}
	return (RV_OK);

} /******************* End of atp_interpret_raw_data function *******************/


/********************************************************************************
* Function name	: atp_translate_cmd_to_txt
*
* Description   : Translate a command in interpreted format to text format. Buffer 
*                 containing the command is assumed to be BTF buffer and is freed
*                 by this function. Text buffer is a BTF buffer
*
* Parameters    : cmd_type = type of the command (AT_CMD, RESULT_CODE and 
*                 UNSOLICITED_RESULT)
*                 cmd_nb = binary related code
*                 cmd_info_p = pointer on the custom command information structure
*                 mb_id = memory bank used to get the text buffer
*                 text_pp = pointer on the text chain (0-terminated)
*                 text_length_p = length of the text chain, '\x00' not included
*
* Return        : RV_OK,
*                 RV_NOT_SUPPORTED if the command is not recognized
*
* History       : 0.1 (25-August-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_translate_cmd_to_txt (T_ATP_CMD_TYPE  cmd_type,
									T_ATP_CMD_NB    cmd_nb,
									T_ATP_CMD       *cmd_info_p,
									T_RVF_MB_ID     mb_id,
									T_ATP_TXT_CMD   *text_pp,
									UINT16          *text_length_p)
{
    /* Declare local variables.                                                 */
	const char  *table     = NULL;
	UINT16      offset     = 0x0000;
	T_ATP_RET   ret_status = RV_OK;
	
/******************* atp_translate_cmd_to_txt function begins *******************/

	switch (cmd_type)
	{

		/* Translate AT commands into text.                                     */
		case AT_CMD:
			{
				rvf_send_trace ("ATP : Translate an AT command into text ",
								40,
								NULL_PARAM,
								RV_TRACE_LEVEL_DEBUG_LOW,
								ATP_USE_ID);
				table = ATP_AT_TXT_TABLE;

				/* Get the related offset.                                      */
				offset = ATP_AT_INFO[cmd_nb][ATP_AT_OFFSET_COLUMN];

				/* Get the length of the AT command.                            */
				*text_length_p = (UINT16) (ATP_AT_PREFIX_LEN + \
										   ATP_AT_INFO[cmd_nb + 0x01][ATP_AT_OFFSET_COLUMN] - ATP_AT_INFO[cmd_nb][ATP_AT_OFFSET_COLUMN]);

				/* Get the related structure.                                   */
				switch (ATP_AT_INFO[cmd_nb][ATP_AT_PARAM_COLUMN])
				{

					/* Basic syntax command does not expect any <number>.       */
					case ATP_NO_PARAM:
						{

							/* Create a buffer and copy text string into it     */
							/* ('\x00' included). If insufficient resources     */
							/* available, then report an internal memory error  */
							/* and abort.                                       */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + 0x0001, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}
	
							/* Copy the command line prefix into the buffer.    */
							memcpy ((void *) (*text_pp),
									ATP_AT_PREFIX,
									ATP_AT_PREFIX_LEN);

							/* Copy the text into the buffer.                   */
							memcpy ((void *) &((*text_pp)[ATP_AT_PREFIX_LEN]),
									(void *) &(table[offset]),
									*text_length_p - ATP_AT_PREFIX_LEN);
							(*text_pp)[*text_length_p] = '\x00';
							break;
						}

					/* Basic syntax command.                                    */
					case ATP_BASIC_PARAM:
						{

							/* Declare a local block variable.                  */
							T_ATP_BASIC_CMD  *basic_cmd_param_p = (T_ATP_BASIC_CMD *) cmd_info_p;

							/* Create a buffer and copy text string into it     */
							/* ('\x00' included). If insufficient resources     */
							/* available, then report an internal memory error  */
							/* and abort.                                       */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + MAX_BASIC_CMD_PARAM_LEN + 0x0001, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}
	
							/* Copy the command line prefix into the buffer.    */
							memcpy ((void *) (*text_pp),
									ATP_AT_PREFIX,
									ATP_AT_PREFIX_LEN);

							/* Copy the text into the buffer.                   */
							memcpy ((void *) &((*text_pp)[ATP_AT_PREFIX_LEN]),
									(void *) &(table[offset]),
									*text_length_p - ATP_AT_PREFIX_LEN);

							/* If needed, copy the buffer describing the        */
							/* command in interpreted format and free it.       */
							if (basic_cmd_param_p != NULL)
							{
								*text_length_p = (UINT16) (*text_length_p + \
														   dtoa (basic_cmd_param_p->number,
																 &((*text_pp)[*text_length_p])));
							}
							(*text_pp)[*text_length_p] = '\x00';
							break;
						}

					/* Dial.                                                    */
					case ATP_DIAL_PARAM:
						{

							/* Declare local block variables.                   */
							UINT8       dial_param_length = 0x00;
							UINT8       dial_semicolon    = DATA_CALL;
							T_ATP_DIAL  *dial_param_p     = (T_ATP_DIAL *) cmd_info_p;

							/* If needed, take the buffer describing the        */
							/* command in interpreted format into account.      */
							if (dial_param_p != NULL)
							{
								dial_param_length = dial_param_p->dial_string_length;
								dial_semicolon    = (UINT8) (dial_param_p->call_type);
							}

							/* Create a buffer and copy text string into it     */
							/* ('\x00' included). If insufficient resources     */
							/* available, then report an internal memory error  */
							/* and abort.                                       */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + dial_param_length + dial_semicolon + 0x0001, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}
	
							/* Copy the command line prefix into the buffer.    */
							memcpy ((void *) (*text_pp),
									ATP_AT_PREFIX,
									ATP_AT_PREFIX_LEN);

							/* Copy the text into the buffer.                   */
							memcpy ((void *) &((*text_pp)[ATP_AT_PREFIX_LEN]),
									(void *) &(table[offset]),
									*text_length_p - ATP_AT_PREFIX_LEN);

							/* If needed, copy the buffer describing the        */
							/* command in interpreted format and free it.       */
							if (dial_param_p != NULL)
							{
								memcpy ((void *) &((*text_pp)[*text_length_p]),
										(void *) (dial_param_p->dial_string_p),
										dial_param_length);
								if (dial_semicolon == VOICE_CALL)
								{
									(*text_pp)[*text_length_p + dial_param_length] = ';';
								}
								*text_length_p = (UINT16) (*text_length_p + \
														   dial_param_length + dial_semicolon);
							}
							(*text_pp)[*text_length_p] = '\x00';
							break;
						}

					/* S-parameter.                                             */
					case ATP_S_PARAM:
						{

							/* Declare a local block variable.                  */
							T_ATP_S_PARAM  *s_param_p = (T_ATP_S_PARAM *) cmd_info_p;

							/* Create a buffer and copy text string into it     */
							/* ('\x00' included). If insufficient resources     */
							/* available, then report an internal memory error  */
							/* and abort.                                       */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + MAX_S_PARAM_LEN + 0x0001,
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}
	
							/* Copy the command line prefix into the buffer.    */
							memcpy ((void *) (*text_pp),
									ATP_AT_PREFIX,
									ATP_AT_PREFIX_LEN);

							/* Copy the text into the buffer.                   */
							memcpy ((void *) &((*text_pp)[ATP_AT_PREFIX_LEN]),
									(void *) &(table[offset]),
									*text_length_p - ATP_AT_PREFIX_LEN);

							/* If needed, copy the buffer describing the        */
							/* command in interpreted format and free it.       */
							if (s_param_p == NULL)
							{
								(*text_pp)[*text_length_p] = '\x00';
								break;
							}
							switch (s_param_p->s_operator)
							{

								/* Parameter read command syntax.               */
								case READ_S_PARAM:
									{
										(*text_pp)[(*text_length_p)++] = '?';
										(*text_pp)[*text_length_p]     = '\x00';
										break;
									}

								/* Parameter set command syntax.                */
								case SET_S_PARAM:
									{
										(*text_pp)[(*text_length_p)++] = '=';
										*text_length_p = (UINT16) (*text_length_p + \
																   dtoa (s_param_p->value,
																		 &((*text_pp)[*text_length_p])));
										(*text_pp)[*text_length_p] = '\x00';
										break;
									}
								default:
									{
										rvf_free_buf (*text_pp);
										*text_pp   = NULL;
										ret_status = RV_NOT_SUPPORTED;
										break;
									}
							}
							break;
						}

					/* Extended syntax command does not expect any <value>.     */
					case ATP_NO_EXTENDED_PARAM:
						{

							/* Declare a local block variable.                  */
							T_ATP_NO_SUBPARAMETER  *extended_cmd_param_p = (T_ATP_NO_SUBPARAMETER *) cmd_info_p;

							/* Create a buffer and copy text string into it     */
							/* ('\x00' included). If insufficient resources     */
							/* available, then report an internal memory error  */
							/* and abort.                                       */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + MAX_NO_SUBPARAMETER_LEN + 0x0001, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}
	
							/* Copy the command line prefix into the buffer.    */
							memcpy ((void *) (*text_pp),
									ATP_AT_PREFIX,
									ATP_AT_PREFIX_LEN);

							/* Copy the text into the buffer.                   */
							memcpy ((void *) &((*text_pp)[ATP_AT_PREFIX_LEN]),
									(void *) &(table[offset]),
									*text_length_p - ATP_AT_PREFIX_LEN);

							/* If needed, copy the buffer describing the        */
							/* command in interpreted format and free it.       */
							if (extended_cmd_param_p == NULL)
							{
								(*text_pp)[*text_length_p] = '\x00';
								break;
							}
							switch (extended_cmd_param_p->extended_operator)
							{

								/* No subparameter.                             */
								case NO_SUBPARAMETER:
									{
										(*text_pp)[*text_length_p] = '\x00';
										break;
									}

								/* Action test command syntax.                  */
								case TEST_EXTENDED_CMD:
									{
										(*text_pp)[(*text_length_p)++] = '=';
										(*text_pp)[(*text_length_p)++] = '?';
										(*text_pp)[*text_length_p]     = '\x00';
										break;
									}
								default:
									{
										rvf_free_buf (*text_pp);
										*text_pp   = NULL;
										ret_status = RV_NOT_SUPPORTED;
										break;
									}
							}
							break;
						}

					/* Extended syntax command whose subparameter is a numeric  */
					/* constant.                                                */
					case ATP_SINGLE_EXTENDED_PARAM:
						{

							/* Declare a local block variable.                  */
							T_ATP_SINGLE_SUBPARAMETER  *extended_cmd_param_p = (T_ATP_SINGLE_SUBPARAMETER *) cmd_info_p;

							/* Create a buffer and copy text string into it     */
							/* ('\x00' included). If insufficient resources     */
							/* available, then report an internal memory error  */
							/* and abort.                                       */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + MAX_SINGLE_SUBPARAMETER_LEN + 0x0001, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}
	
							/* Copy the command line prefix into the buffer.    */
							memcpy ((void *) (*text_pp),
									ATP_AT_PREFIX,
									ATP_AT_PREFIX_LEN);

							/* Copy the text into the buffer.                   */
							memcpy ((void *) &((*text_pp)[ATP_AT_PREFIX_LEN]),
									(void *) &(table[offset]),
									*text_length_p - ATP_AT_PREFIX_LEN);

							/* If needed, copy the buffer describing the        */
							/* command in interpreted format and free it.       */
							if (extended_cmd_param_p == NULL)
							{
								(*text_pp)[*text_length_p] = '\x00';
								break;
							}
							switch (extended_cmd_param_p->extended_operator)
							{

								/* No subparameter.                             */
								case NO_SUBPARAMETER:
									{
										(*text_pp)[*text_length_p] = '\x00';
										break;
									}

								/* Action test command syntax.                  */
								case TEST_EXTENDED_CMD:
									{
										(*text_pp)[(*text_length_p)++] = '=';
									}

								/* Parameter read command syntax.               */
								case READ_EXTENDED_CMD:
									{
										(*text_pp)[(*text_length_p)++] = '?';
										(*text_pp)[*text_length_p]     = '\x00';
										break;
									}

								/* Parameter set command syntax.                */
								case SET_EXTENDED_CMD:
									{
										(*text_pp)[(*text_length_p)++] = '=';
										*text_length_p = (UINT16) (*text_length_p + \
																   dtoa (extended_cmd_param_p->value,
																		 &((*text_pp)[*text_length_p])));
										(*text_pp)[*text_length_p] = '\x00';
										break;
									}
								default:
									{
										rvf_free_buf (*text_pp);
										*text_pp   = NULL;
										ret_status = RV_NOT_SUPPORTED;
										break;
									}
							}
							break;
						}

					/* Keypad control command. Note that <keys> is a string of  */
					/* characters representing keys (See See ETS 300 916 (GSM   */
					/* 07.07) Version 5.8.1 page 62). Colon character followed  */
					/* by one character can be used to indicate a manufacturer  */
					/* specific key not listed here. All characters from a      */
					/* semicolon character to the next single semicolon         */
					/* character are treated as alpha entries and are not       */
					/* converted to key equivalents. All semicolon characters   */
					/* inside alpha entries should be duplicated in the DTE.    */
					/* Pause characters "W" and "w" can be used to pause        */
					/* between key pressings for a time specified by <pause>.   */
					case ATP_PLUS_CKPD_PARAM:
						{

							/* Declare local block variables.                   */
							UINT8            nb_keypressed = 0x00;
							T_ATP_PLUS_CKPD  *ckpd_param_p = (T_ATP_PLUS_CKPD *) cmd_info_p;

							/* Create a buffer and copy text string into it     */
							/* ('\x00' included). If insufficient resources     */
							/* available, then report an internal memory error  */
							/* and abort.                                       */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + MAX_CKPD_PARAM_LEN + 0x0001, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}

							/* Copy the command line prefix into the buffer.    */
							memcpy ((void *) (*text_pp),
									ATP_AT_PREFIX,
									ATP_AT_PREFIX_LEN);

							/* Copy the text into the buffer.                   */
							memcpy ((void *) &((*text_pp)[ATP_AT_PREFIX_LEN]),
									(void *) &(table[offset]),
									*text_length_p - ATP_AT_PREFIX_LEN);

							/* If needed, copy the buffer describing the        */
							/* command in interpreted format and free it.       */
							if (ckpd_param_p == NULL)
							{
								(*text_pp)[*text_length_p] = '\x00';
								break;
							}
							switch (ckpd_param_p->extended_operator)
							{

								/* Action test command syntax.                  */
								case TEST_EXTENDED_CMD:
									{
										(*text_pp)[(*text_length_p)++] = '=';
										(*text_pp)[(*text_length_p)++] = '?';
										(*text_pp)[*text_length_p]     = '\x00';
										break;
									}

								/* Parameter set command syntax.                */
								case SET_EXTENDED_CMD:
									{
										(*text_pp)[(*text_length_p)++] = '=';
										(*text_pp)[(*text_length_p)++] = '"';

										/* Store each keypressed into the       */
										/* buffer.                              */
										for (nb_keypressed = 0x00;
											 nb_keypressed < ckpd_param_p->nb_keys;
											 nb_keypressed++)
										{
											(*text_pp)[(*text_length_p)++] = ';';
											*text_length_p = (UINT16) (*text_length_p + \
																	   dtoa (ckpd_param_p->keys[nb_keypressed],
																			 &((*text_pp)[*text_length_p])));
											(*text_pp)[(*text_length_p)++] = ';';
										}
										(*text_pp)[(*text_length_p)++] = '"';

										/* Store <time> subparameter into the   */
										/* buffer.                              */
										(*text_pp)[(*text_length_p)++] = ',';
										if ((ckpd_param_p->pause != DEFAULT_TIME) || \
											(ckpd_param_p->pause != TIME_DO_NOT_CARE))
										{
											*text_length_p = (UINT16) (*text_length_p + \
																	   dtoa (ckpd_param_p->time,
																			 &((*text_pp)[*text_length_p])));
										}

										/* Store <pause> subparameter into the  */
										/* buffer.                              */
										(*text_pp)[(*text_length_p)++] = ',';
										if ((ckpd_param_p->pause != DEFAULT_PAUSE) || \
											(ckpd_param_p->pause != PAUSE_DO_NOT_CARE))
										{
											*text_length_p = (UINT16) (*text_length_p + \
																	   dtoa (ckpd_param_p->pause,
																			 &((*text_pp)[*text_length_p])));
										}
										(*text_pp)[*text_length_p] = '\x00';
										break;
									}
								default:
									{
										rvf_free_buf (*text_pp);
										*text_pp   = NULL;
										ret_status = RV_NOT_SUPPORTED;
										break;
									}
							}
							break;
						}
					default:
						{
							rvf_send_trace ("ATP : Received an unknown command ",
											34,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							*text_pp   = NULL;
							ret_status = RV_NOT_SUPPORTED;
							break;
						}
				}
				break;
			}

		/* Translate DCE responses into text (See ITU-T Recommendation V.250    */
		/* ter page 10).                                                        */
		case RESULT_CODE:
		case UNSOLICITED_RESULT:
			{
				rvf_send_trace ("ATP : Translate a result into text ",
								35,
								NULL_PARAM,
								RV_TRACE_LEVEL_DEBUG_LOW,
								ATP_USE_ID);
				table = ATP_RESULT_CODE_TXT_TABLE_V1;

				/* Get the related offset.                                      */
				offset = ATP_RESULT_CODE_INFO[cmd_nb][ATP_RESULT_OFFSET_V1_COLUMN];

				/* Get the length of the result code.                           */
				*text_length_p = (UINT16) (ATP_RESULT_CODE_INFO[cmd_nb + 0x01][ATP_RESULT_OFFSET_V1_COLUMN] - ATP_RESULT_CODE_INFO[cmd_nb][ATP_RESULT_OFFSET_V1_COLUMN]);

				/* Get the related structure.                                   */
				switch (ATP_RESULT_CODE_INFO[cmd_nb][ATP_RESULT_PARAM_COLUMN])
				{

					/* Basic syntax result code.                                */
					case ATP_BASIC_RESULT_CODE:
						{

							/* Create a buffer and copy text string into it     */
							/* ('\x00' included). If insufficient resources     */
							/* available, then report an internal memory error  */
							/* and abort.                                       */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + 0x0001, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}

							/* Copy text into the buffer.                       */
							memcpy ((void *) (*text_pp),
									(void *) &(table[offset]),
									*text_length_p);
							(*text_pp)[*text_length_p] = '\x00';
							break;
						}

					/* Extended syntax result code.                             */
					case ATP_EXTENDED_RESULT_CODE:
						{

							/* Declare a local block variable.                  */
							T_ATP_SINGLE_RESULT_CODE_VALUE  *result_code_param_p = (T_ATP_SINGLE_RESULT_CODE_VALUE *) cmd_info_p;

							/* Create a buffer and copy text string into it     */
							/* ('=' and '\x00' included). If insufficient       */
							/* resources available, then report an internal     */
							/* memory error and abort.                          */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + MAX_SINGLE_RESULT_CODE_VALUE_LEN + 0x0002, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}

							/* Copy text into the buffer.                       */
							memcpy ((void *) (*text_pp),
									(void *) &(table[offset]),
									*text_length_p);

							/* If needed, copy the buffer describing the        */
							/* command in interpreted format and free it.       */
							if (result_code_param_p != NULL)
							{
								(*text_pp)[(*text_length_p)++] = '=';
								*text_length_p = (UINT16) (*text_length_p + \
														   dtoa (result_code_param_p->value,
																 &((*text_pp)[*text_length_p])));
							}
							(*text_pp)[*text_length_p] = '\x00';
							break;
						}

					/* CONNECT <text> result code.                              */
					case ATP_CONNECT_TXT_PARAM:
						{

							/* Declare a local block variable.                  */
							T_ATP_CONNECT_TXT_PARAM  *connect_txt_param_p = (T_ATP_CONNECT_TXT_PARAM *) cmd_info_p;

							/* Create a buffer and copy text string into it     */
							/* (' ' and '\x00' included). If insufficient       */
							/* resources available, then report an internal     */
							/* memory error and abort.                          */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + MAX_CONNECT_TXT_LEN + 0x0002, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}

							/* Copy text into the buffer.                       */
							memcpy ((void *) (*text_pp),
									(void *) &(table[offset]),
									*text_length_p);

							/* If needed, copy the buffer describing the        */
							/* command in interpreted format and free it.       */
							if (connect_txt_param_p != NULL)
							{
								(*text_pp)[(*text_length_p)++] = ' ';
								*text_length_p = (UINT16) (*text_length_p + \
														   dtoa (connect_txt_param_p->value,
																 &((*text_pp)[*text_length_p])));
							}
							(*text_pp)[*text_length_p] = '\x00';
							break;
						}

					/* +CME ERROR: <error> and +CMS ERROR: <error> result       */
					/* codes.                                                   */
					case ATP_PLUS_ERROR_RESULT_CODE:
						{

							/* Declare local block variables.                   */
							UINT8                         error_length              = 0x00;
							T_ATP_PLUS_ERROR_RESULT_CODE  *plus_error_result_code_p = cmd_info_p;

							/* If needed, take the buffer describing the        */
							/* command in interpreted format into account.      */
							if (plus_error_result_code_p != NULL)
							{
								error_length = plus_error_result_code_p->error_length;
							}

							/* Create a buffer and copy text string into it     */
							/* (' ' and '\x00' included). If insufficient       */
							/* resources available, then report an internal     */
							/* memory error and abort.                          */
							if (rvf_get_buf (mb_id, \
											 *text_length_p + error_length + 0x0002, \
											 (void **) text_pp) == RVF_RED)
							{
								atp_error (ATP_ERROR_TX_MB_RED);
								ret_status = RV_MEMORY_ERR;
								break;
							}
	
							/* Copy the command line prefix into the buffer.    */
							memcpy ((void *) (*text_pp),
									ATP_AT_PREFIX,
									ATP_AT_PREFIX_LEN);

							/* Copy the text into the buffer.                   */
							memcpy ((void *) &((*text_pp)[ATP_AT_PREFIX_LEN]),
									(void *) &(table[offset]),
									*text_length_p - ATP_AT_PREFIX_LEN);

							/* If needed, copy the buffer describing the        */
							/* command in interpreted format and free it.       */
							if (plus_error_result_code_p != NULL)
							{
								(*text_pp)[(*text_length_p)++] = ' ';
								memcpy ((void *) &((*text_pp)[*text_length_p]),
										(void *) (plus_error_result_code_p->error_p),
										error_length);
								*text_length_p = (UINT16) (*text_length_p + \
														   error_length);
							}
							(*text_pp)[*text_length_p] = '\x00';
							break;
						}
					default:
						{
							rvf_send_trace ("ATP : Received an unknown command ",
											34,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							*text_pp   = NULL;
							ret_status = RV_NOT_SUPPORTED;
							break;
						}
				}
				break;
			}
		default:
			{
				rvf_send_trace ("ATP : Received an unknown command ",
								34,
								NULL_PARAM,
								RV_TRACE_LEVEL_WARNING,
								ATP_USE_ID);
				*text_pp   = NULL;
				ret_status = RV_NOT_SUPPORTED;
				break;
			}
	}

	/* If needed, free the buffer describing the command in interpreted format. */
	if (cmd_info_p != NULL)
	{
		rvf_free_buf (cmd_info_p);
		cmd_info_p = NULL;
	}
	return (ret_status);

} /****************** End of atp_translate_cmd_to_txt function ******************/


/********************************************************************************
* Function name : atp_copy_buffer
* 
* Description   : Copy 'data size' bytes of 'in buffer' to 'out buffer'
*
* Parameters    : in_buffer_p = buffer to copy from
*                 out_buffer_p = new buffer
*                 data_size = number of bytes to be copied
*
* Return        : RV_OK
*
* History       : 0.1 (05-May-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_copy_buffer (UINT8   *in_buffer_p,
						   UINT8   *out_buffer_p,
						   UINT32  data_size)
{

/************************ atp_copy_buffer function begins ***********************/

	memcpy ((void *) out_buffer_p,
			(void *) in_buffer_p,
			data_size);
  	return (RV_OK);

} /*********************** End of atp_copy_buffer function **********************/


/********************************************************************************
* Function name : atp_create_data_buffer_from_cmd
* 
* Description   : create a data buffer based on port features and on the command 
*                 which is interpreted or in text format
*
* Parameters    : cmd_mode = interpreted or text
*                 header = header size
*                 trailer = trailer size
*                 dce_info_p = pointer on the DCE information
*                 mb_id = memory bank used to get the data buffer
*                 cmd_type = type of the command
*                 cmd_nb = related binary code of the command (not used if TXT
*                          format)
*                 text_p = pointer on the text string (0-terminated) (not used
*                          if INTERPRETED format)
*                 cmd_info_p = pointer on the custom command information structure
*                              (not used if TXT format)
*                 buffer_pp = pointer on the data buffer generated by the function
*                 length_p = length of the data buffer
*
* Return        : RV_OK,
*                 RV_NOT_SUPPORTED if the command is not recognized
*
* History       : 0.1 (01-March-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_create_data_buffer_from_cmd (T_ATP_CMD_MODE  cmd_mode,
										   UINT16          header,
										   UINT16          trailer,
										   T_ATP_DCE_INFO  *dce_info_p,
										   T_RVF_MB_ID     mb_id,
										   T_ATP_CMD_TYPE  cmd_type,
										   T_ATP_CMD_NB    cmd_nb,
										   T_ATP_TXT_CMD   text_p,
										   T_ATP_CMD       *cmd_info_p,
										   T_ATP_BUFFER    *buffer_pp,
										   UINT16          *length_p)
{
    /* Declare local variables.                                                 */
	UINT16         txt_length   = 0x0000;
	T_ATP_BUFFER   atp_buffer_p = NULL;
	T_ATP_TXT_CMD  text_cmd_p   = NULL;
	
/**************** atp_create_data_buffer_from_cmd function begins ***************/

	/* Need to have the command type provided.                                  */
	if (cmd_type == UNKNOWN)
	{
		return (RV_NOT_SUPPORTED);
	}

	/* Get text version of the AT command and point on it via text_cmd_p. If    */
	/* the command has been provided already in text format, then...            */
	if (cmd_mode == TXT_MODE)
	{
		text_cmd_p = text_p;

		/* The length does not include '\x00'.                                  */
		txt_length = (UINT16) (strlen (text_cmd_p));
	}
	else
	{

		/* Declare a local block variable.                                      */
		T_ATP_RET  ret_status = RV_OK;

		/* Translate the command into text.                                     */
		ret_status = atp_translate_cmd_to_txt (cmd_type,
											   cmd_nb,
											   cmd_info_p,
											   mb_id,
											   &text_cmd_p,
											   &txt_length);

		/* If any error occurred, then abort.                                   */
		if (ret_status != RV_OK)
		{
			return (RV_NOT_SUPPORTED);
		}
	}

	/* Create real buffer to send for a AT Command.                             */
	switch (dce_info_p->verbose_mode)
	{

		/* Verbose responses enabled.                                           */
		case ATP_VERBOSE_0:
			{
				switch (cmd_type)
				{

					/* DCE responses (See ITU-T Recommendation V.250 ter page   */
					/* 10).                                                     */
					case RESULT_CODE:
					case UNSOLICITED_RESULT:
						{
							*length_p = (UINT16) (trailer + header + 0x0002);

							/* Create buffer and copy text string into it. If   */
							/* insufficient resources available, then report an */
							/* internal memory error and abort.                 */
							if (rvf_get_buf (mb_id, \
											 *length_p, \
											 (void **) buffer_pp) == RVF_RED)
							{
								*length_p = 0x0000;
								atp_error (ATP_ERROR_TX_MB_RED);
								return (RV_MEMORY_ERR);
							}
							atp_buffer_p = *buffer_pp;

							/* Add code.                                        */
							atp_buffer_p[header] = (char) (cmd_nb + '0');

							/* Add special characters.                          */
							atp_buffer_p[header + 0x0001] = dce_info_p->cr_character;

							/* Release text buffer.                             */
							rvf_free_buf (text_cmd_p);
							return (RV_OK);
						}
					case PRELIMINARY_RESULT_CODE:
						{

							/* Add 2 special characters <CR> and <LF>.          */
							*length_p = (UINT16) (trailer + header + txt_length + 0x0002);
			
							/* Create buffer and copy text string into it. If   */
							/* insufficient resources available, then report an */
							/* internal memory error and abort.                 */
							if (rvf_get_buf (mb_id, \
											 *length_p, \
											 (void **) buffer_pp) == RVF_RED)
							{
								*length_p = 0x0000;
								atp_error (ATP_ERROR_TX_MB_RED);
								return (RV_MEMORY_ERR);
							}
							atp_buffer_p = *buffer_pp;

							/* Copy text into the buffer.                       */
							memcpy ((void *) (atp_buffer_p + header),
									(void *) text_cmd_p,
									txt_length);

							/* Add special characters.                          */
							atp_buffer_p[header + txt_length]          = dce_info_p->cr_character;
							atp_buffer_p[header + txt_length + 0x0001] = dce_info_p->lf_character;

							/* Release text buffer.                             */
							rvf_free_buf (text_cmd_p);
							return (RV_OK);
						}
					default:
						{
							break;
						}
				}
			}

		/* Verbose responses disabled.                                          */
		case ATP_VERBOSE_1:
			{
				switch (cmd_type)
				{

					/* DTE command lines (See ITU-T Recommendation V.250 ter    */
					/* page 4).                                                 */
					case AT_CMD:
						{

							/* The buffer contains AT command and <CR>          */
							/* character.                                       */
							*length_p = (UINT16) (trailer + header + txt_length + 0x0001);

							/* Create buffer and copy text string into it. If   */
							/* insufficient resources available, then report an */
							/* internal memory error and abort.                 */
							if (rvf_get_buf (mb_id, \
											 *length_p, \
											 (void **) buffer_pp) == RVF_RED)
							{
								*length_p = 0x0000;
								atp_error (ATP_ERROR_TX_MB_RED);
								return (RV_MEMORY_ERR);
							}
							atp_buffer_p = *buffer_pp;

							/* Copy text into the buffer.                       */
							memcpy ((void *) (atp_buffer_p + header),
									(void *) text_cmd_p,
									txt_length);

							/* Add special characters.                          */
							atp_buffer_p[header + txt_length] = dce_info_p->cr_character;

							/* Release text buffer.                             */
							rvf_free_buf (text_cmd_p);
							return (RV_OK);
						}

					/* DCE responses (See ITU-T Recommendation V.250 ter page   */
					/* 10).                                                     */
					case RESULT_CODE:
					case UNSOLICITED_RESULT:
					case PRELIMINARY_RESULT_CODE:
						{

							/* Add 4 special characters <CR> and <LF> (twice).  */
							*length_p = (UINT16) (trailer + header + txt_length + 0x0004);
			
							/* Create buffer and copy text string into it. If   */
							/* insufficient resources available, then report an */
							/* internal memory error and abort.                 */
							if (rvf_get_buf (mb_id, \
											 *length_p, \
											 (void **) buffer_pp) == RVF_RED)
							{
								*length_p = 0x0000;
								atp_error (ATP_ERROR_TX_MB_RED);
								return (RV_MEMORY_ERR);
							}
							atp_buffer_p = *buffer_pp;

							/* Copy text into the buffer.                       */
							memcpy ((void *) (atp_buffer_p + header + 0x0002),
									(void *) text_cmd_p,
									txt_length);

							/* Add special characters.                          */
							atp_buffer_p[header]                       = dce_info_p->cr_character;
							atp_buffer_p[header + 0x0001]              = dce_info_p->lf_character;
							atp_buffer_p[header + txt_length + 0x0002] = dce_info_p->cr_character;
							atp_buffer_p[header + txt_length + 0x0003] = dce_info_p->lf_character;

							/* Release text buffer.                             */
							rvf_free_buf (text_cmd_p);
							return (RV_OK);
						}
					default:
						{
							rvf_send_trace ("ATP : Tried to create a buffer for an unknown command ",
											54,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							*length_p  = 0x0000;
							*buffer_pp = NULL;
							break;
						}
				}
				break;
			}
		default:
			{
				rvf_send_trace ("ATP : Verbose mode invalid ",
								27,
								NULL_PARAM,
								RV_TRACE_LEVEL_WARNING,
								ATP_USE_ID);
				*length_p  = 0x0000;
				*buffer_pp = NULL;
				break;
			}
	}
	return (RV_NOT_SUPPORTED);

} /*************** End of atp_create_data_buffer_from_cmd function **************/


/********************************************************************************
* Function name : atp_copy_buffer_from_l2cap
*
* Description   : Check the text command
*
* Parameters    : l2cap_buffer_p = type is L2CAP_ACL_DATA
*                 copy_buffer_p = pointer on the buffer to copy data in 
*                 buffer_length = data length to read
*
* Return        : RV_OK if it fits
*
* Note          : l2cap_buffer_p is not freed by this function !
*
* History       : 0.1 (21-March-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_copy_buffer_from_l2cap (void    *l2cap_buffer_p,
									  void    *copy_buffer_p,
									  UINT32  buffer_length,
									  UINT32  offset)
{

#ifdef BLUETOOTH

	/* Declare local variables.                                                 */
	UINT16            nb_byte    = 0x0000;
	T_RECV_DATA_ADDR  acl_data_p = {NULL, \
									NULL};
	
/****************** atp_copy_buffer_from_l2cap function begins ******************/

	rvf_send_trace ("ATP : Translate L2CAP buffer into a ATP buffer ",
					47,
					NULL_PARAM,
					RV_TRACE_LEVEL_DEBUG_LOW,
					ATP_USE_ID);
	l2cap_read_next_uint ((T_L2CAP_ACL_DATA *) l2cap_buffer_p,
						  sizeof (UINT8),
						  ((UINT8 *) copy_buffer_p),
						  &acl_data_p,
						  (UINT8) offset);
	for (nb_byte = 1;
		 nb_byte < buffer_length;
		 nb_byte++)
	{
		l2cap_read_next_uint ((T_L2CAP_ACL_DATA *) l2cap_buffer_p,
							  sizeof (UINT8),
							  ((UINT8 *) copy_buffer_p) + nb_byte,
							  &acl_data_p,
							  0x0000);
	}
	return (RV_OK);
#else
	rvf_send_trace ("ATP : Tried to read buffer in L2CAP format whereas Bluetooth is not enabled ",
					76,
					NULL_PARAM,
					RV_TRACE_LEVEL_WARNING,
					ATP_USE_ID);
	return (RV_NOT_SUPPORTED);
#endif
	
} /***************** End of atp_copy_buffer_from_l2cap function *****************/


/********************************************************************************
* Function name : atp_free_l2cap_buffer
*
* Description   : Release a L2CAP buffer
*
* Parameter     : l2cap_buffer_p = type is L2CAP_ACL_DATA
*
* Return        : RV_OK if free is OK
*
* History       : 0.1 (19-Dec-2001) - Created
*
*********************************************************************************/
T_ATP_RET atp_free_l2cap_buffer (UINT8  *atp_buffer_p)
{
	
/********************* atp_free_l2cap_buffer function begins ********************/

#ifdef BLUETOOTH
	return ((T_ATP_RET) (l2cap_free_data ((T_L2CAP_ACL_DATA *) atp_buffer_p)));
#else
	rvf_send_trace ("ATP : Tried to read buffer in L2CAP format whereas Bluetooth is not enabled ",
					76,
					NULL_PARAM,
					RV_TRACE_LEVEL_WARNING,
					ATP_USE_ID);
	return (RV_NOT_SUPPORTED);
#endif

} /******************** End of atp_free_l2cap_buffer function *******************/


/********************************************************************************
* Function name : atp_escape_sequence_process
*
* Description   : This function is used to detect the escape sequence in the data
*                 flow. This function should not be called if the port is not
*                 configured in DCE mode. The escape sequence should start in a new
*                 packet and the last character of the exit sequence should be the
*                 last character of a packet. Note that each data buffer checked
*                 that may be part of the escape sequence is temporarily stored so
*                 that it can be sent to the SWE later on in case it was the escape
*                 sequence.
*
* Parameters	: port_p = structure of the port
*                 atp_buffer_p = pointer on the buffer received by ATP (can be a 
*                 NORMAL data packet or a SEGMENTED data packet)
*                 data_length = number of payload data in the packet pointed by
*                 atp_buffer_p
*                 packet_mode = indicates the mode of the data packet (NORMAL or
*                 SEGMENTED)
*
* Return        : ATP_ESCAPE_SEQUENCE_SUCCESS,
*                 ATP_ESCAPE_SEQUENCE_FAILED otherwise
*
* History       : 0.1 (06-Feb-2001) - Created
*
*********************************************************************************/
T_ATP_ESCAPE_SEQUENCE_STATUS atp_escape_sequence_process (T_ATP_PORT_STRUCT  *port_p,
														  UINT8              *atp_buffer_p,
														  UINT32             data_length,
														  T_ATP_PACKET_MODE  packet_mode)
{
	/* Declare local variables.                                                 */
	UINT8  count   = 0;
	UINT8  data_sequence[MAX_NB_OF_CHARACTER_FOR_END_SEQUENCE];
	
/****************** atp_escape_sequence_process function begins *****************/

	/* Check the sequence. Indeed, there are data after the last character of   */
	/* the escape sequence.                                                     */
	if (((port_p->dce_info_p)->nb_plus_received + data_length) > MAX_NB_OF_CHARACTER_FOR_END_SEQUENCE)
	{
		return (ATP_ESCAPE_SEQUENCE_FAILED);
	}

	/* Get data from the buffer.                                                */
	if (packet_mode == SEGMENTED_PACKET)
	{
		atp_copy_buffer_from_l2cap (atp_buffer_p,
									data_sequence,
									data_length,
									0);
	}
	else
	{
		memcpy (data_sequence,
				atp_buffer_p,
				data_length);
	}

	/* Check every character.                                                   */
	for (count = 0;
		 count < data_length;
		 count++)
	{
		if (data_sequence[count] != (port_p->dce_info_p)->escape_sequence[count + (port_p->dce_info_p)->nb_plus_received])
		{
			return (ATP_ESCAPE_SEQUENCE_FAILED);
		}
	}

	/* Keep temporarily the pointer on the buffer.                              */
	for (count = 0;
		 (port_p->dce_info_p)->escape_sequence_tmp_buffer_p[count] != NULL;
		 count++);
	(port_p->dce_info_p)->escape_sequence_tmp_buffer_p[count]           = atp_buffer_p;
	(port_p->dce_info_p)->length_of_escape_sequence_tmp_buffer_p[count]	= (UINT8) data_length;
	if (((port_p->dce_info_p)->nb_plus_received + data_length) !=  MAX_NB_OF_CHARACTER_FOR_END_SEQUENCE)
	{
		(port_p->dce_info_p)->nb_plus_received = (UINT8) ((port_p->dce_info_p)->nb_plus_received + data_length);		
		return (ATP_ESCAPE_SEQUENCE_WAIT);
	}

	/* Otherwise, all characters have been found.                               */
	return (ATP_ESCAPE_SEQUENCE_SUCCESS);

} /***************** End of atp_escape_sequence_process function ****************/

  
/********************************************************************************
* Function name : atp_pipe_extra_character
*
* Description   : This function is called when it has been found that the escape
*                 sequence search has failed and when other SWE is in copy mode.
*                 In this case, data that has been received and that have not been
*                 sent to the other SWE because we thought they may contain the
*                 escape sequence must finally be sent.
*                 For this reason, all the buffer to sent has been previously stored
*                 in a temporary buffer called dce_info_p->escape_sequence_tmp_buffer_p.
*                 This function pipes all this buffer into the data pipe of the SWE.
*                 Note that such a complex mechanism is essentially due to the fact
*                 that we may have to deal with L2CAP packet (SEGMENTED_MODE).
*
* Parameters    : port_p = pointer on the port structure
*                 other_port_info_p = pointer on the port information structure of
*                 the SWE which will receive the data.
*
* Return        : RV_OK
*
* History       : 0.1 (01-March-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_pipe_extra_character (T_ATP_PORT_STRUCT      *port_p,
									T_ATP_PORT_END_STRUCT  *other_port_info_p)
{
	/* Declare local variables.                                                 */
	UINT8            count        = 0;
	UINT8            nb_packet    = 0;
	T_ATP_RX_PACKET  *rx_packet_p = NULL;
	
/******************* atp_pipe_extra_character function begins *******************/

	for (nb_packet = 0;
		 ((port_p->dce_info_p)->escape_sequence_tmp_buffer_p[nb_packet] != NULL) && \
		 (nb_packet < MAX_NB_OF_CHARACTER_FOR_END_SEQUENCE);
		 nb_packet++);
	for (count = 0; count < nb_packet; count++)
	{
		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);
		}
		rx_packet_p->first_byte        = 0;
		rx_packet_p->last_byte         = ((port_p->dce_info_p)->length_of_escape_sequence_tmp_buffer_p[count]) - 1;
		rx_packet_p->atp_buffer_p      = (port_p->dce_info_p)->escape_sequence_tmp_buffer_p[count];
		rx_packet_p->next_byte_to_read = rx_packet_p->first_byte;
		rvf_enqueue (&(other_port_info_p->rx_queue),
					 rx_packet_p);
		other_port_info_p->rx_data_left += (port_p->dce_info_p)->length_of_escape_sequence_tmp_buffer_p[count];
	}
	return (RV_OK);

} /****************** End of atp_pipe_extra_character function ******************/

  
/********************************************************************************
* Function name : atp_reset_escape_sequence
*
* Description   : This function resets all internal values used by the algorithm
*                 of escape sequence search (information stored in the dce_info_p
*                 structure)
*
* Parameter     : port_p = pointer on the port structure
*
* Return        : RV_OK
*
* History       : 0.1 (01-March-2000) - Created
*
*********************************************************************************/
T_ATP_RET atp_reset_escape_sequence (T_ATP_PORT_STRUCT  *port_p)
{
	/* Declare local variables.                                                 */
	UINT8  count     = 0;
	UINT8  *buffer_p = NULL;
	
/******************* atp_reset_escape_sequence function begins ******************/

	(port_p->dce_info_p)->nb_plus_received = 0;
	
	/* Clear pointers on temporary buffer containing potentially escape         */
	/* sequence.                                                                */
	for (count = 0;
		 count < MAX_NB_OF_CHARACTER_FOR_END_SEQUENCE;
		 count++)
	{
		if ((buffer_p = (port_p->dce_info_p)->escape_sequence_tmp_buffer_p[count]) != NULL)
		{

#ifdef BLUETOOTH

			/* Check if the buffer has been issued by SPP. Not very clean way to */
			/* check what is the packet mode.                                    */
			if ((strcmp ((char *) atp_sw_entity_table_p[(port_p->port_info[0]).sw_id]->sw_entity_name, \
						 ATP_SPP_NAME) == 0) || \
				(strcmp ((char *) atp_sw_entity_table_p[(port_p->port_info[1]).sw_id]->sw_entity_name, \
						 ATP_SPP_NAME) == 0))
			{

				/* Mode is SEGMENTED PACKET.                                     */
				l2cap_free_data ((T_L2CAP_ACL_DATA *) buffer_p);
			}
			else
			{

				/* Mode  is NORMAL_PACKET.                                       */
				rvf_free_buf (buffer_p);
			}
#else
			rvf_free_buf (buffer_p);
#endif
			(port_p->dce_info_p)->escape_sequence_tmp_buffer_p[count]           = NULL;
			(port_p->dce_info_p)->length_of_escape_sequence_tmp_buffer_p[count] = 0;
		}
	}
	return (RV_OK);

} /****************** End of atp_reset_escape_sequence function ******************/
