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