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