1 /*
2  * Copyright (c) 2021-2025 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/bluetooth/gap.h>
8 #include <zephyr/types.h>
9 #include <stddef.h>
10 #include <errno.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/sys/printk.h>
13 
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/hci.h>
16 #include <zephyr/bluetooth/conn.h>
17 #include <zephyr/bluetooth/uuid.h>
18 #include <zephyr/bluetooth/gatt.h>
19 #include <zephyr/bluetooth/hci_types.h>
20 #include <zephyr/bluetooth/iso.h>
21 #include <zephyr/settings/settings.h>
22 #include <zephyr/sys/byteorder.h>
23 
24 static void start_scan(void);
25 
26 static struct bt_conn *default_conn;
27 static struct k_work_delayable iso_send_work;
28 static struct bt_iso_chan iso_chan;
29 static uint16_t seq_num;
30 static uint16_t latency_ms = 10U; /* 10ms */
31 static uint32_t interval_us = 10U * USEC_PER_MSEC; /* 10 ms */
32 NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
33 			  CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
34 
35 /**
36  * @brief Send ISO data on timeout
37  *
38  * This will send an increasing amount of ISO data, starting from 1 octet.
39  *
40  * First iteration : 0x00
41  * Second iteration: 0x00 0x01
42  * Third iteration : 0x00 0x01 0x02
43  *
44  * And so on, until it wraps around the configured ISO TX MTU (CONFIG_BT_ISO_TX_MTU)
45  *
46  * @param work Pointer to the work structure
47  */
iso_timer_timeout(struct k_work * work)48 static void iso_timer_timeout(struct k_work *work)
49 {
50 	int ret;
51 	static uint8_t buf_data[CONFIG_BT_ISO_TX_MTU];
52 	static bool data_initialized;
53 	struct net_buf *buf;
54 	static size_t len_to_send = 1;
55 
56 	if (!data_initialized) {
57 		for (int i = 0; i < ARRAY_SIZE(buf_data); i++) {
58 			buf_data[i] = (uint8_t)i;
59 		}
60 
61 		data_initialized = true;
62 	}
63 
64 	buf = net_buf_alloc(&tx_pool, K_NO_WAIT);
65 	if (buf != NULL) {
66 		net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
67 
68 		net_buf_add_mem(buf, buf_data, len_to_send);
69 
70 		ret = bt_iso_chan_send(&iso_chan, buf, seq_num);
71 
72 		if (ret < 0) {
73 			printk("Failed to send ISO data (%d)\n", ret);
74 			net_buf_unref(buf);
75 		}
76 
77 		len_to_send++;
78 		if (len_to_send > ARRAY_SIZE(buf_data)) {
79 			len_to_send = 1;
80 		}
81 	} else {
82 		printk("Failed to allocate buffer, retrying in next interval (%u us)\n",
83 		       interval_us);
84 	}
85 
86 	/* Sequence number shall be incremented for each SDU interval */
87 	seq_num++;
88 
89 	k_work_schedule(&iso_send_work, K_USEC(interval_us));
90 }
91 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)92 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
93 			 struct net_buf_simple *ad)
94 {
95 	const struct bt_le_conn_param *conn_param =
96 		BT_LE_CONN_PARAM(BT_GAP_MS_TO_CONN_INTERVAL(60), BT_GAP_MS_TO_CONN_INTERVAL(60), 0,
97 				 BT_GAP_MS_TO_CONN_TIMEOUT(4000));
98 	char addr_str[BT_ADDR_LE_STR_LEN];
99 	int err;
100 
101 	if (default_conn) {
102 		/* Already connected */
103 		return;
104 	}
105 
106 	/* We're only interested in connectable events */
107 	if (type != BT_GAP_ADV_TYPE_ADV_IND && type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
108 		return;
109 	}
110 
111 	bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
112 	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
113 
114 	/* connect only to devices in close proximity */
115 	if (rssi < -50) {
116 		return;
117 	}
118 
119 	if (bt_le_scan_stop()) {
120 		return;
121 	}
122 
123 	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, conn_param, &default_conn);
124 	if (err) {
125 		printk("Create conn to %s failed (%u)\n", addr_str, err);
126 		start_scan();
127 	}
128 }
129 
start_scan(void)130 static void start_scan(void)
131 {
132 	int err;
133 
134 	/* This demo doesn't require active scan */
135 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
136 	if (err) {
137 		printk("Scanning failed to start (err %d)\n", err);
138 		return;
139 	}
140 
141 	printk("Scanning successfully started\n");
142 }
143 
iso_connected(struct bt_iso_chan * chan)144 static void iso_connected(struct bt_iso_chan *chan)
145 {
146 	const struct bt_iso_chan_path hci_path = {
147 		.pid = BT_ISO_DATA_PATH_HCI,
148 		.format = BT_HCI_CODING_FORMAT_TRANSPARENT,
149 	};
150 	int err;
151 
152 	printk("ISO Channel %p connected\n", chan);
153 
154 	seq_num = 0U;
155 
156 	err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path);
157 	if (err != 0) {
158 		printk("Failed to setup ISO TX data path: %d\n", err);
159 	} else {
160 		/* Start send timer */
161 		k_work_schedule(&iso_send_work, K_NO_WAIT);
162 	}
163 }
164 
iso_disconnected(struct bt_iso_chan * chan,uint8_t reason)165 static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
166 {
167 	int err;
168 
169 	printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason);
170 	k_work_cancel_delayable(&iso_send_work);
171 
172 	err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR);
173 	if (err != 0) {
174 		printk("Failed to setup ISO TX data path: %d\n", err);
175 	}
176 }
177 
178 static struct bt_iso_chan_ops iso_ops = {
179 	.connected	= iso_connected,
180 	.disconnected	= iso_disconnected,
181 };
182 
183 static struct bt_iso_chan_io_qos iso_tx = {
184 	.sdu = CONFIG_BT_ISO_TX_MTU,
185 	.phy = BT_GAP_LE_PHY_2M,
186 	.rtn = 1,
187 };
188 
189 static struct bt_iso_chan_qos iso_qos = {
190 	.tx = &iso_tx,
191 	.rx = NULL,
192 };
193 
connected(struct bt_conn * conn,uint8_t err)194 static void connected(struct bt_conn *conn, uint8_t err)
195 {
196 	char addr[BT_ADDR_LE_STR_LEN];
197 	int iso_err;
198 	struct bt_iso_connect_param connect_param;
199 
200 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
201 
202 	if (err) {
203 		printk("Failed to connect to %s %u %s\n", addr, err, bt_hci_err_to_str(err));
204 
205 		bt_conn_unref(default_conn);
206 		default_conn = NULL;
207 
208 		start_scan();
209 		return;
210 	}
211 
212 	if (conn != default_conn) {
213 		return;
214 	}
215 
216 	printk("Connected: %s\n", addr);
217 
218 	connect_param.acl = conn;
219 	connect_param.iso_chan = &iso_chan;
220 
221 	iso_err = bt_iso_chan_connect(&connect_param, 1);
222 
223 	if (iso_err) {
224 		printk("Failed to connect iso (%d)\n", iso_err);
225 		return;
226 	}
227 }
228 
disconnected(struct bt_conn * conn,uint8_t reason)229 static void disconnected(struct bt_conn *conn, uint8_t reason)
230 {
231 	char addr[BT_ADDR_LE_STR_LEN];
232 
233 	if (conn != default_conn) {
234 		return;
235 	}
236 
237 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
238 
239 	printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
240 
241 	bt_conn_unref(default_conn);
242 	default_conn = NULL;
243 
244 	start_scan();
245 }
246 
247 BT_CONN_CB_DEFINE(conn_callbacks) = {
248 	.connected = connected,
249 	.disconnected = disconnected,
250 };
251 
main(void)252 int main(void)
253 {
254 	int err;
255 	struct bt_iso_chan *channels[1];
256 	struct bt_iso_cig_param param;
257 	struct bt_iso_cig *cig;
258 
259 	err = bt_enable(NULL);
260 	if (err) {
261 		printk("Bluetooth init failed (err %d)\n", err);
262 		return 0;
263 	}
264 
265 	if (IS_ENABLED(CONFIG_SETTINGS)) {
266 		settings_load();
267 	}
268 
269 
270 	printk("Bluetooth initialized\n");
271 
272 	iso_chan.ops = &iso_ops;
273 	iso_chan.qos = &iso_qos;
274 #if defined(CONFIG_BT_SMP)
275 	iso_chan.required_sec_level = BT_SECURITY_L2,
276 #endif /* CONFIG_BT_SMP */
277 
278 	channels[0] = &iso_chan;
279 	param.cis_channels = channels;
280 	param.num_cis = ARRAY_SIZE(channels);
281 	param.sca = BT_GAP_SCA_UNKNOWN;
282 	param.packing = 0;
283 	param.framing = 0;
284 	param.c_to_p_latency = latency_ms; /* ms */
285 	param.p_to_c_latency = latency_ms; /* ms */
286 	param.c_to_p_interval = interval_us; /* us */
287 	param.p_to_c_interval = interval_us; /* us */
288 
289 	err = bt_iso_cig_create(&param, &cig);
290 
291 	if (err != 0) {
292 		printk("Failed to create CIG (%d)\n", err);
293 		return 0;
294 	}
295 
296 	start_scan();
297 
298 	k_work_init_delayable(&iso_send_work, iso_timer_timeout);
299 	return 0;
300 }
301