Skip to content

Commit 2a141fe

Browse files
committed
SHA-1: 606d9e1036d09b473013b2cc3768c4e10e053765
* tests: bluetooth: classic: Add test suite l2cap. IUT works as a l2cap server with basic mode. The peer device, l2cap client with basic mode, is a PC with running `bumble` on it. This test only performs the function of L2CAP basic mode. Support multiple l2cap enerties in new shell l2cap_br, which may support more test function. In the test suite , there are two groups in test cases. Group 1 Including case1-case8 focuses on connection and disconnection around l2cap. The impact of active and passive acl connectivity, disconnectivity and authentication as well as disconnection from ACL without l2cap disconnect is tested. Group2 Including case9-case14 revolves around the basic parameters of L2CAPserver configuration, data transfer. Case 9: Test l2cap connection with max MTU(0xffff).But the max mtu which the stack supports is (CONFIG_BT_BUF_ACL_RX_SIZE - 4U = 196). Case 10: Test l2cap connection with min MTU(0x30). Case 11: Test l2cap connection with invaild PSM. Case 12: Test l2cap multi_channel connection and data tranfer. Case 13: Stress Test. Repeat l2cap connect, disconnect operation. Case 14: Stress Test. Repeat data transfer in a single connection. In Case 13 and 14, if enlarging STRESS_TEST_MAX_COUNT and test fail, you can enlarge timeout in testcase.yml. test_l2cap_server.py is a file containing real test cases. test_l2cap_common.py is a common file. It encapsulates some test function functions that are commonly used for test cases. Signed-off-by: Cheng Chang <[email protected]>
1 parent b2b7a46 commit 2a141fe

10 files changed

+1754
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
set(NO_QEMU_SERIAL_BT_SERVER 1)
5+
6+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
7+
project(bluetooth)
8+
9+
FILE(GLOB app_sources src/*.c)
10+
target_sources(app PRIVATE ${app_sources})
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
.. _bluetooth_classic_l2cap_server_tests:
2+
3+
Bluetooth Classic L2cap Server Tests
4+
##################################
5+
6+
Overview
7+
********
8+
9+
This test suite uses ``bumble`` for testing Bluetooth Classic communication between a host
10+
PC (running :ref:`Twister <twister_script>`) and a device under test (DUT) running Zephyr.
11+
12+
Prerequisites
13+
*************
14+
15+
The test suite has the following prerequisites:
16+
17+
* The ``bumble`` library installed on the host PC.
18+
The Bluetooth Classic controller on PC side is required. Refer to getting started of `bumble`_
19+
for details.
20+
21+
The HCI transport for ``bumble`` can be configured as follows:
22+
23+
* A specific configuration context can be provided along with the ``usb_hci`` fixture separated by
24+
a ``:`` (i.e. specify fixture ``usb_hci:usb:0`` to use the ``usb:0`` as hci transport for
25+
``bumble``).
26+
* The configuration context can be overridden using the `hci transport`_ can be provided using the
27+
``--hci-transport`` test suite argument (i.e. run ``twister`` with the
28+
``--pytest-args=--hci-transport=usb:0`` argument to use the ``usb:0`` as hci transport for
29+
``bumble``).
30+
31+
Building and Running
32+
********************
33+
34+
Running on mimxrt1170_evk@B/mimxrt1176/cm7
35+
==========================================
36+
37+
Running the test suite on :ref:`mimxrt1170_evk` relies on configuration of ``bumble``.
38+
39+
On the host PC, a HCI transport needs to be required. Refer to `bumble platforms`_ page of
40+
``bumble`` for details.
41+
42+
For example, on windows, a PTS dongle is used. After `WinUSB driver`_ has been installed,
43+
the HCI transport would be USB transport interface ``usb:<index>``.
44+
45+
If the HCI transport is ``usb:0`` and debug console port is ``COM4``, the test suite can be
46+
launched using Twister:
47+
48+
.. code-block:: shell
49+
50+
west twister -v -p mimxrt1170_evk@B/mimxrt1176/cm7 --device-testing --device-serial COM4 -T tests/bluetooth/classic/l2cap -O l2cap_s --force-platform --west-flash --west-runner=jlink -X usb_hci:usb:0
51+
52+
Running on Hardware
53+
===================
54+
55+
Running the test suite on hardware requires a HCI transport connected to the host PC.
56+
57+
The test suite can be launched using Twister. Below is an example for running on the
58+
:zephyr:board:`mimxrt1170_evk@B/mimxrt1176/cm7`:
59+
60+
.. code-block:: shell
61+
62+
west twister -v -p mimxrt1170_evk@B/mimxrt1176/cm7 --device-testing --device-serial COM4 -T tests/bluetooth/classic/l2cap -O l2cap_s --force-platform --west-flash --west-runner=jlink -X usb_hci:usb:0
63+
64+
.. _bumble:
65+
https://google.github.io/bumble/getting_started.html
66+
67+
.. _hci transport:
68+
https://google.github.io/bumble/transports/index.html
69+
70+
.. _bumble platforms:
71+
https://google.github.io/bumble/platforms/index.html
72+
73+
.. _WinUSB driver:
74+
https://google.github.io/bumble/platforms/windows.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#select NXP NW612 Chipset
2+
CONFIG_BT_NXP_NW612=y
3+
4+
CONFIG_BT_SETTINGS=n
5+
CONFIG_FLASH=n
6+
CONFIG_FLASH_MAP=n
7+
CONFIG_NVS=n
8+
CONFIG_SETTINGS=n
9+
10+
CONFIG_ENTROPY_GENERATOR=y
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright 2024 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
chosen {
9+
zephyr,sram = &dtcm;
10+
};
11+
};
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CONFIG_BT=y
2+
CONFIG_BT_CLASSIC=y
3+
CONFIG_BT_SHELL=y
4+
CONFIG_LOG=y
5+
CONFIG_DEBUG=y
6+
CONFIG_ZTEST=y
7+
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
8+
CONFIG_BT_L2CAP_RET=y
9+
CONFIG_BT_L2CAP_FC=y
10+
CONFIG_BT_L2CAP_ENH_RET=y
11+
CONFIG_BT_L2CAP_STREAM=y
12+
CONFIG_BT_L2CAP_FCS=y
13+
CONFIG_BT_L2CAP_EXT_WIN_SIZE=y
14+
CONFIG_BT_L2CAP_MAX_WINDOW_SIZE=5
15+
CONFIG_BT_DEVICE_NAME="L2CAP_BR"
16+
CONFIG_BT_CREATE_CONN_TIMEOUT=30
17+
CONFIG_BT_PAGE_TIMEOUT=0xFFFF
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Copyright 2024 NXP
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
import re
5+
6+
import pytest
7+
from test_l2cap_common import L2CAP_SERVER_PSM, MODE, logger
8+
from twister_harness import DeviceAdapter, Shell
9+
10+
11+
def pytest_addoption(parser) -> None:
12+
"""Add local parser options to pytest."""
13+
parser.addoption('--hci-transport', default=None, help='Configuration HCI transport for bumble')
14+
15+
16+
@pytest.fixture(name='initialize', scope='session')
17+
def fixture_initialize(request, shell: Shell, dut: DeviceAdapter):
18+
"""Session initializtion"""
19+
# Get HCI transport for bumble
20+
hci = request.config.getoption('--hci-transport')
21+
22+
if hci is None:
23+
for fixture in dut.device_config.fixtures:
24+
if fixture.startswith('usb_hci:'):
25+
hci = fixture.split(sep=':', maxsplit=1)[1]
26+
break
27+
28+
assert hci is not None
29+
30+
lines = shell.exec_command("bt init")
31+
lines = dut.readlines_until("Bluetooth initialized")
32+
regex = r"Identity: (?P<bd_addr>(.*\s\(.*\)))"
33+
bd_addr = None
34+
for line in lines:
35+
logger.info(f"Shell log {line}")
36+
m = re.search(regex, line)
37+
if m:
38+
bd_addr = m.group('bd_addr')
39+
40+
if bd_addr is None:
41+
logger.error('Fail to get IUT BD address')
42+
raise AssertionError
43+
44+
lines = shell.exec_command("br pscan on")
45+
lines = shell.exec_command("br iscan on")
46+
logger.info('initialized')
47+
48+
lines = shell.exec_command(f"l2cap_br register {format(L2CAP_SERVER_PSM, 'x')} {MODE}")
49+
logger.info("l2cap server register")
50+
return hci, bd_addr
51+
52+
53+
@pytest.fixture
54+
def l2cap_br_dut(initialize):
55+
logger.info('Start running testcase')
56+
yield initialize
57+
logger.info('Done')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Copyright 2025 NXP
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
import asyncio
6+
import logging
7+
8+
from bumble.core import BT_BR_EDR_TRANSPORT
9+
from bumble.hci import (
10+
HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR,
11+
)
12+
from bumble.pairing import PairingDelegate
13+
14+
logger = logging.getLogger(__name__)
15+
16+
L2CAP_SERVER_PSM = 0x1001
17+
MODE = "basic"
18+
L2CAP_CHAN_IUT_ID = 0
19+
MAX_MTU = 0xFFFF
20+
MIN_MTU = 0x30
21+
STRESS_TEST_MAX_COUNT = 50
22+
23+
24+
class Delegate(PairingDelegate):
25+
def __init__(
26+
self,
27+
dut,
28+
io_capability,
29+
):
30+
super().__init__(
31+
io_capability,
32+
)
33+
self.dut = dut
34+
35+
36+
async def device_power_on(device) -> None:
37+
while True:
38+
try:
39+
await device.power_on()
40+
break
41+
except Exception:
42+
continue
43+
44+
45+
async def wait_for_shell_response(dut, message):
46+
found = False
47+
lines = []
48+
try:
49+
while found is False:
50+
read_lines = dut.readlines()
51+
for line in read_lines:
52+
if message in line:
53+
found = True
54+
break
55+
lines = lines + read_lines
56+
await asyncio.sleep(0.1)
57+
except Exception as e:
58+
logger.error(f'{e}!', exc_info=True)
59+
raise e
60+
return found, lines
61+
62+
63+
async def send_cmd_to_iut(shell, dut, cmd, parse=None, wait=True):
64+
found = False
65+
lines = shell.exec_command(cmd)
66+
if wait:
67+
if parse is not None:
68+
found, lines = await wait_for_shell_response(dut, parse)
69+
else:
70+
found = True
71+
else:
72+
found = False
73+
if parse is not None:
74+
for line in lines:
75+
if parse in line:
76+
found = True
77+
break
78+
else:
79+
found = True
80+
logger.info(f'{lines}')
81+
assert found is True
82+
return lines
83+
84+
85+
async def bumble_acl_connect(shell, dut, device, target_address):
86+
connection = None
87+
try:
88+
connection = await device.connect(target_address, transport=BT_BR_EDR_TRANSPORT)
89+
logger.info(f'=== Connected to {connection.peer_address}!')
90+
except Exception as e:
91+
logger.error(f'Fail to connect to {target_address}!')
92+
raise e
93+
return connection
94+
95+
96+
async def bumble_acl_disconnect(shell, dut, device, connection):
97+
await device.disconnect(
98+
connection, reason=HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR
99+
)
100+
found, lines = await wait_for_shell_response(dut, "Disconnected:")
101+
logger.info(f'lines : {lines}')
102+
assert found is True
103+
return found, lines
104+
105+
106+
async def bumble_l2cap_disconnect(shell, dut, incoming_channel, iut_id=L2CAP_CHAN_IUT_ID):
107+
try:
108+
await incoming_channel.disconnect()
109+
except Exception as e:
110+
logger.error('Fail to send l2cap disconnect command!')
111+
raise e
112+
assert incoming_channel.disconnection_result is None
113+
114+
found, _ = await wait_for_shell_response(dut, f"Channel {iut_id} disconnected")
115+
assert found is True

0 commit comments

Comments
 (0)