1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/types.h>
8 #include <stddef.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <zephyr/sys/printk.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/kernel.h>
14 
15 #include <zephyr/bluetooth/bluetooth.h>
16 #include <zephyr/bluetooth/hci.h>
17 #include <zephyr/bluetooth/conn.h>
18 #include <zephyr/bluetooth/iso.h>
19 #include <zephyr/settings/settings.h>
20 
21 static const struct bt_data ad[] = {
22 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
23 };
24 
25 static const struct bt_data sd[] = {
26 	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
27 };
28 
connected(struct bt_conn * conn,uint8_t err)29 static void connected(struct bt_conn *conn, uint8_t err)
30 {
31 	char addr[BT_ADDR_LE_STR_LEN];
32 
33 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
34 
35 	if (err) {
36 		printk("Failed to connect to %s %u %s\n", addr, err, bt_hci_err_to_str(err));
37 		return;
38 	}
39 
40 	printk("Connected %s\n", addr);
41 }
42 
disconnected(struct bt_conn * conn,uint8_t reason)43 static void disconnected(struct bt_conn *conn, uint8_t reason)
44 {
45 	char addr[BT_ADDR_LE_STR_LEN];
46 
47 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
48 
49 	printk("Disconnected from %s, reason 0x%02x %s\n", addr,
50 	       reason, bt_hci_err_to_str(reason));
51 }
52 
53 BT_CONN_CB_DEFINE(conn_callbacks) = {
54 	.connected = connected,
55 	.disconnected = disconnected,
56 };
57 
58 /** Print data as d_0 d_1 d_2 ... d_(n-2) d_(n-1) d_(n) to show the 3 first and 3 last octets
59  *
60  * Examples:
61  * 01
62  * 0102
63  * 010203
64  * 01020304
65  * 0102030405
66  * 010203040506
67  * 010203...050607
68  * 010203...060708
69  * etc.
70  */
iso_print_data(uint8_t * data,size_t data_len)71 static void iso_print_data(uint8_t *data, size_t data_len)
72 {
73 	/* Maximum number of octets from each end of the data */
74 	const uint8_t max_octets = 3;
75 	char data_str[35];
76 	size_t str_len;
77 
78 	str_len = bin2hex(data, MIN(max_octets, data_len), data_str, sizeof(data_str));
79 	if (data_len > max_octets) {
80 		if (data_len > (max_octets * 2)) {
81 			static const char dots[] = "...";
82 
83 			strcat(&data_str[str_len], dots);
84 			str_len += strlen(dots);
85 		}
86 
87 		str_len += bin2hex(data + (data_len - MIN(max_octets, data_len - max_octets)),
88 				   MIN(max_octets, data_len - max_octets),
89 				   data_str + str_len,
90 				   sizeof(data_str) - str_len);
91 	}
92 
93 	printk("\t %s\n", data_str);
94 }
95 
iso_recv(struct bt_iso_chan * chan,const struct bt_iso_recv_info * info,struct net_buf * buf)96 static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *info,
97 		struct net_buf *buf)
98 {
99 	if (info->flags & BT_ISO_FLAGS_VALID) {
100 		printk("Incoming data channel %p len %u\n", chan, buf->len);
101 		iso_print_data(buf->data, buf->len);
102 	}
103 }
104 
iso_connected(struct bt_iso_chan * chan)105 static void iso_connected(struct bt_iso_chan *chan)
106 {
107 	printk("ISO Channel %p connected\n", chan);
108 }
109 
iso_disconnected(struct bt_iso_chan * chan,uint8_t reason)110 static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
111 {
112 	printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason);
113 }
114 
115 static struct bt_iso_chan_ops iso_ops = {
116 	.recv		= iso_recv,
117 	.connected	= iso_connected,
118 	.disconnected	= iso_disconnected,
119 };
120 
121 static struct bt_iso_chan_io_qos iso_rx = {
122 	.sdu = CONFIG_BT_ISO_TX_MTU,
123 	.path = NULL,
124 };
125 
126 static struct bt_iso_chan_qos iso_qos = {
127 	.rx = &iso_rx,
128 	.tx = NULL,
129 };
130 
131 static struct bt_iso_chan iso_chan = {
132 	.ops = &iso_ops,
133 	.qos = &iso_qos,
134 };
135 
iso_accept(const struct bt_iso_accept_info * info,struct bt_iso_chan ** chan)136 static int iso_accept(const struct bt_iso_accept_info *info,
137 		      struct bt_iso_chan **chan)
138 {
139 	printk("Incoming request from %p\n", (void *)info->acl);
140 
141 	if (iso_chan.iso) {
142 		printk("No channels available\n");
143 		return -ENOMEM;
144 	}
145 
146 	*chan = &iso_chan;
147 
148 	return 0;
149 }
150 
151 static struct bt_iso_server iso_server = {
152 #if defined(CONFIG_BT_SMP)
153 	.sec_level = BT_SECURITY_L1,
154 #endif /* CONFIG_BT_SMP */
155 	.accept = iso_accept,
156 };
157 
main(void)158 int main(void)
159 {
160 	int err;
161 
162 	err = bt_enable(NULL);
163 	if (err) {
164 		printk("Bluetooth init failed (err %d)\n", err);
165 		return 0;
166 	}
167 
168 	if (IS_ENABLED(CONFIG_SETTINGS)) {
169 		settings_load();
170 	}
171 
172 	printk("Bluetooth initialized\n");
173 
174 	err = bt_iso_server_register(&iso_server);
175 	if (err) {
176 		printk("Unable to register ISO server (err %d)\n", err);
177 		return 0;
178 	}
179 
180 	err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
181 	if (err) {
182 		printk("Advertising failed to start (err %d)\n", err);
183 		return 0;
184 	}
185 
186 	printk("Advertising successfully started\n");
187 	return 0;
188 }
189