1 /*
2  * Copyright (c) 2022 Michal Morsisko
3  * Copyright (c) 2015-2016 Intel Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/types.h>
9 #include <stddef.h>
10 #include <zephyr/sys/printk.h>
11 #include <zephyr/sys/reboot.h>
12 #include <zephyr/settings/settings.h>
13 #include <zephyr/bluetooth/bluetooth.h>
14 #include <zephyr/bluetooth/conn.h>
15 #include <zephyr/bluetooth/uuid.h>
16 #include <zephyr/bluetooth/gatt.h>
17 #include <zephyr/bluetooth/hci.h>
18 
19 /* Custom Service Variables */
20 #define BT_UUID_CUSTOM_SERVICE_VAL \
21 	BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)
22 
23 static const struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128(
24 	BT_UUID_CUSTOM_SERVICE_VAL);
25 
26 static const struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128(
27 	BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1));
28 
29 static const struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128(
30 	BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2));
31 
32 static int signed_value;
33 static struct bt_le_adv_param adv_param;
34 static int bond_count;
35 
read_signed(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)36 static ssize_t read_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr,
37 			   void *buf, uint16_t len, uint16_t offset)
38 {
39 	int *value = &signed_value;
40 
41 	return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
42 				 sizeof(signed_value));
43 }
44 
write_signed(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)45 static ssize_t write_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr,
46 			    const void *buf, uint16_t len, uint16_t offset,
47 			    uint8_t flags)
48 {
49 	int *value = &signed_value;
50 
51 	if (offset + len > sizeof(signed_value)) {
52 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
53 	}
54 
55 	memcpy(value + offset, buf, len);
56 
57 	return len;
58 }
59 
60 /* Vendor Primary Service Declaration */
61 BT_GATT_SERVICE_DEFINE(primary_service,
62 	BT_GATT_PRIMARY_SERVICE(&primary_service_uuid),
63 	BT_GATT_CHARACTERISTIC(&read_characteristic_uuid.uuid,
64 			       BT_GATT_CHRC_READ,
65 			       BT_GATT_PERM_READ,
66 			       read_signed, NULL, NULL),
67 	BT_GATT_CHARACTERISTIC(&write_characteristic_uuid.uuid,
68 			       BT_GATT_CHRC_WRITE,
69 			       BT_GATT_PERM_WRITE_ENCRYPT,
70 			       NULL, write_signed, NULL),
71 );
72 
73 static const struct bt_data ad[] = {
74 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR))
75 };
76 
77 static const struct bt_data sd[] = {
78 	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL),
79 	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
80 };
81 
connected(struct bt_conn * conn,uint8_t err)82 static void connected(struct bt_conn *conn, uint8_t err)
83 {
84 	if (err) {
85 		printk("Connection failed, err 0x%02x %s\n", err, bt_hci_err_to_str(err));
86 	} else {
87 		printk("Connected\n");
88 	}
89 }
90 
disconnected(struct bt_conn * conn,uint8_t reason)91 static void disconnected(struct bt_conn *conn, uint8_t reason)
92 {
93 	printk("Disconnected, reason 0x%02x %s\n", reason, bt_hci_err_to_str(reason));
94 }
95 
96 BT_CONN_CB_DEFINE(conn_callbacks) = {
97 	.connected = connected,
98 	.disconnected = disconnected
99 };
100 
add_bonded_addr_to_filter_list(const struct bt_bond_info * info,void * data)101 static void add_bonded_addr_to_filter_list(const struct bt_bond_info *info, void *data)
102 {
103 	char addr_str[BT_ADDR_LE_STR_LEN];
104 
105 	bt_le_filter_accept_list_add(&info->addr);
106 	bt_addr_le_to_str(&info->addr, addr_str, sizeof(addr_str));
107 	printk("Added %s to advertising accept filter list\n", addr_str);
108 	bond_count++;
109 }
110 
bt_ready(void)111 static void bt_ready(void)
112 {
113 	int err;
114 
115 	printk("Bluetooth initialized\n");
116 
117 	if (IS_ENABLED(CONFIG_SETTINGS)) {
118 		settings_load();
119 	}
120 
121 	bond_count = 0;
122 	bt_foreach_bond(BT_ID_DEFAULT, add_bonded_addr_to_filter_list, NULL);
123 
124 	adv_param = *BT_LE_ADV_CONN_FAST_1;
125 
126 	/* If we have got at least one bond, activate the filter */
127 	if (bond_count) {
128 		/* BT_LE_ADV_OPT_FILTER_CONN is required to activate accept filter list,
129 		 * BT_LE_ADV_OPT_FILTER_SCAN_REQ will prevent sending scan response data to
130 		 * devices, that are not on the accept filter list
131 		 */
132 		adv_param.options |= BT_LE_ADV_OPT_FILTER_CONN | BT_LE_ADV_OPT_FILTER_SCAN_REQ;
133 	}
134 
135 	err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
136 
137 	if (err) {
138 		printk("Advertising failed to start (err %d)\n", err);
139 	} else {
140 		printk("Advertising successfully started\n");
141 	}
142 }
143 
pairing_complete(struct bt_conn * conn,bool bonded)144 void pairing_complete(struct bt_conn *conn, bool bonded)
145 {
146 	printk("Pairing completed. Rebooting in 5 seconds...\n");
147 
148 	k_sleep(K_SECONDS(5));
149 	sys_reboot(SYS_REBOOT_WARM);
150 }
151 
152 static struct bt_conn_auth_info_cb bt_conn_auth_info = {
153 	.pairing_complete = pairing_complete
154 };
155 
main(void)156 int main(void)
157 {
158 	int err;
159 
160 	err = bt_enable(NULL);
161 	if (err) {
162 		printk("Bluetooth init failed (err %d)\n", err);
163 		return 0;
164 	}
165 
166 	bt_ready();
167 	bt_conn_auth_info_cb_register(&bt_conn_auth_info);
168 
169 	while (1) {
170 		k_sleep(K_FOREVER);
171 	}
172 	return 0;
173 }
174