#include #include #include "user_bt.h" #include "assert.h" #include "app_task.h" #include "FreeRTOS.h" #include "timers.h" #include "btdm_mem.h" #include "user_bt_a2dp.h" #include "fr_device_pa.h" #include "app_lvgl.h" #include "user_bt_call.h" #include "user_bt_pbap.h" #define MAX_RECONNECT_TIMES 3 //reconnect times if page timeout or linkloss #define PAGE_TIMEOUT 0x1000 //connect timeout value, uint:625us const uint8_t hf_enable_voltage_notify[] = "AT+XAPL=AAAA-1111-01,10"; const uint8_t hf_search_remote_dev_type[] = "AT+CGMI"; struct user_bt_env_t user_bt_env; static TimerHandle_t bt_connect_timer = NULL; uint8_t bt_get_free_dev(void) { uint8_t index; for(index = 0; index < NUM_BT_DEVICES; index++){ if(user_bt_env.dev[index].state == BT_LINK_STATE_IDLE){ break; } } return index; } uint8_t bt_find_dev_index(BD_ADDR *addr) { uint8_t index; printf("find dev :%x,%x,,%x\r\n",addr->A[0],addr->A[1],user_bt_env.dev[0].remote_bd.A[0]); for(index = 0; index < NUM_BT_DEVICES; index++){ if(memcmp(&user_bt_env.dev[index].remote_bd, addr, sizeof(BD_ADDR)) == 0){ break; } } return index; } uint8_t bt_find_dev_index_by_dev(void *dev) { uint8_t index; if(dev == NULL){ return NUM_BT_DEVICES; } for(index = 0; index < NUM_BT_DEVICES; index++){ if(user_bt_env.dev[index].remDev == dev){ break; } } return index; } uint8_t bt_find_dev_index_by_hfchan(HfChannel *chan) { uint8_t index; if(chan == NULL){ return NUM_BT_DEVICES; } for(index = 0; index < NUM_BT_DEVICES; index++){ if(user_bt_env.dev[index].hf_chan == chan){ break; } } return index; } uint8_t bt_find_dev_index_by_rcpchan(AvrcpChannel *chan) { uint8_t index; if(chan == NULL){ return NUM_BT_DEVICES; } for(index = 0; index < NUM_BT_DEVICES; index++){ if(user_bt_env.dev[index].rcp_chan == chan){ break; } } return index; } BtStatus bt_do_connect(BD_ADDR *addr) { BtStatus ret = BT_STATUS_PENDING; uint8_t index = 0; printf("bt do connect\r\n"); //connect to remote device depending on the profile if(user_bt_env.enable_profiles & ENABLE_PROFILE_HF){ index = bt_get_free_hf_channel(); ret = HF_CreateServiceLink(&hf_channel[index], addr); } else if(user_bt_env.enable_profiles & ENABLE_PROFILE_HFG){ index = bt_get_free_hfg_channel(); ret = HFG_CreateServiceLink(&hfg_channel[index], addr); } else if(user_bt_env.enable_profiles & ENABLE_PROFILE_A2DP){ index = bt_get_free_a2dp_stream(); ret = A2DP_OpenStream(&Stream[index],addr); } else if(user_bt_env.enable_profiles & ENABLE_PROFILE_HID){ } else if(user_bt_env.enable_profiles & ENABLE_PROFILE_SPP){ } printf("ret = %d\r\n",ret); return ret; } void bt_do_disconnect(BD_ADDR *addr, uint8_t force) { uint8_t dev_index; BtStatus status; dev_index = bt_find_dev_index(addr); xTimerStop(bt_connect_timer,portMAX_DELAY); if(force == true){ if(user_bt_env.dev[dev_index].remDev != NULL){ ME_ForceDisconnectLinkWithReason(NULL,user_bt_env.dev[dev_index].remDev,BEC_USER_TERMINATED,TRUE); } else{ ME_ForceCancelCreateLink(); } } else{ if(user_bt_env.dev[dev_index].conFlags & LINK_STATUS_SCO_CONNECTED){ HF_DisconnectAudioLink(user_bt_env.dev[dev_index].hf_chan); } if(user_bt_env.dev[dev_index].hf_chan->state != HF_STATE_CLOSED){ status = HF_DisconnectServiceLink(user_bt_env.dev[dev_index].hf_chan); } if(user_bt_env.dev[dev_index].hfg_chan->state != HFG_STATE_CLOSED){ HFG_DisconnectServiceLink(user_bt_env.dev[dev_index].hfg_chan); } if(user_bt_env.dev[dev_index].rcp_chan->chnl.conn.state != 0){ AVRCP_Disconnect(user_bt_env.dev[dev_index].rcp_chan); } if(user_bt_env.dev[dev_index].pstream->stream.state != 0){ A2DP_CloseStream(user_bt_env.dev[dev_index].pstream); } } } //BtStatus bt_connect_internal(uint8_t dev_index) //{ // BtStatus status; // if(user_bt_env.dev[dev_index].state == BT_LINK_STATE_CONNECTING){ // if(user_bt_env.connect_param.connect_times > 0){ // user_bt_env.connect_param.connect_times --; // status = bt_connect_according_to_profile(&user_bt_env.dev[dev_index].remote_bd,user_bt_env.enable_profiles); // } // else{ // status = BT_STATUS_TIMEOUT; // } // } // else{ // status = BT_STATUS_INVALID_PARM; // } // printf("connect internal %d,%d\r\n",user_bt_env.connect_param.connect_times,status); // if(status != BT_STATUS_PENDING){ // user_bt_env.connect_param.connect_times = 0; // user_bt_env.dev[dev_index].state = BT_LINK_STATE_IDLE; // memset(&user_bt_env.dev[dev_index].remote_bd,0,sizeof(BD_ADDR)); // } // return status; //} void bt_disconnect_cb(BD_ADDR *addr, uint8_t errcode) { BtStatus status; if(errcode == BEC_CONNECTION_TIMEOUT){ //linkloss, auto reconnect in hf mode // user_bt_env.connect_times = MAX_RECONNECT_TIMES; // status = bt_connect(addr); user_bt_env.connect_times = MAX_RECONNECT_TIMES; memcpy(&user_bt_env.last_dev_addr,addr,BD_ADDR_SIZE); xTimerStart(bt_connect_timer,portMAX_DELAY); } else if(errcode == BEC_USER_TERMINATED){ } else if(errcode == BEC_LOCAL_TERMINATED){ } else{ } } void bt_connect_timer_cb(TimerHandle_t pxTimer) { user_bt_env.connect_times --; bt_connect(&user_bt_env.last_dev_addr); } void bt_connect_cb(uint8_t type, BD_ADDR *addr, uint8_t errcode) { printf("bt connect cb:type = %d,addr=0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,err=%d\r\n",\ type,addr->A[0],addr->A[1],addr->A[2],addr->A[3],addr->A[4],addr->A[5],errcode); if((type == BT_EVENT_CON_CNF) && (errcode == BEC_PAGE_TIMEOUT) && (user_bt_env.connect_times > 0)){ memcpy(&user_bt_env.last_dev_addr,addr,BD_ADDR_SIZE); xTimerStart(bt_connect_timer,portMAX_DELAY); } } static void bt_free_elt(void) { struct bt_connect_elt_t *elt; elt = (struct bt_connect_elt_t *)co_list_pop_front(&user_bt_env.op_list); if(elt){ user_bt_env.cur_action = BT_ACTION_NULL; user_bt_env.action_cnt --; btdm_free((void *)elt); } } uint8_t bt_check_conn(uint8_t dev_index) { uint16_t conn_flag = 0; uint8_t ret = false; if(user_bt_env.enable_profiles & ENABLE_PROFILE_HF){ conn_flag |= LINK_STATUS_HF_CONNECTED; } if(user_bt_env.enable_profiles & ENABLE_PROFILE_A2DP){ conn_flag |= LINK_STATUS_AV_CONNECTED | LINK_STATUS_AVC_CONNECTED; } if(user_bt_env.enable_profiles & ENABLE_PROFILE_HFG){ conn_flag |= LINK_STATUS_HFG_CONNECTED; } if((user_bt_env.dev[dev_index].conFlags & conn_flag) == conn_flag){ ret = true; } printf("bt check conn flag = %x,profile=%x,conn_flg=%x,ret=%d\r\n",user_bt_env.dev[dev_index].conFlags,user_bt_env.enable_profiles,conn_flag,ret); return ret; } void bt_update_conn_status(uint8_t event, void *chan, const void *param) { uint8_t dev_index; BD_ADDR addr; BtRemoteDevice *rm_dev = NULL; BtStatus status; //HfCallbackParms *info; if(event < BT_PROFILE_HF_MAX){ // info = (HfCallbackParms *)param; if((event == BT_PROFILE_HF_CONN_REQ) || (event == BT_PROFILE_HF_CONN)){ rm_dev = ((HfCallbackParms *)param)->p.remDev; dev_index = bt_find_dev_index_by_dev(rm_dev); } else{ dev_index = bt_find_dev_index_by_hfchan(chan); } } else if(event < BT_PROFILE_A2DP_MAX){ if(event == BT_PROFILE_A2DP_DISCONN){ A2dpCallbackParms *pm = (A2dpCallbackParms *)param; rm_dev = pm->p.device; if(rm_dev == NULL){ rm_dev = A2DP_GetRemoteDevice((A2dpStream *)chan); } dev_index = bt_find_dev_index_by_dev(rm_dev); } else{ rm_dev = A2DP_GetRemoteDevice((A2dpStream *)chan); dev_index = bt_find_dev_index_by_dev(rm_dev); } } else if(event < BT_PROFILE_AVRCP_MAX){ if((event == BT_PROFILE_AVRCP_CONN) || (event == BT_PROFILE_AVRCP_DISCONN)){ rm_dev = ((AvrcpCallbackParms *)param)->p.remDev; dev_index = bt_find_dev_index_by_dev(rm_dev); } else{ dev_index = bt_find_dev_index_by_rcpchan(chan); } } if(dev_index >= NUM_BT_DEVICES){ printf("!!!!error dev index, event = %d,%x,%x\r\n",event,(unsigned int)rm_dev,(unsigned int)user_bt_env.dev[0].remDev); return; } printf("bt update conn %d\r\n",event); switch(event){ case BT_PROFILE_HF_CONN_REQ: user_bt_env.dev[dev_index].responder = TRUE; break; case BT_PROFILE_HF_CONN: { user_bt_env.dev[dev_index].hf_chan = chan; user_bt_env.dev[dev_index].conFlags |= LINK_STATUS_HF_CONNECTED; ///check connection if(true == bt_check_conn(dev_index)){ bt_connect_act_cmp(BT_EVENT_PROFILE_CONNECT,0,rm_dev); } ///enable voltage notify bt_send_hf_cmd(dev_index,hf_enable_voltage_notify); ///search remote device type bt_send_hf_cmd(dev_index,hf_search_remote_dev_type); ///connect a2dp in master role if((user_bt_env.dev[dev_index].responder == FALSE) && ((user_bt_env.dev[dev_index].conFlags & LINK_STATUS_AV_CONNECTED) == 0) && (user_bt_env.enable_profiles & ENABLE_PROFILE_A2DP)) { uint8_t index = bt_get_free_a2dp_stream(); status = A2DP_OpenStream(&Stream[index],&user_bt_env.dev[dev_index].remote_bd); } } break; case BT_PROFILE_HF_DISCONN: { // ME_GetBdAddr(info->p.remDev, addr); // dev_index = bt_find_dev_index(addr); // HfCallbackParms *info = (HfCallbackParms *)param; // dev_index = bt_find_dev_index_by_dev(info->p.remDev); user_bt_env.dev[dev_index].hf_chan = NULL; user_bt_env.dev[dev_index].conFlags &= ~LINK_STATUS_HF_CONNECTED; } break; case BT_PROFILE_HF_CALL: { user_bt_env.dev[dev_index].active = ((HfCallbackParms *)param)->p.call; printf("p.call.active %d \r\n",user_bt_env.dev[dev_index].active); user_bt_hfcall_handle(user_bt_env.dev[dev_index].active); } break; case BT_PROFILE_HF_CALLSETUP: { user_bt_env.dev[dev_index].setup_state =((HfCallbackParms *)param)->p.callSetup; printf("p.call.setup_state %d \r\n",user_bt_env.dev[dev_index].setup_state); if(user_bt_env.dev[dev_index].setup_state == 1 || user_bt_env.dev[dev_index].setup_state ==2) { //get currnet call list bt_list_current_calls(dev_index); } user_bt_callsetup_handle(user_bt_env.dev[dev_index].setup_state); } break; case BT_PROFILE_HF_AUDIO_CONN: { user_bt_env.dev[dev_index].conFlags |= LINK_STATUS_SCO_CONNECTED; } break; case BT_PROFILE_HF_AUDIO_DISCONN: { user_bt_env.dev[dev_index].conFlags &= ~LINK_STATUS_SCO_CONNECTED; } break; case BT_PROFILE_A2DP_OPEN_IND: { user_bt_env.dev[dev_index].responder = TRUE; } break; case BT_PROFILE_A2DP_CONN: { // rm_dev = A2DP_GetRemoteDevice((A2dpStream *)chan); // dev_index = bt_find_dev_index_by_dev(rm_dev); // if(dev_index < NUM_BT_DEVICES){ user_bt_env.dev[dev_index].pstream = chan; user_bt_env.dev[dev_index].conFlags |= LINK_STATUS_AV_CONNECTED; if(true == bt_check_conn(dev_index)){ bt_connect_act_cmp(BT_EVENT_PROFILE_CONNECT,0,rm_dev); } if(((user_bt_env.dev[dev_index].conFlags&LINK_STATUS_AVC_CONNECTED) == 0) && (user_bt_env.dev[dev_index].responder == FALSE)){ uint8_t index = bt_get_free_avrcp_channel(); AVRCP_Connect(&rcpCtChannel[index],&user_bt_env.dev[dev_index].remote_bd); } // } user_connect_pbap_client(); } break; case BT_PROFILE_A2DP_DISCONN: { // A2dpCallbackParms *pm = (A2dpCallbackParms *)param; // rm_dev = pm->p.device; // if(rm_dev == NULL){ // rm_dev = A2DP_GetRemoteDevice((A2dpStream *)chan); // } // dev_index = bt_find_dev_index_by_dev(rm_dev); user_bt_env.dev[dev_index].pstream = NULL; user_bt_env.dev[dev_index].conFlags &= ~LINK_STATUS_AV_CONNECTED; } break; case BT_PROFILE_A2DP_PLAYING: { // rm_dev = A2DP_GetRemoteDevice((A2dpStream *)chan); // dev_index = bt_find_dev_index_by_dev(rm_dev); user_bt_env.dev[dev_index].conFlags |= LINK_STATUS_MEDIA_PLAYING; } break; case BT_PROFILE_A2DP_SUSPEND: { user_bt_env.dev[dev_index].conFlags &= ~LINK_STATUS_MEDIA_PLAYING; } break; case BT_PROFILE_AVRCP_CONN: { // AvrcpCallbackParms *pm = (AvrcpCallbackParms *)param; //// ME_GetBdAddr(pm->p.remDev, addr); //// dev_index = bt_find_dev_index(addr); // dev_index = bt_find_dev_index_by_dev(pm->p.remDev); user_bt_env.dev[dev_index].rcp_chan = chan; user_bt_env.dev[dev_index].conFlags |= LINK_STATUS_AVC_CONNECTED; if(true == bt_check_conn(dev_index)){ bt_connect_act_cmp(BT_EVENT_PROFILE_CONNECT,0,rm_dev); } } break; case BT_PROFILE_AVRCP_DISCONN: { // AvrcpCallbackParms *pm = (AvrcpCallbackParms *)param; //// ME_GetBdAddr(pm->p.remDev, addr); //// dev_index = bt_find_dev_index(addr); // dev_index = bt_find_dev_index_by_dev(pm->p.remDev); user_bt_env.dev[dev_index].rcp_chan = NULL; user_bt_env.dev[dev_index].conFlags &= ~LINK_STATUS_AVC_CONNECTED; } break; case BT_PROFILE_AVRCP_MEDIA_STATUS: { uint8_t *media_status = (uint8_t *)param; if((*media_status == AVRCP_MEDIA_PAUSED) || (*media_status == AVRCP_MEDIA_STOPPED)){ printf("media paused\r\n"); user_bt_env.dev[dev_index].conFlags &= ~LINK_STATUS_MEDIA_PLAYING; user_bt_set_music_playstatus(false); } else{ printf("media playing\r\n"); user_bt_env.dev[dev_index].conFlags |= LINK_STATUS_MEDIA_PLAYING; user_bt_set_music_playstatus(true); } } break; } } void bt_connect_act_cmp(uint8_t evt,uint8_t error,BtRemoteDevice *rem_dev) { uint8_t dev_index; struct bt_connect_elt_t *elt; uint8_t cur_act = BT_ACTION_NULL; uint8_t check_op_list = false; BtStatus ret; elt = (struct bt_connect_elt_t *)co_list_pick(&user_bt_env.op_list); if(elt){ cur_act = elt->action; } printf("bt_connect_act_cmp:evt=%d,act = %d,error=%d\r\n",evt,elt->action,error); switch(evt){ case BT_EVENT_CON_IND: case BT_EVENT_CON_CNF: dev_index = bt_find_dev_index(&rem_dev->bdAddr); if(dev_index >= NUM_BT_DEVICES){ if(evt == BT_EVENT_CON_IND){ dev_index = bt_get_free_dev(); assert(dev_index < NUM_BT_DEVICES); } else{ printf("shall not be here...,%s,%d\r\n",__FUNCTION__,__LINE__); } } if(user_bt_env.bt_connect_cb){ user_bt_env.bt_connect_cb(evt,&rem_dev->bdAddr, error); } if(error == BEC_NO_ERROR){ user_bt_env.dev[dev_index].remDev = rem_dev; user_bt_env.dev[dev_index].state = BT_LINK_STATE_ACL_CONNECTED; user_bt_env.last_active_index = dev_index; memcpy(&user_bt_env.dev[dev_index].remote_bd,&rem_dev->bdAddr,BD_ADDR_SIZE); } else{ user_bt_env.dev[dev_index].state = BT_LINK_STATE_IDLE; memset(&user_bt_env.dev[dev_index].remote_bd,0,BD_ADDR_SIZE); if((cur_act == BT_ACTION_CONNECT) || (cur_act == BT_ACTION_DISCONNECT)){ bt_free_elt(); check_op_list = true; } } break; case BT_EVENT_PROFILE_CONNECT: dev_index = bt_find_dev_index(&rem_dev->bdAddr); memcpy(&user_bt_env.last_dev_addr.A[0], &rem_dev->bdAddr,BD_ADDR_SIZE); user_bt_env.dev[dev_index].state = BT_LINK_STATE_PROFILE_CONNECTED; printf("\r\nIV\r\n"); if(user_bt_env.bt_connect_cb){ user_bt_env.bt_connect_cb(evt,&rem_dev->bdAddr, error); } if(cur_act == BT_ACTION_CONNECT){ bt_free_elt(); check_op_list = true; } break; case BT_EVENT_DISCONNECT: dev_index = bt_find_dev_index(&rem_dev->bdAddr); user_bt_env.dev[dev_index].state = BT_LINK_STATE_IDLE; if(user_bt_env.bt_disconnect_cb){ user_bt_env.bt_disconnect_cb(&rem_dev->bdAddr, error); } if((cur_act == BT_ACTION_DISCONNECT) || (cur_act == BT_ACTION_CONNECT)){ bt_free_elt(); check_op_list = true; } // memset(&user_bt_env.dev[dev_index].remote_bd,0,BD_ADDR_SIZE); // user_bt_env.dev[dev_index].conFlags = 0; // user_bt_env.dev[dev_index].hfg_chan = NULL; // user_bt_env.dev[dev_index].hf_chan = NULL; // user_bt_env.dev[dev_index].pstream = NULL; // user_bt_env.dev[dev_index].rcp_chan = NULL; // user_bt_env.dev[dev_index].hid_chan = NULL; memset(&user_bt_env.dev[dev_index],0,sizeof(APP_DEVICE)); break; case BT_EVENT_ACC_CHG: if(user_bt_env.bt_access_change_cb){ user_bt_env.bt_access_change_cb(error); } user_bt_env.access_state = error; if(cur_act == BT_ACTION_ACCESS){ bt_free_elt(); check_op_list = true; } break; } ///check pending op list if(check_op_list == true){ elt = (struct bt_connect_elt_t *)co_list_pick(&user_bt_env.op_list); while(elt && (check_op_list == true)) { printf("check pending list act=%d,state=%d,addr0=%x\r\n",elt->action,user_bt_env.dev[0].state,user_bt_env.dev[0].remote_bd.A[0]); switch(elt->action){ case BT_ACTION_CONNECT: { dev_index = bt_find_dev_index(&elt->addr); if(dev_index >= NUM_BT_DEVICES){ //device not exist, find free dev dev_index = bt_get_free_dev(); if(dev_index < NUM_BT_DEVICES){ //get free dev, create new connection ret = bt_do_connect(&elt->addr); if(ret == BT_STATUS_PENDING){ user_bt_env.cur_action = BT_ACTION_CONNECT; user_bt_env.dev[dev_index].state = BT_LINK_STATE_CONNECTING; memcpy(&user_bt_env.dev[dev_index].remote_bd,&elt->addr,sizeof(BD_ADDR)); check_op_list = false; } else{ bt_free_elt(); } } else{ //no free dev bt_free_elt(); } } else{ //device exist,check device state if(user_bt_env.dev[dev_index].state == BT_LINK_STATE_PROFILE_CONNECTED){ //profile connected,return success bt_free_elt(); }else{ check_op_list = false; } } } break; case BT_ACTION_DISCONNECT: { dev_index = bt_find_dev_index(&elt->addr); if(dev_index >= NUM_BT_DEVICES){ //don't find device bt_free_elt(); } else{ if(user_bt_env.dev[dev_index].state == BT_LINK_STATE_PROFILE_CONNECTED){ //profile connected,return success user_bt_env.dev[dev_index].state = BT_LINK_STATE_DISCONNECTING; user_bt_env.cur_action = BT_ACTION_DISCONNECT; bt_do_disconnect(&elt->addr,false); } else{ //other state,just return check_op_list = false; } } } break; case BT_ACTION_ACCESS: { printf("shall not be here..error action access change."); bt_free_elt(); } break; } elt = (struct bt_connect_elt_t *)co_list_pick(&user_bt_env.op_list); } } } void bt_access_change_cb(uint8_t mode) { printf("access change cb: %d\r\n",mode); } BtStatus bt_connect(BD_ADDR *addr) { BtStatus ret = BT_STATUS_PENDING; uint8_t dev_index = 0; struct bt_connect_elt_t *elt; uint8_t add_to_list = false; printf("bt connect: %x,%x,%x,%x,%x,%x\r\n",addr->A[0],addr->A[1],addr->A[2],addr->A[3],addr->A[4],addr->A[5]); //param check assert(addr != NULL); // //error bt state, return failed // for(index = 0; index < NUM_BT_DEVICES; index++){ // if((user_bt_env.dev[index].state == BT_LINK_STATE_CONNECTING) || (user_bt_env.dev[index].state == BT_LINK_STATE_DISCONNECTING)){ // return BT_STATUS_FAILED; // } // } elt = (struct bt_connect_elt_t *)btdm_malloc(sizeof(struct bt_connect_elt_t)); memcpy(&elt->addr,addr,BD_ADDR_SIZE); elt->action = BT_ACTION_CONNECT; if(co_list_is_empty(&user_bt_env.op_list)){ //list empty, check device index dev_index = bt_find_dev_index(addr); if(dev_index >= NUM_BT_DEVICES){ //not connection with the addr dev_index = bt_get_free_dev(); if(dev_index >= NUM_BT_DEVICES){ //no free device btdm_free(elt); return BT_STATUS_NO_RESOURCES; } } printf("dev[dev_index].state %d \r\n", user_bt_env.dev[dev_index].state); if(user_bt_env.dev[dev_index].state == BT_LINK_STATE_IDLE){ //idle state, do connect imediately ret = bt_do_connect(addr); if(ret == BT_STATUS_PENDING){ add_to_list = true; user_bt_env.cur_action = BT_ACTION_CONNECT; user_bt_env.dev[dev_index].state = BT_LINK_STATE_CONNECTING; memcpy(&user_bt_env.dev[dev_index].remote_bd,addr,sizeof(BD_ADDR)); } else{ btdm_free(elt); } } else if(user_bt_env.dev[dev_index].state == BT_LINK_STATE_DISCONNECTING){ //disconnecting,usally shall not be here add_to_list = true; } else if((user_bt_env.dev[dev_index].state == BT_LINK_STATE_CONNECTING) || (user_bt_env.dev[dev_index].state == BT_LINK_STATE_ACL_CONNECTED)){ //connecting or acl connected,just free connect elt,return pending btdm_free(elt); } else if(user_bt_env.dev[dev_index].state == BT_LINK_STATE_PROFILE_CONNECTED){ //profile connected,return success btdm_free(elt); ret = BT_STATUS_SUCCESS; } }else{ add_to_list = true; printf("add_to_list true\r\n"); } if(add_to_list == true){ GLOBAL_INT_DISABLE(); co_list_push_back(&user_bt_env.op_list,&elt->hdr); user_bt_env.action_cnt ++; GLOBAL_INT_RESTORE(); } return ret; } BtStatus bt_disconnect(BD_ADDR *addr, uint8_t force_disconnect) { BtStatus status = BT_STATUS_PENDING; uint8_t dev_index = 0; struct bt_connect_elt_t *elt,*cur_elt; uint8_t add_to_list = false; printf("bt disconnect\r\n"); elt = (struct bt_connect_elt_t *)btdm_malloc(sizeof(struct bt_connect_elt_t)); memcpy(&elt->addr,addr,BD_ADDR_SIZE); elt->action = BT_ACTION_DISCONNECT; if((co_list_is_empty(&user_bt_env.op_list)) || (force_disconnect == true)){ dev_index = bt_find_dev_index(addr); if(dev_index < NUM_BT_DEVICES){ if(user_bt_env.dev[dev_index].state == BT_LINK_STATE_IDLE){ memset(&user_bt_env.dev[dev_index].remote_bd,0,sizeof(BD_ADDR)); status = BT_STATUS_SUCCESS; } else if(user_bt_env.dev[dev_index].state == BT_LINK_STATE_DISCONNECTING){ add_to_list = false; if(force_disconnect == true){ // cur_elt = (struct bt_connect_elt_t *)co_list_pick(&user_bt_env.op_list); bt_do_disconnect(addr,force_disconnect); } } else if((user_bt_env.dev[dev_index].state == BT_LINK_STATE_CONNECTING) || (user_bt_env.dev[dev_index].state == BT_LINK_STATE_ACL_CONNECTED)) { if(force_disconnect == true){ cur_elt = (struct bt_connect_elt_t *)co_list_pick(&user_bt_env.op_list); if(cur_elt && (cur_elt->action == BT_ACTION_CONNECT)){ co_list_pop_front(&user_bt_env.op_list); user_bt_env.action_cnt --; btdm_free(cur_elt); user_bt_env.dev[dev_index].state = BT_LINK_STATE_DISCONNECTING; bt_do_disconnect(addr,force_disconnect); } } add_to_list = true; } else if(user_bt_env.dev[dev_index].state == BT_LINK_STATE_PROFILE_CONNECTED){ user_bt_env.dev[dev_index].state = BT_LINK_STATE_DISCONNECTING; bt_do_disconnect(addr,force_disconnect); add_to_list = true; } } else{ btdm_free(elt); return BT_STATUS_FAILED; } } else{ add_to_list = true; } if(add_to_list == true){ GLOBAL_INT_DISABLE(); co_list_push_back(&user_bt_env.op_list,&elt->hdr); user_bt_env.action_cnt ++; GLOBAL_INT_RESTORE(); } return status; } void user_bt_init(void) { struct bt_connect_elt_t *elt; while(!co_list_is_empty(&user_bt_env.op_list)){ user_bt_env.action_cnt --; elt = (struct bt_connect_elt_t *)co_list_pop_front(&user_bt_env.op_list); btdm_free((void *)elt); } memset((void *)&user_bt_env,0,sizeof(struct user_bt_env_t)); co_list_init(&user_bt_env.op_list); user_bt_env.bt_disconnect_cb = bt_disconnect_cb; user_bt_env.bt_connect_cb = bt_connect_cb; user_bt_env.bt_access_change_cb = bt_access_change_cb; user_bt_env.enable_profiles = ENABLE_PROFILE_HF | ENABLE_PROFILE_A2DP; // user_bt_env.connect_times = MAX_RECONNECT_TIMES; user_bt_env.page_timeout = PAGE_TIMEOUT; ME_SetPageTimeout(user_bt_env.page_timeout); if(bt_connect_timer == NULL){ bt_connect_timer = xTimerCreate("bt_connect_timer", 10, pdFALSE, 0, bt_connect_timer_cb ); } } uint8_t user_bt_get_state(uint8_t dev_index) { uint8_t state = BT_STATE_IDLE; switch(user_bt_env.dev[dev_index].state) { case BT_LINK_STATE_IDLE: state = BT_STATE_IDLE; break; case BT_LINK_STATE_CONNECTING: state = BT_STATE_CONNECTING; break; case BT_LINK_STATE_DISCONNECTING: state = BT_STATE_DISCONNECTING; break; case BT_LINK_STATE_ACL_CONNECTED: case BT_LINK_STATE_PROFILE_CONNECTED: { state = BT_STATE_CONNECTED; if(user_bt_env.dev[dev_index].active == HF_CALL_ACTIVE){ state = BT_STATE_HFP_CALLACTIVE; } else if(user_bt_env.dev[dev_index].setup_state == HF_CALL_SETUP_IN){ state = BT_STATE_HFP_INCOMMING; } else if((user_bt_env.dev[dev_index].setup_state == HF_CALL_SETUP_OUT) ||(user_bt_env.dev[dev_index].setup_state == HF_CALL_SETUP_ALERT)){ state = BT_STATE_HFP_OUTGOING; }else if(user_bt_env.dev[dev_index].conFlags & LINK_STATUS_MEDIA_PLAYING){ state = BT_STATE_MEDIA_PLAYING; } } break; } return state; } BtStatus bt_answer_call(uint8_t dev_index) { HfCommand *cmd; uint8_t state = user_bt_get_state(dev_index); if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } if(state != BT_STATE_HFP_INCOMMING){ return BT_STATUS_FAILED; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_AnswerCall(user_bt_env.dev[dev_index].hf_chan, cmd); } BtStatus bt_enter_pairing(uint8_t access, BtAccessModeInfo *info) { BtStatus status = BT_STATUS_PENDING; struct bt_connect_elt_t *elt; printf("bt enter pairing\r\n"); if((access == BAM_NOT_ACCESSIBLE) || (access > BAM_GENERAL_ACCESSIBLE)){ return BT_STATUS_INVALID_PARM; } if(user_bt_env.access_state == access){ return BT_STATUS_SUCCESS; } //TBD,only change nonconnected access state status = ME_SetAccessibleModeNC(access, info); if(status == BT_STATUS_PENDING){ elt = (struct bt_connect_elt_t *)btdm_malloc(sizeof(struct bt_connect_elt_t)); elt->action = BT_ACTION_ACCESS; GLOBAL_INT_DISABLE(); co_list_push_back(&user_bt_env.op_list,&elt->hdr); user_bt_env.action_cnt ++; GLOBAL_INT_RESTORE(); } return status; } BtStatus bt_exit_pairing(void) { BtStatus status = BT_STATUS_PENDING; struct bt_connect_elt_t *elt; status = ME_SetAccessibleModeNC(BAM_NOT_ACCESSIBLE, NULL); if(status == BT_STATUS_PENDING){ elt = (struct bt_connect_elt_t *)btdm_malloc(sizeof(struct bt_connect_elt_t)); elt->action = BT_ACTION_ACCESS; GLOBAL_INT_DISABLE(); co_list_push_back(&user_bt_env.op_list,&elt->hdr); user_bt_env.action_cnt ++; GLOBAL_INT_RESTORE(); } return status; } BtStatus bt_dial_number(uint8_t dev_index, uint8_t *number, uint16_t len) { HfCommand *cmd; if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_DialNumber(user_bt_env.dev[dev_index].hf_chan, number, len, cmd); } BtStatus bt_redial(uint8_t dev_index) { HfCommand *cmd; if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_Redial(user_bt_env.dev[dev_index].hf_chan, cmd); } BtStatus bt_call_hold(uint8_t dev_index, HfHoldAction action, uint8_t index) { HfCommand *cmd; if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_CallHold(user_bt_env.dev[dev_index].hf_chan, action, index, cmd); } BtStatus bt_hang_up(uint8_t dev_index) { HfCommand *cmd; uint8_t state = user_bt_get_state(dev_index); if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } printf("state = %d\r\n",state); if((state != BT_STATE_HFP_INCOMMING) && (state != BT_STATE_HFP_OUTGOING) && (state != BT_STATE_HFP_CALLACTIVE)){ return BT_STATUS_FAILED; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_Hangup(user_bt_env.dev[dev_index].hf_chan, cmd); } BtStatus bt_list_current_calls(uint8_t dev_index) { HfCommand *cmd; uint8_t state = user_bt_get_state(dev_index); if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } printf("state = %d\r\n",state); if((state != BT_STATE_HFP_INCOMMING) && (state != BT_STATE_HFP_OUTGOING) && (state != BT_STATE_HFP_CALLACTIVE)){ return BT_STATUS_FAILED; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_ListCurrentCalls(user_bt_env.dev[dev_index].hf_chan, cmd); } BtStatus bt_transfer_sco(uint8_t dev_index) { HfCommand *cmd; uint8_t state = user_bt_get_state(dev_index); if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } if(state < BT_STATE_CONNECTED){ return BT_STATUS_FAILED; } printf("conFlags = %d\r\n",user_bt_env.dev[dev_index].conFlags); if(user_bt_env.dev[dev_index].conFlags & LINK_STATUS_SCO_CONNECTED){ return HF_DisconnectAudioLink(user_bt_env.dev[dev_index].hf_chan); }else{ cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); //return HF_CreateAudioLink(user_bt_env.dev[dev_index].hf_chan); return HF_CodecConnectionReq(user_bt_env.dev[dev_index].hf_chan, cmd); } } BtStatus bt_send_dtmf(uint8_t dev_index, uint8_t dtmf) { HfCommand *cmd; if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_GenerateDtmf(user_bt_env.dev[dev_index].hf_chan, dtmf, cmd); } BtStatus bt_report_mic_volume(uint8_t dev_index, uint8_t vol) { HfCommand *cmd; uint8_t state = user_bt_get_state(dev_index); if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } if((state != BT_STATE_HFP_INCOMMING) && (state != BT_STATE_HFP_OUTGOING) && (state != BT_STATE_HFP_CALLACTIVE)){ return BT_STATUS_FAILED; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_ReportMicVolume(user_bt_env.dev[dev_index].hf_chan, vol, cmd); } BtStatus bt_report_spk_volume(uint8_t dev_index, uint8_t vol) { HfCommand *cmd; uint8_t state = user_bt_get_state(dev_index); if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } if((state != BT_STATE_HFP_INCOMMING) && (state != BT_STATE_HFP_OUTGOING) && (state != BT_STATE_HFP_CALLACTIVE)){ return BT_STATUS_FAILED; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_ReportSpeakerVolume(user_bt_env.dev[dev_index].hf_chan, vol, cmd); } BtStatus bt_send_hf_cmd(uint8_t dev_index, const uint8_t *at_str) { HfCommand *cmd; if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_SendAtCommand(user_bt_env.dev[dev_index].hf_chan, (const char *)at_str, cmd); } BtStatus bt_enable_voice_recognition(uint8_t dev_index, uint8_t enabled) { HfCommand *cmd; if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return BT_STATUS_INVALID_PARM; } cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand)); return HF_EnableVoiceRecognition(user_bt_env.dev[dev_index].hf_chan, enabled, cmd); } uint8_t bt_is_voice_rec_active(uint8_t dev_index) { if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].hf_chan == NULL)){ return 0; } return HF_IsVoiceRecActive(user_bt_env.dev[dev_index].hf_chan); } BtStatus bt_set_media_volume(uint8_t dev_index, uint8_t volume) { AvrcpAdvancedPdu *pdu; BtStatus status; if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].rcp_chan == NULL)){ return BT_STATUS_INVALID_PARM; } pdu = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); pdu->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_TgSetAbsoluteVolume(user_bt_env.dev[dev_index].rcp_chan, pdu,volume); if (status != BT_STATUS_PENDING) { btdm_free(pdu->parms); btdm_free(pdu); } return status; } BtStatus bt_get_playstatus(uint8_t dev_index) { AvrcpAdvancedPdu *pdu; BtStatus status; if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].rcp_chan == NULL)){ return BT_STATUS_INVALID_PARM; } pdu = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); pdu->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtGetPlayStatus(user_bt_env.dev[dev_index].rcp_chan, pdu); if (status != BT_STATUS_PENDING) { btdm_free(pdu->parms); btdm_free(pdu); } return status; } BtStatus bt_get_media_info(uint8_t dev_index,AvrcpMediaAttrIdMask mediaMask) { AvrcpAdvancedPdu *pdu; BtStatus status; if((dev_index >= NUM_BT_DEVICES) || (user_bt_env.dev[dev_index].rcp_chan == NULL)){ return BT_STATUS_INVALID_PARM; } pdu = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu)); pdu->parms = (uint8_t *)btdm_malloc(64); status = AVRCP_CtGetMediaInfo(user_bt_env.dev[dev_index].rcp_chan, pdu, mediaMask); if (status != BT_STATUS_PENDING) { btdm_free(pdu->parms); btdm_free(pdu); } return status; }