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