Skip to content

Commit 01de855

Browse files
lylezhu2012kartben
authored andcommitted
Bluetooth: HFP_HF: Support HF Indicators
Add configuration `CONFIG_BT_HFP_HF_HF_INDICATORS` to enable feature HF Indicators. Add configuration `CONFIG_BT_HFP_HF_HF_INDICATOR_ENH_SAFETY` to support HF indicator `Enhanced Safety`. Add configuration `CONFIG_BT_HFP_HF_HF_INDICATOR_BATTERY` to support HF indicator `Remaining level of Battery`. Add function `bt_hfp_hf_enhanced_safety` to transfer enhanced safety status. Add function `bt_hfp_hf_battery` to transfer Remaining level of Battery. Send AT command to notify AG the supported HF indicators of HF in SLC initialization sequence. Send AT command to get the supported HF indicators of AG in SLC initialization sequence. Send AT command to get the enabled/disabled state of generic status indicators from AG in SLC initialization sequence. Handle unsolicited result code `+BIND`. Signed-off-by: Lyle Zhu <[email protected]>
1 parent 0412244 commit 01de855

File tree

5 files changed

+286
-8
lines changed

5 files changed

+286
-8
lines changed

include/zephyr/bluetooth/classic/hfp_hf.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,32 @@ enum hfp_hf_ag_indicators {
877877
*/
878878
int bt_hfp_hf_indicator_status(struct bt_hfp_hf *hf, uint8_t status);
879879

880+
/** @brief Handsfree HF enable/disable enhanced safety
881+
*
882+
* It allows HF to transfer of HF indicator enhanced safety value.
883+
* If @kconfig{CONFIG_BT_HFP_HF_HF_INDICATOR_ENH_SAFETY} is not enabled,
884+
* the error `-ENOTSUP` will be returned if the function called.
885+
*
886+
* @param hf HFP HF object.
887+
* @param enable The enhanced safety is enabled/disabled.
888+
*
889+
* @return 0 in case of success or negative value in case of error.
890+
*/
891+
int bt_hfp_hf_enhanced_safety(struct bt_hfp_hf *hf, bool enable);
892+
893+
/** @brief Handsfree HF remaining battery level
894+
*
895+
* It allows HF to transfer of HF indicator remaining battery level value.
896+
* If @kconfig{CONFIG_BT_HFP_HF_HF_INDICATOR_BATTERY} is not enabled,
897+
* the error `-ENOTSUP` will be returned if the function called.
898+
*
899+
* @param hf HFP HF object.
900+
* @param level The remaining battery level.
901+
*
902+
* @return 0 in case of success or negative value in case of error.
903+
*/
904+
int bt_hfp_hf_battery(struct bt_hfp_hf *hf, uint8_t level);
905+
880906
#ifdef __cplusplus
881907
}
882908
#endif

subsys/bluetooth/host/classic/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,23 @@ config BT_HFP_HF_VOICE_RECG_TEXT
251251
help
252252
This option enables Voice Recognition Text for HFP HF
253253

254+
config BT_HFP_HF_HF_INDICATORS
255+
bool "HF Indicators for HFP HF [EXPERIMENTAL]"
256+
help
257+
This option enables HF Indicators for HFP HF
258+
259+
config BT_HFP_HF_HF_INDICATOR_ENH_SAFETY
260+
bool "HF Indicator Enhanced Safety for HFP HF [EXPERIMENTAL]"
261+
select BT_HFP_HF_HF_INDICATORS
262+
help
263+
This option enables HF Indicator Enhanced Safety for HFP HF
264+
265+
config BT_HFP_HF_HF_INDICATOR_BATTERY
266+
bool "HF Indicator Battery level for HFP HF [EXPERIMENTAL]"
267+
select BT_HFP_HF_HF_INDICATORS
268+
help
269+
This option enables HF Indicator Battery level for HFP HF
270+
254271
endif # BT_HFP_HF
255272

256273
if BT_HFP_AG

subsys/bluetooth/host/classic/hfp_ag_internal.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,6 @@ enum {
149149
BT_HFP_AG_CALL_NUM_FLAGS,
150150
};
151151

152-
/* HFP HF Indicators */
153-
enum {
154-
HFP_HF_ENHANCED_SAFETY_IND = 1, /* Enhanced Safety */
155-
HFP_HF_BATTERY_LEVEL_IND = 2, /* Remaining level of Battery */
156-
HFP_HF_IND_MAX
157-
};
158-
159152
typedef enum __packed {
160153
/** Session disconnected */
161154
BT_HFP_DISCONNECTED,

subsys/bluetooth/host/classic/hfp_hf.c

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,6 +1642,66 @@ static int cnum_handle(struct at_client *hf_at)
16421642
return 0;
16431643
}
16441644

1645+
#if defined(CONFIG_BT_HFP_HF_HF_INDICATORS)
1646+
static int bind_handle(struct at_client *hf_at)
1647+
{
1648+
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
1649+
int err;
1650+
uint32_t index;
1651+
uint32_t value;
1652+
uint32_t ind = 0;
1653+
uint32_t ind_enable = hf->ind_enable;
1654+
1655+
err = at_open_list(hf_at);
1656+
if (!err) {
1657+
/* It is a list. */
1658+
while (at_has_next_list(hf_at)) {
1659+
err = at_get_number(hf_at, &index);
1660+
if (err) {
1661+
LOG_INF("Cannot get indicator");
1662+
goto failed;
1663+
}
1664+
1665+
ind |= BIT(index);
1666+
}
1667+
1668+
if (at_close_list(hf_at) < 0) {
1669+
LOG_ERR("Could not get close list");
1670+
goto failed;
1671+
}
1672+
1673+
hf->ag_ind = ind;
1674+
return 0;
1675+
}
1676+
1677+
err = at_get_number(hf_at, &index);
1678+
if (err) {
1679+
LOG_INF("Cannot get indicator");
1680+
goto failed;
1681+
}
1682+
1683+
err = at_get_number(hf_at, &value);
1684+
if (err) {
1685+
LOG_INF("Cannot get status");
1686+
goto failed;
1687+
}
1688+
1689+
if (!value) {
1690+
ind_enable &= ~BIT(index);
1691+
} else {
1692+
ind_enable |= BIT(index);
1693+
}
1694+
1695+
hf->ind_enable = ind_enable;
1696+
return 0;
1697+
1698+
failed:
1699+
LOG_ERR("Error on AT+BIND response");
1700+
hf_slc_error(hf_at);
1701+
return -EINVAL;
1702+
}
1703+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATORS */
1704+
16451705
static const struct unsolicited {
16461706
const char *cmd;
16471707
enum at_cmd_type type;
@@ -1672,6 +1732,9 @@ static const struct unsolicited {
16721732
{ "BVRA", AT_CMD_TYPE_UNSOLICITED, bvra_handle },
16731733
#endif /* CONFIG_BT_HFP_HF_VOICE_RECG */
16741734
{ "CNUM", AT_CMD_TYPE_UNSOLICITED, cnum_handle },
1735+
#if defined(CONFIG_BT_HFP_HF_HF_INDICATORS)
1736+
{ "BIND", AT_CMD_TYPE_UNSOLICITED, bind_handle },
1737+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATORS */
16751738
};
16761739

16771740
static const struct unsolicited *hfp_hf_unsol_lookup(struct at_client *hf_at)
@@ -1913,6 +1976,51 @@ static void slc_completed(struct at_client *hf_at)
19131976
}
19141977
}
19151978

1979+
#if defined(CONFIG_BT_HFP_HF_HF_INDICATORS)
1980+
static int send_at_bind_status(struct bt_hfp_hf *hf, at_finish_cb_t cb)
1981+
{
1982+
return hfp_hf_send_cmd(hf, NULL, cb, "AT+BIND?");
1983+
}
1984+
1985+
static int send_at_bind_hf_supported(struct bt_hfp_hf *hf, at_finish_cb_t cb)
1986+
{
1987+
char buffer[4];
1988+
char *bind;
1989+
1990+
hf->hf_ind = 0;
1991+
1992+
bind = &buffer[0];
1993+
if (IS_ENABLED(CONFIG_BT_HFP_HF_HF_INDICATOR_ENH_SAFETY)) {
1994+
*bind = '0' + HFP_HF_ENHANCED_SAFETY_IND;
1995+
bind++;
1996+
*bind = ',';
1997+
bind++;
1998+
hf->hf_ind |= BIT(HFP_HF_ENHANCED_SAFETY_IND);
1999+
}
2000+
2001+
if (IS_ENABLED(CONFIG_BT_HFP_HF_HF_INDICATOR_BATTERY)) {
2002+
*bind = '0' + HFP_HF_BATTERY_LEVEL_IND;
2003+
bind++;
2004+
*bind = ',';
2005+
bind++;
2006+
hf->hf_ind |= BIT(HFP_HF_BATTERY_LEVEL_IND);
2007+
}
2008+
2009+
if (bind <= &buffer[0]) {
2010+
return -EINVAL;
2011+
}
2012+
2013+
bind--;
2014+
*bind = '\0';
2015+
return hfp_hf_send_cmd(hf, NULL, cb, "AT+BIND=%s", buffer);
2016+
}
2017+
2018+
static int send_at_bind_supported(struct bt_hfp_hf *hf, at_finish_cb_t cb)
2019+
{
2020+
return hfp_hf_send_cmd(hf, NULL, cb, "AT+BIND=?");
2021+
}
2022+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATORS */
2023+
19162024
#if defined(CONFIG_BT_HFP_HF_3WAY_CALL)
19172025
static int send_at_chld_supported(struct bt_hfp_hf *hf, at_finish_cb_t cb)
19182026
{
@@ -1989,6 +2097,11 @@ static struct slc_init
19892097
#if defined(CONFIG_BT_HFP_HF_3WAY_CALL)
19902098
{send_at_chld_supported, true, BT_HFP_AG_FEATURE_3WAY_CALL},
19912099
#endif /* CONFIG_BT_HFP_HF_3WAY_CALL */
2100+
#if defined(CONFIG_BT_HFP_HF_HF_INDICATORS)
2101+
{send_at_bind_hf_supported, true, BT_HFP_AG_FEATURE_HF_IND},
2102+
{send_at_bind_supported, true, BT_HFP_AG_FEATURE_HF_IND},
2103+
{send_at_bind_status, true, BT_HFP_AG_FEATURE_HF_IND},
2104+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATORS */
19922105
};
19932106

19942107
static int slc_init_start(struct bt_hfp_hf *hf);
@@ -2512,6 +2625,115 @@ int bt_hfp_hf_indicator_status(struct bt_hfp_hf *hf, uint8_t status)
25122625
return err;
25132626
}
25142627

2628+
#if defined(CONFIG_BT_HFP_HF_HF_INDICATOR_ENH_SAFETY)
2629+
static int biev_enh_safety_finish(struct at_client *hf_at,
2630+
enum at_result result, enum at_cme cme_err)
2631+
{
2632+
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
2633+
2634+
LOG_DBG("AT+BIEV (result %d) on %p", result, hf);
2635+
2636+
return 0;
2637+
}
2638+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATOR_ENH_SAFETY */
2639+
2640+
int bt_hfp_hf_enhanced_safety(struct bt_hfp_hf *hf, bool enable)
2641+
{
2642+
#if defined(CONFIG_BT_HFP_HF_HF_INDICATOR_ENH_SAFETY)
2643+
int err;
2644+
2645+
LOG_DBG("");
2646+
2647+
if (!hf) {
2648+
LOG_ERR("No HF connection found");
2649+
return -ENOTCONN;
2650+
}
2651+
2652+
if (!atomic_test_bit(hf->flags, BT_HFP_HF_FLAG_CONNECTED)) {
2653+
LOG_ERR("SLC is not established on %p", hf);
2654+
return -ENOTCONN;
2655+
}
2656+
2657+
if (!((hf->hf_ind & BIT(HFP_HF_ENHANCED_SAFETY_IND)) &&
2658+
(hf->ag_ind & BIT(HFP_HF_ENHANCED_SAFETY_IND)))) {
2659+
LOG_ERR("The indicator is unsupported");
2660+
return -ENOTSUP;
2661+
}
2662+
2663+
if (!(hf->ind_enable & BIT(HFP_HF_ENHANCED_SAFETY_IND))) {
2664+
LOG_ERR("The indicator is disabled");
2665+
return -EINVAL;
2666+
}
2667+
2668+
err = hfp_hf_send_cmd(hf, NULL, biev_enh_safety_finish, "AT+BIEV=%d,%d",
2669+
HFP_HF_ENHANCED_SAFETY_IND, enable ? 1 : 0);
2670+
if (err < 0) {
2671+
LOG_ERR("Fail to transfer enhanced safety value on %p", hf);
2672+
}
2673+
2674+
return err;
2675+
#else
2676+
return -ENOTSUP;
2677+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATOR_ENH_SAFETY */
2678+
}
2679+
2680+
#if defined(CONFIG_BT_HFP_HF_HF_INDICATOR_BATTERY)
2681+
static int biev_battery_finish(struct at_client *hf_at,
2682+
enum at_result result, enum at_cme cme_err)
2683+
{
2684+
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
2685+
2686+
LOG_DBG("AT+BIEV (result %d) on %p", result, hf);
2687+
2688+
return 0;
2689+
}
2690+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATOR_BATTERY */
2691+
2692+
int bt_hfp_hf_battery(struct bt_hfp_hf *hf, uint8_t level)
2693+
{
2694+
#if defined(CONFIG_BT_HFP_HF_HF_INDICATOR_BATTERY)
2695+
int err;
2696+
2697+
LOG_DBG("");
2698+
2699+
if (!hf) {
2700+
LOG_ERR("No HF connection found");
2701+
return -ENOTCONN;
2702+
}
2703+
2704+
if (!atomic_test_bit(hf->flags, BT_HFP_HF_FLAG_CONNECTED)) {
2705+
LOG_ERR("SLC is not established on %p", hf);
2706+
return -ENOTCONN;
2707+
}
2708+
2709+
if (!((hf->hf_ind & BIT(HFP_HF_BATTERY_LEVEL_IND)) &&
2710+
(hf->ag_ind & BIT(HFP_HF_BATTERY_LEVEL_IND)))) {
2711+
LOG_ERR("The indicator is unsupported");
2712+
return -ENOTSUP;
2713+
}
2714+
2715+
if (!(hf->ind_enable & BIT(HFP_HF_BATTERY_LEVEL_IND))) {
2716+
LOG_ERR("The indicator is disabled");
2717+
return -EINVAL;
2718+
}
2719+
2720+
if (!IS_VALID_BATTERY_LEVEL(level)) {
2721+
LOG_ERR("Invalid battery level %d", level);
2722+
return -EINVAL;
2723+
}
2724+
2725+
err = hfp_hf_send_cmd(hf, NULL, biev_battery_finish, "AT+BIEV=%d,%d",
2726+
HFP_HF_BATTERY_LEVEL_IND, level);
2727+
if (err < 0) {
2728+
LOG_ERR("Fail to transfer remaining battery level on %p", hf);
2729+
}
2730+
2731+
return err;
2732+
#else
2733+
return -ENOTSUP;
2734+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATOR_BATTERY */
2735+
}
2736+
25152737
static int ata_finish(struct at_client *hf_at, enum at_result result,
25162738
enum at_cme cme_err)
25172739
{

subsys/bluetooth/host/classic/hfp_internal.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@
126126
#define BT_HFP_HF_SDP_FEATURE_VOICE_RECG_TEXT_ENABLE 0
127127
#endif /* CONFIG_BT_HFP_HF_VOICE_RECG_TEXT */
128128

129+
#if defined(CONFIG_BT_HFP_HF_HF_INDICATORS)
130+
#define BT_HFP_HF_FEATURE_HF_IND_ENABLE BT_HFP_HF_FEATURE_HF_IND
131+
#else
132+
#define BT_HFP_HF_FEATURE_HF_IND_ENABLE 0
133+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATORS */
134+
129135
/* HFP HF Supported features */
130136
#define BT_HFP_HF_SUPPORTED_FEATURES (\
131137
BT_HFP_HF_FEATURE_CLI_ENABLE | \
@@ -137,7 +143,8 @@
137143
BT_HFP_HF_FEATURE_ECC_ENABLE | \
138144
BT_HFP_HF_FEATURE_VOICE_RECG_ENABLE | \
139145
BT_HFP_HF_FEATURE_ENH_VOICE_RECG_ENABLE | \
140-
BT_HFP_HF_FEATURE_VOICE_RECG_TEXT_ENABLE)
146+
BT_HFP_HF_FEATURE_VOICE_RECG_TEXT_ENABLE | \
147+
BT_HFP_HF_FEATURE_HF_IND_ENABLE)
141148

142149
/* HFP HF Supported features in SDP */
143150
#define BT_HFP_HF_SDP_SUPPORTED_FEATURES (\
@@ -245,6 +252,10 @@ struct bt_hfp_hf {
245252
uint8_t vgs;
246253
int8_t ind_table[HF_MAX_AG_INDICATORS];
247254

255+
uint32_t hf_ind;
256+
uint32_t ag_ind;
257+
uint32_t ind_enable;
258+
248259
/* AT command initialization indicator */
249260
uint8_t cmd_init_seq;
250261

@@ -350,3 +361,12 @@ struct bt_hfp_hf {
350361

351362
#define IS_VALID_DTMF(c) ((((c) >= '0') && ((c) <= '9')) || \
352363
(((c) >= 'A') && ((c) <= 'D')) || ((c) == '#') || ((c) == '*'))
364+
365+
/* HFP HF Indicators */
366+
enum {
367+
HFP_HF_ENHANCED_SAFETY_IND = 1, /* Enhanced Safety */
368+
HFP_HF_BATTERY_LEVEL_IND = 2, /* Remaining level of Battery */
369+
HFP_HF_IND_MAX
370+
};
371+
372+
#define IS_VALID_BATTERY_LEVEL(level) (((level) >= 0) && ((level) <= 100))

0 commit comments

Comments
 (0)