Skip to content

Commit 488d577

Browse files
lylezhu2012kartben
authored andcommitted
Bluetooth: Classic: HFP_HF: Support ongoing calls before SLC
If the any value of Call, Call Setup, and Held Call indicators is not zero in the response of `AT+CIND?`, get all calls via `AT+CLCC`. Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
1 parent 09f3c31 commit 488d577

File tree

1 file changed

+164
-42
lines changed

1 file changed

+164
-42
lines changed

subsys/bluetooth/host/classic/hfp_hf.c

Lines changed: 164 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,41 @@ static void hf_call_state_update(struct bt_hfp_hf_call *call, int state)
592592
}
593593
}
594594

595+
static int get_using_call_count(struct bt_hfp_hf *hf)
596+
{
597+
struct bt_hfp_hf_call *call;
598+
int count = 0;
599+
600+
ARRAY_FOR_EACH(hf->calls, i) {
601+
call = &hf->calls[i];
602+
603+
if (atomic_test_bit(call->flags, BT_HFP_HF_CALL_IN_USING)) {
604+
count++;
605+
}
606+
}
607+
608+
return count;
609+
}
610+
611+
static struct bt_hfp_hf_call *get_new_call(struct bt_hfp_hf *hf)
612+
{
613+
struct bt_hfp_hf_call *call;
614+
615+
ARRAY_FOR_EACH(hf->calls, i) {
616+
call = &hf->calls[i];
617+
618+
if (atomic_test_and_set_bit(call->flags, BT_HFP_HF_CALL_IN_USING)) {
619+
continue;
620+
}
621+
622+
call->hf = hf;
623+
624+
return call;
625+
}
626+
627+
return NULL;
628+
}
629+
595630
#if defined(CONFIG_BT_HFP_HF_ECS)
596631
static void call_state_update(struct bt_hfp_hf_call *call, uint32_t status)
597632
{
@@ -645,6 +680,89 @@ static void call_state_update(struct bt_hfp_hf_call *call, uint32_t status)
645680
}
646681
}
647682

683+
static void new_call_state_update(struct bt_hfp_hf_call *call, bool incoming, uint32_t status)
684+
{
685+
switch (status) {
686+
case BT_HFP_CLCC_STATUS_ACTIVE:
687+
case BT_HFP_CLCC_STATUS_HELD:
688+
case BT_HFP_CLCC_STATUS_DIALING:
689+
case BT_HFP_CLCC_STATUS_ALERTING:
690+
case BT_HFP_CLCC_STATUS_INCOMING:
691+
case BT_HFP_CLCC_STATUS_WAITING:
692+
case BT_HFP_CLCC_STATUS_CALL_HELD_HOLD:
693+
if (incoming) {
694+
if (bt_hf->incoming) {
695+
bt_hf->incoming(call->hf, call);
696+
}
697+
} else {
698+
if (bt_hf->outgoing) {
699+
bt_hf->outgoing(call->hf, call);
700+
}
701+
}
702+
break;
703+
default:
704+
LOG_WRN("Invalid call status %u", status);
705+
free_call(call);
706+
return;
707+
}
708+
709+
switch (status) {
710+
case BT_HFP_CLCC_STATUS_ACTIVE:
711+
hf_call_state_update(call, BT_HFP_HF_CALL_STATE_ACTIVE);
712+
if (bt_hf->accept) {
713+
bt_hf->accept(call);
714+
}
715+
break;
716+
case BT_HFP_CLCC_STATUS_HELD:
717+
hf_call_state_update(call, BT_HFP_HF_CALL_STATE_HELD);
718+
if (bt_hf->held) {
719+
bt_hf->held(call);
720+
}
721+
break;
722+
case BT_HFP_CLCC_STATUS_DIALING:
723+
hf_call_state_update(call, BT_HFP_HF_CALL_STATE_OUTGOING);
724+
if (bt_hf->dialing) {
725+
bt_hf->dialing(call->hf, 0);
726+
}
727+
break;
728+
case BT_HFP_CLCC_STATUS_ALERTING:
729+
hf_call_state_update(call, BT_HFP_HF_CALL_STATE_ALERTING);
730+
if (bt_hf->remote_ringing) {
731+
bt_hf->remote_ringing(call);
732+
}
733+
break;
734+
case BT_HFP_CLCC_STATUS_INCOMING:
735+
case BT_HFP_CLCC_STATUS_WAITING:
736+
hf_call_state_update(call, BT_HFP_HF_CALL_STATE_WAITING);
737+
break;
738+
case BT_HFP_CLCC_STATUS_CALL_HELD_HOLD:
739+
atomic_set_bit(call->flags, BT_HFP_HF_CALL_INCOMING_HELD);
740+
hf_call_state_update(call, BT_HFP_HF_CALL_STATE_ACTIVE);
741+
if (bt_hf->incoming_held) {
742+
bt_hf->incoming_held(call);
743+
}
744+
break;
745+
default:
746+
break;
747+
}
748+
}
749+
750+
static void set_call_incoming_flag(struct bt_hfp_hf_call *call, bool incoming)
751+
{
752+
int call_count;
753+
754+
call_count = get_using_call_count(call->hf);
755+
if (call_count > 1) {
756+
if (incoming) {
757+
atomic_test_bit(call->flags, BT_HFP_HF_CALL_INCOMING_3WAY);
758+
} else {
759+
atomic_test_bit(call->flags, BT_HFP_HF_CALL_OUTGOING_3WAY);
760+
}
761+
} else {
762+
atomic_set_bit_to(call->flags, BT_HFP_HF_CALL_INCOMING, incoming);
763+
}
764+
}
765+
648766
static int clcc_handle(struct at_client *hf_at)
649767
{
650768
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
@@ -658,6 +776,7 @@ static int clcc_handle(struct at_client *hf_at)
658776
char *number = NULL;
659777
uint32_t type = 0;
660778
bool incoming = false;
779+
bool new_call = false;
661780

662781
err = at_get_number(hf_at, &index);
663782
if (err < 0) {
@@ -670,8 +789,12 @@ static int clcc_handle(struct at_client *hf_at)
670789
LOG_INF("Valid call with index %d not found", index);
671790
call = get_call_without_index(hf);
672791
if (!call) {
673-
LOG_INF("Not available call");
674-
return 0;
792+
call = get_new_call(hf);
793+
if (!call) {
794+
LOG_INF("Not available call");
795+
return 0;
796+
}
797+
new_call = true;
675798
}
676799
call->index = (uint8_t)index;
677800
}
@@ -684,12 +807,16 @@ static int clcc_handle(struct at_client *hf_at)
684807
return err;
685808
}
686809

810+
if (new_call) {
811+
set_call_incoming_flag(call, dir == BT_HFP_CLCC_DIR_INCOMING);
812+
}
813+
687814
if (atomic_test_bit(call->flags, BT_HFP_HF_CALL_INCOMING) ||
688-
atomic_test_bit(call->flags, BT_HFP_HF_CALL_INCOMING_3WAY)) {
815+
atomic_test_bit(call->flags, BT_HFP_HF_CALL_INCOMING_3WAY)) {
689816
incoming = true;
690817
}
691818

692-
if (incoming != !!dir) {
819+
if (incoming != (dir == BT_HFP_CLCC_DIR_INCOMING)) {
693820
LOG_ERR("Call dir of HF is not aligned with AG");
694821
return 0;
695822
}
@@ -718,7 +845,11 @@ static int clcc_handle(struct at_client *hf_at)
718845
(void)at_get_number(hf_at, &type);
719846
}
720847

721-
call_state_update(call, status);
848+
if (new_call) {
849+
new_call_state_update(call, incoming, status);
850+
} else {
851+
call_state_update(call, status);
852+
}
722853

723854
LOG_DBG("CLCC idx %d dir %d status %d mode %d mpty %d number %s type %d",
724855
index, dir, status, mode, mpty, number, type);
@@ -922,43 +1053,6 @@ static void bt_hf_deferred_work(struct k_work *work)
9221053
hf_query_current_calls(hf);
9231054
}
9241055

925-
static struct bt_hfp_hf_call *get_new_call(struct bt_hfp_hf *hf)
926-
{
927-
struct bt_hfp_hf_call *call;
928-
929-
for (size_t index = 0; index < ARRAY_SIZE(hf->calls); index++) {
930-
call = &hf->calls[index];
931-
932-
if (atomic_test_and_set_bit(call->flags, BT_HFP_HF_CALL_IN_USING)) {
933-
continue;
934-
}
935-
936-
call->hf = hf;
937-
938-
return call;
939-
}
940-
941-
return NULL;
942-
}
943-
944-
static int get_using_call_count(struct bt_hfp_hf *hf)
945-
{
946-
struct bt_hfp_hf_call *call;
947-
int count = 0;
948-
949-
for (size_t index = 0; index < ARRAY_SIZE(hf->calls); index++) {
950-
call = &hf->calls[index];
951-
952-
if (!atomic_test_bit(call->flags, BT_HFP_HF_CALL_IN_USING)) {
953-
continue;
954-
}
955-
956-
count++;
957-
}
958-
959-
return count;
960-
}
961-
9621056
static void set_all_calls_held_state(struct bt_hfp_hf *hf, bool held)
9631057
{
9641058
struct bt_hfp_hf_call *call;
@@ -992,6 +1086,10 @@ static void ag_indicator_handle_call(struct bt_hfp_hf *hf, uint32_t value)
9921086

9931087
LOG_DBG("call %d", value);
9941088

1089+
if (value != 0) {
1090+
atomic_set_bit(hf->flags, BT_HFP_HF_FLAG_CLCC_PENDING);
1091+
}
1092+
9951093
if (value) {
9961094
call = get_dialing_call(hf);
9971095
if (!call) {
@@ -1050,6 +1148,10 @@ static void ag_indicator_handle_call_setup(struct bt_hfp_hf *hf, uint32_t value)
10501148

10511149
LOG_DBG("call setup %d", value);
10521150

1151+
if (value != BT_HFP_CALL_SETUP_NONE) {
1152+
atomic_set_bit(hf->flags, BT_HFP_HF_FLAG_CLCC_PENDING);
1153+
}
1154+
10531155
switch (value) {
10541156
case BT_HFP_CALL_SETUP_NONE:
10551157
if (call_count == 1) {
@@ -1083,6 +1185,11 @@ static void ag_indicator_handle_call_setup(struct bt_hfp_hf *hf, uint32_t value)
10831185
case BT_HFP_CALL_SETUP_INCOMING:
10841186
call = get_call_with_state(hf, BT_HFP_HF_CALL_STATE_INCOMING);
10851187
if (!call) {
1188+
if (!atomic_test_bit(hf->flags, BT_HFP_HF_FLAG_CONNECTED)) {
1189+
LOG_INF("SLC is not connected. Will get call status via AT+CLCC");
1190+
break;
1191+
}
1192+
10861193
call = get_new_call(hf);
10871194
if (!call) {
10881195
break;
@@ -1103,6 +1210,11 @@ static void ag_indicator_handle_call_setup(struct bt_hfp_hf *hf, uint32_t value)
11031210
case BT_HFP_CALL_SETUP_OUTGOING:
11041211
call = get_call_with_state(hf, BT_HFP_HF_CALL_STATE_OUTGOING);
11051212
if (!call) {
1213+
if (!atomic_test_bit(hf->flags, BT_HFP_HF_FLAG_CONNECTED)) {
1214+
LOG_INF("SLC is not connected. Will get call status via AT+CLCC");
1215+
break;
1216+
}
1217+
11061218
call = get_new_call(hf);
11071219
if (!call) {
11081220
break;
@@ -1141,6 +1253,10 @@ static void ag_indicator_handle_call_held(struct bt_hfp_hf *hf, uint32_t value)
11411253

11421254
LOG_DBG("call setup %d", value);
11431255

1256+
if (value != BT_HFP_CALL_HELD_NONE) {
1257+
atomic_set_bit(hf->flags, BT_HFP_HF_FLAG_CLCC_PENDING);
1258+
}
1259+
11441260
switch (value) {
11451261
case BT_HFP_CALL_HELD_NONE:
11461262
set_all_calls_held_state(hf, false);
@@ -1955,6 +2071,12 @@ static int at_cmd_init_start(struct bt_hfp_hf *hf)
19552071
LOG_WRN("Send next AT command");
19562072
hf->cmd_init_seq++;
19572073
}
2074+
2075+
if ((ARRAY_SIZE(cmd_init_list) <= hf->cmd_init_seq) &&
2076+
atomic_test_and_clear_bit(hf->flags, BT_HFP_HF_FLAG_CLCC_PENDING)) {
2077+
k_work_reschedule(&hf->deferred_work, K_MSEC(HF_ENHANCED_CALL_STATUS_TIMEOUT));
2078+
}
2079+
19582080
return err;
19592081
}
19602082

0 commit comments

Comments
 (0)