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