blob: 046ff15aef3bfe41b51f3e87e224faea5944fa84 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <string.h>
#include <errno.h>
#include "testutil/testutil.h"
#include "nimble/ble.h"
#include "host/ble_uuid.h"
#include "host/ble_hs_test.h"
#include "ble_hs_test_util.h"
#define BLE_GATTS_REG_TEST_MAX_ENTRIES 256
struct ble_gatts_reg_test_entry {
uint8_t op;
ble_uuid_any_t uuid;
uint16_t handle;
uint16_t val_handle; /* If a characteristic. */
const struct ble_gatt_svc_def *svc;
const struct ble_gatt_chr_def *chr;
const struct ble_gatt_dsc_def *dsc;
};
static struct ble_gatts_reg_test_entry
ble_gatts_reg_test_entries[BLE_GATTS_REG_TEST_MAX_ENTRIES];
static int ble_gatts_reg_test_num_entries;
static void
ble_gatts_reg_test_init(void)
{
ble_hs_test_util_init();
ble_gatts_reg_test_num_entries = 0;
}
static void
ble_gatts_reg_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
struct ble_gatts_reg_test_entry *entry;
TEST_ASSERT_FATAL(ble_gatts_reg_test_num_entries <
BLE_GATTS_REG_TEST_MAX_ENTRIES);
entry = ble_gatts_reg_test_entries + ble_gatts_reg_test_num_entries++;
memset(entry, 0, sizeof *entry);
entry->op = ctxt->op;
switch (ctxt->op) {
case BLE_GATT_REGISTER_OP_SVC:
ble_uuid_to_any(ctxt->svc.svc_def->uuid, &entry->uuid);
entry->handle = ctxt->svc.handle;
entry->svc = ctxt->svc.svc_def;
break;
case BLE_GATT_REGISTER_OP_CHR:
ble_uuid_to_any(ctxt->chr.chr_def->uuid, &entry->uuid);
entry->handle = ctxt->chr.def_handle;
entry->val_handle = ctxt->chr.val_handle;
entry->svc = ctxt->chr.svc_def;
entry->chr = ctxt->chr.chr_def;
break;
case BLE_GATT_REGISTER_OP_DSC:
ble_uuid_to_any(ctxt->dsc.dsc_def->uuid, &entry->uuid);
entry->handle = ctxt->dsc.handle;
entry->svc = ctxt->dsc.svc_def;
entry->chr = ctxt->dsc.chr_def;
entry->dsc = ctxt->dsc.dsc_def;
break;
default:
TEST_ASSERT(0);
break;
}
}
static void
ble_gatts_reg_test_misc_lookup_good(struct ble_gatts_reg_test_entry *entry)
{
uint16_t chr_def_handle;
uint16_t chr_val_handle;
uint16_t svc_handle;
uint16_t dsc_handle;
int rc;
switch (entry->op) {
case BLE_GATT_REGISTER_OP_SVC:
rc = ble_gatts_find_svc(&entry->uuid.u, &svc_handle);
TEST_ASSERT_FATAL(rc == 0);
TEST_ASSERT(svc_handle == entry->handle);
break;
case BLE_GATT_REGISTER_OP_CHR:
rc = ble_gatts_find_chr(entry->svc->uuid, entry->chr->uuid,
&chr_def_handle, &chr_val_handle);
TEST_ASSERT_FATAL(rc == 0);
TEST_ASSERT(chr_def_handle == entry->handle);
TEST_ASSERT(chr_val_handle == entry->val_handle);
break;
case BLE_GATT_REGISTER_OP_DSC:
rc = ble_gatts_find_dsc(entry->svc->uuid, entry->chr->uuid,
entry->dsc->uuid, &dsc_handle);
break;
default:
TEST_ASSERT(0);
break;
}
}
static void
ble_gatts_reg_test_misc_lookup_bad(struct ble_gatts_reg_test_entry *entry)
{
struct ble_gatts_reg_test_entry *cur;
ble_uuid_any_t wrong_uuid;
int rc;
int i;
switch (entry->op) {
case BLE_GATT_REGISTER_OP_SVC:
/* Wrong service UUID. */
ble_uuid_to_any(entry->svc->uuid, &wrong_uuid);
wrong_uuid.u16.value++;
rc = ble_gatts_find_svc(&wrong_uuid.u, NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
break;
case BLE_GATT_REGISTER_OP_CHR:
/* Correct service UUID, wrong characteristic UUID. */
ble_uuid_to_any(entry->chr->uuid, &wrong_uuid);
wrong_uuid.u16.value++;
rc = ble_gatts_find_chr(entry->svc->uuid, &wrong_uuid.u, NULL, NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
/* Incorrect service UUID, correct characteristic UUID. */
ble_uuid_to_any(entry->svc->uuid, &wrong_uuid);
wrong_uuid.u16.value++;
rc = ble_gatts_find_chr(&wrong_uuid.u, entry->chr->uuid, NULL, NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
/* Existing (but wrong) service, correct characteristic UUID. */
for (i = 0; i < ble_gatts_reg_test_num_entries; i++) {
cur = ble_gatts_reg_test_entries + i;
switch (cur->op) {
case BLE_GATT_REGISTER_OP_SVC:
if (cur->svc != entry->svc) {
rc = ble_gatts_find_chr(cur->svc->uuid,
entry->chr->uuid,
NULL, NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
}
break;
case BLE_GATT_REGISTER_OP_CHR:
/* Characteristic that isn't in this service. */
if (cur->svc != entry->svc) {
rc = ble_gatts_find_chr(entry->svc->uuid,
cur->chr->uuid,
NULL, NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
}
break;
case BLE_GATT_REGISTER_OP_DSC:
/* Use descriptor UUID instead of characteristic UUID. */
rc = ble_gatts_find_chr(entry->svc->uuid,
cur->dsc->uuid,
NULL, NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
break;
default:
TEST_ASSERT(0);
break;
}
}
break;
case BLE_GATT_REGISTER_OP_DSC:
/* Correct svc/chr UUID, wrong dsc UUID. */
ble_uuid_to_any(entry->dsc->uuid, &wrong_uuid);
wrong_uuid.u128.value[15]++;
rc = ble_gatts_find_dsc(entry->svc->uuid, entry->chr->uuid,
&wrong_uuid.u, NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
/* Incorrect svc UUID, correct chr/dsc UUID. */
ble_uuid_to_any(entry->svc->uuid, &wrong_uuid);
wrong_uuid.u128.value[15]++;
rc = ble_gatts_find_dsc(&wrong_uuid.u, entry->chr->uuid,
entry->dsc->uuid, NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
for (i = 0; i < ble_gatts_reg_test_num_entries; i++) {
cur = ble_gatts_reg_test_entries + i;
switch (cur->op) {
case BLE_GATT_REGISTER_OP_SVC:
/* Existing (but wrong) svc, correct chr/dsc UUID. */
if (cur->svc != entry->svc) {
rc = ble_gatts_find_dsc(cur->svc->uuid,
entry->chr->uuid,
entry->dsc->uuid,
NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
}
break;
case BLE_GATT_REGISTER_OP_CHR:
/* Existing (but wrong) svc/chr, correct dsc UUID. */
if (cur->chr != entry->chr) {
rc = ble_gatts_find_dsc(cur->svc->uuid,
cur->chr->uuid,
entry->dsc->uuid,
NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
}
break;
case BLE_GATT_REGISTER_OP_DSC:
/* Descriptor that isn't in this characteristic. */
if (cur->chr != entry->chr) {
rc = ble_gatts_find_dsc(cur->svc->uuid,
cur->chr->uuid,
entry->dsc->uuid,
NULL);
TEST_ASSERT(rc == BLE_HS_ENOENT);
}
break;
default:
TEST_ASSERT(0);
break;
}
}
break;
default:
TEST_ASSERT(0);
break;
}
}
static void
ble_gatts_reg_test_misc_verify_entry(uint8_t op, const ble_uuid_t *uuid)
{
struct ble_gatts_reg_test_entry *entry;
int i;
for (i = 0; i < ble_gatts_reg_test_num_entries; i++) {
entry = ble_gatts_reg_test_entries + i;
if (entry->op == op && ble_uuid_cmp(&entry->uuid.u, uuid) == 0) {
break;
}
}
TEST_ASSERT_FATAL(entry != NULL);
/* Verify that characteristic value handle was properly assigned at
* registration.
*/
if (op == BLE_GATT_REGISTER_OP_CHR) {
TEST_ASSERT(*entry->chr->val_handle == entry->val_handle);
}
/* Verify that the entry can be looked up. */
ble_gatts_reg_test_misc_lookup_good(entry);
/* Verify that "barely incorrect" UUID information doesn't retrieve any
* handles.
*/
ble_gatts_reg_test_misc_lookup_bad(entry);
}
static int
ble_gatts_reg_test_misc_dummy_access(uint16_t conn_handle,
uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt,
void *arg)
{
return 0;
}
TEST_CASE(ble_gatts_reg_test_svc_return)
{
int rc;
/*** Missing UUID. */
ble_gatts_reg_test_init();
struct ble_gatt_svc_def svcs_no_uuid[] = { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
}, {
0
} };
rc = ble_gatts_register_svcs(svcs_no_uuid, NULL, NULL);
TEST_ASSERT(rc == BLE_HS_EINVAL);
/*** Circular dependency. */
ble_gatts_reg_test_init();
struct ble_gatt_svc_def svcs_circ[] = { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.includes = (const struct ble_gatt_svc_def*[]) { svcs_circ + 1, NULL },
}, {
.type = BLE_GATT_SVC_TYPE_SECONDARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.includes = (const struct ble_gatt_svc_def*[]) { svcs_circ + 0, NULL },
}, {
0
} };
rc = ble_gatts_register_svcs(svcs_circ, NULL, NULL);
TEST_ASSERT(rc == BLE_HS_EINVAL);
/*** Success. */
ble_gatts_reg_test_init();
struct ble_gatt_svc_def svcs_good[] = { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.includes = (const struct ble_gatt_svc_def*[]) { svcs_good + 1, NULL },
}, {
.type = BLE_GATT_SVC_TYPE_SECONDARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
}, {
0
} };
rc = ble_gatts_register_svcs(svcs_good, NULL, NULL);
TEST_ASSERT(rc == 0);
}
TEST_CASE(ble_gatts_reg_test_chr_return)
{
int rc;
/*** Missing callback. */
ble_gatts_reg_test_init();
struct ble_gatt_svc_def svcs_no_chr_cb[] = { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x1111),
.flags = BLE_GATT_CHR_F_READ,
}, {
0
} },
}, {
0
} };
rc = ble_gatts_register_svcs(svcs_no_chr_cb, NULL, NULL);
TEST_ASSERT(rc == BLE_HS_EINVAL);
/*** Success. */
ble_gatts_reg_test_init();
struct ble_gatt_svc_def svcs_good[] = { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x1111),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
}, {
0
} },
}, {
0
} };
rc = ble_gatts_register_svcs(svcs_good, NULL, NULL);
TEST_ASSERT(rc == 0);
}
TEST_CASE(ble_gatts_reg_test_dsc_return)
{
int rc;
/*** Missing callback. */
ble_gatts_reg_test_init();
struct ble_gatt_svc_def svcs_no_dsc_cb[] = { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x1111),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
.descriptors = (struct ble_gatt_dsc_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x8888),
.att_flags = 5,
}, {
0
} },
}, {
0
} },
}, {
0
} };
rc = ble_gatts_register_svcs(svcs_no_dsc_cb, NULL, NULL);
TEST_ASSERT(rc == BLE_HS_EINVAL);
/*** Success. */
ble_gatts_reg_test_init();
struct ble_gatt_svc_def svcs_good[] = { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x1111),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
.descriptors = (struct ble_gatt_dsc_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x8888),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.att_flags = 5,
}, {
0
} },
}, {
0
} },
}, {
0
} };
rc = ble_gatts_register_svcs(svcs_good, NULL, NULL);
TEST_ASSERT(rc == 0);
}
static void
ble_gatts_reg_test_misc_svcs(struct ble_gatt_svc_def *svcs)
{
const struct ble_gatt_svc_def *svc;
const struct ble_gatt_chr_def *chr;
const struct ble_gatt_dsc_def *dsc;
int rc;
ble_gatts_reg_test_init();
/* Register all the attributes. */
rc = ble_gatts_register_svcs(svcs, ble_gatts_reg_test_misc_reg_cb,
NULL);
TEST_ASSERT_FATAL(rc == 0);
/* Verify that the appropriate callbacks were executed. */
for (svc = svcs; svc->type != BLE_GATT_SVC_TYPE_END; svc++) {
ble_gatts_reg_test_misc_verify_entry(BLE_GATT_REGISTER_OP_SVC,
svc->uuid);
if (svc->characteristics != NULL) {
for (chr = svc->characteristics; chr->uuid != NULL; chr++) {
ble_gatts_reg_test_misc_verify_entry(BLE_GATT_REGISTER_OP_CHR,
chr->uuid);
if (chr->descriptors != NULL) {
for (dsc = chr->descriptors; dsc->uuid != NULL; dsc++) {
ble_gatts_reg_test_misc_verify_entry(
BLE_GATT_REGISTER_OP_DSC, dsc->uuid);
}
}
}
}
}
}
TEST_CASE(ble_gatts_reg_test_svc_cb)
{
/*** 1 primary. */
ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
}, {
0
} });
/*** 3 primary. */
ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
}, {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x2234),
}, {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x3234),
}, {
0
} });
/*** 1 primary, 1 secondary. */
ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
}, {
.type = BLE_GATT_SVC_TYPE_SECONDARY,
.uuid = BLE_UUID16_DECLARE(0x2222),
}, {
0
} });
/*** 1 primary, 1 secondary, 1 include. */
struct ble_gatt_svc_def svcs[] = {
[0] = {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.includes = (const struct ble_gatt_svc_def*[]) { svcs + 1, NULL, },
},
[1] = {
.type = BLE_GATT_SVC_TYPE_SECONDARY,
.uuid = BLE_UUID16_DECLARE(0x2222),
}, {
0
}
};
ble_gatts_reg_test_misc_svcs(svcs);
}
TEST_CASE(ble_gatts_reg_test_chr_cb)
{
uint16_t val_handles[16];
/*** 1 characteristic. */
ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x1111),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = val_handles + 0,
}, {
0
} },
}, {
0
} });
/*** 3 characteristics. */
ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x1111),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = val_handles + 0,
}, {
.uuid = BLE_UUID16_DECLARE(0x2222),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_WRITE,
.val_handle = val_handles + 1,
}, {
0
} },
}, {
.type = BLE_GATT_SVC_TYPE_SECONDARY,
.uuid = BLE_UUID16_DECLARE(0x5678),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x3333),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = val_handles + 2,
}, {
0
} },
}, {
0
} });
}
TEST_CASE(ble_gatts_reg_test_dsc_cb)
{
uint16_t val_handles[16];
/*** 1 descriptor. */
ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x1111),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = val_handles + 0,
.descriptors = (struct ble_gatt_dsc_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x111a),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
0
} },
}, {
0
} },
}, {
0
} });
/*** 5+ descriptors. */
ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x1234),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x1111),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = val_handles + 0,
.descriptors = (struct ble_gatt_dsc_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x111a),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
0
} },
}, {
.uuid = BLE_UUID16_DECLARE(0x2222),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_WRITE,
.val_handle = val_handles + 1,
}, {
0
} },
}, {
.type = BLE_GATT_SVC_TYPE_SECONDARY,
.uuid = BLE_UUID16_DECLARE(0x5678),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x3333),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = val_handles + 2,
.descriptors = (struct ble_gatt_dsc_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x333a),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
.uuid = BLE_UUID16_DECLARE(0x333b),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
.uuid = BLE_UUID16_DECLARE(0x333c),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
.uuid = BLE_UUID16_DECLARE(0x333e),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
0
} },
}, {
.uuid = BLE_UUID16_DECLARE(0x4444),
.access_cb = ble_gatts_reg_test_misc_dummy_access,
.flags = BLE_GATT_CHR_F_READ,
.val_handle = val_handles + 3,
.descriptors = (struct ble_gatt_dsc_def[]) { {
.uuid = BLE_UUID16_DECLARE(0x444a),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
.uuid = BLE_UUID16_DECLARE(0x444b),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
.uuid = BLE_UUID16_DECLARE(0x444c),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
.uuid = BLE_UUID16_DECLARE(0x444e),
.att_flags = 5,
.access_cb = ble_gatts_reg_test_misc_dummy_access,
}, {
0
} },
}, {
0
} },
}, {
0
} });
}
TEST_SUITE(ble_gatts_reg_suite)
{
tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
ble_gatts_reg_test_svc_return();
ble_gatts_reg_test_chr_return();
ble_gatts_reg_test_dsc_return();
ble_gatts_reg_test_svc_cb();
ble_gatts_reg_test_chr_cb();
ble_gatts_reg_test_dsc_cb();
}
int
ble_gatts_reg_test_all(void)
{
ble_gatts_reg_suite();
return tu_any_failed;
}