1 /*
2 * Copyright (c) 2022 Codecoup
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stddef.h>
7 #include <stdint.h>
8
9 #include <zephyr/bluetooth/bluetooth.h>
10 #include <zephyr/bluetooth/byteorder.h>
11 #include <zephyr/bluetooth/conn.h>
12 #include <zephyr/bluetooth/audio/audio.h>
13 #include <zephyr/bluetooth/audio/bap.h>
14 #include <zephyr/bluetooth/audio/pacs.h>
15 #include <zephyr/bluetooth/audio/csip.h>
16 #include <zephyr/bluetooth/gap.h>
17 #include <zephyr/bluetooth/services/ias.h>
18 #include <zephyr/bluetooth/uuid.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/sys/__assert.h>
21 #include <zephyr/sys/byteorder.h>
22 #include <zephyr/sys/printk.h>
23 #include <zephyr/sys/util.h>
24 #include <zephyr/sys/util_macro.h>
25
26 #include "hap_ha.h"
27
28 #define MANDATORY_SINK_CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \
29 BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \
30 BT_AUDIO_CONTEXT_TYPE_MEDIA | \
31 BT_AUDIO_CONTEXT_TYPE_LIVE)
32
33 #define AVAILABLE_SINK_CONTEXT MANDATORY_SINK_CONTEXT
34 #define AVAILABLE_SOURCE_CONTEXT MANDATORY_SINK_CONTEXT
35
36 static uint8_t unicast_server_addata[] = {
37 BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL), /* ASCS UUID */
38 BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED, /* Target Announcement */
39 BT_BYTES_LIST_LE16(AVAILABLE_SINK_CONTEXT),
40 BT_BYTES_LIST_LE16(AVAILABLE_SOURCE_CONTEXT),
41 0x00, /* Metadata length */
42 };
43
44 static uint8_t csis_rsi_addata[BT_CSIP_RSI_SIZE];
45
46 /* TODO: Expand with BAP data */
47 static const struct bt_data ad[] = {
48 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
49 BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL)),
50 #if defined(CONFIG_BT_CSIP_SET_MEMBER)
51 BT_DATA(BT_DATA_CSIS_RSI, csis_rsi_addata, ARRAY_SIZE(csis_rsi_addata)),
52 #endif /* CONFIG_BT_CSIP_SET_MEMBER */
53 BT_DATA(BT_DATA_SVC_DATA16, unicast_server_addata, ARRAY_SIZE(unicast_server_addata)),
54 BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
55 };
56
57 static struct k_work_delayable adv_work;
58 static struct bt_le_ext_adv *ext_adv;
59
disconnected(struct bt_conn * conn,uint8_t reason)60 static void disconnected(struct bt_conn *conn, uint8_t reason)
61 {
62 /* Restart advertising after disconnection */
63 k_work_schedule(&adv_work, K_SECONDS(1));
64 }
65
66 BT_CONN_CB_DEFINE(conn_callbacks) = {
67 .disconnected = disconnected,
68 };
69
70 #if defined(CONFIG_BT_PRIVACY) && defined(CONFIG_BT_CSIP_SET_MEMBER)
adv_rpa_expired_cb(struct bt_le_ext_adv * adv)71 static bool adv_rpa_expired_cb(struct bt_le_ext_adv *adv)
72 {
73 char rsi_str[13];
74 int err;
75
76 err = csip_generate_rsi(csis_rsi_addata);
77 if (err != 0) {
78 printk("Failed to generate RSI (err %d)\n", err);
79 return false;
80 }
81
82 snprintk(rsi_str, ARRAY_SIZE(rsi_str), "%02x%02x%02x%02x%02x%02x",
83 csis_rsi_addata[0], csis_rsi_addata[1], csis_rsi_addata[2],
84 csis_rsi_addata[3], csis_rsi_addata[4], csis_rsi_addata[5]);
85
86 printk("PRSI: 0x%s\n", rsi_str);
87
88 err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
89 if (err) {
90 printk("Failed to set advertising data (err %d)\n", err);
91 return false;
92 }
93
94 return true;
95 }
96 #endif /* CONFIG_BT_PRIVACY && CONFIG_BT_CSIP_SET_MEMBER */
97
98 static const struct bt_le_ext_adv_cb adv_cb = {
99 #if defined(CONFIG_BT_PRIVACY) && defined(CONFIG_BT_CSIP_SET_MEMBER)
100 .rpa_expired = adv_rpa_expired_cb,
101 #endif /* CONFIG_BT_PRIVACY && CONFIG_BT_CSIP_SET_MEMBER */
102 };
103
adv_work_handler(struct k_work * work)104 static void adv_work_handler(struct k_work *work)
105 {
106 int err;
107
108 if (ext_adv == NULL) {
109 /* Create a connectable advertising set */
110 err = bt_le_ext_adv_create(BT_BAP_ADV_PARAM_CONN_QUICK, &adv_cb, &ext_adv);
111 if (err) {
112 printk("Failed to create advertising set (err %d)\n", err);
113 }
114
115 err = bt_le_ext_adv_set_data(ext_adv, ad, ARRAY_SIZE(ad), NULL, 0);
116 if (err) {
117 printk("Failed to set advertising data (err %d)\n", err);
118 }
119
120 __ASSERT_NO_MSG(err == 0);
121 }
122
123 err = bt_le_ext_adv_start(ext_adv, BT_LE_EXT_ADV_START_DEFAULT);
124 if (err) {
125 printk("Failed to start advertising set (err %d)\n", err);
126 } else {
127 printk("Advertising successfully started\n");
128 }
129 }
130
131 #if defined(CONFIG_BT_IAS)
alert_stop(void)132 static void alert_stop(void)
133 {
134 printk("Alert stopped\n");
135 }
136
alert_start(void)137 static void alert_start(void)
138 {
139 printk("Mild alert started\n");
140 }
141
alert_high_start(void)142 static void alert_high_start(void)
143 {
144 printk("High alert started\n");
145 }
146
147 BT_IAS_CB_DEFINE(ias_callbacks) = {
148 .no_alert = alert_stop,
149 .mild_alert = alert_start,
150 .high_alert = alert_high_start,
151 };
152 #endif /* CONFIG_BT_IAS */
153
main(void)154 int main(void)
155 {
156 int err;
157
158 err = bt_enable(NULL);
159 if (err != 0) {
160 printk("Bluetooth init failed (err %d)\n", err);
161 return 0;
162 }
163
164 printk("Bluetooth initialized\n");
165
166 err = has_server_init();
167 if (err != 0) {
168 printk("HAS Server init failed (err %d)\n", err);
169 return 0;
170 }
171
172 err = bap_unicast_sr_init();
173 if (err != 0) {
174 printk("BAP Unicast Server init failed (err %d)\n", err);
175 return 0;
176 }
177
178 if (IS_ENABLED(CONFIG_HAP_HA_HEARING_AID_BINAURAL)) {
179 err = csip_set_member_init();
180 if (err != 0) {
181 printk("CSIP Set Member init failed (err %d)\n", err);
182 return 0;
183 }
184
185 err = csip_generate_rsi(csis_rsi_addata);
186 if (err != 0) {
187 printk("Failed to generate RSI (err %d)\n", err);
188 return 0;
189 }
190 }
191
192 err = vcp_vol_renderer_init();
193 if (err != 0) {
194 printk("VCP Volume Renderer init failed (err %d)\n", err);
195 return 0;
196 }
197
198 if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SRC)) {
199 err = micp_mic_dev_init();
200 if (err != 0) {
201 printk("MICP Microphone Device init failed (err %d)\n", err);
202 return 0;
203 }
204 }
205
206 if (IS_ENABLED(CONFIG_BT_TBS_CLIENT)) {
207 err = ccp_call_ctrl_init();
208 if (err != 0) {
209 printk("MICP Microphone Device init failed (err %d)\n", err);
210 return 0;
211 }
212 }
213
214 if (IS_ENABLED(CONFIG_HAP_HA_HEARING_AID_BANDED)) {
215 /* HAP_d1.0r00; 3.7 BAP Unicast Server role requirements
216 * A Banded Hearing Aid in the HA role shall set the
217 * Front Left and the Front Right bits to a value of 0b1
218 * in the Sink Audio Locations characteristic value.
219 */
220 bt_pacs_set_location(BT_AUDIO_DIR_SINK,
221 (BT_AUDIO_LOCATION_FRONT_LEFT |
222 BT_AUDIO_LOCATION_FRONT_RIGHT));
223 } else {
224 bt_pacs_set_location(BT_AUDIO_DIR_SINK,
225 BT_AUDIO_LOCATION_FRONT_LEFT);
226 }
227
228 bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK,
229 AVAILABLE_SINK_CONTEXT);
230
231 if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SRC)) {
232 bt_pacs_set_location(BT_AUDIO_DIR_SOURCE,
233 BT_AUDIO_LOCATION_FRONT_LEFT);
234 bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE,
235 AVAILABLE_SOURCE_CONTEXT);
236 }
237
238 k_work_init_delayable(&adv_work, adv_work_handler);
239 k_work_schedule(&adv_work, K_NO_WAIT);
240 return 0;
241 }
242