1 /**
2 * @file
3 * @brief Bluetooth Hearing Access Service (HAS) APIs.
4 */
5
6 /*
7 * Copyright (c) 2022 Codecoup
8 * Copyright (c) 2024 Nordic Semiconductor ASA
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13 #ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_HAS_H_
14 #define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_HAS_H_
15
16 /**
17 * @brief Hearing Access Service (HAS)
18 *
19 * @defgroup bt_has Hearing Access Service (HAS)
20 *
21 * @since 3.1
22 * @version 0.8.0
23 *
24 * @ingroup bluetooth
25 * @{
26 *
27 * The Hearing Access Service is used to identify a hearing aid and optionally
28 * to control hearing aid presets.
29 */
30
31 #include <stdint.h>
32 #include <stdbool.h>
33
34 #include <zephyr/bluetooth/bluetooth.h>
35 #include <zephyr/sys/util.h>
36 #include <zephyr/sys/util_macro.h>
37
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41
42 /**
43 * @name Preset index definitions
44 * @{
45 */
46 /** No index */
47 #define BT_HAS_PRESET_INDEX_NONE 0x00
48 /** First preset index */
49 #define BT_HAS_PRESET_INDEX_FIRST 0x01
50 /** Last preset index */
51 #define BT_HAS_PRESET_INDEX_LAST 0xFF
52 /** @} */
53
54 /** Preset name minimum length */
55 #define BT_HAS_PRESET_NAME_MIN 1
56 /** Preset name maximum length */
57 #define BT_HAS_PRESET_NAME_MAX 40
58
59 /** @brief Opaque Hearing Access Service object. */
60 struct bt_has;
61
62 /** Hearing Aid device type */
63 enum bt_has_hearing_aid_type {
64 /**
65 * Two hearing aids that form a Coordinated Set, one for the right ear and one for the left
66 * ear of the user. Typically used by a user with bilateral hearing loss.
67 */
68 BT_HAS_HEARING_AID_TYPE_BINAURAL = 0x00,
69 /**
70 * A single hearing aid for the left or the right ear. Typically used by a user with
71 * unilateral hearing loss.
72 */
73 BT_HAS_HEARING_AID_TYPE_MONAURAL = 0x01,
74 /**
75 * Two hearing aids with a connection to one another that expose a single Bluetooth radio
76 * interface.
77 */
78 BT_HAS_HEARING_AID_TYPE_BANDED = 0x02,
79 };
80
81 /** Preset Properties values */
82 enum bt_has_properties {
83 /** No properties set */
84 BT_HAS_PROP_NONE = 0,
85
86 /** Preset name can be written by the client */
87 BT_HAS_PROP_WRITABLE = BIT(0),
88
89 /** Preset availability */
90 BT_HAS_PROP_AVAILABLE = BIT(1),
91 };
92
93 /** Hearing Aid device capabilities */
94 enum bt_has_capabilities {
95 /** Indicate support for presets */
96 BT_HAS_PRESET_SUPPORT = BIT(0),
97 };
98
99 /** @brief Structure for registering features of a Hearing Access Service instance. */
100 struct bt_has_features_param {
101 /** Hearing Aid Type value */
102 enum bt_has_hearing_aid_type type;
103
104 /**
105 * @brief Preset Synchronization Support.
106 *
107 * Only applicable if @p type is @ref BT_HAS_HEARING_AID_TYPE_BINAURAL
108 * and @kconfig{CONFIG_BT_HAS_PRESET_COUNT} is non-zero.
109 */
110 bool preset_sync_support;
111
112 /**
113 * @brief Independent Presets.
114 *
115 * Only applicable if @p type is @ref BT_HAS_HEARING_AID_TYPE_BINAURAL
116 * and @kconfig{CONFIG_BT_HAS_PRESET_COUNT} is non-zero.
117 */
118 bool independent_presets;
119 };
120
121 /** @brief Preset record definition */
122 struct bt_has_preset_record {
123 /** Unique preset index. */
124 uint8_t index;
125
126 /** Bitfield of preset properties. */
127 enum bt_has_properties properties;
128
129 /** Preset name. */
130 const char *name;
131 };
132
133 /** @brief Hearing Access Service Client callback structure. */
134 struct bt_has_client_cb {
135 /**
136 * @brief Callback function for bt_has_discover.
137 *
138 * This callback is called when discovery procedure is complete.
139 *
140 * @param conn Bluetooth connection object.
141 * @param err 0 on success, ATT error or negative errno otherwise.
142 * @param has Pointer to the Hearing Access Service object or NULL on errors.
143 * @param type Hearing Aid type.
144 * @param caps Hearing Aid capabilities.
145 */
146 void (*discover)(struct bt_conn *conn, int err, struct bt_has *has,
147 enum bt_has_hearing_aid_type type, enum bt_has_capabilities caps);
148
149 /**
150 * @brief Callback function for Hearing Access Service active preset changes.
151 *
152 * Optional callback called when the active preset is changed by the remote server when the
153 * preset switch procedure is complete. The callback must be set to receive active preset
154 * changes and enable support for switching presets. If the callback is not set, the Active
155 * Index and Control Point characteristics will not be discovered by
156 * @ref bt_has_client_discover.
157 *
158 * @param has Pointer to the Hearing Access Service object.
159 * @param err 0 on success, ATT error or negative errno otherwise.
160 * @param index Active preset index.
161 */
162 void (*preset_switch)(struct bt_has *has, int err, uint8_t index);
163
164 /**
165 * @brief Callback function for presets read operation.
166 *
167 * The callback is called when the preset read response is sent by the remote server.
168 * The record object as well as its members are temporary and must be copied to in order
169 * to cache its information.
170 *
171 * @param has Pointer to the Hearing Access Service object.
172 * @param err 0 on success, ATT error or negative errno otherwise.
173 * @param record Preset record or NULL on errors.
174 * @param is_last True if Read Presets operation can be considered concluded.
175 */
176 void (*preset_read_rsp)(struct bt_has *has, int err,
177 const struct bt_has_preset_record *record, bool is_last);
178
179 /**
180 * @brief Callback function for preset update notifications.
181 *
182 * The callback is called when the preset record update is notified by the remote server.
183 * The record object as well as its objects are temporary and must be copied to in order
184 * to cache its information.
185 *
186 * @param has Pointer to the Hearing Access Service object.
187 * @param index_prev Index of the previous preset in the list.
188 * @param record Preset record.
189 * @param is_last True if preset list update operation can be considered concluded.
190 */
191 void (*preset_update)(struct bt_has *has, uint8_t index_prev,
192 const struct bt_has_preset_record *record, bool is_last);
193
194 /**
195 * @brief Callback function for preset deletion notifications.
196 *
197 * The callback is called when the preset has been deleted by the remote server.
198 *
199 * @param has Pointer to the Hearing Access Service object.
200 * @param index Preset index.
201 * @param is_last True if preset list update operation can be considered concluded.
202 */
203 void (*preset_deleted)(struct bt_has *has, uint8_t index, bool is_last);
204
205 /**
206 * @brief Callback function for preset availability notifications.
207 *
208 * The callback is called when the preset availability change is notified by the remote
209 * server.
210 *
211 * @param has Pointer to the Hearing Access Service object.
212 * @param index Preset index.
213 * @param available True if available, false otherwise.
214 * @param is_last True if preset list update operation can be considered concluded.
215 */
216 void (*preset_availability)(struct bt_has *has, uint8_t index, bool available,
217 bool is_last);
218 };
219
220 /**
221 * @brief Registers the callbacks used by the Hearing Access Service client.
222 *
223 * @param cb The callback structure.
224 *
225 * @return 0 in case of success or negative value in case of error.
226 */
227 int bt_has_client_cb_register(const struct bt_has_client_cb *cb);
228
229 /**
230 * @brief Discover Hearing Access Service on a remote device.
231 *
232 * Client method to find a Hearing Access Service on a server identified by @p conn.
233 * The @ref bt_has_client_cb.discover callback will be called when the discovery procedure
234 * is complete to provide user a @ref bt_has object.
235 *
236 * @param conn Bluetooth connection object.
237 *
238 * @return 0 if success, errno on failure.
239 */
240 int bt_has_client_discover(struct bt_conn *conn);
241
242 /**
243 * @brief Get the Bluetooth connection object of the service object.
244 *
245 * The caller gets a new reference to the connection object which must be
246 * released with bt_conn_unref() once done using the object.
247 *
248 * @param[in] has Pointer to the Hearing Access Service object.
249 * @param[out] conn Connection object.
250 *
251 * @return 0 in case of success or negative value in case of error.
252 */
253 int bt_has_client_conn_get(const struct bt_has *has, struct bt_conn **conn);
254
255 /**
256 * @brief Read Preset Records.
257 *
258 * Client method to read up to @p max_count presets starting from given @p index.
259 * The preset records are returned in the @ref bt_has_client_cb.preset_read_rsp callback
260 * (called once for each preset).
261 *
262 * @param has Pointer to the Hearing Access Service object.
263 * @param index The index to start with.
264 * @param max_count Maximum number of presets to read.
265 *
266 * @return 0 in case of success or negative value in case of error.
267 */
268 int bt_has_client_presets_read(struct bt_has *has, uint8_t index, uint8_t max_count);
269
270 /**
271 * @brief Set Active Preset.
272 *
273 * Client procedure to set preset identified by @p index as active.
274 * The status is returned in the @ref bt_has_client_cb.preset_switch callback.
275 *
276 * @param has Pointer to the Hearing Access Service object.
277 * @param index Preset index to activate.
278 * @param sync Request active preset synchronization in set.
279 *
280 * @return 0 in case of success or negative value in case of error.
281 */
282 int bt_has_client_preset_set(struct bt_has *has, uint8_t index, bool sync);
283
284 /**
285 * @brief Activate Next Preset.
286 *
287 * Client procedure to set next available preset as active.
288 * The status is returned in the @ref bt_has_client_cb.preset_switch callback.
289 *
290 * @param has Pointer to the Hearing Access Service object.
291 * @param sync Request active preset synchronization in set.
292 *
293 * @return 0 in case of success or negative value in case of error.
294 */
295 int bt_has_client_preset_next(struct bt_has *has, bool sync);
296
297 /**
298 * @brief Activate Previous Preset.
299 *
300 * Client procedure to set previous available preset as active.
301 * The status is returned in the @ref bt_has_client_cb.preset_switch callback.
302 *
303 * @param has Pointer to the Hearing Access Service object.
304 * @param sync Request active preset synchronization in set.
305 *
306 * @return 0 in case of success or negative value in case of error.
307 */
308 int bt_has_client_preset_prev(struct bt_has *has, bool sync);
309
310 /** @brief Preset operations structure. */
311 struct bt_has_preset_ops {
312 /**
313 * @brief Preset select callback.
314 *
315 * This callback is called when the client requests to select preset identified by
316 * @p index.
317 *
318 * @param index Preset index requested to activate.
319 * @param sync Whether the server must relay this change to the other member of the
320 * Binaural Hearing Aid Set.
321 *
322 * @return 0 in case of success or negative value in case of error.
323 * @return -EBUSY if operation cannot be performed at the time.
324 * @return -EINPROGRESS in case where user has to confirm once the requested preset
325 * becomes active by calling @ref bt_has_preset_active_set.
326 */
327 int (*select)(uint8_t index, bool sync);
328
329 /**
330 * @brief Preset name changed callback
331 *
332 * This callback is called when the name of the preset identified by @p index has changed.
333 *
334 * @param index Preset index that name has been changed.
335 * @param name Preset current name.
336 */
337 void (*name_changed)(uint8_t index, const char *name);
338 };
339
340 /** @brief Register structure for preset. */
341 struct bt_has_preset_register_param {
342 /**
343 * @brief Preset index.
344 *
345 * Unique preset identifier. The value shall be other than @ref BT_HAS_PRESET_INDEX_NONE.
346 */
347 uint8_t index;
348
349 /**
350 * @brief Preset properties.
351 *
352 * Bitfield of preset properties.
353 */
354 enum bt_has_properties properties;
355
356 /**
357 * @brief Preset name.
358 *
359 * Preset name that further can be changed by either server or client if
360 * @kconfig{CONFIG_BT_HAS_PRESET_NAME_DYNAMIC} configuration option has been enabled.
361 * It's length shall be greater than @ref BT_HAS_PRESET_NAME_MIN. If the length exceeds
362 * @ref BT_HAS_PRESET_NAME_MAX, the name will be truncated.
363 */
364 const char *name;
365
366 /** Preset operations structure. */
367 const struct bt_has_preset_ops *ops;
368 };
369
370 /**
371 * @brief Register the Hearing Access Service instance.
372 *
373 * @param features Hearing Access Service register parameters.
374 *
375 * @return 0 if success, errno on failure.
376 */
377 int bt_has_register(const struct bt_has_features_param *features);
378
379 /**
380 * @brief Register preset.
381 *
382 * Register preset. The preset will be a added to the list of exposed preset records.
383 * This symbol is linkable if @kconfig{CONFIG_BT_HAS_PRESET_COUNT} is non-zero.
384 *
385 * @param param Preset registration parameter.
386 *
387 * @return 0 if success, errno on failure.
388 */
389 int bt_has_preset_register(const struct bt_has_preset_register_param *param);
390
391 /**
392 * @brief Unregister Preset.
393 *
394 * Unregister preset. The preset will be removed from the list of preset records.
395 *
396 * @param index The index of preset that's being requested to unregister.
397 *
398 * @return 0 if success, errno on failure.
399 */
400 int bt_has_preset_unregister(uint8_t index);
401
402 /**
403 * @brief Set the preset as available.
404 *
405 * Set the @ref BT_HAS_PROP_AVAILABLE property bit. This will notify preset availability
406 * to peer devices. Only available preset can be selected as active preset.
407 *
408 * @param index The index of preset that's became available.
409 *
410 * @return 0 in case of success or negative value in case of error.
411 */
412 int bt_has_preset_available(uint8_t index);
413
414 /**
415 * @brief Set the preset as unavailable.
416 *
417 * Clear the @ref BT_HAS_PROP_AVAILABLE property bit. This will notify preset availability
418 * to peer devices. Unavailable preset cannot be selected as active preset.
419 *
420 * @param index The index of preset that's became unavailable.
421 *
422 * @return 0 in case of success or negative value in case of error.
423 */
424 int bt_has_preset_unavailable(uint8_t index);
425
426 /** Enum for return values for @ref bt_has_preset_func_t functions */
427 enum {
428 /** Stop iterating */
429 BT_HAS_PRESET_ITER_STOP = 0,
430 /** Continue iterating */
431 BT_HAS_PRESET_ITER_CONTINUE,
432 };
433
434 /**
435 * @typedef bt_has_preset_func_t
436 * @brief Preset iterator callback.
437 *
438 * @param index The index of preset found.
439 * @param properties Preset properties.
440 * @param name Preset name.
441 * @param user_data Data given.
442 *
443 * @return BT_HAS_PRESET_ITER_CONTINUE if should continue to the next preset.
444 * @return BT_HAS_PRESET_ITER_STOP to stop.
445 */
446 typedef uint8_t (*bt_has_preset_func_t)(uint8_t index, enum bt_has_properties properties,
447 const char *name, void *user_data);
448
449 /**
450 * @brief Preset iterator.
451 *
452 * Iterate presets. Optionally, match non-zero index if given.
453 *
454 * @param index Preset index, passing @ref BT_HAS_PRESET_INDEX_NONE skips index matching.
455 * @param func Callback function.
456 * @param user_data Data to pass to the callback.
457 */
458 void bt_has_preset_foreach(uint8_t index, bt_has_preset_func_t func, void *user_data);
459
460 /**
461 * @brief Set active preset.
462 *
463 * Function used to set the preset identified by the @p index as the active preset.
464 * The preset index will be notified to peer devices.
465 *
466 * @param index Preset index.
467 *
468 * @return 0 in case of success or negative value in case of error.
469 */
470 int bt_has_preset_active_set(uint8_t index);
471
472 /**
473 * @brief Get active preset.
474 *
475 * Function used to get the currently active preset index.
476 *
477 * @return Active preset index.
478 */
479 uint8_t bt_has_preset_active_get(void);
480
481 /**
482 * @brief Clear out active preset.
483 *
484 * Used by server to deactivate currently active preset.
485 *
486 * @return 0 in case of success or negative value in case of error.
487 */
bt_has_preset_active_clear(void)488 static inline int bt_has_preset_active_clear(void)
489 {
490 return bt_has_preset_active_set(BT_HAS_PRESET_INDEX_NONE);
491 }
492
493 /**
494 * @brief Change the Preset Name.
495 *
496 * Change the name of the preset identified by @p index.
497 *
498 * @param index The index of the preset to change the name of.
499 * @param name Name to write.
500 *
501 * @return 0 in case of success or negative value in case of error.
502 */
503 int bt_has_preset_name_change(uint8_t index, const char *name);
504
505 /**
506 * @brief Change the Hearing Aid Features.
507 *
508 * Change the hearing aid features.
509 *
510 * @param features The features to be set.
511 *
512 * @return 0 in case of success or negative value in case of error.
513 */
514 int bt_has_features_set(const struct bt_has_features_param *features);
515
516 #ifdef __cplusplus
517 }
518 #endif
519
520 /**
521 * @}
522 */
523
524 #endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_HAS_H_ */
525