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