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 					       &param);
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 					       &param);
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