1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2015-2016 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/types.h>
10 #include <stddef.h>
11 #include <errno.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/sys/printk.h>
14
15 #include <zephyr/bluetooth/bluetooth.h>
16 #include <zephyr/bluetooth/hci.h>
17 #include <zephyr/bluetooth/conn.h>
18 #include <zephyr/bluetooth/uuid.h>
19 #include <zephyr/bluetooth/gatt.h>
20 #include <zephyr/sys/byteorder.h>
21
22 static void start_scan(void);
23
24 static struct bt_conn *default_conn;
25
26 static struct bt_uuid_16 discover_uuid = BT_UUID_INIT_16(0);
27 static struct bt_gatt_discover_params discover_params;
28 static struct bt_gatt_subscribe_params subscribe_params;
29
30 uint64_t total_rx_count; /* This value is exposed to test code */
31
notify_func(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)32 static uint8_t notify_func(struct bt_conn *conn,
33 struct bt_gatt_subscribe_params *params,
34 const void *data, uint16_t length)
35 {
36 if (!data) {
37 printk("[UNSUBSCRIBED]\n");
38 params->value_handle = 0U;
39 return BT_GATT_ITER_STOP;
40 }
41
42 printk("[NOTIFICATION] data %p length %u\n", data, length);
43
44 total_rx_count++;
45
46 return BT_GATT_ITER_CONTINUE;
47 }
48
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)49 static uint8_t discover_func(struct bt_conn *conn,
50 const struct bt_gatt_attr *attr,
51 struct bt_gatt_discover_params *params)
52 {
53 int err;
54
55 if (!attr) {
56 printk("Discover complete\n");
57 (void)memset(params, 0, sizeof(*params));
58 return BT_GATT_ITER_STOP;
59 }
60
61 printk("[ATTRIBUTE] handle %u\n", attr->handle);
62
63 if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HRS)) {
64 memcpy(&discover_uuid, BT_UUID_HRS_MEASUREMENT, sizeof(discover_uuid));
65 discover_params.uuid = &discover_uuid.uuid;
66 discover_params.start_handle = attr->handle + 1;
67 discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
68
69 err = bt_gatt_discover(conn, &discover_params);
70 if (err) {
71 printk("Discover failed (err %d)\n", err);
72 }
73 } else if (!bt_uuid_cmp(discover_params.uuid,
74 BT_UUID_HRS_MEASUREMENT)) {
75 memcpy(&discover_uuid, BT_UUID_GATT_CCC, sizeof(discover_uuid));
76 discover_params.uuid = &discover_uuid.uuid;
77 discover_params.start_handle = attr->handle + 2;
78 discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
79 subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
80
81 err = bt_gatt_discover(conn, &discover_params);
82 if (err) {
83 printk("Discover failed (err %d)\n", err);
84 }
85 } else {
86 subscribe_params.notify = notify_func;
87 subscribe_params.value = BT_GATT_CCC_NOTIFY;
88 subscribe_params.ccc_handle = attr->handle;
89
90 err = bt_gatt_subscribe(conn, &subscribe_params);
91 if (err && err != -EALREADY) {
92 printk("Subscribe failed (err %d)\n", err);
93 } else {
94 printk("[SUBSCRIBED]\n");
95 }
96
97 return BT_GATT_ITER_STOP;
98 }
99
100 return BT_GATT_ITER_STOP;
101 }
102
eir_found(struct bt_data * data,void * user_data)103 static bool eir_found(struct bt_data *data, void *user_data)
104 {
105 bt_addr_le_t *addr = user_data;
106 int i;
107
108 printk("[AD]: %u data_len %u\n", data->type, data->data_len);
109
110 switch (data->type) {
111 case BT_DATA_UUID16_SOME:
112 case BT_DATA_UUID16_ALL:
113 if (data->data_len % sizeof(uint16_t) != 0U) {
114 printk("AD malformed\n");
115 return true;
116 }
117
118 for (i = 0; i < data->data_len; i += sizeof(uint16_t)) {
119 struct bt_conn_le_create_param *create_param;
120 struct bt_le_conn_param *param;
121 const struct bt_uuid *uuid;
122 uint16_t u16;
123 int err;
124
125 memcpy(&u16, &data->data[i], sizeof(u16));
126 uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16));
127 if (bt_uuid_cmp(uuid, BT_UUID_HRS)) {
128 continue;
129 }
130
131 err = bt_le_scan_stop();
132 if (err) {
133 printk("Stop LE scan failed (err %d)\n", err);
134 continue;
135 }
136
137 printk("Creating connection with Coded PHY support\n");
138 param = BT_LE_CONN_PARAM_DEFAULT;
139 create_param = BT_CONN_LE_CREATE_CONN;
140 create_param->options |= BT_CONN_LE_OPT_CODED;
141 err = bt_conn_le_create(addr, create_param, param,
142 &default_conn);
143 if (err) {
144 printk("Create connection with Coded PHY support failed (err %d)\n",
145 err);
146
147 printk("Creating non-Coded PHY connection\n");
148 create_param->options &= ~BT_CONN_LE_OPT_CODED;
149 err = bt_conn_le_create(addr, create_param,
150 param, &default_conn);
151 if (err) {
152 printk("Create connection failed (err %d)\n", err);
153 start_scan();
154 }
155 }
156
157 return false;
158 }
159 }
160
161 return true;
162 }
163
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)164 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
165 struct net_buf_simple *ad)
166 {
167 char dev[BT_ADDR_LE_STR_LEN];
168
169 bt_addr_le_to_str(addr, dev, sizeof(dev));
170 printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n",
171 dev, type, ad->len, rssi);
172
173 /* We're only interested in legacy connectable events or
174 * possible extended advertising that are connectable.
175 */
176 if (type == BT_GAP_ADV_TYPE_ADV_IND ||
177 type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND ||
178 type == BT_GAP_ADV_TYPE_EXT_ADV) {
179 bt_data_parse(ad, eir_found, (void *)addr);
180 }
181 }
182
start_scan(void)183 static void start_scan(void)
184 {
185 int err;
186
187 /* Use active scanning and disable duplicate filtering to handle any
188 * devices that might update their advertising data at runtime. */
189 struct bt_le_scan_param scan_param = {
190 .type = BT_LE_SCAN_TYPE_ACTIVE,
191 .options = BT_LE_SCAN_OPT_CODED,
192 .interval = BT_GAP_SCAN_FAST_INTERVAL,
193 .window = BT_GAP_SCAN_FAST_WINDOW,
194 };
195
196 err = bt_le_scan_start(&scan_param, device_found);
197 if (err) {
198 printk("Scanning with Coded PHY support failed (err %d)\n", err);
199
200 printk("Scanning without Coded PHY\n");
201 scan_param.options &= ~BT_LE_SCAN_OPT_CODED;
202 err = bt_le_scan_start(&scan_param, device_found);
203 if (err) {
204 printk("Scanning failed to start (err %d)\n", err);
205 return;
206 }
207 }
208
209 printk("Scanning successfully started\n");
210 }
211
connected(struct bt_conn * conn,uint8_t conn_err)212 static void connected(struct bt_conn *conn, uint8_t conn_err)
213 {
214 char addr[BT_ADDR_LE_STR_LEN];
215 int err;
216
217 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
218
219 if (conn_err) {
220 printk("Failed to connect to %s (%u)\n", addr, conn_err);
221
222 bt_conn_unref(default_conn);
223 default_conn = NULL;
224
225 start_scan();
226 return;
227 }
228
229 printk("Connected: %s\n", addr);
230
231 total_rx_count = 0U;
232
233 if (conn == default_conn) {
234 memcpy(&discover_uuid, BT_UUID_HRS, sizeof(discover_uuid));
235 discover_params.uuid = &discover_uuid.uuid;
236 discover_params.func = discover_func;
237 discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
238 discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
239 discover_params.type = BT_GATT_DISCOVER_PRIMARY;
240
241 err = bt_gatt_discover(default_conn, &discover_params);
242 if (err) {
243 printk("Discover failed(err %d)\n", err);
244 return;
245 }
246 }
247 }
248
disconnected(struct bt_conn * conn,uint8_t reason)249 static void disconnected(struct bt_conn *conn, uint8_t reason)
250 {
251 char addr[BT_ADDR_LE_STR_LEN];
252
253 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
254
255 printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
256
257 if (default_conn != conn) {
258 return;
259 }
260
261 bt_conn_unref(default_conn);
262 default_conn = NULL;
263
264 start_scan();
265 }
266
267 BT_CONN_CB_DEFINE(conn_callbacks) = {
268 .connected = connected,
269 .disconnected = disconnected,
270 };
271
main(void)272 int main(void)
273 {
274 int err;
275 err = bt_enable(NULL);
276
277 if (err) {
278 printk("Bluetooth init failed (err %d)\n", err);
279 return 0;
280 }
281
282 printk("Bluetooth initialized\n");
283
284 start_scan();
285 return 0;
286 }
287