summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Henri Chataing <henrichataing@google.com> 2023-04-10 09:09:53 -0700
committer Henri Chataing <henrichataing@google.com> 2023-04-13 20:56:15 +0000
commitba5bbf613efdc36f342a32465a1e030445154b13 (patch)
treed7e65d3fd6a2cce49059cec7fea86d199267e283
parent31285e07cc0efb67786772b0187159fdf5cd73ca (diff)
RootCanal: Implement LL tests for LE periodic advertising
Added tests: - LL/DDI/ADV/BV-26-C - LL/DDI/SCN/BV-79-C Fixed test: - LL/DDI/ADV/BV-06-C (broken after HCI disconnection code fixup patch) Enabled test: - LL/DDI/ADV/BV-20-C (enabled by implementation of HCI LE Set Default Phy) Bug: 275847929 Test: atest --host rootcanal_ll_test Change-Id: Icde224c36b2b554dc3e28e521c716dc2eef617df
-rw-r--r--tools/rootcanal/py/controller.py40
-rw-r--r--tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py2
-rw-r--r--tools/rootcanal/test/LL/DDI/ADV/BV_26_C.py224
-rw-r--r--tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py188
-rw-r--r--tools/rootcanal/test/main.py5
5 files changed, 441 insertions, 18 deletions
diff --git a/tools/rootcanal/py/controller.py b/tools/rootcanal/py/controller.py
index 99e93a4221..cc0dbe2360 100644
--- a/tools/rootcanal/py/controller.py
+++ b/tools/rootcanal/py/controller.py
@@ -38,6 +38,7 @@ class LeFeatures:
self.mask = le_features
self.ll_privacy = (le_features & hci.LLFeaturesBits.LL_PRIVACY) != 0
self.le_extended_advertising = (le_features & hci.LLFeaturesBits.LE_EXTENDED_ADVERTISING) != 0
+ self.le_periodic_advertising = (le_features & hci.LLFeaturesBits.LE_PERIODIC_ADVERTISING) != 0
def generate_rpa(irk: bytes) -> hci.Address:
@@ -223,24 +224,33 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase):
assert evt.num_hci_command_packets == 1
return evt
- async def expect_ll(self, expected_pdu: typing.Union[ll.LinkLayerPacket, type], timeout: int = 3):
+ async def expect_ll(self,
+ expected_pdus: typing.Union[list, typing.Union[ll.LinkLayerPacket, type]],
+ timeout: int = 3) -> int:
+ if not isinstance(expected_pdus, list):
+ expected_pdus = [expected_pdus]
+
packet = await asyncio.wait_for(self.controller.receive_ll(), timeout=timeout)
pdu = ll.LinkLayerPacket.parse_all(packet)
- if isinstance(expected_pdu, type) and not isinstance(pdu, expected_pdu):
- print("received pdu of unexpected type")
- print(f"expected pdu: {expected_pdu.__name__}")
- print("received pdu:")
- pdu.show()
- self.assertTrue(False)
-
- if isinstance(expected_pdu, ll.LinkLayerPacket) and pdu != expected_pdu:
- print("received unexpected pdu")
- print("expected pdu:")
- expected_pdu.show()
- print("received pdu:")
- pdu.show()
- self.assertTrue(False)
+ matched_index = -1
+ for (index, expected_pdu) in enumerate(expected_pdus):
+ if isinstance(expected_pdu, type) and isinstance(pdu, expected_pdu):
+ return index
+ if isinstance(expected_pdu, ll.LinkLayerPacket) and pdu == expected_pdu:
+ return index
+
+ print("received unexpected pdu:")
+ pdu.show()
+ print("expected pdus:")
+ for expected_pdu in expected_pdus:
+ if isinstance(expected_pdu, type):
+ print(f"- {expected_pdu.__name__}")
+ if isinstance(expected_pdu, ll.LinkLayerPacket):
+ print(f"- {expected_pdu.__class__.__name__}")
+ expected_pdu.show()
+
+ self.assertTrue(False)
def tearDown(self):
self.controller.stop()
diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py
index 6c078af77c..38acd5bea8 100644
--- a/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py
+++ b/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py
@@ -104,7 +104,7 @@ class Test(ControllerTest):
await self.expect_evt(
hci.DisconnectionComplete(status=ErrorCode.SUCCESS,
connection_handle=connection_handle,
- reason=hci.DisconnectReason.REMOTE_USER_TERMINATED_CONNECTION))
+ reason=hci.ErrorCode.CONNECTION_TERMINATED_BY_LOCAL_HOST))
# 9. Configure Lower Tester to use a public device address that differs from the IUT address in the
# most significant octet as parameter of CONNECT_IND.
diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_26_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_26_C.py
new file mode 100644
index 0000000000..f3b1365ed9
--- /dev/null
+++ b/tools/rootcanal/test/LL/DDI/ADV/BV_26_C.py
@@ -0,0 +1,224 @@
+import asyncio
+import hci_packets as hci
+import link_layer_packets as ll
+import math
+import random
+import unittest
+from dataclasses import dataclass
+from hci_packets import ErrorCode, FragmentPreference
+from py.bluetooth import Address
+from py.controller import ControllerTest
+from typing import List
+
+
+@dataclass
+class TestRound:
+ data_length: int
+
+
+class Test(ControllerTest):
+ # Test parameters.
+ LL_advertiser_advInterval_MIN = 0x200
+ LL_advertiser_advInterval_MAX = 0x200
+ LL_advertiser_Adv_Channel_Map = 0x7
+ LL_initiator_connInterval = 0x200
+ LL_initiator_connPeripheralLatency = 0x200
+ LL_initiator_connSupervisionTimeout = 0x200
+
+ # LL/DDI/ADV/BV-26-C [Extended Advertising, Periodic Advertising – LE 1M PHY]
+ async def test(self):
+ controller = self.controller
+
+ if not controller.le_features.le_periodic_advertising:
+ self.skipTest("LE periodic advertising not supported")
+
+ # 1. The Upper Tester sends an HCI_LE_Read_Maximum_Advertising_Data_Length command to the
+ # IUT and receives a Maximum_Advertising_Data_Length between 0x001F and 0x0672 in return.
+ # The Upper Tester stores the Maximum_Advertising_Data_Length for future use.
+ # For each round from 1–6 based on Table 4.10.
+ controller.send_cmd(hci.LeReadMaximumAdvertisingDataLength())
+
+ event = await self.expect_cmd_complete(hci.LeReadMaximumAdvertisingDataLengthComplete)
+ maximum_advertising_data_length = event.maximum_advertising_data_length
+
+ # Test rounds.
+ test_rounds = [
+ TestRound(0),
+ TestRound(252),
+ TestRound(474),
+ TestRound(711),
+ TestRound(948),
+ TestRound(maximum_advertising_data_length),
+ ]
+
+ # 17. Repeat steps 2–16 for each Round shown in Table 4.10.
+ for test_round in test_rounds:
+ await self.steps_2_16(maximum_advertising_data_length, **vars(test_round))
+
+ async def steps_2_16(self, maximum_advertising_data_length: int, data_length: int):
+ controller = self.controller
+
+ # 2. If the Data Length listed in Table 4.10 for the current Round is less than or equal to the
+ # Maximum_Advertising_Data_Length proceed to step 3, otherwise skip to step 17.
+ if data_length > maximum_advertising_data_length:
+ return
+
+ # 3. The Upper Tester sends an HCI_LE_Set_Extended_Advertising_Parameters command to the
+ # IUT using all supported advertising channels and a selected advertising interval between the
+ # minimum and maximum advertising intervals supported. Advertising_Event_Properties parameter
+ # shall be set to 0x0000. The Primary_Advertising_PHY and Secondary_Advertising_PHY shall be
+ # set to the values specified in Table 4.9.
+ controller.send_cmd(
+ hci.LeSetExtendedAdvertisingParameters(advertising_handle=0,
+ advertising_event_properties=hci.AdvertisingEventProperties(),
+ primary_advertising_interval_min=self.LL_advertiser_advInterval_MIN,
+ primary_advertising_interval_max=self.LL_advertiser_advInterval_MAX,
+ primary_advertising_channel_map=self.LL_advertiser_Adv_Channel_Map,
+ own_address_type=hci.OwnAddressType.PUBLIC_DEVICE_ADDRESS,
+ advertising_filter_policy=hci.AdvertisingFilterPolicy.ALL_DEVICES,
+ primary_advertising_phy=hci.PrimaryPhyType.LE_1M))
+
+ await self.expect_evt(
+ hci.LeSetExtendedAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ # 4. The Upper Tester sends an HCI_LE_Set_Periodic_Advertising_Parameters command to the IUT
+ # using all supported advertising channels and selected periodic interval.
+ # Periodic_Advertising_Properties parameter shall be set to 0x0000.
+ controller.send_cmd(
+ hci.LeSetPeriodicAdvertisingParameters(advertising_handle=0,
+ periodic_advertising_interval_min=0x100,
+ periodic_advertising_interval_max=0x100,
+ include_tx_power=False))
+
+ await self.expect_evt(
+ hci.LeSetPeriodicAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ # 5. The Upper Tester sends one or more HCI_LE_Set_Periodic_Advertising_Data commands to the
+ # IUT with values according to Table 4.10 and using random octets from 1 to 254 as the payload. If
+ # the Data Length is greater than 252 the Upper Tester shall send multiple commands using one
+ # Operation 0x01 (First fragment) command, followed by zero or more Operation 0x00
+ # (Intermediate Fragment) commands, and a final Operation 0x02 (Last fragment) command.
+ # Otherwise the Upper Tester shall send a single command using Operation 0x03 (Complete Data).
+ advertising_data = [random.randint(1, 254) for n in range(data_length)]
+ num_fragments = math.ceil(data_length / 251) or 1 # Make sure to set the advertising data if it is empty.
+ for n in range(num_fragments):
+ fragment_offset = 251 * n
+ fragment_length = min(251, data_length - fragment_offset)
+ if num_fragments == 1:
+ operation = hci.Operation.COMPLETE_ADVERTISEMENT
+ elif n == 0:
+ operation = hci.Operation.FIRST_FRAGMENT
+ elif n == num_fragments - 1:
+ operation = hci.Operation.LAST_FRAGMENT
+ else:
+ operation = hci.Operation.INTERMEDIATE_FRAGMENT
+
+ controller.send_cmd(
+ hci.LeSetPeriodicAdvertisingDataRaw(advertising_handle=0,
+ operation=operation,
+ advertising_data=advertising_data[fragment_offset:fragment_offset +
+ fragment_length]))
+
+ await self.expect_evt(
+ hci.LeSetPeriodicAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ # 6. The Upper Tester enables periodic advertising using the
+ # HCI_LE_Set_Periodic_Advertising_Enable command with the Enable parameter set to 0x01
+ # (Periodic Advertising).
+ controller.send_cmd(hci.LeSetPeriodicAdvertisingEnable(enable=True, include_adi=False, advertising_handle=0))
+
+ await self.expect_evt(
+ hci.LeSetPeriodicAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ # Note: no periodic advertising event is expected until extended
+ # advertising is also enabled for the advertising set.
+
+ # 7. The Upper Tester enables advertising using the HCI_LE_Set_Extended_Advertising_Enable
+ # command. The Duration[0] parameter is set to 0x0000 (No Advertising Duration).
+ controller.send_cmd(
+ hci.LeSetExtendedAdvertisingEnable(
+ enable=hci.Enable.ENABLED,
+ enabled_sets=[hci.EnabledSet(advertising_handle=0, duration=0, max_extended_advertising_events=0)]))
+
+ await self.expect_evt(
+ hci.LeSetExtendedAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ # 8. The Lower Tester receives an ADV_EXT_IND packet from the IUT with AdvMode set to 00b with
+ # the AuxPtr Extended Header field present.
+
+ # 9. The Lower Tester utilizes the AuxPtr field to listen for an AUX_ADV_IND PDU on the secondary
+ # advertising channel with the AdvMode field set to 00b and the SyncInfo Extended Header fields
+ # present.
+
+ # 10. The Lower Tester utilizes the SyncInfo field to listen for an AUX_SYNC_IND PDU on the
+ # secondary advertising channel using the index selected by the LE Channel Selection Algorithm
+ # #2 and synchronizes with the periodic advertisements. The AUX_SYNC_IND PDU shall have the
+ # AdvMode field set to 00b with no ADI field. If the AUX_SYNC_IND PDU AdvData field does not
+ # contain all the data submitted in step 5 (if any), it shall include an AuxPtr field.
+
+ # 11. If the AUX_SYNC_IND PDU contains an AuxPtr field, the Lower Tester utilizes it to listen for an
+ # AUX_CHAIN_IND PDU with the AdvMode field set to 00b and containing additional data
+ # submitted in step 5. If the AUX_CHAIN_IND PDU contains an AuxPtr field this step is repeated
+ # until an AUX_CHAIN_IND PDU is received with no AuxPtr field and all data has been received.
+
+ # 12. Repeat steps 8–11 100 times.
+ received = [0, 0]
+ for n in range(15):
+ index = await self.expect_ll([
+ ll.LeExtendedAdvertisingPdu(source_address=controller.address,
+ advertising_address_type=ll.AddressType.PUBLIC,
+ target_address_type=ll.AddressType.PUBLIC,
+ connectable=False,
+ scannable=False,
+ directed=False,
+ sid=0,
+ tx_power=0,
+ primary_phy=ll.PrimaryPhyType.LE_1M,
+ secondary_phy=ll.SecondaryPhyType.NO_PACKETS,
+ periodic_advertising_interval=0x100,
+ advertising_data=[]),
+ ll.LePeriodicAdvertisingPdu(source_address=controller.address,
+ advertising_address_type=ll.AddressType.PUBLIC,
+ sid=0,
+ tx_power=0,
+ advertising_interval=0x100,
+ advertising_data=advertising_data)
+ ])
+ received[index] = received[index] + 1
+
+ # Note: the extended advertising interval is twice the periodic
+ # advertising interval; the number of events received of each kind is
+ # deterministic.
+ self.assertTrue(received[0] == 5)
+ self.assertTrue(received[1] == 10)
+
+ # 13. The Upper Tester disables extended advertising using the
+ # HCI_LE_Set_Extended_Advertising_Enable command but maintains periodic advertising.
+ controller.send_cmd(hci.LeSetExtendedAdvertisingEnable(enable=hci.Enable.DISABLED, enabled_sets=[]))
+
+ await self.expect_evt(
+ hci.LeSetExtendedAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ # 14. The Lower Tester confirms that periodic advertising continues when extended advertising is
+ # disabled by repeating steps 10–11 100 times.
+ for n in range(10):
+ await self.expect_ll(
+ ll.LePeriodicAdvertisingPdu(source_address=controller.address,
+ advertising_address_type=ll.AddressType.PUBLIC,
+ sid=0,
+ tx_power=0,
+ advertising_interval=0x100,
+ advertising_data=advertising_data))
+
+ # 15. The Upper Tester disables periodic advertising using the
+ # HCI_LE_Set_Periodic_Advertising_Enable command.
+ controller.send_cmd(hci.LeSetPeriodicAdvertisingEnable(enable=False, include_adi=False, advertising_handle=0))
+
+ await self.expect_evt(
+ hci.LeSetPeriodicAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ # 16. The Upper Tester clears the advertising configuration using the HCI_LE_Clear_Advertising_Sets
+ # command.
+ controller.send_cmd(hci.LeClearAdvertisingSets())
+
+ await self.expect_evt(hci.LeClearAdvertisingSetsComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py
new file mode 100644
index 0000000000..ff2ccba5d7
--- /dev/null
+++ b/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py
@@ -0,0 +1,188 @@
+import hci_packets as hci
+import link_layer_packets as ll
+import math
+import random
+from dataclasses import dataclass
+from hci_packets import ErrorCode
+from py.bluetooth import Address
+from py.controller import ControllerTest
+from typing import Optional
+
+ADV_IND = 0x13
+ADV_DIRECT_IND = 0x15
+ADV_SCAN_IND = 0x12
+ADV_NONCONN_IND = 0x10
+ADV_EXT_IND = 0x0
+
+
+class Test(ControllerTest):
+
+ # LL/DDI/SCN/BV-79-C [Extended Scanning, Passive, Periodic Advertising Report,
+ # RSSI and TX_Power – LE 1M PHY]
+ async def test(self):
+ # Test rounds.
+ # Note: some tests are skipped as no distinction is made between
+ # ADV_EXT_IND, AUX_ADV_IND, AUX_CHAIN_IND.
+ controller = self.controller
+ lower_tester_address = Address('11:22:33:44:55:66')
+ advertising_sid = 0x3
+ tx_power = 0x0a
+ periodic_advertising_interval = 0x100
+
+ # 1. The Upper Tester sends an HCI_LE_Set_Extended_Scan_Parameters command to the IUT with
+ # Scanning_PHYs set as specified in Table 4.35, Scan_Type[0] set to 0x00 (Passive Scanning),
+ # Scan_Interval[0] set to 0x0010, Scan_Window[0] set to 0x0010, Own_Address_Type set to 0x00
+ # (Public Device Address), and Scanning_Filter_Policy shall be set to 0x00 (Accept All) and
+ # receives a successful HCI_Command_Complete event in return.
+ controller.send_cmd(
+ hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.PUBLIC_DEVICE_ADDRESS,
+ scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL,
+ scanning_phys=0x1,
+ parameters=[
+ hci.PhyScanParameters(le_scan_type=hci.LeScanType.PASSIVE,
+ le_scan_interval=0x0010,
+ le_scan_window=0x0010)
+ ]))
+
+ await self.expect_evt(
+ hci.LeSetExtendedScanParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ # 2. The Upper Tester sends an HCI_LE_Set_Extended_Scan_Enable command to the IUT to enable
+ # scanning with Filter_Duplicates, Duration, and Period are set to zero and receives a successful
+ # HCI_Command_Complete event in return.
+ controller.send_cmd(
+ hci.LeSetExtendedScanEnable(enable=hci.Enable.ENABLED,
+ filter_duplicates=hci.Enable.DISABLED,
+ duration=0,
+ period=0))
+
+ await self.expect_evt(hci.LeSetExtendedScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ for n in range(3):
+ # 3. The Lower Tester begins advertising using ADV_EXT_IND and AUX_ADV_IND PDUs. The
+ # ADV_EXT_IND PDUs include an AuxPtr that refers to the AUX_ADV_IND PDU on the secondary
+ # advertising channel. The AUX_ADV_IND PDUs include the AdvA field containing the Lower
+ # Tester address, and the SyncInfo field referring to the AUX_SYNC_IND PDU. The Lower Tester
+ # continues advertising until directed to stop in the test procedure.
+ controller.send_ll(ll.LeExtendedAdvertisingPdu(source_address=lower_tester_address,
+ advertising_address_type=ll.AddressType.PUBLIC,
+ connectable=False,
+ scannable=False,
+ directed=False,
+ sid=advertising_sid,
+ tx_power=tx_power,
+ primary_phy=ll.PrimaryPhyType.LE_1M,
+ secondary_phy=ll.SecondaryPhyType.NO_PACKETS,
+ periodic_advertising_interval=0x100,
+ advertising_data=[]),
+ rssi=0x10)
+
+ # 4. The IUT sends an HCI_LE_Extended_Advertising_Report event to the Upper Tester containing a
+ # nonzero Periodic_Advertising_Interval, Data Status in the Event_Type[i] field set to the value
+ # 0b00 (Complete), and RSSI[i] set to a valid value.
+ await self.expect_evt(
+ hci.LeExtendedAdvertisingReportRaw(responses=[
+ hci.LeExtendedAdvertisingResponseRaw(
+ connectable=False,
+ scannable=False,
+ directed=False,
+ scan_response=False,
+ legacy=False,
+ data_status=hci.DataStatus.COMPLETE,
+ address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS,
+ address=lower_tester_address,
+ primary_phy=hci.PrimaryPhyType.LE_1M,
+ secondary_phy=hci.SecondaryPhyType.NO_PACKETS,
+ advertising_sid=advertising_sid,
+ tx_power=tx_power,
+ rssi=0x10,
+ periodic_advertising_interval=periodic_advertising_interval,
+ direct_address_type=hci.DirectAdvertisingAddressType.NO_ADDRESS_PROVIDED,
+ direct_address=Address(),
+ advertising_data=[])
+ ]))
+
+ # 5. The Upper Tester sends an HCI_LE_Periodic_Advertising_Create_Sync command to the IUT to
+ # synchronize with the Lower Tester’s periodic advertisements with Options set to 0x00 (Do not
+ # Use List), Advertising_SID set to the Advertising_SID from step 3, Advertiser_Address_Type set
+ # to 0x00 (Public Device Address), Advertiser_Address set to the Lower Tester’s address, Skip set
+ # to the value 0x0003, Sync_Timeout set to (Skip + 3) x Periodic_Advertising_Interval from step 4,
+ # and Sync_CTE_Type set to 0x00 and receives a successful HCI_Command_Complete event in
+ # return.
+ controller.send_cmd(
+ hci.LePeriodicAdvertisingCreateSync(
+ options=hci.PeriodicAdvertisingOptions(use_periodic_advertiser_list=False,
+ disable_reporting=False,
+ enable_duplicate_filtering=False),
+ advertising_sid=advertising_sid,
+ advertiser_address_type=hci.AdvertiserAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
+ advertiser_address=lower_tester_address,
+ skip=0x3,
+ sync_timeout=6 * periodic_advertising_interval,
+ sync_cte_type=0))
+
+ await self.expect_evt(
+ hci.LePeriodicAdvertisingCreateSyncStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1))
+
+ # 6. The Lower Tester generates an AUX_SYNC_IND PDU on the secondary advertising channel with
+ # AuxPtr set to a value referring to the first AUX_CHAIN_IND PDU in the train, TxPower set to 10,
+ # and AdvData set to N octets of random data.
+ controller.send_ll(
+ ll.LePeriodicAdvertisingPdu(source_address=lower_tester_address,
+ advertising_address_type=ll.AddressType.PUBLIC,
+ sid=advertising_sid,
+ tx_power=tx_power,
+ advertising_interval=periodic_advertising_interval,
+ advertising_data=[]))
+
+ # 7. The IUT sends a successful HCI_LE_Periodic_Advertising_Sync_Established event to the Upper
+ # Tester containing a Status of 0x00 (Success), Sync_Handle set to a valid value, and the
+ # Advertising_SID received in step 3.
+ await self.expect_evt(
+ hci.LePeriodicAdvertisingSyncEstablished(
+ status=ErrorCode.SUCCESS,
+ sync_handle=0,
+ advertising_sid=advertising_sid,
+ advertiser_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS,
+ advertiser_address=lower_tester_address,
+ advertiser_phy=hci.SecondaryPhyType.LE_1M,
+ periodic_advertising_interval=periodic_advertising_interval,
+ advertiser_clock_accuracy=hci.ClockAccuracy.PPM_500,
+ ))
+
+ for n in range(3):
+ advertising_data_length = 256
+ advertising_data = [random.randint(1, 254) for n in range(advertising_data_length)]
+
+ # 8. The Lower Tester sends two AUX_CHAIN_IND PDUs to the IUT with AdvData set to min(249,
+ # (Scan_Max_Data – N) / 2) octets of random data for each AUX_CHAIN_IND PDU and the
+ # TxPower value of the AUX_CHAIN_IND PDUs set to 15. The PDUs should be sent as far apart
+ # as practical.
+ controller.send_ll(ll.LePeriodicAdvertisingPdu(source_address=lower_tester_address,
+ advertising_address_type=ll.AddressType.PUBLIC,
+ sid=advertising_sid,
+ tx_power=tx_power,
+ advertising_interval=periodic_advertising_interval,
+ advertising_data=advertising_data),
+ rssi=0x10)
+
+ # 9. The IUT sends multiple HCI_LE_Periodic_Advertising_Report events to the Upper Tester with
+ # Data Status in the Event_Type[i] field set to 0b01 (Incomplete, more data to come), TX_Power[i]
+ # set to the value of the TxPower field for the AUX_SYNC_IND received in step 6, and RSSI[i] set
+ # to a valid value. Subsequent reports with data and the status set to “Incomplete, more data to
+ # come” or “complete” can have the TX_Power field set to 0x7F.
+ offset = 0
+ max_fragment_length = 247
+ num_fragments = math.ceil(advertising_data_length / max_fragment_length) or 1
+ for n in range(num_fragments):
+ remaining_length = advertising_data_length - offset
+ fragment_length = min(max_fragment_length, remaining_length)
+ data_status = hci.DataStatus.CONTINUING if remaining_length > max_fragment_length else hci.DataStatus.COMPLETE
+ await self.expect_evt(
+ hci.LePeriodicAdvertisingReport(sync_handle=0,
+ tx_power=tx_power,
+ rssi=0x10,
+ cte_type=hci.CteType.NO_CONSTANT_TONE_EXTENSION,
+ data_status=data_status,
+ data=advertising_data[offset:offset + fragment_length]))
+ offset += fragment_length
diff --git a/tools/rootcanal/test/main.py b/tools/rootcanal/test/main.py
index d3062cd136..aefd3d4972 100644
--- a/tools/rootcanal/test/main.py
+++ b/tools/rootcanal/test/main.py
@@ -21,15 +21,16 @@ tests = [
'LL.DDI.ADV.BV_17_C',
'LL.DDI.ADV.BV_18_C',
'LL.DDI.ADV.BV_19_C',
- # TODO: Implement HCI command Le Set Default Phy
- # 'LL.DDI.ADV.BV_20_C',
+ 'LL.DDI.ADV.BV_20_C',
'LL.DDI.ADV.BV_21_C',
'LL.DDI.ADV.BV_22_C',
+ 'LL.DDI.ADV.BV_26_C',
'LL.DDI.ADV.BV_47_C',
'LL.DDI.SCN.BV_13_C',
'LL.DDI.SCN.BV_14_C',
'LL.DDI.SCN.BV_18_C',
'LL.DDI.SCN.BV_19_C',
+ 'LL.DDI.SCN.BV_79_C',
]
if __name__ == "__main__":