| /* main.c - Application main entry point */ |
| |
| /* |
| * Copyright (c) 2019 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/kernel.h> |
| #include <stddef.h> |
| #include <zephyr/ztest.h> |
| |
| #include <zephyr/bluetooth/buf.h> |
| #include <zephyr/bluetooth/bluetooth.h> |
| #include <zephyr/bluetooth/gatt.h> |
| |
| /* Custom Service Variables */ |
| static struct bt_uuid_128 test_uuid = BT_UUID_INIT_128( |
| 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, |
| 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); |
| static struct bt_uuid_128 test_chrc_uuid = BT_UUID_INIT_128( |
| 0xf2, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, |
| 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); |
| |
| static uint8_t test_value[] = { 'T', 'e', 's', 't', '\0' }; |
| |
| static struct bt_uuid_128 test1_uuid = BT_UUID_INIT_128( |
| 0xf4, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, |
| 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); |
| |
| static const struct bt_uuid_128 test1_nfy_uuid = BT_UUID_INIT_128( |
| 0xf5, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, |
| 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); |
| |
| static uint8_t nfy_enabled; |
| |
| static void test1_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) |
| { |
| nfy_enabled = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0; |
| } |
| |
| static ssize_t read_test(struct bt_conn *conn, const struct bt_gatt_attr *attr, |
| void *buf, uint16_t len, uint16_t offset) |
| { |
| const char *value = attr->user_data; |
| |
| return bt_gatt_attr_read(conn, attr, buf, len, offset, value, |
| strlen(value)); |
| } |
| |
| static ssize_t write_test(struct bt_conn *conn, const struct bt_gatt_attr *attr, |
| const void *buf, uint16_t len, uint16_t offset, |
| uint8_t flags) |
| { |
| uint8_t *value = attr->user_data; |
| |
| if (offset + len > sizeof(test_value)) { |
| return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); |
| } |
| |
| memcpy(value + offset, buf, len); |
| |
| return len; |
| } |
| |
| static struct bt_gatt_attr test_attrs[] = { |
| /* Vendor Primary Service Declaration */ |
| BT_GATT_PRIMARY_SERVICE(&test_uuid), |
| |
| BT_GATT_CHARACTERISTIC(&test_chrc_uuid.uuid, |
| BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, |
| BT_GATT_PERM_READ_AUTHEN | |
| BT_GATT_PERM_WRITE_AUTHEN, |
| read_test, write_test, test_value), |
| }; |
| |
| static struct bt_gatt_service test_svc = BT_GATT_SERVICE(test_attrs); |
| |
| static struct bt_gatt_attr test1_attrs[] = { |
| /* Vendor Primary Service Declaration */ |
| BT_GATT_PRIMARY_SERVICE(&test1_uuid), |
| |
| BT_GATT_CHARACTERISTIC(&test1_nfy_uuid.uuid, |
| BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE, |
| NULL, NULL, &nfy_enabled), |
| BT_GATT_CCC(test1_ccc_cfg_changed, |
| BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), |
| }; |
| |
| static struct bt_gatt_service test1_svc = BT_GATT_SERVICE(test1_attrs); |
| |
| ZTEST_SUITE(test_gatt, NULL, NULL, NULL, NULL, NULL); |
| |
| ZTEST(test_gatt, test_gatt_register) |
| { |
| /* Ensure our test services are not already registered */ |
| bt_gatt_service_unregister(&test_svc); |
| bt_gatt_service_unregister(&test1_svc); |
| |
| /* Attempt to register services */ |
| zassert_false(bt_gatt_service_register(&test_svc), |
| "Test service registration failed"); |
| zassert_false(bt_gatt_service_register(&test1_svc), |
| "Test service1 registration failed"); |
| |
| /* Attempt to register already registered services */ |
| zassert_true(bt_gatt_service_register(&test_svc), |
| "Test service duplicate succeeded"); |
| zassert_true(bt_gatt_service_register(&test1_svc), |
| "Test service1 duplicate succeeded"); |
| } |
| |
| ZTEST(test_gatt, test_gatt_unregister) |
| { |
| /* Attempt to unregister last */ |
| zassert_false(bt_gatt_service_unregister(&test1_svc), |
| "Test service1 unregister failed"); |
| zassert_false(bt_gatt_service_register(&test1_svc), |
| "Test service1 re-registration failed"); |
| |
| /* Attempt to unregister first/middle */ |
| zassert_false(bt_gatt_service_unregister(&test_svc), |
| "Test service unregister failed"); |
| zassert_false(bt_gatt_service_register(&test_svc), |
| "Test service re-registration failed"); |
| |
| /* Attempt to unregister all reverse order */ |
| zassert_false(bt_gatt_service_unregister(&test1_svc), |
| "Test service1 unregister failed"); |
| zassert_false(bt_gatt_service_unregister(&test_svc), |
| "Test service unregister failed"); |
| |
| zassert_false(bt_gatt_service_register(&test_svc), |
| "Test service registration failed"); |
| zassert_false(bt_gatt_service_register(&test1_svc), |
| "Test service1 registration failed"); |
| |
| /* Attempt to unregister all same order */ |
| zassert_false(bt_gatt_service_unregister(&test_svc), |
| "Test service1 unregister failed"); |
| zassert_false(bt_gatt_service_unregister(&test1_svc), |
| "Test service unregister failed"); |
| } |
| |
| static uint8_t count_attr(const struct bt_gatt_attr *attr, uint16_t handle, |
| void *user_data) |
| { |
| uint16_t *count = user_data; |
| |
| (*count)++; |
| |
| return BT_GATT_ITER_CONTINUE; |
| } |
| |
| static uint8_t find_attr(const struct bt_gatt_attr *attr, uint16_t handle, |
| void *user_data) |
| { |
| const struct bt_gatt_attr **tmp = user_data; |
| |
| *tmp = attr; |
| |
| return BT_GATT_ITER_CONTINUE; |
| } |
| |
| ZTEST(test_gatt, test_gatt_foreach) |
| { |
| const struct bt_gatt_attr *attr; |
| uint16_t num = 0; |
| |
| /* Attempt to register services */ |
| zassert_false(bt_gatt_service_register(&test_svc), |
| "Test service registration failed"); |
| zassert_false(bt_gatt_service_register(&test1_svc), |
| "Test service1 registration failed"); |
| |
| /* Iterate attributes */ |
| bt_gatt_foreach_attr(test_attrs[0].handle, 0xffff, count_attr, &num); |
| zassert_equal(num, 7, "Number of attributes don't match"); |
| |
| /* Iterate 1 attribute */ |
| num = 0; |
| bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, NULL, NULL, 1, |
| count_attr, &num); |
| zassert_equal(num, 1, "Number of attributes don't match"); |
| |
| /* Find attribute by UUID */ |
| attr = NULL; |
| bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, |
| &test_chrc_uuid.uuid, NULL, 0, find_attr, |
| &attr); |
| zassert_not_null(attr, "Attribute don't match"); |
| if (attr) { |
| zassert_equal(attr->uuid, &test_chrc_uuid.uuid, |
| "Attribute UUID don't match"); |
| } |
| |
| /* Find attribute by DATA */ |
| attr = NULL; |
| bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, NULL, |
| test_value, 0, find_attr, &attr); |
| zassert_not_null(attr, "Attribute don't match"); |
| if (attr) { |
| zassert_equal(attr->user_data, test_value, |
| "Attribute value don't match"); |
| } |
| |
| /* Find all characteristics */ |
| num = 0; |
| bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, |
| BT_UUID_GATT_CHRC, NULL, 0, count_attr, &num); |
| zassert_equal(num, 2, "Number of attributes don't match"); |
| |
| /* Find 1 characteristic */ |
| attr = NULL; |
| bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, |
| BT_UUID_GATT_CHRC, NULL, 1, find_attr, &attr); |
| zassert_not_null(attr, "Attribute don't match"); |
| |
| /* Find attribute by UUID and DATA */ |
| attr = NULL; |
| bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, |
| &test1_nfy_uuid.uuid, &nfy_enabled, 1, |
| find_attr, &attr); |
| zassert_not_null(attr, "Attribute don't match"); |
| if (attr) { |
| zassert_equal(attr->uuid, &test1_nfy_uuid.uuid, |
| "Attribute UUID don't match"); |
| zassert_equal(attr->user_data, &nfy_enabled, |
| "Attribute value don't match"); |
| } |
| } |
| |
| ZTEST(test_gatt, test_gatt_read) |
| { |
| const struct bt_gatt_attr *attr; |
| uint8_t buf[256]; |
| ssize_t ret; |
| |
| /* Find attribute by UUID */ |
| attr = NULL; |
| bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, |
| &test_chrc_uuid.uuid, NULL, 0, find_attr, |
| &attr); |
| zassert_not_null(attr, "Attribute don't match"); |
| zassert_equal(attr->uuid, &test_chrc_uuid.uuid, |
| "Attribute UUID don't match"); |
| |
| ret = attr->read(NULL, attr, (void *)buf, sizeof(buf), 0); |
| zassert_equal(ret, strlen(test_value), |
| "Attribute read unexpected return"); |
| zassert_mem_equal(buf, test_value, ret, |
| "Attribute read value don't match"); |
| } |
| |
| ZTEST(test_gatt, test_gatt_write) |
| { |
| const struct bt_gatt_attr *attr; |
| char *value = " "; |
| ssize_t ret; |
| |
| /* Need our service to be registered */ |
| zassert_false(bt_gatt_service_register(&test_svc), |
| "Test service registration failed"); |
| |
| /* Find attribute by UUID */ |
| attr = NULL; |
| bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, |
| &test_chrc_uuid.uuid, NULL, 0, find_attr, |
| &attr); |
| zassert_not_null(attr, "Attribute don't match"); |
| |
| ret = attr->write(NULL, attr, (void *)value, strlen(value), 0, 0); |
| zassert_equal(ret, strlen(value), "Attribute write unexpected return"); |
| zassert_mem_equal(value, test_value, ret, |
| "Attribute write value don't match"); |
| } |