1 /*
2  * Copyright (c) 2020 Bose Corporation
3  * Copyright (c) 2020 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/kernel.h>
9 #include <zephyr/sys/byteorder.h>
10 #include <zephyr/sys/check.h>
11 
12 #include <zephyr/device.h>
13 #include <zephyr/init.h>
14 
15 #include <zephyr/bluetooth/bluetooth.h>
16 #include <zephyr/bluetooth/conn.h>
17 #include <zephyr/bluetooth/gatt.h>
18 #include <zephyr/bluetooth/audio/aics.h>
19 
20 #include "aics_internal.h"
21 #include "audio_internal.h"
22 
23 #define LOG_LEVEL CONFIG_BT_AICS_LOG_LEVEL
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_REGISTER(bt_aics);
26 
27 #define VALID_AICS_OPCODE(opcode)                                              \
28 	((opcode) >= BT_AICS_OPCODE_SET_GAIN && (opcode) <= BT_AICS_OPCODE_SET_AUTO)
29 
30 #define AICS_CP_LEN                 0x02
31 #define AICS_CP_SET_GAIN_LEN        0x03
32 
33 
34 static ssize_t write_description(struct bt_conn *conn,
35 				 const struct bt_gatt_attr *attr,
36 				 const void *buf, uint16_t len, uint16_t offset,
37 				 uint8_t flags);
38 
39 static ssize_t write_aics_control(struct bt_conn *conn,
40 				  const struct bt_gatt_attr *attr,
41 				  const void *buf, uint16_t len,
42 				  uint16_t offset, uint8_t flags);
43 
44 #if defined(CONFIG_BT_AICS)
45 static void aics_state_cfg_changed(const struct bt_gatt_attr *attr,
46 				   uint16_t value);
47 static ssize_t read_aics_state(struct bt_conn *conn,
48 			       const struct bt_gatt_attr *attr,
49 			       void *buf, uint16_t len, uint16_t offset);
50 static ssize_t read_aics_gain_settings(struct bt_conn *conn,
51 				       const struct bt_gatt_attr *attr,
52 				       void *buf, uint16_t len,
53 				       uint16_t offset);
54 static ssize_t read_type(struct bt_conn *conn, const struct bt_gatt_attr *attr,
55 			 void *buf, uint16_t len, uint16_t offset);
56 static void aics_input_status_cfg_changed(const struct bt_gatt_attr *attr,
57 					  uint16_t value);
58 static ssize_t read_input_status(struct bt_conn *conn,
59 				 const struct bt_gatt_attr *attr,
60 				 void *buf, uint16_t len, uint16_t offset);
61 static void aics_description_cfg_changed(const struct bt_gatt_attr *attr,
62 					 uint16_t value);
63 static ssize_t read_description(struct bt_conn *conn,
64 				const struct bt_gatt_attr *attr, void *buf,
65 				uint16_t len, uint16_t offset);
66 
67 #define BT_AICS_SERVICE_DEFINITION(_aics) {                                    \
68 	BT_GATT_SECONDARY_SERVICE(BT_UUID_AICS),                               \
69 	BT_AUDIO_CHRC(BT_UUID_AICS_STATE,                                      \
70 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,                 \
71 		      BT_GATT_PERM_READ_ENCRYPT,                               \
72 		      read_aics_state, NULL, &_aics),                          \
73 	BT_AUDIO_CCC(aics_state_cfg_changed),                                  \
74 	BT_AUDIO_CHRC(BT_UUID_AICS_GAIN_SETTINGS,                              \
75 		      BT_GATT_CHRC_READ,                                       \
76 		      BT_GATT_PERM_READ_ENCRYPT,                               \
77 		      read_aics_gain_settings, NULL, &_aics),                  \
78 	BT_AUDIO_CHRC(BT_UUID_AICS_INPUT_TYPE,                                 \
79 		      BT_GATT_CHRC_READ,                                       \
80 		      BT_GATT_PERM_READ_ENCRYPT,                               \
81 		      read_type, NULL, &_aics),                                \
82 	BT_AUDIO_CHRC(BT_UUID_AICS_INPUT_STATUS,                               \
83 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,                 \
84 		      BT_GATT_PERM_READ_ENCRYPT,                               \
85 		      read_input_status, NULL, &_aics),                        \
86 	BT_AUDIO_CCC(aics_input_status_cfg_changed),                           \
87 	BT_AUDIO_CHRC(BT_UUID_AICS_CONTROL,                                    \
88 		      BT_GATT_CHRC_WRITE,                                      \
89 		      BT_GATT_PERM_WRITE_ENCRYPT,                              \
90 		      NULL, write_aics_control, &_aics),                       \
91 	BT_AUDIO_CHRC(BT_UUID_AICS_DESCRIPTION,                                \
92 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,                 \
93 		      BT_GATT_PERM_READ_ENCRYPT,                               \
94 		      read_description, write_description, &_aics),            \
95 	BT_AUDIO_CCC(aics_description_cfg_changed)                             \
96 	}
97 
98 
99 static struct bt_aics aics_insts[CONFIG_BT_AICS_MAX_INSTANCE_COUNT];
100 static uint32_t instance_cnt;
101 BT_GATT_SERVICE_INSTANCE_DEFINE(aics_service_list, aics_insts,
102 				CONFIG_BT_AICS_MAX_INSTANCE_COUNT,
103 				BT_AICS_SERVICE_DEFINITION);
104 
aics_state_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)105 static void aics_state_cfg_changed(const struct bt_gatt_attr *attr,
106 				   uint16_t value)
107 {
108 	LOG_DBG("value 0x%04x", value);
109 }
110 
read_aics_state(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)111 static ssize_t read_aics_state(struct bt_conn *conn,
112 			       const struct bt_gatt_attr *attr, void *buf,
113 			       uint16_t len, uint16_t offset)
114 {
115 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
116 
117 	LOG_DBG("gain %d, mute %u, gain_mode %u, counter %u", inst->srv.state.gain,
118 		inst->srv.state.mute, inst->srv.state.gain_mode, inst->srv.state.change_counter);
119 
120 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.state,
121 				 sizeof(inst->srv.state));
122 }
123 
read_aics_gain_settings(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)124 static ssize_t read_aics_gain_settings(struct bt_conn *conn,
125 				       const struct bt_gatt_attr *attr,
126 				       void *buf, uint16_t len, uint16_t offset)
127 {
128 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
129 
130 	LOG_DBG("units %u, min %d, max %d", inst->srv.gain_settings.units,
131 		inst->srv.gain_settings.minimum, inst->srv.gain_settings.maximum);
132 
133 	return bt_gatt_attr_read(conn, attr, buf, len, offset,
134 				 &inst->srv.gain_settings,
135 				 sizeof(inst->srv.gain_settings));
136 }
137 
read_type(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)138 static ssize_t read_type(struct bt_conn *conn, const struct bt_gatt_attr *attr,
139 			 void *buf, uint16_t len, uint16_t offset)
140 {
141 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
142 
143 	LOG_DBG("%u", inst->srv.type);
144 
145 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.type,
146 				 sizeof(inst->srv.type));
147 }
148 
aics_input_status_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)149 static void aics_input_status_cfg_changed(const struct bt_gatt_attr *attr,
150 					  uint16_t value)
151 {
152 	LOG_DBG("value 0x%04x", value);
153 }
154 
read_input_status(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)155 static ssize_t read_input_status(struct bt_conn *conn,
156 				 const struct bt_gatt_attr *attr, void *buf,
157 				 uint16_t len, uint16_t offset)
158 {
159 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
160 
161 	LOG_DBG("%u", inst->srv.status);
162 
163 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.status,
164 				 sizeof(inst->srv.status));
165 }
166 
aics_notify_str(enum bt_aics_notify notify)167 static const char *aics_notify_str(enum bt_aics_notify notify)
168 {
169 	switch (notify) {
170 	case AICS_NOTIFY_STATE:
171 		return "state";
172 	case AICS_NOTIFY_DESCRIPTION:
173 		return "description";
174 	case AICS_NOTIFY_STATUS:
175 		return "status";
176 	default:
177 		return "unknown";
178 	}
179 }
180 
notify_work_reschedule(struct bt_aics * inst,enum bt_aics_notify notify,k_timeout_t delay)181 static void notify_work_reschedule(struct bt_aics *inst, enum bt_aics_notify notify,
182 				   k_timeout_t delay)
183 {
184 	int err;
185 
186 	atomic_set_bit(inst->srv.notify, notify);
187 
188 	err = k_work_reschedule(&inst->srv.notify_work, K_NO_WAIT);
189 	if (err < 0) {
190 		LOG_ERR("Failed to reschedule %s notification err %d",
191 			aics_notify_str(notify), err);
192 	}
193 }
194 
notify(struct bt_aics * inst,enum bt_aics_notify notify,const struct bt_uuid * uuid,const void * data,uint16_t len)195 static void notify(struct bt_aics *inst, enum bt_aics_notify notify, const struct bt_uuid *uuid,
196 		   const void *data, uint16_t len)
197 {
198 	int err;
199 
200 	err = bt_gatt_notify_uuid(NULL, uuid, inst->srv.service_p->attrs, data, len);
201 	if (err == -ENOMEM) {
202 		notify_work_reschedule(inst, notify, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
203 	} else if (err < 0 && err != -ENOTCONN) {
204 		LOG_ERR("Notify %s err %d", aics_notify_str(notify), err);
205 	}
206 }
207 
notify_work_handler(struct k_work * work)208 static void notify_work_handler(struct k_work *work)
209 {
210 	struct k_work_delayable *d_work = k_work_delayable_from_work(work);
211 	struct bt_aics *inst = CONTAINER_OF(d_work, struct bt_aics, srv.notify_work);
212 
213 	if (atomic_test_and_clear_bit(inst->srv.notify, AICS_NOTIFY_STATE)) {
214 		notify(inst, AICS_NOTIFY_STATE, BT_UUID_AICS_STATE, &inst->srv.state,
215 		       sizeof(inst->srv.state));
216 	}
217 
218 	if (atomic_test_and_clear_bit(inst->srv.notify, AICS_NOTIFY_DESCRIPTION)) {
219 		notify(inst, AICS_NOTIFY_DESCRIPTION, BT_UUID_AICS_DESCRIPTION,
220 		       &inst->srv.description, strlen(inst->srv.description));
221 	}
222 
223 	if (atomic_test_and_clear_bit(inst->srv.notify, AICS_NOTIFY_STATUS)) {
224 		notify(inst, AICS_NOTIFY_STATUS, BT_UUID_AICS_INPUT_STATUS, &inst->srv.status,
225 		       sizeof(inst->srv.status));
226 	}
227 }
228 
value_changed(struct bt_aics * inst,enum bt_aics_notify notify)229 static void value_changed(struct bt_aics *inst, enum bt_aics_notify notify)
230 {
231 	notify_work_reschedule(inst, notify, K_NO_WAIT);
232 }
233 #else
234 #define value_changed(...)
235 #endif /* CONFIG_BT_AICS */
236 
write_aics_control(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)237 static ssize_t write_aics_control(struct bt_conn *conn,
238 				  const struct bt_gatt_attr *attr,
239 				  const void *buf, uint16_t len,
240 				  uint16_t offset, uint8_t flags)
241 {
242 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
243 	const struct bt_aics_gain_control *cp = buf;
244 	bool notify = false;
245 
246 	if (offset) {
247 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
248 	}
249 
250 	if (!len || !buf) {
251 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
252 	}
253 
254 	/* Check opcode before length */
255 	if (!VALID_AICS_OPCODE(cp->cp.opcode)) {
256 		LOG_DBG("Invalid opcode %u", cp->cp.opcode);
257 		return BT_GATT_ERR(BT_AICS_ERR_OP_NOT_SUPPORTED);
258 	}
259 
260 	if ((len < AICS_CP_LEN) ||
261 	    (len == AICS_CP_SET_GAIN_LEN && cp->cp.opcode != BT_AICS_OPCODE_SET_GAIN) ||
262 	    (len > AICS_CP_SET_GAIN_LEN)) {
263 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
264 	}
265 
266 	LOG_DBG("Opcode %u, counter %u", cp->cp.opcode, cp->cp.counter);
267 	if (cp->cp.counter != inst->srv.state.change_counter) {
268 		return BT_GATT_ERR(BT_AICS_ERR_INVALID_COUNTER);
269 	}
270 
271 	switch (cp->cp.opcode) {
272 	case BT_AICS_OPCODE_SET_GAIN:
273 		LOG_DBG("Set gain %d", cp->gain_setting);
274 		if (cp->gain_setting < inst->srv.gain_settings.minimum ||
275 		    cp->gain_setting > inst->srv.gain_settings.maximum) {
276 			return BT_GATT_ERR(BT_AICS_ERR_OUT_OF_RANGE);
277 		}
278 		if (BT_AICS_INPUT_MODE_SETTABLE(inst->srv.state.gain_mode) &&
279 		    inst->srv.state.gain != cp->gain_setting) {
280 			inst->srv.state.gain = cp->gain_setting;
281 			notify = true;
282 		}
283 		break;
284 	case BT_AICS_OPCODE_UNMUTE:
285 		LOG_DBG("Unmute");
286 		if (inst->srv.state.mute == BT_AICS_STATE_MUTE_DISABLED) {
287 			return BT_GATT_ERR(BT_AICS_ERR_MUTE_DISABLED);
288 		}
289 		if (inst->srv.state.mute != BT_AICS_STATE_UNMUTED) {
290 			inst->srv.state.mute = BT_AICS_STATE_UNMUTED;
291 			notify = true;
292 		}
293 		break;
294 	case BT_AICS_OPCODE_MUTE:
295 		LOG_DBG("Mute");
296 		if (inst->srv.state.mute == BT_AICS_STATE_MUTE_DISABLED) {
297 			return BT_GATT_ERR(BT_AICS_ERR_MUTE_DISABLED);
298 		}
299 		if (inst->srv.state.mute != BT_AICS_STATE_MUTED) {
300 			inst->srv.state.mute = BT_AICS_STATE_MUTED;
301 			notify = true;
302 		}
303 		break;
304 	case BT_AICS_OPCODE_SET_MANUAL:
305 		LOG_DBG("Set manual mode");
306 		if (BT_AICS_INPUT_MODE_IMMUTABLE(inst->srv.state.gain_mode)) {
307 			return BT_GATT_ERR(BT_AICS_ERR_GAIN_MODE_NOT_ALLOWED);
308 		}
309 		if (inst->srv.state.gain_mode != BT_AICS_MODE_MANUAL) {
310 			inst->srv.state.gain_mode = BT_AICS_MODE_MANUAL;
311 			notify = true;
312 		}
313 		break;
314 	case BT_AICS_OPCODE_SET_AUTO:
315 		LOG_DBG("Set automatic mode");
316 		if (BT_AICS_INPUT_MODE_IMMUTABLE(inst->srv.state.gain_mode)) {
317 			return BT_GATT_ERR(BT_AICS_ERR_GAIN_MODE_NOT_ALLOWED);
318 		}
319 		if (inst->srv.state.gain_mode != BT_AICS_MODE_AUTO) {
320 			inst->srv.state.gain_mode = BT_AICS_MODE_AUTO;
321 			notify = true;
322 		}
323 		break;
324 	default:
325 		return BT_GATT_ERR(BT_AICS_ERR_OP_NOT_SUPPORTED);
326 	}
327 
328 	if (notify) {
329 		inst->srv.state.change_counter++;
330 
331 		LOG_DBG("New state: gain %d, mute %u, gain_mode %u, counter %u",
332 			inst->srv.state.gain, inst->srv.state.mute, inst->srv.state.gain_mode,
333 			inst->srv.state.change_counter);
334 
335 		value_changed(inst, AICS_NOTIFY_STATE);
336 
337 		if (inst->srv.cb && inst->srv.cb->state) {
338 			inst->srv.cb->state(inst, 0, inst->srv.state.gain,
339 					inst->srv.state.mute,
340 					inst->srv.state.gain_mode);
341 		} else {
342 			LOG_DBG("Callback not registered for instance %p", inst);
343 		}
344 	}
345 
346 	return len;
347 }
348 
349 #if defined(CONFIG_BT_AICS)
aics_description_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)350 static void aics_description_cfg_changed(const struct bt_gatt_attr *attr,
351 					 uint16_t value)
352 {
353 	LOG_DBG("value 0x%04x", value);
354 }
355 #endif /* CONFIG_BT_AICS */
356 
write_description(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)357 static ssize_t write_description(struct bt_conn *conn,
358 				 const struct bt_gatt_attr *attr,
359 				 const void *buf, uint16_t len, uint16_t offset,
360 				 uint8_t flags)
361 {
362 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
363 
364 	if (len >= sizeof(inst->srv.description)) {
365 		LOG_DBG("Output desc was clipped from length %u to %zu", len,
366 			sizeof(inst->srv.description) - 1);
367 		/* We just clip the string value if it's too long */
368 		len = (uint16_t)sizeof(inst->srv.description) - 1;
369 	}
370 
371 	if (memcmp(buf, inst->srv.description, len)) {
372 		memcpy(inst->srv.description, buf, len);
373 		inst->srv.description[len] = '\0';
374 
375 		value_changed(inst, AICS_NOTIFY_DESCRIPTION);
376 
377 		if (inst->srv.cb && inst->srv.cb->description) {
378 			inst->srv.cb->description(inst, 0,
379 						  inst->srv.description);
380 		} else {
381 			LOG_DBG("Callback not registered for instance %p", inst);
382 		}
383 	}
384 
385 	LOG_DBG("%s", inst->srv.description);
386 
387 	return len;
388 }
389 
aics_write(struct bt_aics * inst,ssize_t (* write)(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags),const void * buf,uint16_t len)390 static int aics_write(struct bt_aics *inst,
391 		      ssize_t (*write)(struct bt_conn *conn,
392 				       const struct bt_gatt_attr *attr,
393 				       const void *buf, uint16_t len,
394 				       uint16_t offset, uint8_t flags),
395 		      const void *buf, uint16_t len)
396 {
397 	struct bt_audio_attr_user_data user_data = {
398 		.user_data = inst,
399 	};
400 	struct bt_gatt_attr attr = {
401 		.user_data = &user_data,
402 	};
403 	int err;
404 
405 	err = write(NULL, &attr, buf, len, 0, 0);
406 	if (err < 0) {
407 		return err;
408 	}
409 
410 	return 0;
411 }
412 
413 #if defined(CONFIG_BT_AICS)
read_description(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)414 static ssize_t read_description(struct bt_conn *conn,
415 				const struct bt_gatt_attr *attr, void *buf,
416 				uint16_t len, uint16_t offset)
417 {
418 	struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
419 
420 	LOG_DBG("%s", inst->srv.description);
421 
422 	return bt_gatt_attr_read(conn, attr, buf, len, offset,
423 				 &inst->srv.description, strlen(inst->srv.description));
424 }
425 
426 /************************ PUBLIC API ************************/
bt_aics_svc_decl_get(struct bt_aics * aics)427 void *bt_aics_svc_decl_get(struct bt_aics *aics)
428 {
429 	CHECKIF(!aics) {
430 		LOG_DBG("NULL instance");
431 		return NULL;
432 	}
433 
434 	return aics->srv.service_p->attrs;
435 }
436 
prepare_aics_instances(void)437 static void prepare_aics_instances(void)
438 {
439 	for (int i = 0; i < ARRAY_SIZE(aics_insts); i++) {
440 		aics_insts[i].srv.service_p = &aics_service_list[i];
441 	}
442 }
443 
bt_aics_register(struct bt_aics * aics,struct bt_aics_register_param * param)444 int bt_aics_register(struct bt_aics *aics, struct bt_aics_register_param *param)
445 {
446 	int err;
447 	static bool instance_prepared;
448 
449 	CHECKIF(!aics) {
450 		LOG_DBG("NULL aics pointer");
451 		return -ENOTCONN;
452 	}
453 
454 	CHECKIF(!param) {
455 		LOG_DBG("NULL param");
456 		return -EINVAL;
457 	}
458 
459 	if (!instance_prepared) {
460 		prepare_aics_instances();
461 		instance_prepared = true;
462 	}
463 
464 	CHECKIF(aics->srv.initialized) {
465 		return -EALREADY;
466 	}
467 
468 	CHECKIF(param->mute > BT_AICS_STATE_MUTE_DISABLED) {
469 		LOG_DBG("Invalid AICS mute value: %u", param->mute);
470 		return -EINVAL;
471 	}
472 
473 	CHECKIF(param->gain_mode > BT_AICS_MODE_AUTO) {
474 		LOG_DBG("Invalid AICS mode value: %u", param->gain_mode);
475 		return -EINVAL;
476 	}
477 
478 	CHECKIF(param->type > BT_AICS_INPUT_TYPE_STREAMING) {
479 		LOG_DBG("Invalid AICS input type value: %u", param->type);
480 		return -EINVAL;
481 	}
482 
483 	CHECKIF(param->units == 0) {
484 		LOG_DBG("AICS units value shall not be 0");
485 		return -EINVAL;
486 	}
487 
488 	CHECKIF(!(param->min_gain <= param->max_gain)) {
489 		LOG_DBG("AICS min gain (%d) shall be lower than or equal to max gain (%d)",
490 			param->min_gain, param->max_gain);
491 		return -EINVAL;
492 	}
493 
494 	CHECKIF(param->gain < param->min_gain || param->gain > param->max_gain) {
495 		LOG_DBG("AICS gain (%d) shall be not lower than min gain (%d) "
496 		       "or higher than max gain (%d)",
497 		       param->gain, param->min_gain, param->max_gain);
498 		return -EINVAL;
499 	}
500 
501 	aics->srv.state.gain = param->gain;
502 	aics->srv.state.mute = param->mute;
503 	aics->srv.state.gain_mode = param->gain_mode;
504 	aics->srv.gain_settings.units = param->units;
505 	aics->srv.gain_settings.minimum = param->min_gain;
506 	aics->srv.gain_settings.maximum = param->max_gain;
507 	aics->srv.type = param->type;
508 	aics->srv.status = param->status ? BT_AICS_STATUS_ACTIVE : BT_AICS_STATUS_INACTIVE;
509 	aics->srv.cb = param->cb;
510 
511 	atomic_clear(aics->srv.notify);
512 	k_work_init_delayable(&aics->srv.notify_work, notify_work_handler);
513 
514 	if (param->description) {
515 		strncpy(aics->srv.description, param->description,
516 			sizeof(aics->srv.description) - 1);
517 		/* strncpy may not always null-terminate */
518 		aics->srv.description[sizeof(aics->srv.description) - 1] = '\0';
519 		if (IS_ENABLED(CONFIG_BT_AICS_LOG_LEVEL_DBG) &&
520 		    strcmp(aics->srv.description, param->description)) {
521 			LOG_DBG("Input desc clipped to %s", aics->srv.description);
522 		}
523 	}
524 
525 	/* Iterate over the attributes in AICS (starting from i = 1 to skip the
526 	 * service declaration) to find the BT_UUID_AICS_DESCRIPTION and update
527 	 * the characteristic value (at [i]), update that with the write
528 	 * permission and callback, and also update the characteristic
529 	 * declaration (always found at [i - 1]) with the
530 	 * BT_GATT_CHRC_WRITE_WITHOUT_RESP property.
531 	 */
532 	if (param->desc_writable) {
533 		for (int i = 1; i < aics->srv.service_p->attr_count; i++) {
534 			struct bt_gatt_attr *attr;
535 
536 			attr = &aics->srv.service_p->attrs[i];
537 
538 			if (!bt_uuid_cmp(attr->uuid, BT_UUID_AICS_DESCRIPTION)) {
539 				/* Update attr and chrc to be writable */
540 				struct bt_gatt_chrc *chrc;
541 
542 				chrc = aics->srv.service_p->attrs[i - 1].user_data;
543 				attr->perm |= BT_GATT_PERM_WRITE_ENCRYPT;
544 				chrc->properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP;
545 
546 				break;
547 			}
548 		}
549 	}
550 
551 	err = bt_gatt_service_register(aics->srv.service_p);
552 	if (err) {
553 		LOG_DBG("Could not register AICS service");
554 		return err;
555 	}
556 
557 	aics->srv.initialized = true;
558 
559 	return 0;
560 }
561 
bt_aics_free_instance_get(void)562 struct bt_aics *bt_aics_free_instance_get(void)
563 {
564 	if (instance_cnt >= CONFIG_BT_AICS_MAX_INSTANCE_COUNT) {
565 		return NULL;
566 	}
567 
568 	return (struct bt_aics *)&aics_insts[instance_cnt++];
569 }
570 
571 /****************************** PUBLIC API ******************************/
bt_aics_deactivate(struct bt_aics * inst)572 int bt_aics_deactivate(struct bt_aics *inst)
573 {
574 	CHECKIF(!inst) {
575 		LOG_DBG("NULL instance");
576 		return -EINVAL;
577 	}
578 
579 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
580 		return -ENOTSUP;
581 	}
582 
583 	if (inst->srv.status == BT_AICS_STATUS_ACTIVE) {
584 		inst->srv.status = BT_AICS_STATUS_INACTIVE;
585 		LOG_DBG("Instance %p: Status was set to inactive", inst);
586 
587 		value_changed(inst, AICS_NOTIFY_STATUS);
588 
589 		if (inst->srv.cb && inst->srv.cb->status) {
590 			inst->srv.cb->status(inst, 0, inst->srv.status);
591 		} else {
592 			LOG_DBG("Callback not registered for instance %p", inst);
593 		}
594 	}
595 
596 	return 0;
597 }
598 
bt_aics_activate(struct bt_aics * inst)599 int bt_aics_activate(struct bt_aics *inst)
600 {
601 	CHECKIF(!inst) {
602 		LOG_DBG("NULL instance");
603 		return -EINVAL;
604 	}
605 
606 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
607 		return -ENOTSUP;
608 	}
609 
610 	if (inst->srv.status == BT_AICS_STATUS_INACTIVE) {
611 		inst->srv.status = BT_AICS_STATUS_ACTIVE;
612 		LOG_DBG("Instance %p: Status was set to active", inst);
613 
614 		value_changed(inst, AICS_NOTIFY_STATUS);
615 
616 		if (inst->srv.cb && inst->srv.cb->status) {
617 			inst->srv.cb->status(inst, 0, inst->srv.status);
618 		} else {
619 			LOG_DBG("Callback not registered for instance %p", inst);
620 		}
621 	}
622 
623 	return 0;
624 }
625 
626 #endif /* CONFIG_BT_AICS */
bt_aics_gain_set_manual_only(struct bt_aics * inst)627 int bt_aics_gain_set_manual_only(struct bt_aics *inst)
628 {
629 	CHECKIF(!inst) {
630 		LOG_DBG("NULL instance");
631 		return -EINVAL;
632 	}
633 
634 	inst->srv.state.gain_mode = BT_AICS_MODE_MANUAL_ONLY;
635 
636 	value_changed(inst, AICS_NOTIFY_STATE);
637 
638 	return 0;
639 }
640 
bt_aics_gain_set_auto_only(struct bt_aics * inst)641 int bt_aics_gain_set_auto_only(struct bt_aics *inst)
642 {
643 	CHECKIF(!inst) {
644 		LOG_DBG("NULL instance");
645 		return -EINVAL;
646 	}
647 
648 	inst->srv.state.gain_mode = BT_AICS_MODE_AUTO_ONLY;
649 
650 	value_changed(inst, AICS_NOTIFY_STATE);
651 
652 	return 0;
653 }
654 
bt_aics_state_get(struct bt_aics * inst)655 int bt_aics_state_get(struct bt_aics *inst)
656 {
657 	CHECKIF(!inst) {
658 		LOG_DBG("NULL instance");
659 		return -EINVAL;
660 	}
661 
662 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
663 		return bt_aics_client_state_get(inst);
664 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
665 		if (inst->srv.cb && inst->srv.cb->state) {
666 			inst->srv.cb->state(inst, 0, inst->srv.state.gain,
667 					    inst->srv.state.mute,
668 					    inst->srv.state.gain_mode);
669 		} else {
670 			LOG_DBG("Callback not registered for instance %p", inst);
671 		}
672 		return 0;
673 	}
674 
675 	return -ENOTSUP;
676 }
677 
bt_aics_gain_setting_get(struct bt_aics * inst)678 int bt_aics_gain_setting_get(struct bt_aics *inst)
679 {
680 	CHECKIF(!inst) {
681 		LOG_DBG("NULL instance");
682 		return -EINVAL;
683 	}
684 
685 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
686 		return bt_aics_client_gain_setting_get(inst);
687 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
688 		if (inst->srv.cb && inst->srv.cb->gain_setting) {
689 			inst->srv.cb->gain_setting(inst, 0,
690 						   inst->srv.gain_settings.units,
691 						   inst->srv.gain_settings.minimum,
692 						   inst->srv.gain_settings.maximum);
693 		} else {
694 			LOG_DBG("Callback not registered for instance %p", inst);
695 		}
696 		return 0;
697 	}
698 
699 	return -ENOTSUP;
700 }
701 
bt_aics_type_get(struct bt_aics * inst)702 int bt_aics_type_get(struct bt_aics *inst)
703 {
704 	CHECKIF(!inst) {
705 		LOG_DBG("NULL instance");
706 		return -EINVAL;
707 	}
708 
709 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
710 		return bt_aics_client_type_get(inst);
711 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
712 		if (inst->srv.cb && inst->srv.cb->type) {
713 			inst->srv.cb->type(inst, 0, inst->srv.type);
714 		} else {
715 			LOG_DBG("Callback not registered for instance %p", inst);
716 		}
717 		return 0;
718 	}
719 
720 	return -ENOTSUP;
721 }
722 
bt_aics_status_get(struct bt_aics * inst)723 int bt_aics_status_get(struct bt_aics *inst)
724 {
725 	CHECKIF(!inst) {
726 		LOG_DBG("NULL instance");
727 		return -EINVAL;
728 	}
729 
730 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
731 		return bt_aics_client_status_get(inst);
732 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
733 		if (inst->srv.cb && inst->srv.cb->status) {
734 			inst->srv.cb->status(inst, 0, inst->srv.status);
735 		} else {
736 			LOG_DBG("Callback not registered for instance %p", inst);
737 		}
738 		return 0;
739 	}
740 
741 	return -ENOTSUP;
742 }
743 
bt_aics_disable_mute(struct bt_aics * inst)744 int bt_aics_disable_mute(struct bt_aics *inst)
745 {
746 	CHECKIF(!inst) {
747 		LOG_DBG("NULL instance");
748 		return -EINVAL;
749 	}
750 
751 	inst->srv.state.mute = BT_AICS_STATE_MUTE_DISABLED;
752 
753 	value_changed(inst, AICS_NOTIFY_STATE);
754 
755 	return 0;
756 }
757 
bt_aics_unmute(struct bt_aics * inst)758 int bt_aics_unmute(struct bt_aics *inst)
759 {
760 	CHECKIF(!inst) {
761 		LOG_DBG("NULL instance");
762 		return -EINVAL;
763 	}
764 
765 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
766 		return bt_aics_client_unmute(inst);
767 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
768 		struct bt_aics_control cp;
769 
770 		cp.opcode = BT_AICS_OPCODE_UNMUTE;
771 		cp.counter = inst->srv.state.change_counter;
772 
773 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
774 	}
775 
776 	return -ENOTSUP;
777 }
778 
bt_aics_mute(struct bt_aics * inst)779 int bt_aics_mute(struct bt_aics *inst)
780 {
781 	CHECKIF(!inst) {
782 		LOG_DBG("NULL instance");
783 		return -EINVAL;
784 	}
785 
786 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
787 		return bt_aics_client_mute(inst);
788 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
789 		struct bt_aics_control cp;
790 
791 		cp.opcode = BT_AICS_OPCODE_MUTE;
792 		cp.counter = inst->srv.state.change_counter;
793 
794 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
795 	}
796 
797 	return -ENOTSUP;
798 }
799 
bt_aics_manual_gain_set(struct bt_aics * inst)800 int bt_aics_manual_gain_set(struct bt_aics *inst)
801 {
802 	CHECKIF(!inst) {
803 		LOG_DBG("NULL instance");
804 		return -EINVAL;
805 	}
806 
807 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
808 		return bt_aics_client_manual_gain_set(inst);
809 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
810 		struct bt_aics_control cp;
811 
812 		cp.opcode = BT_AICS_OPCODE_SET_MANUAL;
813 		cp.counter = inst->srv.state.change_counter;
814 
815 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
816 	}
817 
818 	return -ENOTSUP;
819 }
820 
bt_aics_automatic_gain_set(struct bt_aics * inst)821 int bt_aics_automatic_gain_set(struct bt_aics *inst)
822 {
823 	CHECKIF(!inst) {
824 		LOG_DBG("NULL instance");
825 		return -EINVAL;
826 	}
827 
828 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
829 		return bt_aics_client_automatic_gain_set(inst);
830 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
831 		struct bt_aics_control cp;
832 
833 		cp.opcode = BT_AICS_OPCODE_SET_AUTO;
834 		cp.counter = inst->srv.state.change_counter;
835 
836 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
837 	}
838 
839 	return -ENOTSUP;
840 }
841 
bt_aics_gain_set(struct bt_aics * inst,int8_t gain)842 int bt_aics_gain_set(struct bt_aics *inst, int8_t gain)
843 {
844 	CHECKIF(!inst) {
845 		LOG_DBG("NULL instance");
846 		return -EINVAL;
847 	}
848 
849 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
850 		return bt_aics_client_gain_set(inst, gain);
851 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
852 		struct bt_aics_gain_control cp;
853 
854 		cp.cp.opcode = BT_AICS_OPCODE_SET_GAIN;
855 		cp.cp.counter = inst->srv.state.change_counter;
856 		cp.gain_setting = gain;
857 
858 		return aics_write(inst, write_aics_control, &cp, sizeof(cp));
859 	}
860 
861 	return -ENOTSUP;
862 }
863 
bt_aics_description_get(struct bt_aics * inst)864 int bt_aics_description_get(struct bt_aics *inst)
865 {
866 	CHECKIF(!inst) {
867 		LOG_DBG("NULL instance");
868 		return -EINVAL;
869 	}
870 
871 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
872 		return bt_aics_client_description_get(inst);
873 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
874 		if (inst->srv.cb && inst->srv.cb->description) {
875 			inst->srv.cb->description(inst, 0,
876 						  inst->srv.description);
877 		} else {
878 			LOG_DBG("Callback not registered for instance %p", inst);
879 		}
880 		return 0;
881 	}
882 
883 	return -ENOTSUP;
884 }
885 
bt_aics_description_set(struct bt_aics * inst,const char * description)886 int bt_aics_description_set(struct bt_aics *inst, const char *description)
887 {
888 	CHECKIF(!inst) {
889 		LOG_DBG("NULL instance");
890 		return -EINVAL;
891 	}
892 
893 	CHECKIF(!description) {
894 		LOG_DBG("NULL description");
895 		return -EINVAL;
896 	}
897 
898 	if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
899 		return bt_aics_client_description_set(inst, description);
900 	} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
901 		return aics_write(inst, write_description, description, strlen(description));
902 	}
903 
904 	return -ENOTSUP;
905 }
906