Skip to content

Commit f2d2060

Browse files
lylezhu2012Hardevsinh-Palaniya
authored andcommitted
Bluetooth: Classic: HFP_HF: Support users to query current call list
Add the function `bt_hfp_hf_query_list_of_current_calls()` to support users to query current call list. Add the callback `bt_hfp_hf_cb::query_call` to notify the received current calls. Signed-off-by: Lyle Zhu <[email protected]>
1 parent 46fb82a commit f2d2060

File tree

3 files changed

+175
-25
lines changed

3 files changed

+175
-25
lines changed

include/zephyr/bluetooth/classic/hfp_hf.h

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,77 @@ struct bt_hfp_hf;
3232

3333
struct bt_hfp_hf_call;
3434

35+
/** @brief The status of the call
36+
*
37+
* Enumeration defining the various states a call can be in during
38+
* HFP communication between HF and AG.
39+
*/
40+
enum __packed bt_hfp_hf_call_status {
41+
/** Call is active and ongoing */
42+
BT_HFP_HF_CALL_STATUS_ACTIVE = 0,
43+
/** Call is on hold */
44+
BT_HFP_HF_CALL_STATUS_HELD = 1,
45+
/** Outgoing call is being dialed */
46+
BT_HFP_HF_CALL_STATUS_DIALING = 2,
47+
/** Outgoing call is being alerted (ringing on remote end) */
48+
BT_HFP_HF_CALL_STATUS_ALERTING = 3,
49+
/** Incoming call has arrived */
50+
BT_HFP_HF_CALL_STATUS_INCOMING = 4,
51+
/** Incoming call is waiting (call waiting scenario) */
52+
BT_HFP_HF_CALL_STATUS_WAITING = 5,
53+
/** Call held by Response and Hold feature */
54+
BT_HFP_HF_CALL_STATUS_INCOMING_HELD = 6
55+
};
56+
57+
/** @brief The direction of the call
58+
*
59+
* Enumeration defining whether the call was initiated by the HF
60+
* (outgoing) or by the remote party (incoming).
61+
*/
62+
enum __packed bt_hfp_hf_call_dir {
63+
/** It is an outgoing call initiated by HF */
64+
BT_HFP_HF_CALL_DIR_OUTGOING = 0,
65+
/** It is an incoming call from remote party */
66+
BT_HFP_HF_CALL_DIR_INCOMING = 1,
67+
};
68+
69+
/** @brief The mode of the call
70+
*
71+
* Enumeration defining the type of call being established,
72+
* whether voice, data, or fax transmission.
73+
*/
74+
enum __packed bt_hfp_hf_call_mode {
75+
/** Voice call */
76+
BT_HFP_HF_CALL_MODE_VOICE = 0,
77+
/** Data call */
78+
BT_HFP_HF_CALL_MODE_DATA = 1,
79+
/** Fax transmission */
80+
BT_HFP_HF_CALL_MODE_FAX = 2,
81+
};
82+
83+
/** @brief The information of current call
84+
*
85+
* Structure containing comprehensive information about a current call,
86+
* including its index, direction, status, mode, multiparty status,
87+
* phone number, and number type.
88+
*/
89+
struct bt_hfp_hf_current_call {
90+
/** Call index identifier */
91+
uint8_t index;
92+
/** Call direction (incoming/outgoing) */
93+
enum bt_hfp_hf_call_dir dir;
94+
/** Current status of the call */
95+
enum bt_hfp_hf_call_status status;
96+
/** Call mode (voice/data/fax) */
97+
enum bt_hfp_hf_call_mode mode;
98+
/** True if call is part of a multiparty conference */
99+
bool multiparty;
100+
/** Phone number string, NULL if not available */
101+
const char *number;
102+
/** Phone number type format identifier */
103+
uint8_t type;
104+
};
105+
35106
/** @brief HFP profile application callback */
36107
struct bt_hfp_hf_cb {
37108
/** HF connected callback to application
@@ -416,6 +487,20 @@ struct bt_hfp_hf_cb {
416487
*/
417488
void (*subscriber_number)(struct bt_hfp_hf *hf, const char *number, uint8_t type,
418489
uint8_t service);
490+
491+
/** Query list of current calls callback
492+
*
493+
* If this callback is provided it will be called whenever the
494+
* result code `+CLCC: <idx>,<dir>,<status>,<mode>,<mprty>[,<number>,<type>]`
495+
* is received from AG.
496+
* If the request is failed or no active calls, the callback will not be called.
497+
* If the @ref bt_hfp_hf_current_call::number is NULL, the
498+
* @ref bt_hfp_hf_current_call::type shall be ignored.
499+
*
500+
* @param hf HFP HF object.
501+
* @param call Current call information.
502+
*/
503+
void (*query_call)(struct bt_hfp_hf *hf, struct bt_hfp_hf_current_call *call);
419504
};
420505

421506
/** @brief Register HFP HF profile
@@ -952,6 +1037,18 @@ int bt_hfp_hf_enhanced_safety(struct bt_hfp_hf *hf, bool enable);
9521037
*/
9531038
int bt_hfp_hf_battery(struct bt_hfp_hf *hf, uint8_t level);
9541039

1040+
/** @brief Handsfree HF query list of current calls
1041+
*
1042+
* It allows HF to query list of current calls by sending `AT+CLCC` command.
1043+
* If @kconfig{CONFIG_BT_HFP_HF_ECS} is not enabled,
1044+
* the error `-ENOTSUP` will be returned if the function called.
1045+
*
1046+
* @param hf HFP HF object.
1047+
*
1048+
* @return 0 in case of success or negative value in case of error.
1049+
*/
1050+
int bt_hfp_hf_query_list_of_current_calls(struct bt_hfp_hf *hf);
1051+
9551052
#ifdef __cplusplus
9561053
}
9571054
#endif

subsys/bluetooth/host/classic/hfp_hf.c

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ static int clcc_finish(struct at_client *hf_at, enum at_result result,
509509
clear_call_without_clcc(hf);
510510
}
511511

512+
atomic_clear_bit(hf->flags, BT_HFP_HF_FLAG_USR_CLCC_CMD);
512513
atomic_clear_bit(hf->flags, BT_HFP_HF_FLAG_CLCC_PENDING);
513514

514515
return 0;
@@ -529,32 +530,36 @@ static void clear_call_clcc_state(struct bt_hfp_hf *hf)
529530
}
530531
}
531532

532-
static void hf_query_current_calls(struct bt_hfp_hf *hf)
533+
static int hf_query_current_calls(struct bt_hfp_hf *hf)
533534
{
534535
int err;
535536

536537
LOG_DBG("");
537538

538539
if (!hf) {
539540
LOG_ERR("No HF connection found");
540-
return;
541+
return -EINVAL;
541542
}
542543

543544
if (!atomic_test_bit(hf->flags, BT_HFP_HF_FLAG_CONNECTED)) {
544-
return;
545+
return -ENOTCONN;
545546
}
546547

547548
if (!(hf->ag_features & BT_HFP_AG_FEATURE_ECS)) {
548-
return;
549+
return -ENOTSUP;
549550
}
550551

551552
if (!(hf->hf_features & BT_HFP_HF_FEATURE_ECS)) {
552-
return;
553+
return -ENOTSUP;
553554
}
554555

555556
if (atomic_test_and_set_bit(hf->flags, BT_HFP_HF_FLAG_CLCC_PENDING)) {
556557
k_work_reschedule(&hf->deferred_work, K_MSEC(HF_ENHANCED_CALL_STATUS_TIMEOUT));
557-
return;
558+
return 0;
559+
}
560+
561+
if (atomic_test_and_clear_bit(hf->flags, BT_HFP_HF_FLAG_USR_CLCC_PND)) {
562+
atomic_set_bit(hf->flags, BT_HFP_HF_FLAG_USR_CLCC_CMD);
558563
}
559564

560565
clear_call_clcc_state(hf);
@@ -563,6 +568,8 @@ static void hf_query_current_calls(struct bt_hfp_hf *hf)
563568
if (err < 0) {
564569
LOG_ERR("Fail to query current calls on %p", hf);
565570
}
571+
572+
return err;
566573
}
567574

568575
static void hf_call_state_update(struct bt_hfp_hf_call *call, int state)
@@ -812,20 +819,6 @@ static int clcc_handle(struct at_client *hf_at)
812819
return err;
813820
}
814821

815-
if (new_call) {
816-
set_call_incoming_flag(call, dir == BT_HFP_CLCC_DIR_INCOMING);
817-
}
818-
819-
if (atomic_test_bit(call->flags, BT_HFP_HF_CALL_INCOMING) ||
820-
atomic_test_bit(call->flags, BT_HFP_HF_CALL_INCOMING_3WAY)) {
821-
incoming = true;
822-
}
823-
824-
if (incoming != (dir == BT_HFP_CLCC_DIR_INCOMING)) {
825-
LOG_ERR("Call dir of HF is not aligned with AG");
826-
return 0;
827-
}
828-
829822
err = at_get_number(hf_at, &status);
830823
if (err < 0) {
831824
LOG_ERR("Error getting status");
@@ -846,19 +839,48 @@ static int clcc_handle(struct at_client *hf_at)
846839

847840
number = at_get_string(hf_at);
848841

849-
if (number) {
842+
if (number != NULL) {
850843
(void)at_get_number(hf_at, &type);
851844
}
852845

846+
if (atomic_test_bit(hf->flags, BT_HFP_HF_FLAG_USR_CLCC_CMD) &&
847+
(bt_hf->query_call != NULL)) {
848+
struct bt_hfp_hf_current_call current_call;
849+
850+
current_call.index = (uint8_t)index;
851+
current_call.dir = (enum bt_hfp_hf_call_dir)dir;
852+
current_call.status = (enum bt_hfp_hf_call_status)status;
853+
current_call.mode = (enum bt_hfp_hf_call_mode)mode;
854+
current_call.multiparty = mpty > 0 ? true : false;
855+
current_call.number = number;
856+
current_call.type = (uint8_t)type;
857+
858+
bt_hf->query_call(hf, &current_call);
859+
}
860+
861+
LOG_DBG("CLCC idx %d dir %d status %d mode %d mpty %d number %s type %d",
862+
index, dir, status, mode, mpty, number, type);
863+
864+
if (new_call) {
865+
set_call_incoming_flag(call, dir == BT_HFP_CLCC_DIR_INCOMING);
866+
}
867+
868+
if (atomic_test_bit(call->flags, BT_HFP_HF_CALL_INCOMING) ||
869+
atomic_test_bit(call->flags, BT_HFP_HF_CALL_INCOMING_3WAY)) {
870+
incoming = true;
871+
}
872+
873+
if (incoming != (dir == BT_HFP_CLCC_DIR_INCOMING)) {
874+
LOG_ERR("Call dir of HF is not aligned with AG");
875+
return 0;
876+
}
877+
853878
if (new_call) {
854879
new_call_state_update(call, incoming, status);
855880
} else {
856881
call_state_update(call, status);
857882
}
858883

859-
LOG_DBG("CLCC idx %d dir %d status %d mode %d mpty %d number %s type %d",
860-
index, dir, status, mode, mpty, number, type);
861-
862884
return 0;
863885
}
864886
#endif /* CONFIG_BT_HFP_HF_ECS */
@@ -1054,8 +1076,12 @@ static void bt_hf_deferred_work(struct k_work *work)
10541076
{
10551077
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
10561078
struct bt_hfp_hf *hf = CONTAINER_OF(dwork, struct bt_hfp_hf, deferred_work);
1079+
int err;
10571080

1058-
hf_query_current_calls(hf);
1081+
err = hf_query_current_calls(hf);
1082+
if (err != 0) {
1083+
LOG_ERR("Failed to query current calls: %d", err);
1084+
}
10591085
}
10601086

10611087
static void set_all_calls_held_state(struct bt_hfp_hf *hf, bool held)
@@ -4273,3 +4299,28 @@ int bt_hfp_hf_disconnect(struct bt_hfp_hf *hf)
42734299

42744300
return bt_rfcomm_dlc_disconnect(&hf->rfcomm_dlc);
42754301
}
4302+
4303+
int bt_hfp_hf_query_list_of_current_calls(struct bt_hfp_hf *hf)
4304+
{
4305+
int err;
4306+
4307+
if ((hf == NULL) || (bt_hf == NULL) || (bt_hf->query_call == NULL)) {
4308+
return -EINVAL;
4309+
}
4310+
4311+
if (!IS_ENABLED(CONFIG_BT_HFP_HF_ECS)) {
4312+
return -ENOTSUP;
4313+
}
4314+
4315+
if (atomic_test_and_set_bit(hf->flags, BT_HFP_HF_FLAG_USR_CLCC_PND)) {
4316+
return -EBUSY;
4317+
}
4318+
4319+
err = hf_query_current_calls(hf);
4320+
if (err != 0) {
4321+
atomic_clear_bit(hf->flags, BT_HFP_HF_FLAG_USR_CLCC_PND);
4322+
LOG_ERR("Failed to query current calls, err %d", err);
4323+
}
4324+
4325+
return err;
4326+
}

subsys/bluetooth/host/classic/hfp_hf_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ enum {
145145
BT_HFP_HF_FLAG_BINP, /* +BINP result code is received */
146146
BT_HFP_HF_FLAG_INITIATING, /* HF is in initiating state */
147147
BT_HFP_HF_FLAG_QUERY_CALLS, /* Require to query list of current calls */
148+
BT_HFP_HF_FLAG_USR_CLCC_CMD, /* User-initiated AT+CLCC command */
149+
BT_HFP_HF_FLAG_USR_CLCC_PND, /* User-initiated AT+CLCC command is pending */
148150
/* Total number of flags - must be at the end of the enum */
149151
BT_HFP_HF_NUM_FLAGS,
150152
};

0 commit comments

Comments
 (0)