1 /*
2  * Copyright (c) 2022 Codecoup
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdlib.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/sys/check.h>
10 
11 #include <zephyr/device.h>
12 
13 #include <zephyr/bluetooth/bluetooth.h>
14 #include <zephyr/bluetooth/gatt.h>
15 #include <zephyr/bluetooth/audio/audio.h>
16 #include <zephyr/bluetooth/audio/pacs.h>
17 #include <zephyr/bluetooth/audio/has.h>
18 #include <zephyr/sys/check.h>
19 
20 #include "../bluetooth/host/conn_internal.h"
21 #include "../bluetooth/host/hci_core.h"
22 #include "audio_internal.h"
23 #include "has_internal.h"
24 
25 #include <zephyr/logging/log.h>
26 
27 LOG_MODULE_REGISTER(bt_has, CONFIG_BT_HAS_LOG_LEVEL);
28 
29 /* The service allows operations with paired devices only.
30  * For now, the context is kept for connected devices only, thus the number of contexts is
31  * equal to maximum number of simultaneous connections to paired devices.
32  */
33 #define BT_HAS_MAX_CONN MIN(CONFIG_BT_MAX_CONN, CONFIG_BT_MAX_PAIRED)
34 
35 #define BITS_CHANGED(_new_value, _old_value) ((_new_value) ^ (_old_value))
36 #define FEATURE_DEVICE_TYPE_UNCHANGED(_new_value) \
37 	!BITS_CHANGED(_new_value, (has.features & BT_HAS_FEAT_HEARING_AID_TYPE_MASK))
38 #define FEATURE_SYNC_SUPPORT_UNCHANGED(_new_value) \
39 	!BITS_CHANGED(_new_value, ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0 ? 1 : 0))
40 #define FEATURE_IND_PRESETS_UNCHANGED(_new_value) \
41 	!BITS_CHANGED(_new_value, ((has.features & BT_HAS_FEAT_INDEPENDENT_PRESETS) != 0 ? 1 : 0))
42 
43 static struct bt_has has;
44 
45 #if defined(CONFIG_BT_HAS_ACTIVE_PRESET_INDEX)
active_preset_index_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)46 static void active_preset_index_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
47 {
48 	LOG_DBG("attr %p value 0x%04x", attr, value);
49 }
50 #endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
51 
52 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
53 struct has_client;
54 
55 /* Active preset notification work */
56 static void active_preset_work_process(struct k_work *work);
57 static K_WORK_DEFINE(active_preset_work, active_preset_work_process);
58 
59 static void process_control_point_work(struct k_work *work);
60 static void read_presets_req_free(struct has_client *client);
61 static ssize_t write_control_point(struct bt_conn *conn, const struct bt_gatt_attr *attr,
62 				   const void *data, uint16_t len, uint16_t offset, uint8_t flags);
63 
preset_cp_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)64 static void preset_cp_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
65 {
66 	LOG_DBG("attr %p value 0x%04x", attr, value);
67 }
68 
read_active_preset_index(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)69 static ssize_t read_active_preset_index(struct bt_conn *conn, const struct bt_gatt_attr *attr,
70 					void *buf, uint16_t len, uint16_t offset)
71 {
72 	LOG_DBG("conn %p attr %p offset %d", (void *)conn, attr, offset);
73 
74 	if (offset > sizeof(has.active_index)) {
75 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
76 	}
77 
78 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &has.active_index,
79 				 sizeof(has.active_index));
80 }
81 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
82 
83 #if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
features_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)84 static void features_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
85 {
86 	LOG_DBG("attr %p value 0x%04x", attr, value);
87 }
88 #endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
89 
read_features(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)90 static ssize_t read_features(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
91 			     uint16_t len, uint16_t offset)
92 {
93 	LOG_DBG("conn %p attr %p offset %d", (void *)conn, attr, offset);
94 
95 	if (offset > sizeof(has.features)) {
96 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
97 	}
98 
99 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &has.features,
100 				 sizeof(has.features));
101 }
102 
103 #if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
104 #define BT_HAS_CHR_FEATURES \
105 	BT_AUDIO_CHRC(BT_UUID_HAS_HEARING_AID_FEATURES, \
106 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
107 		      BT_GATT_PERM_READ_ENCRYPT, \
108 		      read_features, NULL, NULL), \
109 	BT_AUDIO_CCC(features_cfg_changed),
110 #else
111 #define BT_HAS_CHR_FEATURES \
112 	BT_AUDIO_CHRC(BT_UUID_HAS_HEARING_AID_FEATURES, \
113 		      BT_GATT_CHRC_READ, \
114 		      BT_GATT_PERM_READ_ENCRYPT, \
115 		      read_features, NULL, NULL),
116 #endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
117 
118 
119 
120 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
121 #if defined(CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE)
122 #define BT_HAS_CHR_PRESET_CONTROL_POINT \
123 	BT_AUDIO_CHRC(BT_UUID_HAS_PRESET_CONTROL_POINT, \
124 		      BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE | BT_GATT_CHRC_NOTIFY, \
125 		      BT_GATT_PERM_WRITE_ENCRYPT, \
126 		      NULL, write_control_point, NULL), \
127 	BT_AUDIO_CCC(preset_cp_cfg_changed),
128 #else
129 #define BT_HAS_CHR_PRESET_CONTROL_POINT \
130 	BT_AUDIO_CHRC(BT_UUID_HAS_PRESET_CONTROL_POINT, \
131 		      BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE, \
132 		      BT_GATT_PERM_WRITE_ENCRYPT, \
133 		      NULL, write_control_point, NULL), \
134 	BT_AUDIO_CCC(preset_cp_cfg_changed),
135 #endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
136 #else
137 #define BT_HAS_CHR_PRESET_CONTROL_POINT
138 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
139 
140 #if defined(CONFIG_BT_HAS_ACTIVE_PRESET_INDEX)
141 #define BT_HAS_CHR_ACTIVE_PRESET_INDEX \
142 	BT_AUDIO_CHRC(BT_UUID_HAS_ACTIVE_PRESET_INDEX, \
143 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
144 		      BT_GATT_PERM_READ_ENCRYPT, \
145 		      read_active_preset_index, NULL, NULL), \
146 	BT_AUDIO_CCC(active_preset_index_cfg_changed)
147 #else
148 #define BT_HAS_CHR_ACTIVE_PRESET_INDEX
149 #endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
150 
151 /* Hearing Access Service GATT Attributes */
152 static struct bt_gatt_attr has_attrs[] = {
153 	BT_GATT_PRIMARY_SERVICE(BT_UUID_HAS),
154 	BT_HAS_CHR_FEATURES
155 	BT_HAS_CHR_PRESET_CONTROL_POINT
156 	BT_HAS_CHR_ACTIVE_PRESET_INDEX
157 };
158 
159 static struct bt_gatt_service has_svc;
160 
161 #if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
162 /* Features notification work */
163 static void features_work_process(struct k_work *work);
164 static K_WORK_DEFINE(features_work, features_work_process);
165 
166 #define FEATURES_ATTR &has_attrs[2]
167 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
168 #define PRESET_CONTROL_POINT_ATTR &has_attrs[5]
169 #define ACTIVE_PRESET_INDEX_ATTR &has_attrs[8]
170 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
171 #else
172 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
173 #define PRESET_CONTROL_POINT_ATTR &has_attrs[4]
174 #define ACTIVE_PRESET_INDEX_ATTR &has_attrs[7]
175 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
176 #endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
177 
178 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
179 enum {
180 	FLAG_ACTIVE_INDEX_CHANGED,
181 	FLAG_CONTROL_POINT_NOTIFY,
182 	FLAG_FEATURES_CHANGED,
183 	FLAG_NUM,
184 };
185 
186 static struct has_client {
187 	struct bt_conn *conn;
188 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
189 	union {
190 		struct bt_gatt_indicate_params ind;
191 #if defined(CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE)
192 		struct bt_gatt_notify_params ntf;
193 #endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
194 	} params;
195 
196 	uint8_t preset_changed_index_next;
197 	struct bt_has_cp_read_presets_req read_presets_req;
198 	struct k_work control_point_work;
199 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
200 	ATOMIC_DEFINE(flags, FLAG_NUM);
201 } has_client_list[BT_HAS_MAX_CONN];
202 
client_get_or_new(struct bt_conn * conn)203 static struct has_client *client_get_or_new(struct bt_conn *conn)
204 {
205 	struct has_client *client = NULL;
206 
207 	for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) {
208 		if (conn == has_client_list[i].conn) {
209 			return &has_client_list[i];
210 		}
211 
212 		/* first free slot */
213 		if (!client && !has_client_list[i].conn) {
214 			client = &has_client_list[i];
215 		}
216 	}
217 
218 	__ASSERT(client, "failed to get client for conn %p", (void *)conn);
219 
220 	client->conn = bt_conn_ref(conn);
221 
222 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
223 	k_work_init(&client->control_point_work, process_control_point_work);
224 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
225 
226 	return client;
227 }
228 
client_free(struct has_client * client)229 static void client_free(struct has_client *client)
230 {
231 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
232 	(void)k_work_cancel(&client->control_point_work);
233 	read_presets_req_free(client);
234 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
235 
236 	atomic_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY);
237 	atomic_clear_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED);
238 	atomic_clear_bit(client->flags, FLAG_FEATURES_CHANGED);
239 
240 	bt_conn_unref(client->conn);
241 
242 	client->conn = NULL;
243 }
244 
client_get(struct bt_conn * conn)245 static struct has_client *client_get(struct bt_conn *conn)
246 {
247 	for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) {
248 		if (conn == has_client_list[i].conn) {
249 			return &has_client_list[i];
250 		}
251 	}
252 
253 	return NULL;
254 }
255 
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)256 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
257 {
258 	struct has_client *client;
259 
260 	LOG_DBG("conn %p level %d err %d", (void *)conn, level, err);
261 
262 	if (err != BT_SECURITY_ERR_SUCCESS) {
263 		return;
264 	}
265 
266 	client = client_get_or_new(conn);
267 	if (unlikely(!client)) {
268 		LOG_ERR("Failed to allocate client");
269 		return;
270 	}
271 
272 	if (!bt_addr_le_is_bonded(conn->id, &conn->le.dst)) {
273 		return;
274 	}
275 
276 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
277 	/* Notify after reconnection */
278 	if (atomic_test_and_clear_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED)) {
279 		/* Emit active preset notification */
280 		k_work_submit(&active_preset_work);
281 	}
282 
283 	if (atomic_test_and_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY)) {
284 		/* Emit preset changed notifications */
285 		k_work_submit(&client->control_point_work);
286 	}
287 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
288 
289 #if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
290 	if (atomic_test_and_clear_bit(client->flags, FLAG_FEATURES_CHANGED)) {
291 		/* Emit preset changed notifications */
292 		k_work_submit(&features_work);
293 	}
294 #endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
295 }
296 
connected(struct bt_conn * conn,uint8_t err)297 static void connected(struct bt_conn *conn, uint8_t err)
298 {
299 	struct has_client *client;
300 
301 	LOG_DBG("conn %p err %d", conn, err);
302 
303 	if (err != 0 || !bt_addr_le_is_bonded(conn->id, &conn->le.dst)) {
304 		return;
305 	}
306 
307 	client = client_get_or_new(conn);
308 	if (unlikely(!client)) {
309 		LOG_ERR("Failed to allocate client");
310 		return;
311 	}
312 }
313 
disconnected(struct bt_conn * conn,uint8_t reason)314 static void disconnected(struct bt_conn *conn, uint8_t reason)
315 {
316 	struct has_client *client;
317 
318 	LOG_DBG("conn %p reason %d", (void *)conn, reason);
319 
320 	client = client_get(conn);
321 	if (client) {
322 		client_free(client);
323 	}
324 }
325 
326 BT_CONN_CB_DEFINE(conn_cb) = {
327 	.connected = connected,
328 	.disconnected = disconnected,
329 	.security_changed = security_changed,
330 };
331 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
332 
333 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
334 /* HAS internal preset representation */
335 static struct has_preset {
336 	uint8_t index;
337 	enum bt_has_properties properties;
338 #if defined(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)
339 	char name[BT_HAS_PRESET_NAME_MAX + 1]; /* +1 byte for NULL-terminator */
340 #else
341 	const char *name;
342 #endif /* CONFIG_BT_HAS_PRESET_NAME_DYNAMIC */
343 	const struct bt_has_preset_ops *ops;
344 } has_preset_list[CONFIG_BT_HAS_PRESET_COUNT];
345 
346 /* Number of registered presets */
347 static uint8_t has_preset_num;
348 
read_presets_req_pending_cp(const struct has_client * client)349 static bool read_presets_req_pending_cp(const struct has_client *client)
350 {
351 	return client->read_presets_req.num_presets > 0;
352 }
353 
read_presets_req_free(struct has_client * client)354 static void read_presets_req_free(struct has_client *client)
355 {
356 	client->read_presets_req.num_presets = 0;
357 }
358 
359 typedef uint8_t (*preset_func_t)(const struct has_preset *preset, void *user_data);
360 
preset_foreach(uint8_t start_index,uint8_t end_index,preset_func_t func,void * user_data)361 static void preset_foreach(uint8_t start_index, uint8_t end_index, preset_func_t func,
362 			   void *user_data)
363 {
364 	for (size_t i = 0; i < ARRAY_SIZE(has_preset_list); i++) {
365 		const struct has_preset *preset = &has_preset_list[i];
366 
367 		if (preset->index < start_index) {
368 			continue;
369 		}
370 
371 		if (preset->index > end_index) {
372 			return;
373 		}
374 
375 		if (func(preset, user_data) == BT_HAS_PRESET_ITER_STOP) {
376 			return;
377 		}
378 	}
379 }
380 
preset_found(const struct has_preset * preset,void * user_data)381 static uint8_t preset_found(const struct has_preset *preset, void *user_data)
382 {
383 	const struct has_preset **found = user_data;
384 
385 	*found = preset;
386 
387 	return BT_HAS_PRESET_ITER_STOP;
388 }
389 
preset_index_compare(const void * p1,const void * p2)390 static int preset_index_compare(const void *p1, const void *p2)
391 {
392 	const struct has_preset *preset_1 = p1;
393 	const struct has_preset *preset_2 = p2;
394 
395 	if (preset_1->index == BT_HAS_PRESET_INDEX_NONE) {
396 		return 1;
397 	}
398 
399 	if (preset_2->index == BT_HAS_PRESET_INDEX_NONE) {
400 		return -1;
401 	}
402 
403 	return preset_1->index - preset_2->index;
404 }
405 
preset_alloc(uint8_t index,enum bt_has_properties properties,const char * name,const struct bt_has_preset_ops * ops)406 static struct has_preset *preset_alloc(uint8_t index, enum bt_has_properties properties,
407 				       const char *name, const struct bt_has_preset_ops *ops)
408 {
409 	struct has_preset *preset = NULL;
410 
411 	if (has_preset_num < ARRAY_SIZE(has_preset_list)) {
412 		preset = &has_preset_list[has_preset_num];
413 		preset->index = index;
414 		preset->properties = properties;
415 #if defined(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)
416 		utf8_lcpy(preset->name, name, ARRAY_SIZE(preset->name));
417 #else
418 		preset->name = name;
419 #endif /* CONFIG_BT_HAS_PRESET_NAME_DYNAMIC */
420 		preset->ops = ops;
421 
422 		has_preset_num++;
423 
424 		/* sort the presets in index ascending order */
425 		qsort(has_preset_list, has_preset_num, sizeof(*preset), preset_index_compare);
426 	}
427 
428 	return preset;
429 }
430 
preset_free(struct has_preset * preset)431 static void preset_free(struct has_preset *preset)
432 {
433 	preset->index = BT_HAS_PRESET_INDEX_NONE;
434 
435 	/* sort the presets in index ascending order */
436 	if (has_preset_num > 1) {
437 		qsort(has_preset_list, has_preset_num, sizeof(*preset), preset_index_compare);
438 	}
439 
440 	has_preset_num--;
441 }
442 
control_point_ntf_complete(struct bt_conn * conn,void * user_data)443 static void control_point_ntf_complete(struct bt_conn *conn, void *user_data)
444 {
445 	struct has_client *client = client_get(conn);
446 
447 	LOG_DBG("conn %p", (void *)conn);
448 
449 	/* Resubmit if needed */
450 	if (client != NULL &&
451 	    (read_presets_req_pending_cp(client) ||
452 	     atomic_test_and_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY))) {
453 		k_work_submit(&client->control_point_work);
454 	}
455 }
456 
control_point_ind_complete(struct bt_conn * conn,struct bt_gatt_indicate_params * params,uint8_t err)457 static void control_point_ind_complete(struct bt_conn *conn,
458 				       struct bt_gatt_indicate_params *params,
459 				       uint8_t err)
460 {
461 	if (err) {
462 		/* TODO: Handle error somehow */
463 		LOG_ERR("conn %p err 0x%02x", (void *)conn, err);
464 	}
465 
466 	control_point_ntf_complete(conn, NULL);
467 }
468 
control_point_send(struct has_client * client,struct net_buf_simple * buf)469 static int control_point_send(struct has_client *client, struct net_buf_simple *buf)
470 {
471 #if defined(CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE)
472 	if (bt_eatt_count(client->conn) > 0 &&
473 	    bt_gatt_is_subscribed(client->conn, PRESET_CONTROL_POINT_ATTR, BT_GATT_CCC_NOTIFY)) {
474 		client->params.ntf.attr = PRESET_CONTROL_POINT_ATTR;
475 		client->params.ntf.func = control_point_ntf_complete;
476 		client->params.ntf.data = buf->data;
477 		client->params.ntf.len = buf->len;
478 
479 		return bt_gatt_notify_cb(client->conn, &client->params.ntf);
480 	}
481 #endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
482 
483 	if (bt_gatt_is_subscribed(client->conn, PRESET_CONTROL_POINT_ATTR, BT_GATT_CCC_INDICATE)) {
484 		client->params.ind.attr = PRESET_CONTROL_POINT_ATTR;
485 		client->params.ind.func = control_point_ind_complete;
486 		client->params.ind.destroy = NULL;
487 		client->params.ind.data = buf->data;
488 		client->params.ind.len = buf->len;
489 
490 		return bt_gatt_indicate(client->conn, &client->params.ind);
491 	}
492 
493 	return -ECANCELED;
494 }
495 
control_point_send_all(struct net_buf_simple * buf)496 static int control_point_send_all(struct net_buf_simple *buf)
497 {
498 	int result = 0;
499 
500 	for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) {
501 		struct has_client *client = &has_client_list[i];
502 		int err;
503 
504 		if (!client->conn) {
505 			/* Mark preset changed operation as pending */
506 			atomic_set_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY);
507 			/* For simplicity we simply start with the first index,
508 			 * rather than keeping detailed logs of which clients
509 			 * have knowledge of which presets
510 			 */
511 			client->preset_changed_index_next = BT_HAS_PRESET_INDEX_FIRST;
512 			continue;
513 		}
514 
515 		if (!bt_gatt_is_subscribed(client->conn, PRESET_CONTROL_POINT_ATTR,
516 					   BT_GATT_CCC_NOTIFY | BT_GATT_CCC_INDICATE)) {
517 			continue;
518 		}
519 
520 		err = control_point_send(client, buf);
521 		if (err) {
522 			result = err;
523 			/* continue anyway */
524 		}
525 	}
526 
527 	return result;
528 }
529 
bt_has_cp_read_preset_rsp(struct has_client * client,const struct has_preset * preset,bool is_last)530 static int bt_has_cp_read_preset_rsp(struct has_client *client, const struct has_preset *preset,
531 				     bool is_last)
532 {
533 	struct bt_has_cp_hdr *hdr;
534 	struct bt_has_cp_read_preset_rsp *rsp;
535 
536 	NET_BUF_SIMPLE_DEFINE(buf, sizeof(*hdr) + sizeof(*rsp) + BT_HAS_PRESET_NAME_MAX);
537 
538 	LOG_DBG("conn %p preset %p is_last 0x%02x", (void *)client->conn, preset, is_last);
539 
540 	hdr = net_buf_simple_add(&buf, sizeof(*hdr));
541 	hdr->opcode = BT_HAS_OP_READ_PRESET_RSP;
542 	rsp = net_buf_simple_add(&buf, sizeof(*rsp));
543 	rsp->is_last = is_last ? 0x01 : 0x00;
544 	rsp->index = preset->index;
545 	rsp->properties = preset->properties;
546 	net_buf_simple_add_mem(&buf, preset->name, strlen(preset->name));
547 
548 	return control_point_send(client, &buf);
549 }
550 
get_prev_preset_index(const struct has_preset * preset)551 static uint8_t get_prev_preset_index(const struct has_preset *preset)
552 {
553 	const struct has_preset *prev = NULL;
554 
555 	for (size_t i = 0; i < ARRAY_SIZE(has_preset_list); i++) {
556 		const struct has_preset *tmp = &has_preset_list[i];
557 
558 		if (tmp->index == BT_HAS_PRESET_INDEX_NONE || tmp == preset) {
559 			break;
560 		}
561 
562 		prev = tmp;
563 	}
564 
565 	return prev ? prev->index : BT_HAS_PRESET_INDEX_NONE;
566 }
567 
preset_changed_prepare(struct net_buf_simple * buf,uint8_t change_id,uint8_t is_last)568 static void preset_changed_prepare(struct net_buf_simple *buf, uint8_t change_id, uint8_t is_last)
569 {
570 	struct bt_has_cp_hdr *hdr;
571 	struct bt_has_cp_preset_changed *preset_changed;
572 
573 	hdr = net_buf_simple_add(buf, sizeof(*hdr));
574 	hdr->opcode = BT_HAS_OP_PRESET_CHANGED;
575 	preset_changed = net_buf_simple_add(buf, sizeof(*preset_changed));
576 	preset_changed->change_id = change_id;
577 	preset_changed->is_last = is_last;
578 }
579 
bt_has_cp_generic_update(struct has_client * client,const struct has_preset * preset,uint8_t is_last)580 static int bt_has_cp_generic_update(struct has_client *client, const struct has_preset *preset,
581 				    uint8_t is_last)
582 {
583 	struct bt_has_cp_generic_update *generic_update;
584 
585 	NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
586 			      sizeof(struct bt_has_cp_preset_changed) +
587 			      sizeof(struct bt_has_cp_generic_update) + BT_HAS_PRESET_NAME_MAX);
588 
589 	preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_GENERIC_UPDATE, is_last);
590 
591 	generic_update = net_buf_simple_add(&buf, sizeof(*generic_update));
592 	generic_update->prev_index = get_prev_preset_index(preset);
593 	generic_update->index = preset->index;
594 	generic_update->properties = preset->properties;
595 	net_buf_simple_add_mem(&buf, preset->name, strlen(preset->name));
596 
597 	if (client) {
598 		return control_point_send(client, &buf);
599 	} else {
600 		return control_point_send_all(&buf);
601 	}
602 }
603 
process_control_point_work(struct k_work * work)604 static void process_control_point_work(struct k_work *work)
605 {
606 	struct has_client *client = CONTAINER_OF(work, struct has_client, control_point_work);
607 	int err;
608 
609 	if (!client->conn) {
610 		return;
611 	}
612 
613 	if (read_presets_req_pending_cp(client)) {
614 		const struct has_preset *preset = NULL;
615 		bool is_last = true;
616 
617 		preset_foreach(client->read_presets_req.start_index, BT_HAS_PRESET_INDEX_LAST,
618 			       preset_found, &preset);
619 
620 		if (unlikely(preset == NULL)) {
621 			(void)bt_has_cp_read_preset_rsp(client, NULL, 0x01);
622 
623 			return;
624 		}
625 
626 		if (client->read_presets_req.num_presets > 1) {
627 			const struct has_preset *next = NULL;
628 
629 			preset_foreach(preset->index + 1, BT_HAS_PRESET_INDEX_LAST,
630 				       preset_found, &next);
631 
632 			is_last = next == NULL;
633 
634 		}
635 
636 		err = bt_has_cp_read_preset_rsp(client, preset, is_last);
637 		if (err) {
638 			LOG_ERR("bt_has_cp_read_preset_rsp failed (err %d)", err);
639 		}
640 
641 		if (err || is_last) {
642 			read_presets_req_free(client);
643 		} else {
644 			client->read_presets_req.start_index = preset->index + 1;
645 			client->read_presets_req.num_presets--;
646 		}
647 	} else if (atomic_test_and_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY)) {
648 		const struct has_preset *preset = NULL;
649 		const struct has_preset *next = NULL;
650 		bool is_last = true;
651 
652 		preset_foreach(client->preset_changed_index_next,
653 			       BT_HAS_PRESET_INDEX_LAST, preset_found, &preset);
654 
655 		if (preset == NULL) {
656 			return;
657 		}
658 
659 		preset_foreach(preset->index + 1, BT_HAS_PRESET_INDEX_LAST,
660 			       preset_found, &next);
661 
662 		is_last = next == NULL;
663 
664 		err = bt_has_cp_generic_update(client, preset, is_last);
665 		if (err) {
666 			LOG_ERR("bt_has_cp_read_preset_rsp failed (err %d)", err);
667 		}
668 
669 		if (err || is_last) {
670 			atomic_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY);
671 		} else {
672 			client->preset_changed_index_next = preset->index + 1;
673 		}
674 	}
675 }
676 
handle_read_preset_req(struct bt_conn * conn,struct net_buf_simple * buf)677 static uint8_t handle_read_preset_req(struct bt_conn *conn, struct net_buf_simple *buf)
678 {
679 	const struct bt_has_cp_read_presets_req *req;
680 	const struct has_preset *preset = NULL;
681 	struct has_client *client;
682 
683 	if (buf->len < sizeof(*req)) {
684 		return BT_HAS_ERR_INVALID_PARAM_LEN;
685 	}
686 
687 	/* As per HAS_d1.0r00 Client Characteristic Configuration Descriptor Improperly Configured
688 	 * shall be returned if client writes Read Presets Request but is not registered for
689 	 * indications.
690 	 */
691 	if (!bt_gatt_is_subscribed(conn, PRESET_CONTROL_POINT_ATTR, BT_GATT_CCC_INDICATE)) {
692 		return BT_ATT_ERR_CCC_IMPROPER_CONF;
693 	}
694 
695 	client = client_get(conn);
696 	if (!client) {
697 		return BT_ATT_ERR_UNLIKELY;
698 	}
699 
700 	req = net_buf_simple_pull_mem(buf, sizeof(*req));
701 
702 	LOG_DBG("start_index %d num_presets %d", req->start_index, req->num_presets);
703 
704 	/* Abort if there is no preset in requested index range */
705 	preset_foreach(req->start_index, BT_HAS_PRESET_INDEX_LAST, preset_found, &preset);
706 
707 	if (preset == NULL) {
708 		return BT_ATT_ERR_OUT_OF_RANGE;
709 	}
710 
711 	/* Reject if already in progress */
712 	if (read_presets_req_pending_cp(client)) {
713 		return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
714 	}
715 
716 	/* Store the request */
717 	client->read_presets_req.start_index = req->start_index;
718 	client->read_presets_req.num_presets = req->num_presets;
719 
720 	k_work_submit(&client->control_point_work);
721 
722 	return 0;
723 }
724 
set_preset_name(uint8_t index,const char * name,size_t len)725 static int set_preset_name(uint8_t index, const char *name, size_t len)
726 {
727 	struct has_preset *preset = NULL;
728 
729 	LOG_DBG("index %d name_len %zu", index, len);
730 
731 	if (len < BT_HAS_PRESET_NAME_MIN || len > BT_HAS_PRESET_NAME_MAX) {
732 		return -EINVAL;
733 	}
734 
735 	/* Abort if there is no preset in requested index range */
736 	preset_foreach(index, BT_HAS_PRESET_INDEX_LAST, preset_found, &preset);
737 
738 	if (preset == NULL) {
739 		return -ENOENT;
740 	}
741 
742 	if (!(preset->properties & BT_HAS_PROP_WRITABLE)) {
743 		return -EPERM;
744 	}
745 
746 	IF_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC, (
747 		__ASSERT(len < ARRAY_SIZE(preset->name), "No space for name");
748 
749 		(void)memcpy(preset->name, name, len);
750 
751 		/* NULL-terminate string */
752 		preset->name[len] = '\0';
753 
754 		/* Properly truncate a NULL-terminated UTF-8 string */
755 		utf8_trunc(preset->name);
756 	));
757 
758 	if (preset->ops->name_changed) {
759 		preset->ops->name_changed(index, preset->name);
760 	}
761 
762 	return bt_has_cp_generic_update(NULL, preset, BT_HAS_IS_LAST);
763 }
764 
handle_write_preset_name(struct bt_conn * conn,struct net_buf_simple * buf)765 static uint8_t handle_write_preset_name(struct bt_conn *conn, struct net_buf_simple *buf)
766 {
767 	const struct bt_has_cp_write_preset_name *req;
768 	struct has_client *client;
769 	int err;
770 
771 	if (buf->len < sizeof(*req)) {
772 		return BT_HAS_ERR_INVALID_PARAM_LEN;
773 	}
774 
775 	/* As per HAS_v1.0 Client Characteristic Configuration Descriptor Improperly Configured
776 	 * shall be returned if client writes Write Preset Name opcode but is not registered for
777 	 * indications.
778 	 */
779 	if (!bt_gatt_is_subscribed(conn, PRESET_CONTROL_POINT_ATTR, BT_GATT_CCC_INDICATE)) {
780 		return BT_ATT_ERR_CCC_IMPROPER_CONF;
781 	}
782 
783 	client = client_get(conn);
784 	if (!client) {
785 		return BT_ATT_ERR_UNLIKELY;
786 	}
787 
788 	req = net_buf_simple_pull_mem(buf, sizeof(*req));
789 
790 	err = set_preset_name(req->index, req->name, buf->len);
791 	if (err == -EINVAL) {
792 		return BT_HAS_ERR_INVALID_PARAM_LEN;
793 	} else if (err == -ENOENT) {
794 		return BT_ATT_ERR_OUT_OF_RANGE;
795 	} else if (err == -EPERM) {
796 		return BT_HAS_ERR_WRITE_NAME_NOT_ALLOWED;
797 	} else if (err) {
798 		return BT_ATT_ERR_UNLIKELY;
799 	}
800 
801 	return BT_ATT_ERR_SUCCESS;
802 }
803 
active_preset_work_process(struct k_work * work)804 static void active_preset_work_process(struct k_work *work)
805 {
806 	const uint8_t active_index = bt_has_preset_active_get();
807 
808 	for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) {
809 		struct has_client *client = &has_client_list[i];
810 		int err;
811 
812 		if (client->conn == NULL) {
813 			/* mark to notify on reconnect */
814 			atomic_set_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED);
815 			continue;
816 		} else if (atomic_test_and_clear_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED)) {
817 			err = bt_gatt_notify(client->conn, ACTIVE_PRESET_INDEX_ATTR, &active_index,
818 					     sizeof(active_index));
819 			if (err != 0) {
820 				LOG_DBG("failed to notify active_index for %p: %d", client->conn,
821 				     err);
822 			}
823 		}
824 	}
825 }
826 
preset_active_set(uint8_t index)827 static void preset_active_set(uint8_t index)
828 {
829 	if (index != has.active_index) {
830 		has.active_index = index;
831 
832 	for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) {
833 		struct has_client *client = &has_client_list[i];
834 			/* mark to notify */
835 		atomic_set_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED);
836 	}
837 
838 		/* Emit active preset notification */
839 		k_work_submit(&active_preset_work);
840 	}
841 }
842 
preset_select(const struct has_preset * preset,bool sync)843 static uint8_t preset_select(const struct has_preset *preset, bool sync)
844 {
845 	const int err = preset->ops->select(preset->index, sync);
846 
847 	if (err == -EINPROGRESS) {
848 		/* User has to confirm once the requested preset becomes active by
849 		 * calling bt_has_preset_active_set.
850 		 */
851 		return 0;
852 	}
853 
854 	if (err == -EBUSY) {
855 		return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
856 	}
857 
858 	if (err) {
859 		return BT_ATT_ERR_UNLIKELY;
860 	}
861 
862 	preset_active_set(preset->index);
863 
864 	return 0;
865 }
866 
handle_set_active_preset(struct net_buf_simple * buf,bool sync)867 static uint8_t handle_set_active_preset(struct net_buf_simple *buf, bool sync)
868 {
869 	const struct bt_has_cp_set_active_preset *pdu;
870 	const struct has_preset *preset = NULL;
871 
872 	if (buf->len < sizeof(*pdu)) {
873 		return BT_HAS_ERR_INVALID_PARAM_LEN;
874 	}
875 
876 	pdu = net_buf_simple_pull_mem(buf, sizeof(*pdu));
877 
878 	preset_foreach(pdu->index, pdu->index, preset_found, &preset);
879 	if (preset == NULL) {
880 		return BT_ATT_ERR_OUT_OF_RANGE;
881 	}
882 
883 	if (!(preset->properties & BT_HAS_PROP_AVAILABLE)) {
884 		return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
885 	}
886 
887 	return preset_select(preset, sync);
888 }
889 
handle_set_next_preset(bool sync)890 static uint8_t handle_set_next_preset(bool sync)
891 {
892 	const struct has_preset *next_avail = NULL;
893 	const struct has_preset *first_avail = NULL;
894 
895 	for (size_t i = 0; i < has_preset_num; i++) {
896 		const struct has_preset *tmp = &has_preset_list[i];
897 
898 		if (tmp->index == BT_HAS_PRESET_INDEX_NONE) {
899 			break;
900 		}
901 
902 		if (!(tmp->properties & BT_HAS_PROP_AVAILABLE)) {
903 			continue;
904 		}
905 
906 		if (tmp->index < has.active_index && !first_avail) {
907 			first_avail = tmp;
908 			continue;
909 		}
910 
911 		if (tmp->index > has.active_index) {
912 			next_avail = tmp;
913 			break;
914 		}
915 	}
916 
917 	if (next_avail) {
918 		return preset_select(next_avail, sync);
919 	}
920 
921 	if (first_avail) {
922 		return preset_select(first_avail, sync);
923 	}
924 
925 	return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
926 }
927 
handle_set_prev_preset(bool sync)928 static uint8_t handle_set_prev_preset(bool sync)
929 {
930 	const struct has_preset *prev_available = NULL;
931 	const struct has_preset *last_available = NULL;
932 
933 	for (size_t i = 0; i < ARRAY_SIZE(has_preset_list); i++) {
934 		const struct has_preset *tmp = &has_preset_list[i];
935 
936 		if (tmp->index == BT_HAS_PRESET_INDEX_NONE) {
937 			break;
938 		}
939 
940 		if (!(tmp->properties & BT_HAS_PROP_AVAILABLE)) {
941 			continue;
942 		}
943 
944 		if (tmp->index < has.active_index) {
945 			prev_available = tmp;
946 			continue;
947 		}
948 
949 		if (prev_available) {
950 			break;
951 		}
952 
953 		if (tmp->index > has.active_index) {
954 			last_available = tmp;
955 			continue;
956 		}
957 	}
958 
959 	if (prev_available) {
960 		return preset_select(prev_available, sync);
961 	}
962 
963 	if (last_available) {
964 		return preset_select(last_available, sync);
965 	}
966 
967 	return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
968 }
969 
handle_control_point_op(struct bt_conn * conn,struct net_buf_simple * buf)970 static uint8_t handle_control_point_op(struct bt_conn *conn, struct net_buf_simple *buf)
971 {
972 	const struct bt_has_cp_hdr *hdr;
973 
974 	hdr = net_buf_simple_pull_mem(buf, sizeof(*hdr));
975 
976 	LOG_DBG("conn %p opcode %s (0x%02x)", (void *)conn, bt_has_op_str(hdr->opcode),
977 		hdr->opcode);
978 
979 	switch (hdr->opcode) {
980 	case BT_HAS_OP_READ_PRESET_REQ:
981 		return handle_read_preset_req(conn, buf);
982 	case BT_HAS_OP_WRITE_PRESET_NAME:
983 		if (IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) {
984 			return handle_write_preset_name(conn, buf);
985 		}
986 		break;
987 	case BT_HAS_OP_SET_ACTIVE_PRESET:
988 		return handle_set_active_preset(buf, false);
989 	case BT_HAS_OP_SET_NEXT_PRESET:
990 		return handle_set_next_preset(false);
991 	case BT_HAS_OP_SET_PREV_PRESET:
992 		return handle_set_prev_preset(false);
993 	case BT_HAS_OP_SET_ACTIVE_PRESET_SYNC:
994 		if ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0) {
995 			return handle_set_active_preset(buf, true);
996 		} else {
997 			return BT_HAS_ERR_PRESET_SYNC_NOT_SUPP;
998 		}
999 	case BT_HAS_OP_SET_NEXT_PRESET_SYNC:
1000 		if ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0) {
1001 			return handle_set_next_preset(true);
1002 		} else {
1003 			return BT_HAS_ERR_PRESET_SYNC_NOT_SUPP;
1004 		}
1005 	case BT_HAS_OP_SET_PREV_PRESET_SYNC:
1006 		if ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0) {
1007 			return handle_set_prev_preset(true);
1008 		} else {
1009 			return BT_HAS_ERR_PRESET_SYNC_NOT_SUPP;
1010 		}
1011 	};
1012 
1013 	return BT_HAS_ERR_INVALID_OPCODE;
1014 }
1015 
write_control_point(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * data,uint16_t len,uint16_t offset,uint8_t flags)1016 static ssize_t write_control_point(struct bt_conn *conn, const struct bt_gatt_attr *attr,
1017 				   const void *data, uint16_t len, uint16_t offset, uint8_t flags)
1018 {
1019 	struct net_buf_simple buf;
1020 	uint8_t err;
1021 
1022 	LOG_DBG("conn %p attr %p data %p len %d offset %d flags 0x%02x", (void *)conn, attr, data,
1023 		len, offset, flags);
1024 
1025 	if (offset > 0) {
1026 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
1027 	}
1028 
1029 	if (len == 0) {
1030 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
1031 	}
1032 
1033 	net_buf_simple_init_with_data(&buf, (void *)data, len);
1034 
1035 	err = handle_control_point_op(conn, &buf);
1036 	if (err) {
1037 		LOG_WRN("err 0x%02x", err);
1038 		return BT_GATT_ERR(err);
1039 	}
1040 
1041 	return len;
1042 }
1043 
bt_has_preset_register(const struct bt_has_preset_register_param * param)1044 int bt_has_preset_register(const struct bt_has_preset_register_param *param)
1045 {
1046 	struct has_preset *preset = NULL;
1047 	size_t name_len;
1048 
1049 	CHECKIF(param == NULL) {
1050 		LOG_ERR("param is NULL");
1051 		return -EINVAL;
1052 	}
1053 
1054 	CHECKIF(param->index == BT_HAS_PRESET_INDEX_NONE) {
1055 		LOG_ERR("param->index is invalid");
1056 		return -EINVAL;
1057 	}
1058 
1059 	CHECKIF(param->name == NULL) {
1060 		LOG_ERR("param->name is NULL");
1061 		return -EINVAL;
1062 	}
1063 
1064 	name_len = strlen(param->name);
1065 
1066 	CHECKIF(name_len < BT_HAS_PRESET_NAME_MIN) {
1067 		LOG_ERR("param->name is too short (%zu < %u)", name_len, BT_HAS_PRESET_NAME_MIN);
1068 		return -EINVAL;
1069 	}
1070 
1071 	CHECKIF(name_len > BT_HAS_PRESET_NAME_MAX) {
1072 		LOG_WRN("param->name is too long (%zu > %u)", name_len, BT_HAS_PRESET_NAME_MAX);
1073 	}
1074 
1075 	CHECKIF(param->ops == NULL) {
1076 		LOG_ERR("param->ops is NULL");
1077 		return -EINVAL;
1078 	}
1079 
1080 	CHECKIF(param->ops->select == NULL) {
1081 		LOG_ERR("param->ops->select is NULL");
1082 		return -EINVAL;
1083 	}
1084 
1085 	preset_foreach(param->index, param->index, preset_found, &preset);
1086 	if (preset != NULL) {
1087 		return -EALREADY;
1088 	}
1089 
1090 	preset = preset_alloc(param->index, param->properties, param->name, param->ops);
1091 	if (preset == NULL) {
1092 		return -ENOMEM;
1093 	}
1094 
1095 	return bt_has_cp_generic_update(NULL, preset, BT_HAS_IS_LAST);
1096 }
1097 
bt_has_preset_unregister(uint8_t index)1098 int bt_has_preset_unregister(uint8_t index)
1099 {
1100 	struct has_preset *preset = NULL;
1101 
1102 	NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
1103 			      sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t));
1104 
1105 	CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) {
1106 		LOG_ERR("index is invalid");
1107 		return -EINVAL;
1108 	}
1109 
1110 	preset_foreach(index, index, preset_found, &preset);
1111 	if (preset == NULL) {
1112 		return -ENOENT;
1113 	}
1114 
1115 	preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_DELETED, BT_HAS_IS_LAST);
1116 	net_buf_simple_add_u8(&buf, preset->index);
1117 
1118 	preset_free(preset);
1119 
1120 	return control_point_send_all(&buf);
1121 }
1122 
bt_has_preset_available(uint8_t index)1123 int bt_has_preset_available(uint8_t index)
1124 {
1125 	struct has_preset *preset = NULL;
1126 
1127 	CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) {
1128 		LOG_ERR("index is invalid");
1129 		return -EINVAL;
1130 	}
1131 
1132 	preset_foreach(index, index, preset_found, &preset);
1133 	if (preset == NULL) {
1134 		return -ENOENT;
1135 	}
1136 
1137 	/* toggle property bit if needed */
1138 	if (!(preset->properties & BT_HAS_PROP_AVAILABLE)) {
1139 		NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
1140 				      sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t));
1141 
1142 		preset->properties ^= BT_HAS_PROP_AVAILABLE;
1143 
1144 		preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_AVAILABLE, BT_HAS_IS_LAST);
1145 		net_buf_simple_add_u8(&buf, preset->index);
1146 
1147 		return control_point_send_all(&buf);
1148 	}
1149 
1150 	return 0;
1151 }
1152 
bt_has_preset_unavailable(uint8_t index)1153 int bt_has_preset_unavailable(uint8_t index)
1154 {
1155 	struct has_preset *preset = NULL;
1156 
1157 	CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) {
1158 		LOG_ERR("index is invalid");
1159 		return -EINVAL;
1160 	}
1161 
1162 	preset_foreach(index, index, preset_found, &preset);
1163 	if (preset == NULL) {
1164 		return -ENOENT;
1165 	}
1166 
1167 	/* toggle property bit if needed */
1168 	if (preset->properties & BT_HAS_PROP_AVAILABLE) {
1169 		NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
1170 				      sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t));
1171 
1172 		preset->properties ^= BT_HAS_PROP_AVAILABLE;
1173 
1174 		preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_UNAVAILABLE, BT_HAS_IS_LAST);
1175 		net_buf_simple_add_u8(&buf, preset->index);
1176 
1177 		return control_point_send_all(&buf);
1178 	}
1179 
1180 	return 0;
1181 }
1182 
1183 struct bt_has_preset_foreach_data {
1184 	bt_has_preset_func_t func;
1185 	void *user_data;
1186 };
1187 
bt_has_preset_foreach_func(const struct has_preset * preset,void * user_data)1188 static uint8_t bt_has_preset_foreach_func(const struct has_preset *preset, void *user_data)
1189 {
1190 	const struct bt_has_preset_foreach_data *data = user_data;
1191 
1192 	return data->func(preset->index, preset->properties, preset->name, data->user_data);
1193 }
1194 
bt_has_preset_foreach(uint8_t index,bt_has_preset_func_t func,void * user_data)1195 void bt_has_preset_foreach(uint8_t index, bt_has_preset_func_t func, void *user_data)
1196 {
1197 	uint8_t start_index, end_index;
1198 	struct bt_has_preset_foreach_data data = {
1199 		.func = func,
1200 		.user_data = user_data,
1201 	};
1202 
1203 	if (index == BT_HAS_PRESET_INDEX_NONE) {
1204 		start_index = BT_HAS_PRESET_INDEX_FIRST;
1205 		end_index = BT_HAS_PRESET_INDEX_LAST;
1206 	} else {
1207 		start_index = end_index = index;
1208 	}
1209 
1210 	preset_foreach(start_index, end_index, bt_has_preset_foreach_func, &data);
1211 }
1212 
bt_has_preset_active_set(uint8_t index)1213 int bt_has_preset_active_set(uint8_t index)
1214 {
1215 	if (index != BT_HAS_PRESET_INDEX_NONE) {
1216 		struct has_preset *preset = NULL;
1217 
1218 		preset_foreach(index, index, preset_found, &preset);
1219 		if (preset == NULL) {
1220 			return -ENOENT;
1221 		}
1222 
1223 		if (!(preset->properties & BT_HAS_PROP_AVAILABLE)) {
1224 			return -EINVAL;
1225 		}
1226 	}
1227 
1228 	preset_active_set(index);
1229 
1230 	return 0;
1231 }
1232 
bt_has_preset_active_get(void)1233 uint8_t bt_has_preset_active_get(void)
1234 {
1235 	return has.active_index;
1236 }
1237 
bt_has_preset_name_change(uint8_t index,const char * name)1238 int bt_has_preset_name_change(uint8_t index, const char *name)
1239 {
1240 	CHECKIF(name == NULL) {
1241 		return -EINVAL;
1242 	}
1243 
1244 	if (IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) {
1245 		return set_preset_name(index, name, strlen(name));
1246 	} else {
1247 		return -EOPNOTSUPP;
1248 	}
1249 }
1250 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
1251 
has_features_register(const struct bt_has_features_param * features)1252 static int has_features_register(const struct bt_has_features_param *features)
1253 {
1254 	/* Initialize the supported features characteristic value */
1255 	has.features = features->type;
1256 
1257 	if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT)) {
1258 		has.features |= BT_HAS_FEAT_DYNAMIC_PRESETS;
1259 
1260 		if (features->preset_sync_support) {
1261 			if (features->type != BT_HAS_HEARING_AID_TYPE_BINAURAL) {
1262 				LOG_DBG("Preset sync support only available "
1263 					"for binaural hearing aid type");
1264 				return -EINVAL;
1265 			}
1266 
1267 			has.features |= BT_HAS_FEAT_PRESET_SYNC_SUPP;
1268 		}
1269 
1270 		if (features->independent_presets) {
1271 			if (features->type != BT_HAS_HEARING_AID_TYPE_BINAURAL) {
1272 				LOG_DBG("Independent presets only available "
1273 					"for binaural hearing aid type");
1274 				return -EINVAL;
1275 			}
1276 
1277 			has.features |= BT_HAS_FEAT_INDEPENDENT_PRESETS;
1278 		}
1279 	}
1280 
1281 	if (IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) {
1282 		has.features |= BT_HAS_FEAT_WRITABLE_PRESETS_SUPP;
1283 	}
1284 
1285 	return 0;
1286 }
1287 
1288 #if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
features_work_process(struct k_work * work)1289 static void features_work_process(struct k_work *work)
1290 {
1291 	for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) {
1292 		struct has_client *client = &has_client_list[i];
1293 		int err;
1294 
1295 		if (client->conn == NULL) {
1296 			/* mark to notify on reconnect */
1297 			atomic_set_bit(client->flags, FLAG_FEATURES_CHANGED);
1298 			continue;
1299 		} else if (atomic_test_and_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY)) {
1300 			err = bt_gatt_notify(client->conn, FEATURES_ATTR, &has.features,
1301 					     sizeof(has.features));
1302 			if (err != 0) {
1303 				LOG_DBG("failed to notify features for %p: %d",	client->conn, err);
1304 			}
1305 		}
1306 	}
1307 }
1308 
bt_has_features_set(const struct bt_has_features_param * features)1309 int bt_has_features_set(const struct bt_has_features_param *features)
1310 {
1311 	uint8_t tmp_features;
1312 	int err;
1313 
1314 	if (!has.registered) {
1315 		return -ENOTSUP;
1316 	}
1317 
1318 	/* Check whether any features will change, otherwise we don't want to notify clients */
1319 	if (FEATURE_DEVICE_TYPE_UNCHANGED(features->type) &&
1320 	    FEATURE_SYNC_SUPPORT_UNCHANGED(features->preset_sync_support) &&
1321 	    FEATURE_IND_PRESETS_UNCHANGED(features->independent_presets)) {
1322 		return 0;
1323 	}
1324 
1325 	tmp_features = has.features;
1326 
1327 	err = has_features_register(features);
1328 	if (err != 0) {
1329 		LOG_DBG("Failed to register features");
1330 		return err;
1331 	}
1332 
1333 	bool tmp_pending_ntf_features[ARRAY_SIZE(has_client_list)];
1334 
1335 	for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) {
1336 		struct has_client *client = &has_client_list[i];
1337 		/* save old state */
1338 		tmp_pending_ntf_features[i] = atomic_test_bit(client->flags, FLAG_FEATURES_CHANGED);
1339 		/* mark to notify */
1340 		atomic_set_bit(client->flags, FLAG_FEATURES_CHANGED);
1341 	}
1342 
1343 	err = k_work_submit(&features_work);
1344 	if (err < 0) {
1345 		/* restore old values */
1346 		for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) {
1347 			struct has_client *client = &has_client_list[i];
1348 
1349 			atomic_set_bit_to(client->flags, FLAG_FEATURES_CHANGED,
1350 					  tmp_pending_ntf_features[i]);
1351 		}
1352 		has.features = tmp_features;
1353 
1354 		return err;
1355 	}
1356 
1357 	return 0;
1358 }
1359 #endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
1360 
bt_has_register(const struct bt_has_features_param * features)1361 int bt_has_register(const struct bt_has_features_param *features)
1362 {
1363 	int err;
1364 
1365 	LOG_DBG("features %p", features);
1366 
1367 	CHECKIF(!features) {
1368 		LOG_DBG("NULL params pointer");
1369 		return -EINVAL;
1370 	}
1371 
1372 	if (has.registered) {
1373 		return -EALREADY;
1374 	}
1375 
1376 	err = has_features_register(features);
1377 	if (err != 0) {
1378 		LOG_DBG("HAS service failed to register features: %d", err);
1379 		return err;
1380 	}
1381 
1382 	has_svc = (struct bt_gatt_service)BT_GATT_SERVICE(has_attrs);
1383 	err = bt_gatt_service_register(&has_svc);
1384 	if (err != 0) {
1385 		LOG_DBG("HAS service register failed: %d", err);
1386 		return err;
1387 	}
1388 
1389 	has.registered = true;
1390 
1391 	return 0;
1392 }
1393