# Copyright 2021-2022 Google LLC # # 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 # # https://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. # ----------------------------------------------------------------------------- # Imports # ----------------------------------------------------------------------------- import asyncio import collections import ctypes import logging import os import socket import struct from bumble.transport.common import ParserSource, Transport # ----------------------------------------------------------------------------- # Logging # ----------------------------------------------------------------------------- logger = logging.getLogger(__name__) # ----------------------------------------------------------------------------- async def open_hci_socket_transport(spec: str | None) -> Transport: ''' Open an HCI Socket (only available on some platforms). The parameter string is either empty (to use the first/default Bluetooth adapter) or a 0-based integer to indicate the adapter number. ''' HCI_CHANNEL_USER = 1 # pylint: disable=invalid-name # Create a raw HCI socket try: hci_socket = socket.socket( socket.AF_BLUETOOTH, # type: ignore[attr-defined] socket.SOCK_RAW | socket.SOCK_NONBLOCK, # type: ignore[attr-defined] socket.BTPROTO_HCI, # type: ignore[attr-defined] ) except AttributeError as error: # Not supported on this platform logger.info("HCI sockets not supported on this platform") raise Exception( 'Bluetooth HCI sockets not supported on this platform' ) from error # Compute the adapter index adapter_index = int(spec) if spec else 0 # Bind the socket # NOTE: since Python doesn't support binding with the required address format (yet), # we need to go directly to the C runtime... try: ctypes.cdll.LoadLibrary('libc.so.6') libc = ctypes.CDLL('libc.so.6', use_errno=True) except OSError as error: logger.info("HCI sockets not supported on this platform") raise Exception( 'Bluetooth HCI sockets not supported on this platform' ) from error libc.bind.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.c_char), ctypes.c_int) libc.bind.restype = ctypes.c_int bind_address = struct.pack( # pylint: disable=no-member '