2022-09-20 14:23:24 +02:00
|
|
|
/* main_l2cap_stress.c - Application main entry point */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2022 Nordic Semiconductor
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "bstests.h"
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
#define LOG_MODULE_NAME main
|
|
|
|
#include <zephyr/logging/log.h>
|
2024-03-19 09:56:28 +01:00
|
|
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
|
2022-09-20 14:23:24 +02:00
|
|
|
|
|
|
|
CREATE_FLAG(is_connected);
|
|
|
|
CREATE_FLAG(flag_l2cap_connected);
|
|
|
|
|
|
|
|
#define NUM_PERIPHERALS 6
|
2023-03-06 12:47:00 +01:00
|
|
|
#define L2CAP_CHANS NUM_PERIPHERALS
|
|
|
|
#define SDU_NUM 20
|
2023-03-07 09:26:15 +01:00
|
|
|
#define SDU_LEN 3000
|
2024-04-15 15:03:48 +02:00
|
|
|
#define NUM_SEGMENTS 100
|
2023-03-06 12:47:00 +01:00
|
|
|
#define RESCHEDULE_DELAY K_MSEC(100)
|
2022-09-20 14:23:24 +02:00
|
|
|
|
2024-01-04 12:15:17 +01:00
|
|
|
static void sdu_destroy(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
LOG_DBG("%p", buf);
|
|
|
|
|
|
|
|
net_buf_destroy(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void segment_destroy(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
LOG_DBG("%p", buf);
|
|
|
|
|
|
|
|
net_buf_destroy(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rx_destroy(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
LOG_DBG("%p", buf);
|
|
|
|
|
|
|
|
net_buf_destroy(buf);
|
|
|
|
}
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
/* Only one SDU per link will be transmitted at a time */
|
|
|
|
NET_BUF_POOL_DEFINE(sdu_tx_pool,
|
2022-11-24 15:31:17 +01:00
|
|
|
CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN),
|
2024-01-04 12:15:17 +01:00
|
|
|
CONFIG_BT_CONN_TX_USER_DATA_SIZE, sdu_destroy);
|
2022-09-20 15:48:11 +02:00
|
|
|
|
|
|
|
NET_BUF_POOL_DEFINE(segment_pool,
|
2022-11-24 15:31:17 +01:00
|
|
|
/* MTU + 4 l2cap hdr + 4 ACL hdr */
|
2022-09-20 15:48:11 +02:00
|
|
|
NUM_SEGMENTS, BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
|
2024-01-04 12:15:17 +01:00
|
|
|
CONFIG_BT_CONN_TX_USER_DATA_SIZE, segment_destroy);
|
2022-09-20 14:23:24 +02:00
|
|
|
|
|
|
|
/* Only one SDU per link will be received at a time */
|
|
|
|
NET_BUF_POOL_DEFINE(sdu_rx_pool,
|
2022-11-24 15:31:17 +01:00
|
|
|
CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN),
|
2024-01-04 12:15:17 +01:00
|
|
|
8, rx_destroy);
|
2022-09-20 14:23:24 +02:00
|
|
|
|
|
|
|
static uint8_t tx_data[SDU_LEN];
|
|
|
|
static uint16_t rx_cnt;
|
|
|
|
static uint8_t disconnect_counter;
|
2022-11-24 15:31:17 +01:00
|
|
|
static uint32_t max_seg_allocated;
|
2022-09-20 14:23:24 +02:00
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
struct test_ctx {
|
|
|
|
struct k_work_delayable work_item;
|
|
|
|
struct bt_l2cap_le_chan le_chan;
|
|
|
|
size_t tx_left;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct test_ctx contexts[L2CAP_CHANS];
|
|
|
|
|
|
|
|
struct test_ctx *get_ctx(struct bt_l2cap_chan *chan)
|
|
|
|
{
|
|
|
|
struct bt_l2cap_le_chan *le_chan = CONTAINER_OF(chan, struct bt_l2cap_le_chan, chan);
|
|
|
|
struct test_ctx *ctx = CONTAINER_OF(le_chan, struct test_ctx, le_chan);
|
|
|
|
|
|
|
|
ASSERT(ctx >= &contexts[0] &&
|
|
|
|
ctx <= &contexts[L2CAP_CHANS], "memory corruption");
|
|
|
|
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
int l2cap_chan_send(struct bt_l2cap_chan *chan, uint8_t *data, size_t len)
|
|
|
|
{
|
2023-03-06 12:47:00 +01:00
|
|
|
LOG_DBG("chan %p conn %u data %p len %d", chan, bt_conn_index(chan->conn), data, len);
|
2022-09-20 14:23:24 +02:00
|
|
|
|
|
|
|
struct net_buf *buf = net_buf_alloc(&sdu_tx_pool, K_NO_WAIT);
|
|
|
|
|
|
|
|
if (buf == NULL) {
|
|
|
|
FAIL("No more memory\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2022-11-24 15:31:17 +01:00
|
|
|
net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE);
|
2022-09-20 14:23:24 +02:00
|
|
|
net_buf_add_mem(buf, data, len);
|
|
|
|
|
|
|
|
int ret = bt_l2cap_chan_send(chan, buf);
|
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
if (ret == -EAGAIN) {
|
|
|
|
LOG_DBG("L2CAP error %d, attempting to reschedule sending", ret);
|
2022-09-20 14:23:24 +02:00
|
|
|
net_buf_unref(buf);
|
2023-03-06 12:47:00 +01:00
|
|
|
k_work_reschedule(&(get_ctx(chan)->work_item), RESCHEDULE_DELAY);
|
|
|
|
|
|
|
|
return ret;
|
2022-09-20 14:23:24 +02:00
|
|
|
}
|
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
ASSERT(ret >= 0, "Failed sending: err %d", ret);
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
LOG_DBG("sent %d len %d", ret, len);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-09-20 15:48:11 +02:00
|
|
|
struct net_buf *alloc_seg_cb(struct bt_l2cap_chan *chan)
|
|
|
|
{
|
|
|
|
struct net_buf *buf = net_buf_alloc(&segment_pool, K_NO_WAIT);
|
|
|
|
|
2022-11-24 15:31:17 +01:00
|
|
|
if ((NUM_SEGMENTS - segment_pool.avail_count) > max_seg_allocated) {
|
|
|
|
max_seg_allocated++;
|
|
|
|
}
|
|
|
|
|
2022-09-20 15:48:11 +02:00
|
|
|
ASSERT(buf, "Ran out of segment buffers");
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan)
|
|
|
|
{
|
|
|
|
return net_buf_alloc(&sdu_rx_pool, K_NO_WAIT);
|
|
|
|
}
|
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
void continue_sending(struct test_ctx *ctx)
|
2022-09-20 14:23:24 +02:00
|
|
|
{
|
2023-03-06 12:47:00 +01:00
|
|
|
struct bt_l2cap_chan *chan = &ctx->le_chan.chan;
|
2022-09-20 14:23:24 +02:00
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
LOG_DBG("%p, left %d", chan, ctx->tx_left);
|
2022-09-20 14:23:24 +02:00
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
if (ctx->tx_left) {
|
|
|
|
l2cap_chan_send(chan, tx_data, sizeof(tx_data));
|
|
|
|
} else {
|
|
|
|
LOG_DBG("Done sending %u", bt_conn_index(chan->conn));
|
|
|
|
}
|
2022-09-20 14:23:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void sent_cb(struct bt_l2cap_chan *chan)
|
|
|
|
{
|
2023-03-06 12:47:00 +01:00
|
|
|
struct test_ctx *ctx = get_ctx(chan);
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
LOG_DBG("%p", chan);
|
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
if (ctx->tx_left) {
|
|
|
|
ctx->tx_left--;
|
2022-09-20 14:23:24 +02:00
|
|
|
}
|
2023-03-06 12:47:00 +01:00
|
|
|
|
|
|
|
continue_sending(ctx);
|
2022-09-20 14:23:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf)
|
|
|
|
{
|
|
|
|
LOG_DBG("len %d", buf->len);
|
|
|
|
rx_cnt++;
|
|
|
|
|
2022-11-24 15:31:17 +01:00
|
|
|
/* Verify SDU data matches TX'd data. */
|
|
|
|
ASSERT(memcmp(buf->data, tx_data, buf->len) == 0, "RX data doesn't match TX");
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void l2cap_chan_connected_cb(struct bt_l2cap_chan *l2cap_chan)
|
|
|
|
{
|
|
|
|
struct bt_l2cap_le_chan *chan =
|
|
|
|
CONTAINER_OF(l2cap_chan, struct bt_l2cap_le_chan, chan);
|
|
|
|
|
|
|
|
SET_FLAG(flag_l2cap_connected);
|
|
|
|
LOG_DBG("%x (tx mtu %d mps %d) (tx mtu %d mps %d)",
|
|
|
|
l2cap_chan,
|
|
|
|
chan->tx.mtu,
|
|
|
|
chan->tx.mps,
|
|
|
|
chan->rx.mtu,
|
|
|
|
chan->rx.mps);
|
|
|
|
}
|
|
|
|
|
|
|
|
void l2cap_chan_disconnected_cb(struct bt_l2cap_chan *chan)
|
|
|
|
{
|
|
|
|
UNSET_FLAG(flag_l2cap_connected);
|
2023-03-06 12:47:00 +01:00
|
|
|
LOG_DBG("%p", chan);
|
2022-09-20 14:23:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct bt_l2cap_chan_ops ops = {
|
|
|
|
.connected = l2cap_chan_connected_cb,
|
|
|
|
.disconnected = l2cap_chan_disconnected_cb,
|
|
|
|
.alloc_buf = alloc_buf_cb,
|
2022-09-20 15:48:11 +02:00
|
|
|
.alloc_seg = alloc_seg_cb,
|
2022-09-20 14:23:24 +02:00
|
|
|
.recv = recv_cb,
|
|
|
|
.sent = sent_cb,
|
|
|
|
};
|
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
void deferred_send(struct k_work *item)
|
|
|
|
{
|
2023-08-29 09:45:51 +00:00
|
|
|
struct test_ctx *ctx = CONTAINER_OF(k_work_delayable_from_work(item),
|
|
|
|
struct test_ctx, work_item);
|
2023-03-06 12:47:00 +01:00
|
|
|
|
|
|
|
struct bt_l2cap_chan *chan = &ctx->le_chan.chan;
|
|
|
|
|
|
|
|
LOG_DBG("continue %u left %d", bt_conn_index(chan->conn), ctx->tx_left);
|
|
|
|
|
|
|
|
continue_sending(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct test_ctx *alloc_test_context(void)
|
2022-09-20 14:23:24 +02:00
|
|
|
{
|
|
|
|
for (int i = 0; i < L2CAP_CHANS; i++) {
|
2023-03-06 12:47:00 +01:00
|
|
|
struct bt_l2cap_le_chan *le_chan = &contexts[i].le_chan;
|
2022-09-20 14:23:24 +02:00
|
|
|
|
|
|
|
if (le_chan->state != BT_L2CAP_DISCONNECTED) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
memset(&contexts[i], 0, sizeof(struct test_ctx));
|
|
|
|
k_work_init_delayable(&contexts[i].work_item, deferred_send);
|
|
|
|
|
|
|
|
return &contexts[i];
|
2022-09-20 14:23:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-07-18 17:37:56 +00:00
|
|
|
int server_accept_cb(struct bt_conn *conn, struct bt_l2cap_server *server,
|
|
|
|
struct bt_l2cap_chan **chan)
|
2022-09-20 14:23:24 +02:00
|
|
|
{
|
2023-03-06 12:47:00 +01:00
|
|
|
struct test_ctx *ctx = NULL;
|
2022-09-20 14:23:24 +02:00
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
ctx = alloc_test_context();
|
|
|
|
if (ctx == NULL) {
|
2022-09-20 14:23:24 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
struct bt_l2cap_le_chan *le_chan = &ctx->le_chan;
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
memset(le_chan, 0, sizeof(*le_chan));
|
|
|
|
le_chan->chan.ops = &ops;
|
|
|
|
le_chan->rx.mtu = SDU_LEN;
|
|
|
|
*chan = &le_chan->chan;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct bt_l2cap_server test_l2cap_server = {
|
|
|
|
.accept = server_accept_cb
|
|
|
|
};
|
|
|
|
|
|
|
|
static int l2cap_server_register(bt_security_t sec_level)
|
|
|
|
{
|
|
|
|
test_l2cap_server.psm = 0;
|
|
|
|
test_l2cap_server.sec_level = sec_level;
|
|
|
|
|
|
|
|
int err = bt_l2cap_server_register(&test_l2cap_server);
|
|
|
|
|
|
|
|
ASSERT(err == 0, "Failed to register l2cap server.");
|
|
|
|
|
|
|
|
return test_l2cap_server.psm;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void connected(struct bt_conn *conn, uint8_t conn_err)
|
|
|
|
{
|
|
|
|
char addr[BT_ADDR_LE_STR_LEN];
|
|
|
|
|
|
|
|
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
|
|
|
|
|
|
|
if (conn_err) {
|
|
|
|
FAIL("Failed to connect to %s (%u)", addr, conn_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DBG("%s", addr);
|
|
|
|
|
|
|
|
SET_FLAG(is_connected);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disconnected(struct bt_conn *conn, uint8_t reason)
|
|
|
|
{
|
|
|
|
char addr[BT_ADDR_LE_STR_LEN];
|
|
|
|
|
|
|
|
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
|
|
|
|
|
|
|
LOG_DBG("%p %s (reason 0x%02x)", conn, addr, reason);
|
|
|
|
|
|
|
|
UNSET_FLAG(is_connected);
|
|
|
|
disconnect_counter++;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
|
|
|
.connected = connected,
|
|
|
|
.disconnected = disconnected,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void disconnect_device(struct bt_conn *conn, void *data)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
SET_FLAG(is_connected);
|
|
|
|
|
|
|
|
err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
|
|
|
ASSERT(!err, "Failed to initate disconnect (err %d)", err);
|
|
|
|
|
|
|
|
LOG_DBG("Waiting for disconnection...");
|
|
|
|
WAIT_FOR_FLAG_UNSET(is_connected);
|
|
|
|
}
|
|
|
|
|
2024-04-17 17:50:03 +02:00
|
|
|
#define BT_LE_ADV_CONN_OT BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \
|
|
|
|
BT_LE_ADV_OPT_ONE_TIME, \
|
|
|
|
BT_GAP_ADV_FAST_INT_MIN_2, \
|
|
|
|
BT_GAP_ADV_FAST_INT_MAX_2, NULL)
|
2022-09-20 14:23:24 +02:00
|
|
|
|
|
|
|
static void test_peripheral_main(void)
|
|
|
|
{
|
|
|
|
LOG_DBG("*L2CAP STRESS Peripheral started*");
|
|
|
|
int err;
|
|
|
|
|
2022-11-24 15:31:17 +01:00
|
|
|
/* Prepare tx_data */
|
|
|
|
for (size_t i = 0; i < sizeof(tx_data); i++) {
|
|
|
|
tx_data[i] = (uint8_t)i;
|
|
|
|
}
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
err = bt_enable(NULL);
|
|
|
|
if (err) {
|
|
|
|
FAIL("Can't enable Bluetooth (err %d)", err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DBG("Peripheral Bluetooth initialized.");
|
|
|
|
LOG_DBG("Connectable advertising...");
|
2024-04-17 17:50:03 +02:00
|
|
|
err = bt_le_adv_start(BT_LE_ADV_CONN_OT, NULL, 0, NULL, 0);
|
2022-09-20 14:23:24 +02:00
|
|
|
if (err) {
|
|
|
|
FAIL("Advertising failed to start (err %d)", err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DBG("Advertising started.");
|
|
|
|
LOG_DBG("Peripheral waiting for connection...");
|
|
|
|
WAIT_FOR_FLAG_SET(is_connected);
|
|
|
|
LOG_DBG("Peripheral Connected.");
|
|
|
|
|
|
|
|
int psm = l2cap_server_register(BT_SECURITY_L1);
|
|
|
|
|
|
|
|
LOG_DBG("Registered server PSM %x", psm);
|
|
|
|
|
|
|
|
LOG_DBG("Peripheral waiting for transfer completion");
|
|
|
|
while (rx_cnt < SDU_NUM) {
|
|
|
|
k_msleep(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_foreach(BT_CONN_TYPE_LE, disconnect_device, NULL);
|
|
|
|
WAIT_FOR_FLAG_UNSET(is_connected);
|
|
|
|
LOG_INF("Total received: %d", rx_cnt);
|
2023-03-06 12:47:00 +01:00
|
|
|
|
|
|
|
ASSERT(rx_cnt == SDU_NUM, "Did not receive expected no of SDUs\n");
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
PASS("L2CAP STRESS Peripheral passed\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
|
|
|
|
struct net_buf_simple *ad)
|
|
|
|
{
|
|
|
|
struct bt_le_conn_param *param;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = bt_le_scan_stop();
|
|
|
|
if (err) {
|
|
|
|
FAIL("Stop LE scan failed (err %d)", err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char str[BT_ADDR_LE_STR_LEN];
|
|
|
|
|
|
|
|
bt_addr_le_to_str(addr, str, sizeof(str));
|
|
|
|
|
|
|
|
LOG_DBG("Connecting to %s", str);
|
|
|
|
|
|
|
|
param = BT_LE_CONN_PARAM_DEFAULT;
|
|
|
|
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &conn);
|
|
|
|
if (err) {
|
|
|
|
FAIL("Create conn failed (err %d)", err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void connect_peripheral(void)
|
|
|
|
{
|
|
|
|
struct bt_le_scan_param scan_param = {
|
|
|
|
.type = BT_LE_SCAN_TYPE_ACTIVE,
|
|
|
|
.options = BT_LE_SCAN_OPT_NONE,
|
|
|
|
.interval = BT_GAP_SCAN_FAST_INTERVAL,
|
|
|
|
.window = BT_GAP_SCAN_FAST_WINDOW,
|
|
|
|
};
|
|
|
|
|
|
|
|
UNSET_FLAG(is_connected);
|
|
|
|
|
|
|
|
int err = bt_le_scan_start(&scan_param, device_found);
|
|
|
|
|
|
|
|
ASSERT(!err, "Scanning failed to start (err %d)\n", err);
|
|
|
|
|
|
|
|
LOG_DBG("Central initiating connection...");
|
|
|
|
WAIT_FOR_FLAG_SET(is_connected);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void connect_l2cap_channel(struct bt_conn *conn, void *data)
|
|
|
|
{
|
|
|
|
int err;
|
2023-03-06 12:47:00 +01:00
|
|
|
struct test_ctx *ctx = alloc_test_context();
|
|
|
|
|
|
|
|
ASSERT(ctx, "No more available test contexts\n");
|
2022-09-20 14:23:24 +02:00
|
|
|
|
2023-03-06 12:47:00 +01:00
|
|
|
struct bt_l2cap_le_chan *le_chan = &ctx->le_chan;
|
2022-09-20 14:23:24 +02:00
|
|
|
|
|
|
|
le_chan->chan.ops = &ops;
|
|
|
|
le_chan->rx.mtu = SDU_LEN;
|
|
|
|
|
|
|
|
UNSET_FLAG(flag_l2cap_connected);
|
|
|
|
|
|
|
|
err = bt_l2cap_chan_connect(conn, &le_chan->chan, 0x0080);
|
|
|
|
ASSERT(!err, "Error connecting l2cap channel (err %d)\n", err);
|
|
|
|
|
|
|
|
WAIT_FOR_FLAG_SET(flag_l2cap_connected);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_central_main(void)
|
|
|
|
{
|
|
|
|
LOG_DBG("*L2CAP STRESS Central started*");
|
|
|
|
int err;
|
|
|
|
|
2022-11-24 15:31:17 +01:00
|
|
|
/* Prepare tx_data */
|
|
|
|
for (size_t i = 0; i < sizeof(tx_data); i++) {
|
|
|
|
tx_data[i] = (uint8_t)i;
|
|
|
|
}
|
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
err = bt_enable(NULL);
|
|
|
|
ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err);
|
|
|
|
LOG_DBG("Central Bluetooth initialized.");
|
|
|
|
|
|
|
|
/* Connect all peripherals */
|
|
|
|
for (int i = 0; i < NUM_PERIPHERALS; i++) {
|
|
|
|
connect_peripheral();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Connect L2CAP channels */
|
|
|
|
LOG_DBG("Connect L2CAP channels");
|
|
|
|
bt_conn_foreach(BT_CONN_TYPE_LE, connect_l2cap_channel, NULL);
|
|
|
|
|
|
|
|
/* Send SDU_NUM SDUs to each peripheral */
|
|
|
|
for (int i = 0; i < NUM_PERIPHERALS; i++) {
|
2023-03-06 12:47:00 +01:00
|
|
|
contexts[i].tx_left = SDU_NUM;
|
|
|
|
l2cap_chan_send(&contexts[i].le_chan.chan, tx_data, sizeof(tx_data));
|
2022-09-20 14:23:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DBG("Wait until all transfers are completed.");
|
|
|
|
int remaining_tx_total;
|
|
|
|
|
|
|
|
do {
|
|
|
|
k_msleep(100);
|
|
|
|
|
|
|
|
remaining_tx_total = 0;
|
|
|
|
for (int i = 0; i < L2CAP_CHANS; i++) {
|
2023-03-06 12:47:00 +01:00
|
|
|
remaining_tx_total += contexts[i].tx_left;
|
2022-09-20 14:23:24 +02:00
|
|
|
}
|
|
|
|
} while (remaining_tx_total);
|
|
|
|
|
|
|
|
LOG_DBG("Waiting until all peripherals are disconnected..");
|
|
|
|
while (disconnect_counter < NUM_PERIPHERALS) {
|
|
|
|
k_msleep(100);
|
|
|
|
}
|
|
|
|
LOG_DBG("All peripherals disconnected.");
|
|
|
|
|
2024-04-15 15:03:48 +02:00
|
|
|
LOG_INF("Max segment pool usage: %u bufs", max_seg_allocated);
|
2022-11-24 15:31:17 +01:00
|
|
|
|
2022-09-20 14:23:24 +02:00
|
|
|
PASS("L2CAP STRESS Central passed\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct bst_test_instance test_def[] = {
|
|
|
|
{
|
|
|
|
.test_id = "peripheral",
|
|
|
|
.test_descr = "Peripheral L2CAP STRESS",
|
2024-05-27 14:33:05 +02:00
|
|
|
.test_pre_init_f = test_init,
|
2022-09-20 14:23:24 +02:00
|
|
|
.test_tick_f = test_tick,
|
|
|
|
.test_main_f = test_peripheral_main
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.test_id = "central",
|
|
|
|
.test_descr = "Central L2CAP STRESS",
|
2024-05-27 14:33:05 +02:00
|
|
|
.test_pre_init_f = test_init,
|
2022-09-20 14:23:24 +02:00
|
|
|
.test_tick_f = test_tick,
|
|
|
|
.test_main_f = test_central_main
|
|
|
|
},
|
|
|
|
BSTEST_END_MARKER
|
|
|
|
};
|
|
|
|
|
|
|
|
struct bst_test_list *test_main_l2cap_stress_install(struct bst_test_list *tests)
|
|
|
|
{
|
|
|
|
return bst_add_tests(tests, test_def);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern struct bst_test_list *test_main_l2cap_stress_install(struct bst_test_list *tests);
|
|
|
|
|
|
|
|
bst_test_install_t test_installers[] = {
|
|
|
|
test_main_l2cap_stress_install,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2023-02-07 21:00:59 -08:00
|
|
|
int main(void)
|
2022-09-20 14:23:24 +02:00
|
|
|
{
|
|
|
|
bst_main();
|
2023-02-07 21:00:59 -08:00
|
|
|
return 0;
|
2022-09-20 14:23:24 +02:00
|
|
|
}
|