Skip to content

Commit 8e6793a

Browse files
committed
tests: gap local reimplementation
WIP Signed-off-by: Radosław Koppel <[email protected]>
1 parent 8042113 commit 8e6793a

File tree

4 files changed

+301
-0
lines changed

4 files changed

+301
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CONFIG_BT=y
2+
CONFIG_BT_DEVICE_NAME="GapSvc"
3+
CONFIG_BT_PERIPHERAL=y
4+
CONFIG_BT_CENTRAL=y
5+
CONFIG_BT_HRS=y
6+
7+
# Testing locally redefined SVC implementation
8+
CONFIG_BT_GAP_SVC_DEFAULT_IMPL=n
9+
CONFIG_BT_DEVICE_NAME_GATT_WRITABLE=y
10+
CONFIG_BT_DEVICE_APPEARANCE_GATT_WRITABLE=y
11+
# Do not care about paramsters below - simpler GAP implementation
12+
CONFIG_BT_PRIVACY=n
13+
CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=n

tests/bsim/bluetooth/gap_svc/src/main.c

Whitespace-only changes.

tests/bsim/bluetooth/gap_svc/src/test_local_gap_svc_central.c

Whitespace-only changes.
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
/** @file
2+
* @brief Test local GATT Generic Access Service - peripheral role
3+
*/
4+
/*
5+
* Copyright (c) 2025 Koppel Electronic
6+
*
7+
* SPDX-License-Identifier: Apache-2.0
8+
*/
9+
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/sys/byteorder.h>
12+
#include <zephyr/bluetooth/bluetooth.h>
13+
#include <zephyr/bluetooth/gatt.h>
14+
15+
#include "bs_types.h"
16+
#include "bs_tracing.h"
17+
#include "bstests.h"
18+
19+
BUILD_ASSERT(IS_ENABLED(CONFIG_BT_DEVICE_NAME_GATT_WRITABLE),
20+
"This test requires BT_DEVICE_NAME_GATT_WRITABLE to be enabled");
21+
BUILD_ASSERT(IS_ENABLED(CONFIG_BT_DEVICE_APPEARANCE_GATT_WRITABLE),
22+
"This test requires BT_DEVICE_APPEARANCE_GATT_WRITABLE to be enabled");
23+
BUILD_ASSERT(!IS_ENABLED(CONFIG_BT_GAP_SVC_DEFAULT_IMPL),
24+
"This test requires BT_GAP_SVC_DEFAULT_IMPL to be disabled");
25+
BUILD_ASSERT(!IS_ENABLED(CONFIG_BT_PRIVACY),
26+
"Simplified GAP implementation - BT_PRIVACY not implemented");
27+
BUILD_ASSERT(!IS_ENABLED(CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS),
28+
"Simplified GAP implementation - BT_GAP_PERIPHERAL_PREF_PARAMS not implemented");
29+
30+
/* Wait time in microseconds for the name and appearance to be changed */
31+
#define WAIT_TIME 10e6
32+
/* Name changed called in the test */
33+
bool gap_svc_name_changed;
34+
/* Appearance changed called in the test */
35+
bool gap_svc_appearance_changed;
36+
/* Test result */
37+
extern enum bst_result_t bst_result;
38+
39+
static const struct bt_data ad[] = {
40+
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
41+
BT_DATA_BYTES(BT_DATA_UUID16_ALL,
42+
BT_UUID_16_ENCODE(BT_UUID_HRS_VAL)),
43+
};
44+
45+
#define FAIL(...) \
46+
do { \
47+
bst_result = Failed; \
48+
bs_trace_error_time_line(__VA_ARGS__); \
49+
} while (0)
50+
51+
#define PASS(...) \
52+
do { \
53+
bst_result = Passed; \
54+
bs_trace_info_time(1, __VA_ARGS__); \
55+
} while (0)
56+
57+
#define LOG_INFO(...) \
58+
do { \
59+
bs_trace_info_time(1, __VA_ARGS__); \
60+
} while (0)
61+
62+
/* -----------------------------------------------------------------------------
63+
64+
* Local implementation of GAP service
65+
*/
66+
67+
static ssize_t read_name(struct bt_conn *conn, const struct bt_gatt_attr *attr,
68+
void *buf, uint16_t len, uint16_t offset)
69+
{
70+
const char *name = bt_get_name();
71+
72+
return bt_gatt_attr_read(conn, attr, buf, len, offset, name,
73+
strlen(name));
74+
}
75+
76+
static ssize_t write_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
77+
uint16_t len, uint16_t offset, uint8_t flags)
78+
{
79+
LOG_INFO("Name changed called\n");
80+
/* adding one to fit the terminating null character */
81+
char value[CONFIG_BT_DEVICE_NAME_MAX + 1] = {};
82+
83+
if (offset != 0) {
84+
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
85+
}
86+
87+
if (offset + len > CONFIG_BT_DEVICE_NAME_MAX) {
88+
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
89+
}
90+
91+
memcpy(value, buf, len);
92+
93+
value[len] = '\0';
94+
95+
bt_set_name(value);
96+
97+
LOG_INFO("Name changed to %s\n", value);
98+
gap_svc_name_changed = true;
99+
if (gap_svc_appearance_changed) {
100+
PASS("GAP service name and appearance changed successfully");
101+
}
102+
103+
return len;
104+
}
105+
106+
static ssize_t read_appearance(struct bt_conn *conn,
107+
const struct bt_gatt_attr *attr, void *buf,
108+
uint16_t len, uint16_t offset)
109+
{
110+
uint16_t appearance = sys_cpu_to_le16(bt_get_appearance());
111+
112+
return bt_gatt_attr_read(conn, attr, buf, len, offset, &appearance, sizeof(appearance));
113+
}
114+
115+
static ssize_t write_appearance(struct bt_conn *conn, const struct bt_gatt_attr *attr,
116+
const void *buf, uint16_t len, uint16_t offset,
117+
uint8_t flags)
118+
{
119+
LOG_INFO("Appearance write called\n");
120+
121+
uint16_t appearance_le = sys_cpu_to_le16(bt_get_appearance());
122+
char * const appearance_le_bytes = (char *)&appearance_le;
123+
uint16_t appearance;
124+
int err;
125+
126+
if (offset >= sizeof(appearance_le)) {
127+
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
128+
}
129+
130+
if ((offset + len) > sizeof(appearance_le)) {
131+
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
132+
}
133+
134+
memcpy(&appearance_le_bytes[offset], buf, len);
135+
appearance = sys_le16_to_cpu(appearance_le);
136+
137+
err = bt_set_appearance(appearance);
138+
139+
if (err) {
140+
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
141+
}
142+
143+
LOG_INFO("Appearance changed to 0x%04x\n", appearance);
144+
gap_svc_appearance_changed = true;
145+
if (gap_svc_name_changed) {
146+
PASS("GAP service name and appearance changed successfully\n");
147+
}
148+
149+
return len;
150+
}
151+
152+
BT_GATT_SERVICE_DEFINE(BT_GATT_GAP_SVC_DEFAULT_NAME,
153+
BT_GATT_PRIMARY_SERVICE(BT_UUID_GAP),
154+
/* Require pairing for writes to device name */
155+
BT_GATT_CHARACTERISTIC(BT_UUID_GAP_DEVICE_NAME,
156+
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
157+
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
158+
read_name, write_name, NULL),
159+
BT_GATT_CHARACTERISTIC(BT_UUID_GAP_APPEARANCE,
160+
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
161+
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
162+
read_appearance, write_appearance, NULL),
163+
);
164+
165+
/* End of local implementation of GAP service
166+
* ---------------------------------------------------------------------------
167+
*/
168+
169+
static void connected(struct bt_conn *conn, uint8_t conn_err)
170+
{
171+
char addr[BT_ADDR_LE_STR_LEN];
172+
int err;
173+
174+
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
175+
176+
if (conn_err) {
177+
FAIL("Failed to connect to %s (%u)\n", addr, conn_err);
178+
return;
179+
}
180+
181+
gap_svc_name_changed = false;
182+
gap_svc_appearance_changed = false;
183+
184+
LOG_INFO("Connected: %s\n", addr);
185+
}
186+
187+
static void disconnected(struct bt_conn *conn, uint8_t reason)
188+
{
189+
char addr[BT_ADDR_LE_STR_LEN];
190+
int err;
191+
192+
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
193+
194+
LOG_INFO("Disconnected: %s (reason 0x%02x)\n", addr, reason);
195+
}
196+
197+
static int start_advertising(void)
198+
{
199+
int err;
200+
201+
err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
202+
if (err) {
203+
printk("Advertising failed to start (err %d)\n", err);
204+
}
205+
206+
return err;
207+
}
208+
209+
static void recycled(void)
210+
{
211+
start_advertising();
212+
}
213+
214+
static struct bt_conn_cb conn_callbacks = {
215+
.connected = connected,
216+
.disconnected = disconnected,
217+
.recycled = recycled,
218+
};
219+
220+
static void bt_ready(void)
221+
{
222+
int err;
223+
224+
LOG_INFO("Peripheral Bluetooth initialized\n");
225+
226+
227+
err = start_advertising();
228+
if (!err) {
229+
LOG_INFO("Advertising successfully started\n");
230+
}
231+
}
232+
233+
static void test_local_gap_svc_peripheral_main(void)
234+
{
235+
int err;
236+
237+
bt_conn_cb_register(&conn_callbacks);
238+
239+
err = bt_enable(NULL);
240+
241+
if (err) {
242+
FAIL("Bluetooth init failed (err %d)\n", err);
243+
return;
244+
}
245+
246+
LOG_INFO("Peripheral Bluetooth initialized\n");
247+
err = start_advertising();
248+
if (err) {
249+
return;
250+
}
251+
LOG_INFO("Advertising successfully started\n");
252+
}
253+
254+
static void test_local_gap_svc_peripheral_init(void)
255+
{
256+
bst_ticker_set_next_tick_absolute(WAIT_TIME);
257+
bst_result = In_progress;
258+
}
259+
260+
static void test_local_gap_svc_peripheral_tick(bs_time_t HW_device_time)
261+
262+
{
263+
/*
264+
* If in WAIT_TIME seconds the testcase did not already pass
265+
* (and finish) we consider it failed
266+
*/
267+
if (bst_result != Passed) {
268+
FAIL("test_local_gap_svc_peripheral failed (not passed after %i seconds)\n",
269+
WAIT_TIME / 1e6);
270+
}
271+
}
272+
273+
static const struct bst_test_instance test_peripheral[] = {
274+
{
275+
.test_id = "peripheral",
276+
.test_descr = "GAP service local reimplementation - peripheral role.",
277+
.test_pre_init_f = test_local_gap_svc_peripheral_init,
278+
.test_tick_f = test_local_gap_svc_peripheral_tick,
279+
.test_main_f = test_local_gap_svc_peripheral_main
280+
},
281+
BSTEST_END_MARKER
282+
};
283+
284+
struct bst_test_list *test_local_gap_svc_peripheral_install(struct bst_test_list *tests)
285+
{
286+
tests = bst_add_tests(tests, test_peripheral);
287+
return tests;
288+
}

0 commit comments

Comments
 (0)