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