Loading tools/rootcanal/model/controller/dual_mode_controller.cc +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ using std::vector; namespace rootcanal { constexpr uint16_t kNumCommandPackets = 0x01; constexpr uint16_t kLeMaximumAdvertisingDataLength = 256; constexpr uint16_t kLeMaximumAdvertisingDataLength = 512; constexpr uint16_t kLeMaximumDataLength = 64; constexpr uint16_t kLeMaximumDataTime = 0x148; Loading tools/rootcanal/model/controller/le_advertiser.cc +21 −4 Original line number Diff line number Diff line Loading @@ -1015,10 +1015,11 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( // If the advertising is high duty cycle connectable directed advertising, // then Duration[i] shall be less than or equal to 1.28 seconds and shall // not be equal to 0. std::chrono::milliseconds duration = std::chrono::milliseconds(set.duration_ * 10); if (connectable_advertising && directed_advertising && high_duty_cycle_advertising && (set.duration_ == 0 || slots(set.duration_) > adv_direct_ind_high_timeout)) { (set.duration_ == 0 || duration > adv_direct_ind_high_timeout)) { LOG_INFO( "extended advertising is high duty cycle connectable directed" " but the duration is either 0 or larger than 1.28 seconds"); Loading Loading @@ -1141,10 +1142,19 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( ExtendedAdvertiser& advertiser = extended_advertisers_[set.advertising_handle_]; advertiser.max_extended_advertising_events = set.max_extended_advertising_events_; advertiser.num_completed_extended_advertising_events = 0; advertiser.advertising_enable = true; advertiser.next_event = std::chrono::steady_clock::now() + advertiser.primary_advertising_interval; if (set.duration_ > 0) { std::chrono::milliseconds duration = std::chrono::milliseconds(set.duration_ * 10); advertiser.timeout = std::chrono::steady_clock::now() + duration; } else { advertiser.timeout.reset(); } } return ErrorCode::SUCCESS; Loading Loading @@ -1374,7 +1384,7 @@ void LinkLayerController::LeAdvertising() { for (auto& [_, advertiser] : extended_advertisers_) { // Extended Advertising Timeouts if (advertiser.IsEnabled() && advertiser.timeout && if (advertiser.IsEnabled() && advertiser.timeout.has_value() && now >= advertiser.timeout.value()) { // If the Duration[i] parameter is set to a value other than 0x0000, an // HCI_LE_Advertising_Set_Terminated event shall be generated when the Loading Loading @@ -1412,9 +1422,16 @@ void LinkLayerController::LeAdvertising() { } if (IsLeEventUnmasked(SubeventCode::ADVERTISING_SET_TERMINATED)) { // The parameter Num_Completed_Extended_Advertising_Events is set // only when Max_Extended_Advertising_Events was configured as // non-zero in the advertising parameters. uint8_t num_completed_extended_advertising_events = advertiser.max_extended_advertising_events != 0 ? advertiser.num_completed_extended_advertising_events : 0; send_event_(bluetooth::hci::LeAdvertisingSetTerminatedBuilder::Create( ErrorCode::ADVERTISING_TIMEOUT, advertiser.advertising_handle, 0, advertiser.num_completed_extended_advertising_events)); num_completed_extended_advertising_events)); } } Loading tools/rootcanal/py/controller.py +16 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,22 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase): evt.show() self.assertTrue(False) async def expect_cmd_complete(self, expected_evt: type, timeout: int = 3) -> hci.Event: packet = await asyncio.wait_for(self.controller.receive_evt(), timeout=timeout) evt = hci.Event.parse_all(packet) if not isinstance(evt, expected_evt): print("received unexpected event") print("expected event:") print(expected_evt) print("received event:") evt.show() self.assertTrue(False) assert evt.status == ErrorCode.SUCCESS assert evt.num_hci_command_packets == 1 return evt async def expect_ll(self, expected_pdu: ll.LinkLayerPacket, timeout: int = 3): packet = await asyncio.wait_for(self.controller.receive_ll(), timeout=timeout) pdu = ll.LinkLayerPacket.parse_all(packet) Loading tools/rootcanal/test/LL/DDI/ADV/BV_21_C.py +1 −4 Original line number Diff line number Diff line import lib_rootcanal_python3 as rootcanal import hci_packets as hci import link_layer_packets as ll import unittest Loading @@ -17,8 +16,6 @@ class Test(ControllerTest): # LL/DDI/ADV/BV-21-C [Extended Advertising, Legacy PDUs, Non-Connectable] async def test(self): controller = self.controller public_peer_address = Address('aa:bb:cc:dd:ee:ff') connection_handle = 0xefe # 1. Configure Lower Tester to monitor advertising packets from the IUT. # 2. The Upper Tester sends an HCI_LE_Set_Extended_Advertising_Parameters command to the Loading Loading @@ -72,7 +69,7 @@ class Test(ControllerTest): # first packet. # 7. Repeat steps 5–6 until a number of advertising intervals (50) have been detected. for n in range(3): self.expect_ll( await self.expect_ll( ll.LeLegacyAdvertisingPdu(source_address=controller.address, advertising_address_type=ll.AddressType.PUBLIC, advertising_type=ll.LegacyAdvertisingType.ADV_NONCONN_IND, Loading tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py 0 → 100644 +83 −0 Original line number Diff line number Diff line import lib_rootcanal_python3 as rootcanal import hci_packets as hci import link_layer_packets as ll import unittest from typing import List from hci_packets import ErrorCode from py.bluetooth import Address from py.controller import ControllerTest class Test(ControllerTest): # Test parameters. LL_advertiser_advInterval_MIN = 0x200 LL_advertiser_advInterval_MAX = 0x200 LL_advertiser_Adv_Channel_Map = 0x7 # LL/DDI/ADV/BV-22-C [Extended Advertising, Legacy PDUs, Undirected, CSA #2] async def test(self): controller = self.controller # 1. Configure Lower Tester to monitor advertising packets from the IUT. # 2. The Upper Tester sends an HCI_LE_Set_Extended_Advertising_Parameters command to the # IUT using all supported advertising channels and minimum advertising interval. The # Advertising_Event_Properties parameter shall be set to 00010011b (ADV_IND legacy PDU). controller.send_cmd( hci.LeSetExtendedAdvertisingParametersLegacy( advertising_handle=0, legacy_advertising_event_properties=hci.LegacyAdvertisingEventProperties.ADV_IND, 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)) await self.expect_evt( hci.LeSetExtendedAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) # 8. Repeat steps 3–7 for each Round shown in Table 4.4. await self.steps_3_7(advertising_data=[1]) await self.steps_3_7(advertising_data=[]) await self.steps_3_7(advertising_data=[0xf8] + [0] * 30) async def steps_3_7(self, advertising_data: List[int]): controller = self.controller # 3. Upper Tester sends an HCI_LE_Set_Extended_Advertising_Data command to the IUT with # values according to Table 4.4 and receives an HCI_Command_Complete in response. controller.send_cmd( hci.LeSetExtendedAdvertisingDataRaw(advertising_handle=0, operation=hci.Operation.COMPLETE_ADVERTISEMENT, advertising_data=advertising_data)) await self.expect_evt( hci.LeSetExtendedAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) # 4. Upper Tester sends an HCI_LE_Set_Extended_Advertising_Enable command to the IUT to # enable advertising with Duration[0] set to 0x0000 (continue advertising until disabled), and # receives an HCI_Command_Complete event in response. 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)) # 5. Lower Tester scans on a single primary advertising channel as indicated in Table 4.4 and expects # the IUT to send ADV_IND packets, with ChSel set as specified in Table 4.3, including the data # submitted in step 3 starting an event on the applicable primary advertising channel. # 6. Repeat step 5 until a number of advertising intervals (50) have been detected. for n in range(3): await self.expect_ll( ll.LeLegacyAdvertisingPdu(source_address=controller.address, advertising_address_type=ll.AddressType.PUBLIC, advertising_type=ll.LegacyAdvertisingType.ADV_IND, advertising_data=advertising_data)) # 7. Upper Tester sends an HCI_LE_Set_Extended_Advertising_Enable command to the IUT to # disable advertising function and receives an HCI_Command_Complete event in response. 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)) Loading
tools/rootcanal/model/controller/dual_mode_controller.cc +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ using std::vector; namespace rootcanal { constexpr uint16_t kNumCommandPackets = 0x01; constexpr uint16_t kLeMaximumAdvertisingDataLength = 256; constexpr uint16_t kLeMaximumAdvertisingDataLength = 512; constexpr uint16_t kLeMaximumDataLength = 64; constexpr uint16_t kLeMaximumDataTime = 0x148; Loading
tools/rootcanal/model/controller/le_advertiser.cc +21 −4 Original line number Diff line number Diff line Loading @@ -1015,10 +1015,11 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( // If the advertising is high duty cycle connectable directed advertising, // then Duration[i] shall be less than or equal to 1.28 seconds and shall // not be equal to 0. std::chrono::milliseconds duration = std::chrono::milliseconds(set.duration_ * 10); if (connectable_advertising && directed_advertising && high_duty_cycle_advertising && (set.duration_ == 0 || slots(set.duration_) > adv_direct_ind_high_timeout)) { (set.duration_ == 0 || duration > adv_direct_ind_high_timeout)) { LOG_INFO( "extended advertising is high duty cycle connectable directed" " but the duration is either 0 or larger than 1.28 seconds"); Loading Loading @@ -1141,10 +1142,19 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( ExtendedAdvertiser& advertiser = extended_advertisers_[set.advertising_handle_]; advertiser.max_extended_advertising_events = set.max_extended_advertising_events_; advertiser.num_completed_extended_advertising_events = 0; advertiser.advertising_enable = true; advertiser.next_event = std::chrono::steady_clock::now() + advertiser.primary_advertising_interval; if (set.duration_ > 0) { std::chrono::milliseconds duration = std::chrono::milliseconds(set.duration_ * 10); advertiser.timeout = std::chrono::steady_clock::now() + duration; } else { advertiser.timeout.reset(); } } return ErrorCode::SUCCESS; Loading Loading @@ -1374,7 +1384,7 @@ void LinkLayerController::LeAdvertising() { for (auto& [_, advertiser] : extended_advertisers_) { // Extended Advertising Timeouts if (advertiser.IsEnabled() && advertiser.timeout && if (advertiser.IsEnabled() && advertiser.timeout.has_value() && now >= advertiser.timeout.value()) { // If the Duration[i] parameter is set to a value other than 0x0000, an // HCI_LE_Advertising_Set_Terminated event shall be generated when the Loading Loading @@ -1412,9 +1422,16 @@ void LinkLayerController::LeAdvertising() { } if (IsLeEventUnmasked(SubeventCode::ADVERTISING_SET_TERMINATED)) { // The parameter Num_Completed_Extended_Advertising_Events is set // only when Max_Extended_Advertising_Events was configured as // non-zero in the advertising parameters. uint8_t num_completed_extended_advertising_events = advertiser.max_extended_advertising_events != 0 ? advertiser.num_completed_extended_advertising_events : 0; send_event_(bluetooth::hci::LeAdvertisingSetTerminatedBuilder::Create( ErrorCode::ADVERTISING_TIMEOUT, advertiser.advertising_handle, 0, advertiser.num_completed_extended_advertising_events)); num_completed_extended_advertising_events)); } } Loading
tools/rootcanal/py/controller.py +16 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,22 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase): evt.show() self.assertTrue(False) async def expect_cmd_complete(self, expected_evt: type, timeout: int = 3) -> hci.Event: packet = await asyncio.wait_for(self.controller.receive_evt(), timeout=timeout) evt = hci.Event.parse_all(packet) if not isinstance(evt, expected_evt): print("received unexpected event") print("expected event:") print(expected_evt) print("received event:") evt.show() self.assertTrue(False) assert evt.status == ErrorCode.SUCCESS assert evt.num_hci_command_packets == 1 return evt async def expect_ll(self, expected_pdu: ll.LinkLayerPacket, timeout: int = 3): packet = await asyncio.wait_for(self.controller.receive_ll(), timeout=timeout) pdu = ll.LinkLayerPacket.parse_all(packet) Loading
tools/rootcanal/test/LL/DDI/ADV/BV_21_C.py +1 −4 Original line number Diff line number Diff line import lib_rootcanal_python3 as rootcanal import hci_packets as hci import link_layer_packets as ll import unittest Loading @@ -17,8 +16,6 @@ class Test(ControllerTest): # LL/DDI/ADV/BV-21-C [Extended Advertising, Legacy PDUs, Non-Connectable] async def test(self): controller = self.controller public_peer_address = Address('aa:bb:cc:dd:ee:ff') connection_handle = 0xefe # 1. Configure Lower Tester to monitor advertising packets from the IUT. # 2. The Upper Tester sends an HCI_LE_Set_Extended_Advertising_Parameters command to the Loading Loading @@ -72,7 +69,7 @@ class Test(ControllerTest): # first packet. # 7. Repeat steps 5–6 until a number of advertising intervals (50) have been detected. for n in range(3): self.expect_ll( await self.expect_ll( ll.LeLegacyAdvertisingPdu(source_address=controller.address, advertising_address_type=ll.AddressType.PUBLIC, advertising_type=ll.LegacyAdvertisingType.ADV_NONCONN_IND, Loading
tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py 0 → 100644 +83 −0 Original line number Diff line number Diff line import lib_rootcanal_python3 as rootcanal import hci_packets as hci import link_layer_packets as ll import unittest from typing import List from hci_packets import ErrorCode from py.bluetooth import Address from py.controller import ControllerTest class Test(ControllerTest): # Test parameters. LL_advertiser_advInterval_MIN = 0x200 LL_advertiser_advInterval_MAX = 0x200 LL_advertiser_Adv_Channel_Map = 0x7 # LL/DDI/ADV/BV-22-C [Extended Advertising, Legacy PDUs, Undirected, CSA #2] async def test(self): controller = self.controller # 1. Configure Lower Tester to monitor advertising packets from the IUT. # 2. The Upper Tester sends an HCI_LE_Set_Extended_Advertising_Parameters command to the # IUT using all supported advertising channels and minimum advertising interval. The # Advertising_Event_Properties parameter shall be set to 00010011b (ADV_IND legacy PDU). controller.send_cmd( hci.LeSetExtendedAdvertisingParametersLegacy( advertising_handle=0, legacy_advertising_event_properties=hci.LegacyAdvertisingEventProperties.ADV_IND, 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)) await self.expect_evt( hci.LeSetExtendedAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) # 8. Repeat steps 3–7 for each Round shown in Table 4.4. await self.steps_3_7(advertising_data=[1]) await self.steps_3_7(advertising_data=[]) await self.steps_3_7(advertising_data=[0xf8] + [0] * 30) async def steps_3_7(self, advertising_data: List[int]): controller = self.controller # 3. Upper Tester sends an HCI_LE_Set_Extended_Advertising_Data command to the IUT with # values according to Table 4.4 and receives an HCI_Command_Complete in response. controller.send_cmd( hci.LeSetExtendedAdvertisingDataRaw(advertising_handle=0, operation=hci.Operation.COMPLETE_ADVERTISEMENT, advertising_data=advertising_data)) await self.expect_evt( hci.LeSetExtendedAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) # 4. Upper Tester sends an HCI_LE_Set_Extended_Advertising_Enable command to the IUT to # enable advertising with Duration[0] set to 0x0000 (continue advertising until disabled), and # receives an HCI_Command_Complete event in response. 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)) # 5. Lower Tester scans on a single primary advertising channel as indicated in Table 4.4 and expects # the IUT to send ADV_IND packets, with ChSel set as specified in Table 4.3, including the data # submitted in step 3 starting an event on the applicable primary advertising channel. # 6. Repeat step 5 until a number of advertising intervals (50) have been detected. for n in range(3): await self.expect_ll( ll.LeLegacyAdvertisingPdu(source_address=controller.address, advertising_address_type=ll.AddressType.PUBLIC, advertising_type=ll.LegacyAdvertisingType.ADV_IND, advertising_data=advertising_data)) # 7. Upper Tester sends an HCI_LE_Set_Extended_Advertising_Enable command to the IUT to # disable advertising function and receives an HCI_Command_Complete event in response. 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))