Skip to content

Commit 0d7eca6

Browse files
lylezhu2012kartben
authored andcommitted
Bluetooth: HFP_AG: Support HF Indicators
Add configuration `CONFIG_BT_HFP_AG_HF_INDICATORS` to enable feature HF Indicators. Add configuration `CONFIG_BT_HFP_AG_HF_INDICATOR_ENH_SAFETY` to support HF indicator `Enhanced Safety`. Add configuration `CONFIG_BT_HFP_AG_HF_INDICATOR_BATTERY` to support HF indicator `Remaining level of Battery`. Add function `bt_hfp_ag_hf_indicator` to activate/deactivate HF indicator. Optimize the handle of AT command `AT+BIND`. Handle AT command `AT+BIEV`. Add callback `hf_indicator_value` to notify the value of HF indicator. Signed-off-by: Lyle Zhu <[email protected]>
1 parent 01de855 commit 0d7eca6

File tree

4 files changed

+188
-17
lines changed

4 files changed

+188
-17
lines changed

include/zephyr/bluetooth/classic/hfp_ag.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ struct bt_hfp_ag_call;
7171
typedef int (*bt_hfp_ag_query_subscriber_func_t)(struct bt_hfp_ag *ag, char *number, uint8_t type,
7272
uint8_t service);
7373

74+
/* HF indicators */
75+
enum hfp_ag_hf_indicators {
76+
HFP_AG_ENHANCED_SAFETY_IND = 1, /* Enhanced Safety */
77+
HFP_AG_BATTERY_LEVEL_IND = 2, /* Remaining level of Battery */
78+
};
79+
7480
/** @brief HFP profile AG application callback */
7581
struct bt_hfp_ag_cb {
7682
/** HF AG connected callback to application
@@ -388,6 +394,20 @@ struct bt_hfp_ag_cb {
388394
* @return 0 in case of success or negative value in case of error.
389395
*/
390396
int (*subscriber_number)(struct bt_hfp_ag *ag, bt_hfp_ag_query_subscriber_func_t func);
397+
398+
/** HF indicator value callback
399+
*
400+
* If this callback is provided it will be called whenever the
401+
* AT command `AT+BIEV` is received.
402+
* If @kconfig{CONFIG_BT_HFP_AG_HF_INDICATORS} is not enabled,
403+
* the callback will not be notified.
404+
*
405+
* @param ag HFP AG object.
406+
* @param indicator HF indicator
407+
* @param value The value of specific indicator
408+
*/
409+
void (*hf_indicator_value)(struct bt_hfp_ag *ag, enum hfp_ag_hf_indicators indicator,
410+
uint32_t value);
391411
};
392412

393413
/** @brief Register HFP AG profile
@@ -747,6 +767,29 @@ int bt_hfp_ag_battery_level(struct bt_hfp_ag *ag, uint8_t level);
747767
*/
748768
int bt_hfp_ag_service_availability(struct bt_hfp_ag *ag, bool available);
749769

770+
/** @brief Activate/deactivate HF indicator
771+
*
772+
* It allows HF to issue the +BIND unsolicited result code to
773+
* activate/deactivate of the AG’s supported HF Indicators.
774+
* The indicator of supported indicators can be activated/deactivated
775+
* are defined in `enum hfp_ag_hf_indicators`.
776+
* `BT_HFP_AG_HF_INDICATOR_ENH_SAFETY` is used to support
777+
* `Enhanced Safety`. Only the configuration has been enabled, the
778+
* `indicator` can be HFP_AG_ENHANCED_SAFETY_IND.
779+
* `BT_HFP_AG_HF_INDICATOR_BATTERY` is used to support
780+
* `Remaining level of Battery`. Only the configuration has been
781+
* enabled, the `indicator` can be HFP_AG_BATTERY_LEVEL_IND.
782+
* If @kconfig{CONFIG_BT_HFP_HF_HF_INDICATORS} is not enabled, the error
783+
* `-ENOTSUP` will be returned if the function called.
784+
*
785+
* @param ag HFP AG object.
786+
* @param indicator The indicator of the AG’s supported HF Indicators.
787+
* @param enable enable/disable specific HF Indicator.
788+
*
789+
* @return 0 in case of success or negative value in case of error.
790+
*/
791+
int bt_hfp_ag_hf_indicator(struct bt_hfp_ag *ag, enum hfp_ag_hf_indicators indicator, bool enable);
792+
750793
#ifdef __cplusplus
751794
}
752795
#endif

subsys/bluetooth/host/classic/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,23 @@ config BT_HFP_AG_VOICE_TAG
396396
help
397397
This option enables Attach a phone number for a voice tag for HFP AG
398398

399+
config BT_HFP_AG_HF_INDICATORS
400+
bool "HF Indicators for HFP AG [EXPERIMENTAL]"
401+
help
402+
This option enables HF Indicators for HFP AG
403+
404+
config BT_HFP_AG_HF_INDICATOR_ENH_SAFETY
405+
bool "HF Indicator Enhanced Safety for HFP AG [EXPERIMENTAL]"
406+
select BT_HFP_AG_HF_INDICATORS
407+
help
408+
This option enables HF Indicator Enhanced Safety for HFP AG
409+
410+
config BT_HFP_AG_HF_INDICATOR_BATTERY
411+
bool "HF Indicator Battery level for HFP AG [EXPERIMENTAL]"
412+
select BT_HFP_AG_HF_INDICATORS
413+
help
414+
This option enables HF Indicator Battery level for HFP AG
415+
399416
endif # BT_HFP_AG
400417

401418
config BT_AVDTP

subsys/bluetooth/host/classic/hfp_ag.c

Lines changed: 119 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,6 +1508,7 @@ static int bt_hfp_ag_bind_handler(struct bt_hfp_ag *ag, struct net_buf *buf)
15081508
{
15091509
uint32_t indicator;
15101510
uint32_t hf_indicators = 0U;
1511+
uint32_t supported_indicators = 0U;
15111512
int err;
15121513
char *data;
15131514
uint32_t len;
@@ -1526,20 +1527,27 @@ static int bt_hfp_ag_bind_handler(struct bt_hfp_ag *ag, struct net_buf *buf)
15261527
}
15271528

15281529
hfp_ag_lock(ag);
1529-
hf_indicators = ag->hf_indicators_of_hf & ag->hf_indicators_of_ag;
1530+
hf_indicators = ag->hf_indicators;
1531+
supported_indicators = ag->hf_indicators_of_ag & ag->hf_indicators_of_hf;
15301532
hfp_ag_unlock(ag);
1531-
len = (sizeof(hf_indicators) * 8) > HFP_HF_IND_MAX ? HFP_HF_IND_MAX
1532-
: (sizeof(hf_indicators) * 8);
1533+
len = MIN(NUM_BITS(sizeof(supported_indicators)), HFP_HF_IND_MAX);
15331534
for (int i = 1; i < len; i++) {
1534-
if (BIT(i) & hf_indicators) {
1535-
err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BIND:%d,%d\r\n", i, 1);
1536-
} else {
1537-
err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BIND:%d,%d\r\n", i, 0);
1535+
bool enabled;
1536+
1537+
if (!(BIT(i) & supported_indicators)) {
1538+
continue;
15381539
}
1539-
if (err < 0) {
1540+
1541+
enabled = BIT(i) & hf_indicators;
1542+
err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BIND:%d,%d\r\n", i,
1543+
enabled ? 1 : 0);
1544+
if (err) {
15401545
return err;
15411546
}
1542-
if (hf_indicators == 0) {
1547+
1548+
supported_indicators &= ~BIT(i);
1549+
1550+
if (!supported_indicators) {
15431551
break;
15441552
}
15451553
}
@@ -1561,12 +1569,11 @@ static int bt_hfp_ag_bind_handler(struct bt_hfp_ag *ag, struct net_buf *buf)
15611569
hfp_ag_lock(ag);
15621570
hf_indicators = ag->hf_indicators_of_ag;
15631571
hfp_ag_unlock(ag);
1564-
len = (sizeof(hf_indicators) * 8) > HFP_HF_IND_MAX ? HFP_HF_IND_MAX
1565-
: (sizeof(hf_indicators) * 8);
1572+
len = MIN(NUM_BITS(sizeof(hf_indicators)), HFP_HF_IND_MAX);
15661573
for (int i = 1; (i < len) && (hf_indicators != 0); i++) {
15671574
if (BIT(i) & hf_indicators) {
15681575
int length = snprintk(
1569-
data, (char *)&ag->buffer[HF_MAX_BUF_LEN - 1] - data - 3,
1576+
data, (char *)&ag->buffer[HF_MAX_BUF_LEN - 1] - data - 2,
15701577
"%d", i);
15711578
data += length;
15721579
hf_indicators &= ~BIT(i);
@@ -1578,8 +1585,6 @@ static int bt_hfp_ag_bind_handler(struct bt_hfp_ag *ag, struct net_buf *buf)
15781585
}
15791586
*data = ')';
15801587
data++;
1581-
*data = '\r';
1582-
data++;
15831588
*data = '\0';
15841589
data++;
15851590

@@ -1599,7 +1604,7 @@ static int bt_hfp_ag_bind_handler(struct bt_hfp_ag *ag, struct net_buf *buf)
15991604
}
16001605
}
16011606

1602-
if (indicator < (sizeof(hf_indicators) * 8)) {
1607+
if (indicator < NUM_BITS(sizeof(hf_indicators))) {
16031608
hf_indicators |= BIT(indicator);
16041609
}
16051610
}
@@ -3089,6 +3094,47 @@ static int bt_hfp_ag_cnum_handler(struct bt_hfp_ag *ag, struct net_buf *buf)
30893094
return 0;
30903095
}
30913096

3097+
static int bt_hfp_ag_biev_handler(struct bt_hfp_ag *ag, struct net_buf *buf)
3098+
{
3099+
uint32_t indicator;
3100+
uint32_t value;
3101+
3102+
if (!is_char(buf, '=')) {
3103+
return -ENOTSUP;
3104+
}
3105+
3106+
if (get_number(buf, &indicator)) {
3107+
return -ENOTSUP;
3108+
}
3109+
3110+
if (!is_char(buf, ',')) {
3111+
return -ENOTSUP;
3112+
}
3113+
3114+
if (get_number(buf, &value)) {
3115+
return -ENOTSUP;
3116+
}
3117+
3118+
if (!is_char(buf, '\r')) {
3119+
return -ENOTSUP;
3120+
}
3121+
3122+
hfp_ag_lock(ag);
3123+
if (!(ag->hf_indicators_of_ag & BIT(indicator))) {
3124+
hfp_ag_unlock(ag);
3125+
return -ENOTSUP;
3126+
}
3127+
hfp_ag_unlock(ag);
3128+
3129+
#if defined(CONFIG_BT_HFP_AG_HF_INDICATORS)
3130+
if (bt_ag && bt_ag->hf_indicator_value) {
3131+
bt_ag->hf_indicator_value(ag, indicator, value);
3132+
}
3133+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATORS */
3134+
3135+
return 0;
3136+
}
3137+
30923138
static struct bt_hfp_ag_at_cmd_handler cmd_handlers[] = {
30933139
{"AT+BRSF", bt_hfp_ag_brsf_handler}, {"AT+BAC", bt_hfp_ag_bac_handler},
30943140
{"AT+CIND", bt_hfp_ag_cind_handler}, {"AT+CMER", bt_hfp_ag_cmer_handler},
@@ -3103,6 +3149,7 @@ static struct bt_hfp_ag_at_cmd_handler cmd_handlers[] = {
31033149
{"AT+BTRH", bt_hfp_ag_btrh_handler}, {"AT+CCWA", bt_hfp_ag_ccwa_handler},
31043150
{"AT+BVRA", bt_hfp_ag_bvra_handler}, {"AT+BINP", bt_hfp_ag_binp_handler},
31053151
{"AT+VTS", bt_hfp_ag_vts_handler}, {"AT+CNUM", bt_hfp_ag_cnum_handler},
3152+
{"AT+BIEV", bt_hfp_ag_biev_handler},
31063153
};
31073154

31083155
static void hfp_ag_connected(struct bt_rfcomm_dlc *dlc)
@@ -3492,6 +3539,17 @@ int bt_hfp_ag_connect(struct bt_conn *conn, struct bt_hfp_ag **ag, uint8_t chann
34923539
/* Set the supported features*/
34933540
_ag->ag_features = BT_HFP_AG_SUPPORTED_FEATURES;
34943541

3542+
/* Support HF indicators */
3543+
if (IS_ENABLED(CONFIG_BT_HFP_AG_HF_INDICATOR_ENH_SAFETY)) {
3544+
_ag->hf_indicators_of_ag |= BIT(HFP_HF_ENHANCED_SAFETY_IND);
3545+
}
3546+
3547+
if (IS_ENABLED(CONFIG_BT_HFP_AG_HF_INDICATOR_BATTERY)) {
3548+
_ag->hf_indicators_of_ag |= BIT(HFP_HF_BATTERY_LEVEL_IND);
3549+
}
3550+
3551+
_ag->hf_indicators = _ag->hf_indicators_of_ag;
3552+
34953553
/* If supported codec ids cannot be notified, disable codec negotiation. */
34963554
if (!(bt_ag && bt_ag->codec)) {
34973555
_ag->ag_features &= ~BT_HFP_AG_FEATURE_CODEC_NEG;
@@ -4730,3 +4788,49 @@ int bt_hfp_ag_service_availability(struct bt_hfp_ag *ag, bool available)
47304788

47314789
return err;
47324790
}
4791+
4792+
int bt_hfp_ag_hf_indicator(struct bt_hfp_ag *ag, enum hfp_ag_hf_indicators indicator, bool enable)
4793+
{
4794+
#if defined(CONFIG_BT_HFP_AG_HF_INDICATORS)
4795+
int err;
4796+
uint32_t supported_indicators;
4797+
4798+
LOG_DBG("");
4799+
4800+
if (ag == NULL) {
4801+
return -EINVAL;
4802+
}
4803+
4804+
hfp_ag_lock(ag);
4805+
if (ag->state != BT_HFP_CONNECTED) {
4806+
hfp_ag_unlock(ag);
4807+
return -ENOTCONN;
4808+
}
4809+
4810+
supported_indicators = ag->hf_indicators_of_ag & ag->hf_indicators_of_hf;
4811+
hfp_ag_unlock(ag);
4812+
4813+
if (!(supported_indicators & BIT(indicator))) {
4814+
LOG_ERR("Unsupported indicator %d", indicator);
4815+
return -ENOTSUP;
4816+
}
4817+
4818+
hfp_ag_lock(ag);
4819+
if (enable) {
4820+
ag->hf_indicators |= BIT(indicator);
4821+
} else {
4822+
ag->hf_indicators &= ~BIT(indicator);
4823+
}
4824+
hfp_ag_unlock(ag);
4825+
4826+
err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BIND:%d,%d\r\n",
4827+
indicator, enable ? 1 : 0);
4828+
if (err) {
4829+
LOG_ERR("Fail to update registration status of indicator:(%d)", err);
4830+
}
4831+
4832+
return err;
4833+
#else
4834+
return -ENOTSUP;
4835+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATORS */
4836+
}

subsys/bluetooth/host/classic/hfp_ag_internal.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@
9292
#define BT_HFP_AG_SDP_FEATURE_VOICE_TAG_ENABLE 0
9393
#endif /* CONFIG_BT_HFP_AG_VOICE_TAG */
9494

95+
#if defined(CONFIG_BT_HFP_AG_HF_INDICATORS)
96+
#define BT_HFP_AG_FEATURE_HF_IND_ENABLE BT_HFP_AG_FEATURE_HF_IND
97+
#else
98+
#define BT_HFP_AG_FEATURE_HF_IND_ENABLE 0
99+
#endif /* CONFIG_BT_HFP_HF_HF_INDICATORS */
100+
95101
/* HFP AG Supported features */
96102
#define BT_HFP_AG_SUPPORTED_FEATURES (\
97103
BT_HFP_AG_FEATURE_3WAY_CALL_ENABLE | \
@@ -104,7 +110,8 @@
104110
BT_HFP_AG_FEATURE_VOICE_RECG_ENABLE | \
105111
BT_HFP_AG_FEATURE_ENH_VOICE_RECG_ENABLE | \
106112
BT_HFP_AG_FEATURE_VOICE_RECG_TEXT_ENABLE | \
107-
BT_HFP_AG_FEATURE_VOICE_TAG_ENABLE)
113+
BT_HFP_AG_FEATURE_VOICE_TAG_ENABLE | \
114+
BT_HFP_AG_FEATURE_HF_IND_ENABLE)
108115

109116
/* HFP AG Supported features in SDP */
110117
#define BT_HFP_AG_SDP_SUPPORTED_FEATURES (\
@@ -221,7 +228,7 @@ struct bt_hfp_ag {
221228
/* HF Indicators */
222229
uint32_t hf_indicators_of_ag;
223230
uint32_t hf_indicators_of_hf;
224-
uint8_t hf_indicator_value[HFP_HF_IND_MAX];
231+
uint32_t hf_indicators;
225232

226233
/* operator */
227234
uint8_t mode;

0 commit comments

Comments
 (0)