diff options
| author | 2023-03-09 11:43:23 -0800 | |
|---|---|---|
| committer | 2023-03-14 00:51:55 +0000 | |
| commit | 39cfd33a2c1c18795b2a6ac6d0b752c0c7093982 (patch) | |
| tree | 224c44ca4d6d69e38c63e96ebd28d8a5535c5fc8 | |
| parent | 17b967b0ed4973a018572ce6defb0d649a4f105e (diff) | |
RootCanal: Migrate python binding from pybind to ctype
pybind is not officially supported in Android.
Change the python binding to the supported ctype.
Test: atest rootcanal_ll_test
Change-Id: Id82ddc6cf27c016e42026720644c987bb6dfad68
26 files changed, 314 insertions, 307 deletions
diff --git a/tools/rootcanal/Android.bp b/tools/rootcanal/Android.bp index 49823c88e9..48a9bcf51b 100644 --- a/tools/rootcanal/Android.bp +++ b/tools/rootcanal/Android.bp @@ -127,12 +127,11 @@ cc_library_static {      ],  } -// This library implements Python bindings to the DualModeController -// class to enable scripted testing in Python. +// This library implements a foreigh function interface over DualModeController +// compatible with Python or Rust.  cc_library_host_shared { -    name: "lib_rootcanal_python3", +    name: "lib_rootcanal_ffi",      defaults: [ -        "bluetooth_py3_native_extension_defaults",          "rootcanal_defaults",      ],      srcs: [ @@ -140,7 +139,7 @@ cc_library_host_shared {          "model/controller/acl_connection_handler.cc",          "model/controller/controller_properties.cc",          "model/controller/dual_mode_controller.cc", -        "model/controller/dual_mode_controller_python3.cc", +        "model/controller/ffi.cc",          "model/controller/isochronous_connection_handler.cc",          "model/controller/le_advertiser.cc",          "model/controller/link_layer_controller.cc", @@ -163,14 +162,11 @@ cc_library_host_shared {      whole_static_libs: [          "libbase",          "liblmp", -    ], -    header_libs: [ -        "pybind11_headers", +        "liblog",      ],      cflags: [          "-fexceptions",      ], -    rtti: true,  }  // Generate the python parser+serializer backend for @@ -278,7 +274,7 @@ python_test_host {          "test/LL/DDI/SCN/*.py",      ],      data: [ -        ":lib_rootcanal_python3", +        ":lib_rootcanal_ffi",      ],      libs: [          "typing_extensions", diff --git a/tools/rootcanal/model/controller/dual_mode_controller_python3.cc b/tools/rootcanal/model/controller/dual_mode_controller_python3.cc deleted file mode 100644 index 54ce44f130..0000000000 --- a/tools/rootcanal/model/controller/dual_mode_controller_python3.cc +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <android-base/logging.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> - -#include "dual_mode_controller.h" -#include "model/setup/async_manager.h" - -using namespace std::literals; -namespace py = pybind11; - -namespace rootcanal { - -namespace hci { -enum Type { -  CMD, -  EVT, -  ACL, -  SCO, -  ISO, -}; -}  // namespace hci - -// Overload the class DualModeController to implement -// SendLinkLayerPacket as forwarding packets to a registered handler. -class BaseController : public DualModeController { - public: -  BaseController() {} -  ~BaseController() = default; - -  void Start() { -    if (timer_task_id_ == kInvalidTaskId) { -      timer_task_id_ = async_manager_.ExecAsyncPeriodically( -          0, 0ms, 5ms, [this]() { this->Tick(); }); -    } -  } - -  void Stop() { -    if (timer_task_id_ != kInvalidTaskId) { -      async_manager_.CancelAsyncTask(timer_task_id_); -      timer_task_id_ = kInvalidTaskId; -    } -  } - - private: -  AsyncManager async_manager_{}; -  AsyncTaskId timer_task_id_{kInvalidTaskId}; - -  BaseController(BaseController const&) = delete; -  DualModeController& operator=(BaseController const&) = delete; -}; - -PYBIND11_MODULE(lib_rootcanal_python3, m) { -  m.doc() = "RootCanal controller plugin"; - -  py::enum_<hci::Type>(m, "HciType") -      .value("Cmd", hci::Type::CMD) -      .value("Evt", hci::Type::EVT) -      .value("Acl", hci::Type::ACL) -      .value("Sco", hci::Type::SCO) -      .value("Iso", hci::Type::ISO); - -  m.def( -      "generate_rpa", -      [](py::bytes arg) { -        std::string irk_str = arg; -        irk_str.resize(LinkLayerController::kIrkSize); - -        std::array<uint8_t, LinkLayerController::kIrkSize> irk{}; -        std::copy(irk_str.begin(), irk_str.end(), irk.begin()); - -        bluetooth::hci::Address rpa = -            rootcanal::LinkLayerController::generate_rpa(irk); -        // Python address representation keeps the same -        // byte order as the string representation, instead of using -        // little endian order. -        std::reverse(rpa.address.begin(), rpa.address.end()); -        return rpa.address; -      }, -      "Bluetooth RPA generation"); - -  py::class_<rootcanal::BaseController, -             std::shared_ptr<rootcanal::BaseController>> -      basic_controller(m, "BaseController"); - -  // Implement the constructor with two callback parameters to -  // handle emitted HCI packets and LL packets. -  basic_controller.def(py::init([](std::string address_str, -                                   py::object hci_handler, -                                   py::object ll_handler) { -    std::shared_ptr<BaseController> controller = -        std::make_shared<BaseController>(); - -    std::optional<bluetooth::hci::Address> address = -        bluetooth::hci::Address::FromString(address_str); -    if (address.has_value()) { -      controller->SetAddress(address.value()); -    } -    controller->RegisterEventChannel( -        [=](std::shared_ptr<std::vector<uint8_t>> data) { -          pybind11::gil_scoped_acquire acquire; -          hci_handler( -              hci::Type::EVT, -              py::bytes(reinterpret_cast<char*>(data->data()), data->size())); -        }); -    controller->RegisterAclChannel( -        [=](std::shared_ptr<std::vector<uint8_t>> data) { -          pybind11::gil_scoped_acquire acquire; -          hci_handler( -              hci::Type::ACL, -              py::bytes(reinterpret_cast<char*>(data->data()), data->size())); -        }); -    controller->RegisterScoChannel( -        [=](std::shared_ptr<std::vector<uint8_t>> data) { -          pybind11::gil_scoped_acquire acquire; -          hci_handler( -              hci::Type::SCO, -              py::bytes(reinterpret_cast<char*>(data->data()), data->size())); -        }); -    controller->RegisterIsoChannel( -        [=](std::shared_ptr<std::vector<uint8_t>> data) { -          pybind11::gil_scoped_acquire acquire; -          hci_handler( -              hci::Type::ISO, -              py::bytes(reinterpret_cast<char*>(data->data()), data->size())); -        }); -    controller->RegisterLinkLayerChannel([=](std::vector<uint8_t> const& data, -                                             Phy::Type /*type*/, -                                             int8_t /*tx_power*/) { -      pybind11::gil_scoped_acquire acquire; -      ll_handler( -          py::bytes(reinterpret_cast<const char*>(data.data()), data.size())); -    }); -    return controller; -  })); - -  // Timer interface. -  basic_controller.def("start", &BaseController::Start); -  basic_controller.def("stop", &BaseController::Stop); - -  // Implement method BaseController.receive_hci which -  // injects HCI packets into the controller as if sent from the host. -  basic_controller.def( -      "send_hci", [](std::shared_ptr<rootcanal::BaseController> controller, -                     hci::Type typ, py::bytes data) { -        std::string data_str = data; -        std::shared_ptr<std::vector<uint8_t>> bytes = -            std::make_shared<std::vector<uint8_t>>(data_str.begin(), -                                                   data_str.end()); - -        switch (typ) { -          case hci::Type::CMD: -            controller->HandleCommand(bytes); -            break; -          case hci::Type::ACL: -            controller->HandleAcl(bytes); -            break; -          case hci::Type::SCO: -            controller->HandleSco(bytes); -            break; -          case hci::Type::ISO: -            controller->HandleIso(bytes); -            break; -          default: -            std::cerr << "Dropping HCI packet with unknown type " << typ -                      << std::endl; -            break; -        } -      }); - -  // Implement method BaseController.send_ll which -  // injects LL packets into the controller as if sent over the air. -  basic_controller.def( -      "send_ll", [](std::shared_ptr<rootcanal::BaseController> controller, -                    py::bytes data, int rssi) { -        std::string data_str = data; -        std::shared_ptr<std::vector<uint8_t>> bytes = -            std::make_shared<std::vector<uint8_t>>(data_str.begin(), -                                                   data_str.end()); - -        model::packets::LinkLayerPacketView packet = -            model::packets::LinkLayerPacketView::Create( -                bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian>( -                    bytes)); -        if (!packet.IsValid()) { -          std::cerr << "Dropping malformed LL packet" << std::endl; -          return; -        } -        // TODO: pass correct phy information to ReceiveLinkLayerPacket. -        controller->ReceiveLinkLayerPacket(std::move(packet), -                                           Phy::Type::LOW_ENERGY, rssi); -      }); -} - -__attribute__((constructor)) static void ConfigureLogging() { -  android::base::InitLogging({}, android::base::StdioLogger); -} - -}  // namespace rootcanal diff --git a/tools/rootcanal/model/controller/ffi.cc b/tools/rootcanal/model/controller/ffi.cc new file mode 100644 index 0000000000..81162ed9dd --- /dev/null +++ b/tools/rootcanal/model/controller/ffi.cc @@ -0,0 +1,145 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ffi.h" + +#include <android-base/logging.h> + +#include <iostream> + +#include "dual_mode_controller.h" + +using namespace rootcanal; +using bluetooth::hci::Address; + +namespace hci { + +enum Idc { +  CMD = 1, +  ACL, +  SCO, +  EVT, +  ISO, +}; + +__attribute__((constructor)) static void ConfigureLogging() { +  android::base::InitLogging({}, android::base::StdioLogger); +} + +}  // namespace hci + +extern "C" { + +__attribute__((visibility("default"))) void* ffi_controller_new( +    uint8_t const address[6], +    void (*send_hci)(int idc, uint8_t const* data, size_t data_len), +    void (*send_ll)(uint8_t const* data, size_t data_len, int phy, +                    int tx_power)) { +  DualModeController* controller = new DualModeController(); +  controller->SetAddress(Address({address[0], address[1], address[2], +                                  address[3], address[4], address[5]})); +  controller->RegisterEventChannel( +      [=](std::shared_ptr<std::vector<uint8_t>> data) { +        send_hci(hci::Idc::EVT, data->data(), data->size()); +      }); +  controller->RegisterAclChannel( +      [=](std::shared_ptr<std::vector<uint8_t>> data) { +        send_hci(hci::Idc::ACL, data->data(), data->size()); +      }); +  controller->RegisterScoChannel( +      [=](std::shared_ptr<std::vector<uint8_t>> data) { +        send_hci(hci::Idc::SCO, data->data(), data->size()); +      }); +  controller->RegisterIsoChannel( +      [=](std::shared_ptr<std::vector<uint8_t>> data) { +        send_hci(hci::Idc::ISO, data->data(), data->size()); +      }); +  controller->RegisterLinkLayerChannel( +      [=](std::vector<uint8_t> const& data, Phy::Type phy, int8_t tx_power) { +        send_ll(data.data(), data.size(), static_cast<int>(phy), tx_power); +      }); + +  return controller; +} + +__attribute__((visibility("default"))) void ffi_controller_delete( +    void* controller_) { +  DualModeController* controller = +      reinterpret_cast<DualModeController*>(controller_); +  delete controller; +} + +__attribute__((visibility("default"))) void ffi_controller_receive_hci( +    void* controller_, int idc, uint8_t const* data, size_t data_len) { +  DualModeController* controller = +      reinterpret_cast<DualModeController*>(controller_); +  std::shared_ptr<std::vector<uint8_t>> bytes = +      std::make_shared<std::vector<uint8_t>>(data, data + data_len); + +  switch (idc) { +    case hci::Idc::CMD: +      controller->HandleCommand(bytes); +      break; +    case hci::Idc::ACL: +      controller->HandleAcl(bytes); +      break; +    case hci::Idc::SCO: +      controller->HandleSco(bytes); +      break; +    case hci::Idc::ISO: +      controller->HandleIso(bytes); +      break; +    default: +      std::cerr << "Dropping HCI packet with unknown type " << (int)idc +                << std::endl; +      break; +  } +} + +__attribute__((visibility("default"))) void ffi_controller_receive_ll( +    void* controller_, uint8_t const* data, size_t data_len, int phy, +    int rssi) { +  DualModeController* controller = +      reinterpret_cast<DualModeController*>(controller_); +  std::shared_ptr<std::vector<uint8_t>> bytes = +      std::make_shared<std::vector<uint8_t>>(data, data + data_len); +  model::packets::LinkLayerPacketView packet = +      model::packets::LinkLayerPacketView::Create( +          bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian>( +              bytes)); +  if (!packet.IsValid()) { +    std::cerr << "Dropping malformed LL packet" << std::endl; +    return; +  } +  controller->ReceiveLinkLayerPacket(packet, Phy::Type(phy), rssi); +} + +__attribute__((visibility("default"))) void ffi_controller_tick( +    void* controller_) { +  DualModeController* controller = +      reinterpret_cast<DualModeController*>(controller_); +  controller->Tick(); +} + +__attribute__((visibility("default"))) void ffi_generate_rpa( +    uint8_t const irk_[16], uint8_t rpa[6]) { +  std::array<uint8_t, LinkLayerController::kIrkSize> irk; +  memcpy(irk.data(), irk_, LinkLayerController::kIrkSize); +  Address address = LinkLayerController::generate_rpa(irk); +  memcpy(rpa, address.data(), Address::kLength); +} + +};  // extern "C" diff --git a/tools/rootcanal/model/controller/ffi.h b/tools/rootcanal/model/controller/ffi.h new file mode 100644 index 0000000000..8b6033be02 --- /dev/null +++ b/tools/rootcanal/model/controller/ffi.h @@ -0,0 +1,35 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cstddef> +#include <cstdint> + +extern "C" { + +void* ffi_controller_new(uint8_t const address[6], +                         void (*send_hci)(int idc, uint8_t const* data, +                                          size_t data_len), +                         void (*send_ll)(uint8_t const* data, size_t data_len, +                                         int phy, int tx_power)); +void ffi_controller_delete(void* controller); +void ffi_controller_receive_hci(void* controller, int idc, uint8_t const* data, +                                size_t data_len); +void ffi_controller_receive_ll(void* controller, uint8_t const* data, +                               size_t data_len, int phy, int rssi); +void ffi_controller_tick(void* controller); +void ffi_generate_rpa(uint8_t const irk[16], uint8_t rpa[6]); + +};  // extern "C" diff --git a/tools/rootcanal/py/controller.py b/tools/rootcanal/py/controller.py index b1575f1819..99e93a4221 100644 --- a/tools/rootcanal/py/controller.py +++ b/tools/rootcanal/py/controller.py @@ -1,13 +1,36 @@  import asyncio  import collections +import enum  import hci_packets as hci -import lib_rootcanal_python3 as rootcanal  import link_layer_packets as ll  import py.bluetooth +import sys +import typing  import unittest  from typing import Optional  from hci_packets import ErrorCode +from ctypes import * + +rootcanal = cdll.LoadLibrary("lib_rootcanal_ffi.so") +rootcanal.ffi_controller_new.restype = c_void_p + +SEND_HCI_FUNC = CFUNCTYPE(None, c_int, POINTER(c_ubyte), c_size_t) +SEND_LL_FUNC = CFUNCTYPE(None, POINTER(c_ubyte), c_size_t, c_int, c_int) + + +class Idc(enum.IntEnum): +    Cmd = 1 +    Acl = 2 +    Sco = 3 +    Evt = 4 +    Iso = 5 + + +class Phy(enum.IntEnum): +    LowEnergy = 0 +    BrEdr = 1 +  class LeFeatures: @@ -17,14 +40,42 @@ class LeFeatures:          self.le_extended_advertising = (le_features & hci.LLFeaturesBits.LE_EXTENDED_ADVERTISING) != 0 -class Controller(rootcanal.BaseController): -    """Binder class to DualModeController. +def generate_rpa(irk: bytes) -> hci.Address: +    rpa = bytearray(6) +    rpa_type = c_char * 6 +    rootcanal.ffi_generate_rpa(c_char_p(irk), rpa_type.from_buffer(rpa)) +    return hci.Address(bytes(rpa)) + + +class Controller: +    """Binder class over RootCanal's ffi interfaces.      The methods send_cmd, send_hci, send_ll are used to inject HCI or LL      packets into the controller, and receive_hci, receive_ll to      catch outgoing HCI packets of LL pdus."""      def __init__(self, address: hci.Address): -        super().__init__(repr(address), self.receive_hci_, self.receive_ll_) +        # Write the callbacks for handling HCI and LL send events. +        @SEND_HCI_FUNC +        def send_hci(idc: c_int, data: POINTER(c_ubyte), data_len: c_size_t): +            packet = [] +            for n in range(data_len): +                packet.append(data[n]) +            self.receive_hci_(int(idc), bytes(packet)) + +        @SEND_LL_FUNC +        def send_ll(data: POINTER(c_ubyte), data_len: c_size_t, phy: c_int, tx_power: c_int): +            packet = [] +            for n in range(data_len): +                packet.append(data[n]) +            self.receive_ll_(bytes(packet), int(phy), int(tx_power)) + +        self.send_hci_callback = SEND_HCI_FUNC(send_hci) +        self.send_ll_callback = SEND_LL_FUNC(send_ll) + +        # Create a c++ controller instance. +        self.instance = rootcanal.ffi_controller_new(c_char_p(address.address), self.send_hci_callback, +                                                     self.send_ll_callback) +          self.address = address          self.evt_queue = collections.deque()          self.acl_queue = collections.deque() @@ -33,37 +84,51 @@ class Controller(rootcanal.BaseController):          self.acl_queue_event = asyncio.Event()          self.ll_queue_event = asyncio.Event() -    def receive_hci_(self, typ: rootcanal.HciType, packet: bytes): -        if typ == rootcanal.HciType.Evt: +    def __del__(self): +        rootcanal.ffi_controller_delete(c_void_p(self.instance)) + +    def receive_hci_(self, idc: int, packet: bytes): +        if idc == Idc.Evt:              print(f"<-- received HCI event data={len(packet)}[..]")              self.evt_queue.append(packet) -            self.loop.call_soon_threadsafe(self.evt_queue_event.set) -        elif typ == rootcanal.HciType.Acl: +            self.evt_queue_event.set() +        elif idc == Idc.Acl:              print(f"<-- received HCI ACL packet data={len(packet)}[..]")              self.acl_queue.append(packet) -            self.loop.call_soon_threadsafe(self.acl_queue_event.set) +            self.acl_queue_event.set()          else:              print(f"ignoring HCI packet typ={typ}") -    def receive_ll_(self, packet: bytes): +    def receive_ll_(self, packet: bytes, phy: int, tx_power: int):          print(f"<-- received LL pdu data={len(packet)}[..]")          self.ll_queue.append(packet) -        self.loop.call_soon_threadsafe(self.ll_queue_event.set) +        self.ll_queue_event.set()      def send_cmd(self, cmd: hci.Command):          print(f"--> sending HCI command {cmd.__class__.__name__}") -        self.send_hci(rootcanal.HciType.Cmd, cmd.serialize()) +        data = cmd.serialize() +        rootcanal.ffi_controller_receive_hci(c_void_p(self.instance), c_int(Idc.Cmd), c_char_p(data), c_int(len(data))) -    def send_ll(self, pdu: ll.LinkLayerPacket, rssi: int = -90): +    def send_ll(self, pdu: ll.LinkLayerPacket, phy: Phy = Phy.LowEnergy, rssi: int = -90):          print(f"--> sending LL pdu {pdu.__class__.__name__}") -        super().send_ll(pdu.serialize(), rssi) +        data = pdu.serialize() +        rootcanal.ffi_controller_receive_ll(c_void_p(self.instance), c_char_p(data), c_int(len(data)), c_int(phy), +                                            c_int(rssi))      async def start(self): -        super().start() -        self.loop = asyncio.get_event_loop() + +        async def timer(): +            while True: +                await asyncio.sleep(0.005) +                rootcanal.ffi_controller_tick(c_void_p(self.instance)) + +        # Spawn the controller timer task. +        self.timer_task = asyncio.create_task(timer())      def stop(self): -        super().stop() +        # Cancel the controller timer task. +        del self.timer_task +          if self.evt_queue:              print("evt queue not empty at stop():")              for packet in self.evt_queue: @@ -123,10 +188,10 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase):          await controller.expect_evt(hci.SetEventMaskComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))          controller.send_cmd(hci.LeSetEventMask(le_event_mask=0xffffffffffffffff))          await controller.expect_evt(hci.LeSetEventMaskComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) -        controller.send_cmd(hci.LeReadLocalSupportedFeatures())          # Load the local supported features to be able to disable tests          # that rely on unsupported features. +        controller.send_cmd(hci.LeReadLocalSupportedFeatures())          evt = await self.expect_cmd_complete(hci.LeReadLocalSupportedFeaturesComplete)          controller.le_features = LeFeatures(evt.le_features) @@ -158,11 +223,18 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase):          assert evt.num_hci_command_packets == 1          return evt -    async def expect_ll(self, expected_pdu: ll.LinkLayerPacket, timeout: int = 3): +    async def expect_ll(self, expected_pdu: typing.Union[ll.LinkLayerPacket, type], timeout: int = 3):          packet = await asyncio.wait_for(self.controller.receive_ll(), timeout=timeout)          pdu = ll.LinkLayerPacket.parse_all(packet) -        if pdu != expected_pdu: +        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() diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_01_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_01_C.py index cd8bae1b4c..be89bfc3b8 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_01_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_01_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_02_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_02_C.py index e27eea17d3..3f49d18c1c 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_02_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_02_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_03_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_03_C.py index c266c62bea..1eb851153d 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_03_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_03_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_04_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_04_C.py index f3b8a29916..8888d51fdd 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_04_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_04_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_05_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_05_C.py index 396ead9ed6..3f846aec4b 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_05_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_05_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest 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 57875af2c3..6c078af77c 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py index 9cdad2405a..8a10b6a1ba 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_08_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_08_C.py index 34e3dee951..13eb857aee 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_08_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_08_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py index e20f30b329..bad9c81ba7 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py index 153dd7a36f..f2d14f325c 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py @@ -1,5 +1,4 @@  import asyncio -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest @@ -102,6 +101,10 @@ class Test(ControllerTest):                                          conn_supervision_timeout=self.LL_initiator_connSupervisionTimeout),                             rssi=-16) +        # Note: another advertising pdu is received waiting from the connect +        # complete. +        await self.expect_ll(ll.LeLegacyAdvertisingPdu) +          # Note: Link layer sends LeConnectComplete here.          await self.expect_ll(              ll.LeConnectComplete(source_address=controller.address, diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_15_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_15_C.py index 70a7a24c45..14d5be02fe 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_15_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_15_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_16_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_16_C.py index b444112c83..1512ddc7b6 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_16_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_16_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_17_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_17_C.py index efdc1a2ca4..f22c0421ad 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_17_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_17_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_18_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_18_C.py index 9fcc4142ac..729d934ffa 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_18_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_18_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py index 60528e9f64..f48caf2fc0 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_20_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_20_C.py index 6cbf26ed5b..b1c1769b5a 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_20_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_20_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py index 8a6be12ec5..5c36abe633 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py @@ -1,4 +1,3 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_13_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_13_C.py index 87ae4fab08..1052503eb8 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_13_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_13_C.py @@ -1,10 +1,9 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest  from hci_packets import ErrorCode  from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, generate_rpa  class Test(ControllerTest): @@ -22,7 +21,7 @@ class Test(ControllerTest):          peer_irk = bytes([1] * 16)          peer_identity_address = Address('aa:bb:cc:dd:ee:ff')          peer_identity_address_type = hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS -        peer_resolvable_address = Address(rootcanal.generate_rpa(peer_irk)) +        peer_resolvable_address = generate_rpa(peer_irk)          if not controller.le_features.ll_privacy:              self.skipTest("LL privacy not supported") diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_14_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_14_C.py index 37903e9051..7caa4e1240 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_14_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_14_C.py @@ -1,10 +1,9 @@ -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest  from hci_packets import ErrorCode  from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, generate_rpa  class Test(ControllerTest): @@ -23,9 +22,9 @@ class Test(ControllerTest):          controller = self.controller          peer_irk = bytes([1] * 16)          local_irk = bytes([2] * 16) -        peer_resolvable_address = Address(rootcanal.generate_rpa(peer_irk)) -        local_resolvable_address_1 = Address(rootcanal.generate_rpa(local_irk)) -        local_resolvable_address_2 = Address(rootcanal.generate_rpa(local_irk)) +        peer_resolvable_address = generate_rpa(peer_irk) +        local_resolvable_address_1 = generate_rpa(local_irk) +        local_resolvable_address_2 = generate_rpa(local_irk)          if not controller.le_features.ll_privacy:              self.skipTest("LL privacy not supported") diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_18_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_18_C.py index bff342bac1..a56ba366df 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_18_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_18_C.py @@ -1,11 +1,10 @@  import asyncio -import lib_rootcanal_python3 as rootcanal  import hci_packets as hci  import link_layer_packets as ll  import unittest  from hci_packets import ErrorCode  from py.bluetooth import Address -from py.controller import ControllerTest +from py.controller import ControllerTest, generate_rpa  class Test(ControllerTest): @@ -26,7 +25,7 @@ class Test(ControllerTest):          local_irk = bytes([2] * 16)          peer_identity_address = Address('aa:bb:cc:dd:ff:c0')          peer_identity_address_type = hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS -        peer_resolvable_address = Address(rootcanal.generate_rpa(peer_irk)) +        peer_resolvable_address = generate_rpa(peer_irk)          if not controller.le_features.ll_privacy:              self.skipTest("LL privacy not supported") diff --git a/tools/rootcanal/test/main.py b/tools/rootcanal/test/main.py index 9f9db3963e..e1022b4a92 100644 --- a/tools/rootcanal/test/main.py +++ b/tools/rootcanal/test/main.py @@ -1,45 +1,34 @@  from importlib import resources  from pathlib import Path  import importlib +import sys  import tempfile - -# Python is not able to load the module lib_rootcanal_python3.so -# when the test target is configured with embedded_launcher: true. -# This code loads the file to a temporary directory and adds the -# path to the sys lookup. -with tempfile.TemporaryDirectory() as cache: -    with (Path('lib_rootcanal_python3.so').open('rb') as fin, -          Path(cache, 'lib_rootcanal_python3.so').open('wb') as fout): -        fout.write(fin.read()) -    sys.path.append(cache) -    import lib_rootcanal_python3 -  import unittest  tests = [ -  'LL.DDI.ADV.BV_01_C', -  'LL.DDI.ADV.BV_02_C', -  'LL.DDI.ADV.BV_03_C', -  'LL.DDI.ADV.BV_04_C', -  'LL.DDI.ADV.BV_05_C', -  'LL.DDI.ADV.BV_06_C', -  'LL.DDI.ADV.BV_07_C', -  'LL.DDI.ADV.BV_08_C', -  'LL.DDI.ADV.BV_09_C', -  'LL.DDI.ADV.BV_11_C', -  'LL.DDI.ADV.BV_15_C', -  'LL.DDI.ADV.BV_16_C', -  '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_21_C', -  'LL.DDI.ADV.BV_22_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.ADV.BV_01_C', +    'LL.DDI.ADV.BV_02_C', +    'LL.DDI.ADV.BV_03_C', +    'LL.DDI.ADV.BV_04_C', +    'LL.DDI.ADV.BV_05_C', +    'LL.DDI.ADV.BV_06_C', +    'LL.DDI.ADV.BV_07_C', +    'LL.DDI.ADV.BV_08_C', +    'LL.DDI.ADV.BV_09_C', +    'LL.DDI.ADV.BV_11_C', +    'LL.DDI.ADV.BV_15_C', +    'LL.DDI.ADV.BV_16_C', +    '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_21_C', +    'LL.DDI.ADV.BV_22_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',  ]  if __name__ == "__main__":  |