|
4 | 4 | """BLE advertising tests for nrf5340bsim.""" |
5 | 5 |
|
6 | 6 | import logging |
| 7 | +import re |
7 | 8 |
|
8 | 9 | import pytest |
9 | 10 |
|
|
44 | 45 | """ |
45 | 46 |
|
46 | 47 |
|
| 48 | +BSIM_TX_POWER_DEFAULT_CODE = """\ |
| 49 | +import _bleio |
| 50 | +import time |
| 51 | +
|
| 52 | +adapter = _bleio.adapter |
| 53 | +
|
| 54 | +name = b"CPTXPWR" |
| 55 | +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name |
| 56 | +
|
| 57 | +print("advertising default") |
| 58 | +adapter.start_advertising(advertisement) |
| 59 | +time.sleep(4) |
| 60 | +adapter.stop_advertising() |
| 61 | +print("done") |
| 62 | +""" |
| 63 | + |
| 64 | +BSIM_TX_POWER_LOW_CODE = """\ |
| 65 | +import _bleio |
| 66 | +import time |
| 67 | +
|
| 68 | +adapter = _bleio.adapter |
| 69 | +
|
| 70 | +name = b"CPTXPWR" |
| 71 | +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name |
| 72 | +
|
| 73 | +print("advertising low") |
| 74 | +adapter.start_advertising(advertisement, tx_power=-20) |
| 75 | +time.sleep(4) |
| 76 | +adapter.stop_advertising() |
| 77 | +print("done") |
| 78 | +""" |
| 79 | + |
| 80 | + |
47 | 81 | @pytest.mark.zephyr_sample("bluetooth/observer") |
48 | 82 | @pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_CODE}) |
49 | 83 | def test_bsim_advertise_and_scan(bsim_phy, circuitpython, zephyr_sample): |
@@ -90,3 +124,51 @@ def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): |
90 | 124 | assert cp_output.count("adv run done") >= 1 |
91 | 125 | assert observer_output.count("Device found:") >= observer_count_before + 1 |
92 | 126 | assert "Already advertising" not in cp_output |
| 127 | + |
| 128 | + |
| 129 | +@pytest.mark.zephyr_sample("bluetooth/observer") |
| 130 | +@pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_DEFAULT_CODE}) |
| 131 | +def test_bsim_tx_power_default_rssi(bsim_phy, circuitpython, zephyr_sample): |
| 132 | + """Verify default TX power produces expected RSSI.""" |
| 133 | + observer = zephyr_sample |
| 134 | + |
| 135 | + circuitpython.wait_until_done() |
| 136 | + |
| 137 | + cp_output = circuitpython.serial.all_output |
| 138 | + obs_output = observer.serial.all_output |
| 139 | + |
| 140 | + assert "advertising default" in cp_output |
| 141 | + assert "done" in cp_output |
| 142 | + |
| 143 | + # Observer: "Device found: <addr> (RSSI <n>), type <t>, AD data len <l>" |
| 144 | + # Advertisement is 12 bytes: flags (3) + name (9). |
| 145 | + # With 40 dB channel attenuation and 0 dBm TX → RSSI ~ -39 |
| 146 | + rssi_pattern = re.compile(r"RSSI (-?\d+)\), type \d+, AD data len 12") |
| 147 | + all_rssi = [int(m.group(1)) for m in rssi_pattern.finditer(obs_output)] |
| 148 | + logger.info("RSSI values: %s", all_rssi) |
| 149 | + |
| 150 | + assert len(all_rssi) > 0, "Observer saw no advertisements" |
| 151 | + assert all_rssi[0] == -39, f"Expected RSSI -39 (0 dBm TX), got {all_rssi[0]}" |
| 152 | + |
| 153 | + |
| 154 | +@pytest.mark.zephyr_sample("bluetooth/observer") |
| 155 | +@pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_LOW_CODE}) |
| 156 | +def test_bsim_tx_power_low_rssi(bsim_phy, circuitpython, zephyr_sample): |
| 157 | + """Verify low TX power reduces RSSI.""" |
| 158 | + observer = zephyr_sample |
| 159 | + |
| 160 | + circuitpython.wait_until_done() |
| 161 | + |
| 162 | + cp_output = circuitpython.serial.all_output |
| 163 | + obs_output = observer.serial.all_output |
| 164 | + |
| 165 | + assert "advertising low" in cp_output |
| 166 | + assert "done" in cp_output |
| 167 | + |
| 168 | + # With 40 dB channel attenuation and -20 dBm TX → RSSI ~ -59 |
| 169 | + rssi_pattern = re.compile(r"RSSI (-?\d+)\), type \d+, AD data len 12") |
| 170 | + all_rssi = [int(m.group(1)) for m in rssi_pattern.finditer(obs_output)] |
| 171 | + logger.info("RSSI values: %s", all_rssi) |
| 172 | + |
| 173 | + assert len(all_rssi) > 0, "Observer saw no advertisements" |
| 174 | + assert all_rssi[0] < -39, f"Expected lower RSSI with -20 dBm TX, got {all_rssi[0]}" |
0 commit comments