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