Skip to content

Commit d7cdadc

Browse files
lylezhu2012kartben
authored andcommitted
Bluetooth: HFP_HF: Initiate SLC establishment
Add function `bt_hfp_hf_connect` to initialize the Service Level Connection establishment procedure. Add function `bt_hfp_hf_disconnect` to release the Service Level Connection. Clear HF object if the RFCOMM is disconnected. Signed-off-by: Lyle Zhu <[email protected]>
1 parent f482613 commit d7cdadc

File tree

2 files changed

+130
-29
lines changed

2 files changed

+130
-29
lines changed

include/zephyr/bluetooth/classic/hfp_hf.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,55 @@ struct bt_hfp_hf_cb {
429429
*/
430430
int bt_hfp_hf_register(struct bt_hfp_hf_cb *cb);
431431

432+
/** @brief Initiate the service level connection establishment procedure
433+
*
434+
* Initiate the service level connection establishment procedure on the
435+
* ACL connection specified by the parameter `conn` using the specific
436+
* RFCOMM channel discovered by the function `bt_br_discovery_start`.
437+
*
438+
* The parameter `hf` is a output parameter. When the service level
439+
* connection establishment procedure is initiated without any error,
440+
* the HFP HF object is allocated and it will be returned via the parameter
441+
* `hf` if the parameter `hf` is not a NULL pointer.
442+
*
443+
* When service level conenction is established, the registered callback
444+
* `connected` will be triggered to notify the application that the service
445+
* level connection establishment procedure is done. And the HFP HF object
446+
* is valid at this time. It means after the function is called without
447+
* any error, all interfaces provided by HFP HF can only be called after
448+
* the registered callback `connected` is triggered.
449+
*
450+
* @param conn ACL connection object.
451+
* @param hf Created HFP HF object.
452+
* @param channel Peer RFCOMM channel to be connected.
453+
*
454+
* @return 0 in case of success or negative value in case of error.
455+
*/
456+
int bt_hfp_hf_connect(struct bt_conn *conn, struct bt_hfp_hf **hf, uint8_t channel);
457+
458+
/** @brief Release the service level connection
459+
*
460+
* Release the service level connection from the peer device.
461+
*
462+
* The function can only be called after the registered callback `connected`
463+
* is triggered.
464+
*
465+
* If the function is called without any error, the HFP HF object is
466+
* invalid at this time. All interfaces provided by HFP HF should not
467+
* be called anymore.
468+
*
469+
* If the service level connection is released, the registered callback
470+
* `disconnected` will be triggered to notify the application that the
471+
* service level connection release procedure is done. And the HFP HF
472+
* object will be freed after the registered callback `disconnected`
473+
* returned.
474+
*
475+
* @param hf HFP HF object.
476+
*
477+
* @return 0 in case of success or negative value in case of error.
478+
*/
479+
int bt_hfp_hf_disconnect(struct bt_hfp_hf *hf);
480+
432481
/** @brief Handsfree HF enable/disable Calling Line Identification (CLI) Notification
433482
*
434483
* Enable/disable Calling Line Identification (CLI) Notification.

subsys/bluetooth/host/classic/hfp_hf.c

Lines changed: 81 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3919,6 +3919,10 @@ static void hfp_hf_disconnected(struct bt_rfcomm_dlc *dlc)
39193919
if (bt_hf->disconnected) {
39203920
bt_hf->disconnected(hf);
39213921
}
3922+
3923+
k_work_cancel(&hf->work);
3924+
k_work_cancel_delayable(&hf->deferred_work);
3925+
hf->acl = NULL;
39223926
}
39233927

39243928
static void hfp_hf_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
@@ -3945,60 +3949,68 @@ static void bt_hf_work(struct k_work *work)
39453949
hfp_hf_send_data(hf);
39463950
}
39473951

3948-
static int hfp_hf_accept(struct bt_conn *conn, struct bt_rfcomm_server *server,
3949-
struct bt_rfcomm_dlc **dlc)
3952+
static struct bt_hfp_hf *hfp_hf_create(struct bt_conn *conn)
39503953
{
3951-
int i;
3954+
size_t index;
39523955
static struct bt_rfcomm_dlc_ops ops = {
39533956
.connected = hfp_hf_connected,
39543957
.disconnected = hfp_hf_disconnected,
39553958
.recv = hfp_hf_recv,
39563959
.sent = hfp_hf_sent,
39573960
};
3961+
struct bt_hfp_hf *hf;
39583962

39593963
LOG_DBG("conn %p", conn);
39603964

3961-
for (i = 0; i < ARRAY_SIZE(bt_hfp_hf_pool); i++) {
3962-
struct bt_hfp_hf *hf = &bt_hfp_hf_pool[i];
3963-
int j;
3965+
index = (size_t)bt_conn_index(conn);
3966+
hf = &bt_hfp_hf_pool[index];
3967+
if (hf->acl) {
3968+
LOG_ERR("HF connection (%p) is established", conn);
3969+
return NULL;
3970+
}
39643971

3965-
if (hf->rfcomm_dlc.session) {
3966-
continue;
3967-
}
3972+
memset(hf, 0, sizeof(*hf));
3973+
3974+
hf->acl = conn;
3975+
hf->at.buf = hf->hf_buffer;
3976+
hf->at.buf_max_len = HF_MAX_BUF_LEN;
39683977

3969-
memset(hf, 0, sizeof(*hf));
3978+
hf->rfcomm_dlc.ops = &ops;
3979+
hf->rfcomm_dlc.mtu = BT_HFP_MAX_MTU;
39703980

3971-
hf->acl = conn;
3972-
hf->at.buf = hf->hf_buffer;
3973-
hf->at.buf_max_len = HF_MAX_BUF_LEN;
3981+
/* Set the supported features*/
3982+
hf->hf_features = BT_HFP_HF_SUPPORTED_FEATURES;
39743983

3975-
hf->rfcomm_dlc.ops = &ops;
3976-
hf->rfcomm_dlc.mtu = BT_HFP_MAX_MTU;
3984+
/* Set supported codec ids */
3985+
hf->hf_codec_ids = BT_HFP_HF_SUPPORTED_CODEC_IDS;
39773986

3978-
*dlc = &hf->rfcomm_dlc;
3987+
k_fifo_init(&hf->tx_pending);
39793988

3980-
/* Set the supported features*/
3981-
hf->hf_features = BT_HFP_HF_SUPPORTED_FEATURES;
3989+
k_work_init(&hf->work, bt_hf_work);
39823990

3983-
/* Set supported codec ids */
3984-
hf->hf_codec_ids = BT_HFP_HF_SUPPORTED_CODEC_IDS;
3991+
k_work_init_delayable(&hf->deferred_work, bt_hf_deferred_work);
39853992

3986-
k_fifo_init(&hf->tx_pending);
3993+
for (index = 0; index < ARRAY_SIZE(hf->ind_table); index++) {
3994+
hf->ind_table[index] = -1;
3995+
}
39873996

3988-
k_work_init(&hf->work, bt_hf_work);
3997+
return hf;
3998+
}
39893999

3990-
k_work_init_delayable(&hf->deferred_work, bt_hf_deferred_work);
4000+
static int hfp_hf_accept(struct bt_conn *conn, struct bt_rfcomm_server *server,
4001+
struct bt_rfcomm_dlc **dlc)
4002+
{
4003+
struct bt_hfp_hf *hf;
39914004

3992-
for (j = 0; j < HF_MAX_AG_INDICATORS; j++) {
3993-
hf->ind_table[j] = -1;
3994-
}
4005+
hf = hfp_hf_create(conn);
39954006

3996-
return 0;
4007+
if (!hf) {
4008+
return -ECONNREFUSED;
39974009
}
39984010

3999-
LOG_ERR("Unable to establish HF connection (%p)", conn);
4011+
*dlc = &hf->rfcomm_dlc;
40004012

4001-
return -ENOMEM;
4013+
return 0;
40024014
}
40034015

40044016
static void hfp_hf_sco_connected(struct bt_sco_chan *chan)
@@ -4086,3 +4098,43 @@ int bt_hfp_hf_register(struct bt_hfp_hf_cb *cb)
40864098

40874099
return 0;
40884100
}
4101+
4102+
int bt_hfp_hf_connect(struct bt_conn *conn, struct bt_hfp_hf **hf, uint8_t channel)
4103+
{
4104+
struct bt_hfp_hf *new_hf;
4105+
int err;
4106+
4107+
if (!conn || !hf || !channel) {
4108+
return -EINVAL;
4109+
}
4110+
4111+
if (!bt_hf) {
4112+
return -EFAULT;
4113+
}
4114+
4115+
new_hf = hfp_hf_create(conn);
4116+
if (!new_hf) {
4117+
return -ECONNREFUSED;
4118+
}
4119+
4120+
err = bt_rfcomm_dlc_connect(conn, &new_hf->rfcomm_dlc, channel);
4121+
if (err != 0) {
4122+
(void)memset(new_hf, 0, sizeof(*new_hf));
4123+
*hf = NULL;
4124+
} else {
4125+
*hf = new_hf;
4126+
}
4127+
4128+
return err;
4129+
}
4130+
4131+
int bt_hfp_hf_disconnect(struct bt_hfp_hf *hf)
4132+
{
4133+
LOG_DBG("");
4134+
4135+
if (!hf) {
4136+
return -EINVAL;
4137+
}
4138+
4139+
return bt_rfcomm_dlc_disconnect(&hf->rfcomm_dlc);
4140+
}

0 commit comments

Comments
 (0)