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