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