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