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