Skip to content

Commit f30996d

Browse files
committed
Tests: Bluetooth: Tester: Add support for PBP testing
Adds support for the existing BTP commands for PBP testing. This should enable bttester to be used to test this profile with AutoPTS. Signed-off-by: Frode van der Meeren <[email protected]>
1 parent a8ca36c commit f30996d

File tree

6 files changed

+339
-1
lines changed

6 files changed

+339
-1
lines changed

tests/bluetooth/tester/src/audio/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,7 @@ endif()
6767
if(CONFIG_BT_TMAP)
6868
target_sources(app PRIVATE btp_tmap.c)
6969
endif()
70+
71+
if(CONFIG_BT_PBP)
72+
target_sources(app PRIVATE btp_pbp.c)
73+
endif()
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/* btp_pbp.c - Bluetooth PBP Tester */
2+
3+
/*
4+
* Copyright (c) 2024 Nordic Semiconductor ASA
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
#define BTP_PBP_READ_SUPPORTED_COMMANDS 0x01
10+
struct btp_pbp_read_supported_commands_rp {
11+
uint8_t data[0];
12+
} __packed;
13+
14+
#define BTP_PBP_SET_PUBLIC_BROADCAST_ANNOUNCEMENT 0x02
15+
struct btp_pbp_set_public_broadcast_announcement_cmd {
16+
uint8_t features;
17+
uint8_t metadata_len;
18+
uint8_t metadata[];
19+
} __packed;
20+
21+
#define BTP_PBP_SET_BROADCAST_NAME 0x03
22+
struct btp_pbp_set_broadcast_name_cmd {
23+
uint8_t name_len;
24+
uint8_t name[];
25+
} __packed;
26+
27+
#define BTP_PBP_BROADCAST_SCAN_START 0x04
28+
struct btp_pbp_broadcast_scan_start_cmd {
29+
} __packed;
30+
31+
#define BTP_PBP_BROADCAST_SCAN_STOP 0x05
32+
struct btp_pbp_broadcast_scan_stop_cmd {
33+
} __packed;
34+
35+
#define BTP_PBP_EV_PUBLIC_BROADCAST_ANOUNCEMENT_FOUND 0x80
36+
struct btp_pbp_ev_public_broadcast_anouncement_found_rp {
37+
bt_addr_le_t address;
38+
uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE];
39+
uint8_t advertiser_sid;
40+
uint16_t padv_interval;
41+
uint8_t pba_features;
42+
uint8_t broadcast_name_len;
43+
uint8_t broadcast_name[];
44+
} __packed;
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
/* btp_pbp.c - Bluetooth PBP Tester */
2+
3+
/*
4+
* Copyright (c) 2024 Nordic Semiconductor ASA
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
#include "btp/btp.h"
10+
11+
#include <zephyr/bluetooth/audio/pbp.h>
12+
#include <zephyr/logging/log.h>
13+
#include <zephyr/sys/util.h>
14+
#define LOG_MODULE_NAME bttester_pbp
15+
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
16+
17+
#define PBP_EXT_ADV_METADATA_LEN_MAX 128
18+
19+
static uint8_t pbp_metadata_cached_len;
20+
static uint8_t pbp_metadata_cached[PBP_EXT_ADV_METADATA_LEN_MAX];
21+
static uint8_t pbp_name_cached_len;
22+
static uint8_t pbp_broadcast_name_cached[BT_AUDIO_BROADCAST_NAME_LEN_MAX];
23+
24+
static bool scan_get_broadcast_name_len(struct bt_data *data, void *user_data)
25+
{
26+
uint8_t *broadcast_name_len = user_data;
27+
28+
switch (data->type) {
29+
case BT_DATA_BROADCAST_NAME:
30+
*broadcast_name_len = data->data_len;
31+
return false;
32+
default:
33+
return true;
34+
}
35+
}
36+
37+
static bool scan_get_data(struct bt_data *data, void *user_data)
38+
{
39+
uint8_t source_features;
40+
uint32_t broadcast_id;
41+
uint8_t metadata_len;
42+
uint8_t *metadata;
43+
struct btp_pbp_ev_public_broadcast_anouncement_found_rp *ev = user_data;
44+
45+
switch (data->type) {
46+
case BT_DATA_BROADCAST_NAME:
47+
ev->broadcast_name_len = data->data_len;
48+
memcpy(ev->broadcast_name, data->data, data->data_len);
49+
return false;
50+
case BT_DATA_SVC_DATA16:
51+
broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16);
52+
sys_put_le24(broadcast_id, ev->broadcast_id);
53+
metadata_len = bt_pbp_parse_announcement(data, &source_features, &metadata);
54+
ev->pba_features = source_features;
55+
return false;
56+
default:
57+
return true;
58+
}
59+
}
60+
61+
static void pbp_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad)
62+
{
63+
if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) ||
64+
info->interval == 0) {
65+
return;
66+
}
67+
68+
uint8_t broadcast_name_len = 0;
69+
struct net_buf_simple ad_copy;
70+
71+
net_buf_simple_clone(ad, &ad_copy);
72+
bt_data_parse(&ad_copy, scan_get_broadcast_name_len, &broadcast_name_len);
73+
74+
struct btp_pbp_ev_public_broadcast_anouncement_found_rp *ev_ptr;
75+
76+
tester_rsp_buffer_lock();
77+
tester_rsp_buffer_allocate(sizeof(*ev_ptr) + broadcast_name_len, (uint8_t **)&ev_ptr);
78+
79+
bt_addr_le_copy(&ev_ptr->address, info->addr);
80+
ev_ptr->advertiser_sid = info->sid;
81+
ev_ptr->padv_interval = info->interval;
82+
bt_data_parse(ad, scan_get_data, ev_ptr);
83+
84+
tester_event(BTP_SERVICE_ID_PBP, BTP_PBP_EV_PUBLIC_BROADCAST_ANOUNCEMENT_FOUND, ev_ptr,
85+
sizeof(*ev_ptr) + broadcast_name_len);
86+
87+
tester_rsp_buffer_free();
88+
tester_rsp_buffer_unlock();
89+
}
90+
91+
static struct bt_le_scan_cb pbp_scan_cb = {
92+
.recv = pbp_scan_recv,
93+
};
94+
95+
static uint8_t pbp_read_supported_commands(const void *cmd, uint16_t cmd_len,
96+
void *rsp, uint16_t *rsp_len)
97+
{
98+
struct btp_pbp_read_supported_commands_rp *rp = rsp;
99+
100+
tester_set_bit(rp->data, BTP_PBP_READ_SUPPORTED_COMMANDS);
101+
tester_set_bit(rp->data, BTP_PBP_SET_PUBLIC_BROADCAST_ANNOUNCEMENT);
102+
tester_set_bit(rp->data, BTP_PBP_SET_BROADCAST_NAME);
103+
tester_set_bit(rp->data, BTP_PBP_BROADCAST_SCAN_START);
104+
tester_set_bit(rp->data, BTP_PBP_BROADCAST_SCAN_STOP);
105+
106+
*rsp_len = sizeof(*rp) + 1;
107+
108+
return BTP_STATUS_SUCCESS;
109+
}
110+
111+
static int pbp_broadcast_source_adv_setup(void)
112+
{
113+
struct bt_le_adv_param param = BT_LE_ADV_PARAM_INIT(0, BT_GAP_ADV_FAST_INT_MIN_2,
114+
BT_GAP_ADV_FAST_INT_MAX_2, NULL);
115+
uint32_t gap_settings = BIT(BTP_GAP_SETTINGS_DISCOVERABLE) |
116+
BIT(BTP_GAP_SETTINGS_EXTENDED_ADVERTISING);
117+
uint32_t broadcast_id;
118+
119+
NET_BUF_SIMPLE_DEFINE(ad_buf,
120+
BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE);
121+
122+
int err = bt_rand(&broadcast_id, BT_AUDIO_BROADCAST_ID_SIZE);
123+
124+
if (err) {
125+
LOG_ERR("Unable to generate broadcast ID: %d\n", err);
126+
return -EINVAL;
127+
}
128+
129+
struct bt_data ext_ad[3];
130+
131+
ext_ad[0].type = BT_DATA_BROADCAST_NAME;
132+
ext_ad[0].data_len = pbp_name_cached_len;
133+
ext_ad[0].data = pbp_broadcast_name_cached;
134+
net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL);
135+
net_buf_simple_add_le24(&ad_buf, broadcast_id);
136+
ext_ad[1].type = BT_DATA_SVC_DATA16;
137+
ext_ad[1].data_len = ad_buf.len;
138+
ext_ad[1].data = ad_buf.data;
139+
ext_ad[2].type = BT_DATA_SVC_DATA16;
140+
ext_ad[2].data_len = pbp_metadata_cached_len;
141+
ext_ad[2].data = pbp_metadata_cached;
142+
err = tester_gap_create_adv_instance(&param, BTP_GAP_ADDR_TYPE_IDENTITY, ext_ad,
143+
ARRAY_SIZE(ext_ad), NULL, 0, &gap_settings);
144+
if (err) {
145+
LOG_ERR("Could not set up extended advertisement: %d", err);
146+
return -EINVAL;
147+
}
148+
149+
err = tester_gap_start_ext_adv();
150+
if (err) {
151+
LOG_ERR("Could not start extended advertisement: %d", err);
152+
return -EINVAL;
153+
}
154+
155+
return 0;
156+
}
157+
158+
static uint8_t pbp_set_public_broadcast_announcement(const void *cmd, uint16_t cmd_len,
159+
void *rsp, uint16_t *rsp_len)
160+
{
161+
const struct btp_pbp_set_public_broadcast_announcement_cmd *cp = cmd;
162+
int err = -EINVAL;
163+
164+
if (cp->metadata_len <= PBP_EXT_ADV_METADATA_LEN_MAX) {
165+
pbp_name_cached_len = cp->metadata_len;
166+
memcpy(pbp_metadata_cached, cp->metadata, cp->metadata_len);
167+
err = pbp_broadcast_source_adv_setup();
168+
} else {
169+
LOG_ERR("Metadata too long: %d > %d", cp->metadata_len,
170+
PBP_EXT_ADV_METADATA_LEN_MAX);
171+
}
172+
173+
return BTP_STATUS_VAL(err);
174+
}
175+
176+
static uint8_t pbp_set_broadcast_name(const void *cmd, uint16_t cmd_len,
177+
void *rsp, uint16_t *rsp_len)
178+
{
179+
const struct btp_pbp_set_broadcast_name_cmd *cp = cmd;
180+
int err = -EINVAL;
181+
182+
if (cp->name_len <= BT_AUDIO_BROADCAST_NAME_LEN_MAX) {
183+
pbp_metadata_cached_len = cp->name_len;
184+
memcpy(pbp_broadcast_name_cached, cp->name, cp->name_len);
185+
err = pbp_broadcast_source_adv_setup();
186+
} else {
187+
LOG_ERR("Broadcast name too long: %d > %d", cp->name_len,
188+
BT_AUDIO_BROADCAST_NAME_LEN_MAX);
189+
}
190+
191+
return BTP_STATUS_VAL(err);
192+
}
193+
194+
static uint8_t pbp_broadcast_scan_start(const void *cmd, uint16_t cmd_len,
195+
void *rsp, uint16_t *rsp_len)
196+
{
197+
int err;
198+
199+
LOG_DBG("Advertisement starting...");
200+
201+
err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
202+
if (err != 0 && err != -EALREADY) {
203+
LOG_ERR("Unable to start scan for broadcast sources: %d", err);
204+
205+
return BTP_STATUS_FAILED;
206+
}
207+
208+
return BTP_STATUS_SUCCESS;
209+
}
210+
211+
static uint8_t pbp_broadcast_scan_stop(const void *cmd, uint16_t cmd_len,
212+
void *rsp, uint16_t *rsp_len)
213+
{
214+
int err;
215+
216+
LOG_DBG("Advertisement stopping...");
217+
218+
err = bt_le_scan_stop();
219+
if (err != 0) {
220+
LOG_ERR("Failed to stop scan, %d", err);
221+
222+
return BTP_STATUS_FAILED;
223+
}
224+
225+
return BTP_STATUS_SUCCESS;
226+
}
227+
228+
static const struct btp_handler pbp_handlers[] = {
229+
{
230+
.opcode = BTP_PBP_READ_SUPPORTED_COMMANDS,
231+
.index = BTP_INDEX_NONE,
232+
.expect_len = 0,
233+
.func = pbp_read_supported_commands
234+
},
235+
{
236+
.opcode = BTP_PBP_SET_PUBLIC_BROADCAST_ANNOUNCEMENT,
237+
.expect_len = sizeof(struct btp_pbp_set_public_broadcast_announcement_cmd),
238+
.func = pbp_set_public_broadcast_announcement
239+
},
240+
{
241+
.opcode = BTP_PBP_SET_BROADCAST_NAME,
242+
.expect_len = sizeof(struct btp_pbp_set_broadcast_name_cmd),
243+
.func = pbp_set_broadcast_name
244+
},
245+
{
246+
.opcode = BTP_PBP_BROADCAST_SCAN_START,
247+
.expect_len = sizeof(struct btp_pbp_broadcast_scan_start_cmd),
248+
.func = pbp_broadcast_scan_start
249+
},
250+
{
251+
.opcode = BTP_PBP_BROADCAST_SCAN_STOP,
252+
.expect_len = sizeof(struct btp_pbp_broadcast_scan_stop_cmd),
253+
.func = pbp_broadcast_scan_stop
254+
}
255+
};
256+
257+
uint8_t tester_init_pbp(void)
258+
{
259+
pbp_metadata_cached_len = 0;
260+
pbp_name_cached_len = 0;
261+
tester_register_command_handlers(BTP_SERVICE_ID_PBP, pbp_handlers,
262+
ARRAY_SIZE(pbp_handlers));
263+
264+
bt_le_scan_cb_register(&pbp_scan_cb);
265+
266+
return BTP_STATUS_SUCCESS;
267+
}
268+
269+
uint8_t tester_unregister_pbp(void)
270+
{
271+
return BTP_STATUS_SUCCESS;
272+
}

tests/bluetooth/tester/src/btp/btp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "btp_tbs.h"
3939
#include "btp_tmap.h"
4040
#include "btp_ots.h"
41+
#include "btp_pbp.h"
4142

4243
#define BTP_MTU 1024
4344
#define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr))
@@ -75,8 +76,9 @@
7576
#define BTP_SERVICE_ID_TBS 27
7677
#define BTP_SERVICE_ID_TMAP 28
7778
#define BTP_SERVICE_ID_OTS 29
79+
#define BTP_SERVICE_ID_PBP 30
7880

79-
#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_OTS
81+
#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_PBP
8082

8183
#define BTP_STATUS_SUCCESS 0x00
8284
#define BTP_STATUS_FAILED 0x01

tests/bluetooth/tester/src/btp/bttester.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,6 @@ uint8_t tester_unregister_tmap(void);
138138

139139
uint8_t tester_init_ots(void);
140140
uint8_t tester_unregister_ots(void);
141+
142+
uint8_t tester_init_pbp(void);
143+
uint8_t tester_unregister_pbp(void);

tests/bluetooth/tester/src/btp_core.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ static uint8_t supported_services(const void *cmd, uint16_t cmd_len,
107107
#if defined(CONFIG_BT_TMAP)
108108
tester_set_bit(rp->data, BTP_SERVICE_ID_TMAP);
109109
#endif /* CONFIG_BT_TMAP */
110+
#if defined(CONFIG_BT_PBP)
111+
tester_set_bit(rp->data, BTP_SERVICE_ID_PBP);
112+
#endif /* CONFIG_BT_PBP */
110113

111114
*rsp_len = sizeof(*rp) + 2;
112115

@@ -250,6 +253,11 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len,
250253
status = tester_init_ots();
251254
break;
252255
#endif /* CONFIG_BT_OTS */
256+
#if defined(CONFIG_BT_PBP)
257+
case BTP_SERVICE_ID_PBP:
258+
status = tester_init_pbp();
259+
break;
260+
#endif /* CONFIG_BT_PBP */
253261
default:
254262
LOG_WRN("unknown id: 0x%02x", cp->id);
255263
status = BTP_STATUS_FAILED;
@@ -397,6 +405,11 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len,
397405
status = tester_unregister_ots();
398406
break;
399407
#endif /* CONFIG_BT_OTS */
408+
#if defined(CONFIG_BT_PBP)
409+
case BTP_SERVICE_ID_PBP:
410+
status = tester_unregister_pbp();
411+
break;
412+
#endif /* CONFIG_BT_PBP */
400413
default:
401414
LOG_WRN("unknown id: 0x%x", cp->id);
402415
status = BTP_STATUS_FAILED;

0 commit comments

Comments
 (0)