1 /** @file
2  *  @brief Internal APIs for Bluetooth Hearing Access Profile.
3  */
4 
5 /*
6  * Copyright (c) 2022 Codecoup
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 #include <stdbool.h>
12 #include <stdint.h>
13 
14 #include <zephyr/bluetooth/conn.h>
15 #include <zephyr/bluetooth/gatt.h>
16 #include <zephyr/bluetooth/uuid.h>
17 #include <zephyr/sys/atomic.h>
18 #include <zephyr/sys/util_macro.h>
19 
20 /* Control Point opcodes */
21 #define BT_HAS_OP_READ_PRESET_REQ        0x01
22 #define BT_HAS_OP_READ_PRESET_RSP        0x02
23 #define BT_HAS_OP_PRESET_CHANGED         0x03
24 #define BT_HAS_OP_WRITE_PRESET_NAME      0x04
25 #define BT_HAS_OP_SET_ACTIVE_PRESET      0x05
26 #define BT_HAS_OP_SET_NEXT_PRESET        0x06
27 #define BT_HAS_OP_SET_PREV_PRESET        0x07
28 #define BT_HAS_OP_SET_ACTIVE_PRESET_SYNC 0x08
29 #define BT_HAS_OP_SET_NEXT_PRESET_SYNC   0x09
30 #define BT_HAS_OP_SET_PREV_PRESET_SYNC   0x0a
31 
32 /* Application error codes */
33 #define BT_HAS_ERR_INVALID_OPCODE         0x80
34 #define BT_HAS_ERR_WRITE_NAME_NOT_ALLOWED 0x81
35 #define BT_HAS_ERR_PRESET_SYNC_NOT_SUPP   0x82
36 #define BT_HAS_ERR_OPERATION_NOT_POSSIBLE 0x83
37 #define BT_HAS_ERR_INVALID_PARAM_LEN      0x84
38 
39 /* Hearing Aid Feature bits */
40 #define BT_HAS_FEAT_HEARING_AID_TYPE_LSB  BIT(0)
41 #define BT_HAS_FEAT_HEARING_AID_TYPE_MSB  BIT(1)
42 #define BT_HAS_FEAT_PRESET_SYNC_SUPP      BIT(2)
43 #define BT_HAS_FEAT_INDEPENDENT_PRESETS   BIT(3)
44 #define BT_HAS_FEAT_DYNAMIC_PRESETS       BIT(4)
45 #define BT_HAS_FEAT_WRITABLE_PRESETS_SUPP BIT(5)
46 
47 #define BT_HAS_FEAT_HEARING_AID_TYPE_MASK (BT_HAS_FEAT_HEARING_AID_TYPE_LSB | \
48 					   BT_HAS_FEAT_HEARING_AID_TYPE_MSB)
49 
50 /* Preset Changed Change ID values */
51 #define BT_HAS_CHANGE_ID_GENERIC_UPDATE     0x00
52 #define BT_HAS_CHANGE_ID_PRESET_DELETED     0x01
53 #define BT_HAS_CHANGE_ID_PRESET_AVAILABLE   0x02
54 #define BT_HAS_CHANGE_ID_PRESET_UNAVAILABLE 0x03
55 
56 #define BT_HAS_IS_LAST 0x01
57 
58 struct bt_has {
59 	/** Hearing Aid Features value */
60 	uint8_t features;
61 
62 	/** Active preset index value */
63 	uint8_t active_index;
64 
65 	/* Whether the service has been registered or not */
66 	bool registered;
67 };
68 
69 struct bt_has_cp_hdr {
70 	uint8_t opcode;
71 	uint8_t data[0];
72 } __packed;
73 
74 struct bt_has_cp_read_presets_req {
75 	uint8_t start_index;
76 	uint8_t num_presets;
77 } __packed;
78 
79 struct bt_has_cp_read_preset_rsp {
80 	uint8_t is_last;
81 	uint8_t index;
82 	uint8_t properties;
83 	uint8_t name[0];
84 } __packed;
85 
86 struct bt_has_cp_preset_changed {
87 	uint8_t change_id;
88 	uint8_t is_last;
89 	uint8_t additional_params[0];
90 } __packed;
91 
92 struct bt_has_cp_generic_update {
93 	uint8_t prev_index;
94 	uint8_t index;
95 	uint8_t properties;
96 	uint8_t name[0];
97 } __packed;
98 
99 struct bt_has_cp_write_preset_name {
100 	uint8_t index;
101 	uint8_t name[0];
102 } __packed;
103 
104 struct bt_has_cp_set_active_preset {
105 	uint8_t index;
106 } __packed;
107 
bt_has_op_str(uint8_t op)108 static inline const char *bt_has_op_str(uint8_t op)
109 {
110 	switch (op) {
111 	case BT_HAS_OP_READ_PRESET_REQ:
112 		return "Read preset request";
113 	case BT_HAS_OP_READ_PRESET_RSP:
114 		return "Read preset response";
115 	case BT_HAS_OP_PRESET_CHANGED:
116 		return "Preset changed";
117 	case BT_HAS_OP_WRITE_PRESET_NAME:
118 		return "Write preset name";
119 	case BT_HAS_OP_SET_ACTIVE_PRESET:
120 		return "Set active preset";
121 	case BT_HAS_OP_SET_NEXT_PRESET:
122 		return "Set next preset";
123 	case BT_HAS_OP_SET_PREV_PRESET:
124 		return "Set previous preset";
125 	case BT_HAS_OP_SET_ACTIVE_PRESET_SYNC:
126 		return "Set active preset (sync)";
127 	case BT_HAS_OP_SET_NEXT_PRESET_SYNC:
128 		return "Set next preset (sync)";
129 	case BT_HAS_OP_SET_PREV_PRESET_SYNC:
130 		return "Set previous preset (sync)";
131 	default:
132 		return "Unknown";
133 	}
134 }
135 
bt_has_change_id_str(uint8_t change_id)136 static inline const char *bt_has_change_id_str(uint8_t change_id)
137 {
138 	switch (change_id) {
139 	case BT_HAS_CHANGE_ID_GENERIC_UPDATE:
140 		return "Generic update";
141 	case BT_HAS_CHANGE_ID_PRESET_DELETED:
142 		return "Preset deleted";
143 	case BT_HAS_CHANGE_ID_PRESET_AVAILABLE:
144 		return "Preset available";
145 	case BT_HAS_CHANGE_ID_PRESET_UNAVAILABLE:
146 		return "Preset unavailable";
147 	default:
148 		return "Unknown changeId";
149 	}
150 }
151 
152 enum has_client_flags {
153 	HAS_CLIENT_DISCOVER_IN_PROGRESS,
154 	HAS_CLIENT_CP_OPERATION_IN_PROGRESS,
155 
156 	HAS_CLIENT_NUM_FLAGS, /* keep as last */
157 };
158 
159 struct bt_has_client {
160 	/** Common profile reference object */
161 	struct bt_has has;
162 
163 	/** Profile connection reference */
164 	struct bt_conn *conn;
165 
166 	/** Internal flags */
167 	ATOMIC_DEFINE(flags, HAS_CLIENT_NUM_FLAGS);
168 
169 	/* GATT procedure parameters */
170 	union {
171 		struct {
172 			struct bt_uuid_16 uuid;
173 			union {
174 				struct bt_gatt_read_params read;
175 				struct bt_gatt_discover_params discover;
176 			};
177 		};
178 		struct bt_gatt_write_params write;
179 	} params;
180 
181 	struct bt_gatt_subscribe_params features_subscription;
182 	struct bt_gatt_subscribe_params control_point_subscription;
183 	struct bt_gatt_subscribe_params active_index_subscription;
184 };
185