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