/******************************************************************************* ** ** Function bta_ag_sm_execute ** ** Description State machine event handling function for AG ** ** ** Returns void ** *******************************************************************************/ void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data) { tBTA_AG_ST_TBL state_table; UINT8 action; int i; UINT16 in_event = event; UINT8 in_state = p_scb->state; if (in_event != BTA_AG_API_RESULT_EVT || p_scb->state == BTA_AG_OPEN_ST) { #if BTA_AG_DEBUG == TRUE APPL_TRACE_IMP("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)", bta_ag_scb_to_idx(p_scb), p_scb->state, bta_ag_state_str(p_scb->state), event, bta_ag_evt_str(event, p_data->api_result.result)); #else APPL_TRACE_IMP("AG evt (hdl 0x%04x): State %d, Event 0x%04x", bta_ag_scb_to_idx(p_scb), p_scb->state, event); #endif } event &= 0x00FF; if (event >= (BTA_AG_MAX_EVT & 0x00FF)) { APPL_TRACE_ERROR("AG evt out of range, ignoring..."); return; } /* look up the state table for the current state */ state_table = bta_ag_st_tbl[p_scb->state]; /* set next state */ p_scb->state = state_table[event][BTA_AG_NEXT_STATE]; /* execute action functions */ for (i = 0; i < BTA_AG_ACTIONS; i++) { if ((action = state_table[event][i]) != BTA_AG_IGNORE) { (*bta_ag_action[action])(p_scb, p_data); } else { break; } } if (p_scb->state != in_state) { #if BTA_AG_DEBUG == TRUE APPL_TRACE_IMP("BTA AG State Change: [%s] -> [%s] after Event [%s]", bta_ag_state_str(in_state), bta_ag_state_str(p_scb->state), bta_ag_evt_str(in_event, p_data->api_result.result)); #else APPL_TRACE_IMP("BTA AG State Change: [%d] -> [%d]", in_state, p_scb->state); #endif } }
/******************************************************************************* ** ** Function bta_ag_api_result ** ** Description Handle an API result event. ** ** ** Returns void ** *******************************************************************************/ static void bta_ag_api_result(tBTA_AG_DATA *p_data) { tBTA_AG_SCB *p_scb; int i; if (p_data->hdr.layer_specific != BTA_AG_HANDLE_ALL) { if ((p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific)) != NULL) { APPL_TRACE_IMP("bta_ag_api_result: p_scb 0x%08x ", p_scb); bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data); } } else { for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++) { if (p_scb->in_use && p_scb->svc_conn) { APPL_TRACE_DEBUG("bta_ag_api_result p_scb 0x%08x ", p_scb); bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data); } } } }
/******************************************************************************* ** ** Function bta_ag_rfc_data ** ** Description Read and process data from RFCOMM. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { UINT16 len; char buf[BTA_AG_RFC_READ_MAX]; UNUSED(p_data); memset(buf, 0, BTA_AG_RFC_READ_MAX); APPL_TRACE_DEBUG ("bta_ag_rfc_data"); /* do the following */ for(;;) { /* read data from rfcomm; if bad status, we're done */ if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) != PORT_SUCCESS) { break; } /* if no data, we're done */ if (len == 0) { break; } /* run AT command interpreter on data */ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); bta_ag_at_parse(&p_scb->at_cb, buf, len); if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) && bta_ag_sco_is_open(p_scb)) { APPL_TRACE_IMP ("bta_ag_rfc_data, change link policy for SCO"); bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); } else { bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); } /* no more data to read, we're done */ if (len < BTA_AG_RFC_READ_MAX) { break; } } }
/******************************************************************************* ** ** Function bta_ag_ci_rx_data ** ** Description Send result code ** ** Returns void ** *******************************************************************************/ void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { UINT16 len; tBTA_AG_CI_RX_WRITE *p_rx_write_msg = (tBTA_AG_CI_RX_WRITE *)p_data; char *p_data_area = (char *)(p_rx_write_msg+1); /* Point to data area after header */ APPL_TRACE_DEBUG ("bta_ag_ci_rx_data:"); /* send to RFCOMM */ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len); if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) && bta_ag_sco_is_open(p_scb)) { APPL_TRACE_IMP ("bta_ag_rfc_data, change link policy for SCO"); bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); } else { bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); } }
/******************************************************************************* ** ** Function bta_ag_hdl_event ** ** Description Data gateway main event handling function. ** ** ** Returns BOOLEAN ** *******************************************************************************/ BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg) { tBTA_AG_SCB *p_scb; APPL_TRACE_DEBUG("bta_ag_hdl_event: Event 0x%04x ", p_msg->event); switch (p_msg->event) { /* handle enable event */ case BTA_AG_API_ENABLE_EVT: bta_ag_api_enable((tBTA_AG_DATA *) p_msg); break; /* handle disable event */ case BTA_AG_API_DISABLE_EVT: bta_ag_api_disable((tBTA_AG_DATA *) p_msg); break; /* handle register event */ case BTA_AG_API_REGISTER_EVT: bta_ag_api_register((tBTA_AG_DATA *) p_msg); break; /* handle result event */ case BTA_AG_API_RESULT_EVT: bta_ag_api_result((tBTA_AG_DATA *) p_msg); break; /* all others reference scb by handle */ default: if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL) { APPL_TRACE_IMP("bta_ag_hdl_event: p_scb 0x%08x ", p_scb); bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg); } break; } return TRUE; }
/******************************************************************************* ** ** Function bta_av_ssm_execute ** ** Description Stream state machine event handling function for AV ** ** ** Returns void ** *******************************************************************************/ void bta_av_ssm_execute(tBTA_AV_SCB *p_scb, UINT16 event, tBTA_AV_DATA *p_data) { tBTA_AV_SST_TBL state_table; UINT8 action; int i, xx; if(p_scb == NULL) { /* this stream is not registered */ APPL_TRACE_EVENT("AV channel not registered"); return; } /* In case incoming connection is for VDP, we need to swap scb. */ /* When ACP_CONNECT_EVT was received, we put first available scb to */ /* to Incoming state. Later, when STR_CONFIG_IND_EVT is coming, we */ /* know if it is A2DP or VDP. */ if ((p_scb->state == BTA_AV_INIT_SST) && (event == BTA_AV_STR_CONFIG_IND_EVT)) { for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { if (bta_av_cb.p_scb[xx]) { if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST) { bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST; bta_av_cb.p_scb[xx]->coll_mask = 0; p_scb->state = BTA_AV_INCOMING_SST; break; } } } } if ((event != BTA_AV_STR_WRITE_CFM_EVT) && (event != BTA_AV_SRC_DATA_READY_EVT)) { #if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) APPL_TRACE_IMP("AV Sevent(0x%x)=0x%x(%s) state=%d(%s)", p_scb->hndl, event, bta_av_evt_code(event), p_scb->state, bta_av_sst_code(p_scb->state)); #else APPL_TRACE_IMP("AV Sevent=0x%x state=%d", event, p_scb->state); #endif } /* look up the state table for the current state */ state_table = bta_av_sst_tbl[p_scb->state]; event -= BTA_AV_FIRST_SSM_EVT; /* set next state */ p_scb->state = state_table[event][BTA_AV_SNEXT_STATE]; /* execute action functions */ for(i=0; i< BTA_AV_SACTIONS; i++) { if ((action = state_table[event][i]) != BTA_AV_SIGNORE) { (*p_scb->p_act_tbl[action])(p_scb, p_data); } else break; } }
/******************************************************************************* ** ** Function bta_ag_rfc_acp_open ** ** Description Handle RFCOMM channel open when accepting connection. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { UINT16 lcid; int i; tBTA_AG_SCB *ag_scb, *other_scb; BD_ADDR dev_addr; int status; /* set role */ p_scb->role = BTA_AG_ACP; APPL_TRACE_IMP ("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d", p_scb->serv_handle[0], p_scb->serv_handle[1]); /* get bd addr of peer */ if (PORT_SUCCESS != (status=PORT_CheckConnection(p_data->rfc.port_handle, dev_addr, &lcid))) { APPL_TRACE_DEBUG ("bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d", status); } /* Collision Handling */ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++) { if ((ag_scb->in_use) && (ag_scb->colli_tmr_on)) { /* stop collision timer */ ag_scb->colli_tmr_on = FALSE; bta_sys_stop_timer (&ag_scb->colli_timer); if (bdcmp (dev_addr, ag_scb->peer_addr) == 0) { /* If incoming and outgoing device are same, nothing more to do. */ /* Outgoing conn will be aborted because we have successful incoming conn. */ } else { /* Resume outgoing connection. */ other_scb = bta_ag_get_other_idle_scb (p_scb); if (other_scb) { bdcpy(other_scb->peer_addr, ag_scb->peer_addr); other_scb->open_services = ag_scb->open_services; other_scb->cli_sec_mask = ag_scb->cli_sec_mask; bta_ag_resume_open (other_scb); } } break; } } bdcpy (p_scb->peer_addr, dev_addr); /* determine connected service from port handle */ for (i = 0; i < BTA_AG_NUM_IDX; i++) { APPL_TRACE_DEBUG ("bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", i, p_scb->serv_handle[i], p_data->rfc.port_handle); if (p_scb->serv_handle[i] == p_data->rfc.port_handle) { p_scb->conn_service = i; p_scb->conn_handle = p_data->rfc.port_handle; break; } } APPL_TRACE_IMP ("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d", p_scb->conn_service, p_scb->conn_handle); /* close any unopened server */ bta_ag_close_servers(p_scb, (p_scb->reg_services & ~bta_ag_svc_mask[p_scb->conn_service])); /* do service discovery to get features */ bta_ag_do_disc(p_scb, bta_ag_svc_mask[p_scb->conn_service]); /* continue with common open processing */ bta_ag_rfc_open(p_scb, p_data); }