1 /*  Bluetooth AICS client */
2 
3 /*
4  * Copyright (c) 2020 Bose Corporation
5  * Copyright (c) 2020 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/audio/aics.h>
18 #include <zephyr/bluetooth/att.h>
19 #include <zephyr/bluetooth/bluetooth.h>
20 #include <zephyr/bluetooth/l2cap.h>
21 #include <zephyr/bluetooth/conn.h>
22 #include <zephyr/bluetooth/gatt.h>
23 #include <zephyr/bluetooth/uuid.h>
24 #include <zephyr/device.h>
25 #include <zephyr/kernel.h>
26 #include <zephyr/logging/log.h>
27 #include <zephyr/init.h>
28 #include <zephyr/sys/__assert.h>
29 #include <zephyr/sys/atomic.h>
30 #include <zephyr/sys/check.h>
31 #include <zephyr/sys/util.h>
32 #include <zephyr/types.h>
33 
34 #include "aics_internal.h"
35 
36 LOG_MODULE_REGISTER(bt_aics_client, CONFIG_BT_AICS_CLIENT_LOG_LEVEL);
37 
38 static struct bt_aics aics_insts[CONFIG_BT_MAX_CONN * CONFIG_BT_AICS_CLIENT_MAX_INSTANCE_COUNT];
39 
40 static int aics_client_common_control(uint8_t opcode, struct bt_aics *inst);
41 
lookup_aics_by_handle(struct bt_conn * conn,uint16_t handle)42 static struct bt_aics *lookup_aics_by_handle(struct bt_conn *conn, uint16_t handle)
43 {
44 	for (int i = 0; i < ARRAY_SIZE(aics_insts); i++) {
45 		if (aics_insts[i].cli.conn == conn &&
46 		    atomic_test_bit(aics_insts[i].cli.flags, BT_AICS_CLIENT_FLAG_ACTIVE) &&
47 		    aics_insts[i].cli.start_handle <= handle &&
48 		    aics_insts[i].cli.end_handle >= handle) {
49 			return &aics_insts[i];
50 		}
51 	}
52 
53 	LOG_DBG("Could not find AICS instance with handle 0x%04x", handle);
54 
55 	return NULL;
56 }
57 
aics_client_notify_handler(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)58 uint8_t aics_client_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
59 				   const void *data, uint16_t length)
60 {
61 	uint16_t handle = params->value_handle;
62 	struct bt_aics *inst;
63 	struct bt_aics_state *state;
64 	uint8_t *status;
65 
66 	if (conn == NULL) {
67 		return BT_GATT_ITER_CONTINUE;
68 	}
69 
70 	inst = lookup_aics_by_handle(conn, handle);
71 
72 	if (!inst) {
73 		LOG_DBG("Instance not found");
74 		return BT_GATT_ITER_STOP;
75 	}
76 
77 	if (!data || !length) {
78 		return BT_GATT_ITER_CONTINUE;
79 	}
80 
81 	if (handle == inst->cli.state_handle) {
82 		if (length == sizeof(*state)) {
83 			state = (struct bt_aics_state *)data;
84 			LOG_DBG("Inst %p: Gain %d, mute %u, gain_mode %u, counter %u", inst,
85 				state->gain, state->mute, state->gain_mode, state->change_counter);
86 
87 			inst->cli.change_counter = state->change_counter;
88 
89 			if (inst->cli.cb && inst->cli.cb->state) {
90 				inst->cli.cb->state(inst, 0, state->gain,
91 						    state->mute,
92 						    state->gain_mode);
93 			}
94 		}
95 	} else if (handle == inst->cli.status_handle) {
96 		if (length == sizeof(*status)) {
97 			status = (uint8_t *)data;
98 			LOG_DBG("Inst %p: Status %u", inst, *status);
99 			if (inst->cli.cb && inst->cli.cb->status) {
100 				inst->cli.cb->status(inst, 0, *status);
101 			}
102 		}
103 	} else if (handle == inst->cli.desc_handle) {
104 		char desc[MIN(BT_L2CAP_RX_MTU, BT_ATT_MAX_ATTRIBUTE_LEN) + 1];
105 
106 		/* Truncate if too large */
107 		if (length > sizeof(desc) - 1) {
108 			LOG_DBG("Description truncated from %u to %zu octets", length,
109 				sizeof(desc) - 1);
110 		}
111 		length = MIN(sizeof(desc) - 1, length);
112 
113 		memcpy(desc, data, length);
114 		desc[length] = '\0';
115 		LOG_DBG("Inst %p: Input description: %s", inst, desc);
116 		if (inst->cli.cb && inst->cli.cb->description) {
117 			inst->cli.cb->description(inst, 0, desc);
118 		}
119 	}
120 
121 	return BT_GATT_ITER_CONTINUE;
122 }
123 
aics_client_read_state_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)124 static uint8_t aics_client_read_state_cb(struct bt_conn *conn, uint8_t err,
125 					 struct bt_gatt_read_params *params,
126 					 const void *data, uint16_t length)
127 {
128 	int cb_err = err;
129 	struct bt_aics *inst = lookup_aics_by_handle(conn, params->single.handle);
130 	struct bt_aics_state *state = (struct bt_aics_state *)data;
131 
132 	memset(params, 0, sizeof(*params));
133 
134 	if (!inst) {
135 		LOG_DBG("Instance not found");
136 		return BT_GATT_ITER_STOP;
137 	}
138 
139 	LOG_DBG("Inst %p: err: 0x%02X", inst, err);
140 	atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
141 
142 	if (cb_err) {
143 		LOG_DBG("State read failed: %d", err);
144 		if (inst->cli.cb && inst->cli.cb->state) {
145 			inst->cli.cb->state(inst, cb_err, 0, 0, 0);
146 		}
147 		return BT_GATT_ITER_STOP;
148 	}
149 
150 	if (data) {
151 		if (length == sizeof(*state)) {
152 			LOG_DBG("Gain %d, mute %u, gain_mode %u, counter %u", state->gain,
153 				state->mute, state->gain_mode, state->change_counter);
154 
155 			inst->cli.change_counter = state->change_counter;
156 		} else {
157 			LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*state));
158 			cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
159 		}
160 	} else {
161 		LOG_DBG("Invalid state");
162 		cb_err = BT_ATT_ERR_UNLIKELY;
163 	}
164 
165 	if (inst->cli.cb && inst->cli.cb->state) {
166 		inst->cli.cb->state(inst, cb_err, state->gain,
167 				    state->mute, state->gain_mode);
168 	}
169 
170 	return BT_GATT_ITER_STOP;
171 }
172 
aics_client_read_gain_settings_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)173 static uint8_t aics_client_read_gain_settings_cb(struct bt_conn *conn, uint8_t err,
174 						 struct bt_gatt_read_params *params,
175 						 const void *data, uint16_t length)
176 {
177 	int cb_err = err;
178 	struct bt_aics *inst = lookup_aics_by_handle(conn, params->single.handle);
179 	struct bt_aics_gain_settings *gain_settings = (struct bt_aics_gain_settings *)data;
180 
181 	memset(params, 0, sizeof(*params));
182 
183 	if (!inst) {
184 		LOG_DBG("Instance not found");
185 		return BT_GATT_ITER_STOP;
186 	}
187 
188 	LOG_DBG("Inst %p: err: 0x%02X", inst, err);
189 	atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
190 
191 	if (cb_err) {
192 		LOG_DBG("Gain settings read failed: %d", err);
193 		if (inst->cli.cb && inst->cli.cb->gain_setting) {
194 			inst->cli.cb->gain_setting(inst, cb_err, 0, 0, 0);
195 		}
196 		return BT_GATT_ITER_STOP;
197 	}
198 
199 	if (data) {
200 		if (length == sizeof(*gain_settings)) {
201 			LOG_DBG("Units %u, Max %d, Min %d", gain_settings->units,
202 				gain_settings->maximum, gain_settings->minimum);
203 		} else {
204 			LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*gain_settings));
205 			cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
206 		}
207 	} else {
208 		LOG_DBG("Invalid gain settings");
209 		cb_err = BT_ATT_ERR_UNLIKELY;
210 	}
211 
212 	if (inst->cli.cb && inst->cli.cb->gain_setting) {
213 		inst->cli.cb->gain_setting(inst, cb_err, gain_settings->units,
214 					   gain_settings->minimum,
215 					   gain_settings->maximum);
216 	}
217 
218 	return BT_GATT_ITER_STOP;
219 }
220 
aics_client_read_type_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)221 static uint8_t aics_client_read_type_cb(struct bt_conn *conn, uint8_t err,
222 					struct bt_gatt_read_params *params,
223 					const void *data, uint16_t length)
224 {
225 	int cb_err = err;
226 	uint8_t *type = (uint8_t *)data;
227 	struct bt_aics *inst = lookup_aics_by_handle(conn, params->single.handle);
228 
229 	memset(params, 0, sizeof(*params));
230 
231 	if (!inst) {
232 		LOG_DBG("Instance not found");
233 		return BT_GATT_ITER_STOP;
234 	}
235 
236 	LOG_DBG("Inst %p: err: 0x%02X", inst, err);
237 	atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
238 
239 	if (cb_err) {
240 		LOG_DBG("Type read failed: %d", err);
241 		if (inst->cli.cb && inst->cli.cb->type) {
242 			inst->cli.cb->type(inst, cb_err, 0);
243 		}
244 		return BT_GATT_ITER_STOP;
245 	}
246 
247 	if (data) {
248 		if (length == sizeof(*type)) {
249 			LOG_DBG("Type %u", *type);
250 		} else {
251 			LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*type));
252 			cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
253 		}
254 	} else {
255 		LOG_DBG("Invalid type");
256 		cb_err = BT_ATT_ERR_UNLIKELY;
257 	}
258 
259 	if (inst->cli.cb && inst->cli.cb->type) {
260 		inst->cli.cb->type(inst, cb_err, *type);
261 	}
262 
263 	return BT_GATT_ITER_STOP;
264 }
265 
aics_client_read_status_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)266 static uint8_t aics_client_read_status_cb(struct bt_conn *conn, uint8_t err,
267 					  struct bt_gatt_read_params *params,
268 					  const void *data, uint16_t length)
269 {
270 	int cb_err = err;
271 	uint8_t *status = (uint8_t *)data;
272 	struct bt_aics *inst = lookup_aics_by_handle(conn, params->single.handle);
273 
274 	memset(params, 0, sizeof(*params));
275 
276 	if (!inst) {
277 		LOG_DBG("Instance not found");
278 		return BT_GATT_ITER_STOP;
279 	}
280 
281 	LOG_DBG("Inst %p: err: 0x%02X", inst, err);
282 	atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
283 
284 	if (cb_err) {
285 		LOG_DBG("Status read failed: %d", err);
286 		if (inst->cli.cb && inst->cli.cb->status) {
287 			inst->cli.cb->status(inst, cb_err, 0);
288 		}
289 		return BT_GATT_ITER_STOP;
290 	}
291 
292 	if (data) {
293 		if (length == sizeof(*status)) {
294 			LOG_DBG("Status %u", *status);
295 		} else {
296 			LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*status));
297 			cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
298 		}
299 	} else {
300 		LOG_DBG("Invalid status");
301 		cb_err = BT_ATT_ERR_UNLIKELY;
302 	}
303 
304 	if (inst->cli.cb && inst->cli.cb->status) {
305 		inst->cli.cb->status(inst, cb_err, *status);
306 	}
307 
308 	return BT_GATT_ITER_STOP;
309 }
310 
aics_cp_notify_app(struct bt_aics * inst,uint8_t err)311 static void aics_cp_notify_app(struct bt_aics *inst, uint8_t err)
312 {
313 	if (!inst->cli.cb) {
314 		return;
315 	}
316 
317 	switch (inst->cli.cp_val.cp.opcode) {
318 	case BT_AICS_OPCODE_SET_GAIN:
319 		if (inst->cli.cb->set_gain) {
320 			inst->cli.cb->set_gain(inst, err);
321 		}
322 		break;
323 	case BT_AICS_OPCODE_UNMUTE:
324 		if (inst->cli.cb->unmute) {
325 			inst->cli.cb->unmute(inst, err);
326 		}
327 		break;
328 	case BT_AICS_OPCODE_MUTE:
329 		if (inst->cli.cb->mute) {
330 			inst->cli.cb->mute(inst, err);
331 		}
332 		break;
333 	case BT_AICS_OPCODE_SET_MANUAL:
334 		if (inst->cli.cb->set_manual_mode) {
335 			inst->cli.cb->set_manual_mode(inst, err);
336 		}
337 		break;
338 	case BT_AICS_OPCODE_SET_AUTO:
339 		if (inst->cli.cb->set_auto_mode) {
340 			inst->cli.cb->set_auto_mode(inst, err);
341 		}
342 		break;
343 	default:
344 		LOG_DBG("Unknown opcode 0x%02x", inst->cli.cp_val.cp.opcode);
345 		break;
346 	}
347 }
348 
internal_read_state_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)349 static uint8_t internal_read_state_cb(struct bt_conn *conn, uint8_t err,
350 				      struct bt_gatt_read_params *params,
351 				      const void *data, uint16_t length)
352 {
353 	int cb_err = err;
354 	struct bt_aics *inst = lookup_aics_by_handle(conn, params->single.handle);
355 	struct bt_aics_state *state = (struct bt_aics_state *)data;
356 
357 	memset(params, 0, sizeof(*params));
358 
359 	if (!inst) {
360 		LOG_ERR("Instance not found");
361 		return BT_GATT_ITER_STOP;
362 	}
363 
364 	if (err) {
365 		LOG_WRN("State read failed: %d", err);
366 	} else if (data) {
367 		if (length == sizeof(*state)) {
368 			int write_err;
369 
370 			LOG_DBG("Gain %d, mute %u, gain_mode %u, counter %u", state->gain,
371 				state->mute, state->gain_mode, state->change_counter);
372 			inst->cli.change_counter = state->change_counter;
373 
374 			/* clear busy flag to reuse function */
375 			atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
376 
377 			if (inst->cli.cp_val.cp.opcode == BT_AICS_OPCODE_SET_GAIN) {
378 				write_err = bt_aics_client_gain_set(inst,
379 								    inst->cli.cp_val.gain_setting);
380 			} else {
381 				write_err = aics_client_common_control(inst->cli.cp_val.cp.opcode,
382 								       inst);
383 			}
384 
385 			if (write_err) {
386 				cb_err = BT_ATT_ERR_UNLIKELY;
387 			}
388 		} else {
389 			LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*state));
390 			cb_err = BT_ATT_ERR_UNLIKELY;
391 		}
392 	}
393 
394 	if (cb_err) {
395 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
396 		aics_cp_notify_app(inst, cb_err);
397 	}
398 
399 	return BT_GATT_ITER_STOP;
400 }
401 
402 
aics_client_write_aics_cp_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)403 static void aics_client_write_aics_cp_cb(struct bt_conn *conn, uint8_t err,
404 					 struct bt_gatt_write_params *params)
405 {
406 	int cb_err = err;
407 	struct bt_aics *inst = lookup_aics_by_handle(conn, params->handle);
408 
409 	memset(params, 0, sizeof(*params));
410 
411 	if (!inst) {
412 		LOG_DBG("Instance not found");
413 		return;
414 	}
415 
416 	LOG_DBG("Inst %p: err: %d", inst, cb_err);
417 
418 	/* If the change counter is out of data when a write was attempted from
419 	 * the application, we automatically initiate a read to get the newest
420 	 * state and try again. Once the change counter has been read, we
421 	 * restart the applications write request. If it fails
422 	 * the second time, we return an error to the application.
423 	 */
424 	if (cb_err == BT_AICS_ERR_INVALID_COUNTER &&
425 	    atomic_test_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_CP_RETRIED)) {
426 		cb_err = BT_ATT_ERR_UNLIKELY;
427 	} else if (cb_err == BT_AICS_ERR_INVALID_COUNTER && inst->cli.state_handle) {
428 		inst->cli.read_params.func = internal_read_state_cb;
429 		inst->cli.read_params.handle_count = 1;
430 		inst->cli.read_params.single.handle = inst->cli.state_handle;
431 		inst->cli.read_params.single.offset = 0U;
432 
433 		atomic_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_CP_RETRIED);
434 
435 		cb_err = bt_gatt_read(conn, &inst->cli.read_params);
436 		if (cb_err != 0) {
437 			LOG_WRN("Could not read state: %d", cb_err);
438 		} else {
439 			/* Wait for read callback */
440 			return;
441 		}
442 	}
443 
444 	atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_CP_RETRIED);
445 	atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
446 
447 	aics_cp_notify_app(inst, cb_err);
448 }
449 
aics_client_common_control(uint8_t opcode,struct bt_aics * inst)450 static int aics_client_common_control(uint8_t opcode, struct bt_aics *inst)
451 {
452 	int err;
453 
454 	CHECKIF(!inst) {
455 		LOG_DBG("NULL instance");
456 		return -EINVAL;
457 	}
458 
459 	CHECKIF(!inst->client_instance) {
460 		LOG_DBG("Not a client instance instance");
461 		return -EINVAL;
462 	}
463 
464 	CHECKIF(inst->cli.conn == NULL) {
465 		LOG_DBG("NULL conn");
466 		return -EINVAL;
467 	}
468 
469 	if (!inst->cli.control_handle) {
470 		LOG_DBG("Handle not set for opcode %u", opcode);
471 		return -EINVAL;
472 	} else if (atomic_test_and_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY)) {
473 		return -EBUSY;
474 	}
475 
476 	inst->cli.cp_val.cp.opcode = opcode;
477 	inst->cli.cp_val.cp.counter = inst->cli.change_counter;
478 
479 	inst->cli.write_params.offset = 0;
480 	inst->cli.write_params.data = &inst->cli.cp_val.cp;
481 	inst->cli.write_params.length = sizeof(inst->cli.cp_val.cp);
482 	inst->cli.write_params.handle = inst->cli.control_handle;
483 	inst->cli.write_params.func = aics_client_write_aics_cp_cb;
484 
485 	err = bt_gatt_write(inst->cli.conn, &inst->cli.write_params);
486 	if (err != 0) {
487 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
488 	}
489 
490 	return err;
491 }
492 
aics_client_read_desc_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)493 static uint8_t aics_client_read_desc_cb(struct bt_conn *conn, uint8_t err,
494 					struct bt_gatt_read_params *params,
495 					const void *data, uint16_t length)
496 {
497 	int cb_err = err;
498 	char desc[MIN(BT_L2CAP_RX_MTU, BT_ATT_MAX_ATTRIBUTE_LEN) + 1];
499 	struct bt_aics *inst = lookup_aics_by_handle(conn, params->single.handle);
500 
501 	memset(params, 0, sizeof(*params));
502 
503 	if (!inst) {
504 		LOG_DBG("Instance not found");
505 		return BT_GATT_ITER_STOP;
506 	}
507 
508 	atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
509 
510 	if (cb_err) {
511 		LOG_DBG("Description read failed: %d", err);
512 		if (inst->cli.cb && inst->cli.cb->description) {
513 			inst->cli.cb->description(inst, cb_err, NULL);
514 		}
515 		return BT_GATT_ITER_STOP;
516 	}
517 
518 	if (data) {
519 		LOG_HEXDUMP_DBG(data, length, "Input description read");
520 
521 		/* Truncate if too large */
522 		if (length > sizeof(desc) - 1) {
523 			LOG_DBG("Description truncated from %u to %zu octets", length,
524 				sizeof(desc) - 1);
525 		}
526 		length = MIN(sizeof(desc) - 1, length);
527 
528 		/* TODO: Handle long reads */
529 
530 		memcpy(desc, data, length);
531 	}
532 
533 	desc[length] = '\0';
534 	LOG_DBG("Input description: %s", desc);
535 
536 	if (inst->cli.cb && inst->cli.cb->description) {
537 		inst->cli.cb->description(inst, cb_err, desc);
538 	}
539 
540 	return BT_GATT_ITER_STOP;
541 }
542 
valid_inst_discovered(struct bt_aics * inst)543 static bool valid_inst_discovered(struct bt_aics *inst)
544 {
545 	return inst->cli.state_handle &&
546 	       inst->cli.gain_handle &&
547 	       inst->cli.type_handle &&
548 	       inst->cli.status_handle &&
549 	       inst->cli.control_handle &&
550 	       inst->cli.desc_handle;
551 }
552 
aics_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)553 static uint8_t aics_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
554 				  struct bt_gatt_discover_params *params)
555 {
556 	struct bt_aics_client *client_inst = CONTAINER_OF(params,
557 							  struct bt_aics_client,
558 							  discover_params);
559 	struct bt_aics *inst = CONTAINER_OF(client_inst, struct bt_aics, cli);
560 
561 	if (!attr) {
562 		LOG_DBG("Discovery complete for AICS %p", inst);
563 
564 		memset(params, 0, sizeof(*params));
565 
566 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
567 
568 		if (inst->cli.cb && inst->cli.cb->discover) {
569 			int err = valid_inst_discovered(inst) ? 0 : -ENOENT;
570 
571 			inst->cli.cb->discover(inst, err);
572 		}
573 
574 		return BT_GATT_ITER_STOP;
575 	}
576 
577 	LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
578 
579 	if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) {
580 		struct bt_gatt_subscribe_params *sub_params = NULL;
581 		struct bt_gatt_chrc *chrc;
582 
583 		chrc = (struct bt_gatt_chrc *)attr->user_data;
584 		if (inst->cli.start_handle == 0) {
585 			inst->cli.start_handle = chrc->value_handle;
586 		}
587 		inst->cli.end_handle = chrc->value_handle;
588 
589 		if (!bt_uuid_cmp(chrc->uuid, BT_UUID_AICS_STATE)) {
590 			LOG_DBG("Audio Input state");
591 			inst->cli.state_handle = chrc->value_handle;
592 			sub_params = &inst->cli.state_sub_params;
593 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_AICS_GAIN_SETTINGS)) {
594 			LOG_DBG("Gain settings");
595 			inst->cli.gain_handle = chrc->value_handle;
596 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_AICS_INPUT_TYPE)) {
597 			LOG_DBG("Input type");
598 			inst->cli.type_handle = chrc->value_handle;
599 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_AICS_INPUT_STATUS)) {
600 			LOG_DBG("Input status");
601 			inst->cli.status_handle = chrc->value_handle;
602 			sub_params = &inst->cli.status_sub_params;
603 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_AICS_CONTROL)) {
604 			LOG_DBG("Control point");
605 			inst->cli.control_handle = chrc->value_handle;
606 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_AICS_DESCRIPTION)) {
607 			LOG_DBG("Description");
608 			inst->cli.desc_handle = chrc->value_handle;
609 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
610 				sub_params = &inst->cli.desc_sub_params;
611 			}
612 
613 			if (chrc->properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) {
614 				atomic_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_DESC_WRITABLE);
615 			}
616 		}
617 
618 		if (sub_params) {
619 			int err;
620 
621 			sub_params->value = BT_GATT_CCC_NOTIFY;
622 			sub_params->value_handle = chrc->value_handle;
623 			/*
624 			 * TODO: Don't assume that CCC is at handle + 2;
625 			 * do proper discovery;
626 			 */
627 			sub_params->ccc_handle = attr->handle + 2;
628 			sub_params->notify = aics_client_notify_handler;
629 			atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
630 
631 			err = bt_gatt_subscribe(conn, sub_params);
632 			if (err != 0 && err != -EALREADY) {
633 				LOG_ERR("Failed to subscribe: %d", err);
634 
635 				if (inst->cli.cb && inst->cli.cb->discover) {
636 					inst->cli.cb->discover(inst, err);
637 				}
638 
639 				return BT_GATT_ITER_STOP;
640 			}
641 		}
642 	}
643 
644 	return BT_GATT_ITER_CONTINUE;
645 }
646 
aics_client_reset(struct bt_aics * inst)647 static void aics_client_reset(struct bt_aics *inst)
648 {
649 	inst->cli.change_counter = 0;
650 	inst->cli.gain_mode = 0;
651 	inst->cli.start_handle = 0;
652 	inst->cli.end_handle = 0;
653 	inst->cli.state_handle = 0;
654 	inst->cli.gain_handle = 0;
655 	inst->cli.type_handle = 0;
656 	inst->cli.status_handle = 0;
657 	inst->cli.control_handle = 0;
658 	inst->cli.desc_handle = 0;
659 
660 	atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_DESC_WRITABLE);
661 	atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_CP_RETRIED);
662 
663 	if (inst->cli.conn != NULL) {
664 		struct bt_conn *conn = inst->cli.conn;
665 
666 		bt_conn_unref(conn);
667 		inst->cli.conn = NULL;
668 	}
669 }
670 
disconnected(struct bt_conn * conn,uint8_t reason)671 static void disconnected(struct bt_conn *conn, uint8_t reason)
672 {
673 	for (size_t i = 0; i < ARRAY_SIZE(aics_insts); i++) {
674 		if (aics_insts[i].cli.conn == conn) {
675 			aics_client_reset(&aics_insts[i]);
676 		}
677 	}
678 }
679 
680 BT_CONN_CB_DEFINE(conn_callbacks) = {
681 	.disconnected = disconnected,
682 };
683 
bt_aics_discover(struct bt_conn * conn,struct bt_aics * inst,const struct bt_aics_discover_param * param)684 int bt_aics_discover(struct bt_conn *conn, struct bt_aics *inst,
685 		     const struct bt_aics_discover_param *param)
686 {
687 	int err = 0;
688 
689 	CHECKIF(!inst || !conn || !param) {
690 		LOG_DBG("%s cannot be NULL", inst == NULL   ? "inst"
691 					     : conn == NULL ? "conn"
692 							    : "param");
693 		return -EINVAL;
694 	}
695 
696 	CHECKIF(param->end_handle <= param->start_handle) {
697 		LOG_DBG("start_handle (%u) shall be less than end_handle (%u)", param->start_handle,
698 			param->end_handle);
699 		return -EINVAL;
700 	}
701 
702 	CHECKIF(!atomic_test_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_ACTIVE)) {
703 		LOG_DBG("Inactive instance");
704 		return -EINVAL;
705 	}
706 
707 	if (atomic_test_and_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY)) {
708 		LOG_DBG("Instance is busy");
709 		return -EBUSY;
710 	}
711 
712 	aics_client_reset(inst);
713 
714 	(void)memset(&inst->cli.discover_params, 0, sizeof(inst->cli.discover_params));
715 
716 	inst->cli.discover_params.start_handle = param->start_handle;
717 	inst->cli.discover_params.end_handle = param->end_handle;
718 	inst->cli.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
719 	inst->cli.discover_params.func = aics_discover_func;
720 
721 	err = bt_gatt_discover(conn, &inst->cli.discover_params);
722 	if (err != 0) {
723 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
724 		LOG_DBG("Discover failed (err %d)", err);
725 	} else {
726 		inst->cli.conn = bt_conn_ref(conn);
727 	}
728 
729 	return err;
730 }
731 
bt_aics_client_free_instance_get(void)732 struct bt_aics *bt_aics_client_free_instance_get(void)
733 {
734 	for (int i = 0; i < ARRAY_SIZE(aics_insts); i++) {
735 		if (!atomic_test_and_set_bit(aics_insts[i].cli.flags, BT_AICS_CLIENT_FLAG_ACTIVE)) {
736 			aics_insts[i].client_instance = true;
737 			return &aics_insts[i];
738 		}
739 	}
740 
741 	return NULL;
742 }
743 
bt_aics_client_conn_get(const struct bt_aics * aics,struct bt_conn ** conn)744 int bt_aics_client_conn_get(const struct bt_aics *aics, struct bt_conn **conn)
745 {
746 	CHECKIF(aics == NULL) {
747 		LOG_DBG("NULL aics pointer");
748 		return -EINVAL;
749 	}
750 
751 	if (!aics->client_instance) {
752 		LOG_DBG("aics pointer shall be client instance");
753 		return -EINVAL;
754 	}
755 
756 	if (aics->cli.conn == NULL) {
757 		LOG_DBG("aics pointer not associated with a connection. "
758 		       "Do discovery first");
759 		return -ENOTCONN;
760 	}
761 
762 	*conn = aics->cli.conn;
763 	return 0;
764 }
765 
bt_aics_client_state_get(struct bt_aics * inst)766 int bt_aics_client_state_get(struct bt_aics *inst)
767 {
768 	int err;
769 
770 	CHECKIF(!inst) {
771 		LOG_DBG("NULL instance");
772 		return -EINVAL;
773 	}
774 
775 	CHECKIF(!inst->client_instance) {
776 		LOG_DBG("Not a client instance instance");
777 		return -EINVAL;
778 	}
779 
780 	CHECKIF(inst->cli.conn == NULL) {
781 		LOG_DBG("NULL conn");
782 		return -EINVAL;
783 	}
784 
785 	if (!inst->cli.state_handle) {
786 		LOG_DBG("Handle not set");
787 		return -EINVAL;
788 	} else if (atomic_test_and_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY)) {
789 		return -EBUSY;
790 	}
791 
792 	inst->cli.read_params.func = aics_client_read_state_cb;
793 	inst->cli.read_params.handle_count = 1;
794 	inst->cli.read_params.single.handle = inst->cli.state_handle;
795 
796 	err = bt_gatt_read(inst->cli.conn, &inst->cli.read_params);
797 	if (err != 0) {
798 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
799 	}
800 
801 	return err;
802 }
803 
bt_aics_client_gain_setting_get(struct bt_aics * inst)804 int bt_aics_client_gain_setting_get(struct bt_aics *inst)
805 {
806 	int err;
807 
808 	CHECKIF(!inst) {
809 		LOG_DBG("NULL instance");
810 		return -EINVAL;
811 	}
812 
813 	CHECKIF(!inst->client_instance) {
814 		LOG_DBG("Not a client instance instance");
815 		return -EINVAL;
816 	}
817 
818 	CHECKIF(inst->cli.conn == NULL) {
819 		LOG_DBG("NULL conn");
820 		return -EINVAL;
821 	}
822 
823 	if (!inst->cli.gain_handle) {
824 		LOG_DBG("Handle not set");
825 		return -EINVAL;
826 	} else if (atomic_test_and_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY)) {
827 		return -EBUSY;
828 	}
829 
830 	inst->cli.read_params.func = aics_client_read_gain_settings_cb;
831 	inst->cli.read_params.handle_count = 1;
832 	inst->cli.read_params.single.handle = inst->cli.gain_handle;
833 
834 	err = bt_gatt_read(inst->cli.conn, &inst->cli.read_params);
835 	if (err != 0) {
836 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
837 	}
838 
839 	return err;
840 }
841 
bt_aics_client_type_get(struct bt_aics * inst)842 int bt_aics_client_type_get(struct bt_aics *inst)
843 {
844 	int err;
845 
846 	CHECKIF(!inst) {
847 		LOG_DBG("NULL instance");
848 		return -EINVAL;
849 	}
850 
851 	CHECKIF(!inst->client_instance) {
852 		LOG_DBG("Not a client instance instance");
853 		return -EINVAL;
854 	}
855 
856 	CHECKIF(inst->cli.conn == NULL) {
857 		LOG_DBG("NULL conn");
858 		return -EINVAL;
859 	}
860 
861 	if (!inst->cli.type_handle) {
862 		LOG_DBG("Handle not set");
863 		return -EINVAL;
864 	} else if (atomic_test_and_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY)) {
865 		return -EBUSY;
866 	}
867 
868 	inst->cli.read_params.func = aics_client_read_type_cb;
869 	inst->cli.read_params.handle_count = 1;
870 	inst->cli.read_params.single.handle = inst->cli.type_handle;
871 
872 	err = bt_gatt_read(inst->cli.conn, &inst->cli.read_params);
873 	if (err != 0) {
874 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
875 	}
876 
877 	return err;
878 }
879 
bt_aics_client_status_get(struct bt_aics * inst)880 int bt_aics_client_status_get(struct bt_aics *inst)
881 {
882 	int err;
883 
884 	CHECKIF(!inst) {
885 		LOG_DBG("NULL instance");
886 		return -EINVAL;
887 	}
888 
889 	CHECKIF(!inst->client_instance) {
890 		LOG_DBG("Not a client instance instance");
891 		return -EINVAL;
892 	}
893 
894 	CHECKIF(inst->cli.conn == NULL) {
895 		LOG_DBG("NULL conn");
896 		return -EINVAL;
897 	}
898 
899 	if (!inst->cli.status_handle) {
900 		LOG_DBG("Handle not set");
901 		return -EINVAL;
902 	} else if (atomic_test_and_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY)) {
903 		return -EBUSY;
904 	}
905 
906 	inst->cli.read_params.func = aics_client_read_status_cb;
907 	inst->cli.read_params.handle_count = 1;
908 	inst->cli.read_params.single.handle = inst->cli.status_handle;
909 
910 	err = bt_gatt_read(inst->cli.conn, &inst->cli.read_params);
911 	if (err != 0) {
912 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
913 	}
914 
915 	return err;
916 }
917 
bt_aics_client_unmute(struct bt_aics * inst)918 int bt_aics_client_unmute(struct bt_aics *inst)
919 {
920 	return aics_client_common_control(BT_AICS_OPCODE_UNMUTE, inst);
921 }
922 
bt_aics_client_mute(struct bt_aics * inst)923 int bt_aics_client_mute(struct bt_aics *inst)
924 {
925 	return aics_client_common_control(BT_AICS_OPCODE_MUTE, inst);
926 }
927 
bt_aics_client_manual_gain_set(struct bt_aics * inst)928 int bt_aics_client_manual_gain_set(struct bt_aics *inst)
929 {
930 	return aics_client_common_control(BT_AICS_OPCODE_SET_MANUAL, inst);
931 }
932 
bt_aics_client_automatic_gain_set(struct bt_aics * inst)933 int bt_aics_client_automatic_gain_set(struct bt_aics *inst)
934 {
935 	return aics_client_common_control(BT_AICS_OPCODE_SET_AUTO, inst);
936 }
937 
bt_aics_client_gain_set(struct bt_aics * inst,int8_t gain)938 int bt_aics_client_gain_set(struct bt_aics *inst, int8_t gain)
939 {
940 	int err;
941 
942 	CHECKIF(!inst) {
943 		LOG_DBG("NULL instance");
944 		return -EINVAL;
945 	}
946 
947 	CHECKIF(!inst->client_instance) {
948 		LOG_DBG("Not a client instance instance");
949 		return -EINVAL;
950 	}
951 
952 	CHECKIF(inst->cli.conn == NULL) {
953 		LOG_DBG("NULL conn");
954 		return -EINVAL;
955 	}
956 
957 	if (!inst->cli.control_handle) {
958 		LOG_DBG("Handle not set");
959 		return -EINVAL;
960 	} else if (atomic_test_and_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY)) {
961 		return -EBUSY;
962 	}
963 
964 	inst->cli.cp_val.cp.opcode = BT_AICS_OPCODE_SET_GAIN;
965 	inst->cli.cp_val.cp.counter = inst->cli.change_counter;
966 	inst->cli.cp_val.gain_setting = gain;
967 
968 	inst->cli.write_params.data = &inst->cli.cp_val;
969 	inst->cli.write_params.length = sizeof(inst->cli.cp_val);
970 	inst->cli.write_params.handle = inst->cli.control_handle;
971 	inst->cli.write_params.func = aics_client_write_aics_cp_cb;
972 
973 	err = bt_gatt_write(inst->cli.conn, &inst->cli.write_params);
974 	if (err != 0) {
975 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
976 	}
977 
978 	return err;
979 }
980 
bt_aics_client_description_get(struct bt_aics * inst)981 int bt_aics_client_description_get(struct bt_aics *inst)
982 {
983 	int err;
984 
985 	CHECKIF(!inst) {
986 		LOG_DBG("NULL instance");
987 		return -EINVAL;
988 	}
989 
990 	CHECKIF(!inst->client_instance) {
991 		LOG_DBG("Not a client instance instance");
992 		return -EINVAL;
993 	}
994 
995 	CHECKIF(inst->cli.conn == NULL) {
996 		LOG_DBG("NULL conn");
997 		return -EINVAL;
998 	}
999 
1000 	if (!inst->cli.desc_handle) {
1001 		LOG_DBG("Handle not set");
1002 		return -EINVAL;
1003 	} else if (atomic_test_and_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY)) {
1004 		return -EBUSY;
1005 	}
1006 
1007 	inst->cli.read_params.func = aics_client_read_desc_cb;
1008 	inst->cli.read_params.handle_count = 1;
1009 	inst->cli.read_params.single.handle = inst->cli.desc_handle;
1010 
1011 	err = bt_gatt_read(inst->cli.conn, &inst->cli.read_params);
1012 	if (err != 0) {
1013 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
1014 	}
1015 
1016 	return err;
1017 }
1018 
bt_aics_client_description_set(struct bt_aics * inst,const char * description)1019 int bt_aics_client_description_set(struct bt_aics *inst,
1020 				   const char *description)
1021 {
1022 	int err;
1023 
1024 	CHECKIF(!inst) {
1025 		LOG_DBG("NULL instance");
1026 		return -EINVAL;
1027 	}
1028 
1029 	CHECKIF(!inst->client_instance) {
1030 		LOG_DBG("Not a client instance instance");
1031 		return -EINVAL;
1032 	}
1033 
1034 	CHECKIF(inst->cli.conn == NULL) {
1035 		LOG_DBG("NULL conn");
1036 		return -EINVAL;
1037 	}
1038 
1039 	if (!inst->cli.desc_handle) {
1040 		LOG_DBG("Handle not set");
1041 		return -EINVAL;
1042 	} else if (!atomic_test_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_DESC_WRITABLE)) {
1043 		LOG_DBG("Description is not writable on peer service instance");
1044 		return -EPERM;
1045 	} else if (atomic_test_and_set_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY)) {
1046 		return -EBUSY;
1047 	}
1048 
1049 	err = bt_gatt_write_without_response(inst->cli.conn, inst->cli.desc_handle, description,
1050 					     strlen(description), false);
1051 	if (err != 0) {
1052 		atomic_clear_bit(inst->cli.flags, BT_AICS_CLIENT_FLAG_BUSY);
1053 	}
1054 
1055 	return err;
1056 }
1057 
bt_aics_client_cb_register(struct bt_aics * inst,struct bt_aics_cb * cb)1058 void bt_aics_client_cb_register(struct bt_aics *inst, struct bt_aics_cb *cb)
1059 {
1060 	CHECKIF(!inst) {
1061 		LOG_DBG("inst cannot be NULL");
1062 		return;
1063 	}
1064 
1065 	inst->cli.cb = cb;
1066 }
1067