forked from auracaster/bumble_mirror
Merge pull request #845 from google/gbg/ruff
use ruff for linting and import sorting
This commit is contained in:
@@ -490,7 +490,7 @@ class VendorSpecificMediaCodecInformation(MediaCodecInformation):
|
||||
'VendorSpecificMediaCodecInformation(',
|
||||
f' vendor_id: {self.vendor_id:08X} ({name_or_number(COMPANY_IDENTIFIERS, self.vendor_id & 0xFFFF)})',
|
||||
f' codec_id: {self.codec_id:04X}',
|
||||
f' value: {self.value.hex()}' ')',
|
||||
f' value: {self.value.hex()})',
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ def tokenize_parameters(buffer: bytes) -> list[bytes]:
|
||||
|
||||
if in_quotes:
|
||||
token.extend(char)
|
||||
if char == b'\"':
|
||||
if char == b'"':
|
||||
in_quotes = False
|
||||
tokens.append(token[1:-1])
|
||||
token = bytearray()
|
||||
|
||||
@@ -258,7 +258,7 @@ class Protocol:
|
||||
|
||||
def send_ipid(self, transaction_label: int, pid: int) -> None:
|
||||
logger.debug(
|
||||
">>> AVCTP ipid: " f"transaction_label={transaction_label}, " f"pid={pid}"
|
||||
f">>> AVCTP ipid: transaction_label={transaction_label}, pid={pid}"
|
||||
)
|
||||
self.send_message(transaction_label, False, True, pid, b'')
|
||||
|
||||
|
||||
@@ -2011,7 +2011,7 @@ class Protocol(utils.EventEmitter):
|
||||
f"{command} is not a valid AV/C Command Frame"
|
||||
)
|
||||
logger.debug(
|
||||
f"<<< AVCTP Command, transaction_label={transaction_label}: " f"{command}"
|
||||
f"<<< AVCTP Command, transaction_label={transaction_label}: {command}"
|
||||
)
|
||||
|
||||
# Only addressing the unit, or the PANEL subunit with subunit ID 0 is supported
|
||||
|
||||
@@ -163,23 +163,23 @@ class AacAudioRtpPacket:
|
||||
cls, reader: BitReader, channel_configuration: int, audio_object_type: int
|
||||
) -> Self:
|
||||
# GASpecificConfig - ISO/EIC 14496-3 Table 4.1
|
||||
frame_length_flag = reader.read(1)
|
||||
reader.read(1) # frame_length_flag
|
||||
depends_on_core_coder = reader.read(1)
|
||||
if depends_on_core_coder:
|
||||
core_coder_delay = reader.read(14)
|
||||
reader.read(14) # core_coder_delay
|
||||
extension_flag = reader.read(1)
|
||||
if not channel_configuration:
|
||||
raise core.InvalidPacketError('program_config_element not supported')
|
||||
if audio_object_type in (6, 20):
|
||||
layer_nr = reader.read(3)
|
||||
reader.read(3) # layer_nr
|
||||
if extension_flag:
|
||||
if audio_object_type == 22:
|
||||
num_of_sub_frame = reader.read(5)
|
||||
layer_length = reader.read(11)
|
||||
reader.read(5) # num_of_sub_frame
|
||||
reader.read(11) # layer_length
|
||||
if audio_object_type in (17, 19, 20, 23):
|
||||
aac_section_data_resilience_flags = reader.read(1)
|
||||
aac_scale_factor_data_resilience_flags = reader.read(1)
|
||||
aac_spectral_data_resilience_flags = reader.read(1)
|
||||
reader.read(1) # aac_section_data_resilience_flags
|
||||
reader.read(1) # aac_scale_factor_data_resilience_flags
|
||||
reader.read(1) # aac_spectral_data_resilience_flags
|
||||
extension_flag_3 = reader.read(1)
|
||||
if extension_flag_3 == 1:
|
||||
raise core.InvalidPacketError('extensionFlag3 == 1 not supported')
|
||||
@@ -364,10 +364,10 @@ class AacAudioRtpPacket:
|
||||
if audio_mux_version_a != 0:
|
||||
raise core.InvalidPacketError('audioMuxVersionA != 0 not supported')
|
||||
if audio_mux_version == 1:
|
||||
tara_buffer_fullness = AacAudioRtpPacket.read_latm_value(reader)
|
||||
stream_cnt = 0
|
||||
all_streams_same_time_framing = reader.read(1)
|
||||
num_sub_frames = reader.read(6)
|
||||
AacAudioRtpPacket.read_latm_value(reader) # tara_buffer_fullness
|
||||
# stream_cnt = 0
|
||||
reader.read(1) # all_streams_same_time_framing
|
||||
reader.read(6) # num_sub_frames
|
||||
num_program = reader.read(4)
|
||||
if num_program != 0:
|
||||
raise core.InvalidPacketError('num_program != 0 not supported')
|
||||
@@ -391,9 +391,9 @@ class AacAudioRtpPacket:
|
||||
reader.skip(asc_len)
|
||||
frame_length_type = reader.read(3)
|
||||
if frame_length_type == 0:
|
||||
latm_buffer_fullness = reader.read(8)
|
||||
reader.read(8) # latm_buffer_fullness
|
||||
elif frame_length_type == 1:
|
||||
frame_length = reader.read(9)
|
||||
reader.read(9) # frame_length
|
||||
else:
|
||||
raise core.InvalidPacketError(
|
||||
f'frame_length_type {frame_length_type} not supported'
|
||||
@@ -413,7 +413,7 @@ class AacAudioRtpPacket:
|
||||
break
|
||||
crc_check_present = reader.read(1)
|
||||
if crc_check_present:
|
||||
crc_checksum = reader.read(8)
|
||||
reader.read(8) # crc_checksum
|
||||
|
||||
return cls(other_data_present, other_data_len_bits, audio_specific_config)
|
||||
|
||||
|
||||
@@ -25,10 +25,8 @@ import random
|
||||
import struct
|
||||
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
||||
|
||||
from bumble import hci
|
||||
from bumble import link
|
||||
from bumble import hci, link, ll, lmp
|
||||
from bumble import link as bumble_link
|
||||
from bumble import ll, lmp
|
||||
from bumble.colors import color
|
||||
from bumble.core import PhysicalTransport
|
||||
|
||||
@@ -170,10 +168,6 @@ class AdvertisingSet:
|
||||
|
||||
def send_extended_advertising_data(self) -> None:
|
||||
if self.controller.link:
|
||||
properties = (
|
||||
self.parameters.advertising_event_properties if self.parameters else 0
|
||||
)
|
||||
|
||||
address = self.address
|
||||
assert address
|
||||
|
||||
|
||||
@@ -25,10 +25,11 @@ try:
|
||||
from bumble.crypto.cryptography import EccKey, aes_cmac, e
|
||||
except ImportError:
|
||||
logging.getLogger(__name__).debug(
|
||||
"Unable to import cryptography, use built-in primitives."
|
||||
"Unable to import cryptography, using built-in primitives."
|
||||
)
|
||||
from bumble.crypto.builtin import EccKey, aes_cmac, e # type: ignore[assignment]
|
||||
|
||||
_EccKey = EccKey # For the linter only
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Logging
|
||||
|
||||
@@ -85,7 +85,6 @@ class _AES:
|
||||
# fmt: on
|
||||
|
||||
def __init__(self, key: bytes) -> None:
|
||||
|
||||
if len(key) not in (16, 24, 32):
|
||||
raise core.InvalidArgumentError(f'Invalid key size {len(key)}')
|
||||
|
||||
@@ -112,7 +111,6 @@ class _AES:
|
||||
r_con_pointer = 0
|
||||
t = kc
|
||||
while t < round_key_count:
|
||||
|
||||
tt = tk[kc - 1]
|
||||
tk[0] ^= (
|
||||
(self._S[(tt >> 16) & 0xFF] << 24)
|
||||
@@ -269,7 +267,6 @@ class _ECB:
|
||||
|
||||
|
||||
class _CBC:
|
||||
|
||||
def __init__(self, key: bytes, iv: bytes = bytes(16)) -> None:
|
||||
if len(iv) != 16:
|
||||
raise core.InvalidArgumentError(
|
||||
@@ -302,7 +299,6 @@ class _CBC:
|
||||
|
||||
|
||||
class _CMAC:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
key: bytes,
|
||||
@@ -414,7 +410,6 @@ class _CMAC:
|
||||
self._last_pt = _xor(second_last, data_block[-bs:])
|
||||
|
||||
def digest(self) -> bytes:
|
||||
|
||||
bs = self._block_size
|
||||
|
||||
if self._mac_tag is not None and not self._update_after_digest:
|
||||
|
||||
@@ -5248,8 +5248,7 @@ class Device(utils.CompositeEventEmitter):
|
||||
|
||||
if status != hci.HCI_SUCCESS:
|
||||
logger.debug(
|
||||
f'advertising set {advertising_handle} '
|
||||
f'terminated with status {status}'
|
||||
f'advertising set {advertising_handle} terminated with status {status}'
|
||||
)
|
||||
return
|
||||
|
||||
@@ -5628,7 +5627,8 @@ class Device(utils.CompositeEventEmitter):
|
||||
|
||||
self.host.send_command_sync(
|
||||
hci.HCI_Accept_Connection_Request_Command(
|
||||
bd_addr=bd_addr, role=0x01 # Remain the peripheral
|
||||
bd_addr=bd_addr,
|
||||
role=0x01, # Remain the peripheral
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -380,7 +380,7 @@ class Driver(common.Driver):
|
||||
|
||||
if (vendor_id, product_id) not in INTEL_USB_PRODUCTS:
|
||||
logger.debug(
|
||||
f"USB device ({vendor_id:04X}, {product_id:04X}) " "not in known list"
|
||||
f"USB device ({vendor_id:04X}, {product_id:04X}) not in known list"
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -483,9 +483,7 @@ class Driver(common.Driver):
|
||||
raise DriverError("insufficient device info, missing CNVI or CNVR")
|
||||
|
||||
firmware_base_name = (
|
||||
"ibt-"
|
||||
f"{device_info[ValueType.CNVI]:04X}-"
|
||||
f"{device_info[ValueType.CNVR]:04X}"
|
||||
f"ibt-{device_info[ValueType.CNVI]:04X}-{device_info[ValueType.CNVR]:04X}"
|
||||
)
|
||||
logger.debug(f"FW base name: {firmware_base_name}")
|
||||
|
||||
|
||||
@@ -484,7 +484,7 @@ class Driver(common.Driver):
|
||||
|
||||
if (vendor_id, product_id) not in RTK_USB_PRODUCTS:
|
||||
logger.debug(
|
||||
f"USB device ({vendor_id:04X}, {product_id:04X}) " "not in known list"
|
||||
f"USB device ({vendor_id:04X}, {product_id:04X}) not in known list"
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
@@ -361,5 +361,4 @@ class EnumCharacteristicProxyAdapter(CharacteristicProxyAdapter[_T3]):
|
||||
|
||||
def decode_value(self, value: bytes) -> _T3:
|
||||
int_value = int.from_bytes(value, self.byteorder)
|
||||
a = self.cls(int_value)
|
||||
return self.cls(int_value)
|
||||
|
||||
@@ -119,7 +119,6 @@ def phy_list_to_bits(phys: Optional[Iterable[Phy]]) -> int:
|
||||
|
||||
|
||||
class SpecableEnum(utils.OpenIntEnum):
|
||||
|
||||
@classmethod
|
||||
def type_spec(cls, size: int, byteorder: Literal['little', 'big'] = 'little'):
|
||||
return {
|
||||
@@ -147,7 +146,6 @@ class SpecableEnum(utils.OpenIntEnum):
|
||||
|
||||
|
||||
class SpecableFlag(enum.IntFlag):
|
||||
|
||||
@classmethod
|
||||
def type_spec(cls, size: int, byteorder: Literal['little', 'big'] = 'little'):
|
||||
return {
|
||||
@@ -1786,20 +1784,20 @@ class HCI_Object:
|
||||
|
||||
@classmethod
|
||||
def dict_and_offset_from_bytes(
|
||||
cls, data: bytes, offset: int, fields: Fields
|
||||
cls, data: bytes, offset: int, object_fields: Fields
|
||||
) -> tuple[int, collections.OrderedDict[str, Any]]:
|
||||
result = collections.OrderedDict[str, Any]()
|
||||
for field in fields:
|
||||
if isinstance(field, list):
|
||||
for object_field in object_fields:
|
||||
if isinstance(object_field, list):
|
||||
# This is an array field, starting with a 1-byte item count.
|
||||
item_count = data[offset]
|
||||
offset += 1
|
||||
# Set fields first, because item_count might be 0.
|
||||
for sub_field_name, _ in field:
|
||||
for sub_field_name, _ in object_field:
|
||||
result[sub_field_name] = []
|
||||
|
||||
for _ in range(item_count):
|
||||
for sub_field_name, sub_field_type in field:
|
||||
for sub_field_name, sub_field_type in object_field:
|
||||
value, size = HCI_Object.parse_field(
|
||||
data, offset, sub_field_type
|
||||
)
|
||||
@@ -1807,7 +1805,7 @@ class HCI_Object:
|
||||
offset += size
|
||||
continue
|
||||
|
||||
field_name, field_type = field
|
||||
field_name, field_type = object_field
|
||||
assert isinstance(field_name, str)
|
||||
field_value, field_size = HCI_Object.parse_field(
|
||||
data, offset, cast(FieldSpec, field_type)
|
||||
@@ -1890,26 +1888,26 @@ class HCI_Object:
|
||||
return field_bytes
|
||||
|
||||
@staticmethod
|
||||
def dict_to_bytes(hci_object, fields):
|
||||
def dict_to_bytes(hci_object, object_fields):
|
||||
result = bytearray()
|
||||
for field in fields:
|
||||
if isinstance(field, list):
|
||||
for object_field in object_fields:
|
||||
if isinstance(object_field, list):
|
||||
# The field is an array. The serialized form starts with a 1-byte
|
||||
# item count. We use the length of the first array field as the
|
||||
# array count, since all array fields have the same number of items.
|
||||
item_count = len(hci_object[field[0][0]])
|
||||
item_count = len(hci_object[object_field[0][0]])
|
||||
result += bytes([item_count]) + b''.join(
|
||||
b''.join(
|
||||
HCI_Object.serialize_field(
|
||||
hci_object[sub_field_name][i], sub_field_type
|
||||
)
|
||||
for sub_field_name, sub_field_type in field
|
||||
for sub_field_name, sub_field_type in object_field
|
||||
)
|
||||
for i in range(item_count)
|
||||
)
|
||||
continue
|
||||
|
||||
(field_name, field_type) = field
|
||||
(field_name, field_type) = object_field
|
||||
result += HCI_Object.serialize_field(hci_object[field_name], field_type)
|
||||
|
||||
return bytes(result)
|
||||
@@ -1967,15 +1965,15 @@ class HCI_Object:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def format_fields(hci_object, fields, indentation='', value_mappers=None):
|
||||
if not fields:
|
||||
def format_fields(hci_object, object_fields, indentation='', value_mappers=None):
|
||||
if not object_fields:
|
||||
return ''
|
||||
|
||||
# Build array of formatted key:value pairs
|
||||
field_strings = []
|
||||
for field in fields:
|
||||
if isinstance(field, list):
|
||||
for sub_field in field:
|
||||
for object_field in object_fields:
|
||||
if isinstance(object_field, list):
|
||||
for sub_field in object_field:
|
||||
sub_field_name, sub_field_type = sub_field
|
||||
item_count = len(hci_object[sub_field_name])
|
||||
for i in range(item_count):
|
||||
@@ -1993,7 +1991,7 @@ class HCI_Object:
|
||||
)
|
||||
continue
|
||||
|
||||
field_name, field_type = field
|
||||
field_name, field_type = object_field
|
||||
field_value = hci_object[field_name]
|
||||
field_strings.append(
|
||||
(
|
||||
@@ -2016,16 +2014,16 @@ class HCI_Object:
|
||||
@classmethod
|
||||
def fields_from_dataclass(cls, obj: Any) -> list[Any]:
|
||||
stack: list[list[Any]] = [[]]
|
||||
for field in dataclasses.fields(obj):
|
||||
for object_field in dataclasses.fields(obj):
|
||||
# Fields without metadata should be ignored.
|
||||
if not isinstance(
|
||||
(metadata := field.metadata.get("bumble.hci")), FieldMetadata
|
||||
(metadata := object_field.metadata.get("bumble.hci")), FieldMetadata
|
||||
):
|
||||
continue
|
||||
if metadata.list_begin:
|
||||
stack.append([])
|
||||
if metadata.spec:
|
||||
stack[-1].append((field.name, metadata.spec))
|
||||
stack[-1].append((object_field.name, metadata.spec))
|
||||
if metadata.list_end:
|
||||
top = stack.pop()
|
||||
stack[-1].append(top)
|
||||
|
||||
@@ -597,7 +597,7 @@ class AgIndicatorState:
|
||||
supported_values_text = (
|
||||
f'({",".join(str(v) for v in self.supported_values)})'
|
||||
)
|
||||
return f'(\"{self.indicator.value}\",{supported_values_text})'
|
||||
return f'("{self.indicator.value}",{supported_values_text})'
|
||||
|
||||
@classmethod
|
||||
def call(cls: type[Self]) -> Self:
|
||||
@@ -1351,7 +1351,7 @@ class AgProtocol(utils.EventEmitter):
|
||||
logger.warning(f'AG indicator {indicator} is disabled')
|
||||
|
||||
indicator_state.current_status = value
|
||||
self.send_response(f'+CIEV: {index+1},{value}')
|
||||
self.send_response(f'+CIEV: {index + 1},{value}')
|
||||
|
||||
async def negotiate_codec(self, codec: AudioCodec) -> None:
|
||||
"""Starts codec negotiation."""
|
||||
@@ -1417,7 +1417,7 @@ class AgProtocol(utils.EventEmitter):
|
||||
operation_code = operation_code[:1] + b'x'
|
||||
try:
|
||||
operation = CallHoldOperation(operation_code.decode())
|
||||
except:
|
||||
except Exception:
|
||||
logger.error(f'Invalid operation: {operation_code.decode()}')
|
||||
self.send_cme_error(CmeError.OPERATION_NOT_SUPPORTED)
|
||||
return
|
||||
@@ -1589,7 +1589,7 @@ class AgProtocol(utils.EventEmitter):
|
||||
|
||||
def _on_clcc(self) -> None:
|
||||
for call in self.calls:
|
||||
number_text = f',\"{call.number}\"' if call.number is not None else ''
|
||||
number_text = f',"{call.number}"' if call.number is not None else ''
|
||||
type_text = f',{call.type}' if call.type is not None else ''
|
||||
response = (
|
||||
f'+CLCC: {call.index}'
|
||||
|
||||
@@ -108,8 +108,7 @@ class DataPacketQueue(utils.EventEmitter):
|
||||
|
||||
if self._packets:
|
||||
logger.debug(
|
||||
f'{self._in_flight} packets in flight, '
|
||||
f'{len(self._packets)} in queue'
|
||||
f'{self._in_flight} packets in flight, {len(self._packets)} in queue'
|
||||
)
|
||||
|
||||
def flush(self, connection_handle: int) -> None:
|
||||
@@ -1394,8 +1393,7 @@ class Host(utils.EventEmitter):
|
||||
if event.status == hci.HCI_SUCCESS:
|
||||
# Create/update the connection
|
||||
logger.debug(
|
||||
f'### SCO CONNECTION: [0x{event.connection_handle:04X}] '
|
||||
f'{event.bd_addr}'
|
||||
f'### SCO CONNECTION: [0x{event.connection_handle:04X}] {event.bd_addr}'
|
||||
)
|
||||
|
||||
self.sco_links[event.connection_handle] = ScoLink(
|
||||
@@ -1447,7 +1445,7 @@ class Host(utils.EventEmitter):
|
||||
def on_hci_le_data_length_change_event(
|
||||
self, event: hci.HCI_LE_Data_Length_Change_Event
|
||||
):
|
||||
if (connection := self.connections.get(event.connection_handle)) is None:
|
||||
if event.connection_handle not in self.connections:
|
||||
logger.warning('!!! DATA LENGTH CHANGE: unknown handle')
|
||||
return
|
||||
|
||||
|
||||
@@ -331,7 +331,6 @@ class InformationEnhancedControlField(EnhancedControlField):
|
||||
|
||||
@dataclasses.dataclass
|
||||
class SupervisoryEnhancedControlField(EnhancedControlField):
|
||||
|
||||
supervision_function: int = ControlField.SupervisoryFunction.RR
|
||||
poll: int = 0
|
||||
req_seq: int = 0
|
||||
@@ -884,7 +883,6 @@ class Processor:
|
||||
|
||||
# TODO: Handle retransmission
|
||||
class EnhancedRetransmissionProcessor(Processor):
|
||||
|
||||
MAX_SEQ_NUM = 64
|
||||
|
||||
@dataclasses.dataclass
|
||||
|
||||
@@ -74,7 +74,9 @@ class PandoraDevice:
|
||||
|
||||
# open HCI transport & set device host.
|
||||
self._hci = await transport.open_transport(self._hci_name)
|
||||
self.device.host = Host(controller_source=self._hci.source, controller_sink=self._hci.sink) # type: ignore[no-untyped-call]
|
||||
self.device.host = Host(
|
||||
controller_source=self._hci.source, controller_sink=self._hci.sink
|
||||
) # type: ignore[no-untyped-call]
|
||||
|
||||
# power-on.
|
||||
await self.device.power_on()
|
||||
|
||||
@@ -21,8 +21,10 @@ from typing import AsyncGenerator, Optional, cast
|
||||
|
||||
import grpc
|
||||
import grpc.aio
|
||||
from google.protobuf import any_pb2 # pytype: disable=pyi-error
|
||||
from google.protobuf import empty_pb2 # pytype: disable=pyi-error
|
||||
from google.protobuf import (
|
||||
any_pb2, # pytype: disable=pyi-error
|
||||
empty_pb2, # pytype: disable=pyi-error
|
||||
)
|
||||
from pandora import host_pb2
|
||||
from pandora.host_grpc_aio import HostServicer
|
||||
from pandora.host_pb2 import (
|
||||
@@ -302,7 +304,9 @@ class HostService(HostServicer):
|
||||
await disconnection_future
|
||||
self.log.debug("Disconnected")
|
||||
finally:
|
||||
connection.remove_listener(connection.EVENT_DISCONNECTION, on_disconnection) # type: ignore
|
||||
connection.remove_listener(
|
||||
connection.EVENT_DISCONNECTION, on_disconnection
|
||||
) # type: ignore
|
||||
|
||||
return empty_pb2.Empty()
|
||||
|
||||
@@ -539,7 +543,7 @@ class HostService(HostServicer):
|
||||
await bumble.utils.cancel_on_event(
|
||||
self.device, 'flush', self.device.stop_advertising()
|
||||
)
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@utils.rpc
|
||||
@@ -609,7 +613,7 @@ class HostService(HostServicer):
|
||||
await bumble.utils.cancel_on_event(
|
||||
self.device, 'flush', self.device.stop_scanning()
|
||||
)
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@utils.rpc
|
||||
@@ -644,14 +648,18 @@ class HostService(HostServicer):
|
||||
)
|
||||
|
||||
finally:
|
||||
self.device.remove_listener(self.device.EVENT_INQUIRY_COMPLETE, complete_handler) # type: ignore
|
||||
self.device.remove_listener(self.device.EVENT_INQUIRY_RESULT, result_handler) # type: ignore
|
||||
self.device.remove_listener(
|
||||
self.device.EVENT_INQUIRY_COMPLETE, complete_handler
|
||||
) # type: ignore
|
||||
self.device.remove_listener(
|
||||
self.device.EVENT_INQUIRY_RESULT, result_handler
|
||||
) # type: ignore
|
||||
try:
|
||||
self.log.debug('Stop inquiry')
|
||||
await bumble.utils.cancel_on_event(
|
||||
self.device, 'flush', self.device.stop_discovery()
|
||||
)
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@utils.rpc
|
||||
|
||||
@@ -24,9 +24,9 @@ from typing import AsyncGenerator, Optional, Union
|
||||
import grpc
|
||||
from google.protobuf import any_pb2, empty_pb2 # pytype: disable=pyi-error
|
||||
from pandora.l2cap_grpc_aio import L2CAPServicer # pytype: disable=pyi-error
|
||||
from pandora.l2cap_pb2 import COMMAND_NOT_UNDERSTOOD, INVALID_CID_IN_REQUEST
|
||||
from pandora.l2cap_pb2 import Channel as PandoraChannel # pytype: disable=pyi-error
|
||||
from pandora.l2cap_pb2 import (
|
||||
COMMAND_NOT_UNDERSTOOD,
|
||||
INVALID_CID_IN_REQUEST,
|
||||
ConnectRequest,
|
||||
ConnectResponse,
|
||||
CreditBasedChannelRequest,
|
||||
@@ -41,6 +41,7 @@ from pandora.l2cap_pb2 import (
|
||||
WaitDisconnectionRequest,
|
||||
WaitDisconnectionResponse,
|
||||
)
|
||||
from pandora.l2cap_pb2 import Channel as PandoraChannel # pytype: disable=pyi-error
|
||||
|
||||
from bumble.core import InvalidArgumentError, OutOfResourcesError
|
||||
from bumble.device import Device
|
||||
|
||||
@@ -21,9 +21,11 @@ from collections.abc import Awaitable
|
||||
from typing import Any, AsyncGenerator, AsyncIterator, Callable, Optional, Union
|
||||
|
||||
import grpc
|
||||
from google.protobuf import any_pb2 # pytype: disable=pyi-error
|
||||
from google.protobuf import empty_pb2 # pytype: disable=pyi-error
|
||||
from google.protobuf import wrappers_pb2 # pytype: disable=pyi-error
|
||||
from google.protobuf import (
|
||||
any_pb2, # pytype: disable=pyi-error
|
||||
empty_pb2, # pytype: disable=pyi-error
|
||||
wrappers_pb2, # pytype: disable=pyi-error
|
||||
)
|
||||
from pandora.host_pb2 import Connection
|
||||
from pandora.security_grpc_aio import SecurityServicer, SecurityStorageServicer
|
||||
from pandora.security_pb2 import (
|
||||
@@ -455,7 +457,7 @@ class SecurityService(SecurityServicer):
|
||||
|
||||
def pair(*_: Any) -> None:
|
||||
if self.need_pairing(connection, level):
|
||||
pair_task = asyncio.create_task(connection.pair())
|
||||
bumble.utils.AsyncRunner.spawn(connection.pair())
|
||||
|
||||
listeners: dict[str, Callable[..., Union[None, Awaitable[None]]]] = {
|
||||
'disconnection': set_failure('connection_died'),
|
||||
|
||||
@@ -199,7 +199,6 @@ class AudioInputControlPoint:
|
||||
gain_settings_properties: GainSettingsProperties
|
||||
|
||||
async def on_write(self, connection: Connection, value: bytes) -> None:
|
||||
|
||||
opcode = AudioInputControlPointOpCode(value[0])
|
||||
|
||||
if opcode == AudioInputControlPointOpCode.SET_GAIN_SETTING:
|
||||
|
||||
@@ -40,7 +40,6 @@ class GenericAttributeProfileService(gatt.TemplateService):
|
||||
database_hash_enabled: bool = True,
|
||||
service_change_enabled: bool = True,
|
||||
) -> None:
|
||||
|
||||
if server_supported_features is not None:
|
||||
self.server_supported_features_characteristic = gatt.Characteristic(
|
||||
uuid=gatt.GATT_SERVER_SUPPORTED_FEATURES_CHARACTERISTIC,
|
||||
|
||||
@@ -137,7 +137,7 @@ class Metadata:
|
||||
values.append(str(decoded))
|
||||
|
||||
return '\n'.join(
|
||||
f'{indent}{key}: {" " * (max_key_length-len(key))}{value}'
|
||||
f'{indent}{key}: {" " * (max_key_length - len(key))}{value}'
|
||||
for key, value in zip(keys, values)
|
||||
)
|
||||
|
||||
|
||||
@@ -118,7 +118,6 @@ class VolumeOffsetControlPoint:
|
||||
volume_offset_state: VolumeOffsetState
|
||||
|
||||
async def on_write(self, connection: Connection, value: bytes) -> None:
|
||||
|
||||
opcode = value[0]
|
||||
if opcode != SetVolumeOffsetOpCode.SET_VOLUME_OFFSET:
|
||||
raise ATT_Error(ErrorCode.OPCODE_NOT_SUPPORTED)
|
||||
@@ -177,7 +176,6 @@ class VolumeOffsetControlService(TemplateService):
|
||||
audio_location: Optional[VocsAudioLocation] = None,
|
||||
audio_output_description: Optional[AudioOutputDescription] = None,
|
||||
) -> None:
|
||||
|
||||
self.volume_offset_state = (
|
||||
VolumeOffsetState() if volume_offset_state is None else volume_offset_state
|
||||
)
|
||||
|
||||
@@ -528,7 +528,7 @@ class ServiceAttribute:
|
||||
def to_string(self, with_colors=False):
|
||||
if with_colors:
|
||||
return (
|
||||
f'Attribute(id={color(self.id_name(self.id),"magenta")},'
|
||||
f'Attribute(id={color(self.id_name(self.id), "magenta")},'
|
||||
f'value={self.value})'
|
||||
)
|
||||
|
||||
|
||||
@@ -997,7 +997,6 @@ class Session:
|
||||
self.send_command(response)
|
||||
|
||||
def send_pairing_confirm_command(self) -> None:
|
||||
|
||||
if self.pairing_method != PairingMethod.OOB:
|
||||
self.r = crypto.r()
|
||||
logger.debug(f'generated random: {self.r.hex()}')
|
||||
@@ -1833,7 +1832,6 @@ class Session:
|
||||
self.send_public_key_command()
|
||||
|
||||
def next_steps() -> None:
|
||||
|
||||
if self.pairing_method in (
|
||||
PairingMethod.JUST_WORKS,
|
||||
PairingMethod.NUMERIC_COMPARISON,
|
||||
|
||||
@@ -284,7 +284,9 @@ async def open_pyusb_transport(spec: str) -> Transport:
|
||||
device = await _power_cycle(device) # type: ignore
|
||||
except Exception as e:
|
||||
logging.debug(e, stack_info=True)
|
||||
logging.info(f"Unable to power cycle {hex(device.idVendor)} {hex(device.idProduct)}") # type: ignore
|
||||
logging.info(
|
||||
f"Unable to power cycle {hex(device.idVendor)} {hex(device.idProduct)}"
|
||||
) # type: ignore
|
||||
|
||||
# Collect the metadata
|
||||
device_metadata = {'vendor_id': device.idVendor, 'product_id': device.idProduct}
|
||||
@@ -370,7 +372,9 @@ async def _power_cycle(device: UsbDevice) -> UsbDevice:
|
||||
# Device needs to be find again otherwise it will appear as disconnected
|
||||
return usb.core.find(idVendor=device.idVendor, idProduct=device.idProduct) # type: ignore
|
||||
except USBError:
|
||||
logger.exception(f"Adjustment needed: Please revise the udev rule for device {hex(device.idVendor)}:{hex(device.idProduct)} for proper recognition.") # type: ignore
|
||||
logger.exception(
|
||||
f"Adjustment needed: Please revise the udev rule for device {hex(device.idVendor)}:{hex(device.idProduct)} for proper recognition."
|
||||
) # type: ignore
|
||||
|
||||
return device
|
||||
|
||||
|
||||
3
bumble/vendor/android/hci.py
vendored
3
bumble/vendor/android/hci.py
vendored
@@ -51,6 +51,7 @@ class HCI_LE_Get_Vendor_Capabilities_Command(hci.HCI_Command):
|
||||
'''
|
||||
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#vendor-specific-capabilities
|
||||
'''
|
||||
|
||||
return_parameters_fields = [
|
||||
('status', hci.STATUS_SPEC),
|
||||
('max_advt_instances', 1),
|
||||
@@ -137,6 +138,7 @@ class HCI_Get_Controller_Activity_Energy_Info_Command(hci.HCI_Command):
|
||||
'''
|
||||
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le_get_controller_activity_energy_info
|
||||
'''
|
||||
|
||||
return_parameters_fields = [
|
||||
('status', hci.STATUS_SPEC),
|
||||
('total_tx_time_ms', 4),
|
||||
@@ -229,6 +231,7 @@ class HCI_Bluetooth_Quality_Report_Event(HCI_Android_Vendor_Event):
|
||||
'''
|
||||
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#bluetooth-quality-report-sub-event
|
||||
'''
|
||||
|
||||
quality_report_id: int = field(metadata=hci.metadata(1))
|
||||
packet_types: int = field(metadata=hci.metadata(1))
|
||||
connection_handle: int = field(metadata=hci.metadata(2))
|
||||
|
||||
Reference in New Issue
Block a user