1168 lines
39 KiB
C
1168 lines
39 KiB
C
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "user_bt.h"
|
|
#include "assert.h"
|
|
#include "app_task.h"
|
|
#include "FreeRTOS.h"
|
|
#include "timers.h"
|
|
#include "btdm_mem.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;
|
|
}
|
|
|
|
uint8_t bt_find_dev_index_by_pbapclient(PbapClientSession *client)
|
|
{
|
|
uint8_t index;
|
|
if(client == NULL){
|
|
return NUM_BT_DEVICES;
|
|
}
|
|
for(index = 0; index < NUM_BT_DEVICES; index++){
|
|
if(user_bt_env.dev[index].pbap_client == client){
|
|
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);
|
|
}
|
|
}
|
|
else if(event < BT_PROFILE_PBAP_MAX){
|
|
dev_index = bt_find_dev_index_by_pbapclient(((PbapClientCallbackParms *)param)->client);
|
|
}
|
|
|
|
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;
|
|
}
|
|
break;
|
|
case BT_PROFILE_HF_CALLSETUP:
|
|
{
|
|
user_bt_env.dev[dev_index].setup_state =((HfCallbackParms *)param)->p.callSetup;
|
|
}
|
|
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);
|
|
}
|
|
// }
|
|
}
|
|
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;
|
|
}
|
|
else{
|
|
printf("media playing\r\n");
|
|
user_bt_env.dev[dev_index].conFlags |= LINK_STATUS_MEDIA_PLAYING;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BT_PROFILE_PBAP_CONN:
|
|
{
|
|
user_bt_env.dev[dev_index].conFlags |= LINK_STATUS_PBAP_CONNECTED;
|
|
}
|
|
break;
|
|
|
|
case BT_PROFILE_PBAP_DISCONN:
|
|
{
|
|
user_bt_env.dev[dev_index].pbap_client = NULL;
|
|
user_bt_env.dev[dev_index].conFlags &= ~LINK_STATUS_PBAP_CONNECTED;
|
|
}
|
|
break;
|
|
|
|
case BT_PROFILE_PBAP_DATA_IND:
|
|
{
|
|
printf("data ind: \r\n");
|
|
for(uint16_t i = 0; i < ((PbapClientCallbackParms *)param)->u.dataInd.len; i++)
|
|
{
|
|
printf("%c",((PbapClientCallbackParms *)param)->u.dataInd.buffer[i]);
|
|
}
|
|
printf("\r\n");
|
|
}
|
|
break;
|
|
|
|
case BT_PROFILE_PBAP_COMP:
|
|
|
|
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);
|
|
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\r\n",addr->A[0],addr->A[1]);
|
|
|
|
//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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
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_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_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_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, 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;
|
|
}
|
|
|