@@ -83,6 +83,8 @@ static struct bt_ag_tx ag_tx[CONFIG_BT_HFP_AG_TX_BUF_COUNT * 2];
8383static K_FIFO_DEFINE (ag_tx_free );
8484static K_FIFO_DEFINE (ag_tx_notify );
8585
86+ #define BT_HFP_AG_VERSION BT_HFP_VERSION_1_9
87+
8688/* HFP Gateway SDP record */
8789static 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+
37303751static 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+
40074119static 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 */
0 commit comments