HFP 1.7 profile update (1/4)
-> Added AG support for HFP 1.7 version upgrade which
adds new type of indicator called HF(headset) indicators.
-> Added support for two new AT commands AT + BIND and AT + BIEV
which have been appended to Hands-Free SLC sequence.
-> Added support to propagate the above commands and their data to
the upper layers.
Bug: 19983867
Change-Id: I93d5b2af949f9fb99507a954e623cd0927ddc976
diff --git a/bta/ag/bta_ag_act.c b/bta/ag/bta_ag_act.c
index 3d52cef..285a967 100644
--- a/bta/ag/bta_ag_act.c
+++ b/bta/ag/bta_ag_act.c
@@ -432,6 +432,9 @@
p_scb->hsp_version = HSP_VERSION_1_2;
bta_ag_at_reinit(&p_scb->at_cb);
+ memset(&(p_scb->peer_hf_indicators), 0, sizeof(p_scb->peer_hf_indicators));
+ memset(&(p_scb->local_hf_indicators), 0, sizeof(p_scb->local_hf_indicators));
+
/* stop timers */
alarm_cancel(p_scb->ring_timer);
#if (BTM_WBS_INCLUDED == TRUE)
diff --git a/bta/ag/bta_ag_cfg.c b/bta/ag/bta_ag_cfg.c
index cfe298a..e5893e1 100644
--- a/bta/ag/bta_ag_cfg.c
+++ b/bta/ag/bta_ag_cfg.c
@@ -52,9 +52,24 @@
BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
#endif
+#ifndef BTA_AG_BIND_INFO
+#define BTA_AG_BIND_INFO "(1)"
+#endif
+
+const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[] =
+{
+ /* The first row contains the number of indicators. Need to be updated accordingly */
+ {BTA_AG_NUM_LOCAL_HF_IND, 0, 0, 0, 0},
+
+ {1, 1, 1, 0, 1}, /* Enhanced Driver Status, supported, enabled, range 0 ~ 1 */
+ {2, 1, 1, 0, 100} /* Battery Level Status, supported, enabled, range 0 ~ 100 */
+};
+
const tBTA_AG_CFG bta_ag_cfg =
{
BTA_AG_CIND_INFO,
+ BTA_AG_BIND_INFO,
+ BTA_AG_NUM_LOCAL_HF_IND,
BTA_AG_CONN_TIMEOUT,
BTA_AG_SCO_PKT_TYPES,
BTA_AG_CHLD_VAL_ECC,
diff --git a/bta/ag/bta_ag_cmd.c b/bta/ag/bta_ag_cmd.c
index 2ab9f51..110b531 100644
--- a/bta/ag/bta_ag_cmd.c
+++ b/bta/ag/bta_ag_cmd.c
@@ -111,6 +111,8 @@
BTA_AG_HF_CMD_CBC,
BTA_AG_HF_CMD_BCC,
BTA_AG_HF_CMD_BCS,
+ BTA_AG_HF_CMD_BIND,
+ BTA_AG_HF_CMD_BIEV,
BTA_AG_HF_CMD_BAC
};
@@ -152,6 +154,8 @@
{"+CBC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
{"+BCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
{"+BCS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
+ {"+BIND", BTA_AG_AT_SET | BTA_AG_AT_READ | BTA_AG_AT_TEST , BTA_AG_AT_STR, 0, 0},
+ {"+BIEV", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
{"+BAC", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
{"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}
};
@@ -194,6 +198,7 @@
BTA_AG_RES_COPS,
BTA_AG_RES_CMEE,
BTA_AG_RES_BCS,
+ BTA_AG_RES_BIND,
BTA_AG_RES_UNAT
};
@@ -223,6 +228,7 @@
{"+COPS: ", BTA_AG_RES_FMT_STR},
{"+CME ERROR: ", BTA_AG_RES_FMT_INT},
{"+BCS: ", BTA_AG_RES_FMT_INT},
+ {"+BIND: ", BTA_AG_RES_FMT_STR},
{"", BTA_AG_RES_FMT_STR}
};
@@ -268,6 +274,8 @@
BTA_AG_AT_CBC_EVT, /* BTA_AG_HF_CMD_CBC */
0, /* BTA_AG_HF_CMD_BCC */
BTA_AG_AT_BCS_EVT, /* BTA_AG_HF_CMD_BCS */
+ BTA_AG_AT_BIND_EVT, /* BTA_AG_HF_CMD_BIND */
+ BTA_AG_AT_BIEV_EVT, /* BTA_AG_HF_CMD_BIEV */
BTA_AG_AT_BAC_EVT /* BTA_AG_HF_CMD_BAC */
};
@@ -294,6 +302,7 @@
0, /* BTA_AG_CALL_CANCEL_RES */
0, /* BTA_AG_END_CALL_RES */
0, /* BTA_AG_IN_CALL_HELD_RES */
+ BTA_AG_RES_BIND, /* BTA_AG_BIND_RES */
BTA_AG_RES_UNAT /* BTA_AG_UNAT_RES */
};
@@ -319,7 +328,8 @@
BTA_AG_CALLSETUP_NONE, /* BTA_AG_OUT_CALL_CONN_RES */
BTA_AG_CALLSETUP_NONE, /* BTA_AG_CALL_CANCEL_RES */
BTA_AG_CALLSETUP_NONE, /* BTA_AG_END_CALL_RES */
- BTA_AG_CALLSETUP_NONE /* BTA_AG_IN_CALL_HELD_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_IN_CALL_HELD_RES */
+ 0 /* BTA_AG_BIND_RES */
};
/*******************************************************************************
@@ -858,6 +868,222 @@
/*******************************************************************************
**
+** Function bta_ag_find_empty_hf_ind)
+**
+** Description This function returns the index of an empty HF indicator
+** structure.
+**
+** Returns int : index of the empty HF indicator structure or
+** -1 if no empty indicator
+** is available.
+**
+*******************************************************************************/
+static int bta_ag_find_empty_hf_ind(tBTA_AG_SCB *p_scb)
+{
+ for (int index = 0; index < BTA_AG_MAX_NUM_PEER_HF_IND; index++)
+ {
+ if (p_scb->peer_hf_indicators[index].ind_id == 0)
+ return index;
+ }
+
+ return -1;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_find_hf_ind_by_id
+**
+** Description This function returns the index of the HF indicator
+** structure by the indicator id
+**
+** Returns int : index of the HF indicator structure
+** -1 if the indicator
+** was not found.
+**
+*******************************************************************************/
+static int bta_ag_find_hf_ind_by_id(tBTA_AG_HF_IND *p_hf_ind, int size, uint32_t ind_id)
+{
+ for (int index = 0; index < size; index++)
+ {
+ if (p_hf_ind[index].ind_id == ind_id)
+ return index;
+ }
+
+ return -1;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_parse_bind_set
+**
+** Description Parse AT+BIND set command and save the indicators
+**
+** Returns true if successful
+**
+*******************************************************************************/
+static bool bta_ag_parse_bind_set(tBTA_AG_SCB *p_scb, tBTA_AG_VAL val)
+{
+ char *p_token = strtok(val.str, ",");
+ if (p_token == NULL)
+ return false;
+
+ while (p_token != NULL)
+ {
+ uint16_t rcv_ind_id = atoi(p_token);
+ int index = bta_ag_find_empty_hf_ind(p_scb);
+ if (index == -1)
+ {
+ APPL_TRACE_WARNING("%s Can't save more indicators", __func__);
+ return false;
+ }
+
+ p_scb->peer_hf_indicators[index].ind_id = rcv_ind_id;
+ APPL_TRACE_DEBUG("%s peer_hf_ind[%d] = %d", __func__, index, rcv_ind_id);
+
+ p_token = strtok(NULL, ",");
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_bind_response
+**
+** Description Send response for the AT+BIND command (HFP 1.7) received
+** from the headset based on the argument types.
+**
+** Returns Void
+**
+*******************************************************************************/
+static void bta_ag_bind_response(tBTA_AG_SCB *p_scb, uint8_t arg_type)
+{
+ char buffer[BTA_AG_AT_MAX_LEN];
+ memset(buffer, 0, BTA_AG_AT_MAX_LEN);
+
+ if (arg_type == BTA_AG_AT_TEST)
+ {
+ int index = 0;
+ buffer[index++] = '(';
+
+ for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++)
+ {
+ if (bta_ag_local_hf_ind_cfg[i+1].is_supported == true)
+ {
+ /* Add ',' from second indicator */
+ if (index > 1)
+ buffer[index++] = ',';
+ sprintf(&buffer[index++], "%d", bta_ag_local_hf_ind_cfg[i+1].ind_id);
+ }
+ }
+
+ buffer[index++] = ')';
+
+ bta_ag_send_result(p_scb, BTA_AG_RES_BIND, buffer, 0);
+ bta_ag_send_ok(p_scb);
+ }
+ else if (arg_type == BTA_AG_AT_READ)
+ {
+ char *p = buffer;
+
+ /* bta_ag_local_hf_ind_cfg[0].ind_id is used as BTA_AG_NUM_LOCAL_HF_IND */
+ for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++)
+ {
+ if (i == BTA_AG_MAX_NUM_LOCAL_HF_IND)
+ {
+ APPL_TRACE_WARNING("%s No space for more HF indicators", __func__);
+ break;
+ }
+
+ p_scb->local_hf_indicators[i].ind_id = bta_ag_local_hf_ind_cfg[i+1].ind_id;
+ p_scb->local_hf_indicators[i].is_supported = bta_ag_local_hf_ind_cfg[i+1].is_supported;
+ p_scb->local_hf_indicators[i].is_enable = bta_ag_local_hf_ind_cfg[i+1].is_enable;
+
+ int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators,
+ BTA_AG_MAX_NUM_PEER_HF_IND,
+ p_scb->local_hf_indicators[i].ind_id);
+
+ /* Check whether local and peer sides support this indicator */
+ if (p_scb->local_hf_indicators[i].is_supported == true && peer_index != -1)
+ {
+ /* In the format of ind, state */
+ p += utl_itoa((uint16_t) p_scb->local_hf_indicators[i].ind_id, p);
+ *p++ = ',';
+ p += utl_itoa((uint16_t) p_scb->local_hf_indicators[i].is_enable, p);
+
+ bta_ag_send_result(p_scb, BTA_AG_RES_BIND, buffer, 0);
+
+ memset(buffer, 0, sizeof(buffer));
+ p = buffer;
+ } else {
+ /* If indicator is not supported, also set it to disable */
+ p_scb->local_hf_indicators[i].is_enable = false;
+ }
+ }
+
+ bta_ag_send_ok(p_scb);
+
+ /* If the service level connection wan't already open, now it's open */
+ if (!p_scb->svc_conn)
+ bta_ag_svc_conn_open(p_scb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_parse_biev_response
+**
+** Description Send response for AT+BIEV command (HFP 1.7) received from
+** the headset based on the argument types.
+**
+** Returns true if the response was parsed successfully
+**
+*******************************************************************************/
+static bool bta_ag_parse_biev_response(tBTA_AG_SCB *p_scb, tBTA_AG_VAL *val)
+{
+ char *p_token = strtok(val->str, ",");
+ uint16_t rcv_ind_id = atoi(p_token);
+
+ p_token = strtok(NULL, ",");
+ uint16_t rcv_ind_val = atoi(p_token);
+
+ APPL_TRACE_DEBUG("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id, rcv_ind_val);
+
+ /* Check whether indicator ID is valid or not */
+ if (rcv_ind_id > BTA_AG_NUM_LOCAL_HF_IND)
+ {
+ APPL_TRACE_WARNING("%s received invalid indicator id %d", __func__, rcv_ind_id);
+ return false;
+ }
+
+ /* Check this indicator is support or not and enabled or not */
+ int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators,
+ BTA_AG_MAX_NUM_LOCAL_HF_IND, rcv_ind_id);
+ if (local_index == -1 ||
+ p_scb->local_hf_indicators[local_index].is_supported != true ||
+ p_scb->local_hf_indicators[local_index].is_enable != true)
+ {
+ APPL_TRACE_WARNING("%s indicator id %d not supported or disabled", __func__, rcv_ind_id);
+ return false;
+ }
+
+ /* For each indicator ID, check whether the indicator value is in range */
+ if (rcv_ind_val < bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_min_val ||
+ rcv_ind_val > bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_max_val)
+ {
+ APPL_TRACE_WARNING("%s invalid ind_val %d", __func__, rcv_ind_val);
+ return false;
+ }
+
+ val->lidx = rcv_ind_id;
+ val->num = rcv_ind_val;
+
+ return true;
+}
+
+/*******************************************************************************
+**
** Function bta_ag_at_hfp_cback
**
** Description AT command processing callback for HFP.
@@ -889,6 +1115,7 @@
val.hdr.handle = bta_ag_scb_to_idx(p_scb);
val.hdr.app_id = p_scb->app_id;
+ val.hdr.status = BTA_AG_SUCCESS;
val.num = int_arg;
bdcpy(val.bd_addr, p_scb->peer_addr);
strlcpy(val.str, p_arg, BTA_AG_AT_MAX_LEN);
@@ -1017,6 +1244,37 @@
}
break;
+ case BTA_AG_HF_CMD_BIND:
+ APPL_TRACE_DEBUG("%s BTA_AG_HF_CMD_BIND arg_type: %d", __func__, arg_type);
+ if (arg_type == BTA_AG_AT_SET)
+ {
+ if (bta_ag_parse_bind_set(p_scb, val))
+ {
+ bta_ag_send_ok(p_scb);
+ } else {
+ event = 0;/* don't call callback */
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+ }
+ } else {
+ bta_ag_bind_response(p_scb, arg_type);
+
+ /* Need not pass this command beyond BTIF.*/
+ /* Stack handles it internally */
+ event = 0;/* don't call callback */
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BIEV:
+ if (bta_ag_parse_biev_response(p_scb, &val))
+ {
+ bta_ag_send_ok(p_scb);
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+ /* don't call callback receiving invalid indicator */
+ event = 0;
+ }
+ break;
+
case BTA_AG_HF_CMD_CIND:
if (arg_type == BTA_AG_AT_TEST)
{
@@ -1089,7 +1347,12 @@
case BTA_AG_HF_CMD_BRSF:
/* store peer features */
- p_scb->peer_features = (UINT16) int_arg;
+ p_scb->peer_features = (uint16_t) int_arg;
+#if (BTA_HFP_VERSION < HFP_VERSION_1_7 || BTA_HFP_HF_IND_SUPPORTED != true)
+ p_scb->features &= ~BTA_AG_FEAT_HF_IND;
+#endif
+ APPL_TRACE_DEBUG("%s BRSF HF: 0x%x, phone: 0x%x", __func__,
+ p_scb->peer_features, p_scb->features);
/* send BRSF, send OK */
bta_ag_send_result(p_scb, BTA_AG_RES_BRSF, NULL,
@@ -1317,6 +1580,7 @@
{
val.hdr.handle = bta_ag_scb_to_idx(p_scb);
val.hdr.app_id = p_scb->app_id;
+ val.hdr.status = BTA_AG_SUCCESS;
val.num = 0;
strlcpy(val.str, p_arg, BTA_AG_AT_MAX_LEN);
(*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG *) &val);
@@ -1452,7 +1716,6 @@
void bta_ag_hfp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
{
UINT8 code = bta_ag_trans_result[p_result->result];
-
APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", p_result->result);
switch(p_result->result)
@@ -1709,12 +1972,53 @@
}
break;
- default:
+ case BTA_AG_BIND_RES:
+ {
+ /* Find whether ind_id is supported by local device or not */
+ int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators,
+ BTA_AG_MAX_NUM_LOCAL_HF_IND, p_result->data.ind.id);
+ if (local_index == -1)
+ {
+ APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
+ p_result->data.ind.id);
+ return;
+ }
+
+ /* Find whether ind_id is supported by peer device or not */
+ int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators,
+ BTA_AG_MAX_NUM_PEER_HF_IND, p_result->data.ind.id);
+ if (peer_index == -1)
+ {
+ APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
+ p_result->data.ind.id);
+ return;
+ } else {
+ /* If the current state is different from the one upper layer request
+ change current state and send out the result */
+ if (p_scb->local_hf_indicators[local_index].is_enable != p_result->data.ind.on_demand)
+ {
+ char buffer[BTA_AG_AT_MAX_LEN] = {0};
+ char *p = buffer;
+
+ p_scb->local_hf_indicators[local_index].is_enable = p_result->data.ind.on_demand;
+ p += utl_itoa(p_result->data.ind.id, p);
+ *p++ = ',';
+ p += utl_itoa(p_scb->local_hf_indicators[local_index].is_enable, p);
+
+ bta_ag_send_result(p_scb, code, buffer, 0);
+ } else {
+ APPL_TRACE_DEBUG("%s HF Indicator %d already %s", p_result->data.ind.id,
+ (p_result->data.ind.on_demand == true) ? "Enabled" : "Disabled");
+ }
+ }
+ break;
+ }
+
+ default:
break;
}
}
-
/*******************************************************************************
**
** Function bta_ag_result
diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
index a95f0a8..b721ac0 100644
--- a/bta/ag/bta_ag_int.h
+++ b/bta/ag/bta_ag_int.h
@@ -42,13 +42,6 @@
/*****************************************************************************
** Constants
*****************************************************************************/
-#define HFP_VERSION_1_1 0x0101
-#define HFP_VERSION_1_5 0x0105
-#define HFP_VERSION_1_6 0x0106
-
-#define HSP_VERSION_1_0 0x0100
-#define HSP_VERSION_1_2 0x0102
-
/* Number of SCBs (AG service instances that can be registered) */
#ifndef BTA_AG_NUM_SCB
#define BTA_AG_NUM_SCB 2
@@ -62,6 +55,10 @@
/* RFCOMM MTU SIZE */
#define BTA_AG_MTU 256
+/* Max number of peer and local HF indicators */
+#define BTA_AG_MAX_NUM_PEER_HF_IND 20
+#define BTA_AG_MAX_NUM_LOCAL_HF_IND 4
+
/* Internal profile indexes */
#define BTA_AG_HSP 0 /* index for HSP */
#define BTA_AG_HFP 1 /* index for HFP */
@@ -77,6 +74,7 @@
BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT | \
BTA_AG_FEAT_ECS | BTA_AG_FEAT_ECC | \
BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_CODEC | \
+ BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO | \
BTA_AG_FEAT_VOIP)
#define BTA_AG_SDP_FEAT_SPEC (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | \
@@ -298,6 +296,10 @@
tBTA_AG_SCO_MSBC_SETTINGS codec_msbc_settings; /* settings to be used for the impending eSCO */
#endif
+ tBTA_AG_HF_IND peer_hf_indicators[BTA_AG_MAX_NUM_PEER_HF_IND]; /* Peer supported
+ HF indicators */
+ tBTA_AG_HF_IND local_hf_indicators[BTA_AG_MAX_NUM_LOCAL_HF_IND]; /* Local supported
+ HF indicators */
} tBTA_AG_SCB;
/* type for sco data */
@@ -342,6 +344,7 @@
/* config struct */
extern tBTA_AG_CFG *p_bta_ag_cfg;
+extern tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[];
/*****************************************************************************
** Function prototypes
diff --git a/bta/ag/bta_ag_sdp.c b/bta/ag/bta_ag_sdp.c
index cb5bd80..aa43c02 100644
--- a/bta/ag/bta_ag_sdp.c
+++ b/bta/ag/bta_ag_sdp.c
@@ -159,7 +159,7 @@
if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
{
profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
- version = HFP_VERSION_1_6;
+ version = BTA_HFP_VERSION;
}
else
{
diff --git a/bta/include/bta_ag_api.h b/bta/include/bta_ag_api.h
index ff85c9b..fa76a57 100644
--- a/bta/include/bta_ag_api.h
+++ b/bta/include/bta_ag_api.h
@@ -30,6 +30,24 @@
/*****************************************************************************
** Constants and data types
*****************************************************************************/
+#define HFP_VERSION_1_1 0x0101
+#define HFP_VERSION_1_5 0x0105
+#define HFP_VERSION_1_6 0x0106
+#define HFP_VERSION_1_7 0x0107
+
+#define HSP_VERSION_1_0 0x0100
+#define HSP_VERSION_1_2 0x0102
+
+/* Note, if you change the default version here, please also change the one in
+ * bta_hs_api.h, they are meant to be the same.
+ */
+#ifndef BTA_HFP_VERSION
+#define BTA_HFP_VERSION HFP_VERSION_1_7
+#endif
+
+#ifndef BTA_HFP_HF_IND_SUPPORTED
+#define BTA_HFP_HF_IND_SUPPORTED TRUE
+#endif
/* AG feature masks */
#define BTA_AG_FEAT_3WAY 0x00000001 /* Three-way calling */
@@ -42,12 +60,15 @@
#define BTA_AG_FEAT_ECC 0x00000080 /* Enhanced Call Control */
#define BTA_AG_FEAT_EXTERR 0x00000100 /* Extended error codes */
#define BTA_AG_FEAT_CODEC 0x00000200 /* Codec Negotiation */
-#define BTA_AG_FEAT_VOIP 0x00000400 /* VoIP call */
+#define BTA_AG_FEAT_HF_IND 0x00000400 /* HF Indicators */
+#define BTA_AG_FEAT_ESCO 0x00000800 /* eSCO S4 (and T2) setting supported */
+
/* Proprietary features: using 31 ~ 16 bits */
#define BTA_AG_FEAT_BTRH 0x00010000 /* CCAP incoming call hold */
#define BTA_AG_FEAT_UNAT 0x00020000 /* Pass unknown AT commands to application */
#define BTA_AG_FEAT_NOSCO 0x00040000 /* No SCO control performed by BTA AG */
#define BTA_AG_FEAT_NO_ESCO 0x00080000 /* Do not allow or use eSCO */
+#define BTA_AG_FEAT_VOIP 0x00100000 /* VoIP call */
typedef UINT32 tBTA_AG_FEAT;
@@ -63,6 +84,9 @@
#define BTA_AG_FAIL_RFCOMM 2 /* Open failed due to RFCOMM */
#define BTA_AG_FAIL_RESOURCES 3 /* out of resources failure */
+/*Status to disallow passing AT Events after BTIF */
+
+#define BTA_AG_DISALLOW_AT 5
typedef UINT8 tBTA_AG_STATUS;
/* handle values used with BTA_AgResult */
@@ -73,6 +97,18 @@
* SCO_NO_CHANGE is used for changing sco behavior
* They donot interfere with each other
*/
+
+/* Number of supported HF indicators, there is one HF indicator so far i.e.
+ enhanced driver status. */
+/* Number of supported HF indicators,
+ 1 for Enhanced Safety Status
+ 2 for Battery Level Status */
+#ifndef BTA_AG_NUM_LOCAL_HF_IND
+#define BTA_AG_NUM_LOCAL_HF_IND 2
+#endif
+
+
+
#define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF
/* AG result codes used with BTA_AgResult */
@@ -98,6 +134,7 @@
#define BTA_AG_IN_CALL_HELD_RES 19 /* Incoming call held */
#define BTA_AG_UNAT_RES 20 /* Response to unknown AT command event */
#define BTA_AG_MULTI_CALL_RES 21 /* SLC at three way call */
+#define BTA_AG_BIND_RES 22 /* Activate/Deactivate HF indicator */
typedef UINT8 tBTA_AG_RES;
@@ -110,9 +147,14 @@
#define BTA_AG_PEER_FEAT_ECS 0x0020 /* Enhanced Call Status */
#define BTA_AG_PEER_FEAT_ECC 0x0040 /* Enhanced Call Control */
#define BTA_AG_PEER_FEAT_CODEC 0x0080 /* Codec Negotiation */
-#define BTA_AG_PEER_FEAT_VOIP 0x0100 /* VoIP call */
+#define BTA_AG_PEER_FEAT_HF_IND 0x0100 /* HF Indicators */
+#define BTA_AG_PEER_FEAT_ESCO 0x0200 /* eSCO S4 (and T2) setting supported */
-typedef UINT16 tBTA_AG_PEER_FEAT;
+/* Proprietary features: using bits after 12 */
+#define BTA_AG_PEER_FEAT_UNAT 0x1000 /* Pass unknown AT command responses to application */
+#define BTA_AG_PEER_FEAT_VOIP 0x2000 /* VoIP call */
+
+typedef uint16_t tBTA_AG_PEER_FEAT;
/* HFP peer supported codec masks */
// TODO(google) This should use common definitions
@@ -204,8 +246,9 @@
/* data associated with BTA_AG_IND_RES */
typedef struct
{
- UINT16 id;
- UINT16 value;
+ uint16_t id;
+ uint16_t value;
+ bool on_demand;
} tBTA_AG_IND;
/* data type for BTA_AgResult() */
@@ -254,6 +297,8 @@
#define BTA_AG_AT_CBC_EVT 25 /* Battery Level report from HF */
#define BTA_AG_AT_BAC_EVT 26 /* avablable codec */
#define BTA_AG_AT_BCS_EVT 27 /* Codec select */
+#define BTA_AG_AT_BIND_EVT 28 /* HF indicator */
+#define BTA_AG_AT_BIEV_EVT 29 /* HF indicator updates from peer */
typedef UINT8 tBTA_AG_EVT;
@@ -305,6 +350,7 @@
char str[BTA_AG_AT_MAX_LEN+1];
UINT16 num;
UINT8 idx; /* call number used by CLCC and CHLD */
+ UINT16 lidx; /* long index, ex, HF indicator */
} tBTA_AG_VAL;
/* union of data associated with AG callback */
@@ -368,12 +414,24 @@
#define BTA_AG_BEARER_RES2 6 /* Reserved */
#define BTA_AG_BEARER_RES3 7 /* Reserved */
+/* type for HF indicator */
+typedef struct
+{
+ UINT16 ind_id;
+ BOOLEAN is_supported;
+ BOOLEAN is_enable;
+ UINT32 ind_min_val;
+ UINT32 ind_max_val;
+} tBTA_AG_HF_IND;
+
/* AG configuration structure */
typedef struct
{
char *cind_info;
- INT32 conn_tout;
- UINT16 sco_pkt_types;
+ char *bind_info;
+ uint8_t num_local_hf_ind;
+ int32_t conn_tout;
+ uint16_t sco_pkt_types;
char *chld_val_ecc;
char *chld_val;
} tBTA_AG_CFG;
diff --git a/btif/src/btif_hf.c b/btif/src/btif_hf.c
index 4987bbe..6abf099 100644
--- a/btif/src/btif_hf.c
+++ b/btif/src/btif_hf.c
@@ -73,6 +73,8 @@
BTA_AG_FEAT_BTRH | \
BTA_AG_FEAT_VREC | \
BTA_AG_FEAT_CODEC |\
+ BTA_AG_FEAT_HF_IND | \
+ BTA_AG_FEAT_ESCO | \
BTA_AG_FEAT_UNAT)
#endif
#else
@@ -84,6 +86,8 @@
BTA_AG_FEAT_EXTERR | \
BTA_AG_FEAT_BTRH | \
BTA_AG_FEAT_VREC | \
+ BTA_AG_FEAT_HF_IND | \
+ BTA_AG_FEAT_ESCO | \
BTA_AG_FEAT_UNAT)
#endif
#endif
@@ -621,6 +625,21 @@
BTHF_WBS_YES : BTHF_WBS_NO, &btif_hf_cb[idx].connected_bda);
break;
+ case BTA_AG_AT_BIND_EVT:
+ if (p_data->val.hdr.status == BTA_AG_SUCCESS)
+ {
+ HAL_CBACK(bt_hf_callbacks, bind_cb,p_data->val.str,
+ &btif_hf_cb[idx].connected_bda);
+ }
+ break;
+
+ case BTA_AG_AT_BIEV_EVT:
+ if (p_data->val.hdr.status == BTA_AG_SUCCESS)
+ {
+ HAL_CBACK(bt_hf_callbacks, biev_cb, (bthf_hf_ind_type_t)p_data->val.lidx, (int)p_data->val.num,
+ &btif_hf_cb[idx].connected_bda);
+ }
+ break;
default:
BTIF_TRACE_WARNING("%s: Unhandled event: %d", __FUNCTION__, event);
break;
@@ -1107,6 +1126,33 @@
/*******************************************************************************
**
+** Function bind_response
+**
+** Description Send +BIND response
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t bind_response(bthf_hf_ind_type_t ind_id, bthf_hf_ind_status_t ind_status,
+ bt_bdaddr_t * bd_addr)
+{
+ CHECK_BTHF_INIT();
+
+ int index = btif_hf_idx_by_bdaddr(bd_addr);
+ if (!is_connected(bd_addr) || index == BTIF_HF_INVALID_IDX)
+ return BT_STATUS_FAIL;
+
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.ind.id = ind_id;
+ ag_res.ind.on_demand = (ind_status == BTHF_HF_IND_ENABLED);
+
+ BTA_AgResult(btif_hf_cb[index].handle, BTA_AG_BIND_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
** Function formatted_at_response
**
** Description Pre-formatted AT response, typically in response to unknown AT cmd
@@ -1581,6 +1627,7 @@
phone_state_change,
cleanup,
configure_wbs,
+ bind_response,
};
/*******************************************************************************
diff --git a/btif/src/btif_util.c b/btif/src/btif_util.c
index f4cffcb..a8c58c9 100644
--- a/btif/src/btif_util.c
+++ b/btif/src/btif_util.c
@@ -306,6 +306,8 @@
CASE_RETURN_STR(BTA_AG_AT_CBC_EVT)
CASE_RETURN_STR(BTA_AG_AT_BAC_EVT)
CASE_RETURN_STR(BTA_AG_AT_BCS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BIND_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BIEV_EVT)
default:
return "UNKNOWN MSG ID";
diff --git a/stack/btm/btm_sco.c b/stack/btm/btm_sco.c
index 8c374f9..952d182 100644
--- a/stack/btm/btm_sco.c
+++ b/stack/btm/btm_sco.c
@@ -34,6 +34,8 @@
#include "btm_int.h"
#include "hcidefs.h"
#include "bt_utils.h"
+#include "device/include/controller.h"
+
#if BTM_SCO_INCLUDED == TRUE
@@ -668,7 +670,7 @@
btm_cb.btm_sco_pkt_types_supported);
/* OR in any exception packet types */
- if (btm_cb.sco_cb.desired_sco_mode == HCI_LINK_TYPE_ESCO)
+ if (controller_get_interface()->get_bt_version()->hci_version >= HCI_PROTO_VERSION_2_0)
{
temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
(btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
diff --git a/stack/btu/btu_hcif.c b/stack/btu/btu_hcif.c
index 9fa29e7..ade7a9b 100644
--- a/stack/btu/btu_hcif.c
+++ b/stack/btu/btu_hcif.c
@@ -1633,10 +1633,17 @@
/* extract the HCI handle first */
UINT8 status;
UINT16 handle;
+ UINT16 interval;
+ UINT16 latency;
+ UINT16 timeout;
- STREAM_TO_UINT8 (status, p);
- STREAM_TO_UINT16 (handle, p);
- l2cble_process_conn_update_evt(handle, status);
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT16(interval, p);
+ STREAM_TO_UINT16(latency, p);
+ STREAM_TO_UINT16(timeout, p);
+
+ l2cble_process_conn_update_evt(handle, status, interval, latency, timeout);
}
static void btu_ble_read_remote_feat_evt (UINT8 *p)
diff --git a/stack/include/sdpdefs.h b/stack/include/sdpdefs.h
index 44d87e7..a4d6cc2 100644
--- a/stack/include/sdpdefs.h
+++ b/stack/include/sdpdefs.h
@@ -281,6 +281,9 @@
#define UUID_CODEC_MSBC 0x0002 /* mSBC */
#endif
+#define UUID_HF_IND_ENHANCED_DRIVER_SAFETY 0x0001 /* Assigned number for Enhanced Safety */
+#define UUID_HF_IND_BATTERY_LEVEL_STATUS 0x0002 /* Assigned number for Battery Status */
+
/* Define all the 'Descriptor Type' values.
*/
#define NULL_DESC_TYPE 0
diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
index 4a2daa9..863530f 100644
--- a/stack/l2cap/l2c_ble.c
+++ b/stack/l2cap/l2c_ble.c
@@ -581,17 +581,16 @@
** Returns void
**
*******************************************************************************/
-void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status)
+void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status,
+ UINT16 interval, UINT16 latency, UINT16 timeout)
{
- tL2C_LCB *p_lcb;
-
- L2CAP_TRACE_DEBUG("l2cble_process_conn_update_evt");
+ L2CAP_TRACE_DEBUG("%s", __func__);
/* See if we have a link control block for the remote device */
- p_lcb = l2cu_find_lcb_by_handle(handle);
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle);
if (!p_lcb)
{
- L2CAP_TRACE_WARNING("l2cble_process_conn_update_evt: Invalid handle: %d", handle);
+ L2CAP_TRACE_WARNING("%s: Invalid handle: %d", __func__, handle);
return;
}
@@ -599,13 +598,14 @@
if (status != HCI_SUCCESS)
{
- L2CAP_TRACE_WARNING("l2cble_process_conn_update_evt: Error status: %d", status);
+ L2CAP_TRACE_WARNING("%s: Error status: %d", __func__, status);
}
l2cble_start_conn_update(p_lcb);
- L2CAP_TRACE_DEBUG("l2cble_process_conn_update_evt: conn_update_mask=%d", p_lcb->conn_update_mask);
+ L2CAP_TRACE_DEBUG("%s: conn_update_mask=%d", __func__, p_lcb->conn_update_mask);
}
+
/*******************************************************************************
**
** Function l2cble_process_sig_cmd
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index 54e1f03..8af47d7 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -767,7 +767,8 @@
extern BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb);
extern void l2cble_notify_le_connection (BD_ADDR bda);
extern void l2c_ble_link_adjust_allocation (void);
-extern void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status);
+extern void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status,
+ UINT16 interval, UINT16 latency, UINT16 timeout);
extern void l2cble_credit_based_conn_req (tL2C_CCB *p_ccb);
extern void l2cble_credit_based_conn_res (tL2C_CCB *p_ccb, UINT16 result);