1 /** @file
2  *  @brief Bluetooth Object Transfer Client Sample
3  *
4  * Copyright (c) 2022 Nordic Semiconductor ASA
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <errno.h>
10 #include <stddef.h>
11 
12 #include <zephyr/bluetooth/bluetooth.h>
13 #include <zephyr/bluetooth/conn.h>
14 #include <zephyr/bluetooth/gatt.h>
15 #include <zephyr/bluetooth/hci.h>
16 #include <zephyr/bluetooth/services/ots.h>
17 #include <zephyr/bluetooth/uuid.h>
18 #include <zephyr/device.h>
19 #include <zephyr/drivers/gpio.h>
20 #include <zephyr/sys/byteorder.h>
21 #include <zephyr/sys/printk.h>
22 #include <zephyr/types.h>
23 #include <zephyr/kernel.h>
24 
25 #define OBJ_MAX_SIZE			      1024
26 /* Hardcoded here since definition is in internal header */
27 #define BT_GATT_OTS_OLCP_RES_OPERATION_FAILED 0x04
28 #define BT_GATT_OTS_OLCP_RES_OUT_OF_BONDS     0x05
29 
30 static struct bt_ots_client otc;
31 static struct bt_ots_client_cb otc_cb;
32 static struct bt_gatt_discover_params discover_params;
33 static struct bt_gatt_subscribe_params *oacp_sub_params;
34 static struct bt_gatt_subscribe_params *olcp_sub_params;
35 static unsigned char obj_data_buf[OBJ_MAX_SIZE];
36 static uint32_t last_checksum;
37 
38 static bool first_selected;
39 static void on_obj_selected(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err);
40 
41 static void on_obj_metadata_read(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err,
42 				 uint8_t metadata_read);
43 
44 static int on_obj_data_read(struct bt_ots_client *ots_inst, struct bt_conn *conn, uint32_t offset,
45 			    uint32_t len, uint8_t *data_p, bool is_complete);
46 
47 static void start_scan(void);
48 static struct bt_uuid_16 discover_uuid = BT_UUID_INIT_16(0);
49 static struct bt_conn *default_conn;
50 static atomic_t discovery_state;
51 
52 enum OTS_SERVICE_DISCOVERY_STATE_BIT {
53 	DISC_OTS_FEATURE,
54 	DISC_OTS_NAME,
55 	DISC_OTS_TYPE,
56 	DISC_OTS_SIZE,
57 	DISC_OTS_ID,
58 	DISC_OTS_PROPERTIES,
59 	DISC_OTS_ACTION_CP,
60 	DISC_OTS_LIST_CP,
61 };
62 
print_hex_number(const uint8_t * num,size_t len)63 static void print_hex_number(const uint8_t *num, size_t len)
64 {
65 	printk("0x");
66 	for (size_t i = 0; i < len; i++) {
67 		printk("%02x ", num[i]);
68 	}
69 
70 	printk("\n");
71 }
72 
73 /*
74  * Get buttons configuration from the devicetree sw0~sw3 alias. This is mandatory.
75  */
76 #define SW0_NODE DT_ALIAS(sw0)
77 #define SW1_NODE DT_ALIAS(sw1)
78 #define SW2_NODE DT_ALIAS(sw2)
79 #define SW3_NODE DT_ALIAS(sw3)
80 #if !DT_NODE_HAS_STATUS_OKAY(SW0_NODE) || !DT_NODE_HAS_STATUS_OKAY(SW1_NODE) ||                    \
81 	!DT_NODE_HAS_STATUS_OKAY(SW2_NODE) || !DT_NODE_HAS_STATUS_OKAY(SW3_NODE)
82 #error "Unsupported board: This sample need 4 buttons to run"
83 #endif
84 
85 static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0});
86 static const struct gpio_dt_spec button1 = GPIO_DT_SPEC_GET_OR(SW1_NODE, gpios, {0});
87 static const struct gpio_dt_spec button2 = GPIO_DT_SPEC_GET_OR(SW2_NODE, gpios, {0});
88 static const struct gpio_dt_spec button3 = GPIO_DT_SPEC_GET_OR(SW3_NODE, gpios, {0});
89 #define BTN_COUNT 4
90 
91 static const struct gpio_dt_spec btns[BTN_COUNT] = {button0, button1, button2, button3};
92 static struct gpio_callback button_cb_data;
93 struct otc_btn_work_info {
94 	struct k_work_delayable work;
95 	uint32_t pins;
96 } otc_btn_work;
97 
98 struct otc_checksum_work_info {
99 	struct k_work_delayable work;
100 	off_t offset;
101 	size_t len;
102 } otc_checksum_work;
103 
otc_btn_work_fn(struct k_work * work)104 static void otc_btn_work_fn(struct k_work *work)
105 {
106 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
107 	struct otc_btn_work_info *btn_work = CONTAINER_OF(dwork, struct otc_btn_work_info, work);
108 	int err;
109 	size_t size_to_write;
110 
111 	if (btn_work->pins == BIT(button0.pin)) {
112 		if (!first_selected) {
113 			err = bt_ots_client_select_id(&otc, default_conn, BT_OTS_OBJ_ID_MIN);
114 			first_selected = true;
115 		} else {
116 			printk("select next\n");
117 			err = bt_ots_client_select_next(&otc, default_conn);
118 		}
119 
120 		if (err != 0) {
121 			printk("Failed to select object (err %d)\n", err);
122 		}
123 
124 		printk("Selecting object succeeded\n");
125 	} else if (btn_work->pins == BIT(button1.pin)) {
126 		printk("read OTS object meta\n");
127 		err = bt_ots_client_read_object_metadata(&otc, default_conn,
128 							 BT_OTS_METADATA_REQ_ALL);
129 		if (err != 0) {
130 			printk("Failed to read object metadata (err %d)\n", err);
131 		}
132 
133 	} else if (btn_work->pins == BIT(button2.pin)) {
134 		if (BT_OTS_OBJ_GET_PROP_WRITE(otc.cur_object.props)) {
135 			size_to_write = MIN(OBJ_MAX_SIZE, otc.cur_object.size.alloc);
136 			(void)memset(obj_data_buf, 0, size_to_write);
137 			printk("Going to write OTS object len %d\n", size_to_write);
138 			for (uint32_t idx = 0; idx < size_to_write; idx++) {
139 				obj_data_buf[idx] = UINT8_MAX - (idx % UINT8_MAX);
140 			}
141 
142 			last_checksum = bt_ots_client_calc_checksum(obj_data_buf, size_to_write);
143 			printk("Data sent checksum 0x%08x\n", last_checksum);
144 			err = bt_ots_client_write_object_data(&otc, default_conn, obj_data_buf,
145 							      size_to_write, 0,
146 							      BT_OTS_OACP_WRITE_OP_MODE_NONE);
147 			if (err != 0) {
148 				printk("Failed to write object (err %d)\n", err);
149 			}
150 		} else {
151 			printk("This OBJ does not support WRITE OP\n");
152 		}
153 
154 	} else if (btn_work->pins == BIT(button3.pin)) {
155 		if (BT_OTS_OBJ_GET_PROP_READ(otc.cur_object.props)) {
156 			printk("read OTS object\n");
157 			err = bt_ots_client_read_object_data(&otc, default_conn);
158 			if (err != 0) {
159 				printk("Failed to read object %d\n", err);
160 			}
161 		} else {
162 			printk("This OBJ does not support READ OP\n");
163 		}
164 	}
165 }
166 
otc_checksum_work_fn(struct k_work * work)167 static void otc_checksum_work_fn(struct k_work *work)
168 {
169 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
170 	struct otc_checksum_work_info *checksum_work =
171 		CONTAINER_OF(dwork, struct otc_checksum_work_info, work);
172 	int err;
173 
174 	err = bt_ots_client_get_object_checksum(&otc, default_conn, checksum_work->offset,
175 						checksum_work->len);
176 	if (err != 0) {
177 		printk("bt_ots_client_get_object_checksum failed (%d)\n", err);
178 	}
179 }
180 
button_pressed(const struct device * dev,struct gpio_callback * cb,uint32_t pins)181 static void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
182 {
183 	otc_btn_work.pins = pins;
184 	k_work_schedule(&otc_btn_work.work, K_MSEC(100));
185 }
186 
configure_button_irq(const struct gpio_dt_spec btn)187 static void configure_button_irq(const struct gpio_dt_spec btn)
188 {
189 	int ret;
190 
191 	if (!gpio_is_ready_dt(&btn)) {
192 		printk("Error: button device %s is not ready\n", btn.port->name);
193 		return;
194 	}
195 
196 	ret = gpio_pin_configure_dt(&btn, GPIO_INPUT);
197 	if (ret != 0) {
198 		printk("Error %d: failed to configure %s pin %d\n", ret, btn.port->name, btn.pin);
199 		return;
200 	}
201 
202 	ret = gpio_pin_interrupt_configure_dt(&btn, GPIO_INT_EDGE_TO_ACTIVE);
203 
204 	if (ret != 0) {
205 		printk("Error %d: failed to configure interrupt on %s pin %d\n", ret,
206 		       btn.port->name, btn.pin);
207 		return;
208 	}
209 
210 	button_cb_data.pin_mask |= BIT(btn.pin);
211 	gpio_add_callback(btn.port, &button_cb_data);
212 
213 	printk("Set up button at %s pin %d\n", btn.port->name, btn.pin);
214 }
215 
configure_buttons(void)216 static void configure_buttons(void)
217 {
218 	gpio_init_callback(&button_cb_data, button_pressed, 0);
219 
220 	for (int idx = 0; idx < BTN_COUNT; idx++) {
221 		configure_button_irq(btns[idx]);
222 	}
223 }
224 
eir_found(struct bt_data * data,void * user_data)225 static bool eir_found(struct bt_data *data, void *user_data)
226 {
227 	bt_addr_le_t *addr = user_data;
228 	int i;
229 
230 	switch (data->type) {
231 	case BT_DATA_UUID16_SOME:
232 	case BT_DATA_UUID16_ALL:
233 		if (data->data_len % sizeof(uint16_t) != 0U) {
234 			printk("AD malformed\n");
235 			return true;
236 		}
237 
238 		for (i = 0; i < data->data_len; i += sizeof(uint16_t)) {
239 			struct bt_le_conn_param *param;
240 			const struct bt_uuid *uuid;
241 			uint16_t u16;
242 			int err;
243 
244 			(void)memcpy(&u16, &data->data[i], sizeof(u16));
245 			uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16));
246 			if (bt_uuid_cmp(uuid, BT_UUID_OTS) != 0) {
247 				continue;
248 			}
249 
250 			err = bt_le_scan_stop();
251 			if (err != 0) {
252 				printk("Stop LE scan failed (err %d)\n", err);
253 				continue;
254 			}
255 
256 			param = BT_LE_CONN_PARAM_DEFAULT;
257 			err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn);
258 			if (err != 0) {
259 				printk("Create conn failed (err %d)\n", err);
260 				start_scan();
261 			}
262 
263 			return false;
264 		}
265 	}
266 	return true;
267 }
268 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)269 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
270 			 struct net_buf_simple *ad)
271 {
272 	char dev[BT_ADDR_LE_STR_LEN];
273 
274 	bt_addr_le_to_str(addr, dev, sizeof(dev));
275 
276 	/* We're only interested in connectable events and scan response
277 	 * because service UUID is in sd of sample peripheral_ots.
278 	 */
279 	if (type == BT_GAP_ADV_TYPE_ADV_IND || type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND ||
280 	    type == BT_GAP_ADV_TYPE_SCAN_RSP) {
281 		bt_data_parse(ad, eir_found, (void *)addr);
282 	}
283 }
284 
start_scan(void)285 static void start_scan(void)
286 {
287 	int err;
288 
289 	/* Use active scanning and disable duplicate filtering to handle any
290 	 * devices that might update their advertising data at runtime.
291 	 */
292 	struct bt_le_scan_param scan_param = {
293 		.type = BT_LE_SCAN_TYPE_ACTIVE,
294 		.options = BT_LE_SCAN_OPT_NONE,
295 		.interval = BT_GAP_SCAN_FAST_INTERVAL,
296 		.window = BT_GAP_SCAN_FAST_WINDOW,
297 	};
298 
299 	err = bt_le_scan_start(&scan_param, device_found);
300 	if (err != 0) {
301 		printk("Scanning OTS TAG failed to start (err %d)\n", err);
302 		return;
303 	}
304 
305 	printk("Scanning successfully started\n");
306 }
307 
subscribe_func(void)308 static int subscribe_func(void)
309 {
310 	int ret;
311 
312 	printk("Subscribe OACP and OLCP Indication\n");
313 	oacp_sub_params = &otc.oacp_sub_params;
314 	oacp_sub_params->disc_params = &otc.oacp_sub_disc_params;
315 	if (oacp_sub_params) {
316 		oacp_sub_params->ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
317 		oacp_sub_params->end_handle = otc.end_handle;
318 		oacp_sub_params->value = BT_GATT_CCC_INDICATE;
319 		oacp_sub_params->value_handle = otc.oacp_handle;
320 		oacp_sub_params->notify = bt_ots_client_indicate_handler;
321 		ret = bt_gatt_subscribe(default_conn, oacp_sub_params);
322 
323 		if (ret != 0) {
324 			printk("Subscribe OACP failed %d\n", ret);
325 			return ret;
326 		}
327 	}
328 
329 	olcp_sub_params = &otc.olcp_sub_params;
330 	olcp_sub_params->disc_params = &otc.olcp_sub_disc_params;
331 	if (olcp_sub_params) {
332 		olcp_sub_params->ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
333 		olcp_sub_params->end_handle = otc.end_handle;
334 		olcp_sub_params->value = BT_GATT_CCC_INDICATE;
335 		olcp_sub_params->value_handle = otc.olcp_handle;
336 		olcp_sub_params->notify = bt_ots_client_indicate_handler;
337 		ret = bt_gatt_subscribe(default_conn, olcp_sub_params);
338 
339 		if (ret != 0) {
340 			printk("Subscribe OLCP failed %d\n", ret);
341 			return ret;
342 		}
343 	}
344 
345 	return ret;
346 }
347 
is_discovery_complete(void)348 static bool is_discovery_complete(void)
349 {
350 	return (atomic_test_bit(&discovery_state, DISC_OTS_FEATURE) &&
351 		atomic_test_bit(&discovery_state, DISC_OTS_NAME) &&
352 		atomic_test_bit(&discovery_state, DISC_OTS_TYPE) &&
353 		atomic_test_bit(&discovery_state, DISC_OTS_SIZE) &&
354 		atomic_test_bit(&discovery_state, DISC_OTS_ID) &&
355 		atomic_test_bit(&discovery_state, DISC_OTS_PROPERTIES) &&
356 		atomic_test_bit(&discovery_state, DISC_OTS_ACTION_CP) &&
357 		atomic_test_bit(&discovery_state, DISC_OTS_LIST_CP));
358 }
359 
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)360 static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
361 			     struct bt_gatt_discover_params *params)
362 {
363 	int err;
364 
365 	if (!attr) {
366 		printk("Discover complete\n");
367 		(void)memset(params, 0, sizeof(*params));
368 		return BT_GATT_ITER_STOP;
369 	}
370 
371 	if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OTS) == 0) {
372 		(void)memcpy(&discover_uuid, BT_UUID_OTS_FEATURE, sizeof(discover_uuid));
373 		discover_params.uuid = &discover_uuid.uuid;
374 		discover_params.start_handle = attr->handle + 1;
375 		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
376 		err = bt_gatt_discover(conn, &discover_params);
377 
378 		if (err != 0) {
379 			printk("Discover failed (err %d)\n", err);
380 		}
381 
382 	} else if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OTS_FEATURE) == 0) {
383 		atomic_set_bit(&discovery_state, DISC_OTS_FEATURE);
384 		otc.feature_handle = bt_gatt_attr_value_handle(attr);
385 		(void)memcpy(&discover_uuid, BT_UUID_OTS_NAME, sizeof(discover_uuid));
386 		discover_params.uuid = &discover_uuid.uuid;
387 		discover_params.start_handle = attr->handle + 1;
388 		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
389 
390 		err = bt_gatt_discover(conn, &discover_params);
391 		if (err != 0) {
392 			printk("Discover failed (err %d)\n", err);
393 		}
394 
395 	} else if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OTS_NAME) == 0) {
396 		atomic_set_bit(&discovery_state, DISC_OTS_NAME);
397 		otc.obj_name_handle = bt_gatt_attr_value_handle(attr);
398 		(void)memcpy(&discover_uuid, BT_UUID_OTS_TYPE, sizeof(discover_uuid));
399 		discover_params.uuid = &discover_uuid.uuid;
400 		discover_params.start_handle = attr->handle + 1;
401 		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
402 
403 		err = bt_gatt_discover(conn, &discover_params);
404 		if (err != 0) {
405 			printk("Discover failed (err %d)\n", err);
406 		}
407 
408 	} else if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OTS_TYPE) == 0) {
409 		atomic_set_bit(&discovery_state, DISC_OTS_TYPE);
410 		otc.obj_type_handle = bt_gatt_attr_value_handle(attr);
411 		(void)memcpy(&discover_uuid, BT_UUID_OTS_SIZE, sizeof(discover_uuid));
412 		discover_params.uuid = &discover_uuid.uuid;
413 		discover_params.start_handle = attr->handle + 1;
414 		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
415 
416 		err = bt_gatt_discover(conn, &discover_params);
417 		if (err != 0) {
418 			printk("Discover failed (err %d)\n", err);
419 		}
420 
421 	} else if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OTS_SIZE) == 0) {
422 		atomic_set_bit(&discovery_state, DISC_OTS_SIZE);
423 		otc.obj_size_handle = bt_gatt_attr_value_handle(attr);
424 		(void)memcpy(&discover_uuid, BT_UUID_OTS_ID, sizeof(discover_uuid));
425 		discover_params.uuid = &discover_uuid.uuid;
426 		discover_params.start_handle = attr->handle + 1;
427 		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
428 
429 		err = bt_gatt_discover(conn, &discover_params);
430 		if (err != 0) {
431 			printk("Discover failed (err %d)\n", err);
432 		}
433 
434 	} else if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OTS_ID) == 0) {
435 		atomic_set_bit(&discovery_state, DISC_OTS_ID);
436 		otc.obj_id_handle = bt_gatt_attr_value_handle(attr);
437 		(void)memcpy(&discover_uuid, BT_UUID_OTS_PROPERTIES, sizeof(discover_uuid));
438 		discover_params.uuid = &discover_uuid.uuid;
439 		discover_params.start_handle = attr->handle + 1;
440 		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
441 
442 		err = bt_gatt_discover(conn, &discover_params);
443 		if (err != 0) {
444 			printk("Discover failed (err %d)\n", err);
445 		}
446 
447 	} else if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OTS_PROPERTIES) == 0) {
448 		atomic_set_bit(&discovery_state, DISC_OTS_PROPERTIES);
449 		otc.obj_properties_handle = bt_gatt_attr_value_handle(attr);
450 		(void)memcpy(&discover_uuid, BT_UUID_OTS_ACTION_CP, sizeof(discover_uuid));
451 		discover_params.uuid = &discover_uuid.uuid;
452 		discover_params.start_handle = attr->handle + 1;
453 		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
454 
455 		err = bt_gatt_discover(conn, &discover_params);
456 		if (err != 0) {
457 			printk("Discover failed (err %d)\n", err);
458 		}
459 	} else if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OTS_ACTION_CP) == 0) {
460 		atomic_set_bit(&discovery_state, DISC_OTS_ACTION_CP);
461 		otc.oacp_handle = bt_gatt_attr_value_handle(attr);
462 		(void)memcpy(&discover_uuid, BT_UUID_OTS_LIST_CP, sizeof(discover_uuid));
463 		discover_params.uuid = &discover_uuid.uuid;
464 		discover_params.start_handle = attr->handle + 1;
465 		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
466 
467 		err = bt_gatt_discover(conn, &discover_params);
468 		if (err != 0) {
469 			printk("Discover failed (err %d)\n", err);
470 		}
471 	} else if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OTS_LIST_CP) == 0) {
472 		atomic_set_bit(&discovery_state, DISC_OTS_LIST_CP);
473 		otc.olcp_handle = bt_gatt_attr_value_handle(attr);
474 	} else {
475 		return BT_GATT_ITER_STOP;
476 	}
477 
478 	if (is_discovery_complete()) {
479 		printk("Discovery complete for OTS Client\n");
480 		err = subscribe_func();
481 
482 		if (err != 0) {
483 			return BT_GATT_ITER_STOP;
484 		}
485 
486 		/* Read feature of OTS server*/
487 		err = bt_ots_client_read_feature(&otc, default_conn);
488 		if (err != 0) {
489 			printk("bt_ots_client_read_feature failed (err %d)", err);
490 		}
491 	}
492 
493 	return BT_GATT_ITER_STOP;
494 }
495 
connected(struct bt_conn * conn,uint8_t err)496 static void connected(struct bt_conn *conn, uint8_t err)
497 {
498 	char addr[BT_ADDR_LE_STR_LEN];
499 
500 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
501 	first_selected = false;
502 	if (err != 0) {
503 		printk("Failed to connect to %s %u %s\n", addr, err, bt_hci_err_to_str(err));
504 
505 		bt_conn_unref(default_conn);
506 		default_conn = NULL;
507 		start_scan();
508 		return;
509 	}
510 
511 	if (conn != default_conn) {
512 		return;
513 	}
514 
515 	printk("Connected: %s\n", addr);
516 
517 	if (conn == default_conn) {
518 		(void)memcpy(&discover_uuid, BT_UUID_OTS, sizeof(discover_uuid));
519 		discover_params.uuid = &discover_uuid.uuid;
520 		discover_params.func = discover_func;
521 		discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
522 		discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
523 		discover_params.type = BT_GATT_DISCOVER_PRIMARY;
524 
525 		err = bt_gatt_discover(default_conn, &discover_params);
526 		if (err != 0) {
527 			printk("Discover failed(err %d)\n", err);
528 			return;
529 		}
530 	}
531 }
532 
disconnected(struct bt_conn * conn,uint8_t reason)533 static void disconnected(struct bt_conn *conn, uint8_t reason)
534 {
535 	char addr[BT_ADDR_LE_STR_LEN];
536 
537 	if (conn != default_conn) {
538 		return;
539 	}
540 
541 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
542 
543 	printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
544 
545 	bt_conn_unref(default_conn);
546 	default_conn = NULL;
547 	discovery_state = ATOMIC_INIT(0);
548 	start_scan();
549 }
550 
551 BT_CONN_CB_DEFINE(conn_callbacks) = {
552 	.connected = connected,
553 	.disconnected = disconnected,
554 };
555 
on_obj_selected(struct bt_ots_client * ots_inst,struct bt_conn * conn,int err)556 static void on_obj_selected(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err)
557 {
558 	printk("Current object selected cb OLCP result (%d)\n", err);
559 
560 	if (err == BT_GATT_OTS_OLCP_RES_OPERATION_FAILED) {
561 		printk("BT_GATT_OTS_OLCP_RES_OPERATION_FAILED %d\n", err);
562 		first_selected = false;
563 	} else if (err == BT_GATT_OTS_OLCP_RES_OUT_OF_BONDS) {
564 		printk("BT_GATT_OTS_OLCP_RES_OUT_OF_BONDS %d. Select first valid instead\n", err);
565 		(void)bt_ots_client_select_id(&otc, default_conn, BT_OTS_OBJ_ID_MIN);
566 	}
567 
568 	(void)memset(obj_data_buf, 0, OBJ_MAX_SIZE);
569 }
570 
on_obj_data_read(struct bt_ots_client * ots_inst,struct bt_conn * conn,uint32_t offset,uint32_t len,uint8_t * data_p,bool is_complete)571 static int on_obj_data_read(struct bt_ots_client *ots_inst, struct bt_conn *conn, uint32_t offset,
572 			    uint32_t len, uint8_t *data_p, bool is_complete)
573 {
574 	printk("Received OTS Object content, %i bytes at offset %i\n", len, offset);
575 
576 	print_hex_number(data_p, len);
577 
578 	if ((offset + len) > OBJ_MAX_SIZE) {
579 		printk("Can not fit whole object, drop the rest of data\n");
580 	} else {
581 		(void)memcpy((obj_data_buf + offset), data_p, MIN((OBJ_MAX_SIZE - offset), len));
582 	}
583 
584 	if (is_complete) {
585 		printk("Object total received %d\n", len + offset);
586 		print_hex_number(obj_data_buf, len + offset);
587 		(void)memset(obj_data_buf, 0, OBJ_MAX_SIZE);
588 		otc_checksum_work.offset = 0;
589 		otc_checksum_work.len = otc.cur_object.size.cur;
590 		k_work_schedule(&otc_checksum_work.work, K_NO_WAIT);
591 		return BT_OTS_STOP;
592 	}
593 
594 	return BT_OTS_CONTINUE;
595 }
596 
on_obj_metadata_read(struct bt_ots_client * ots_inst,struct bt_conn * conn,int err,uint8_t metadata_read)597 static void on_obj_metadata_read(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err,
598 				 uint8_t metadata_read)
599 {
600 	printk("Object's meta data:\n");
601 	printk("\tCurrent size\t:%u", ots_inst->cur_object.size.cur);
602 	printk("\tAlloc size\t:%u\n", ots_inst->cur_object.size.alloc);
603 
604 	if (ots_inst->cur_object.size.cur > OBJ_MAX_SIZE) {
605 		printk("Object larger than allocated buffer\n");
606 	}
607 
608 	bt_ots_metadata_display(&ots_inst->cur_object, 1);
609 }
on_obj_data_written(struct bt_ots_client * ots_inst,struct bt_conn * conn,size_t len)610 static void on_obj_data_written(struct bt_ots_client *ots_inst, struct bt_conn *conn, size_t len)
611 {
612 	int err;
613 
614 	printk("Object been written %d\n", len);
615 	/* Update object size after write done*/
616 	err = bt_ots_client_read_object_metadata(&otc, default_conn,
617 						 BT_OTS_METADATA_REQ_ALL);
618 	if (err != 0) {
619 		printk("Failed to read object metadata (err %d)\n", err);
620 	}
621 }
622 
on_obj_checksum_calculated(struct bt_ots_client * ots_inst,struct bt_conn * conn,int err,uint32_t checksum)623 void on_obj_checksum_calculated(struct bt_ots_client *ots_inst,
624 				struct bt_conn *conn, int err, uint32_t checksum)
625 {
626 	printk("Object Calculate checksum OACP result (%d)\nChecksum 0x%08x last sent 0x%08x %s\n",
627 	       err, checksum, last_checksum, (checksum == last_checksum) ? "match" : "not match");
628 }
629 
bt_otc_init(void)630 static void bt_otc_init(void)
631 {
632 	otc_cb.obj_data_read = on_obj_data_read;
633 	otc_cb.obj_selected = on_obj_selected;
634 	otc_cb.obj_metadata_read = on_obj_metadata_read;
635 	otc_cb.obj_data_written = on_obj_data_written;
636 	otc_cb.obj_checksum_calculated = on_obj_checksum_calculated;
637 	otc.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
638 	otc.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
639 	printk("Current object selected callback: %p\n", otc_cb.obj_selected);
640 	printk("Content callback: %p\n", otc_cb.obj_data_read);
641 	printk("Metadata callback: %p\n", otc_cb.obj_metadata_read);
642 	otc.cb = &otc_cb;
643 	bt_ots_client_register(&otc);
644 }
645 
main(void)646 int main(void)
647 {
648 	int err;
649 
650 	first_selected = false;
651 	discovery_state = ATOMIC_INIT(0);
652 	k_work_init_delayable(&otc_btn_work.work, otc_btn_work_fn);
653 	k_work_init_delayable(&otc_checksum_work.work, otc_checksum_work_fn);
654 
655 	configure_buttons();
656 	err = bt_enable(NULL);
657 
658 	if (err != 0) {
659 		printk("Bluetooth init failed (err %d)\n", err);
660 		return 0;
661 	}
662 
663 	bt_otc_init();
664 	printk("Bluetooth OTS client sample running\n");
665 
666 	start_scan();
667 	return 0;
668 }
669