Skip to main content

Virtual Bluetooth controller

Project description

RootCanal

Binding to the RootCanal controller implementation. Enables virtual testing of Bluetooth applications directly in Python.

Supported platforms

  • linux-x86_64
  • macos-x86_64

Usage

python -m rootcanal [OPTION]

Command line options include:

  • -configuration (controller configuration (see config.proto)) type: string default: ""
  • -configuration_file (controller configuration file path (see config.proto)) type: string default: ""
  • -disable_address_reuse (prevent rootcanal from reusing device addresses) type: bool default: false
  • -enable_baseband_sniffer (enable baseband sniffer) type: bool default: false
  • -enable_hci_sniffer (enable hci sniffer) type: bool default: false
  • -enable_log_color (enable log colors) type: bool default: false
  • -enable_pcap_filter (enable PCAP filter) type: bool default: false
  • -hci_port (hci server tcp port) type: uint32 default: 6402
  • -link_ble_port (le link server tcp port) type: uint32 default: 6404
  • -link_port (link server tcp port) type: uint32 default: 6403
  • -test_port (test tcp port) type: uint32 default: 6401

Example

Example python script to emulate a successful connection establishment for an instance of the RootCanal controller.

import asyncio
from rootcanal.controller import Controller, Any
from rootcanal.bluetooth import Address
from rootcanal.packets import hci
from rootcanal.packets import ll
from rootcanal.packets import llcp
from rootcanal.packets import lmp


async def test():
    controller = Controller(Address("11:11:11:11:11:11"))
    await controller.start()

    # Send HCI Reset to the controller and wait for the response.
    controller.send_cmd(hci.Reset())
    _ = await controller.expect_evt(
        hci.ResetComplete(status=hci.ErrorCode.SUCCESS, num_hci_command_packets=1)
    )

    # Check the local address.
    controller.send_cmd(hci.ReadBdAddr())
    _ = await controller.expect_evt(
        hci.ReadBdAddrComplete(
            status=hci.ErrorCode.SUCCESS,
            num_hci_command_packets=1,
            bd_addr=Address("11:11:11:11:11:11"),
        )
    )

    # Enable page scan.
    controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY))
    _ = await controller.expect_evt(
        hci.WriteScanEnableComplete(
            status=hci.ErrorCode.SUCCESS, num_hci_command_packets=1
        )
    )

    # Send classic connection request.
    controller.send_ll(
        ll.Page(
            class_of_device=0,
            allow_role_switch=0,
            source_address=Address("22:22:22:22:22:22"),
            destination_address=Address("11:11:11:11:11:11"),
        )
    )
    _ = await controller.expect_evt(
        hci.ConnectionRequest(
            bd_addr=Address("22:22:22:22:22:22"),
            class_of_device=0,
            link_type=hci.ConnectionRequestLinkType.ACL,
        )
    )

    # Accept the connection request.
    controller.send_cmd(
        hci.AcceptConnectionRequest(
            bd_addr=Address("22:22:22:22:22:22"),
            role=hci.AcceptConnectionRequestRole.REMAIN_PERIPHERAL,
        )
    )
    _ = await controller.expect_evt(
        hci.AcceptConnectionRequestStatus(
            status=hci.ErrorCode.SUCCESS, num_hci_command_packets=1
        )
    )

    _ = await controller.expect_ll(
        ll.PageResponse(
            source_address=Address("11:11:11:11:11:11"),
            destination_address=Address("22:22:22:22:22:22"),
            try_role_switch=0,
        )
    )

    _ = await controller.expect_evt(
        hci.ConnectionComplete(
            status=hci.ErrorCode.SUCCESS,
            connection_handle=Any(),
            bd_addr=Address("22:22:22:22:22:22"),
            link_type=hci.LinkType.ACL,
            encryption_enabled=hci.Enable.DISABLED,
        )
    )

    controller.stop()


asyncio.get_event_loop().run_until_complete(test())

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

rootcanal-1.10.0-py3-none-any.whl (19.7 MB view details)

Uploaded Python 3

File details

Details for the file rootcanal-1.10.0-py3-none-any.whl.

File metadata

  • Download URL: rootcanal-1.10.0-py3-none-any.whl
  • Upload date:
  • Size: 19.7 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.0.0 CPython/3.12.2

File hashes

Hashes for rootcanal-1.10.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a3e8b451e1c2c9f7e118ed206d15167b1f3f0c7b55453f7b6eb016f2a99dc082
MD5 fb9b270d0f7d8ee805c3610f47fdfdce
BLAKE2b-256 f6216d3b4f6d1b581c17c9252f5641ff97473a30dd9db3eacaecf6ac7f3d19e5

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page