Skip to content

Commit 2314aa2

Browse files
MariuszSkamracarlescufi
authored andcommitted
Bluetooth: has: Add Preset Changed operation support
This extends implementation with sending Preset Changed notification/indication when preset changes its availability or is added or deleted. Signed-off-by: Mariusz Skamra <[email protected]>
1 parent a5d6aaf commit 2314aa2

File tree

3 files changed

+165
-1
lines changed

3 files changed

+165
-1
lines changed

include/zephyr/bluetooth/audio/has.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,30 @@ int bt_has_preset_register(const struct bt_has_preset_register_param *param);
181181
*/
182182
int bt_has_preset_unregister(uint8_t index);
183183

184+
/**
185+
* @brief Set the preset as available.
186+
*
187+
* Set the @ref BT_HAS_PROP_AVAILABLE property bit. This will notify preset availability
188+
* to peer devices. Only available preset can be selected as active preset.
189+
*
190+
* @param index The index of preset that's became available.
191+
*
192+
* @return 0 in case of success or negative value in case of error.
193+
*/
194+
int bt_has_preset_available(uint8_t index);
195+
196+
/**
197+
* @brief Set the preset as unavailable.
198+
*
199+
* Clear the @ref BT_HAS_PROP_AVAILABLE property bit. This will notify preset availability
200+
* to peer devices. Unavailable preset cannot be selected as active preset.
201+
*
202+
* @param index The index of preset that's became unavailable.
203+
*
204+
* @return 0 in case of success or negative value in case of error.
205+
*/
206+
int bt_has_preset_unavailable(uint8_t index);
207+
184208
enum {
185209
BT_HAS_PRESET_ITER_STOP = 0,
186210
BT_HAS_PRESET_ITER_CONTINUE,

subsys/bluetooth/audio/has.c

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,33 @@ static int control_point_send(struct has_client *client, struct net_buf_simple *
326326
return -ECANCELED;
327327
}
328328

329+
static int control_point_send_all(struct net_buf_simple *buf)
330+
{
331+
int result = 0;
332+
333+
for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) {
334+
struct has_client *client = &has_client_list[i];
335+
int err;
336+
337+
if (!client->conn) {
338+
continue;
339+
}
340+
341+
if (!bt_gatt_is_subscribed(client->conn, PRESET_CONTROL_POINT_ATTR,
342+
BT_GATT_CCC_NOTIFY | BT_GATT_CCC_INDICATE)) {
343+
continue;
344+
}
345+
346+
err = control_point_send(client, buf);
347+
if (err) {
348+
result = err;
349+
/* continue anyway */
350+
}
351+
}
352+
353+
return result;
354+
}
355+
329356
static int bt_has_cp_read_preset_rsp(struct has_client *client, const struct has_preset *preset,
330357
bool is_last)
331358
{
@@ -393,6 +420,54 @@ static void process_control_point_work(struct k_work *work)
393420
}
394421
}
395422

423+
static uint8_t get_prev_preset_index(struct has_preset *preset)
424+
{
425+
const struct has_preset *prev = NULL;
426+
427+
for (size_t i = 0; i < ARRAY_SIZE(has_preset_list); i++) {
428+
const struct has_preset *tmp = &has_preset_list[i];
429+
430+
if (tmp->index == BT_HAS_PRESET_INDEX_NONE || tmp == preset) {
431+
break;
432+
}
433+
434+
prev = tmp;
435+
}
436+
437+
return prev ? prev->index : BT_HAS_PRESET_INDEX_NONE;
438+
}
439+
440+
static void preset_changed_prepare(struct net_buf_simple *buf, uint8_t change_id, uint8_t is_last)
441+
{
442+
struct bt_has_cp_hdr *hdr;
443+
struct bt_has_cp_preset_changed *preset_changed;
444+
445+
hdr = net_buf_simple_add(buf, sizeof(*hdr));
446+
hdr->opcode = BT_HAS_OP_PRESET_CHANGED;
447+
preset_changed = net_buf_simple_add(buf, sizeof(*preset_changed));
448+
preset_changed->change_id = change_id;
449+
preset_changed->is_last = is_last;
450+
}
451+
452+
static int bt_has_cp_generic_update(struct has_preset *preset, uint8_t is_last)
453+
{
454+
struct bt_has_cp_generic_update *generic_update;
455+
456+
NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
457+
sizeof(struct bt_has_cp_preset_changed) +
458+
sizeof(struct bt_has_cp_generic_update) + BT_HAS_PRESET_NAME_MAX);
459+
460+
preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_GENERIC_UPDATE, is_last);
461+
462+
generic_update = net_buf_simple_add(&buf, sizeof(*generic_update));
463+
generic_update->prev_index = get_prev_preset_index(preset);
464+
generic_update->index = preset->index;
465+
generic_update->properties = preset->properties;
466+
net_buf_simple_add_mem(&buf, preset->name, strlen(preset->name));
467+
468+
return control_point_send_all(&buf);
469+
}
470+
396471
static uint8_t handle_read_preset_req(struct bt_conn *conn, struct net_buf_simple *buf)
397472
{
398473
const struct bt_has_cp_read_presets_req *req;
@@ -524,13 +599,16 @@ int bt_has_preset_register(const struct bt_has_preset_register_param *param)
524599
return -ENOMEM;
525600
}
526601

527-
return 0;
602+
return bt_has_cp_generic_update(preset, BT_HAS_IS_LAST);
528603
}
529604

530605
int bt_has_preset_unregister(uint8_t index)
531606
{
532607
struct has_preset *preset = NULL;
533608

609+
NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
610+
sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t));
611+
534612
CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) {
535613
BT_ERR("index is invalid");
536614
return -EINVAL;
@@ -541,8 +619,61 @@ int bt_has_preset_unregister(uint8_t index)
541619
return -ENOENT;
542620
}
543621

622+
preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_DELETED, BT_HAS_IS_LAST);
623+
net_buf_simple_add_u8(&buf, preset->index);
624+
544625
preset_free(preset);
545626

627+
return control_point_send_all(&buf);
628+
}
629+
630+
int bt_has_preset_available(uint8_t index)
631+
{
632+
struct has_preset *preset = NULL;
633+
634+
CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) {
635+
BT_ERR("index is invalid");
636+
return -EINVAL;
637+
}
638+
639+
/* toggle property bit if needed */
640+
if (!(preset->properties & BT_HAS_PROP_AVAILABLE)) {
641+
NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
642+
sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t));
643+
644+
preset->properties ^= BT_HAS_PROP_AVAILABLE;
645+
646+
preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_AVAILABLE, BT_HAS_IS_LAST);
647+
net_buf_simple_add_u8(&buf, preset->index);
648+
649+
return control_point_send_all(&buf);
650+
}
651+
652+
return 0;
653+
}
654+
655+
int bt_has_preset_unavailable(uint8_t index)
656+
{
657+
struct has_preset *preset = NULL;
658+
659+
CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) {
660+
BT_ERR("index is invalid");
661+
return -EINVAL;
662+
}
663+
664+
/* toggle property bit if needed */
665+
if (preset->properties & BT_HAS_PROP_AVAILABLE) {
666+
NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
667+
sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t));
668+
669+
preset->properties ^= BT_HAS_PROP_AVAILABLE;
670+
671+
preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_UNAVAILABLE, BT_HAS_IS_LAST);
672+
net_buf_simple_add_u8(&buf, preset->index);
673+
674+
return control_point_send_all(&buf);
675+
}
676+
546677
return 0;
547678
}
548679

subsys/bluetooth/audio/has_internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
#define BT_HAS_CHANGE_ID_PRESET_AVAILABLE 0x02
4545
#define BT_HAS_CHANGE_ID_PRESET_UNAVAILABLE 0x03
4646

47+
#define BT_HAS_IS_LAST 0x01
48+
4749
struct bt_has {
4850
/** Hearing Aid Features value */
4951
uint8_t features;
@@ -74,6 +76,13 @@ struct bt_has_cp_preset_changed {
7476
uint8_t is_last;
7577
} __packed;
7678

79+
struct bt_has_cp_generic_update {
80+
uint8_t prev_index;
81+
uint8_t index;
82+
uint8_t properties;
83+
uint8_t name[0];
84+
} __packed;
85+
7786
struct bt_has_cp_write_preset_name {
7887
uint8_t index;
7988
uint8_t name[0];

0 commit comments

Comments
 (0)