blob: 6c67e2f4b4d7210f1d7252b86acc4588f17ceb76 [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2003-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* This file implements utility functions for the HeaLth device profile
* (HL).
*
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "bt_target.h"
#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE)
#include "gki.h"
#include "utl.h"
#include "bd.h"
#include "bta_fs_api.h"
#include "bta_hl_int.h"
#include "bta_hl_co.h"
#include "mca_defs.h"
#include "mca_api.h"
/*******************************************************************************
**
** Function bta_hl_set_ctrl_psm_for_dch
**
** Description This function set the control PSM for the DCH setup
**
** Returns BOOLEAN - TRUE - control PSM setting is successful
*******************************************************************************/
BOOLEAN bta_hl_set_ctrl_psm_for_dch(UINT8 app_idx, UINT8 mcl_idx,
UINT8 mdl_idx, UINT16 ctrl_psm)
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BOOLEAN success = TRUE, update_ctrl_psm = FALSE;
UNUSED(mdl_idx);
if (p_mcb->sdp.num_recs)
{
if (p_mcb->ctrl_psm != ctrl_psm)
{
/* can not use a different ctrl PSM than the current one*/
success = FALSE;
}
}
else
{
/* No SDP info control i.e. channel was opened by the peer */
update_ctrl_psm = TRUE;
}
if (success && update_ctrl_psm)
{
p_mcb->ctrl_psm = ctrl_psm;
}
#if BTA_HL_DEBUG == TRUE
if (!success)
{
APPL_TRACE_DEBUG("bta_hl_set_ctrl_psm_for_dch num_recs=%d success=%d update_ctrl_psm=%d ctrl_psm=0x%x ",
p_mcb->sdp.num_recs, success, update_ctrl_psm, ctrl_psm );
}
#endif
return success;
}
/*******************************************************************************
**
** Function bta_hl_find_sdp_idx_using_ctrl_psm
**
** Description
**
** Returns UINT8 pool_id
**
*******************************************************************************/
BOOLEAN bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP *p_sdp,
UINT16 ctrl_psm,
UINT8 *p_sdp_idx)
{
BOOLEAN found=FALSE;
tBTA_HL_SDP_REC *p_rec;
UINT8 i;
if (ctrl_psm != 0)
{
for (i=0; i<p_sdp->num_recs; i++)
{
p_rec = &p_sdp->sdp_rec[i];
if (p_rec->ctrl_psm == ctrl_psm)
{
*p_sdp_idx = i;
found = TRUE;
break;
}
}
}
else
{
*p_sdp_idx = 0;
found = TRUE;
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_sdp_idx_using_ctrl_psm found=%d sdp_idx=%d ctrl_psm=0x%x ",
found, *p_sdp_idx, ctrl_psm );
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_set_user_tx_pool_id
**
** Description This function sets the user tx pool id
**
** Returns UINT8 pool_id
**
*******************************************************************************/
UINT8 bta_hl_set_user_tx_pool_id(UINT16 max_tx_size)
{
UINT8 pool_id;
if (max_tx_size > GKI_get_pool_bufsize (OBX_FCR_TX_POOL_ID))
{
pool_id = BTA_HL_LRG_DATA_POOL_ID;
}
else
{
pool_id = L2CAP_DEFAULT_ERM_POOL_ID;
}
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_set_user_rx_pool_id pool_id=%d max_tx_size=%d default_ertm_pool_size=%d",
pool_id, max_tx_size, GKI_get_pool_bufsize (OBX_FCR_TX_POOL_ID));
#endif
return pool_id;
}
/*******************************************************************************
**
** Function bta_hl_set_user_rx_pool_id
**
** Description This function sets the user trx pool id
**
** Returns UINT8 pool_id
**
*******************************************************************************/
UINT8 bta_hl_set_user_rx_pool_id(UINT16 mtu)
{
UINT8 pool_id;
if (mtu > GKI_get_pool_bufsize (OBX_FCR_RX_POOL_ID))
{
pool_id = BTA_HL_LRG_DATA_POOL_ID;
}
else
{
pool_id = L2CAP_DEFAULT_ERM_POOL_ID;
}
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_set_user_rx_pool_id pool_id=%d mtu=%d default_ertm_pool_size=%d",
pool_id, mtu, GKI_get_pool_bufsize (OBX_FCR_RX_POOL_ID));
#endif
return pool_id;
}
/*******************************************************************************
**
** Function bta_hl_set_tx_win_size
**
** Description This function sets the tx window size
**
** Returns UINT8 tx_win_size
**
*******************************************************************************/
UINT8 bta_hl_set_tx_win_size(UINT16 mtu, UINT16 mps)
{
UINT8 tx_win_size;
if (mtu <= mps)
{
tx_win_size =1;
}
else
{
if (mps > 0)
{
tx_win_size = (mtu/mps)+1;
}
else
{
APPL_TRACE_ERROR("The MPS is zero");
tx_win_size = 10;
}
}
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_set_tx_win_size win_size=%d mtu=%d mps=%d",
tx_win_size, mtu, mps);
#endif
return tx_win_size;
}
/*******************************************************************************
**
** Function bta_hl_set_mps
**
** Description This function sets the MPS
**
** Returns UINT16 MPS
**
*******************************************************************************/
UINT16 bta_hl_set_mps(UINT16 mtu)
{
UINT16 mps;
if (mtu > BTA_HL_L2C_MPS)
{
mps = BTA_HL_L2C_MPS;
}
else
{
mps = mtu;
}
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_set_mps mps=%d mtu=%d",
mps, mtu);
#endif
return mps;
}
/*******************************************************************************
**
** Function bta_hl_clean_mdl_cb
**
** Description This function clean up the specified MDL control block
**
** Returns void
**
*******************************************************************************/
void bta_hl_clean_mdl_cb(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx)
{
tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_clean_mdl_cb app_idx=%d mcl_idx=%d mdl_idx=%d",
app_idx, mcl_idx, mdl_idx);
#endif
utl_freebuf((void **) &p_dcb->p_tx_pkt);
utl_freebuf((void **) &p_dcb->p_rx_pkt);
utl_freebuf((void **) &p_dcb->p_echo_tx_pkt);
utl_freebuf((void **) &p_dcb->p_echo_rx_pkt);
memset((void *)p_dcb, 0 , sizeof(tBTA_HL_MDL_CB));
}
/*******************************************************************************
**
** Function bta_hl_get_buf
**
** Description This function allocate a buffer based on the specified data size
**
** Returns BT_HDR *.
**
*******************************************************************************/
BT_HDR * bta_hl_get_buf(UINT16 data_size)
{
BT_HDR *p_new;
UINT16 size = data_size + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
if (size < GKI_MAX_BUF_SIZE)
{
p_new = (BT_HDR *)GKI_getbuf(size);
}
else
{
p_new = (BT_HDR *) GKI_getpoolbuf(BTA_HL_LRG_DATA_POOL_ID);
}
if (p_new)
{
p_new->len = data_size;
p_new->offset = L2CAP_MIN_OFFSET;
}
return p_new;
}
/*******************************************************************************
**
** Function bta_hl_find_service_in_db
**
** Description This function check the specified service class(es) can be find in
** the received SDP database
**
** Returns BOOLEAN TRUE - found
** FALSE - not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_service_in_db( UINT8 app_idx, UINT8 mcl_idx,
UINT16 service_uuid,
tSDP_DISC_REC **pp_rec )
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BOOLEAN found = TRUE;
switch (service_uuid)
{
case UUID_SERVCLASS_HDP_SINK:
case UUID_SERVCLASS_HDP_SOURCE:
if ((*pp_rec = SDP_FindServiceInDb(p_mcb->p_db, service_uuid,
*pp_rec)) == NULL)
{
found = FALSE;
}
break;
default:
if (((*pp_rec = bta_hl_find_sink_or_src_srv_class_in_db(p_mcb->p_db,
*pp_rec)) == NULL))
{
found = FALSE;
}
break;
}
return found;
}
/*******************************************************************************
**
** Function bta_hl_get_service_uuids
**
**
** Description This function finds the service class(es) for both CCH and DCH oeprations
**
** Returns UINT16 - service_id
** if service_uuid = 0xFFFF then it means service uuid
** can be either Sink or Source
**
*******************************************************************************/
UINT16 bta_hl_get_service_uuids(UINT8 sdp_oper, UINT8 app_idx, UINT8 mcl_idx,
UINT8 mdl_idx )
{
tBTA_HL_MDL_CB *p_dcb;
UINT16 service_uuid = 0xFFFF; /* both Sink and Source */
switch (sdp_oper)
{
case BTA_HL_SDP_OP_DCH_OPEN_INIT:
case BTA_HL_SDP_OP_DCH_RECONNECT_INIT:
p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID)
{
if (p_dcb->peer_mdep_role == BTA_HL_MDEP_ROLE_SINK)
{
service_uuid = UUID_SERVCLASS_HDP_SINK;
}
else
{
service_uuid = UUID_SERVCLASS_HDP_SOURCE;
}
}
break;
case BTA_HL_SDP_OP_CCH_INIT:
default:
/* use default that is both Sink and Source */
break;
}
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_get_service_uuids service_uuid=0x%x",service_uuid );
#endif
return service_uuid;
}
/*******************************************************************************
**
** Function bta_hl_find_echo_cfg_rsp
**
**
** Description This function finds the configuration response for the echo test
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_echo_cfg_rsp(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdep_idx, UINT8 cfg,
UINT8 *p_cfg_rsp)
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tBTA_HL_MDEP *p_mdep= &p_acb->sup_feature.mdep[mdep_idx];
BOOLEAN status =TRUE;
if (p_mdep->mdep_id == BTA_HL_ECHO_TEST_MDEP_ID)
{
if ((cfg == BTA_HL_DCH_CFG_RELIABLE) || (cfg == BTA_HL_DCH_CFG_STREAMING))
{
*p_cfg_rsp = cfg;
}
else if (cfg == BTA_HL_DCH_CFG_NO_PREF )
{
*p_cfg_rsp = BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG;
}
else
{
status = FALSE;
APPL_TRACE_ERROR("Inavlid echo cfg value");
}
return status;
}
#if BTA_HL_DEBUG == TRUE
if (!status)
{
APPL_TRACE_DEBUG("bta_hl_find_echo_cfg_rsp status=failed app_idx=%d mcl_idx=%d mdep_idx=%d cfg=%d",
app_idx, mcl_idx, mdep_idx, cfg);
}
#endif
return status;
}
/*******************************************************************************
**
** Function bta_hl_validate_dch_cfg
**
** Description This function validate the DCH configuration
**
** Returns BOOLEAN - TRUE cfg is valid
** FALSE not valid
**
*******************************************************************************/
BOOLEAN bta_hl_validate_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
UINT8 cfg)
{
tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
BOOLEAN is_valid =FALSE;
if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) &&
(cfg != BTA_HL_DCH_CFG_RELIABLE))
{
APPL_TRACE_ERROR("the first DCH should be a reliable channel");
return is_valid;
}
switch (p_dcb->local_cfg)
{
case BTA_HL_DCH_CFG_NO_PREF:
if ((cfg == BTA_HL_DCH_CFG_RELIABLE) || (cfg == BTA_HL_DCH_CFG_STREAMING))
{
is_valid = TRUE;
}
break;
case BTA_HL_DCH_CFG_RELIABLE:
case BTA_HL_DCH_CFG_STREAMING:
if (p_dcb->local_cfg == cfg )
{
is_valid = TRUE;
}
break;
default:
break;
}
#if BTA_HL_DEBUG == TRUE
if (!is_valid)
{
APPL_TRACE_DEBUG("bta_hl_validate_dch_open_cfg is_valid=%d, cfg=%d", is_valid, cfg );
}
#endif
return is_valid;
}
/*******************************************************************************
**
** Function bta_hl_find_cch_cb_indexes
**
** Description This function finds the indexes needed for the CCH state machine
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_cch_cb_indexes(tBTA_HL_DATA *p_msg,
UINT8 *p_app_idx,
UINT8 *p_mcl_idx)
{
BOOLEAN found = FALSE;
tBTA_HL_MCL_CB *p_mcb;
UINT8 app_idx = 0, mcl_idx = 0;
switch (p_msg->hdr.event)
{
case BTA_HL_CCH_SDP_OK_EVT:
case BTA_HL_CCH_SDP_FAIL_EVT:
app_idx = p_msg->cch_sdp.app_idx;
mcl_idx = p_msg->cch_sdp.mcl_idx;
found = TRUE;
break;
case BTA_HL_MCA_CONNECT_IND_EVT:
if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle, &app_idx))
{
if (bta_hl_find_mcl_idx(app_idx, p_msg->mca_evt.mca_data.connect_ind.bd_addr, &mcl_idx))
{
/* local initiated */
found = TRUE;
}
else if (!bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx)&&
bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx))
{
/* remote initiated */
p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
p_mcb->in_use = TRUE;
p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_OPEN;
found = TRUE;
}
}
break;
case BTA_HL_MCA_DISCONNECT_IND_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx))
{
found = TRUE;
}
else if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle, &app_idx) &&
bta_hl_find_mcl_idx(app_idx, p_msg->mca_evt.mca_data.disconnect_ind.bd_addr, &mcl_idx))
{
found = TRUE;
}
if (found)
{
p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
if ((p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) && (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN) )
{
p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_CLOSE;
}
}
break;
case BTA_HL_MCA_RSP_TOUT_IND_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx))
{
found = TRUE;
}
if (found)
{
p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
if ((p_mcb->cch_oper != BTA_HL_CCH_OP_REMOTE_CLOSE) && (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN))
{
p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
}
}
break;
default:
break;
}
if (found)
{
*p_app_idx = app_idx;
*p_mcl_idx = mcl_idx;
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_cch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d",
bta_hl_evt_code(p_msg->hdr.event), found, app_idx, mcl_idx);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_dch_cb_indexes
**
** Description This function finds the indexes needed for the DCH state machine
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_dch_cb_indexes(tBTA_HL_DATA *p_msg,
UINT8 *p_app_idx,
UINT8 *p_mcl_idx,
UINT8 *p_mdl_idx)
{
BOOLEAN found = FALSE;
tBTA_HL_MCL_CB *p_mcb;
UINT8 app_idx = 0, mcl_idx = 0, mdl_idx = 0;
switch (p_msg->hdr.event)
{
case BTA_HL_MCA_CREATE_CFM_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.create_cfm.mdl_id, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_MCA_CREATE_IND_EVT:
case BTA_HL_MCA_RECONNECT_IND_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
bta_hl_find_avail_mdl_idx( app_idx, mcl_idx, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_MCA_OPEN_CFM_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.open_cfm.mdl_id, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_MCA_OPEN_IND_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.open_ind.mdl_id, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_MCA_CLOSE_CFM_EVT:
if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_cfm.mdl,
&app_idx, &mcl_idx, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_MCA_CLOSE_IND_EVT:
if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_ind.mdl,
&app_idx, &mcl_idx, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_API_SEND_DATA_EVT:
if (bta_hl_find_mdl_idx_using_handle(p_msg->api_send_data.mdl_handle,
&app_idx, &mcl_idx, &mdl_idx ))
{
found = TRUE;
}
break;
case BTA_HL_MCA_CONG_CHG_EVT:
if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.cong_chg.mdl,
&app_idx, &mcl_idx, &mdl_idx ))
{
found = TRUE;
}
break;
case BTA_HL_MCA_RCV_DATA_EVT:
app_idx = p_msg->mca_rcv_data_evt.app_idx;
mcl_idx = p_msg->mca_rcv_data_evt.mcl_idx;
mdl_idx = p_msg->mca_rcv_data_evt.mdl_idx;
found = TRUE;
break;
case BTA_HL_DCH_RECONNECT_EVT:
case BTA_HL_DCH_OPEN_EVT:
case BTA_HL_DCH_ECHO_TEST_EVT:
case BTA_HL_DCH_SDP_FAIL_EVT:
app_idx = p_msg->dch_sdp.app_idx;
mcl_idx = p_msg->dch_sdp.mcl_idx;
mdl_idx = p_msg->dch_sdp.mdl_idx;
found = TRUE;
break;
case BTA_HL_MCA_RECONNECT_CFM_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.reconnect_cfm.mdl_id, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_API_DCH_CREATE_RSP_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->api_dch_create_rsp.mcl_handle, &app_idx, &mcl_idx)&&
bta_hl_find_mdl_idx( app_idx, mcl_idx,p_msg->api_dch_create_rsp.mdl_id, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_MCA_ABORT_IND_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
bta_hl_find_mdl_idx( app_idx, mcl_idx,p_msg->mca_evt.mca_data.abort_ind.mdl_id, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_MCA_ABORT_CFM_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) &&
bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.abort_cfm.mdl_id, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_CI_GET_TX_DATA_EVT:
case BTA_HL_CI_PUT_RX_DATA_EVT:
if (bta_hl_find_mdl_idx_using_handle(p_msg->ci_get_put_data.mdl_handle, &app_idx, &mcl_idx, &mdl_idx))
{
found = TRUE;
}
break;
case BTA_HL_CI_GET_ECHO_DATA_EVT:
case BTA_HL_CI_PUT_ECHO_DATA_EVT:
if (bta_hl_find_mcl_idx_using_handle(p_msg->ci_get_put_echo_data.mcl_handle, &app_idx, &mcl_idx))
{
p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
mdl_idx = p_mcb->echo_mdl_idx;
found = TRUE;
}
break;
default:
break;
}
if (found)
{
*p_app_idx = app_idx;
*p_mcl_idx = mcl_idx;
*p_mdl_idx = mdl_idx;
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_dch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d",
bta_hl_evt_code(p_msg->hdr.event), found, *p_app_idx, *p_mcl_idx, *p_mdl_idx );
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_allocate_mdl_id
**
** Description This function allocates a MDL ID
**
** Returns UINT16 - MDL ID
**
*******************************************************************************/
UINT16 bta_hl_allocate_mdl_id(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx )
{
UINT16 mdl_id=0;
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BOOLEAN duplicate_id;
UINT8 i, mdl_cfg_idx;
do
{
duplicate_id = FALSE;
mdl_id = ((mdl_id+1) & 0xFEFF);
/* check mdl_ids that are used for the current conenctions */
for (i=0; i< BTA_HL_NUM_MDLS_PER_MCL; i++)
{
if (p_mcb->mdl[i].in_use &&
(i != mdl_idx) &&
(p_mcb->mdl[i].mdl_id == mdl_id) )
{
duplicate_id = TRUE;
break;
}
}
if (duplicate_id)
{
/* start from the beginning to get another MDL value*/
continue;
}
else
{
/* check mdl_ids that are stored in the persistent memory */
if (bta_hl_find_mdl_cfg_idx(app_idx,mcl_idx, mdl_id, &mdl_cfg_idx))
{
duplicate_id = TRUE;
}
else
{
/* found a new MDL value */
break;
}
}
}while (TRUE);
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_allocate_mdl OK mdl_id=%d", mdl_id);
#endif
return mdl_id;
}
/*******************************************************************************
**
** Function bta_hl_find_mdl_idx
**
** Description This function finds the MDL index based on mdl_id
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, UINT16 mdl_id,
UINT8 *p_mdl_idx)
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
{
if (p_mcb->mdl[i].in_use &&
(mdl_id !=0) &&
(p_mcb->mdl[i].mdl_id== mdl_id))
{
found = TRUE;
*p_mdl_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_mdl_idx found=%d mdl_id=%d mdl_idx=%d ",
found, mdl_id, i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_an_active_mdl_idx
**
** Description This function finds an active MDL
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_an_active_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
UINT8 *p_mdl_idx)
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
{
if (p_mcb->mdl[i].in_use &&
(p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPEN_ST))
{
found = TRUE;
*p_mdl_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (found)
{
APPL_TRACE_DEBUG("bta_hl_find_an_opened_mdl_idx found=%d app_idx=%d mcl_idx=%d mdl_idx=%d",
found, app_idx, mcl_idx, i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_dch_setup_mdl_idx
**
** Description This function finds a MDL which in the DCH setup state
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_dch_setup_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
UINT8 *p_mdl_idx)
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
{
if (p_mcb->mdl[i].in_use &&
(p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPENING_ST))
{
found = TRUE;
*p_mdl_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (found)
{
APPL_TRACE_DEBUG("bta_hl_find_dch_setup_mdl_idx found=%d app_idx=%d mcl_idx=%d mdl_idx=%d",
found, app_idx, mcl_idx, i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_an_in_use_mcl_idx
**
** Description This function finds an in-use MCL control block index
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_an_in_use_mcl_idx(UINT8 app_idx,
UINT8 *p_mcl_idx)
{
tBTA_HL_MCL_CB *p_mcb;
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_MCLS ; i ++)
{
p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, i);
if (p_mcb->in_use &&
(p_mcb->cch_state != BTA_HL_CCH_IDLE_ST))
{
found = TRUE;
*p_mcl_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (found)
{
APPL_TRACE_DEBUG("bta_hl_find_an_in_use_mcl_idx found=%d app_idx=%d mcl_idx=%d ",
found, app_idx, i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_an_in_use_app_idx
**
** Description This function finds an in-use application control block index
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_an_in_use_app_idx(UINT8 *p_app_idx)
{
tBTA_HL_APP_CB *p_acb ;
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_APPS ; i ++)
{
p_acb = BTA_HL_GET_APP_CB_PTR(i);
if (p_acb->in_use)
{
found = TRUE;
*p_app_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (found)
{
APPL_TRACE_DEBUG("bta_hl_find_an_in_use_app_idx found=%d app_idx=%d ",
found, i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_app_idx
**
** Description This function finds the application control block index based on
** the application ID
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_app_idx(UINT8 app_id, UINT8 *p_app_idx)
{
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_APPS ; i ++)
{
if (bta_hl_cb.acb[i].in_use &&
(bta_hl_cb.acb[i].app_id == app_id))
{
found = TRUE;
*p_app_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_find_app_idx found=%d app_id=%d idx=%d ",
found, app_id, i);
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_app_idx_using_handle
**
** Description This function finds the application control block index based on
** the application handle
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
UINT8 *p_app_idx)
{
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_APPS ; i ++)
{
if (bta_hl_cb.acb[i].in_use &&
(bta_hl_cb.acb[i].app_handle == app_handle))
{
found = TRUE;
*p_app_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_app_idx_using_mca_handle status=%d handle=%d app_idx=%d ",
found, app_handle , i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_mcl_idx_using_handle
**
** Description This function finds the MCL control block index based on
** the MCL handle
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_mcl_idx_using_handle( tBTA_HL_MCL_HANDLE mcl_handle,
UINT8 *p_app_idx, UINT8 *p_mcl_idx)
{
tBTA_HL_APP_CB *p_acb;
BOOLEAN found=FALSE;
UINT8 i = 0,j = 0;
for (i=0; i<BTA_HL_NUM_APPS; i++)
{
p_acb = BTA_HL_GET_APP_CB_PTR(i);
if (p_acb->in_use)
{
for (j=0; j < BTA_HL_NUM_MCLS ; j++)
{
if ( p_acb->mcb[j].mcl_handle == mcl_handle )
{
found = TRUE;
*p_app_idx = i;
*p_mcl_idx = j;
break;
}
}
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_mcl_idx_using_handle found=%d app_idx=%d mcl_idx=%d",
found, i, j);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_mcl_idx
**
** Description This function finds the MCL control block index based on
** the peer BD address
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_mcl_idx(UINT8 app_idx, BD_ADDR p_bd_addr, UINT8 *p_mcl_idx)
{
BOOLEAN found=FALSE;
UINT8 i;
tBTA_HL_MCL_CB *p_mcb;
for (i=0; i < BTA_HL_NUM_MCLS ; i ++)
{
p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, i);
if (bta_hl_cb.acb[app_idx].mcb[i].in_use &&
(!memcmp (bta_hl_cb.acb[app_idx].mcb[i].bd_addr, p_bd_addr, BD_ADDR_LEN)))
{
found = TRUE;
*p_mcl_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_mcl_idx found=%d idx=%d",
found, i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_mdl_idx_using_handle
**
** Description This function finds the MDL control block index based on
** the MDL handle
**
** Returns BOOLEAN TRUE-found
**
*******************************************************************************/
BOOLEAN bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
UINT8 *p_app_idx,UINT8 *p_mcl_idx,
UINT8 *p_mdl_idx)
{
tBTA_HL_APP_CB *p_acb;
tBTA_HL_MCL_CB *p_mcb;
tBTA_HL_MDL_CB *p_dcb;
BOOLEAN found=FALSE;
UINT8 i,j,k;
for (i=0; i < BTA_HL_NUM_APPS ; i ++)
{
p_acb = BTA_HL_GET_APP_CB_PTR(i);
if (p_acb->in_use)
{
for (j=0; j< BTA_HL_NUM_MCLS; j++)
{
p_mcb = BTA_HL_GET_MCL_CB_PTR(i,j);
if (p_mcb->in_use)
{
for (k=0; k< BTA_HL_NUM_MDLS_PER_MCL; k++)
{
p_dcb = BTA_HL_GET_MDL_CB_PTR(i,j,k);
if (p_dcb->in_use)
{
if (p_dcb->mdl_handle == mdl_handle)
{
found = TRUE;
*p_app_idx = i;
*p_mcl_idx =j;
*p_mdl_idx = k;
break;
}
}
}
}
}
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_mdl_idx_using_handle found=%d mdl_handle=%d ",
found, mdl_handle);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_is_the_first_reliable_existed
**
** Description This function checks whether the first reliable DCH channel
** has been setup on the MCL or not
**
** Returns BOOLEAN - TRUE exist
** FALSE does not exist
**
*******************************************************************************/
BOOLEAN bta_hl_is_the_first_reliable_existed(UINT8 app_idx, UINT8 mcl_idx )
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BOOLEAN is_existed =FALSE;
UINT8 i ;
for (i=0; i< BTA_HL_NUM_MDLS_PER_MCL; i++)
{
if (p_mcb->mdl[i].in_use && p_mcb->mdl[i].is_the_first_reliable)
{
is_existed = TRUE;
break;
}
}
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_is_the_first_reliable_existed is_existed=%d ",is_existed );
#endif
return is_existed;
}
/*******************************************************************************
**
** Function bta_hl_find_non_active_mdl_cfg
**
** Description This function finds a valid MDL configiration index and this
** MDL ID is not active
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_non_active_mdl_cfg(UINT8 app_idx, UINT8 start_mdl_cfg_idx,
UINT8 *p_mdl_cfg_idx)
{
tBTA_HL_MCL_CB *p_mcb;
tBTA_HL_MDL_CB *p_dcb;
tBTA_HL_MDL_CFG *p_mdl;
BOOLEAN mdl_in_use;
BOOLEAN found = FALSE;
UINT8 i,j,k;
for (i = start_mdl_cfg_idx; i< BTA_HL_NUM_MDL_CFGS; i++)
{
mdl_in_use = FALSE;
p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
for (j=0; j< BTA_HL_NUM_MCLS; j++)
{
p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, j);
if (p_mcb->in_use &&
!memcmp(p_mdl->peer_bd_addr,p_mcb->bd_addr,BD_ADDR_LEN))
{
for (k=0; k<BTA_HL_NUM_MDLS_PER_MCL; k++)
{
p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, j, k);
if (p_dcb->in_use && p_mdl->mdl_id == p_dcb->mdl_id)
{
mdl_in_use = TRUE;
break;
}
}
}
if (mdl_in_use)
{
break;
}
}
if (!mdl_in_use)
{
*p_mdl_cfg_idx = i;
found = TRUE;
break;
}
}
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_mdl_cfg_idx
**
** Description This function finds an available MDL configuration index
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_avail_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx,
UINT8 *p_mdl_cfg_idx)
{
tBTA_HL_MDL_CFG *p_mdl, *p_mdl1, *p_mdl2;
UINT8 i;
BOOLEAN found=FALSE;
UINT8 first_mdl_cfg_idx, second_mdl_cfg_idx, older_mdl_cfg_idx;
BOOLEAN done;
UNUSED(mcl_idx);
for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++)
{
p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
if (!p_mdl->active )
{
/* found an unused space to store mdl cfg*/
found=TRUE;
*p_mdl_cfg_idx =i;
break;
}
}
if (!found)
{
/* all available mdl cfg spaces are in use so we need to find the mdl cfg which is
not currently in use and has the the oldest time stamp to remove*/
found = TRUE;
if (bta_hl_find_non_active_mdl_cfg(app_idx,0, &first_mdl_cfg_idx))
{
if (bta_hl_find_non_active_mdl_cfg(app_idx,(UINT8) (first_mdl_cfg_idx+1), &second_mdl_cfg_idx))
{
done = FALSE;
while (!done)
{
p_mdl1 = BTA_HL_GET_MDL_CFG_PTR(app_idx, first_mdl_cfg_idx);
p_mdl2 = BTA_HL_GET_MDL_CFG_PTR(app_idx, second_mdl_cfg_idx);
if (p_mdl1->time < p_mdl2->time)
{
older_mdl_cfg_idx = first_mdl_cfg_idx;
}
else
{
older_mdl_cfg_idx = second_mdl_cfg_idx;
}
if (bta_hl_find_non_active_mdl_cfg(app_idx,(UINT8) (second_mdl_cfg_idx+1), &second_mdl_cfg_idx))
{
first_mdl_cfg_idx = older_mdl_cfg_idx;
}
else
{
done = TRUE;
}
}
*p_mdl_cfg_idx = older_mdl_cfg_idx;
}
else
{
*p_mdl_cfg_idx = first_mdl_cfg_idx;
}
}
else
{
found = FALSE;
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_avail_mdl_cfg_idx found=%d mdl_cfg_idx=%d ",found, *p_mdl_cfg_idx );
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_mdl_cfg_idx
**
** Description This function finds the MDL configuration index based on
** the MDL ID
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx,
tBTA_HL_MDL_ID mdl_id, UINT8 *p_mdl_cfg_idx)
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
tBTA_HL_MDL_CFG *p_mdl;
UINT8 i ;
BOOLEAN found=FALSE;
*p_mdl_cfg_idx = 0;
for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++)
{
p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
if(p_mdl->active)
APPL_TRACE_DEBUG("bta_hl_find_mdl_cfg_idx: mdl_id =%d, p_mdl->mdl_id=%d",mdl_id,
p_mdl->mdl_id);
if (p_mdl->active &&
(!memcmp (p_mcb->bd_addr, p_mdl->peer_bd_addr, BD_ADDR_LEN))&&
(p_mdl->mdl_id == mdl_id))
{
found=TRUE;
*p_mdl_cfg_idx =i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_mdl_cfg_idx found=%d mdl_cfg_idx=%d ",found, i );
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_get_cur_time
**
** Description This function get the cuurent time value
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_get_cur_time(UINT8 app_idx, UINT8 *p_cur_time)
{
tBTA_HL_MDL_CFG *p_mdl;
UINT8 i, j, time_latest, time;
BOOLEAN found=FALSE, result=TRUE;
for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++)
{
p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
if (p_mdl->active)
{
found=TRUE;
time_latest = p_mdl->time;
for (j=(i+1); j< BTA_HL_NUM_MDL_CFGS; j++ )
{
p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, j);
if (p_mdl->active)
{
time = p_mdl->time;
if (time > time_latest)
{
time_latest = time;
}
}
}
break;
}
}
if (found)
{
if (time_latest < BTA_HL_MAX_TIME)
{
*p_cur_time = time_latest+1;
}
else
{
/* need to wrap around */
result = FALSE;
}
}
else
{
*p_cur_time = BTA_HL_MIN_TIME;
}
#if BTA_HL_DEBUG == TRUE
if (!result)
{
APPL_TRACE_DEBUG("bta_hl_get_cur_time result=%s cur_time=%d",
(result?"OK":"FAIL"), *p_cur_time);
}
#endif
return result;
}
/*******************************************************************************
**
** Function bta_hl_sort_cfg_time_idx
**
** Description This function sort the mdl configuration idx stored in array a
** based on decending time value
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
void bta_hl_sort_cfg_time_idx(UINT8 app_idx, UINT8 *a, UINT8 n)
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
UINT8 temp_time, temp_idx;
INT16 i, j;
for (i = 1; i < n; ++i)
{
temp_idx = a[i];
temp_time = p_acb->mdl_cfg[temp_idx].time;
j = i - 1;
while ((j >= 0) && (temp_time < p_acb->mdl_cfg[a[j]].time))
{
a[j + 1] = a[j];
--j;
}
a[j + 1] = temp_idx;
}
}
/*******************************************************************************
**
** Function bta_hl_compact_mdl_cfg_time
**
** Description This function finds the MDL configuration index based on
** the MDL ID
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
void bta_hl_compact_mdl_cfg_time(UINT8 app_idx, UINT8 mdep_id)
{
tBTA_HL_MDL_CFG *p_mdl;
UINT8 i, time_min, cnt=0;
UINT8 s_arr[BTA_HL_NUM_MDL_CFGS];
for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++)
{
p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
if (p_mdl->active )
{
s_arr[cnt]= i;
cnt++;
}
}
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_compact_mdl_cfg_time cnt=%d ",cnt );
#endif
if (cnt)
{
bta_hl_sort_cfg_time_idx(app_idx, s_arr, cnt);
time_min = BTA_HL_MIN_TIME;
for (i=0;i<cnt; i++)
{
p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, s_arr[i]);
p_mdl->time = time_min + i;
bta_hl_co_save_mdl(mdep_id, s_arr[i], p_mdl);
}
}
}
/*******************************************************************************
**
** Function bta_hl_is_mdl_exsit_in_mcl
**
** Description This function checks whether the MDL ID
** has already existed in teh MCL or not
**
** Returns BOOLEAN - TRUE exist
** FALSE does not exist
**
*******************************************************************************/
BOOLEAN bta_hl_is_mdl_exsit_in_mcl(UINT8 app_idx, BD_ADDR bd_addr,
tBTA_HL_MDL_ID mdl_id)
{
tBTA_HL_MDL_CFG *p_mdl;
BOOLEAN found = FALSE;
UINT8 i;
for (i = 0; i< BTA_HL_NUM_MDL_CFGS; i++)
{
p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
if (p_mdl->active &&
!memcmp(p_mdl->peer_bd_addr, bd_addr,BD_ADDR_LEN))
{
if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS)
{
if (p_mdl->mdl_id == mdl_id)
{
found = TRUE;
break;
}
}
else
{
found = TRUE;
break;
}
}
}
return found;
}
/*******************************************************************************
**
** Function bta_hl_delete_mdl_cfg
**
** Description This function delete the specified MDL ID
**
** Returns BOOLEAN - TRUE Success
** FALSE Failed
**
*******************************************************************************/
BOOLEAN bta_hl_delete_mdl_cfg(UINT8 app_idx, BD_ADDR bd_addr,
tBTA_HL_MDL_ID mdl_id)
{
tBTA_HL_MDL_CFG *p_mdl;
BOOLEAN success = FALSE;
UINT8 i;
for (i = 0; i< BTA_HL_NUM_MDL_CFGS; i++)
{
p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
if (p_mdl->active &&
!memcmp(p_mdl->peer_bd_addr, bd_addr,BD_ADDR_LEN))
{
if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS)
{
if (p_mdl->mdl_id == mdl_id)
{
bta_hl_co_delete_mdl(p_mdl->local_mdep_id, i);
memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
success = TRUE;
break;
}
}
else
{
bta_hl_co_delete_mdl(p_mdl->local_mdep_id, i);
memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
success = TRUE;
}
}
}
return success;
}
/*******************************************************************************
**
** Function bta_hl_is_mdl_value_valid
**
**
** Description This function checks the specified MDL ID is in valid range or not
**
** Returns BOOLEAN - TRUE Success
** FALSE Failed
**
** note: mdl_id range 0x0000 reserved,
** 0x0001-oxFEFF dynamic range,
** 0xFF00-0xFFFE reserved,
** 0xFFFF indicates all MDLs (for delete operation only)
**
*******************************************************************************/
BOOLEAN bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id)
{
BOOLEAN status = TRUE;
if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS)
{
if (mdl_id != 0)
{
if (mdl_id > BTA_HL_MAX_MDL_VAL )
{
status = FALSE;
}
}
else
{
status = FALSE;
}
}
return status;
}
/*******************************************************************************
**
** Function bta_hl_find_mdep_cfg_idx
**
** Description This function finds the MDEP configuration index based
** on the local MDEP ID
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_mdep_cfg_idx(UINT8 app_idx, tBTA_HL_MDEP_ID local_mdep_id,
UINT8 *p_mdep_cfg_idx)
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tBTA_HL_SUP_FEATURE *p_sup_feature= &p_acb->sup_feature;
BOOLEAN found =FALSE;
UINT8 i;
for (i=0; i< p_sup_feature->num_of_mdeps; i++)
{
if ( p_sup_feature->mdep[i].mdep_id == local_mdep_id)
{
found = TRUE;
*p_mdep_cfg_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_mdep_cfg_idx found=%d mdep_idx=%d local_mdep_id=%d ",
found,i, local_mdep_id );
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_rxtx_apdu_size
**
** Description This function finds the maximum APDU rx and tx sizes based on
** the MDEP configuration data
**
** Returns void
**
*******************************************************************************/
void bta_hl_find_rxtx_apdu_size(UINT8 app_idx, UINT8 mdep_cfg_idx,
UINT16 *p_rx_apu_size,
UINT16 *p_tx_apu_size)
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tBTA_HL_MDEP_CFG *p_mdep_cfg;
UINT8 i;
UINT16 max_rx_apdu_size=0, max_tx_apdu_size=0;
p_mdep_cfg = &p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg;
for (i=0; i< p_mdep_cfg->num_of_mdep_data_types ; i++)
{
if (max_rx_apdu_size < p_mdep_cfg->data_cfg[i].max_rx_apdu_size)
{
max_rx_apdu_size = p_mdep_cfg->data_cfg[i].max_rx_apdu_size;
}
if (max_tx_apdu_size < p_mdep_cfg->data_cfg[i].max_tx_apdu_size)
{
max_tx_apdu_size = p_mdep_cfg->data_cfg[i].max_tx_apdu_size;
}
}
*p_rx_apu_size = max_rx_apdu_size;
*p_tx_apu_size = max_tx_apdu_size;
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_find_rxtx_apdu_size max_rx_apdu_size=%d max_tx_apdu_size=%d ",
max_rx_apdu_size, max_tx_apdu_size );
#endif
}
/*******************************************************************************
**
** Function bta_hl_validate_peer_cfg
**
** Description This function validates the peer DCH configuration
**
** Returns BOOLEAN - TRUE validation is successful
** FALSE validation failed
**
*******************************************************************************/
BOOLEAN bta_hl_validate_peer_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,
tBTA_HL_MDEP_ID peer_mdep_id,
tBTA_HL_MDEP_ROLE peer_mdep_role,
UINT8 sdp_idx)
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
tBTA_HL_SDP_REC *p_rec;
BOOLEAN peer_found =FALSE;
UINT8 i;
APPL_TRACE_DEBUG("bta_hl_validate_peer_cfg sdp_idx=%d app_idx %d", sdp_idx, app_idx);
if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID)
{
return TRUE;
}
p_rec = &p_mcb->sdp.sdp_rec[sdp_idx];
for (i=0; i< p_rec->num_mdeps; i++)
{
APPL_TRACE_DEBUG("mdep_id %d peer_mdep_id %d",p_rec->mdep_cfg[i].mdep_id , peer_mdep_id);
APPL_TRACE_DEBUG("mdep_role %d peer_mdep_role %d",p_rec->mdep_cfg[i].mdep_role,
peer_mdep_role)
if ( (p_rec->mdep_cfg[i].mdep_id == peer_mdep_id) &&
(p_rec->mdep_cfg[i].mdep_role == peer_mdep_role))
{
peer_found = TRUE;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (!peer_found)
{
APPL_TRACE_DEBUG("bta_hl_validate_peer_cfg failed num_mdeps=%d",p_rec->num_mdeps);
}
#endif
return peer_found;
}
/*******************************************************************************
**
** Function bta_hl_chk_local_cfg
**
** Description This function check whether the local DCH configuration is OK or not
**
** Returns tBTA_HL_STATUS - OK - local DCH configuration is OK
** NO_FIRST_RELIABLE - the streaming DCH configuration
** is not OK and it needs to use
** reliable DCH configuration
**
*******************************************************************************/
tBTA_HL_STATUS bta_hl_chk_local_cfg(UINT8 app_idx, UINT8 mcl_idx,
UINT8 mdep_cfg_idx,
tBTA_HL_DCH_CFG local_cfg)
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
if ( mdep_cfg_idx &&
(p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE) &&
(!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) &&
(local_cfg != BTA_HL_DCH_CFG_RELIABLE))
{
status = BTA_HL_STATUS_NO_FIRST_RELIABLE;
APPL_TRACE_ERROR("BTA_HL_STATUS_INVALID_DCH_CFG");
}
return status;
}
/*******************************************************************************
**
** Function bta_hl_validate_reconnect_params
**
** Description This function validates the reconnect parameters
**
** Returns BOOLEAN - TRUE validation is successful
** FALSE validation failed
*******************************************************************************/
BOOLEAN bta_hl_validate_reconnect_params(UINT8 app_idx, UINT8 mcl_idx,
tBTA_HL_API_DCH_RECONNECT *p_reconnect,
UINT8 *p_mdep_cfg_idx, UINT8 *p_mdl_cfg_idx)
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tBTA_HL_SUP_FEATURE *p_sup_feature = &p_acb->sup_feature;
UINT8 num_mdeps;
UINT8 mdl_cfg_idx;
BOOLEAN local_mdep_id_found =FALSE;
BOOLEAN mdl_cfg_found =FALSE;
BOOLEAN status=FALSE;
UINT8 i, in_use_mdl_idx = 0;
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_validate_reconnect_params mdl_id=%d app_idx=%d", p_reconnect->mdl_id, app_idx);
#endif
if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect->mdl_id, &mdl_cfg_idx))
{
mdl_cfg_found = TRUE;
}
#if BTA_HL_DEBUG == TRUE
if (!mdl_cfg_found)
{
APPL_TRACE_DEBUG("mdl_cfg_found not found");
}
#endif
if (mdl_cfg_found)
{
num_mdeps = p_sup_feature->num_of_mdeps;
for (i=0; i< num_mdeps ; i++)
{
if ( p_sup_feature->mdep[i].mdep_id == p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id)
{
local_mdep_id_found = TRUE;
*p_mdep_cfg_idx =i;
*p_mdl_cfg_idx = mdl_cfg_idx;
break;
}
}
}
#if BTA_HL_DEBUG == TRUE
if (!local_mdep_id_found)
{
APPL_TRACE_DEBUG("local_mdep_id not found");
}
#endif
if (local_mdep_id_found)
{
if (!bta_hl_find_mdl_idx(app_idx,mcl_idx, p_reconnect->mdl_id, &in_use_mdl_idx))
{
status= TRUE;
}
else
{
APPL_TRACE_ERROR("mdl_id=%d is curreltly in use",p_reconnect->mdl_id);
}
}
#if BTA_HL_DEBUG == TRUE
if (!status)
{
APPL_TRACE_DEBUG("Reconnect validation failed local_mdep_id found=%d mdl_cfg_idx found=%d in_use_mdl_idx=%d ",
local_mdep_id_found, mdl_cfg_found, in_use_mdl_idx);
}
#endif
return status;
}
/*******************************************************************************
**
** Function bta_hl_find_avail_mcl_idx
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_avail_mcl_idx(UINT8 app_idx, UINT8 *p_mcl_idx)
{
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_MCLS ; i ++)
{
if (!bta_hl_cb.acb[app_idx].mcb[i].in_use)
{
found = TRUE;
*p_mcl_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_avail_mcl_idx found=%d idx=%d",
found, i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_find_avail_mdl_idx
**
** Description This function finds an available MDL control block index
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_avail_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
UINT8 *p_mdl_idx)
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
{
if (!p_mcb->mdl[i].in_use)
{
memset((void *)&p_mcb->mdl[i],0, sizeof(tBTA_HL_MDL_CB));
found = TRUE;
*p_mdl_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_avail_mdl_idx found=%d idx=%d",
found, i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_is_a_duplicate_id
**
** Description This function finds the application has been used or not
**
** Returns BOOLEAN - TRUE the app_id is a duplicate ID
** FALSE not a duplicate ID
*******************************************************************************/
BOOLEAN bta_hl_is_a_duplicate_id(UINT8 app_id)
{
BOOLEAN is_duplicate=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_APPS ; i ++)
{
if (bta_hl_cb.acb[i].in_use &&
(bta_hl_cb.acb[i].app_id == app_id))
{
is_duplicate = TRUE;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (is_duplicate)
{
APPL_TRACE_DEBUG("bta_hl_is_a_duplicate_id app_id=%d is_duplicate=%d",
app_id, is_duplicate);
}
#endif
return is_duplicate;
}
/*******************************************************************************
**
** Function bta_hl_find_avail_app_idx
**
** Description This function finds an available application control block index
**
** Returns BOOLEAN - TRUE found
** FALSE not found
**
*******************************************************************************/
BOOLEAN bta_hl_find_avail_app_idx(UINT8 *p_idx)
{
BOOLEAN found=FALSE;
UINT8 i;
for (i=0; i < BTA_HL_NUM_APPS ; i ++)
{
if (!bta_hl_cb.acb[i].in_use)
{
found = TRUE;
*p_idx = i;
break;
}
}
#if BTA_HL_DEBUG == TRUE
if (!found)
{
APPL_TRACE_DEBUG("bta_hl_find_avail_app_idx found=%d app_idx=%d",
found, i);
}
#endif
return found;
}
/*******************************************************************************
**
** Function bta_hl_app_update
**
** Description This function registers an HDP application MCAP and DP
**
** Returns tBTA_HL_STATUS -registration status
**
*******************************************************************************/
tBTA_HL_STATUS bta_hl_app_update(UINT8 app_id, BOOLEAN is_register)
{
tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(0);
tMCA_CS mca_cs;
UINT8 i, mdep_idx, num_of_mdeps;
UINT8 mdep_counter = 0;
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_app_update app_id=%d", app_id);
#endif
if (is_register)
{
if ((status == BTA_HL_STATUS_OK) &&
bta_hl_co_get_num_of_mdep(app_id, &num_of_mdeps))
{
for (i=0; i < num_of_mdeps; i++)
{
mca_cs.type = MCA_TDEP_DATA;
mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
mca_cs.p_data_cback = bta_hl_mcap_data_cback;
/* Find the first available mdep index, and create a MDL Endpoint */
// make a function later if needed
for (mdep_idx = 1; mdep_idx < BTA_HL_NUM_MDEPS; mdep_idx++)
{
if ( p_acb->sup_feature.mdep[mdep_idx].mdep_id == 0)
{
break; /* We found an available index */
}
else
{
mdep_counter++;
}
}
/* If no available MDEPs, return error */
if (mdep_idx == BTA_HL_NUM_MDEPS)
{
APPL_TRACE_ERROR("bta_hl_app_update: Out of MDEP IDs");
status = BTA_HL_STATUS_MCAP_REG_FAIL;
break;
}
if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
&(p_acb->sup_feature.mdep[mdep_idx].mdep_id), &mca_cs) == MCA_SUCCESS)
{
if (bta_hl_co_get_mdep_config(app_id,
mdep_idx,
mdep_counter,
p_acb->sup_feature.mdep[mdep_idx].mdep_id,
&p_acb->sup_feature.mdep[mdep_idx].mdep_cfg))
{
p_acb->sup_feature.mdep[mdep_idx].ori_app_id = app_id;
APPL_TRACE_DEBUG("mdep idx %d id %d ori_app_id %d num data type %d",mdep_idx,
p_acb->sup_feature.mdep[mdep_idx].mdep_id,
p_acb->sup_feature.mdep[mdep_idx].ori_app_id,
p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.num_of_mdep_data_types);
if (p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role ==
BTA_HL_MDEP_ROLE_SOURCE)
{
p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
}
else if (p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role ==
BTA_HL_MDEP_ROLE_SINK)
{
p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
}
else
{
APPL_TRACE_ERROR("bta_hl_app_registration: Invalid Role %d",
p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role);
status = BTA_HL_STATUS_MDEP_CO_FAIL;
break;
}
}
else
{
APPL_TRACE_ERROR("bta_hl_app_registration: Cfg callout failed");
status = BTA_HL_STATUS_MDEP_CO_FAIL;
break;
}
}
else
{
APPL_TRACE_ERROR("bta_hl_app_registration: MCA_CreateDep failed");
status = BTA_HL_STATUS_MCAP_REG_FAIL;
break;
}
}
p_acb->sup_feature.num_of_mdeps += num_of_mdeps;
APPL_TRACE_DEBUG("num_of_mdeps %d", p_acb->sup_feature.num_of_mdeps);
if ((status == BTA_HL_STATUS_OK) &&
(p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE))
{
p_acb->sup_feature.advertize_source_sdp =
bta_hl_co_advrtise_source_sdp(app_id);
}
if ((status == BTA_HL_STATUS_OK)&&
(!bta_hl_co_get_echo_config(app_id, &p_acb->sup_feature.echo_cfg)))
{
status = BTA_HL_STATUS_ECHO_CO_FAIL;
}
if ((status == BTA_HL_STATUS_OK)&&
(!bta_hl_co_load_mdl_config(app_id, BTA_HL_NUM_MDL_CFGS, &p_acb->mdl_cfg[0])))
{
status = BTA_HL_STATUS_MDL_CFG_CO_FAIL;
}
}
else
{
status = BTA_HL_STATUS_MDEP_CO_FAIL;
}
}
else
{
for (i=1; i<BTA_HL_NUM_MDEPS; i++)
{
if (p_acb->sup_feature.mdep[i].ori_app_id == app_id)
{
APPL_TRACE_DEBUG("Found index %", i);
if (MCA_DeleteDep((tMCA_HANDLE)p_acb->app_handle,
(p_acb->sup_feature.mdep[i].mdep_id)) != MCA_SUCCESS)
{
APPL_TRACE_ERROR("Error deregistering");
status = BTA_HL_STATUS_MCAP_REG_FAIL;
return status;
}
memset(&p_acb->sup_feature.mdep[i], 0, sizeof(tBTA_HL_MDEP));
}
}
}
if (status == BTA_HL_STATUS_OK)
{
/* Register/Update MDEP(s) in SDP Record */
status = bta_hl_sdp_update(app_id);
}
/* else do cleanup */
return status;
}
/*******************************************************************************
**
** Function bta_hl_app_registration
**
** Description This function registers an HDP application MCAP and DP
**
** Returns tBTA_HL_STATUS -registration status
**
*******************************************************************************/
tBTA_HL_STATUS bta_hl_app_registration(UINT8 app_idx)
{
tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tMCA_REG reg;
tMCA_CS mca_cs;
UINT8 i, num_of_mdeps;
UINT8 mdep_counter = 0;
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_app_registration app_idx=%d", app_idx);
#endif
reg.ctrl_psm = p_acb->ctrl_psm;
reg.data_psm = p_acb->data_psm;
reg.sec_mask = p_acb->sec_mask;
reg.rsp_tout = BTA_HL_MCAP_RSP_TOUT;
if ( (p_acb->app_handle = (tBTA_HL_APP_HANDLE) MCA_Register(&reg, bta_hl_mcap_ctrl_cback))!=0)
{
mca_cs.type = MCA_TDEP_ECHO;
mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
mca_cs.p_data_cback = bta_hl_mcap_data_cback;
if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
&(p_acb->sup_feature.mdep[0].mdep_id),
&mca_cs) == MCA_SUCCESS)
{
if (p_acb->sup_feature.mdep[0].mdep_id != BTA_HL_ECHO_TEST_MDEP_ID)
{
status = BTA_HL_STATUS_MCAP_REG_FAIL;
APPL_TRACE_ERROR("BAD MDEP ID for echo test mdep_id=%d",
p_acb->sup_feature.mdep[0].mdep_id );
}
}
else
{
status = BTA_HL_STATUS_MCAP_REG_FAIL;
APPL_TRACE_ERROR("MCA_CreateDep for echo test(mdep_id=0) failed");
}
if ((status == BTA_HL_STATUS_OK) &&
bta_hl_co_get_num_of_mdep(p_acb->app_id, &num_of_mdeps))
{
p_acb->sup_feature.num_of_mdeps = num_of_mdeps+1;
for (i=1; i<p_acb->sup_feature.num_of_mdeps; i++)
{
mca_cs.type = MCA_TDEP_DATA;
mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
mca_cs.p_data_cback = bta_hl_mcap_data_cback;
if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
&(p_acb->sup_feature.mdep[i].mdep_id), &mca_cs) == MCA_SUCCESS)
{
if (bta_hl_co_get_mdep_config(p_acb->app_id,
i,mdep_counter,
p_acb->sup_feature.mdep[i].mdep_id,
&p_acb->sup_feature.mdep[i].mdep_cfg))
{
if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
{
p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
}
else if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SINK)
{
p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
}
else
{
status = BTA_HL_STATUS_MDEP_CO_FAIL;
break;
}
p_acb->sup_feature.mdep[i].ori_app_id = p_acb->app_id;
APPL_TRACE_DEBUG("index %d ori_app_id %d", i,
p_acb->sup_feature.mdep[i].ori_app_id);
}
else
{
status = BTA_HL_STATUS_MDEP_CO_FAIL;
break;
}
}
else
{
status = BTA_HL_STATUS_MCAP_REG_FAIL;
break;
}
}
if ((status == BTA_HL_STATUS_OK) &&
(p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE))
{
/* this is a source only applciation */
p_acb->sup_feature.advertize_source_sdp =
bta_hl_co_advrtise_source_sdp(p_acb->app_id);
}
if ((status == BTA_HL_STATUS_OK)&&
(!bta_hl_co_get_echo_config(p_acb->app_id, &p_acb->sup_feature.echo_cfg)))
{
status = BTA_HL_STATUS_ECHO_CO_FAIL;
}
if ((status == BTA_HL_STATUS_OK)&&
(!bta_hl_co_load_mdl_config(p_acb->app_id, BTA_HL_NUM_MDL_CFGS, &p_acb->mdl_cfg[0])))
{
status = BTA_HL_STATUS_MDL_CFG_CO_FAIL;
}
}
else
{
status = BTA_HL_STATUS_MDEP_CO_FAIL;
}
}
else
{
status = BTA_HL_STATUS_MCAP_REG_FAIL;
}
if (status == BTA_HL_STATUS_OK)
{
status = bta_hl_sdp_register(app_idx);
}
return status;
}
/*******************************************************************************
**
** Function bta_hl_discard_data
**
** Description This function discard an HDP event
**
** Returns void
**
*******************************************************************************/
void bta_hl_discard_data(UINT16 event, tBTA_HL_DATA *p_data)
{
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_ERROR("BTA HL Discard event=%s",bta_hl_evt_code(event));
#endif
switch (event)
{
case BTA_HL_API_SEND_DATA_EVT:
break;
case BTA_HL_MCA_RCV_DATA_EVT:
utl_freebuf((void**)&p_data->mca_rcv_data_evt.p_pkt);
break;
default:
/*Nothing to free*/
break;
}
}
/*******************************************************************************
**
** Function bta_hl_save_mdl_cfg
**
** Description This function saves the MDL configuration
**
** Returns void
**
*******************************************************************************/
void bta_hl_save_mdl_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx )
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
UINT8 mdl_cfg_idx;
tBTA_HL_MDL_ID mdl_id;
BOOLEAN found=TRUE;
tBTA_HL_MDL_CFG mdl_cfg;
tBTA_HL_MDEP *p_mdep_cfg;
tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
UINT8 time_val = 0;
mdl_id = p_dcb->mdl_id;
if (!bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx))
{
if (!bta_hl_find_avail_mdl_cfg_idx(app_idx, mcl_idx, &mdl_cfg_idx))
{
APPL_TRACE_ERROR("No space to save the MDL config");
found= FALSE; /*no space available*/
}
}
if (found)
{
bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg);
if (!bta_hl_get_cur_time(app_idx, &time_val ))
{
bta_hl_compact_mdl_cfg_time(app_idx,p_dcb->local_mdep_id);
bta_hl_get_cur_time(app_idx, &time_val);
}
mdl_cfg.active = TRUE;
mdl_cfg.time = time_val;
mdl_cfg.mdl_id = p_dcb->mdl_id;
mdl_cfg.dch_mode = p_dcb->dch_mode;
mdl_cfg.mtu = l2cap_cfg.mtu;
mdl_cfg.fcs = l2cap_cfg.fcs;
bdcpy(mdl_cfg.peer_bd_addr, p_mcb->bd_addr);
mdl_cfg.local_mdep_id= p_dcb->local_mdep_id;
p_mdep_cfg = &p_acb->sup_feature.mdep[p_dcb->local_mdep_cfg_idx];
mdl_cfg.local_mdep_role= p_mdep_cfg->mdep_cfg.mdep_role;
memcpy(&p_acb->mdl_cfg[mdl_cfg_idx], &mdl_cfg, sizeof(tBTA_HL_MDL_CFG));
bta_hl_co_save_mdl(mdl_cfg.local_mdep_id, mdl_cfg_idx, &mdl_cfg);
}
#if BTA_HL_DEBUG == TRUE
if (found)
{
if (p_dcb->mtu != l2cap_cfg.mtu)
{
APPL_TRACE_WARNING("MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from l2cap mtu=%d",
p_dcb->mtu, l2cap_cfg.mtu);
}
APPL_TRACE_DEBUG("bta_hl_save_mdl_cfg saved=%d", found);
APPL_TRACE_DEBUG("Saved. L2cap cfg mdl_id=%d mtu=%d fcs=%d dch_mode=%d",
mdl_cfg.mdl_id, mdl_cfg.mtu, mdl_cfg.fcs, mdl_cfg.dch_mode);
}
#endif
}
/*******************************************************************************
**
** Function bta_hl_set_dch_chan_cfg
**
** Description This function setups the L2CAP DCH channel configuration
**
** Returns void
*******************************************************************************/
void bta_hl_set_dch_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,tBTA_HL_DATA *p_data)
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
UINT8 l2cap_mode = L2CAP_FCR_ERTM_MODE;
tBTA_HL_SUP_FEATURE *p_sup_feature= &p_acb->sup_feature;
UINT8 local_mdep_cfg_idx = p_dcb->local_mdep_cfg_idx;
switch (p_dcb->dch_oper)
{
case BTA_HL_DCH_OP_LOCAL_RECONNECT:
case BTA_HL_DCH_OP_REMOTE_RECONNECT:
if (p_dcb->dch_mode == BTA_HL_DCH_MODE_STREAMING)
l2cap_mode = L2CAP_FCR_STREAM_MODE;
break;
case BTA_HL_DCH_OP_LOCAL_OPEN:
if (p_data->mca_evt.mca_data.create_cfm.cfg == BTA_HL_DCH_CFG_STREAMING)
l2cap_mode = L2CAP_FCR_STREAM_MODE;
break;
case BTA_HL_DCH_OP_REMOTE_OPEN:
if (p_dcb->local_cfg == BTA_HL_DCH_CFG_STREAMING )
l2cap_mode = L2CAP_FCR_STREAM_MODE;
break;
default:
APPL_TRACE_ERROR("Invalid dch oper=%d for set dch chan cfg", p_dcb->dch_oper);
break;
}
p_dcb->chnl_cfg.fcr_opt.mode = l2cap_mode;
p_dcb->chnl_cfg.fcr_opt.mps = bta_hl_set_mps(p_dcb->max_rx_apdu_size);
p_dcb->chnl_cfg.fcr_opt.tx_win_sz = bta_hl_set_tx_win_size(p_dcb->max_rx_apdu_size,
p_dcb->chnl_cfg.fcr_opt.mps);
p_dcb->chnl_cfg.fcr_opt.max_transmit= BTA_HL_L2C_MAX_TRANSMIT;
p_dcb->chnl_cfg.fcr_opt.rtrans_tout = BTA_HL_L2C_RTRANS_TOUT;
p_dcb->chnl_cfg.fcr_opt.mon_tout = BTA_HL_L2C_MON_TOUT;
p_dcb->chnl_cfg.user_rx_pool_id = bta_hl_set_user_rx_pool_id(p_dcb->max_rx_apdu_size);
p_dcb->chnl_cfg.user_tx_pool_id = bta_hl_set_user_tx_pool_id(p_dcb->max_tx_apdu_size);
p_dcb->chnl_cfg.fcr_rx_pool_id = BTA_HL_L2C_FCR_RX_POOL_ID;
p_dcb->chnl_cfg.fcr_tx_pool_id = BTA_HL_L2C_FCR_TX_POOL_ID;
p_dcb->chnl_cfg.data_mtu = p_dcb->max_rx_apdu_size;
p_dcb->chnl_cfg.fcs = BTA_HL_MCA_NO_FCS;
if (local_mdep_cfg_idx != BTA_HL_ECHO_TEST_MDEP_CFG_IDX)
{
if (p_sup_feature->mdep[local_mdep_cfg_idx].mdep_cfg.mdep_role ==
BTA_HL_MDEP_ROLE_SOURCE)
{
p_dcb->chnl_cfg.fcs = BTA_HL_DEFAULT_SOURCE_FCS;
}
}
else
{
p_dcb->chnl_cfg.fcs = BTA_HL_MCA_USE_FCS;
}
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("L2CAP Params l2cap_mode[3-ERTM 4-STREAM]=%d", l2cap_mode);
APPL_TRACE_DEBUG("Use FCS =%s mtu=%d", ((p_dcb->chnl_cfg.fcs & 1)?"YES":"NO"),
p_dcb->chnl_cfg.data_mtu);
APPL_TRACE_DEBUG("tx_win_sz=%d, max_transmit=%d, rtrans_tout=%d, mon_tout=%d, mps=%d",
p_dcb->chnl_cfg.fcr_opt.tx_win_sz,
p_dcb->chnl_cfg.fcr_opt.max_transmit,
p_dcb->chnl_cfg.fcr_opt.rtrans_tout,
p_dcb->chnl_cfg.fcr_opt.mon_tout,
p_dcb->chnl_cfg.fcr_opt.mps);
APPL_TRACE_DEBUG("USER rx_pool_id=%d, tx_pool_id=%d, FCR rx_pool_id=%d, tx_pool_id=%d",
p_dcb->chnl_cfg.user_rx_pool_id,
p_dcb->chnl_cfg.user_tx_pool_id,
p_dcb->chnl_cfg.fcr_rx_pool_id,
p_dcb->chnl_cfg.fcr_tx_pool_id);
#endif
}
/*******************************************************************************
**
** Function bta_hl_get_l2cap_cfg
**
** Description This function get the current L2CAP channel configuration
**
** Returns BOOLEAN - TRUE - operation is successful
*******************************************************************************/
BOOLEAN bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd, tBTA_HL_L2CAP_CFG_INFO *p_cfg)
{
BOOLEAN success = FALSE;
UINT16 lcid;
tL2CAP_CFG_INFO *p_our_cfg;
tL2CAP_CH_CFG_BITS our_cfg_bits;
tL2CAP_CFG_INFO *p_peer_cfg;
tL2CAP_CH_CFG_BITS peer_cfg_bits;
lcid = MCA_GetL2CapChannel((tMCA_DL) mdl_hnd);
if ( lcid &&
L2CA_GetCurrentConfig(lcid, &p_our_cfg, &our_cfg_bits, &p_peer_cfg,
&peer_cfg_bits))
{
p_cfg->fcs = BTA_HL_MCA_NO_FCS;
if (our_cfg_bits & L2CAP_CH_CFG_MASK_FCS)
{
p_cfg->fcs |= p_our_cfg->fcs;
}
else
{
p_cfg->fcs = BTA_HL_MCA_USE_FCS;
}
if (p_cfg->fcs != BTA_HL_MCA_USE_FCS )
{
if (peer_cfg_bits & L2CAP_CH_CFG_MASK_FCS)
{
p_cfg->fcs |= p_peer_cfg->fcs;
}
else
{
p_cfg->fcs = BTA_HL_MCA_USE_FCS;
}
}
p_cfg->mtu =0;
if (peer_cfg_bits & L2CAP_CH_CFG_MASK_MTU)
{
p_cfg->mtu = p_peer_cfg->mtu;
}
else
{
p_cfg->mtu = L2CAP_DEFAULT_MTU;
}
success = TRUE;
}
else
{
p_cfg->mtu = L2CAP_DEFAULT_MTU;
p_cfg->fcs = BTA_HL_L2C_NO_FCS;
}
#if BTA_HL_DEBUG == TRUE
if (!success)
{
APPL_TRACE_DEBUG("bta_hl_get_l2cap_cfg success=%d mdl=%d lcid=%d", success, mdl_hnd, lcid);
APPL_TRACE_DEBUG("l2cap mtu=%d fcs=%d", p_cfg->mtu, p_cfg->fcs);
}
#endif
return success;
}
/*******************************************************************************
**
** Function bta_hl_validate_chan_cfg
**
** Description This function validates the L2CAP channel configuration
**
** Returns BOOLEAN - TRUE - validation is successful
*******************************************************************************/
BOOLEAN bta_hl_validate_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx)
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
BOOLEAN success = FALSE;
UINT8 mdl_cfg_idx = 0;
tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
BOOLEAN get_l2cap_result, get_mdl_result;
get_l2cap_result = bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg);
get_mdl_result = bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_dcb->mdl_id, &mdl_cfg_idx);
if (get_l2cap_result && get_mdl_result)
{
if ((p_acb->mdl_cfg[mdl_cfg_idx].mtu <= l2cap_cfg.mtu) &&
(p_acb->mdl_cfg[mdl_cfg_idx].fcs == l2cap_cfg.fcs) &&
(p_acb->mdl_cfg[mdl_cfg_idx].dch_mode == p_dcb->dch_mode))
{
success = TRUE;
}
}
#if BTA_HL_DEBUG == TRUE
if (p_dcb->mtu != l2cap_cfg.mtu)
{
APPL_TRACE_WARNING("MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from l2cap mtu=%d",
p_dcb->mtu, l2cap_cfg.mtu);
}
if (!success)
{
APPL_TRACE_DEBUG("bta_hl_validate_chan_cfg success=%d app_idx=%d mcl_idx=%d mdl_idx=%d",success, app_idx, mcl_idx, mdl_idx);
APPL_TRACE_DEBUG("Cur. L2cap cfg mtu=%d fcs=%d dch_mode=%d", l2cap_cfg.mtu, l2cap_cfg.fcs, p_dcb->dch_mode);
APPL_TRACE_DEBUG("From saved: L2cap cfg mtu=%d fcs=%d dch_mode=%d", p_acb->mdl_cfg[mdl_cfg_idx].mtu,
p_acb->mdl_cfg[mdl_cfg_idx].fcs , p_acb->mdl_cfg[mdl_cfg_idx].dch_mode);
}
#endif
return success;
}
/*******************************************************************************
**
** Function bta_hl_is_cong_on
**
** Description This function checks whether the congestion condition is on or not
**
** Returns BOOLEAN - TRUE DCH is congested
** FALSE not congested
**
*******************************************************************************/
BOOLEAN bta_hl_is_cong_on(UINT8 app_id, BD_ADDR bd_addr, tBTA_HL_MDL_ID mdl_id)
{
tBTA_HL_MDL_CB *p_dcb;
UINT8 app_idx = 0, mcl_idx, mdl_idx;
BOOLEAN cong_status = TRUE;
if (bta_hl_find_app_idx(app_id, &app_idx))
{
if (bta_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx ))
{
if (bta_hl_find_mdl_idx(app_idx, mcl_idx, mdl_id, &mdl_idx ))
{
p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
cong_status = p_dcb->cong;
}
}
}
return cong_status;
}
/*******************************************************************************
**
** Function bta_hl_check_cch_close
**
** Description This function checks whether there is a pending CCH close request
** or not
**
** Returns void
*******************************************************************************/
void bta_hl_check_cch_close(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data, BOOLEAN check_dch_setup )
{
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
tBTA_HL_MDL_CB *p_dcb;
UINT8 mdl_idx;
#if (BTA_HL_DEBUG == TRUE)
APPL_TRACE_DEBUG("bta_hl_check_cch_close cch_close_dch_oper=%d",p_mcb->cch_close_dch_oper );
#endif
if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE)
{
if (check_dch_setup && bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx))
{
p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
if (!p_mcb->rsp_tout)
{
p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_ABORT;
if (!p_dcb->abort_oper)
{
p_dcb->abort_oper |= BTA_HL_ABORT_CCH_CLOSE_MASK;
bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT, p_data);
}
}
else
{
p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
}
}
else if (bta_hl_find_an_active_mdl_idx(app_idx, mcl_idx,&mdl_idx))
{
p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT, p_data);
}
else
{
p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_NONE;
bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_EVT, p_data);
}
}
}
/*******************************************************************************
**
** Function bta_hl_clean_app
**
** Description Cleans up the HDP application resources and control block
**
** Returns void
**
*******************************************************************************/
void bta_hl_clean_app(UINT8 app_idx)
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
int i, num_act_apps=0;
#if BTA_HL_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_hl_clean_app");
#endif
MCA_Deregister((tMCA_HANDLE)p_acb->app_handle);
if (p_acb->sdp_handle) SDP_DeleteRecord(p_acb->sdp_handle);
memset((void *) p_acb, 0, sizeof(tBTA_HL_APP_CB));
/* check any application is still active */
for (i=0; i < BTA_HL_NUM_APPS ; i ++)
{
p_acb = BTA_HL_GET_APP_CB_PTR(i);
if (p_acb->in_use) num_act_apps++;
}
if (!num_act_apps)
{
bta_sys_remove_uuid(UUID_SERVCLASS_HDP_PROFILE);
}
}
/*******************************************************************************
**
** Function bta_hl_check_deregistration
**
** Description This function checks whether there is a pending deregistration
** request or not
**
** Returns void
*******************************************************************************/
void bta_hl_check_deregistration(UINT8 app_idx, tBTA_HL_DATA *p_data )
{
tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
tBTA_HL_MCL_CB *p_mcb;
UINT8 mcl_idx;
tBTA_HL evt_data;
#if (BTA_HL_DEBUG == TRUE)
APPL_TRACE_DEBUG("bta_hl_check_deregistration");
#endif
if (p_acb->deregistering)
{
if (bta_hl_find_an_in_use_mcl_idx(app_idx, &mcl_idx))
{
p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE)
{
if (p_mcb->cch_state == BTA_HL_CCH_OPENING_ST)
p_mcb->force_close_local_cch_opening = TRUE;
p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
APPL_TRACE_DEBUG("p_mcb->force_close_local_cch_opening=%d", p_mcb->force_close_local_cch_opening );
bta_hl_check_cch_close(app_idx,mcl_idx,p_data, TRUE);
}
}
else
{
/* all cchs are closed */
evt_data.dereg_cfm.app_handle = p_acb->app_handle;
evt_data.dereg_cfm.app_id = p_data->api_dereg.app_id;
evt_data.dereg_cfm.status = BTA_HL_STATUS_OK;
p_acb->p_cback(BTA_HL_DEREGISTER_CFM_EVT, (tBTA_HL *) &evt_data );
bta_hl_clean_app(app_idx);
bta_hl_check_disable(p_data);
}
}
}
/*******************************************************************************
**
** Function bta_hl_check_disable
**
** Description This function checks whether there is a pending disable
** request or not
**
** Returns void
**
*******************************************************************************/
void bta_hl_check_disable(tBTA_HL_DATA *p_data )
{
tBTA_HL_CB *p_cb= &bta_hl_cb;
tBTA_HL_APP_CB *p_acb;
UINT8 app_idx;
tBTA_HL_CTRL evt_data;
#if (BTA_HL_DEBUG == TRUE)
APPL_TRACE_DEBUG("bta_hl_check_disable");
#endif
if (bta_hl_cb.disabling)
{
if (bta_hl_find_an_in_use_app_idx(&app_idx))
{
p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
if (!p_acb->deregistering)
{
p_acb->deregistering = TRUE;
bta_hl_check_deregistration(app_idx, p_data);
}
}
else
{
/* all apps are deregistered */
bta_sys_deregister(BTA_ID_HL);
evt_data.disable_cfm.status = BTA_HL_STATUS_OK;
if (p_cb->p_ctrl_cback) p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT, (tBTA_HL_CTRL *) &evt_data);
memset((void *) p_cb, 0, sizeof(tBTA_HL_CB