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