1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2019 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/kernel.h>
10 #include <stddef.h>
11 #include <zephyr/ztest.h>
12
13 #include <zephyr/bluetooth/buf.h>
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/gatt.h>
16
17 /* Custom Service Variables */
18 static struct bt_uuid_128 test_uuid = BT_UUID_INIT_128(
19 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
20 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
21 static struct bt_uuid_128 test_chrc_uuid = BT_UUID_INIT_128(
22 0xf2, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
23 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
24
25 static uint8_t test_value[] = { 'T', 'e', 's', 't', '\0' };
26
27 static struct bt_uuid_128 test1_uuid = BT_UUID_INIT_128(
28 0xf4, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
29 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
30
31 static const struct bt_uuid_128 test1_nfy_uuid = BT_UUID_INIT_128(
32 0xf5, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
33 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
34
35 static uint8_t nfy_enabled;
36
test1_ccc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)37 static void test1_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
38 {
39 nfy_enabled = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0;
40 }
41
read_test(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)42 static ssize_t read_test(struct bt_conn *conn, const struct bt_gatt_attr *attr,
43 void *buf, uint16_t len, uint16_t offset)
44 {
45 const char *value = attr->user_data;
46
47 return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
48 strlen(value));
49 }
50
write_test(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)51 static ssize_t write_test(struct bt_conn *conn, const struct bt_gatt_attr *attr,
52 const void *buf, uint16_t len, uint16_t offset,
53 uint8_t flags)
54 {
55 uint8_t *value = attr->user_data;
56
57 if (offset + len > sizeof(test_value)) {
58 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
59 }
60
61 memcpy(value + offset, buf, len);
62
63 return len;
64 }
65
66 static struct bt_gatt_attr test_attrs[] = {
67 /* Vendor Primary Service Declaration */
68 BT_GATT_PRIMARY_SERVICE(&test_uuid),
69
70 BT_GATT_CHARACTERISTIC(&test_chrc_uuid.uuid,
71 BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
72 BT_GATT_PERM_READ_AUTHEN |
73 BT_GATT_PERM_WRITE_AUTHEN,
74 read_test, write_test, test_value),
75 };
76
77 static struct bt_gatt_service test_svc = BT_GATT_SERVICE(test_attrs);
78
79 static struct bt_gatt_attr test1_attrs[] = {
80 /* Vendor Primary Service Declaration */
81 BT_GATT_PRIMARY_SERVICE(&test1_uuid),
82
83 BT_GATT_CHARACTERISTIC(&test1_nfy_uuid.uuid,
84 BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE,
85 NULL, NULL, &nfy_enabled),
86 BT_GATT_CCC(test1_ccc_cfg_changed,
87 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
88 };
89
90 static struct bt_gatt_service test1_svc = BT_GATT_SERVICE(test1_attrs);
91
92 ZTEST_SUITE(test_gatt, NULL, NULL, NULL, NULL, NULL);
93
ZTEST(test_gatt,test_gatt_register)94 ZTEST(test_gatt, test_gatt_register)
95 {
96 /* Ensure our test services are not already registered */
97 bt_gatt_service_unregister(&test_svc);
98 bt_gatt_service_unregister(&test1_svc);
99
100 /* Attempt to register services */
101 zassert_false(bt_gatt_service_register(&test_svc),
102 "Test service registration failed");
103 zassert_false(bt_gatt_service_register(&test1_svc),
104 "Test service1 registration failed");
105
106 /* Attempt to register already registered services */
107 zassert_true(bt_gatt_service_register(&test_svc),
108 "Test service duplicate succeeded");
109 zassert_true(bt_gatt_service_register(&test1_svc),
110 "Test service1 duplicate succeeded");
111 }
112
ZTEST(test_gatt,test_gatt_unregister)113 ZTEST(test_gatt, test_gatt_unregister)
114 {
115 /* Attempt to unregister last */
116 zassert_false(bt_gatt_service_unregister(&test1_svc),
117 "Test service1 unregister failed");
118 zassert_false(bt_gatt_service_register(&test1_svc),
119 "Test service1 re-registration failed");
120
121 /* Attempt to unregister first/middle */
122 zassert_false(bt_gatt_service_unregister(&test_svc),
123 "Test service unregister failed");
124 zassert_false(bt_gatt_service_register(&test_svc),
125 "Test service re-registration failed");
126
127 /* Attempt to unregister all reverse order */
128 zassert_false(bt_gatt_service_unregister(&test1_svc),
129 "Test service1 unregister failed");
130 zassert_false(bt_gatt_service_unregister(&test_svc),
131 "Test service unregister failed");
132
133 zassert_false(bt_gatt_service_register(&test_svc),
134 "Test service registration failed");
135 zassert_false(bt_gatt_service_register(&test1_svc),
136 "Test service1 registration failed");
137
138 /* Attempt to unregister all same order */
139 zassert_false(bt_gatt_service_unregister(&test_svc),
140 "Test service1 unregister failed");
141 zassert_false(bt_gatt_service_unregister(&test1_svc),
142 "Test service unregister failed");
143 }
144
count_attr(const struct bt_gatt_attr * attr,uint16_t handle,void * user_data)145 static uint8_t count_attr(const struct bt_gatt_attr *attr, uint16_t handle,
146 void *user_data)
147 {
148 uint16_t *count = user_data;
149
150 (*count)++;
151
152 return BT_GATT_ITER_CONTINUE;
153 }
154
find_attr(const struct bt_gatt_attr * attr,uint16_t handle,void * user_data)155 static uint8_t find_attr(const struct bt_gatt_attr *attr, uint16_t handle,
156 void *user_data)
157 {
158 const struct bt_gatt_attr **tmp = user_data;
159
160 *tmp = attr;
161
162 return BT_GATT_ITER_CONTINUE;
163 }
164
ZTEST(test_gatt,test_gatt_foreach)165 ZTEST(test_gatt, test_gatt_foreach)
166 {
167 const struct bt_gatt_attr *attr;
168 uint16_t num = 0;
169
170 /* Attempt to register services */
171 zassert_false(bt_gatt_service_register(&test_svc),
172 "Test service registration failed");
173 zassert_false(bt_gatt_service_register(&test1_svc),
174 "Test service1 registration failed");
175
176 /* Iterate attributes */
177 bt_gatt_foreach_attr(test_attrs[0].handle, 0xffff, count_attr, &num);
178 zassert_equal(num, 7, "Number of attributes don't match");
179
180 /* Iterate 1 attribute */
181 num = 0;
182 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, NULL, NULL, 1,
183 count_attr, &num);
184 zassert_equal(num, 1, "Number of attributes don't match");
185
186 /* Find attribute by UUID */
187 attr = NULL;
188 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
189 &test_chrc_uuid.uuid, NULL, 0, find_attr,
190 &attr);
191 zassert_not_null(attr, "Attribute don't match");
192 if (attr) {
193 zassert_equal(attr->uuid, &test_chrc_uuid.uuid,
194 "Attribute UUID don't match");
195 }
196
197 /* Find attribute by DATA */
198 attr = NULL;
199 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, NULL,
200 test_value, 0, find_attr, &attr);
201 zassert_not_null(attr, "Attribute don't match");
202 if (attr) {
203 zassert_equal(attr->user_data, test_value,
204 "Attribute value don't match");
205 }
206
207 /* Find all characteristics */
208 num = 0;
209 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
210 BT_UUID_GATT_CHRC, NULL, 0, count_attr, &num);
211 zassert_equal(num, 2, "Number of attributes don't match");
212
213 /* Find 1 characteristic */
214 attr = NULL;
215 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
216 BT_UUID_GATT_CHRC, NULL, 1, find_attr, &attr);
217 zassert_not_null(attr, "Attribute don't match");
218
219 /* Find attribute by UUID and DATA */
220 attr = NULL;
221 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
222 &test1_nfy_uuid.uuid, &nfy_enabled, 1,
223 find_attr, &attr);
224 zassert_not_null(attr, "Attribute don't match");
225 if (attr) {
226 zassert_equal(attr->uuid, &test1_nfy_uuid.uuid,
227 "Attribute UUID don't match");
228 zassert_equal(attr->user_data, &nfy_enabled,
229 "Attribute value don't match");
230 }
231 }
232
ZTEST(test_gatt,test_gatt_read)233 ZTEST(test_gatt, test_gatt_read)
234 {
235 const struct bt_gatt_attr *attr;
236 uint8_t buf[256];
237 ssize_t ret;
238
239 /* Find attribute by UUID */
240 attr = NULL;
241 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
242 &test_chrc_uuid.uuid, NULL, 0, find_attr,
243 &attr);
244 zassert_not_null(attr, "Attribute don't match");
245 zassert_equal(attr->uuid, &test_chrc_uuid.uuid,
246 "Attribute UUID don't match");
247
248 ret = attr->read(NULL, attr, (void *)buf, sizeof(buf), 0);
249 zassert_equal(ret, strlen(test_value),
250 "Attribute read unexpected return");
251 zassert_mem_equal(buf, test_value, ret,
252 "Attribute read value don't match");
253 }
254
ZTEST(test_gatt,test_gatt_write)255 ZTEST(test_gatt, test_gatt_write)
256 {
257 const struct bt_gatt_attr *attr;
258 char *value = " ";
259 ssize_t ret;
260
261 /* Need our service to be registered */
262 zassert_false(bt_gatt_service_register(&test_svc),
263 "Test service registration failed");
264
265 /* Find attribute by UUID */
266 attr = NULL;
267 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
268 &test_chrc_uuid.uuid, NULL, 0, find_attr,
269 &attr);
270 zassert_not_null(attr, "Attribute don't match");
271
272 ret = attr->write(NULL, attr, (void *)value, strlen(value), 0, 0);
273 zassert_equal(ret, strlen(value), "Attribute write unexpected return");
274 zassert_mem_equal(value, test_value, ret,
275 "Attribute write value don't match");
276 }
277