bumble 0.0.223__py3-none-any.whl → 0.0.224__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bumble/drivers/intel.py CHANGED
@@ -89,52 +89,55 @@ HCI_INTEL_WRITE_BOOT_PARAMS_COMMAND = hci.hci_vendor_command_op_code(0x000E)
89
89
  hci.HCI_Command.register_commands(globals())
90
90
 
91
91
 
92
- @hci.HCI_Command.command
93
92
  @dataclasses.dataclass
94
- class HCI_Intel_Read_Version_Command(hci.HCI_Command):
95
- param0: int = dataclasses.field(metadata=hci.metadata(1))
93
+ class HCI_Intel_Read_Version_ReturnParameters(hci.HCI_StatusReturnParameters):
94
+ tlv: bytes = hci.field(metadata=hci.metadata('*'))
95
+
96
96
 
97
- return_parameters_fields = [
98
- ("status", hci.STATUS_SPEC),
99
- ("tlv", "*"),
100
- ]
97
+ @hci.HCI_SyncCommand.sync_command(HCI_Intel_Read_Version_ReturnParameters)
98
+ @dataclasses.dataclass
99
+ class HCI_Intel_Read_Version_Command(
100
+ hci.HCI_SyncCommand[HCI_Intel_Read_Version_ReturnParameters]
101
+ ):
102
+ param0: int = dataclasses.field(metadata=hci.metadata(1))
101
103
 
102
104
 
103
- @hci.HCI_Command.command
105
+ @hci.HCI_SyncCommand.sync_command(hci.HCI_StatusReturnParameters)
104
106
  @dataclasses.dataclass
105
- class Hci_Intel_Secure_Send_Command(hci.HCI_Command):
107
+ class Hci_Intel_Secure_Send_Command(
108
+ hci.HCI_SyncCommand[hci.HCI_StatusReturnParameters]
109
+ ):
106
110
  data_type: int = dataclasses.field(metadata=hci.metadata(1))
107
111
  data: bytes = dataclasses.field(metadata=hci.metadata("*"))
108
112
 
109
- return_parameters_fields = [
110
- ("status", 1),
111
- ]
113
+
114
+ @dataclasses.dataclass
115
+ class HCI_Intel_Reset_ReturnParameters(hci.HCI_ReturnParameters):
116
+ data: bytes = hci.field(metadata=hci.metadata('*'))
112
117
 
113
118
 
114
- @hci.HCI_Command.command
119
+ @hci.HCI_SyncCommand.sync_command(HCI_Intel_Reset_ReturnParameters)
115
120
  @dataclasses.dataclass
116
- class HCI_Intel_Reset_Command(hci.HCI_Command):
121
+ class HCI_Intel_Reset_Command(hci.HCI_SyncCommand[HCI_Intel_Reset_ReturnParameters]):
117
122
  reset_type: int = dataclasses.field(metadata=hci.metadata(1))
118
123
  patch_enable: int = dataclasses.field(metadata=hci.metadata(1))
119
124
  ddc_reload: int = dataclasses.field(metadata=hci.metadata(1))
120
125
  boot_option: int = dataclasses.field(metadata=hci.metadata(1))
121
126
  boot_address: int = dataclasses.field(metadata=hci.metadata(4))
122
127
 
123
- return_parameters_fields = [
124
- ("data", "*"),
125
- ]
128
+
129
+ @dataclasses.dataclass
130
+ class HCI_Intel_Write_Device_Config_ReturnParameters(hci.HCI_StatusReturnParameters):
131
+ params: bytes = hci.field(metadata=hci.metadata('*'))
126
132
 
127
133
 
128
- @hci.HCI_Command.command
134
+ @hci.HCI_SyncCommand.sync_command(HCI_Intel_Write_Device_Config_ReturnParameters)
129
135
  @dataclasses.dataclass
130
- class Hci_Intel_Write_Device_Config_Command(hci.HCI_Command):
136
+ class HCI_Intel_Write_Device_Config_Command(
137
+ hci.HCI_SyncCommand[HCI_Intel_Write_Device_Config_ReturnParameters]
138
+ ):
131
139
  data: bytes = dataclasses.field(metadata=hci.metadata("*"))
132
140
 
133
- return_parameters_fields = [
134
- ("status", hci.STATUS_SPEC),
135
- ("params", "*"),
136
- ]
137
-
138
141
 
139
142
  # -----------------------------------------------------------------------------
140
143
  # Functions
@@ -402,7 +405,7 @@ class Driver(common.Driver):
402
405
  self.host.on_hci_event_packet(event)
403
406
  return
404
407
 
405
- if not event.return_parameters == hci.HCI_SUCCESS:
408
+ if not event.return_parameters.status == hci.HCI_SUCCESS:
406
409
  raise DriverError("HCI_Command_Complete_Event error")
407
410
 
408
411
  if self.max_in_flight_firmware_load_commands != event.num_hci_command_packets:
@@ -641,8 +644,8 @@ class Driver(common.Driver):
641
644
  while ddc_data:
642
645
  ddc_len = 1 + ddc_data[0]
643
646
  ddc_payload = ddc_data[:ddc_len]
644
- await self.host.send_command(
645
- Hci_Intel_Write_Device_Config_Command(data=ddc_payload)
647
+ await self.host.send_sync_command(
648
+ HCI_Intel_Write_Device_Config_Command(data=ddc_payload)
646
649
  )
647
650
  ddc_data = ddc_data[ddc_len:]
648
651
 
@@ -660,31 +663,34 @@ class Driver(common.Driver):
660
663
 
661
664
  async def read_device_info(self) -> dict[ValueType, Any]:
662
665
  self.host.ready = True
663
- response = await self.host.send_command(hci.HCI_Reset_Command())
664
- if not (
665
- isinstance(response, hci.HCI_Command_Complete_Event)
666
- and response.return_parameters
667
- in (hci.HCI_UNKNOWN_HCI_COMMAND_ERROR, hci.HCI_SUCCESS)
666
+ response1 = await self.host.send_sync_command_raw(hci.HCI_Reset_Command())
667
+ if not isinstance(
668
+ response1.return_parameters, hci.HCI_StatusReturnParameters
669
+ ) or response1.return_parameters.status not in (
670
+ hci.HCI_UNKNOWN_HCI_COMMAND_ERROR,
671
+ hci.HCI_SUCCESS,
668
672
  ):
669
673
  # When the controller is in operational mode, the response is a
670
674
  # successful response.
671
675
  # When the controller is in bootloader mode,
672
676
  # HCI_UNKNOWN_HCI_COMMAND_ERROR is the expected response. Anything
673
677
  # else is a failure.
674
- logger.warning(f"unexpected response: {response}")
678
+ logger.warning(f"unexpected response: {response1}")
675
679
  raise DriverError("unexpected HCI response")
676
680
 
677
681
  # Read the firmware version.
678
- response = await self.host.send_command(
682
+ response2 = await self.host.send_sync_command_raw(
679
683
  HCI_Intel_Read_Version_Command(param0=0xFF)
680
684
  )
681
- if not isinstance(response, hci.HCI_Command_Complete_Event):
682
- raise DriverError("unexpected HCI response")
683
-
684
- if response.return_parameters.status != 0: # type: ignore
685
+ if (
686
+ not isinstance(
687
+ response2.return_parameters, HCI_Intel_Read_Version_ReturnParameters
688
+ )
689
+ or response2.return_parameters.status != 0
690
+ ):
685
691
  raise DriverError("HCI_Intel_Read_Version_Command error")
686
692
 
687
- tlvs = _parse_tlv(response.return_parameters.tlv) # type: ignore
693
+ tlvs = _parse_tlv(response2.return_parameters.tlv) # type: ignore
688
694
 
689
695
  # Convert the list to a dict. That's Ok here because we only expect each type
690
696
  # to appear just once.
bumble/drivers/rtk.py CHANGED
@@ -16,6 +16,7 @@ Support for Realtek USB dongles.
16
16
  Based on various online bits of information, including the Linux kernel.
17
17
  (see `drivers/bluetooth/btrtl.c`)
18
18
  """
19
+ from __future__ import annotations
19
20
 
20
21
  import asyncio
21
22
  import enum
@@ -31,10 +32,14 @@ import weakref
31
32
  # Imports
32
33
  # -----------------------------------------------------------------------------
33
34
  from dataclasses import dataclass, field
35
+ from typing import TYPE_CHECKING
34
36
 
35
37
  from bumble import core, hci
36
38
  from bumble.drivers import common
37
39
 
40
+ if TYPE_CHECKING:
41
+ from bumble.host import Host
42
+
38
43
  # -----------------------------------------------------------------------------
39
44
  # Logging
40
45
  # -----------------------------------------------------------------------------
@@ -124,6 +129,7 @@ RTK_USB_PRODUCTS = {
124
129
  (0x2357, 0x0604),
125
130
  (0x2550, 0x8761),
126
131
  (0x2B89, 0x8761),
132
+ (0x2C0A, 0x8761),
127
133
  (0x7392, 0xC611),
128
134
  # Realtek 8761CUV
129
135
  (0x0B05, 0x1BF6),
@@ -188,23 +194,36 @@ HCI_RTK_DROP_FIRMWARE_COMMAND = hci.hci_vendor_command_op_code(0x66)
188
194
  hci.HCI_Command.register_commands(globals())
189
195
 
190
196
 
191
- @hci.HCI_Command.command
192
197
  @dataclass
193
- class HCI_RTK_Read_ROM_Version_Command(hci.HCI_Command):
194
- return_parameters_fields = [("status", hci.STATUS_SPEC), ("version", 1)]
198
+ class HCI_RTK_Read_ROM_Version_ReturnParameters(hci.HCI_StatusReturnParameters):
199
+ version: int = field(metadata=hci.metadata(1))
200
+
201
+
202
+ @hci.HCI_SyncCommand.sync_command(HCI_RTK_Read_ROM_Version_ReturnParameters)
203
+ @dataclass
204
+ class HCI_RTK_Read_ROM_Version_Command(
205
+ hci.HCI_SyncCommand[HCI_RTK_Read_ROM_Version_ReturnParameters]
206
+ ):
207
+ pass
208
+
209
+
210
+ @dataclass
211
+ class HCI_RTK_Download_ReturnParameters(hci.HCI_StatusReturnParameters):
212
+ index: int = field(metadata=hci.metadata(1))
195
213
 
196
214
 
197
- @hci.HCI_Command.command
215
+ @hci.HCI_SyncCommand.sync_command(HCI_RTK_Download_ReturnParameters)
198
216
  @dataclass
199
- class HCI_RTK_Download_Command(hci.HCI_Command):
217
+ class HCI_RTK_Download_Command(hci.HCI_SyncCommand[HCI_RTK_Download_ReturnParameters]):
200
218
  index: int = field(metadata=hci.metadata(1))
201
219
  payload: bytes = field(metadata=hci.metadata(RTK_FRAGMENT_LENGTH))
202
- return_parameters_fields = [("status", hci.STATUS_SPEC), ("index", 1)]
203
220
 
204
221
 
205
- @hci.HCI_Command.command
222
+ @hci.HCI_SyncCommand.sync_command(hci.HCI_GenericReturnParameters)
206
223
  @dataclass
207
- class HCI_RTK_Drop_Firmware_Command(hci.HCI_Command):
224
+ class HCI_RTK_Drop_Firmware_Command(
225
+ hci.HCI_SyncCommand[hci.HCI_GenericReturnParameters]
226
+ ):
208
227
  pass
209
228
 
210
229
 
@@ -490,7 +509,7 @@ class Driver(common.Driver):
490
509
  return None
491
510
 
492
511
  @staticmethod
493
- def check(host):
512
+ def check(host: Host) -> bool:
494
513
  if not host.hci_metadata:
495
514
  logger.debug("USB metadata not found")
496
515
  return False
@@ -514,37 +533,44 @@ class Driver(common.Driver):
514
533
  return True
515
534
 
516
535
  @staticmethod
517
- async def get_loaded_firmware_version(host):
518
- response = await host.send_command(HCI_RTK_Read_ROM_Version_Command())
519
-
520
- if response.return_parameters.status != hci.HCI_SUCCESS:
536
+ async def get_loaded_firmware_version(host: Host) -> int | None:
537
+ response1 = await host.send_sync_command_raw(HCI_RTK_Read_ROM_Version_Command())
538
+ if (
539
+ not isinstance(
540
+ response1.return_parameters, HCI_RTK_Read_ROM_Version_ReturnParameters
541
+ )
542
+ or response1.return_parameters.status != hci.HCI_SUCCESS
543
+ ):
521
544
  return None
522
545
 
523
- response = await host.send_command(
524
- hci.HCI_Read_Local_Version_Information_Command(), check_result=True
525
- )
526
- return (
527
- response.return_parameters.hci_subversion << 16
528
- | response.return_parameters.lmp_subversion
546
+ response2 = await host.send_sync_command(
547
+ hci.HCI_Read_Local_Version_Information_Command()
529
548
  )
549
+ return response2.hci_subversion << 16 | response2.lmp_subversion
530
550
 
531
551
  @classmethod
532
- async def driver_info_for_host(cls, host):
552
+ async def driver_info_for_host(cls, host: Host) -> DriverInfo | None:
533
553
  try:
534
- await host.send_command(
554
+ await host.send_sync_command(
535
555
  hci.HCI_Reset_Command(),
536
- check_result=True,
537
556
  response_timeout=cls.POST_RESET_DELAY,
538
557
  )
539
558
  host.ready = True # Needed to let the host know the controller is ready.
540
559
  except asyncio.exceptions.TimeoutError:
541
560
  logger.warning("timeout waiting for hci reset, retrying")
542
- await host.send_command(hci.HCI_Reset_Command(), check_result=True)
561
+ await host.send_sync_command(hci.HCI_Reset_Command())
543
562
  host.ready = True
544
563
 
545
- command = hci.HCI_Read_Local_Version_Information_Command()
546
- response = await host.send_command(command, check_result=True)
547
- if response.command_opcode != command.op_code:
564
+ response = await host.send_sync_command_raw(
565
+ hci.HCI_Read_Local_Version_Information_Command()
566
+ )
567
+ if (
568
+ not isinstance(
569
+ response.return_parameters,
570
+ hci.HCI_Read_Local_Version_Information_ReturnParameters,
571
+ )
572
+ or response.return_parameters.status != hci.HCI_SUCCESS
573
+ ):
548
574
  logger.error("failed to probe local version information")
549
575
  return None
550
576
 
@@ -569,7 +595,7 @@ class Driver(common.Driver):
569
595
  return driver_info
570
596
 
571
597
  @classmethod
572
- async def for_host(cls, host, force=False):
598
+ async def for_host(cls, host: Host, force: bool = False):
573
599
  # Check that a driver is needed for this host
574
600
  if not force and not cls.check(host):
575
601
  return None
@@ -624,15 +650,21 @@ class Driver(common.Driver):
624
650
 
625
651
  # TODO: load the firmware
626
652
 
627
- async def download_for_rtl8723b(self):
653
+ async def download_for_rtl8723b(self) -> int | None:
628
654
  if self.driver_info.has_rom_version:
629
- response = await self.host.send_command(
630
- HCI_RTK_Read_ROM_Version_Command(), check_result=True
655
+ response1 = await self.host.send_sync_command_raw(
656
+ HCI_RTK_Read_ROM_Version_Command()
631
657
  )
632
- if response.return_parameters.status != hci.HCI_SUCCESS:
658
+ if (
659
+ not isinstance(
660
+ response1.return_parameters,
661
+ HCI_RTK_Read_ROM_Version_ReturnParameters,
662
+ )
663
+ or response1.return_parameters.status != hci.HCI_SUCCESS
664
+ ):
633
665
  logger.warning("can't get ROM version")
634
666
  return None
635
- rom_version = response.return_parameters.version
667
+ rom_version = response1.return_parameters.version
636
668
  logger.debug(f"ROM version before download: {rom_version:04X}")
637
669
  else:
638
670
  rom_version = 0
@@ -667,21 +699,25 @@ class Driver(common.Driver):
667
699
  fragment_offset = fragment_index * RTK_FRAGMENT_LENGTH
668
700
  fragment = payload[fragment_offset : fragment_offset + RTK_FRAGMENT_LENGTH]
669
701
  logger.debug(f"downloading fragment {fragment_index}")
670
- await self.host.send_command(
671
- HCI_RTK_Download_Command(index=download_index, payload=fragment),
672
- check_result=True,
702
+ await self.host.send_sync_command(
703
+ HCI_RTK_Download_Command(index=download_index, payload=fragment)
673
704
  )
674
705
 
675
706
  logger.debug("download complete!")
676
707
 
677
708
  # Read the version again
678
- response = await self.host.send_command(
679
- HCI_RTK_Read_ROM_Version_Command(), check_result=True
709
+ response2 = await self.host.send_sync_command_raw(
710
+ HCI_RTK_Read_ROM_Version_Command()
680
711
  )
681
- if response.return_parameters.status != hci.HCI_SUCCESS:
712
+ if (
713
+ not isinstance(
714
+ response2.return_parameters, HCI_RTK_Read_ROM_Version_ReturnParameters
715
+ )
716
+ or response2.return_parameters.status != hci.HCI_SUCCESS
717
+ ):
682
718
  logger.warning("can't get ROM version")
683
719
  else:
684
- rom_version = response.return_parameters.version
720
+ rom_version = response2.return_parameters.version
685
721
  logger.debug(f"ROM version after download: {rom_version:02X}")
686
722
 
687
723
  return firmware.version
@@ -703,7 +739,7 @@ class Driver(common.Driver):
703
739
 
704
740
  async def init_controller(self):
705
741
  await self.download_firmware()
706
- await self.host.send_command(hci.HCI_Reset_Command(), check_result=True)
742
+ await self.host.send_sync_command(hci.HCI_Reset_Command())
707
743
  logger.info(f"loaded FW image {self.driver_info.fw_name}")
708
744
 
709
745