/********************************************************************************/
/*                                                                              */
/*    File Name:         atp_uart_handle_msg.c                                  */
/*                                                                              */
/*    Purpose:           This file contains the internal function related to    */
/*                       the ATP-UART interface and used to handle incoming     */
/*                       messages                                               */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       10/04/01        Pascal Pompei                                          */
/*                          - Create.                                           */
/*                                                                              */
/* (C) Copyright 2001 by Texas Instruments Incorporated, All Rights Reserved.   */
/*                                                                              */
/********************************************************************************/
#include "atp/atp_i.h"
#include "atp/atp_uart_i.h"
#include "rvm/rvm_use_id_list.h"


/********************************************************************************/
/*                                                                              */
/*    Function Name:     atp_uart_handle_msg                                    */
/*                                                                              */
/*    Purpose:           This function handles incoming messages available from */
/*                       the mailbox dedicated to the ATP-UART interface.       */
/*                                                                              */
/*    Input Parameters:  None.                                                  */
/*                                                                              */
/*    Output Parameters: None.                                                  */
/*                                                                              */
/*    Global Parameters: None.                                                  */
/*                                                                              */
/*    Notes:             The GSM protocol stack must be started first.          */
/*                       Nevertheless, note that incoming data calls are not    */
/*						 supported for now. Moreover, the AT Parser is alerted  */
/*                       that the call is terminated by receiving an 'Ok' or a  */
/*                       'No Carrier' final result code only. At last, the GSM  */
/*                       protocol stack is initialized by invoking the          */
/*                       following AT commands:                                 */
/*                          ATE0      : Echo mode switched off,                 */
/*                          AT+CFUN=1 : Set Phone Functionality (Full),         */
/*                          AT+COPS=0 : Operator Selection.                     */
/*                                                                              */
/*    Revision History:                                                         */
/*       10/04/01        Pascal Pompei                                          */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_ATP_UART_ERROR_CODES atp_uart_handle_msg (void)
{
	/* Declare local variables.                                                 */
	UINT16                event_pending          = 0x0000;
	UINT32                in_buffer_size         = 0x00000000;
	BOOLEAN               echo_mode_switched_off = FALSE;
	BOOLEAN               error_occurred         = FALSE;
	T_ATP_CALLBACK        return_path            = {0x00, \
													NULL};
	T_ATP_ENTITY_MODE     mode                   = {CMD_SUPPORT_ON, \
													TXT_MODE, \
													COPY_ON};
	T_ATP_SW_ENTITY_NAME  name                   = ATP_GSM_NAME;

/********************** atp_uart_handle_msg function begins *********************/

	/* First, wait until the COM port is activated.                             */
	while ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).com_port_handle == INVALID_HANDLE_VALUE)
	{

		/* Wait for the next event(s) of interest.                              */
		event_pending = rvf_wait (ATP_UART_ALL_EVENT_FLAGS,
								  0x00000000);

		/* If an expected event occurred, then get the associated message from  */
		/* the mailbox dedicated to the ATP-UART interface.                     */
		if (event_pending & ATP_UART_EXPECTED_EVENT)
		{

			/* Declare a local block variable.                                  */
			T_RV_HDR  *incoming_message_p = NULL;

			/* Get the incoming message from the mailbox dedicated to the       */
			/* ATP-UART interface.                                              */
			incoming_message_p = (T_RV_HDR *) rvf_read_mbox (ATP_UART_MAILBOX);

			/* Check whether the incoming message is valid.                     */
			if (incoming_message_p == NULL)
			{
				ATP_UART_UNRECOVERABLE_ERROR (RVM_INTERNAL_ERR,
											  "  ATP-UART (handle_msg). Invalid event occurred ");
				return (RVM_INTERNAL_ERR);
			}
			switch (incoming_message_p->msg_id)
			{

				/* 'ATP-UART Open COM Port'.                                    */
				case ATP_UART_OPEN_COM_PORT:
					{

						/* Declare a local block variable.                      */
						UINT8  gsm_basic_init_p[] = {'A', 'T', 'E', '0', \
													 ATP_CR_CHARACTER};

						/* Open the COM port whose number and baud rate are     */
						/* specified. If any error occurred, then call the      */
						/* function used whenever any unrecoverable error       */
						/* occurs and abort.                                    */
						if (atp_uart_create_com_port ((unsigned char) (((T_ATP_UART_OPEN_COM_PORT *) (incoming_message_p))->com_port), \
													  ((T_ATP_UART_OPEN_COM_PORT *) (incoming_message_p))->baud_rate) != RV_OK)
						{
							ATP_UART_UNRECOVERABLE_ERROR (RVM_INTERNAL_ERR,
														  "  ATP-UART (handle_msg). Unable to activate the COM port ");
							return (RVM_INTERNAL_ERR);
						}
						rvf_send_trace ("  ATP-UART (handle_msg). COM port properly opened ",
										50,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);

						/* Configure the GSM especially not to echo characters  */
						/* during 'Command State' and 'Online Command State'.   */
						/* If any error occurred, then call the function used   */
						/* whenever any unrecoverable error occurs and abort.   */
						if (atp_uart_write_com_port (gsm_basic_init_p, \
													 sizeof (gsm_basic_init_p)) != RV_OK)
						{
							ATP_UART_UNRECOVERABLE_ERROR (RVM_INTERNAL_ERR,
														  "  ATP-UART (handle_msg). GSM configuration failed ");
							return (RVM_INTERNAL_ERR);
						}
						break;
					}

				/* Unexpected message.                                          */
				default:
					{
						rvf_send_trace ("  ATP-UART (handle_msg). Unexpected message received ",
										53,
										incoming_message_p->msg_id,
										RV_TRACE_LEVEL_WARNING,
										ATP_USE_ID);
						break;
					}
			}
			(void) rvf_free_buf ((T_RVF_BUFFER *) (incoming_message_p));
		}
	}

	/* Then, wait for the echo mode being switched off.                         */
	while (echo_mode_switched_off == FALSE)
	{

		/* Wait for the next event(s) of interest.                              */
		event_pending = rvf_wait (ATP_UART_ALL_EVENT_FLAGS,
								  0x00000001);

		/* If an expected event occurred, then get the associated message from  */
		/* the mailbox dedicated to the ATP-UART interface.                     */
		if (event_pending & ATP_UART_EXPECTED_EVENT)
		{

			/* Declare a local block variable.                                  */
			T_RV_HDR  *incoming_message_p = NULL;

			/* Get the incoming message from the mailbox dedicated to the       */
			/* ATP-UART interface.                                              */
			incoming_message_p = (T_RV_HDR *) rvf_read_mbox (ATP_UART_MAILBOX);

			/* Check whether the incoming message is valid.                     */
			if (incoming_message_p == NULL)
			{
				ATP_UART_UNRECOVERABLE_ERROR (RVM_INTERNAL_ERR,
											  "  ATP-UART (handle_msg). Invalid event occurred ");
				return (RVM_INTERNAL_ERR);
			}
			rvf_send_trace ("  ATP-UART (handle_msg). Unexpected message received ",
							53,
							incoming_message_p->msg_id,
							RV_TRACE_LEVEL_WARNING,
							ATP_USE_ID);
			(void) rvf_free_buf ((T_RVF_BUFFER *) (incoming_message_p));
		}

		/* Now, attempt forwarding data to the AT Parser. Thus, initialize the  */
		/* amount of data to be forwarded.                                      */
		in_buffer_size = (UINT32) (ATP_UART_MAX_PACKET_SIZE - \
								   (gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left);

		/* Then, wait for data from the COM port. If any error occurred, then   */
		/* abort.                                                               */
		if (atp_uart_read_com_port (&((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left]), \
									&in_buffer_size) == RV_OK)
		{

			/* Declare local block variables.                                   */
			UINT32          in_buffer_begin = 0x00000000;
			UINT32          in_buffer_end   = 0x00000000;
			T_ATP_CMD       *cmd_info_p     = NULL;
			T_ATP_CMD_NB    cmd_nb          = 0x0000;
			T_ATP_CMD_TYPE  cmd_type        = UNKNOWN;

			/* Send every 'Text Command' to the AT Parser separately.           */
			while (in_buffer_end < in_buffer_size)
			{

				/* Skip leading <CR> and <LF> characters.                       */
				for (in_buffer_begin = in_buffer_end;
					 (in_buffer_begin < in_buffer_size) && \
					 (((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_begin] == ATP_LF_CHARACTER) || \
					  ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_begin] == ATP_CR_CHARACTER));
					 in_buffer_begin++)
				{
				}

				/* Get the 'Text Command' length by searching for the ending    */
				/* <CR> character.                                              */
				for (in_buffer_end = in_buffer_begin;
					 (in_buffer_end < in_buffer_size) && \
					 ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_end] != ATP_CR_CHARACTER);
					 in_buffer_end++)
				{
				}

				/* Abort whether no ending <CR> character found.                */
				if ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_end] != ATP_CR_CHARACTER)
				{

					/* Update the number of bytes left.                         */
					in_buffer_size -= in_buffer_begin;

					/* Defrag.                                                  */
					memcpy ((void *) ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p),
							(void *) (&((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_begin])),
							in_buffer_size);

					/* Update the number of bytes left.                         */
					(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left = in_buffer_size;
					break;
				}

				/* Otherwise, replace the ending <CR> character by NULL.        */
				/* Indeed, such a 'Text Command' must be a NULL-terminated      */
				/* string.                                                      */
				(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_end++] = '\x00';
				rvf_send_trace (&((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_begin]),
								(UINT8) (in_buffer_end - in_buffer_begin - 0x01),
								NULL_PARAM,
								RV_TRACE_LEVEL_DEBUG_LOW,
								ATP_USE_ID);

				/* Check whether the 'Text Command' is a final result code.     */
				if ((atp_translate_txt_to_cmd (&((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_begin]), \
											   UNKNOWN, \
											   &cmd_type, \
											   &cmd_nb, \
											   (gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).atp_id, \
											   &cmd_info_p) == RV_OK) && \
					(cmd_type == RESULT_CODE))
				{

					/* If needed, de-allocate the command-related information.  */
					if (cmd_info_p != NULL)
					{
						(void) rvf_free_buf ((T_RVF_BUFFER *) (cmd_info_p));
					}

					/* Check whether the 'Text Command' corresponds to the 'OK' */
					/* final result code.                                       */
					if (cmd_nb == ATP_OK_NB)
					{
						rvf_send_trace ("  ATP-UART (handle_msg). Echo mode switched off ",
										48,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);

						/* The echo mode is properly switched off.              */
						echo_mode_switched_off = TRUE;
						break;
					}
					ATP_UART_UNRECOVERABLE_ERROR (RVM_INTERNAL_ERR,
												  "  ATP-UART (handle_msg). Echo mode not switched off ");
					return (RVM_INTERNAL_ERR);
				}

				/* If needed, de-allocate the command-related information.      */
				if (cmd_info_p != NULL)
				{
					(void) rvf_free_buf ((T_RVF_BUFFER *) (cmd_info_p));
				}
			}
			continue;
		}
		rvf_send_trace ("  ATP-UART (handle_msg). Failed in getting data from the COM port ",
						66,
						NULL_PARAM,
						RV_TRACE_LEVEL_WARNING,
						ATP_USE_ID);
	}

	/* At last, initialize the remainder of the return path in order to receive */
	/* events from the AT parser.                                               */
	return_path.addr_id = gbl_atp_uart_ctrl_blk_p->addr_id;
	
	/* Register the ATP-UART interface to the AT Parser. If any error occurred, */
	/* then call the function used whenever any unrecoverable error occurs and  */
	/* abort.                                                                   */
	if (atp_reg (name, \
				 return_path, \
				 mode, \
				 &((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).atp_id)) != RV_OK)
	{
		ATP_UART_UNRECOVERABLE_ERROR (RVM_INTERNAL_ERR,
									  "  ATP-UART (handle_msg). Registration failed ");
		return (RVM_INTERNAL_ERR);
	}
	rvf_send_trace ("  ATP-UART (handle_msg). Registration completed ",
					48,
					NULL_PARAM,
					RV_TRACE_LEVEL_DEBUG_LOW,
					ATP_USE_ID);

	/* Now, wait for the next events to be handled as long as no error occurs.  */
	while (error_occurred == FALSE)
	{

		/* Wait for the next event(s) of interest.                              */
		event_pending = rvf_wait (ATP_UART_ALL_EVENT_FLAGS,
								  0x00000001);

		/* If an expected event occurred, then get the associated message from  */
		/* the mailbox dedicated to the ATP-UART interface.                     */
		if (event_pending & ATP_UART_EXPECTED_EVENT)
		{

			/* Declare a local block variable.                                  */
			T_RV_HDR  *incoming_message_p = NULL;

			/* Get the incoming message from the mailbox dedicated to the       */
			/* ATP-UART interface.                                              */
			incoming_message_p = (T_RV_HDR *) rvf_read_mbox (ATP_UART_MAILBOX);

			/* Check whether the incoming message is valid.                     */
			if (incoming_message_p == NULL)
			{
				ATP_UART_UNRECOVERABLE_ERROR (RVM_INTERNAL_ERR,
											  "  ATP-UART (handle_msg). Invalid event occurred ");
				return (RVM_INTERNAL_ERR);
			}
			switch (incoming_message_p->msg_id)
			{

				/* 'ATP Open Port Indication'.                                  */
				case ATP_OPEN_PORT_IND:
					{

						/* Declare local block variables.                       */
						T_ATP_PORT_INFO             gsm_port_info      = {NOT_DEFINED_CONFIG, \
																		  ATP_NO_RING_TYPE, \
																		  ATP_ALL_THE_SIGNAL_UNMASK, \
																		  0x0000};
						T_ATP_NO_COPY_INFO          gsm_no_copy_info   = {RVF_INVALID_MB_ID, \
																		  RVF_INVALID_MB_ID, \
																		  TX_HEADER_OFF, \
																		  0x00, \
																		  0x00, \
																		  RX_HEADER_OFF, \
																		  0x00, \
																		  0x00, \
																		  NORMAL_PACKET};
						T_ATP_CUSTOM_FROM_GSM_INFO  *gsm_custom_info_p = NULL;

						rvf_send_trace ("  ATP-UART (handle_msg). 'ATP Open Port Indication' received ",
										61,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_MEDIUM,
										ATP_USE_ID);

						/* Set custom information associated with the pseudo    */
						/* GSM Software Entity. If insufficient resources, then */
						/* call the function used whenever any unrecoverable    */
						/* error occurs and abort.                              */
						if (rvf_get_buf (gbl_atp_uart_ctrl_blk_p->mb_id, \
										 sizeof (T_ATP_CUSTOM_FROM_GSM_INFO), \
										 (T_RVF_BUFFER **) (&gsm_custom_info_p)) == RVF_RED)
						{
							ATP_UART_UNRECOVERABLE_ERROR (RVM_MEMORY_ERR,
														  "  ATP-UART (handle_msg). Insufficient resources ");
							return (RVM_MEMORY_ERR);
						}
						gsm_custom_info_p->custom_type                 = ATP_FROM_GSM_INFO;
						gsm_custom_info_p->optimal_gsm_max_packet_size = ATP_UART_MAX_PACKET_SIZE;

						/* Open the virtual modem port with the AT Parser. If   */
						/* any error occurred, then de-allocate custom          */
						/* information associated with the pseudo GSM Software  */
						/* Entity, call the function used whenever any          */
						/* unrecoverable error occurs and abort.                */
						if (atp_open_port_rsp (((T_ATP_OPEN_PORT_IND *) (incoming_message_p))->initiator_id, \
											   ((T_ATP_OPEN_PORT_IND *) (incoming_message_p))->initiator_port_nb, \
											   (gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).atp_id, \
											   ATP_UART_GSM_PORT_NB, \
											   gsm_port_info, \
											   gsm_no_copy_info, \
											   (T_ATP_CUSTOM_INFO *) (gsm_custom_info_p), \
											   OPEN_PORT_OK) != RV_OK)
						{
							(void) rvf_free_buf ((T_RVF_BUFFER *) (gsm_custom_info_p));
							ATP_UART_UNRECOVERABLE_ERROR (RVM_INTERNAL_ERR,
														  "  ATP-UART (handle_msg). Unable to open the virtual modem port with the AT Parser ");
							return (RVM_INTERNAL_ERR);
						}
						rvf_send_trace ("  ATP-UART (handle_msg). Virtual modem port properly established with the AT Parser ",
										84,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);

						/* The virtual modem port opened with the AT Parser is  */
						/* now properly initialized.                            */
						(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).virtual_modem_port_established = TRUE;

						/* If needed, de-allocate custom information contained  */
						/* in the 'ATP Open Port Indication'.                   */
						if (((T_ATP_OPEN_PORT_IND *) incoming_message_p)->custom_info_p != NULL)
						{
							rvf_free_buf ((T_RVF_BUFFER *) (((T_ATP_OPEN_PORT_IND *) (incoming_message_p))->custom_info_p));
						}
						break;
					}

				/* 'ATP Text Command Ready'.                                    */
				case ATP_TXT_CMD_RDY:
					{

						/* Declare local block variables.                       */
						UINT8              txt_cmd_length = 0x00;
						T_ATP_TXT_CMD_RDY  *txt_cmd_rdy_p = (T_ATP_TXT_CMD_RDY *) (incoming_message_p);

						rvf_send_trace ("  ATP-UART (handle_msg). 'ATP Text Command Ready' received ",
										59,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_MEDIUM,
										ATP_USE_ID);

						/* If any error occurred, then abort.                   */
						if ((txt_cmd_rdy_p->port_nb != ATP_UART_GSM_PORT_NB) || \
							(txt_cmd_rdy_p->txt_cmd_p == NULL))
						{
							rvf_send_trace ("  ATP-UART (handle_msg). 'Text Command' transfer failed ",
											56,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							break;
						}

						/* Get the length of the 'Text Command'. Note that such */
						/* a 'Text Command' is a NULL-terminated string.        */
						txt_cmd_length = (UINT8) (strlen (txt_cmd_rdy_p->txt_cmd_p));
						rvf_send_trace (txt_cmd_rdy_p->txt_cmd_p,
										txt_cmd_length,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);

						/* Forward the 'Text Command' to the COM port. If any   */
						/* error occurred, then proceed.                        */
						txt_cmd_rdy_p->txt_cmd_p[txt_cmd_length] = ATP_CR_CHARACTER;
						if (atp_uart_write_com_port ((UINT8 *) (txt_cmd_rdy_p->txt_cmd_p), \
													 (txt_cmd_length + 0x00000001)) != RV_OK)
						{
							rvf_send_trace ("  ATP-UART (handle_msg). 'Text Command' transfer failed ",
											56,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
						}

						/* De-allocate the data buffer provided with the 'ATP   */
						/* Command Ready'.                                      */
						(void) rvf_free_buf ((T_RVF_BUFFER *) (txt_cmd_rdy_p->txt_cmd_p));
						break;
					}

				/* 'ATP No Copy Data Ready'.                                    */
				case ATP_NO_COPY_DATA_RDY:
					{

						/* Declare a local block variable.                      */
						T_ATP_NO_COPY_DATA_RDY  *no_copy_data_rdy_p = (T_ATP_NO_COPY_DATA_RDY *) (incoming_message_p);

						rvf_send_trace ("  ATP-UART (handle_msg). 'ATP No Copy Data Ready' received ",
										59,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_MEDIUM,
										ATP_USE_ID);

						/* If any error occurred, then abort.                   */
						if ((no_copy_data_rdy_p->port_nb != ATP_UART_GSM_PORT_NB) || \
							(no_copy_data_rdy_p->atp_buffer_p == NULL))
						{
							rvf_send_trace ("  ATP-UART (handle_msg). Data transfer to the COM port failed ",
											62,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							break;
						}
						rvf_send_trace ("  ATP-UART (handle_msg). Data size ",
										35,
										no_copy_data_rdy_p->buffer_size,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);

						/* Forward data to the COM port. If any error occurred, */
						/* then proceed.                                        */
						if (atp_uart_write_com_port (no_copy_data_rdy_p->atp_buffer_p, \
													 no_copy_data_rdy_p->buffer_size) != RV_OK)
						{
							rvf_send_trace ("  ATP-UART (handle_msg). Data transfer to the COM port failed ",
											62,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
						}

						/* De-allocate the data buffer provided with the 'ATP   */
						/* No Copy Data Ready'.                                 */
						(void) rvf_free_buf ((T_RVF_BUFFER *) (no_copy_data_rdy_p->atp_buffer_p));
						break;
					}

				/* 'ATP Signal Changed'.                                        */
				case ATP_SIGNAL_CHANGED:
					{

						/* Declare a local block variable.                      */
						T_ATP_SIGNAL_CHANGED  *signal_changed_p = (T_ATP_SIGNAL_CHANGED *) (incoming_message_p);

						rvf_send_trace ("  ATP-UART (handle_msg). 'ATP Signal Changed' received ",
										55,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_MEDIUM,
										ATP_USE_ID);

						/* If any error occurred, then abort.                   */
						if (signal_changed_p->port_nb != ATP_UART_GSM_PORT_NB)
						{
							rvf_send_trace ("  ATP-UART (handle_msg). Invalid port number ",
											45,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							break;
						}
						rvf_send_trace ("  ATP-UART (handle_msg). Bit mask ",
										34,
										signal_changed_p->signal,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);

						/* Update the RS232 control signals associated with the */
						/* virtual modem port.                                  */
						(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).control_signals = signal_changed_p->signal;
						break;
					}

				/* 'ATP Port Mode Changed'.                                     */
				case ATP_PORT_MODE_CHANGED:
					{

						/* Declare a local block variable.                      */
						T_ATP_PORT_MODE_CHANGED  *port_mode_changed_p = (T_ATP_PORT_MODE_CHANGED *) (incoming_message_p);

						rvf_send_trace ("  ATP-UART (handle_msg). 'ATP Port Mode Changed' received ",
										58,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_MEDIUM,
										ATP_USE_ID);

						/* If any error occurred, then abort.                   */
						if (port_mode_changed_p->port_nb != ATP_UART_GSM_PORT_NB)
						{
							rvf_send_trace ("  ATP-UART (handle_msg). Invalid port number ",
											45,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							break;
						}
						rvf_send_trace ("  ATP-UART (handle_msg). Mode ",
										30,
										port_mode_changed_p->mode,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);

						/* If the virtual modem port is in 'Data' mode, then    */
						/* send the escape sequence first.                      */
						if ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).virtual_modem_port_mode == ATP_PORT_DATA_MODE)
						{

							/* Forward the escape sequence to the COM port. If  */
							/* any error occurred, then call the function used  */
							/* whenever any unrecoverable error occurs and      */
							/* abort.                                           */
							if (atp_uart_write_com_port ((UINT8 *) (ATP_ESCAPE_SEQUENCE), \
														 (sizeof (ATP_ESCAPE_SEQUENCE) - 0x00000001)) != RV_OK)
							{
								ATP_UART_UNRECOVERABLE_ERROR (RVM_INTERNAL_ERR,
															  "  ATP-UART (handle_msg). 'Escape sequence' not transmitted ");
								return (RVM_INTERNAL_ERR);
							}
							rvf_send_trace ("  ATP-UART (handle_msg). 'Escape sequence' properly transmitted ",
											64,
											NULL_PARAM,
											RV_TRACE_LEVEL_DEBUG_LOW,
											ATP_USE_ID);
						}

						/* Update the mode of the virtual modem port.           */
						(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).virtual_modem_port_mode = port_mode_changed_p->mode;
						break;
					}

				/* 'ATP Port Closed'.                                           */
				case ATP_PORT_CLOSED:
					{
						rvf_send_trace ("  ATP-UART (handle_msg). 'ATP Port Closed' received ",
										52,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_MEDIUM,
										ATP_USE_ID);

						/* If any error occurred, then abort.                   */
						if (((T_ATP_PORT_CLOSED *) (incoming_message_p))->port_nb != ATP_UART_GSM_PORT_NB)
						{
							rvf_send_trace ("  ATP-UART (handle_msg). Invalid port number ",
											45,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							break;
						}

						/* The virtual modem port opened with the AT Parser is  */
						/* now closed.                                          */
						(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).virtual_modem_port_established = FALSE;
						break;
					}

				/* 'ATP-UART Start GSM'.                                        */
				case ATP_UART_START_GSM:
					{

						/* Declare a local block variable.                      */
						UINT8  gsm_init_p[] = {'A', 'T', '+', 'C', 'F', 'U', 'N', '=', '1', ';', '+', 'C', 'O', 'P', 'S', '=', '0', \
												ATP_CR_CHARACTER};

						rvf_send_trace ("  ATP-UART (handle_msg). 'ATP-UART Start GSM' received ",
										55,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_MEDIUM,
										ATP_USE_ID);

						/* If any error occurred, then abort.                   */
						if (atp_uart_write_com_port (gsm_init_p, \
													 sizeof (gsm_init_p)) != RV_OK)
						{
							rvf_send_trace ("  ATP-UART (handle_msg). Unable to start the GSM protocol stack ",
											64,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							break;
						}
						break;
					}

				/* Unexpected message.                                          */
				default:
					{
						rvf_send_trace ("  ATP-UART (handle_msg). Unexpected message received ",
										53,
										incoming_message_p->msg_id,
										RV_TRACE_LEVEL_WARNING,
										ATP_USE_ID);
						break;
					}
			}
			(void) rvf_free_buf ((T_RVF_BUFFER *) (incoming_message_p));
		}

		/* Now, if the flow control is activated, then proceed without getting  */
		/* any data from the COM port.                                          */
		if (((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).control_signals & ATP_RX_FLOW_UNMASK) == ATP_RX_FLOW_ON)
		{
			continue;
		}

		/* Otherwise, attempt forwarding data to the AT Parser. Thus,           */
		/* initialize the amount of data to be forwarded.                       */
		in_buffer_size = (UINT32) (ATP_UART_MAX_PACKET_SIZE - \
								   (gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left);

		/* Then, wait for data from the COM port. If any error occurred, then   */
		/* abort.                                                               */
		if (atp_uart_read_com_port (&((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left]), \
									&in_buffer_size) != RV_OK)
		{
			rvf_send_trace ("  ATP-UART (handle_msg). Failed in getting data from the COM port ",
							66,
							NULL_PARAM,
							RV_TRACE_LEVEL_WARNING,
							ATP_USE_ID);
			continue;
		}

		/* Take new data into account.                                          */
		in_buffer_size = (UINT32) ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left + \
								   in_buffer_size);

		/* If no virtual modem port established with the AT Parser or if no     */
		/* data pending for transmission to the AT Parser, then update the      */
		/* number of bytes left and proceed.                                    */
		if (((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).virtual_modem_port_established == FALSE) || \
			(in_buffer_size == 0x00000000))
		{
			(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left = in_buffer_size;
			continue;
		}

		/* Otherwise, re-initialize the number of bytes left.                   */
		(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left = 0x00000000;
		rvf_send_trace ("  ATP-UART (handle_msg). Get data from the COM port ",
						52,
						in_buffer_size,
						RV_TRACE_LEVEL_DEBUG_LOW,
						ATP_USE_ID);

		/* At last, depending on the mode, transfert data from the COM port as  */
		/* 'Text Command' or 'Data'.                                            */
		if ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).virtual_modem_port_mode == ATP_PORT_CMD_MODE)
		{

			/* Declare local block variables.                                   */
			UINT32          in_buffer_begin = 0x00000000;
			UINT32          in_buffer_end   = 0x00000000;
			T_ATP_CMD       *cmd_info_p     = NULL;
			T_ATP_CMD_NB    cmd_nb          = 0x0000;
			T_ATP_TXT_CMD   txt_cmd_p       = NULL;
			T_ATP_CMD_TYPE  cmd_type        = UNKNOWN;

			/* Send every 'Text Command' to the AT Parser separately.           */
			while (in_buffer_end < in_buffer_size)
			{

				/* Skip leading <CR> and <LF> characters.                       */
				for (in_buffer_begin = in_buffer_end;
					 (in_buffer_begin < in_buffer_size) && \
					 (((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_begin] == ATP_LF_CHARACTER) || \
					  ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_begin] == ATP_CR_CHARACTER));
					 in_buffer_begin++)
				{
				}

				/* Get the 'Text Command' length by searching for the ending    */
				/* <CR> character.                                              */
				for (in_buffer_end = in_buffer_begin;
					 (in_buffer_end < in_buffer_size) && \
					 ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_end] != ATP_CR_CHARACTER);
					 in_buffer_end++)
				{
				}

				/* Abort whether no ending <CR> character found.                */
				if ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_end] != ATP_CR_CHARACTER)
				{

					/* Update the number of bytes left.                         */
					in_buffer_size -= in_buffer_begin;

					/* Defrag.                                                  */
					memcpy ((void *) ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p),
							(void *) (&((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_begin])),
							in_buffer_size);

					/* Update the number of bytes left.                         */
					(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left = in_buffer_size;
					break;
				}

				/* Otherwise, replace the ending <CR> character by NULL.        */
				/* Indeed, such a 'Text Command' must be a NULL-terminated      */
				/* string.                                                      */
				(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_end++] = '\x00';

				/* Allocate memory in order to forward the 'Text Command' to    */
				/* the AT Parser. If insufficient resources, then call the      */
				/* function used whenever any unrecoverable error occurs and    */
				/* abort.                                                       */
				if (rvf_get_buf (gbl_atp_uart_ctrl_blk_p->mb_id, \
								 (in_buffer_end - in_buffer_begin), \
								 (T_RVF_BUFFER **) (&txt_cmd_p)) == RVF_RED)
				{
					ATP_UART_UNRECOVERABLE_ERROR (RVM_MEMORY_ERR,
												  "  ATP-UART (handle_msg). Insufficient resources ");
					break;
				}

				/* Copy the 'Text Command'.                                     */
				memcpy ((void *) (txt_cmd_p),
						(void *) (&((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_begin])),
						(in_buffer_end - in_buffer_begin));
				rvf_send_trace (txt_cmd_p,
								(UINT8) (in_buffer_end - in_buffer_begin - 0x01),
								NULL_PARAM,
								RV_TRACE_LEVEL_DEBUG_LOW,
								ATP_USE_ID);

				/* Check whether the 'Text Command' is a final or an            */
				/* unsolicited result code.                                     */
				if ((atp_translate_txt_to_cmd (txt_cmd_p, \
											   UNKNOWN, \
											   &cmd_type, \
											   &cmd_nb, \
											   (gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).atp_id, \
											   &cmd_info_p) == RV_OK) && \
					(cmd_type == RESULT_CODE))
				{

					/* If the 'Text Command' corresponds to the 'Connect' final */
					/* result code, then turn the 'Data Carrier Detect' on      */
					/* before sending it to the AT Parser (See ITU-T            */
					/* Recommendation V.250 ter page 32). If any error          */
					/* occurred, then de-allocate the 'Text Command' and abort. */
					if (cmd_nb == ATP_CONNECT_NB)
					{
						if (atp_set_signal ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).atp_id, \
											ATP_UART_GSM_PORT_NB, \
											ATP_DCD_1, \
											ATP_DCD_UNMASK) != RV_OK)
						{
							(void) rvf_free_buf ((T_RVF_BUFFER *) (txt_cmd_p));

							/* If needed, de-allocate the command-related       */
							/* information.                                     */
							if (cmd_info_p != NULL)
							{
								(void) rvf_free_buf ((T_RVF_BUFFER *) (cmd_info_p));
							}
							rvf_send_trace ("  ATP-UART (handle_msg). 'Data Carrier Detect' not turned on ",
											61,
											NULL_PARAM,
											RV_TRACE_LEVEL_WARNING,
											ATP_USE_ID);
							break;
						}
						rvf_send_trace ("  ATP-UART (handle_msg). 'Data Carrier Detect' properly turned on ",
										66,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);
					}
				}

				/* Otherwise, the 'Text Command' is recognized as a preliminary */
				/* result code.                                                 */
				else
				{
					cmd_type = PRELIMINARY_RESULT_CODE;
				}

				/* If needed, de-allocate the command-related information.      */
				if (cmd_info_p != NULL)
				{
					(void) rvf_free_buf ((T_RVF_BUFFER *) (cmd_info_p));
				}

				/* Forward the 'Text Command' to the AT Parser. If any error    */
				/* occurred, then de-allocate the 'Text Command' and abort.     */
				if (atp_send_txt_cmd ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).atp_id, \
									  ATP_UART_GSM_PORT_NB, \
									  cmd_type, \
									  txt_cmd_p) != RV_OK)
				{
					(void) rvf_free_buf ((T_RVF_BUFFER *) (txt_cmd_p));
					rvf_send_trace ("  ATP-UART (handle_msg). 'Text Command' failed ",
									47,
									NULL_PARAM,
									RV_TRACE_LEVEL_WARNING,
									ATP_USE_ID);
					break;
				}
			}
		}
		else
		{

			/* Declare local block variables.                                   */
			UINT8         no_carrier_count = 0x00;
			UINT8         no_carrier_p[]   = {ATP_CR_CHARACTER, \
											  ATP_LF_CHARACTER, \
											  'N', 'O', ' ', 'C', 'A', 'R', 'R', 'I', 'E', 'R', \
											  ATP_CR_CHARACTER, \
											  ATP_LF_CHARACTER};
			UINT8         ok_count         = 0x00;
			UINT8         ok_p[]           = {ATP_CR_CHARACTER, \
											  ATP_LF_CHARACTER, \
											  'O', 'K', \
											  ATP_CR_CHARACTER, \
											  ATP_LF_CHARACTER};
			UINT32        in_buffer_count  = 0x00000000;
			UINT32        in_data_size     = 0x00000000;
			T_ATP_CMD_NB  result_code_nb   = ATP_MAX_NB_OF_RESULT_CODES;

			/* First, search for 'Ok' or 'No Carrier' final result codes.       */
			for (in_buffer_count = 0x00000000, \
				 in_data_size    = in_buffer_size;
				 in_buffer_count < in_buffer_size;
				 in_buffer_count++)
			{

				/* Search for an 'Ok' final result code.                        */
				if ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_count] == ok_p[ok_count])
				{

					/* 'Ok' final result code detected.                         */
					if (++ok_count == sizeof (ok_p))
					{
						result_code_nb = ATP_OK_NB;
						rvf_send_trace ("  ATP-UART (handle_msg). 'Ok' final result code detected ",
										57,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);

						/* Send the remainder to the AT Parser.                 */
						in_data_size = in_buffer_count - (sizeof (ok_p) - 0x00000001);
						break;
					}
				}
				else
				{
					ok_count = 0x00;
				}

				/* Search for a 'No Carrier' final result code.                 */
				if ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_count] == no_carrier_p[no_carrier_count])
				{

					/* 'No Carrier' final result code detected.                 */
					if (++no_carrier_count == sizeof (no_carrier_p))
					{
						result_code_nb = ATP_NO_CARRIER_NB;
						rvf_send_trace ("  ATP-UART (handle_msg). 'No Carrier' final result code detected ",
										65,
										NULL_PARAM,
										RV_TRACE_LEVEL_DEBUG_LOW,
										ATP_USE_ID);

						/* Send the remainder to the AT Parser.                 */
						in_data_size = in_buffer_count - (sizeof (no_carrier_p) - 0x00000001);
						break;
					}
				}
				else
				{
					no_carrier_count = 0x00;
				}
			}

			/* Then, check for some bytes to be forwarded data to the AT        */
			/* Parser.                                                          */
			if (in_data_size > 0x00000000)
			{

				/* Forward data to the AT Parser. If any error occurred, then   */
				/* proceed.                                                     */
				if (atp_send_data ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).atp_id, \
								   ATP_UART_GSM_PORT_NB, \
								   (void *) ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p), \
								   in_data_size, \
								   &((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left)) != RV_OK)
				{
					rvf_send_trace ("  ATP-UART (handle_msg). Data transfer to the AT Parser failed ",
									63,
									NULL_PARAM,
									RV_TRACE_LEVEL_WARNING,
									ATP_USE_ID);
				}

				/* Update the number of bytes left.                             */
				in_data_size   -= (gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left;
				in_buffer_size -= in_data_size;

				/* Check whether some bytes left to be sent to the AT Parser.   */
				if ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left > 0x00000000)
				{

					/* Defrag.                                                  */
					memcpy ((void *) ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p),
							(void *) (&((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_data_size])),
							in_buffer_size);

					/* Update the number of bytes left.                         */
					(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left = in_buffer_size;
					continue;
				}
			}

			/* At last, check whether an 'Ok' or a 'No Carrier' final result    */
			/* code was detected.                                               */
			if (result_code_nb != ATP_MAX_NB_OF_RESULT_CODES)
			{

				/* Turn the 'Data Carrier Detect' off before sending it to the  */
				/* AT Parser (See ITU-T Recommendation V.250 ter page 37).      */
				/* However, proceed whether any error occurred.                 */
				if (((atp_set_signal ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).atp_id, \
									  ATP_UART_GSM_PORT_NB, \
									  ATP_DCD_0, \
									  ATP_DCD_UNMASK) != RV_OK) || \
					 (atp_send_cmd ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).atp_id, \
									ATP_UART_GSM_PORT_NB, \
									RESULT_CODE, \
									result_code_nb, \
									NULL) != RV_OK)))
				{
					rvf_send_trace ("  ATP-UART (handle_msg). Final result code not transmitted ",
									59,
									NULL_PARAM,
									RV_TRACE_LEVEL_WARNING,
									ATP_USE_ID);
				}

				/* Update the number of bytes left.                             */
				in_buffer_size -= in_buffer_count;

				/* Update the mode of the virtual modem port.                   */
				(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).virtual_modem_port_mode = ATP_PORT_CMD_MODE;
			}

			/* If some data left, then defrag.                                  */
			memcpy ((void *) ((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p),
					(void *) (&((gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).in_buffer_p[in_buffer_count])),
					in_buffer_size);

			/* Update the number of bytes left.                                 */
			(gbl_atp_uart_ctrl_blk_p->conn_ctrl_blk).nb_bytes_left = in_buffer_size;
		}
	}
	return (RVM_OK);

} /********************* End of atp_uart_handle_msg function ********************/
