1 /* Bluetooth vol_ctlr Client - Volume Offset Control Client */
2
3 /*
4 * Copyright (c) 2020 Bose Corporation
5 * Copyright (c) 2020-2022 Nordic Semiconductor ASA
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <errno.h>
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <string.h>
15
16 #include <zephyr/autoconf.h>
17 #include <zephyr/bluetooth/att.h>
18 #include <zephyr/bluetooth/audio/aics.h>
19 #include <zephyr/bluetooth/audio/vcp.h>
20 #include <zephyr/bluetooth/audio/vocs.h>
21 #include <zephyr/bluetooth/bluetooth.h>
22 #include <zephyr/bluetooth/conn.h>
23 #include <zephyr/bluetooth/gatt.h>
24 #include <zephyr/bluetooth/uuid.h>
25 #include <zephyr/device.h>
26 #include <zephyr/init.h>
27 #include <zephyr/kernel.h>
28 #include <zephyr/logging/log.h>
29 #include <zephyr/sys/__assert.h>
30 #include <zephyr/sys/atomic.h>
31 #include <zephyr/sys/check.h>
32 #include <zephyr/sys/slist.h>
33 #include <zephyr/sys/util.h>
34 #include <zephyr/types.h>
35
36 #include "common/bt_str.h"
37 #include "vcp_internal.h"
38
39 LOG_MODULE_REGISTER(bt_vcp_vol_ctlr, CONFIG_BT_VCP_VOL_CTLR_LOG_LEVEL);
40
41 /* Callback functions */
42 static sys_slist_t vcp_vol_ctlr_cbs = SYS_SLIST_STATIC_INIT(&vcp_vol_ctlr_cbs);
43
44 static struct bt_vcp_vol_ctlr vol_ctlr_insts[CONFIG_BT_MAX_CONN];
45 static int write_common_vcs_cp(struct bt_vcp_vol_ctlr *vol_ctlr);
46 static int write_set_vol_cp(struct bt_vcp_vol_ctlr *vol_ctlr);
47
vol_ctlr_get_by_conn(const struct bt_conn * conn)48 static struct bt_vcp_vol_ctlr *vol_ctlr_get_by_conn(const struct bt_conn *conn)
49 {
50 return &vol_ctlr_insts[bt_conn_index(conn)];
51 }
52
vcp_vol_ctlr_state_changed(struct bt_vcp_vol_ctlr * vol_ctlr,int err)53 static void vcp_vol_ctlr_state_changed(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
54 {
55 struct bt_vcp_vol_ctlr_cb *listener, *next;
56
57 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
58 if (listener->state) {
59 listener->state(vol_ctlr, err, err == 0 ? vol_ctlr->state.volume : 0,
60 err == 0 ? vol_ctlr->state.mute : 0);
61 }
62 }
63 }
64
vcp_vol_ctlr_vol_flags_changed(struct bt_vcp_vol_ctlr * vol_ctlr,int err)65 static void vcp_vol_ctlr_vol_flags_changed(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
66 {
67 struct bt_vcp_vol_ctlr_cb *listener, *next;
68
69 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
70 if (listener->flags) {
71 listener->flags(vol_ctlr, err, err == 0 ? vol_ctlr->vol_flags : 0);
72 }
73 }
74 }
75
vcp_vol_ctlr_discover_complete(struct bt_vcp_vol_ctlr * vol_ctlr,int err)76 static void vcp_vol_ctlr_discover_complete(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
77 {
78 struct bt_vcp_vol_ctlr_cb *listener, *next;
79
80 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
81
82 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
83 if (listener->discover) {
84 uint8_t vocs_cnt = 0U;
85 uint8_t aics_cnt = 0U;
86
87 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
88 if (err == 0) {
89 vocs_cnt = vol_ctlr->vocs_inst_cnt;
90 }
91 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
92 #if defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
93 if (err == 0) {
94 aics_cnt = vol_ctlr->aics_inst_cnt;
95 }
96 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
97
98 listener->discover(vol_ctlr, err, vocs_cnt, aics_cnt);
99 }
100 }
101 }
102
vcp_vol_ctlr_notify_handler(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)103 static uint8_t vcp_vol_ctlr_notify_handler(struct bt_conn *conn,
104 struct bt_gatt_subscribe_params *params,
105 const void *data, uint16_t length)
106 {
107 uint16_t handle = params->value_handle;
108 struct bt_vcp_vol_ctlr *vol_ctlr;
109
110 if (data == NULL || conn == NULL) {
111 return BT_GATT_ITER_CONTINUE;
112 }
113
114 vol_ctlr = vol_ctlr_get_by_conn(conn);
115
116 if (handle == vol_ctlr->state_handle &&
117 length == sizeof(vol_ctlr->state)) {
118 memcpy(&vol_ctlr->state, data, length);
119 LOG_DBG("Volume %u, mute %u, counter %u",
120 vol_ctlr->state.volume, vol_ctlr->state.mute,
121 vol_ctlr->state.change_counter);
122 vcp_vol_ctlr_state_changed(vol_ctlr, 0);
123 } else if (handle == vol_ctlr->vol_flag_handle && length == sizeof(vol_ctlr->vol_flags)) {
124 memcpy(&vol_ctlr->vol_flags, data, length);
125 LOG_DBG("Volume Flags %u", vol_ctlr->vol_flags);
126 vcp_vol_ctlr_vol_flags_changed(vol_ctlr, 0);
127 }
128
129 return BT_GATT_ITER_CONTINUE;
130 }
131
vcp_vol_ctlr_read_vol_state_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)132 static uint8_t vcp_vol_ctlr_read_vol_state_cb(struct bt_conn *conn, uint8_t err,
133 struct bt_gatt_read_params *params,
134 const void *data, uint16_t length)
135 {
136 int cb_err = err;
137 struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn);
138
139 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
140
141 if (cb_err) {
142 LOG_DBG("err: %d", cb_err);
143 } else if (data != NULL) {
144 if (length == sizeof(vol_ctlr->state)) {
145 memcpy(&vol_ctlr->state, data, length);
146 LOG_DBG("Volume %u, mute %u, counter %u",
147 vol_ctlr->state.volume,
148 vol_ctlr->state.mute,
149 vol_ctlr->state.change_counter);
150 } else {
151 LOG_DBG("Invalid length %u (expected %zu)",
152 length, sizeof(vol_ctlr->state));
153 cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
154 }
155 }
156
157 vcp_vol_ctlr_state_changed(vol_ctlr, cb_err);
158
159 return BT_GATT_ITER_STOP;
160 }
161
vcp_vol_ctlr_read_vol_flag_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)162 static uint8_t vcp_vol_ctlr_read_vol_flag_cb(struct bt_conn *conn, uint8_t err,
163 struct bt_gatt_read_params *params, const void *data,
164 uint16_t length)
165 {
166 int cb_err = err;
167 struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn);
168
169 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
170
171 if (cb_err) {
172 LOG_DBG("err: %d", cb_err);
173 } else if (data != NULL) {
174 if (length == sizeof(vol_ctlr->vol_flags)) {
175 memcpy(&vol_ctlr->vol_flags, data, length);
176 LOG_DBG("Volume Flags %u", vol_ctlr->vol_flags);
177 } else {
178 LOG_DBG("Invalid length %u (expected %zu)", length,
179 sizeof(vol_ctlr->vol_flags));
180 cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
181 }
182 }
183
184 vcp_vol_ctlr_vol_flags_changed(vol_ctlr, cb_err);
185
186 return BT_GATT_ITER_STOP;
187 }
188
vcs_cp_notify_app(struct bt_vcp_vol_ctlr * vol_ctlr,uint8_t opcode,int err)189 static void vcs_cp_notify_app(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t opcode, int err)
190 {
191 struct bt_vcp_vol_ctlr_cb *listener, *next;
192
193 LOG_DBG("%p opcode %u err %d", vol_ctlr, opcode, err);
194
195 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
196 switch (opcode) {
197 case BT_VCP_OPCODE_REL_VOL_DOWN:
198 if (listener->vol_down) {
199 listener->vol_down(vol_ctlr, err);
200 }
201 break;
202 case BT_VCP_OPCODE_REL_VOL_UP:
203 if (listener->vol_up) {
204 listener->vol_up(vol_ctlr, err);
205 }
206 break;
207 case BT_VCP_OPCODE_UNMUTE_REL_VOL_DOWN:
208 if (listener->vol_down_unmute) {
209 listener->vol_down_unmute(vol_ctlr, err);
210 }
211 break;
212 case BT_VCP_OPCODE_UNMUTE_REL_VOL_UP:
213 if (listener->vol_up_unmute) {
214 listener->vol_up_unmute(vol_ctlr, err);
215 }
216 break;
217 case BT_VCP_OPCODE_SET_ABS_VOL:
218 if (listener->vol_set) {
219 listener->vol_set(vol_ctlr, err);
220 }
221 break;
222 case BT_VCP_OPCODE_UNMUTE:
223 if (listener->unmute) {
224 listener->unmute(vol_ctlr, err);
225 }
226 break;
227 case BT_VCP_OPCODE_MUTE:
228 if (listener->mute) {
229 listener->mute(vol_ctlr, err);
230 }
231 break;
232 default:
233 LOG_DBG("Unknown opcode 0x%02x", opcode);
234 break;
235 }
236 }
237 }
238
internal_read_vol_state_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)239 static uint8_t internal_read_vol_state_cb(struct bt_conn *conn, uint8_t err,
240 struct bt_gatt_read_params *params,
241 const void *data, uint16_t length)
242 {
243 int cb_err = 0;
244 struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn);
245 uint8_t opcode = vol_ctlr->cp_val.cp.opcode;
246
247
248 memset(params, 0, sizeof(*params));
249
250 if (err > 0) {
251 LOG_WRN("Volume state read failed: %d", err);
252 cb_err = BT_ATT_ERR_UNLIKELY;
253 } else if (data != NULL) {
254 if (length == sizeof(vol_ctlr->state)) {
255 int write_err;
256
257 memcpy(&vol_ctlr->state, data, length);
258 LOG_DBG("Volume %u, mute %u, counter %u",
259 vol_ctlr->state.volume,
260 vol_ctlr->state.mute,
261 vol_ctlr->state.change_counter);
262
263 /* clear busy flag to reuse function */
264 if (opcode == BT_VCP_OPCODE_SET_ABS_VOL) {
265 write_err = write_set_vol_cp(vol_ctlr);
266 } else {
267 write_err = write_common_vcs_cp(vol_ctlr);
268 }
269 if (write_err) {
270 cb_err = BT_ATT_ERR_UNLIKELY;
271 }
272 } else {
273 LOG_DBG("Invalid length %u (expected %zu)",
274 length, sizeof(vol_ctlr->state));
275 cb_err = BT_ATT_ERR_UNLIKELY;
276 }
277 }
278
279 if (cb_err) {
280 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_CP_RETRIED);
281 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
282 vcs_cp_notify_app(vol_ctlr, opcode, cb_err);
283 }
284
285 return BT_GATT_ITER_STOP;
286 }
287
vcp_vol_ctlr_write_vcs_cp_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)288 static void vcp_vol_ctlr_write_vcs_cp_cb(struct bt_conn *conn, uint8_t err,
289 struct bt_gatt_write_params *params)
290 {
291 struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn);
292 uint8_t opcode = vol_ctlr->cp_val.cp.opcode;
293 int cb_err = err;
294
295 LOG_DBG("err: 0x%02X", err);
296 memset(params, 0, sizeof(*params));
297
298 /* If the change counter is out of data when a write was attempted from
299 * the application, we automatically initiate a read to get the newest
300 * state and try again. Once the change counter has been read, we
301 * restart the applications write request. If it fails
302 * the second time, we return an error to the application.
303 */
304 if (cb_err == BT_VCP_ERR_INVALID_COUNTER &&
305 atomic_test_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_CP_RETRIED)) {
306 cb_err = BT_ATT_ERR_UNLIKELY;
307 } else if (err == BT_VCP_ERR_INVALID_COUNTER && vol_ctlr->state_handle) {
308 vol_ctlr->read_params.func = internal_read_vol_state_cb;
309 vol_ctlr->read_params.handle_count = 1;
310 vol_ctlr->read_params.single.handle = vol_ctlr->state_handle;
311 vol_ctlr->read_params.single.offset = 0U;
312
313 cb_err = bt_gatt_read(conn, &vol_ctlr->read_params);
314 if (cb_err) {
315 LOG_WRN("Could not read Volume state: %d", cb_err);
316 } else {
317 atomic_set_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_CP_RETRIED);
318 /* Wait for read callback */
319 return;
320 }
321 }
322
323 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
324 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_CP_RETRIED);
325
326 vcs_cp_notify_app(vol_ctlr, opcode, err);
327 }
328
329 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) || defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
vcs_discover_include_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)330 static uint8_t vcs_discover_include_func(struct bt_conn *conn,
331 const struct bt_gatt_attr *attr,
332 struct bt_gatt_discover_params *params)
333 {
334 struct bt_gatt_include *include;
335 uint8_t inst_idx;
336 int err;
337 struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn);
338
339 if (attr == NULL) {
340 uint8_t vocs_cnt = 0U;
341 uint8_t aics_cnt = 0U;
342
343 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
344 vocs_cnt = vol_ctlr->vocs_inst_cnt;
345 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
346
347 #if defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
348 aics_cnt = vol_ctlr->aics_inst_cnt;
349 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
350
351 LOG_DBG("Discover include complete for vol_ctlr: %u AICS and %u VOCS", aics_cnt,
352 vocs_cnt);
353 (void)memset(params, 0, sizeof(*params));
354
355 vcp_vol_ctlr_discover_complete(vol_ctlr, 0);
356
357 return BT_GATT_ITER_STOP;
358 }
359
360 LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
361
362 if (params->type == BT_GATT_DISCOVER_INCLUDE) {
363 uint8_t conn_index = bt_conn_index(conn);
364
365 include = (struct bt_gatt_include *)attr->user_data;
366 LOG_DBG("Include UUID %s", bt_uuid_str(include->uuid));
367
368 #if defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
369 if (bt_uuid_cmp(include->uuid, BT_UUID_AICS) == 0 &&
370 vol_ctlr->aics_inst_cnt < CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST) {
371 struct bt_aics_discover_param param = {
372 .start_handle = include->start_handle,
373 .end_handle = include->end_handle,
374 };
375
376 /* Update discover params so we can continue where we
377 * left off after bt_aics_discover
378 */
379 vol_ctlr->discover_params.start_handle = attr->handle + 1;
380
381 inst_idx = vol_ctlr->aics_inst_cnt++;
382 err = bt_aics_discover(conn,
383 vol_ctlr_insts[conn_index].aics[inst_idx],
384 ¶m);
385 if (err != 0) {
386 LOG_DBG("AICS Discover failed (err %d)", err);
387 vcp_vol_ctlr_discover_complete(vol_ctlr, err);
388 }
389
390 return BT_GATT_ITER_STOP;
391 }
392 #endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */
393 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
394 if (bt_uuid_cmp(include->uuid, BT_UUID_VOCS) == 0 &&
395 vol_ctlr->vocs_inst_cnt < CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST) {
396 struct bt_vocs_discover_param param = {
397 .start_handle = include->start_handle,
398 .end_handle = include->end_handle,
399 };
400
401 /* Update discover params so we can continue where we
402 * left off after bt_vocs_discover
403 */
404 vol_ctlr->discover_params.start_handle = attr->handle + 1;
405
406 inst_idx = vol_ctlr->vocs_inst_cnt++;
407 err = bt_vocs_discover(conn,
408 vol_ctlr_insts[conn_index].vocs[inst_idx],
409 ¶m);
410 if (err != 0) {
411 LOG_DBG("VOCS Discover failed (err %d)", err);
412 vcp_vol_ctlr_discover_complete(vol_ctlr, err);
413 }
414
415 return BT_GATT_ITER_STOP;
416 }
417 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
418 }
419
420 return BT_GATT_ITER_CONTINUE;
421 }
422 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS */
423
424 /**
425 * @brief This will discover all characteristics on the server, retrieving the
426 * handles of the writeable characteristics and subscribing to all notify and
427 * indicate characteristics.
428 */
vcs_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)429 static uint8_t vcs_discover_func(struct bt_conn *conn,
430 const struct bt_gatt_attr *attr,
431 struct bt_gatt_discover_params *params)
432 {
433 int err = 0;
434 struct bt_gatt_chrc *chrc;
435 struct bt_gatt_subscribe_params *sub_params = NULL;
436 struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn);
437
438 if (attr == NULL) {
439 LOG_DBG("Setup complete for vol_ctlr");
440 (void)memset(params, 0, sizeof(*params));
441 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) || defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
442 /* Discover included services */
443 vol_ctlr->discover_params.start_handle = vol_ctlr->start_handle;
444 vol_ctlr->discover_params.end_handle = vol_ctlr->end_handle;
445 vol_ctlr->discover_params.type = BT_GATT_DISCOVER_INCLUDE;
446 vol_ctlr->discover_params.func = vcs_discover_include_func;
447
448 err = bt_gatt_discover(conn, &vol_ctlr->discover_params);
449 if (err != 0) {
450 LOG_DBG("Discover failed (err %d)", err);
451 vcp_vol_ctlr_discover_complete(vol_ctlr, err);
452 }
453 #else
454 vcp_vol_ctlr_discover_complete(vol_ctlr, err);
455 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS */
456
457 return BT_GATT_ITER_STOP;
458 }
459
460 LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
461
462 if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) {
463 chrc = (struct bt_gatt_chrc *)attr->user_data;
464
465 if (bt_uuid_cmp(chrc->uuid, BT_UUID_VCS_STATE) == 0) {
466 LOG_DBG("Volume state");
467 vol_ctlr->state_handle = chrc->value_handle;
468 sub_params = &vol_ctlr->state_sub_params;
469 sub_params->disc_params = &vol_ctlr->state_sub_disc_params;
470 } else if (bt_uuid_cmp(chrc->uuid, BT_UUID_VCS_CONTROL) == 0) {
471 LOG_DBG("Control Point");
472 vol_ctlr->control_handle = chrc->value_handle;
473 } else if (bt_uuid_cmp(chrc->uuid, BT_UUID_VCS_FLAGS) == 0) {
474 LOG_DBG("Volume Flags");
475 vol_ctlr->vol_flag_handle = chrc->value_handle;
476 sub_params = &vol_ctlr->vol_flag_sub_params;
477 sub_params->disc_params = &vol_ctlr->vol_flag_sub_disc_params;
478 }
479
480 if (sub_params != NULL) {
481 sub_params->value = BT_GATT_CCC_NOTIFY;
482 sub_params->value_handle = chrc->value_handle;
483 sub_params->ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
484 sub_params->end_handle = vol_ctlr->end_handle;
485 sub_params->notify = vcp_vol_ctlr_notify_handler;
486 atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
487
488 err = bt_gatt_subscribe(conn, sub_params);
489 if (err == 0 || err == -EALREADY) {
490 LOG_DBG("Subscribed to handle 0x%04X",
491 attr->handle);
492 } else {
493 LOG_DBG("Could not subscribe to handle 0x%04X (%d)", attr->handle,
494 err);
495 vcp_vol_ctlr_discover_complete(vol_ctlr, err);
496
497 return BT_GATT_ITER_STOP;
498 }
499 }
500 }
501
502 return BT_GATT_ITER_CONTINUE;
503 }
504
505 /**
506 * @brief This will discover all characteristics on the server, retrieving the
507 * handles of the writeable characteristics and subscribing to all notify and
508 * indicate characteristics.
509 */
primary_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)510 static uint8_t primary_discover_func(struct bt_conn *conn,
511 const struct bt_gatt_attr *attr,
512 struct bt_gatt_discover_params *params)
513 {
514 struct bt_gatt_service_val *prim_service;
515 struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn);
516
517 if (attr == NULL) {
518 LOG_DBG("Could not find a vol_ctlr instance on the server");
519 vcp_vol_ctlr_discover_complete(vol_ctlr, -ENODATA);
520
521 return BT_GATT_ITER_STOP;
522 }
523
524 LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
525
526 if (params->type == BT_GATT_DISCOVER_PRIMARY) {
527 int err;
528
529 LOG_DBG("Primary discover complete");
530 prim_service = (struct bt_gatt_service_val *)attr->user_data;
531
532 vol_ctlr->start_handle = attr->handle + 1;
533 vol_ctlr->end_handle = prim_service->end_handle;
534
535 /* Discover characteristics */
536 vol_ctlr->discover_params.uuid = NULL;
537 vol_ctlr->discover_params.start_handle = vol_ctlr->start_handle;
538 vol_ctlr->discover_params.end_handle = vol_ctlr->end_handle;
539 vol_ctlr->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
540 vol_ctlr->discover_params.func = vcs_discover_func;
541
542 err = bt_gatt_discover(conn, &vol_ctlr->discover_params);
543 if (err != 0) {
544 LOG_DBG("Discover failed (err %d)", err);
545 vcp_vol_ctlr_discover_complete(vol_ctlr, err);
546 }
547
548 return BT_GATT_ITER_STOP;
549 }
550
551 return BT_GATT_ITER_CONTINUE;
552 }
553
write_common_vcs_cp(struct bt_vcp_vol_ctlr * vol_ctlr)554 static int write_common_vcs_cp(struct bt_vcp_vol_ctlr *vol_ctlr)
555 {
556 int err;
557
558 vol_ctlr->write_params.offset = 0;
559 vol_ctlr->write_params.data = &vol_ctlr->cp_val.cp;
560 vol_ctlr->write_params.length = sizeof(vol_ctlr->cp_val.cp);
561 vol_ctlr->write_params.handle = vol_ctlr->control_handle;
562 vol_ctlr->write_params.func = vcp_vol_ctlr_write_vcs_cp_cb;
563
564 err = bt_gatt_write(vol_ctlr->conn, &vol_ctlr->write_params);
565 if (err != 0) {
566 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
567 }
568
569 return err;
570 }
571
vcp_vol_ctlr_common_vcs_cp(struct bt_vcp_vol_ctlr * vol_ctlr,uint8_t opcode)572 static int vcp_vol_ctlr_common_vcs_cp(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t opcode)
573 {
574 CHECKIF(vol_ctlr == NULL) {
575 LOG_DBG("NULL ctlr");
576 return -EINVAL;
577 }
578
579 if (vol_ctlr->conn == NULL) {
580 LOG_DBG("NULL ctlr conn");
581 return -EINVAL;
582 }
583
584 if (vol_ctlr->control_handle == 0) {
585 LOG_DBG("Handle not set");
586 return -EINVAL;
587 } else if (atomic_test_and_set_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY)) {
588 return -EBUSY;
589 }
590
591 vol_ctlr->cp_val.cp.opcode = opcode;
592 vol_ctlr->cp_val.cp.counter = vol_ctlr->state.change_counter;
593
594 return write_common_vcs_cp(vol_ctlr);
595 }
596
597 #if defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
lookup_vcp_by_aics(const struct bt_aics * aics)598 static struct bt_vcp_vol_ctlr *lookup_vcp_by_aics(const struct bt_aics *aics)
599 {
600 __ASSERT(aics != NULL, "aics pointer cannot be NULL");
601
602 for (size_t i = 0U; i < ARRAY_SIZE(vol_ctlr_insts); i++) {
603 for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlr_insts[i].aics); j++) {
604 if (vol_ctlr_insts[i].aics[j] == aics) {
605 return &vol_ctlr_insts[i];
606 }
607 }
608 }
609
610 return NULL;
611 }
612
vcp_vol_ctlr_aics_state_cb(struct bt_aics * inst,int err,int8_t gain,uint8_t mute,uint8_t mode)613 static void vcp_vol_ctlr_aics_state_cb(struct bt_aics *inst, int err, int8_t gain, uint8_t mute,
614 uint8_t mode)
615 {
616 struct bt_vcp_vol_ctlr_cb *listener, *next;
617
618 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
619 if (listener->aics_cb.state) {
620 listener->aics_cb.state(inst, err, gain, mute, mode);
621 }
622 }
623 }
624
vcp_vol_ctlr_aics_gain_setting_cb(struct bt_aics * inst,int err,uint8_t units,int8_t minimum,int8_t maximum)625 static void vcp_vol_ctlr_aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units,
626 int8_t minimum, int8_t maximum)
627 {
628 struct bt_vcp_vol_ctlr_cb *listener, *next;
629
630 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
631 if (listener->aics_cb.gain_setting) {
632 listener->aics_cb.gain_setting(inst, err, units, minimum, maximum);
633 }
634 }
635 }
636
vcp_vol_ctlr_aics_type_cb(struct bt_aics * inst,int err,uint8_t type)637 static void vcp_vol_ctlr_aics_type_cb(struct bt_aics *inst, int err, uint8_t type)
638 {
639 struct bt_vcp_vol_ctlr_cb *listener, *next;
640
641 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
642 if (listener->aics_cb.type) {
643 listener->aics_cb.type(inst, err, type);
644 }
645 }
646 }
647
vcp_vol_ctlr_aics_status_cb(struct bt_aics * inst,int err,bool active)648 static void vcp_vol_ctlr_aics_status_cb(struct bt_aics *inst, int err, bool active)
649 {
650 struct bt_vcp_vol_ctlr_cb *listener, *next;
651
652 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
653 if (listener->aics_cb.status) {
654 listener->aics_cb.status(inst, err, active);
655 }
656 }
657 }
658
vcp_vol_ctlr_aics_description_cb(struct bt_aics * inst,int err,char * description)659 static void vcp_vol_ctlr_aics_description_cb(struct bt_aics *inst, int err, char *description)
660 {
661 struct bt_vcp_vol_ctlr_cb *listener, *next;
662
663 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
664 if (listener->aics_cb.description) {
665 listener->aics_cb.description(inst, err, description);
666 }
667 }
668 }
669
vcp_vol_ctlr_aics_discover_cb(struct bt_aics * inst,int err)670 static void vcp_vol_ctlr_aics_discover_cb(struct bt_aics *inst, int err)
671 {
672 struct bt_vcp_vol_ctlr *vol_ctlr = lookup_vcp_by_aics(inst);
673 struct bt_vcp_vol_ctlr_cb *listener, *next;
674
675 if (vol_ctlr == NULL) {
676 LOG_ERR("Could not lookup vol_ctlr from aics");
677 vcp_vol_ctlr_discover_complete(vol_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY));
678
679 return;
680 }
681
682 if (err == 0) {
683 /* Continue discovery of included services */
684 err = bt_gatt_discover(vol_ctlr->conn, &vol_ctlr->discover_params);
685 }
686
687 if (err != 0) {
688 LOG_DBG("Discover failed (err %d)", err);
689 vcp_vol_ctlr_discover_complete(vol_ctlr, err);
690 }
691
692 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
693 if (listener->aics_cb.discover) {
694 listener->aics_cb.discover(inst, err);
695 }
696 }
697 }
698
vcp_vol_ctlr_aics_set_gain_cb(struct bt_aics * inst,int err)699 static void vcp_vol_ctlr_aics_set_gain_cb(struct bt_aics *inst, int err)
700 {
701 struct bt_vcp_vol_ctlr_cb *listener, *next;
702
703 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
704 if (listener->aics_cb.set_gain) {
705 listener->aics_cb.set_gain(inst, err);
706 }
707 }
708 }
709
vcp_vol_ctlr_aics_unmute_cb(struct bt_aics * inst,int err)710 static void vcp_vol_ctlr_aics_unmute_cb(struct bt_aics *inst, int err)
711 {
712 struct bt_vcp_vol_ctlr_cb *listener, *next;
713
714 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
715 if (listener->aics_cb.unmute) {
716 listener->aics_cb.unmute(inst, err);
717 }
718 }
719 }
720
vcp_vol_ctlr_aics_mute_cb(struct bt_aics * inst,int err)721 static void vcp_vol_ctlr_aics_mute_cb(struct bt_aics *inst, int err)
722 {
723 struct bt_vcp_vol_ctlr_cb *listener, *next;
724
725 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
726 if (listener->aics_cb.mute) {
727 listener->aics_cb.mute(inst, err);
728 }
729 }
730 }
731
vcp_vol_ctlr_aics_set_manual_mode_cb(struct bt_aics * inst,int err)732 static void vcp_vol_ctlr_aics_set_manual_mode_cb(struct bt_aics *inst, int err)
733 {
734 struct bt_vcp_vol_ctlr_cb *listener, *next;
735
736 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
737 if (listener->aics_cb.set_manual_mode) {
738 listener->aics_cb.set_manual_mode(inst, err);
739 }
740 }
741 }
742
vcp_vol_ctlr_aics_set_auto_mode_cb(struct bt_aics * inst,int err)743 static void vcp_vol_ctlr_aics_set_auto_mode_cb(struct bt_aics *inst, int err)
744 {
745 struct bt_vcp_vol_ctlr_cb *listener, *next;
746
747 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
748 if (listener->aics_cb.set_auto_mode) {
749 listener->aics_cb.set_auto_mode(inst, err);
750 }
751 }
752 }
753 #endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */
754
755 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
lookup_vcp_by_vocs(const struct bt_vocs * vocs)756 static struct bt_vcp_vol_ctlr *lookup_vcp_by_vocs(const struct bt_vocs *vocs)
757 {
758 __ASSERT(vocs != NULL, "VOCS pointer cannot be NULL");
759
760 for (int i = 0; i < ARRAY_SIZE(vol_ctlr_insts); i++) {
761 for (int j = 0; j < ARRAY_SIZE(vol_ctlr_insts[i].vocs); j++) {
762 if (vol_ctlr_insts[i].vocs[j] == vocs) {
763 return &vol_ctlr_insts[i];
764 }
765 }
766 }
767
768 return NULL;
769 }
770
vcp_vol_ctlr_vocs_state_cb(struct bt_vocs * inst,int err,int16_t offset)771 static void vcp_vol_ctlr_vocs_state_cb(struct bt_vocs *inst, int err, int16_t offset)
772 {
773 struct bt_vcp_vol_ctlr_cb *listener, *next;
774
775 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
776 if (listener->vocs_cb.state) {
777 listener->vocs_cb.state(inst, err, offset);
778 }
779 }
780 }
781
vcp_vol_ctlr_vocs_location_cb(struct bt_vocs * inst,int err,uint32_t location)782 static void vcp_vol_ctlr_vocs_location_cb(struct bt_vocs *inst, int err, uint32_t location)
783 {
784 struct bt_vcp_vol_ctlr_cb *listener, *next;
785
786 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
787 if (listener->vocs_cb.location) {
788 listener->vocs_cb.location(inst, err, location);
789 }
790 }
791 }
792
vcp_vol_ctlr_vocs_description_cb(struct bt_vocs * inst,int err,char * description)793 static void vcp_vol_ctlr_vocs_description_cb(struct bt_vocs *inst, int err, char *description)
794 {
795 struct bt_vcp_vol_ctlr_cb *listener, *next;
796
797 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
798 if (listener->vocs_cb.description) {
799 listener->vocs_cb.description(inst, err, description);
800 }
801 }
802 }
803
vcp_vol_ctlr_vocs_discover_cb(struct bt_vocs * inst,int err)804 static void vcp_vol_ctlr_vocs_discover_cb(struct bt_vocs *inst, int err)
805 {
806 struct bt_vcp_vol_ctlr *vol_ctlr = lookup_vcp_by_vocs(inst);
807 struct bt_vcp_vol_ctlr_cb *listener, *next;
808
809 if (vol_ctlr == NULL) {
810 LOG_ERR("Could not lookup vol_ctlr from vocs");
811 vcp_vol_ctlr_discover_complete(vol_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY));
812
813 return;
814 }
815
816 if (err == 0) {
817 /* Continue discovery of included services */
818 err = bt_gatt_discover(vol_ctlr->conn, &vol_ctlr->discover_params);
819 }
820
821 if (err != 0) {
822 LOG_DBG("Discover failed (err %d)", err);
823 vcp_vol_ctlr_discover_complete(vol_ctlr, err);
824 }
825
826 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
827 if (listener->vocs_cb.discover) {
828 listener->vocs_cb.discover(inst, err);
829 }
830 }
831 }
832
vcp_vol_ctlr_vocs_set_offset_cb(struct bt_vocs * inst,int err)833 static void vcp_vol_ctlr_vocs_set_offset_cb(struct bt_vocs *inst, int err)
834 {
835 struct bt_vcp_vol_ctlr_cb *listener, *next;
836
837 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) {
838 if (listener->vocs_cb.set_offset) {
839 listener->vocs_cb.set_offset(inst, err);
840 }
841 }
842 }
843 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
844
vcp_vol_ctlr_reset(struct bt_vcp_vol_ctlr * vol_ctlr)845 static void vcp_vol_ctlr_reset(struct bt_vcp_vol_ctlr *vol_ctlr)
846 {
847 memset(&vol_ctlr->state, 0, sizeof(vol_ctlr->state));
848 vol_ctlr->vol_flags = 0;
849 vol_ctlr->start_handle = 0;
850 vol_ctlr->end_handle = 0;
851 vol_ctlr->state_handle = 0;
852 vol_ctlr->control_handle = 0;
853 vol_ctlr->vol_flag_handle = 0;
854 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
855 vol_ctlr->vocs_inst_cnt = 0;
856 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
857 #if defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
858 vol_ctlr->aics_inst_cnt = 0;
859 #endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */
860
861 memset(&vol_ctlr->discover_params, 0, sizeof(vol_ctlr->discover_params));
862
863 if (vol_ctlr->conn != NULL) {
864 struct bt_conn *conn = vol_ctlr->conn;
865
866 bt_conn_unref(conn);
867 vol_ctlr->conn = NULL;
868 }
869 }
870
disconnected(struct bt_conn * conn,uint8_t reason)871 static void disconnected(struct bt_conn *conn, uint8_t reason)
872 {
873 struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn);
874
875 if (vol_ctlr->conn == conn) {
876 vcp_vol_ctlr_reset(vol_ctlr);
877 }
878 }
879
880 BT_CONN_CB_DEFINE(conn_callbacks) = {
881 .disconnected = disconnected,
882 };
883
bt_vcp_vol_ctlr_init(void)884 static void bt_vcp_vol_ctlr_init(void)
885 {
886 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
887 for (size_t i = 0U; i < ARRAY_SIZE(vol_ctlr_insts); i++) {
888 for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlr_insts[i].vocs); j++) {
889 static struct bt_vocs_cb vocs_cb = {
890 .state = vcp_vol_ctlr_vocs_state_cb,
891 .location = vcp_vol_ctlr_vocs_location_cb,
892 .description = vcp_vol_ctlr_vocs_description_cb,
893 .discover = vcp_vol_ctlr_vocs_discover_cb,
894 .set_offset = vcp_vol_ctlr_vocs_set_offset_cb,
895 };
896
897 vol_ctlr_insts[i].vocs[j] = bt_vocs_client_free_instance_get();
898
899 __ASSERT(vol_ctlr_insts[i].vocs[j],
900 "Could not allocate VOCS client instance");
901
902 bt_vocs_client_cb_register(vol_ctlr_insts[i].vocs[j], &vocs_cb);
903 }
904 }
905 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
906
907 #if defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
908 for (size_t i = 0U; i < ARRAY_SIZE(vol_ctlr_insts); i++) {
909 for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlr_insts[i].aics); j++) {
910 static struct bt_aics_cb aics_cb = {
911 .state = vcp_vol_ctlr_aics_state_cb,
912 .gain_setting = vcp_vol_ctlr_aics_gain_setting_cb,
913 .type = vcp_vol_ctlr_aics_type_cb,
914 .status = vcp_vol_ctlr_aics_status_cb,
915 .description = vcp_vol_ctlr_aics_description_cb,
916 .discover = vcp_vol_ctlr_aics_discover_cb,
917 .set_gain = vcp_vol_ctlr_aics_set_gain_cb,
918 .unmute = vcp_vol_ctlr_aics_unmute_cb,
919 .mute = vcp_vol_ctlr_aics_mute_cb,
920 .set_manual_mode = vcp_vol_ctlr_aics_set_manual_mode_cb,
921 .set_auto_mode = vcp_vol_ctlr_aics_set_auto_mode_cb,
922 };
923
924 vol_ctlr_insts[i].aics[j] = bt_aics_client_free_instance_get();
925
926 __ASSERT(vol_ctlr_insts[i].aics[j],
927 "Could not allocate AICS client instance");
928
929 bt_aics_client_cb_register(vol_ctlr_insts[i].aics[j], &aics_cb);
930 }
931 }
932 #endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */
933 }
934
bt_vcp_vol_ctlr_discover(struct bt_conn * conn,struct bt_vcp_vol_ctlr ** out_vol_ctlr)935 int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **out_vol_ctlr)
936 {
937 static bool initialized;
938 struct bt_vcp_vol_ctlr *vol_ctlr;
939 int err;
940
941 /*
942 * This will initiate a discover procedure. The procedure will do the
943 * following sequence:
944 * 1) Primary discover for the vol_ctlr
945 * 2) Characteristic discover of the vol_ctlr
946 * 3) Discover services included in vol_ctlr (VOCS and AICS)
947 * 4) For each included service found; discovery of the characteristics
948 * 5) When everything above have been discovered, the callback is called
949 */
950
951 CHECKIF(conn == NULL) {
952 LOG_DBG("NULL conn");
953 return -EINVAL;
954 }
955
956 CHECKIF(out_vol_ctlr == NULL) {
957 LOG_DBG("NULL ctlr");
958 return -EINVAL;
959 }
960
961 vol_ctlr = vol_ctlr_get_by_conn(conn);
962
963 if (atomic_test_and_set_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY)) {
964 LOG_DBG("Volume controller busy");
965 return -EBUSY;
966 }
967
968 if (!initialized) {
969 bt_vcp_vol_ctlr_init();
970 initialized = true;
971 }
972
973 vcp_vol_ctlr_reset(vol_ctlr);
974
975 memcpy(&vol_ctlr->uuid, BT_UUID_VCS, sizeof(vol_ctlr->uuid));
976
977 vol_ctlr->conn = bt_conn_ref(conn);
978 vol_ctlr->discover_params.func = primary_discover_func;
979 vol_ctlr->discover_params.uuid = &vol_ctlr->uuid.uuid;
980 vol_ctlr->discover_params.type = BT_GATT_DISCOVER_PRIMARY;
981 vol_ctlr->discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
982 vol_ctlr->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
983
984 err = bt_gatt_discover(conn, &vol_ctlr->discover_params);
985 if (err == 0) {
986 *out_vol_ctlr = vol_ctlr;
987 } else {
988 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
989 }
990
991 return err;
992 }
993
bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb * cb)994 int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb)
995 {
996 struct bt_vcp_vol_ctlr_cb *tmp;
997
998 CHECKIF(cb == NULL) {
999 return -EINVAL;
1000 }
1001
1002 SYS_SLIST_FOR_EACH_CONTAINER(&vcp_vol_ctlr_cbs, tmp, _node) {
1003 if (tmp == cb) {
1004 LOG_DBG("Already registered");
1005 return -EALREADY;
1006 }
1007 }
1008
1009 sys_slist_append(&vcp_vol_ctlr_cbs, &cb->_node);
1010
1011 return 0;
1012 }
1013
bt_vcp_vol_ctlr_cb_unregister(struct bt_vcp_vol_ctlr_cb * cb)1014 int bt_vcp_vol_ctlr_cb_unregister(struct bt_vcp_vol_ctlr_cb *cb)
1015 {
1016 CHECKIF(cb == NULL) {
1017 return -EINVAL;
1018 }
1019
1020 if (!sys_slist_find_and_remove(&vcp_vol_ctlr_cbs, &cb->_node)) {
1021 return -EALREADY;
1022 }
1023
1024 return 0;
1025 }
1026
1027 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) || defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
bt_vcp_vol_ctlr_included_get(struct bt_vcp_vol_ctlr * vol_ctlr,struct bt_vcp_included * included)1028 int bt_vcp_vol_ctlr_included_get(struct bt_vcp_vol_ctlr *vol_ctlr,
1029 struct bt_vcp_included *included)
1030 {
1031 CHECKIF(!included || vol_ctlr == NULL) {
1032 return -EINVAL;
1033 }
1034
1035 memset(included, 0, sizeof(*included));
1036
1037 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
1038 included->vocs_cnt = vol_ctlr->vocs_inst_cnt;
1039 included->vocs = vol_ctlr->vocs;
1040 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
1041
1042 #if defined(CONFIG_BT_VCP_VOL_CTLR_AICS)
1043 included->aics_cnt = vol_ctlr->aics_inst_cnt;
1044 included->aics = vol_ctlr->aics;
1045 #endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */
1046
1047 return 0;
1048 }
1049 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS*/
1050
bt_vcp_vol_ctlr_get_by_conn(const struct bt_conn * conn)1051 struct bt_vcp_vol_ctlr *bt_vcp_vol_ctlr_get_by_conn(const struct bt_conn *conn)
1052 {
1053 struct bt_vcp_vol_ctlr *vol_ctlr;
1054
1055 CHECKIF(conn == NULL) {
1056 LOG_DBG("NULL conn pointer");
1057 return NULL;
1058 }
1059
1060 vol_ctlr = vol_ctlr_get_by_conn(conn);
1061 if (vol_ctlr->conn == NULL) {
1062 LOG_DBG("conn %p is not associated with volume controller. Do discovery first",
1063 (void *)conn);
1064 return NULL;
1065 }
1066
1067 return vol_ctlr;
1068 }
1069
bt_vcp_vol_ctlr_conn_get(const struct bt_vcp_vol_ctlr * vol_ctlr,struct bt_conn ** conn)1070 int bt_vcp_vol_ctlr_conn_get(const struct bt_vcp_vol_ctlr *vol_ctlr, struct bt_conn **conn)
1071 {
1072 CHECKIF(vol_ctlr == NULL) {
1073 LOG_DBG("NULL vol_ctlr pointer");
1074 return -EINVAL;
1075 }
1076
1077 CHECKIF(conn == NULL) {
1078 LOG_DBG("NULL conn pointer");
1079 return -EINVAL;
1080 }
1081
1082 if (vol_ctlr->conn == NULL) {
1083 LOG_DBG("vol_ctlr pointer not associated with a connection. "
1084 "Do discovery first");
1085 return -ENOTCONN;
1086 }
1087
1088 *conn = vol_ctlr->conn;
1089 return 0;
1090 }
1091
bt_vcp_vol_ctlr_read_state(struct bt_vcp_vol_ctlr * vol_ctlr)1092 int bt_vcp_vol_ctlr_read_state(struct bt_vcp_vol_ctlr *vol_ctlr)
1093 {
1094 int err;
1095
1096 CHECKIF(vol_ctlr == NULL) {
1097 LOG_DBG("NULL ctlr");
1098 return -EINVAL;
1099 }
1100
1101 if (vol_ctlr->conn == NULL) {
1102 LOG_DBG("NULL ctlr conn");
1103 return -EINVAL;
1104 }
1105
1106 if (vol_ctlr->state_handle == 0) {
1107 LOG_DBG("Handle not set");
1108 return -EINVAL;
1109 } else if (atomic_test_and_set_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY)) {
1110 LOG_DBG("Volume controller busy");
1111 return -EBUSY;
1112 }
1113
1114 vol_ctlr->read_params.func = vcp_vol_ctlr_read_vol_state_cb;
1115 vol_ctlr->read_params.handle_count = 1;
1116 vol_ctlr->read_params.single.handle = vol_ctlr->state_handle;
1117 vol_ctlr->read_params.single.offset = 0U;
1118
1119 err = bt_gatt_read(vol_ctlr->conn, &vol_ctlr->read_params);
1120 if (err != 0) {
1121 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
1122 }
1123
1124 return err;
1125 }
1126
bt_vcp_vol_ctlr_read_flags(struct bt_vcp_vol_ctlr * vol_ctlr)1127 int bt_vcp_vol_ctlr_read_flags(struct bt_vcp_vol_ctlr *vol_ctlr)
1128 {
1129 int err;
1130
1131 CHECKIF(vol_ctlr == NULL) {
1132 LOG_DBG("NULL ctlr");
1133 return -EINVAL;
1134 }
1135
1136 if (vol_ctlr->conn == NULL) {
1137 LOG_DBG("NULL ctlr conn");
1138 return -EINVAL;
1139 }
1140
1141 if (vol_ctlr->vol_flag_handle == 0) {
1142 LOG_DBG("Handle not set");
1143 return -EINVAL;
1144 } else if (atomic_test_and_set_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY)) {
1145 LOG_DBG("Volume controller busy");
1146 return -EBUSY;
1147 }
1148
1149 vol_ctlr->read_params.func = vcp_vol_ctlr_read_vol_flag_cb;
1150 vol_ctlr->read_params.handle_count = 1;
1151 vol_ctlr->read_params.single.handle = vol_ctlr->vol_flag_handle;
1152 vol_ctlr->read_params.single.offset = 0U;
1153
1154 err = bt_gatt_read(vol_ctlr->conn, &vol_ctlr->read_params);
1155 if (err != 0) {
1156 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
1157 }
1158
1159 return err;
1160 }
1161
bt_vcp_vol_ctlr_vol_down(struct bt_vcp_vol_ctlr * vol_ctlr)1162 int bt_vcp_vol_ctlr_vol_down(struct bt_vcp_vol_ctlr *vol_ctlr)
1163 {
1164 return vcp_vol_ctlr_common_vcs_cp(vol_ctlr, BT_VCP_OPCODE_REL_VOL_DOWN);
1165 }
1166
bt_vcp_vol_ctlr_vol_up(struct bt_vcp_vol_ctlr * vol_ctlr)1167 int bt_vcp_vol_ctlr_vol_up(struct bt_vcp_vol_ctlr *vol_ctlr)
1168 {
1169 return vcp_vol_ctlr_common_vcs_cp(vol_ctlr, BT_VCP_OPCODE_REL_VOL_UP);
1170 }
1171
bt_vcp_vol_ctlr_unmute_vol_down(struct bt_vcp_vol_ctlr * vol_ctlr)1172 int bt_vcp_vol_ctlr_unmute_vol_down(struct bt_vcp_vol_ctlr *vol_ctlr)
1173 {
1174 return vcp_vol_ctlr_common_vcs_cp(vol_ctlr, BT_VCP_OPCODE_UNMUTE_REL_VOL_DOWN);
1175 }
1176
bt_vcp_vol_ctlr_unmute_vol_up(struct bt_vcp_vol_ctlr * vol_ctlr)1177 int bt_vcp_vol_ctlr_unmute_vol_up(struct bt_vcp_vol_ctlr *vol_ctlr)
1178 {
1179 return vcp_vol_ctlr_common_vcs_cp(vol_ctlr, BT_VCP_OPCODE_UNMUTE_REL_VOL_UP);
1180 }
1181
write_set_vol_cp(struct bt_vcp_vol_ctlr * vol_ctlr)1182 static int write_set_vol_cp(struct bt_vcp_vol_ctlr *vol_ctlr)
1183 {
1184 int err;
1185
1186 vol_ctlr->write_params.offset = 0;
1187 vol_ctlr->write_params.data = &vol_ctlr->cp_val;
1188 vol_ctlr->write_params.length = sizeof(vol_ctlr->cp_val);
1189 vol_ctlr->write_params.handle = vol_ctlr->control_handle;
1190 vol_ctlr->write_params.func = vcp_vol_ctlr_write_vcs_cp_cb;
1191
1192 err = bt_gatt_write(vol_ctlr->conn, &vol_ctlr->write_params);
1193 if (err != 0) {
1194 atomic_clear_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY);
1195 }
1196
1197 return err;
1198 }
1199
bt_vcp_vol_ctlr_set_vol(struct bt_vcp_vol_ctlr * vol_ctlr,uint8_t volume)1200 int bt_vcp_vol_ctlr_set_vol(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t volume)
1201 {
1202 CHECKIF(vol_ctlr == NULL) {
1203 LOG_DBG("NULL ctlr");
1204 return -EINVAL;
1205 }
1206
1207 if (vol_ctlr->conn == NULL) {
1208 LOG_DBG("NULL ctlr conn");
1209 return -EINVAL;
1210 }
1211
1212 if (vol_ctlr->control_handle == 0) {
1213 LOG_DBG("Handle not set");
1214 return -EINVAL;
1215 } else if (atomic_test_and_set_bit(vol_ctlr->flags, BT_VCP_VOL_CTLR_FLAG_BUSY)) {
1216 LOG_DBG("Volume controller busy");
1217 return -EBUSY;
1218 }
1219
1220 vol_ctlr->cp_val.cp.opcode = BT_VCP_OPCODE_SET_ABS_VOL;
1221 vol_ctlr->cp_val.cp.counter = vol_ctlr->state.change_counter;
1222 vol_ctlr->cp_val.volume = volume;
1223
1224 return write_set_vol_cp(vol_ctlr);
1225 }
1226
bt_vcp_vol_ctlr_unmute(struct bt_vcp_vol_ctlr * vol_ctlr)1227 int bt_vcp_vol_ctlr_unmute(struct bt_vcp_vol_ctlr *vol_ctlr)
1228 {
1229 return vcp_vol_ctlr_common_vcs_cp(vol_ctlr, BT_VCP_OPCODE_UNMUTE);
1230 }
1231
bt_vcp_vol_ctlr_mute(struct bt_vcp_vol_ctlr * vol_ctlr)1232 int bt_vcp_vol_ctlr_mute(struct bt_vcp_vol_ctlr *vol_ctlr)
1233 {
1234 return vcp_vol_ctlr_common_vcs_cp(vol_ctlr, BT_VCP_OPCODE_MUTE);
1235 }
1236