bumble 0.0.193__py3-none-any.whl → 0.0.195__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/rfcomm.py CHANGED
@@ -106,9 +106,11 @@ CRC_TABLE = bytes([
106
106
  0XBA, 0X2B, 0X59, 0XC8, 0XBD, 0X2C, 0X5E, 0XCF
107
107
  ])
108
108
 
109
- RFCOMM_DEFAULT_L2CAP_MTU = 2048
110
- RFCOMM_DEFAULT_WINDOW_SIZE = 7
111
- RFCOMM_DEFAULT_MAX_FRAME_SIZE = 2000
109
+ RFCOMM_DEFAULT_L2CAP_MTU = 2048
110
+ RFCOMM_DEFAULT_INITIAL_CREDITS = 7
111
+ RFCOMM_DEFAULT_MAX_CREDITS = 32
112
+ RFCOMM_DEFAULT_CREDIT_THRESHOLD = RFCOMM_DEFAULT_MAX_CREDITS // 2
113
+ RFCOMM_DEFAULT_MAX_FRAME_SIZE = 2000
112
114
 
113
115
  RFCOMM_DYNAMIC_CHANNEL_NUMBER_START = 1
114
116
  RFCOMM_DYNAMIC_CHANNEL_NUMBER_END = 30
@@ -365,12 +367,12 @@ class RFCOMM_MCC_PN:
365
367
  ack_timer: int
366
368
  max_frame_size: int
367
369
  max_retransmissions: int
368
- window_size: int
370
+ initial_credits: int
369
371
 
370
372
  def __post_init__(self) -> None:
371
- if self.window_size < 1 or self.window_size > 7:
373
+ if self.initial_credits < 1 or self.initial_credits > 7:
372
374
  logger.warning(
373
- f'Error Recovery Window size {self.window_size} is out of range [1, 7].'
375
+ f'Initial credits {self.initial_credits} is out of range [1, 7].'
374
376
  )
375
377
 
376
378
  @staticmethod
@@ -382,7 +384,7 @@ class RFCOMM_MCC_PN:
382
384
  ack_timer=data[3],
383
385
  max_frame_size=data[4] | data[5] << 8,
384
386
  max_retransmissions=data[6],
385
- window_size=data[7] & 0x07,
387
+ initial_credits=data[7] & 0x07,
386
388
  )
387
389
 
388
390
  def __bytes__(self) -> bytes:
@@ -396,7 +398,7 @@ class RFCOMM_MCC_PN:
396
398
  (self.max_frame_size >> 8) & 0xFF,
397
399
  self.max_retransmissions & 0xFF,
398
400
  # Only 3 bits are meaningful.
399
- self.window_size & 0x07,
401
+ self.initial_credits & 0x07,
400
402
  ]
401
403
  )
402
404
 
@@ -446,40 +448,43 @@ class DLC(EventEmitter):
446
448
  DISCONNECTED = 0x04
447
449
  RESET = 0x05
448
450
 
449
- connection_result: Optional[asyncio.Future]
450
- _sink: Optional[Callable[[bytes], None]]
451
- _enqueued_rx_packets: collections.deque[bytes]
452
-
453
451
  def __init__(
454
452
  self,
455
453
  multiplexer: Multiplexer,
456
454
  dlci: int,
457
- max_frame_size: int,
458
- window_size: int,
455
+ tx_max_frame_size: int,
456
+ tx_initial_credits: int,
457
+ rx_max_frame_size: int,
458
+ rx_initial_credits: int,
459
459
  ) -> None:
460
460
  super().__init__()
461
461
  self.multiplexer = multiplexer
462
462
  self.dlci = dlci
463
- self.max_frame_size = max_frame_size
464
- self.window_size = window_size
465
- self.rx_credits = window_size
466
- self.rx_threshold = window_size // 2
467
- self.tx_credits = window_size
463
+ self.rx_max_frame_size = rx_max_frame_size
464
+ self.rx_initial_credits = rx_initial_credits
465
+ self.rx_max_credits = RFCOMM_DEFAULT_MAX_CREDITS
466
+ self.rx_credits = rx_initial_credits
467
+ self.rx_credits_threshold = RFCOMM_DEFAULT_CREDIT_THRESHOLD
468
+ self.tx_max_frame_size = tx_max_frame_size
469
+ self.tx_credits = tx_initial_credits
468
470
  self.tx_buffer = b''
469
471
  self.state = DLC.State.INIT
470
472
  self.role = multiplexer.role
471
473
  self.c_r = 1 if self.role == Multiplexer.Role.INITIATOR else 0
472
- self.connection_result = None
474
+ self.connection_result: Optional[asyncio.Future] = None
475
+ self.disconnection_result: Optional[asyncio.Future] = None
473
476
  self.drained = asyncio.Event()
474
477
  self.drained.set()
475
478
  # Queued packets when sink is not set.
476
- self._enqueued_rx_packets = collections.deque(maxlen=DEFAULT_RX_QUEUE_SIZE)
477
- self._sink = None
479
+ self._enqueued_rx_packets: collections.deque[bytes] = collections.deque(
480
+ maxlen=DEFAULT_RX_QUEUE_SIZE
481
+ )
482
+ self._sink: Optional[Callable[[bytes], None]] = None
478
483
 
479
484
  # Compute the MTU
480
485
  max_overhead = 4 + 1 # header with 2-byte length + fcs
481
486
  self.mtu = min(
482
- max_frame_size, self.multiplexer.l2cap_channel.peer_mtu - max_overhead
487
+ tx_max_frame_size, self.multiplexer.l2cap_channel.peer_mtu - max_overhead
483
488
  )
484
489
 
485
490
  @property
@@ -525,20 +530,35 @@ class DLC(EventEmitter):
525
530
  self.emit('open')
526
531
 
527
532
  def on_ua_frame(self, _frame: RFCOMM_Frame) -> None:
528
- if self.state != DLC.State.CONNECTING:
533
+ if self.state == DLC.State.CONNECTING:
534
+ # Exchange the modem status with the peer
535
+ msc = RFCOMM_MCC_MSC(dlci=self.dlci, fc=0, rtc=1, rtr=1, ic=0, dv=1)
536
+ mcc = RFCOMM_Frame.make_mcc(mcc_type=MccType.MSC, c_r=1, data=bytes(msc))
537
+ logger.debug(f'>>> MCC MSC Command: {msc}')
538
+ self.send_frame(RFCOMM_Frame.uih(c_r=self.c_r, dlci=0, information=mcc))
539
+
540
+ self.change_state(DLC.State.CONNECTED)
541
+ if self.connection_result:
542
+ self.connection_result.set_result(None)
543
+ self.connection_result = None
544
+ self.multiplexer.on_dlc_open_complete(self)
545
+ elif self.state == DLC.State.DISCONNECTING:
546
+ self.change_state(DLC.State.DISCONNECTED)
547
+ if self.disconnection_result:
548
+ self.disconnection_result.set_result(None)
549
+ self.disconnection_result = None
550
+ self.multiplexer.on_dlc_disconnection(self)
551
+ self.emit('close')
552
+ else:
529
553
  logger.warning(
530
- color('!!! received SABM when not in CONNECTING state', 'red')
554
+ color(
555
+ (
556
+ '!!! received UA frame when not in '
557
+ 'CONNECTING or DISCONNECTING state'
558
+ ),
559
+ 'red',
560
+ )
531
561
  )
532
- return
533
-
534
- # Exchange the modem status with the peer
535
- msc = RFCOMM_MCC_MSC(dlci=self.dlci, fc=0, rtc=1, rtr=1, ic=0, dv=1)
536
- mcc = RFCOMM_Frame.make_mcc(mcc_type=MccType.MSC, c_r=1, data=bytes(msc))
537
- logger.debug(f'>>> MCC MSC Command: {msc}')
538
- self.send_frame(RFCOMM_Frame.uih(c_r=self.c_r, dlci=0, information=mcc))
539
-
540
- self.change_state(DLC.State.CONNECTED)
541
- self.multiplexer.on_dlc_open_complete(self)
542
562
 
543
563
  def on_dm_frame(self, frame: RFCOMM_Frame) -> None:
544
564
  # TODO: handle all states
@@ -609,6 +629,19 @@ class DLC(EventEmitter):
609
629
  self.connection_result = asyncio.get_running_loop().create_future()
610
630
  self.send_frame(RFCOMM_Frame.sabm(c_r=self.c_r, dlci=self.dlci))
611
631
 
632
+ async def disconnect(self) -> None:
633
+ if self.state != DLC.State.CONNECTED:
634
+ raise InvalidStateError('invalid state')
635
+
636
+ self.disconnection_result = asyncio.get_running_loop().create_future()
637
+ self.change_state(DLC.State.DISCONNECTING)
638
+ self.send_frame(
639
+ RFCOMM_Frame.disc(
640
+ c_r=1 if self.role == Multiplexer.Role.INITIATOR else 0, dlci=self.dlci
641
+ )
642
+ )
643
+ await self.disconnection_result
644
+
612
645
  def accept(self) -> None:
613
646
  if self.state != DLC.State.INIT:
614
647
  raise InvalidStateError('invalid state')
@@ -618,9 +651,9 @@ class DLC(EventEmitter):
618
651
  cl=0xE0,
619
652
  priority=7,
620
653
  ack_timer=0,
621
- max_frame_size=self.max_frame_size,
654
+ max_frame_size=self.rx_max_frame_size,
622
655
  max_retransmissions=0,
623
- window_size=self.window_size,
656
+ initial_credits=self.rx_initial_credits,
624
657
  )
625
658
  mcc = RFCOMM_Frame.make_mcc(mcc_type=MccType.PN, c_r=0, data=bytes(pn))
626
659
  logger.debug(f'>>> PN Response: {pn}')
@@ -628,8 +661,8 @@ class DLC(EventEmitter):
628
661
  self.change_state(DLC.State.CONNECTING)
629
662
 
630
663
  def rx_credits_needed(self) -> int:
631
- if self.rx_credits <= self.rx_threshold:
632
- return self.window_size - self.rx_credits
664
+ if self.rx_credits <= self.rx_credits_threshold:
665
+ return self.rx_max_credits - self.rx_credits
633
666
 
634
667
  return 0
635
668
 
@@ -689,8 +722,28 @@ class DLC(EventEmitter):
689
722
  async def drain(self) -> None:
690
723
  await self.drained.wait()
691
724
 
725
+ def abort(self) -> None:
726
+ logger.debug(f'aborting DLC: {self}')
727
+ if self.connection_result:
728
+ self.connection_result.cancel()
729
+ self.connection_result = None
730
+ if self.disconnection_result:
731
+ self.disconnection_result.cancel()
732
+ self.disconnection_result = None
733
+ self.change_state(DLC.State.RESET)
734
+ self.emit('close')
735
+
692
736
  def __str__(self) -> str:
693
- return f'DLC(dlci={self.dlci},state={self.state.name})'
737
+ return (
738
+ f'DLC(dlci={self.dlci}, '
739
+ f'state={self.state.name}, '
740
+ f'rx_max_frame_size={self.rx_max_frame_size}, '
741
+ f'rx_credits={self.rx_credits}, '
742
+ f'rx_max_credits={self.rx_max_credits}, '
743
+ f'tx_max_frame_size={self.tx_max_frame_size}, '
744
+ f'tx_credits={self.tx_credits}'
745
+ ')'
746
+ )
694
747
 
695
748
 
696
749
  # -----------------------------------------------------------------------------
@@ -711,7 +764,7 @@ class Multiplexer(EventEmitter):
711
764
  connection_result: Optional[asyncio.Future]
712
765
  disconnection_result: Optional[asyncio.Future]
713
766
  open_result: Optional[asyncio.Future]
714
- acceptor: Optional[Callable[[int], bool]]
767
+ acceptor: Optional[Callable[[int], Optional[Tuple[int, int]]]]
715
768
  dlcs: Dict[int, DLC]
716
769
 
717
770
  def __init__(self, l2cap_channel: l2cap.ClassicChannel, role: Role) -> None:
@@ -723,11 +776,15 @@ class Multiplexer(EventEmitter):
723
776
  self.connection_result = None
724
777
  self.disconnection_result = None
725
778
  self.open_result = None
779
+ self.open_pn: Optional[RFCOMM_MCC_PN] = None
780
+ self.open_rx_max_credits = 0
726
781
  self.acceptor = None
727
782
 
728
783
  # Become a sink for the L2CAP channel
729
784
  l2cap_channel.sink = self.on_pdu
730
785
 
786
+ l2cap_channel.on('close', self.on_l2cap_channel_close)
787
+
731
788
  def change_state(self, new_state: State) -> None:
732
789
  logger.debug(f'{self} state change -> {color(new_state.name, "cyan")}')
733
790
  self.state = new_state
@@ -791,6 +848,7 @@ class Multiplexer(EventEmitter):
791
848
  'rfcomm',
792
849
  )
793
850
  )
851
+ self.open_result = None
794
852
  else:
795
853
  logger.warning(f'unexpected state for DM: {self}')
796
854
 
@@ -828,9 +886,16 @@ class Multiplexer(EventEmitter):
828
886
  else:
829
887
  if self.acceptor:
830
888
  channel_number = pn.dlci >> 1
831
- if self.acceptor(channel_number):
889
+ if dlc_params := self.acceptor(channel_number):
832
890
  # Create a new DLC
833
- dlc = DLC(self, pn.dlci, pn.max_frame_size, pn.window_size)
891
+ dlc = DLC(
892
+ self,
893
+ dlci=pn.dlci,
894
+ tx_max_frame_size=pn.max_frame_size,
895
+ tx_initial_credits=pn.initial_credits,
896
+ rx_max_frame_size=dlc_params[0],
897
+ rx_initial_credits=dlc_params[1],
898
+ )
834
899
  self.dlcs[pn.dlci] = dlc
835
900
 
836
901
  # Re-emit the handshake completion event
@@ -848,8 +913,17 @@ class Multiplexer(EventEmitter):
848
913
  # Response
849
914
  logger.debug(f'>>> PN Response: {pn}')
850
915
  if self.state == Multiplexer.State.OPENING:
851
- dlc = DLC(self, pn.dlci, pn.max_frame_size, pn.window_size)
916
+ assert self.open_pn
917
+ dlc = DLC(
918
+ self,
919
+ dlci=pn.dlci,
920
+ tx_max_frame_size=pn.max_frame_size,
921
+ tx_initial_credits=pn.initial_credits,
922
+ rx_max_frame_size=self.open_pn.max_frame_size,
923
+ rx_initial_credits=self.open_pn.initial_credits,
924
+ )
852
925
  self.dlcs[pn.dlci] = dlc
926
+ self.open_pn = None
853
927
  dlc.connect()
854
928
  else:
855
929
  logger.warning('ignoring PN response')
@@ -887,7 +961,7 @@ class Multiplexer(EventEmitter):
887
961
  self,
888
962
  channel: int,
889
963
  max_frame_size: int = RFCOMM_DEFAULT_MAX_FRAME_SIZE,
890
- window_size: int = RFCOMM_DEFAULT_WINDOW_SIZE,
964
+ initial_credits: int = RFCOMM_DEFAULT_INITIAL_CREDITS,
891
965
  ) -> DLC:
892
966
  if self.state != Multiplexer.State.CONNECTED:
893
967
  if self.state == Multiplexer.State.OPENING:
@@ -895,17 +969,19 @@ class Multiplexer(EventEmitter):
895
969
 
896
970
  raise InvalidStateError('not connected')
897
971
 
898
- pn = RFCOMM_MCC_PN(
972
+ self.open_pn = RFCOMM_MCC_PN(
899
973
  dlci=channel << 1,
900
974
  cl=0xF0,
901
975
  priority=7,
902
976
  ack_timer=0,
903
977
  max_frame_size=max_frame_size,
904
978
  max_retransmissions=0,
905
- window_size=window_size,
979
+ initial_credits=initial_credits,
980
+ )
981
+ mcc = RFCOMM_Frame.make_mcc(
982
+ mcc_type=MccType.PN, c_r=1, data=bytes(self.open_pn)
906
983
  )
907
- mcc = RFCOMM_Frame.make_mcc(mcc_type=MccType.PN, c_r=1, data=bytes(pn))
908
- logger.debug(f'>>> Sending MCC: {pn}')
984
+ logger.debug(f'>>> Sending MCC: {self.open_pn}')
909
985
  self.open_result = asyncio.get_running_loop().create_future()
910
986
  self.change_state(Multiplexer.State.OPENING)
911
987
  self.send_frame(
@@ -915,15 +991,31 @@ class Multiplexer(EventEmitter):
915
991
  information=mcc,
916
992
  )
917
993
  )
918
- result = await self.open_result
919
- self.open_result = None
920
- return result
994
+ return await self.open_result
921
995
 
922
996
  def on_dlc_open_complete(self, dlc: DLC) -> None:
923
997
  logger.debug(f'DLC [{dlc.dlci}] open complete')
998
+
924
999
  self.change_state(Multiplexer.State.CONNECTED)
1000
+
925
1001
  if self.open_result:
926
1002
  self.open_result.set_result(dlc)
1003
+ self.open_result = None
1004
+
1005
+ def on_dlc_disconnection(self, dlc: DLC) -> None:
1006
+ logger.debug(f'DLC [{dlc.dlci}] disconnection')
1007
+ self.dlcs.pop(dlc.dlci, None)
1008
+
1009
+ def on_l2cap_channel_close(self) -> None:
1010
+ logger.debug('L2CAP channel closed, cleaning up')
1011
+ if self.open_result:
1012
+ self.open_result.cancel()
1013
+ self.open_result = None
1014
+ if self.disconnection_result:
1015
+ self.disconnection_result.cancel()
1016
+ self.disconnection_result = None
1017
+ for dlc in self.dlcs.values():
1018
+ dlc.abort()
927
1019
 
928
1020
  def __str__(self) -> str:
929
1021
  return f'Multiplexer(state={self.state.name})'
@@ -982,15 +1074,13 @@ class Client:
982
1074
 
983
1075
  # -----------------------------------------------------------------------------
984
1076
  class Server(EventEmitter):
985
- acceptors: Dict[int, Callable[[DLC], None]]
986
-
987
1077
  def __init__(
988
1078
  self, device: Device, l2cap_mtu: int = RFCOMM_DEFAULT_L2CAP_MTU
989
1079
  ) -> None:
990
1080
  super().__init__()
991
1081
  self.device = device
992
- self.multiplexer = None
993
- self.acceptors = {}
1082
+ self.acceptors: Dict[int, Callable[[DLC], None]] = {}
1083
+ self.dlc_configs: Dict[int, Tuple[int, int]] = {}
994
1084
 
995
1085
  # Register ourselves with the L2CAP channel manager
996
1086
  self.l2cap_server = device.create_l2cap_server(
@@ -998,7 +1088,13 @@ class Server(EventEmitter):
998
1088
  handler=self.on_connection,
999
1089
  )
1000
1090
 
1001
- def listen(self, acceptor: Callable[[DLC], None], channel: int = 0) -> int:
1091
+ def listen(
1092
+ self,
1093
+ acceptor: Callable[[DLC], None],
1094
+ channel: int = 0,
1095
+ max_frame_size: int = RFCOMM_DEFAULT_MAX_FRAME_SIZE,
1096
+ initial_credits: int = RFCOMM_DEFAULT_INITIAL_CREDITS,
1097
+ ) -> int:
1002
1098
  if channel:
1003
1099
  if channel in self.acceptors:
1004
1100
  # Busy
@@ -1018,6 +1114,8 @@ class Server(EventEmitter):
1018
1114
  return 0
1019
1115
 
1020
1116
  self.acceptors[channel] = acceptor
1117
+ self.dlc_configs[channel] = (max_frame_size, initial_credits)
1118
+
1021
1119
  return channel
1022
1120
 
1023
1121
  def on_connection(self, l2cap_channel: l2cap.ClassicChannel) -> None:
@@ -1035,15 +1133,14 @@ class Server(EventEmitter):
1035
1133
  # Notify
1036
1134
  self.emit('start', multiplexer)
1037
1135
 
1038
- def accept_dlc(self, channel_number: int) -> bool:
1039
- return channel_number in self.acceptors
1136
+ def accept_dlc(self, channel_number: int) -> Optional[Tuple[int, int]]:
1137
+ return self.dlc_configs.get(channel_number)
1040
1138
 
1041
1139
  def on_dlc(self, dlc: DLC) -> None:
1042
1140
  logger.debug(f'@@@ new DLC connected: {dlc}')
1043
1141
 
1044
1142
  # Let the acceptor know
1045
- acceptor = self.acceptors.get(dlc.dlci >> 1)
1046
- if acceptor:
1143
+ if acceptor := self.acceptors.get(dlc.dlci >> 1):
1047
1144
  acceptor(dlc)
1048
1145
 
1049
1146
  def __enter__(self) -> Self:
bumble/sdp.py CHANGED
@@ -997,7 +997,7 @@ class Server:
997
997
  try:
998
998
  handler(sdp_pdu)
999
999
  except Exception as error:
1000
- logger.warning(f'{color("!!! Exception in handler:", "red")} {error}')
1000
+ logger.exception(f'{color("!!! Exception in handler:", "red")} {error}')
1001
1001
  self.send_response(
1002
1002
  SDP_ErrorResponse(
1003
1003
  transaction_id=sdp_pdu.transaction_id,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bumble
3
- Version: 0.0.193
3
+ Version: 0.0.195
4
4
  Summary: Bluetooth Stack for Apps, Emulation, Test and Experimentation
5
5
  Home-page: https://github.com/google/bumble
6
6
  Author: Google
@@ -1,5 +1,5 @@
1
1
  bumble/__init__.py,sha256=Q8jkz6rgl95IMAeInQVt_2GLoJl3DcEP2cxtrQ-ho5c,110
2
- bumble/_version.py,sha256=Gd5zR-hy663VWkpBiQSeTTwcqqLABTk22YvYNZ1-ZgY,415
2
+ bumble/_version.py,sha256=D6Pm_JfDbtXzRrUZBbi94mhpeVRVDGEGFimeorotXxw,415
3
3
  bumble/a2dp.py,sha256=VEeAOCfT1ZqpwnEgel6DJ32vxR8jYX3IAaBfCqPdWO8,22675
4
4
  bumble/at.py,sha256=kdrcsx2C8Rg61EWESD2QHwpZntkXkRBJLrPn9auv9K8,2961
5
5
  bumble/att.py,sha256=TGzhhBKCQPA_P_eDDSNASJVfa3dCr-QzzrRB3GekrI0,32366
@@ -12,35 +12,36 @@ bumble/codecs.py,sha256=Vc7FOo6d-6VCgDI0ibnLmX8vCZ4-jtX_-0vEUM-yOrI,15343
12
12
  bumble/colors.py,sha256=9H-qzGgMr-YoWdIFpcGPaiRvTvkCzz7FPIkpwqKyKug,3033
13
13
  bumble/company_ids.py,sha256=B68e2QPsDeRYP9jjbGs4GGDwEkGxcXGTsON_CHA0uuI,118528
14
14
  bumble/controller.py,sha256=XkYTQb2J5MhH_dGfnFkrLXdChFD2s1wSvqXaHQFeo48,59688
15
- bumble/core.py,sha256=l71AacyuFijZJH-kBYB41riW9SEsRtlVIPYyhnhPwmc,53132
15
+ bumble/core.py,sha256=_32etZ2sW4M-gY-XHmHwTKLrU_iAnMBocNngIkqhygM,71749
16
16
  bumble/crypto.py,sha256=L6z3dn9-dgKYRtOM6O3F6n6Ju4PwTM3LAFJtCg_ie78,9382
17
17
  bumble/decoder.py,sha256=N9nMvuVhuwpnfw7EDVuNe9uYY6B6c3RY2dh8RhRPC1U,9608
18
- bumble/device.py,sha256=W6u3zI9ivj5ypFycq8r7OGs0svBGrFVq3KplXI5minA,168751
18
+ bumble/device.py,sha256=sp7BilrHxRq7aMBQHomPx9owbus9MxV8_a2lgrvkYRc,183289
19
19
  bumble/gap.py,sha256=dRU2_TWvqTDx80hxeSbXlWIeWvptWH4_XbItG5y948Q,2138
20
20
  bumble/gatt.py,sha256=W7h8hEyxM8fu3HbAKYJ2HStb8NM7T98UICVnf4G9HDo,38447
21
21
  bumble/gatt_client.py,sha256=pJ29537m9L_cY2nrtEqZdssOEpg4147fF7vhz0BweyY,43071
22
22
  bumble/gatt_server.py,sha256=uPYbn2-y0MLnyR8xxpOf18gPua_Q49pSlMR1zxEnU-Q,37118
23
- bumble/hci.py,sha256=mL7xvgGyTz56Bn75yQSelFIl3Pys6ZImJIvZnjgkLCM,266912
23
+ bumble/hci.py,sha256=Bdfs2frYhcnUxGG1jYGcvBr_RcHpY1aNE3guQYpwszo,274340
24
24
  bumble/helpers.py,sha256=m0w4UgFFNDEnXwHrDyfRlcBObdVed2fqXGL0lvR3c8s,12733
25
25
  bumble/hfp.py,sha256=OsBDREelxhLMi_UZO9Kxlqzbts08CcGxoiicUgrYlXg,75353
26
26
  bumble/hid.py,sha256=Dd4rsmkRxcxt1IjoozJdu9Qd-QWruKJfsiYqTT89NDk,20590
27
- bumble/host.py,sha256=2hT-HRAlxPhVMoXUwn5E1-M90bbCNsWOam5nV3fnF1o,47175
27
+ bumble/host.py,sha256=H76N8V6mcn1h6zw2qu2blZOrT1Q7JNqeziA-SzNwC20,48224
28
28
  bumble/keys.py,sha256=WbIQ7Ob81mW75qmEPQ2rBLfnqBMA-ts2yowWXP9UaCY,12654
29
- bumble/l2cap.py,sha256=8m_1Kv6Tk-M-DilkAz_OXx0XsiLUhXycEZjUkICwyj0,81064
29
+ bumble/l2cap.py,sha256=YjUoLVR8gYpPzF4JyLoEE8Jhuu72fbW-eXYhXnFphSc,81170
30
30
  bumble/link.py,sha256=QiiMSCZ0z0ko2oUEMYg6nbq-h5A_3DLN4pjqAx_E-SA,23980
31
31
  bumble/pairing.py,sha256=tgPUba6xNxMi-2plm3xfRlzHq-uPRNZEIGWaN0qNGCs,9853
32
32
  bumble/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- bumble/rfcomm.py,sha256=M93g5CxBVvKEEDr_gxbg3immwnWIu_LP158NXVc5B64,36667
34
- bumble/sdp.py,sha256=_Jp3Ui7dwIm-1t5vvIDBzPOs_gLmFpnZBnPcYtgu6nY,45287
33
+ bumble/rfcomm.py,sha256=NHICkhwkQKwSFI_nE8RoFZGpq5PnZYdRph3GbyEYiYo,40683
34
+ bumble/sdp.py,sha256=yA3gkyyFaLkt-nHff3Ge5BgFgqX9uVgr56fWJVA1py8,45289
35
35
  bumble/smp.py,sha256=PcQj8mDoM8fBc4gKECHoOs0A2ukUAaSZQGdgLj6YzB0,76277
36
36
  bumble/snoop.py,sha256=_QfF36eylBW6Snd-_KYOwKaGiM8i_Ed-B5XoFIPt3Dg,5631
37
37
  bumble/utils.py,sha256=e0i-4d28-9zP3gYcd1rdNd669rkPnRs5oJCERUEDfxo,15099
38
38
  bumble/apps/README.md,sha256=XTwjRAY-EJWDXpl1V8K3Mw8B7kIqzUIUizRjVBVhoIE,1769
39
39
  bumble/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
- bumble/apps/bench.py,sha256=wwflVPDw_xaN_duZJF2oCrzAlIuJVR7rEKtVVTmzq1s,52359
40
+ bumble/apps/auracast.py,sha256=ZhaTN4PsYBaX-7MrtmK_VXJqNy-spXBysaOpPa8emoY,14865
41
+ bumble/apps/bench.py,sha256=nPACg5gQWxJ-6phze12FVCv1_WS2UjrWR7OUWj0o8PU,56350
41
42
  bumble/apps/ble_rpa_tool.py,sha256=ZQtsbfnLPd5qUAkEBPpNgJLRynBBc7q_9cDHKUW2SQ0,1701
42
43
  bumble/apps/console.py,sha256=rVR2jmP6Yd76B4zzGPYnpJFtgeYgq19CL6DMSe2-A1M,46093
43
- bumble/apps/controller_info.py,sha256=pgi6leHpwGdi3-kFUc7uFfuyGPTkNEoOws8cWycQVT0,9249
44
+ bumble/apps/controller_info.py,sha256=m29omI2r8q01GccgN6Lb-HfSsBjYdGpLDHlgZ99ldTM,9249
44
45
  bumble/apps/controller_loopback.py,sha256=VJAFsUdFwm2KgOrRuLADymMpZl5qVO0RGkDSr-1XKtY,7214
45
46
  bumble/apps/controllers.py,sha256=R6XJ1XpyuXlyqSCmI7PromVIcoYTcYfpmO-TqTYXnUI,2326
46
47
  bumble/apps/gatt_dump.py,sha256=-dCvCgjuHAp0h1zxm-gmqB4lVlSdas1Kp4cpzzx4gGw,4245
@@ -49,6 +50,7 @@ bumble/apps/hci_bridge.py,sha256=KISv352tKnsQsoxjkDiCQbMFmhnPWdnug5wSFAAXxEs,403
49
50
  bumble/apps/l2cap_bridge.py,sha256=524VgEmgCP4g7T0UdgmsePmNVhDFRJECeaZ_uzKsbco,13062
50
51
  bumble/apps/pair.py,sha256=COU2D7YAIn4lo5iuM0ClObA1zZqQCdrXOcnsiCm0YlQ,17529
51
52
  bumble/apps/pandora_server.py,sha256=5qaoLCpcZE2KsGO21-7t6Vg4dBjBWbnyOQXwrLhxkuE,1397
53
+ bumble/apps/rfcomm_bridge.py,sha256=PSszh4Qh1IsIw8ETs0fevOCAXEdVtqlgnV-ruzqGrZI,17215
52
54
  bumble/apps/scan.py,sha256=b6hIppiJqDfR7VFW2wl3-lkPdFvHLqYZKY8VjjNnhls,8366
53
55
  bumble/apps/show.py,sha256=8w0-8jLtN6IM6_58pOHbEmE1Rmxm71O48ACrXixC2jk,6218
54
56
  bumble/apps/unbond.py,sha256=LDPWpmgKLMGYDdIFGTdGciFDcUliZ0OmseEbGfJ-MAM,3176
@@ -72,18 +74,20 @@ bumble/drivers/rtk.py,sha256=MMxmUo85VkRhFuhbc9SJEZVL9dnRjmsU9k8djmbUGcA,21369
72
74
  bumble/pandora/__init__.py,sha256=5NBVmndeTulANawift0jPT9ISp562wyIHTZ-4uP34Mg,3283
73
75
  bumble/pandora/config.py,sha256=KD85n3oRbuvD65sRah2H0gpxEW4YbD7HbYbsxdcpDDA,2388
74
76
  bumble/pandora/device.py,sha256=LFqCWrgYkQWrFUSKArsAABXkge8sB2DhvaQoEsC4Jn0,5344
75
- bumble/pandora/host.py,sha256=d0qGQ769K9SSfBftEJcktTBebXZU6M8MMbh0xLYKwGk,39189
77
+ bumble/pandora/host.py,sha256=LnEQ3DJAhmJVgHA7VyokvypQejsi2VcbauSFYn1a9Jk,39235
76
78
  bumble/pandora/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
79
  bumble/pandora/security.py,sha256=YErueKNLsnmcRe6dKo724Ht-buOqmZl2Gauswcc8FW0,21946
78
80
  bumble/pandora/utils.py,sha256=Fq4glL0T5cJ2FODoDotmDNdYFOkTOR7DyyL8vkcxp20,3949
79
81
  bumble/profiles/__init__.py,sha256=yBGC8Ti5LvZuoh1F42XtfrBilb39T77_yuxESZeX2yI,581
80
82
  bumble/profiles/asha_service.py,sha256=J4i5jkJciZWMtTWJ1zGJkEx65DlAEIADqjCRYf_CWNs,7220
81
- bumble/profiles/bap.py,sha256=m5abJqb49iDPEkxc_EL3r1jOl2LKtKHSqB4E-4I5Dzw,47272
83
+ bumble/profiles/bap.py,sha256=4NQ-X_d7mUyD5VBQfmGwnmD6gyUTj_PL3H6bYpaP_wU,50486
82
84
  bumble/profiles/battery_service.py,sha256=w-uF4jLoDozJOoykimb2RkrKjVyCke6ts2-h-F1PYyc,2292
83
85
  bumble/profiles/cap.py,sha256=6gH7oOnUKjOggMPuB7rtbwj0AneoNmnWzQ_iR3io8e0,1945
84
86
  bumble/profiles/csip.py,sha256=wzSpNRCOMWtKw2Yd9OTAzPoFDoQWG-KYwWdA6sUkwiI,10102
85
87
  bumble/profiles/device_information_service.py,sha256=RfqnXywcwcSTiFalxd1LVTTdeWLxHGsMvlvr9fI0GJI,6193
86
88
  bumble/profiles/heart_rate_service.py,sha256=7V2LGcWLp6RurjWxsVgMWr3wPDt5aS9qjNxTbHcOK6o,8575
89
+ bumble/profiles/le_audio.py,sha256=BhdGwBdFRdBo35Z8ijRgch77Y1AfzNNM6iUU0LEmTy8,1651
90
+ bumble/profiles/pbp.py,sha256=51aoQcZMXzTzeatHd0zNVN7kYcv4atzr2OWpzxlSVP8,1630
87
91
  bumble/profiles/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
88
92
  bumble/profiles/vcp.py,sha256=wkbTf2NRCbBtvpXplpNJq4dzXp6JGeaEHeeC1kHqW7s,7897
89
93
  bumble/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -140,9 +144,9 @@ bumble/vendor/android/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
140
144
  bumble/vendor/android/hci.py,sha256=GZrkhaWmcMt1JpnRhv0NoySGkf2H4lNUV2f_omRZW0I,10741
141
145
  bumble/vendor/zephyr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
146
  bumble/vendor/zephyr/hci.py,sha256=d83bC0TvT947eN4roFjLkQefWtHOoNsr4xib2ctSkvA,3195
143
- bumble-0.0.193.dist-info/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
144
- bumble-0.0.193.dist-info/METADATA,sha256=gtflo1GIuoKchDFFY0xhmfpzgV8fK78dXSg4NXc349c,5753
145
- bumble-0.0.193.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
146
- bumble-0.0.193.dist-info/entry_points.txt,sha256=UkNj1KMZDhzOb7O4OU7Jn4YI5KaxJZgQF2GF64BwOlQ,883
147
- bumble-0.0.193.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
148
- bumble-0.0.193.dist-info/RECORD,,
147
+ bumble-0.0.195.dist-info/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
148
+ bumble-0.0.195.dist-info/METADATA,sha256=wTbIqANw5lgZcZyizDaAldO9zZ-XXKf33PX2LstfwVQ,5753
149
+ bumble-0.0.195.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
150
+ bumble-0.0.195.dist-info/entry_points.txt,sha256=AOFf_gnWbZ7jk5fzspxXHCQUay1ik71pK3HYO7sZQsk,937
151
+ bumble-0.0.195.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
152
+ bumble-0.0.195.dist-info/RECORD,,
@@ -10,6 +10,7 @@ bumble-l2cap-bridge = bumble.apps.l2cap_bridge:main
10
10
  bumble-link-relay = bumble.apps.link_relay.link_relay:main
11
11
  bumble-pair = bumble.apps.pair:main
12
12
  bumble-pandora-server = bumble.apps.pandora_server:main
13
+ bumble-rfcomm-bridge = bumble.apps.rfcomm_bridge:main
13
14
  bumble-rtk-fw-download = bumble.tools.rtk_fw_download:main
14
15
  bumble-rtk-util = bumble.tools.rtk_util:main
15
16
  bumble-scan = bumble.apps.scan:main