1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2021 Nordic Semiconductor ASA
5 * Copyright (c) 2015-2016 Intel Corporation
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <zephyr/types.h>
11 #include <stddef.h>
12 #include <errno.h>
13 #include <zephyr.h>
14 #include <sys/printk.h>
15
16 #include <bluetooth/bluetooth.h>
17 #include <bluetooth/hci.h>
18 #include <bluetooth/conn.h>
19 #include <bluetooth/uuid.h>
20 #include <bluetooth/gatt.h>
21 #include <sys/byteorder.h>
22
23 #define SCAN_INTERVAL 0x0140 /* 200 ms */
24 #define SCAN_WINDOW 0x0030 /* 30 ms */
25 #define INIT_INTERVAL 0x0010 /* 10 ms */
26 #define INIT_WINDOW 0x0010 /* 10 ms */
27 #define CONN_INTERVAL 0x00A0 /* 200 ms */
28 #define CONN_LATENCY 0
29 #define CONN_TIMEOUT MIN(MAX((CONN_INTERVAL * 125 * \
30 MAX(CONFIG_BT_MAX_CONN, 6) / 1000), 10), 3200)
31
32 static void start_scan(void);
33
34 static struct bt_conn *conn_connecting;
35 static uint8_t volatile conn_count;
36
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)37 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
38 struct net_buf_simple *ad)
39 {
40 struct bt_conn_le_create_param create_param = {
41 .options = BT_CONN_LE_OPT_NONE,
42 .interval = INIT_INTERVAL,
43 .window = INIT_WINDOW,
44 .interval_coded = 0,
45 .window_coded = 0,
46 .timeout = 0,
47 };
48 struct bt_le_conn_param conn_param = {
49 .interval_min = CONN_INTERVAL,
50 .interval_max = CONN_INTERVAL,
51 .latency = CONN_LATENCY,
52 .timeout = CONN_TIMEOUT,
53 };
54 char addr_str[BT_ADDR_LE_STR_LEN];
55 int err;
56
57 if (conn_connecting) {
58 return;
59 }
60
61 /* We're only interested in connectable events */
62 if (type != BT_GAP_ADV_TYPE_ADV_IND &&
63 type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
64 return;
65 }
66
67 bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
68 printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
69
70 /* connect only to devices in close proximity */
71 if (rssi < -35) {
72 return;
73 }
74
75 if (bt_le_scan_stop()) {
76 return;
77 }
78
79 err = bt_conn_le_create(addr, &create_param, &conn_param,
80 &conn_connecting);
81 if (err) {
82 printk("Create conn to %s failed (%d)\n", addr_str, err);
83 start_scan();
84 }
85 }
86
start_scan(void)87 static void start_scan(void)
88 {
89 struct bt_le_scan_param scan_param = {
90 .type = BT_HCI_LE_SCAN_PASSIVE,
91 .options = BT_LE_SCAN_OPT_NONE,
92 .interval = SCAN_INTERVAL,
93 .window = SCAN_WINDOW,
94 };
95 int err;
96
97 err = bt_le_scan_start(&scan_param, device_found);
98 if (err) {
99 printk("Scanning failed to start (err %d)\n", err);
100 return;
101 }
102
103 printk("Scanning successfully started\n");
104 }
105
106 #if defined(CONFIG_BT_GATT_CLIENT)
mtu_exchange_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_exchange_params * params)107 static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
108 struct bt_gatt_exchange_params *params)
109 {
110 printk("MTU exchange %u %s (%u)\n", bt_conn_index(conn),
111 err == 0U ? "successful" : "failed", bt_gatt_get_mtu(conn));
112 }
113
114 static struct bt_gatt_exchange_params mtu_exchange_params[CONFIG_BT_MAX_CONN];
115
mtu_exchange(struct bt_conn * conn)116 static int mtu_exchange(struct bt_conn *conn)
117 {
118 uint8_t conn_index;
119 int err;
120
121 conn_index = bt_conn_index(conn);
122
123 printk("MTU (%u): %u\n", conn_index, bt_gatt_get_mtu(conn));
124
125 mtu_exchange_params[conn_index].func = mtu_exchange_cb;
126
127 err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params[conn_index]);
128 if (err) {
129 printk("MTU exchange failed (err %d)", err);
130 } else {
131 printk("Exchange pending...");
132 }
133
134 return err;
135 }
136 #endif /* CONFIG_BT_GATT_CLIENT */
137
connected(struct bt_conn * conn,uint8_t reason)138 static void connected(struct bt_conn *conn, uint8_t reason)
139 {
140 char addr[BT_ADDR_LE_STR_LEN];
141
142 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
143
144 if (reason) {
145 printk("Failed to connect to %s (%u)\n", addr, reason);
146
147 bt_conn_unref(conn_connecting);
148 conn_connecting = NULL;
149
150 start_scan();
151 return;
152 }
153
154 conn_connecting = NULL;
155
156 conn_count++;
157 if (conn_count < CONFIG_BT_MAX_CONN) {
158 start_scan();
159 }
160
161 printk("Connected (%u): %s\n", conn_count, addr);
162
163 #if defined(CONFIG_BT_SMP)
164 int err = bt_conn_set_security(conn, BT_SECURITY_L2);
165
166 if (err) {
167 printk("Failed to set security (%d).\n", err);
168 }
169 #endif
170
171 #if defined(CONFIG_BT_GATT_CLIENT)
172 mtu_exchange(conn);
173 #endif
174 }
175
disconnected(struct bt_conn * conn,uint8_t reason)176 static void disconnected(struct bt_conn *conn, uint8_t reason)
177 {
178 char addr[BT_ADDR_LE_STR_LEN];
179
180 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
181
182 printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
183
184 bt_conn_unref(conn);
185
186 if (conn_count == CONFIG_BT_MAX_CONN) {
187 start_scan();
188 }
189 conn_count--;
190 }
191
le_param_req(struct bt_conn * conn,struct bt_le_conn_param * param)192 static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
193 {
194 char addr[BT_ADDR_LE_STR_LEN];
195
196 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
197
198 printk("LE conn param req: %s int (0x%04x, 0x%04x) lat %d to %d\n",
199 addr, param->interval_min, param->interval_max, param->latency,
200 param->timeout);
201
202 return true;
203 }
204
le_param_updated(struct bt_conn * conn,uint16_t interval,uint16_t latency,uint16_t timeout)205 static void le_param_updated(struct bt_conn *conn, uint16_t interval,
206 uint16_t latency, uint16_t timeout)
207 {
208 char addr[BT_ADDR_LE_STR_LEN];
209
210 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
211
212 printk("LE conn param updated: %s int 0x%04x lat %d to %d\n",
213 addr, interval, latency, timeout);
214 }
215
216 #if defined(CONFIG_BT_SMP)
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)217 static void security_changed(struct bt_conn *conn, bt_security_t level,
218 enum bt_security_err err)
219 {
220 char addr[BT_ADDR_LE_STR_LEN];
221
222 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
223
224 if (!err) {
225 printk("Security changed: %s level %u\n", addr, level);
226 } else {
227 printk("Security failed: %s level %u err %d\n", addr, level,
228 err);
229 }
230 }
231 #endif
232
233 static struct bt_conn_cb conn_callbacks = {
234 .connected = connected,
235 .disconnected = disconnected,
236 .le_param_req = le_param_req,
237 .le_param_updated = le_param_updated,
238 #if defined(CONFIG_BT_SMP)
239 .security_changed = security_changed,
240 #endif
241 };
242
init_central(void)243 int init_central(void)
244 {
245 int err;
246
247 err = bt_enable(NULL);
248 if (err) {
249 printk("Bluetooth init failed (err %d)\n", err);
250 return err;
251 }
252
253 printk("Bluetooth initialized\n");
254
255 bt_conn_cb_register(&conn_callbacks);
256
257 start_scan();
258
259 while (conn_count < CONFIG_BT_MAX_CONN) {
260 k_sleep(K_SECONDS(1));
261 }
262
263 return 0;
264 }
265