tests: Bluetooth: Tester: Add support for PAST

This adds support for BTP commands and events required for running
PAST tests.

struct btp_gap_ev_periodic_transfer_received_ev is also adjusted
to match BTP specification.

Signed-off-by: Szymon Janc <szymon.janc@codecoup.pl>
This commit is contained in:
Szymon Janc 2025-05-20 14:40:01 +02:00 committed by Benjamin Cabé
parent 821e9f3c6a
commit 256401ed2b
3 changed files with 192 additions and 6 deletions

View File

@ -40,6 +40,8 @@ CONFIG_BT_GATT_DYNAMIC_DB=y
CONFIG_BT_EXT_ADV=y
CONFIG_BT_PER_ADV=y
CONFIG_BT_PER_ADV_SYNC=y
CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER=y
CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y
CONFIG_BT_RX_STACK_SIZE=4096
CONFIG_BT_TESTING=y

View File

@ -313,6 +313,8 @@ struct btp_gap_padv_sync_transfer_start_cmd {
uint16_t service_data;
} __packed;
#define BTP_GAP_PADV_SYNC_TRANSFER_RECV_FLAG_REPORTS_DISABLED 0x01
#define BTP_GAP_PADV_SYNC_TRANSFER_RECV 0x29
struct btp_gap_padv_sync_transfer_recv_cmd {
bt_addr_le_t address;
@ -464,13 +466,10 @@ struct btp_gap_ev_periodic_report_ev {
#define BTP_GAP_EV_PERIODIC_TRANSFER_RECEIVED 0x90
struct btp_gap_ev_periodic_transfer_received_ev {
bt_addr_le_t adv_address;
uint16_t sync_handle;
uint8_t tx_power;
uint8_t rssi;
uint8_t cte_type;
uint8_t data_status;
uint8_t data_len;
uint8_t data[];
uint8_t status;
bt_addr_le_t peer_address;
} __packed;
#define BTP_GAP_EV_ENCRYPTION_CHANGE 0x91

View File

@ -1873,6 +1873,30 @@ static void pa_sync_synced_cb(struct bt_le_per_adv_sync *sync,
{
LOG_DBG("");
/* sync transfer received */
if (IS_ENABLED(CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER) && info->conn != NULL) {
struct btp_gap_ev_periodic_transfer_received_ev ev;
struct bt_conn_info conn_info;
if (pa_sync != NULL) {
return;
}
pa_sync = sync;
bt_conn_get_info(info->conn, &conn_info);
bt_addr_le_copy(&ev.adv_address, &sync->addr);
ev.sync_handle = sys_cpu_to_le16(sync->handle);
ev.status = 0;
bt_addr_le_copy(&ev.peer_address, conn_info.le.dst);
tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PERIODIC_TRANSFER_RECEIVED,
&ev, sizeof(ev));
return;
}
/* locally initiated */
if (sync == pa_sync) {
struct btp_gap_ev_periodic_sync_established_ev ev;
@ -1904,9 +1928,43 @@ static void pa_sync_terminated_cb(struct bt_le_per_adv_sync *sync,
}
}
static struct net_buf_simple *periodic_adv_buf =
NET_BUF_SIMPLE(sizeof(struct btp_gap_ev_periodic_report_ev) + UINT8_MAX);
static void pa_sync_recv_cb(struct bt_le_per_adv_sync *sync,
const struct bt_le_per_adv_sync_recv_info *info,
struct net_buf_simple *buf)
{
struct btp_gap_ev_periodic_report_ev *ev;
LOG_DBG("");
/* cleanup */
net_buf_simple_init(periodic_adv_buf, 0);
ev = net_buf_simple_add(periodic_adv_buf, sizeof(*ev));
ev->sync_handle = sys_cpu_to_le16(sync->handle);
ev->rssi = info->rssi;
ev->cte_type = info->cte_type;
/* TODO BTP has fragmented data (as in HCI) */
if (buf->len > UINT8_MAX) {
ev->data_len = UINT8_MAX;
} else {
ev->data_len = buf->len;
}
memcpy(net_buf_simple_add(periodic_adv_buf, ev->data_len), buf->data, ev->data_len);
tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PERIODIC_REPORT,
ev, sizeof(*ev) + ev->data_len);
}
static struct bt_le_per_adv_sync_cb pa_sync_cb = {
.synced = pa_sync_synced_cb,
.term = pa_sync_terminated_cb,
.recv = pa_sync_recv_cb,
};
#if defined(CONFIG_BT_PER_ADV)
@ -2164,6 +2222,114 @@ static uint8_t padv_create_sync(const void *cmd, uint16_t cmd_len,
return BTP_STATUS_VAL(err);
}
#if defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER)
static uint8_t padv_sync_transfer_set_info(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_gap_padv_sync_transfer_set_info_cmd *cp = cmd;
struct bt_le_ext_adv *ext_adv = tester_gap_ext_adv_get(0);
struct bt_conn *conn;
int err;
if (ext_adv == NULL) {
return BTP_STATUS_FAILED;
}
if (cp->address.type == BTP_BR_ADDRESS_TYPE) {
return BTP_STATUS_FAILED;
}
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (conn == NULL) {
return BTP_STATUS_FAILED;
}
err = bt_le_per_adv_set_info_transfer(ext_adv, conn,
sys_le16_to_cpu(cp->service_data));
bt_conn_unref(conn);
if (err < 0) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t padv_padv_sync_transfer_start(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_gap_padv_sync_transfer_start_cmd *cp = cmd;
struct bt_conn *conn;
int err;
if (pa_sync == NULL) {
return BTP_STATUS_FAILED;
}
if (cp->address.type == BTP_BR_ADDRESS_TYPE) {
return BTP_STATUS_FAILED;
}
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (conn == NULL) {
return BTP_STATUS_FAILED;
}
err = bt_le_per_adv_sync_transfer(pa_sync, conn,
sys_le16_to_cpu(cp->service_data));
bt_conn_unref(conn);
if (err < 0) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
#endif /* defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER) */
#if defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER)
static uint8_t padv_padv_sync_transfer_recv(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_gap_padv_sync_transfer_recv_cmd *cp = cmd;
struct bt_le_per_adv_sync_transfer_param param = {0};
struct bt_conn *conn;
int err;
if (pa_sync != NULL) {
return BTP_STATUS_FAILED;
}
if (cp->address.type == BTP_BR_ADDRESS_TYPE) {
return BTP_STATUS_FAILED;
}
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (conn == NULL) {
return BTP_STATUS_FAILED;
}
param.skip = sys_le16_to_cpu(cp->skip);
param.timeout = sys_le16_to_cpu(cp->sync_timeout);
if ((cp->flags & BTP_GAP_PADV_SYNC_TRANSFER_RECV_FLAG_REPORTS_DISABLED) != 0) {
param.options |= BT_LE_PER_ADV_SYNC_TRANSFER_OPT_REPORTING_INITIALLY_DISABLED;
}
err = bt_le_per_adv_sync_transfer_subscribe(conn, &param);
bt_conn_unref(conn);
if (err < 0) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
#endif /* defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER) */
#endif /* defined(CONFIG_BT_PER_ADV) */
#if defined(CONFIG_BT_RPA_TIMEOUT_DYNAMIC)
@ -2350,6 +2516,25 @@ static const struct btp_handler handlers[] = {
.expect_len = sizeof(struct btp_gap_padv_create_sync_cmd),
.func = padv_create_sync,
},
#if defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER)
{
.opcode = BTP_GAP_PADV_SYNC_TRANSFER_SET_INFO,
.expect_len = sizeof(struct btp_gap_padv_sync_transfer_set_info_cmd),
.func = padv_sync_transfer_set_info,
},
{
.opcode = BTP_GAP_PADV_SYNC_TRANSFER_START,
.expect_len = sizeof(struct btp_gap_padv_sync_transfer_start_cmd),
.func = padv_padv_sync_transfer_start,
},
#endif /* defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER) */
#if defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER)
{
.opcode = BTP_GAP_PADV_SYNC_TRANSFER_RECV,
.expect_len = sizeof(struct btp_gap_padv_sync_transfer_recv_cmd),
.func = padv_padv_sync_transfer_recv,
},
#endif /* defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER) */
#endif /* defined(CONFIG_BT_PER_ADV) */
#endif /* defined(CONFIG_BT_EXT_ADV) */
#if defined(CONFIG_BT_RPA_TIMEOUT_DYNAMIC)