Skip to content

Commit 3d8dfd7

Browse files
lylezhu2012nashif
authored andcommitted
Bluetooth: Classic: HFP_AG: Compatible old version HF
In current implementation, the HF with old version cannot be supported properly. Such as, if the AG is version 0.96, the AT command `AT+BRSF` will not be sent. It causes the AG cannot know the features of HF. Compatible old version with the following changes, Discover the HF SDP record to get the profile version and HF features. If the SDP discovery is failed, break the RFCOMM DLC connection. If the AG version is v0.96, update the HF features according to the discovered HF features. Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
1 parent 477b3dd commit 3d8dfd7

File tree

2 files changed

+173
-14
lines changed

2 files changed

+173
-14
lines changed

subsys/bluetooth/host/classic/hfp_ag.c

Lines changed: 158 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ static struct bt_ag_tx ag_tx[CONFIG_BT_HFP_AG_TX_BUF_COUNT * 2];
8383
static K_FIFO_DEFINE(ag_tx_free);
8484
static K_FIFO_DEFINE(ag_tx_notify);
8585

86+
#define BT_HFP_AG_VERSION BT_HFP_VERSION_1_9
87+
8688
/* HFP Gateway SDP record */
8789
static struct bt_sdp_attribute hfp_ag_attrs[] = {
8890
BT_SDP_NEW_SERVICE,
@@ -141,7 +143,7 @@ static struct bt_sdp_attribute hfp_ag_attrs[] = {
141143
},
142144
{
143145
BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
144-
BT_SDP_ARRAY_16(0x0109)
146+
BT_SDP_ARRAY_16(BT_HFP_AG_VERSION)
145147
},
146148
)
147149
},
@@ -3727,12 +3729,30 @@ static void hfp_ag_postprocess_at_cmd(struct bt_hfp_ag *ag)
37273729
k_work_reschedule(&ag->tx_work, K_NO_WAIT);
37283730
}
37293731

3732+
static int hfp_ag_at_cmd_ack(struct bt_hfp_ag *ag, int err)
3733+
{
3734+
enum at_cme cme_err;
3735+
3736+
if ((err != 0) && atomic_test_bit(ag->flags, BT_HFP_AG_CMEE_ENABLE)) {
3737+
cme_err = bt_hfp_ag_get_cme_err(err);
3738+
err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+CME ERROR:%d\r\n", (uint32_t)cme_err);
3739+
} else {
3740+
bt_hfp_ag_tx_cb_t cb;
3741+
3742+
cb = atomic_test_and_clear_bit(ag->flags, BT_HFP_AG_SLC_CONNECTED)
3743+
? bt_hfp_ag_slc_connected
3744+
: NULL;
3745+
err = hfp_ag_send_data(ag, cb, NULL, "\r\n%s\r\n", (err == 0) ? "OK" : "ERROR");
3746+
}
3747+
3748+
return err;
3749+
}
3750+
37303751
static void hfp_ag_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
37313752
{
37323753
struct bt_hfp_ag *ag = CONTAINER_OF(dlc, struct bt_hfp_ag, rfcomm_dlc);
37333754
uint8_t *data = buf->data;
37343755
uint16_t len = buf->len;
3735-
enum at_cme cme_err;
37363756
int err = -ENOEXEC;
37373757

37383758
LOG_HEXDUMP_DBG(data, len, "Received:");
@@ -3760,18 +3780,15 @@ static void hfp_ag_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
37603780
return;
37613781
}
37623782

3763-
if ((err != 0) && atomic_test_bit(ag->flags, BT_HFP_AG_CMEE_ENABLE)) {
3764-
cme_err = bt_hfp_ag_get_cme_err(err);
3765-
err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+CME ERROR:%d\r\n", (uint32_t)cme_err);
3766-
} else {
3767-
bt_hfp_ag_tx_cb_t cb;
3768-
3769-
cb = atomic_test_and_clear_bit(ag->flags, BT_HFP_AG_SLC_CONNECTED)
3770-
? bt_hfp_ag_slc_connected
3771-
: NULL;
3772-
err = hfp_ag_send_data(ag, cb, NULL, "\r\n%s\r\n", (err == 0) ? "OK" : "ERROR");
3783+
if (!atomic_test_and_set_bit(ag->flags, BT_HFP_AG_1ST_AT_RECV)) {
3784+
LOG_DBG("First AT command ack will be replied later");
3785+
ag->ack_err = err;
3786+
k_work_submit(&ag->slc_work);
3787+
return;
37733788
}
37743789

3790+
err = hfp_ag_at_cmd_ack(ag, err);
3791+
37753792
hfp_ag_postprocess_at_cmd(ag);
37763793

37773794
if (err != 0) {
@@ -4004,16 +4021,123 @@ static void bt_ag_ongoing_call_work(struct k_work *work)
40044021
bt_ag_send_ok_code(ag);
40054022
}
40064023

4024+
static void bt_ag_slc_work(struct k_work *work)
4025+
{
4026+
struct bt_hfp_ag *ag = CONTAINER_OF(work, struct bt_hfp_ag, slc_work);
4027+
int err;
4028+
4029+
if (!atomic_test_bit(ag->flags, BT_HFP_AG_DISCOVER_DONE)) {
4030+
return;
4031+
}
4032+
4033+
if (!atomic_test_bit(ag->flags, BT_HFP_AG_1ST_AT_RECV)) {
4034+
return;
4035+
}
4036+
4037+
if (atomic_test_and_set_bit(ag->flags, BT_HFP_AG_FEAT_UPDATED)) {
4038+
return;
4039+
}
4040+
4041+
if (atomic_test_bit(ag->flags, BT_HFP_AG_RECORD_FOUND)) {
4042+
err = hfp_ag_at_cmd_ack(ag, ag->ack_err);
4043+
hfp_ag_postprocess_at_cmd(ag);
4044+
if (err != 0) {
4045+
LOG_ERR("Failed to send AT command ACK: %d", err);
4046+
}
4047+
return;
4048+
}
4049+
4050+
err = bt_hfp_ag_disconnect(ag);
4051+
if (err != 0) {
4052+
LOG_ERR("Failed to disconnect HF: %d", err);
4053+
}
4054+
}
4055+
4056+
#define HFP_SDP_FEAT_MASK GENMASK(4, 0)
4057+
4058+
static uint8_t bt_hfp_ag_discover_cb(struct bt_conn *conn, struct bt_sdp_client_result *result,
4059+
const struct bt_sdp_discover_params *params)
4060+
{
4061+
size_t index;
4062+
struct bt_hfp_ag *ag;
4063+
int err;
4064+
4065+
index = (size_t)bt_conn_index(conn);
4066+
__ASSERT(index < ARRAY_SIZE(bt_hfp_ag_pool), "Index is out of bounds");
4067+
4068+
ag = &bt_hfp_ag_pool[index];
4069+
4070+
if ((result == NULL) || (result->resp_buf == NULL)) {
4071+
LOG_ERR("SDP discovery failed");
4072+
goto failed;
4073+
}
4074+
4075+
err = bt_sdp_get_profile_version(result->resp_buf, BT_SDP_HANDSFREE_SVCLASS,
4076+
&ag->hf_sdp_version);
4077+
if (err != 0) {
4078+
LOG_ERR("Failed to get HF profile version");
4079+
goto failed;
4080+
}
4081+
err = bt_sdp_get_features(result->resp_buf, &ag->hf_sdp_features);
4082+
if (err != 0) {
4083+
LOG_ERR("Failed to get HF feature");
4084+
goto failed;
4085+
}
4086+
4087+
if ((ag->hf_sdp_version <= BT_HFP_VERSION_1_5) ||
4088+
(BT_HFP_AG_VERSION <= BT_HFP_VERSION_1_5)) {
4089+
if (ag->hf_sdp_features & BT_HFP_HF_SDP_FEATURE_WBS) {
4090+
LOG_WRN("Unsupported SDP feature (WBS) is enabled.");
4091+
ag->hf_sdp_features &= ~BT_HFP_HF_SDP_FEATURE_WBS;
4092+
}
4093+
4094+
if (ag->hf_sdp_features & BT_HFP_HF_SDP_FEATURE_SUPER_WBS) {
4095+
LOG_WRN("Unsupported SDP feature (Super WBS) is enabled.");
4096+
ag->hf_sdp_features &= ~BT_HFP_HF_SDP_FEATURE_SUPER_WBS;
4097+
}
4098+
}
4099+
4100+
if ((ag->hf_sdp_version <= BT_HFP_VERSION_0_96) ||
4101+
(BT_HFP_AG_VERSION <= BT_HFP_VERSION_0_96)) {
4102+
/* Update the AG features according to the SDP features for HFP version 0.96.
4103+
*
4104+
* Hands-Free Profile Specification V1.9, 6.3 SDP Interoperability Requirements
4105+
* The values of the “SupportedFeatures” bitmap given in Table 6.6 shall be the
4106+
* same as the values of the Bits 0 to 4 of the unsolicited result code +BRSF.
4107+
*/
4108+
ag->hf_features = ag->hf_sdp_features & HFP_SDP_FEAT_MASK;
4109+
}
4110+
4111+
atomic_set_bit(ag->flags, BT_HFP_AG_RECORD_FOUND);
4112+
failed:
4113+
atomic_set_bit(ag->flags, BT_HFP_AG_DISCOVER_DONE);
4114+
k_work_submit(&ag->slc_work);
4115+
4116+
return BT_SDP_DISCOVER_UUID_STOP;
4117+
}
4118+
40074119
static struct bt_hfp_ag *hfp_ag_create(struct bt_conn *conn)
40084120
{
4121+
size_t index;
4122+
struct bt_hfp_ag *ag;
4123+
int err;
4124+
40094125
static struct bt_rfcomm_dlc_ops ops = {
40104126
.connected = hfp_ag_connected,
40114127
.disconnected = hfp_ag_disconnected,
40124128
.recv = hfp_ag_recv,
40134129
.sent = hfp_ag_sent,
40144130
};
4015-
size_t index;
4016-
struct bt_hfp_ag *ag;
4131+
static struct bt_sdp_attribute_id_range id_range[] = {
4132+
{ BT_SDP_ATTR_PROTO_DESC_LIST, BT_SDP_ATTR_PROTO_DESC_LIST },
4133+
{ BT_SDP_ATTR_PROFILE_DESC_LIST, BT_SDP_ATTR_PROFILE_DESC_LIST },
4134+
{ BT_SDP_ATTR_SUPPORTED_FEATURES, BT_SDP_ATTR_SUPPORTED_FEATURES },
4135+
};
4136+
static struct bt_sdp_attribute_id_list id_list = {
4137+
.count = ARRAY_SIZE(id_range),
4138+
.ranges = id_range,
4139+
};
4140+
static struct bt_uuid_16 uuid;
40174141

40184142
LOG_DBG("conn %p", conn);
40194143

@@ -4028,6 +4152,20 @@ static struct bt_hfp_ag *hfp_ag_create(struct bt_conn *conn)
40284152

40294153
(void)memset(ag, 0, sizeof(struct bt_hfp_ag));
40304154

4155+
uuid.uuid.type = BT_UUID_TYPE_16;
4156+
uuid.val = BT_SDP_HANDSFREE_SVCLASS;
4157+
4158+
ag->sdp_param.func = bt_hfp_ag_discover_cb;
4159+
ag->sdp_param.type = BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR;
4160+
ag->sdp_param.uuid = &uuid.uuid;
4161+
ag->sdp_param.pool = &ag_pool;
4162+
ag->sdp_param.ids = &id_list;
4163+
4164+
err = bt_sdp_discover(conn, &ag->sdp_param);
4165+
if (err != 0) {
4166+
return NULL;
4167+
}
4168+
40314169
sys_slist_init(&ag->tx_pending);
40324170
sys_slist_init(&ag->tx_submit_pending);
40334171

@@ -4040,6 +4178,10 @@ static struct bt_hfp_ag *hfp_ag_create(struct bt_conn *conn)
40404178
ag->ag_features = BT_HFP_AG_SUPPORTED_FEATURES;
40414179
ag->ag_features |= BT_FEAT_SC(bt_dev.features) ? BT_HFP_AG_FEATURE_ESCO_S4 : 0;
40424180

4181+
/* Set the default HF infrmation */
4182+
ag->hf_sdp_features = 0;
4183+
ag->hf_sdp_version = BT_HFP_VERSION_0_96;
4184+
40434185
/* Support HF indicators */
40444186
if (IS_ENABLED(CONFIG_BT_HFP_AG_HF_INDICATOR_ENH_SAFETY)) {
40454187
ag->hf_indicators_of_ag |= BIT(HFP_HF_ENHANCED_SAFETY_IND);
@@ -4082,6 +4224,8 @@ static struct bt_hfp_ag *hfp_ag_create(struct bt_conn *conn)
40824224
/* Set Codec ID*/
40834225
ag->selected_codec_id = BT_HFP_AG_CODEC_CVSD;
40844226

4227+
k_work_init(&ag->slc_work, bt_ag_slc_work);
4228+
40854229
/* Init delay work */
40864230
k_work_init_delayable(&ag->tx_work, bt_ag_tx_work);
40874231
/* Init delay work */

subsys/bluetooth/host/classic/hfp_ag_internal.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ enum {
173173
BT_HGP_AG_ONGOING_CALLS, /* Waiting ongoing calls */
174174
BT_HFP_AG_SLC_CONNECTED, /* SLC connected event needs to be notified */
175175
BT_HFP_AG_AT_PROCESS, /* AT command is in processing */
176+
BT_HFP_AG_DISCOVER_DONE, /* SDP Record discovered done */
177+
BT_HFP_AG_RECORD_FOUND, /* SDP HF Record found */
178+
BT_HFP_AG_1ST_AT_RECV, /* 1st AT is received */
179+
BT_HFP_AG_FEAT_UPDATED, /* Remote feature has been updated */
176180

177181
/* Total number of flags - must be at the end of the enum */
178182
BT_HFP_AG_NUM_FLAGS,
@@ -266,6 +270,10 @@ struct bt_hfp_ag {
266270
uint32_t hf_indicators_of_hf;
267271
uint32_t hf_indicators;
268272

273+
/* AG profile information */
274+
uint16_t hf_sdp_version;
275+
uint16_t hf_sdp_features;
276+
269277
/* operator */
270278
uint8_t mode;
271279
char operator[AT_COPS_OPERATOR_MAX_LEN + 1];
@@ -285,6 +293,13 @@ struct bt_hfp_ag {
285293
/* SCO connect */
286294
struct bt_conn *sco_conn;
287295

296+
/* SDP discover params */
297+
struct bt_sdp_discover_params sdp_param;
298+
299+
/* SCL work */
300+
struct k_work slc_work;
301+
int ack_err;
302+
288303
/* HFP TX pending */
289304
sys_slist_t tx_pending;
290305
sys_slist_t tx_submit_pending;

0 commit comments

Comments
 (0)