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/_version.py +2 -2
- bumble/apps/auracast.py +407 -0
- bumble/apps/bench.py +146 -35
- bumble/apps/controller_info.py +3 -3
- bumble/apps/rfcomm_bridge.py +511 -0
- bumble/core.py +689 -115
- bumble/device.py +441 -12
- bumble/hci.py +250 -12
- bumble/host.py +25 -0
- bumble/l2cap.py +5 -2
- bumble/pandora/host.py +3 -2
- bumble/profiles/bap.py +101 -5
- bumble/profiles/le_audio.py +49 -0
- bumble/profiles/pbp.py +46 -0
- bumble/rfcomm.py +158 -61
- bumble/sdp.py +1 -1
- {bumble-0.0.193.dist-info → bumble-0.0.195.dist-info}/METADATA +1 -1
- {bumble-0.0.193.dist-info → bumble-0.0.195.dist-info}/RECORD +22 -18
- {bumble-0.0.193.dist-info → bumble-0.0.195.dist-info}/entry_points.txt +1 -0
- {bumble-0.0.193.dist-info → bumble-0.0.195.dist-info}/LICENSE +0 -0
- {bumble-0.0.193.dist-info → bumble-0.0.195.dist-info}/WHEEL +0 -0
- {bumble-0.0.193.dist-info → bumble-0.0.195.dist-info}/top_level.txt +0 -0
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
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
370
|
+
initial_credits: int
|
|
369
371
|
|
|
370
372
|
def __post_init__(self) -> None:
|
|
371
|
-
if self.
|
|
373
|
+
if self.initial_credits < 1 or self.initial_credits > 7:
|
|
372
374
|
logger.warning(
|
|
373
|
-
f'
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
458
|
-
|
|
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.
|
|
464
|
-
self.
|
|
465
|
-
self.
|
|
466
|
-
self.
|
|
467
|
-
self.
|
|
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(
|
|
477
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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.
|
|
654
|
+
max_frame_size=self.rx_max_frame_size,
|
|
622
655
|
max_retransmissions=0,
|
|
623
|
-
|
|
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.
|
|
632
|
-
return self.
|
|
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
|
|
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],
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
993
|
-
self.
|
|
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(
|
|
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) ->
|
|
1039
|
-
return
|
|
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
|
|
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.
|
|
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,5 +1,5 @@
|
|
|
1
1
|
bumble/__init__.py,sha256=Q8jkz6rgl95IMAeInQVt_2GLoJl3DcEP2cxtrQ-ho5c,110
|
|
2
|
-
bumble/_version.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
27
|
+
bumble/host.py,sha256=H76N8V6mcn1h6zw2qu2blZOrT1Q7JNqeziA-SzNwC20,48224
|
|
28
28
|
bumble/keys.py,sha256=WbIQ7Ob81mW75qmEPQ2rBLfnqBMA-ts2yowWXP9UaCY,12654
|
|
29
|
-
bumble/l2cap.py,sha256=
|
|
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=
|
|
34
|
-
bumble/sdp.py,sha256=
|
|
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/
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
144
|
-
bumble-0.0.
|
|
145
|
-
bumble-0.0.
|
|
146
|
-
bumble-0.0.
|
|
147
|
-
bumble-0.0.
|
|
148
|
-
bumble-0.0.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|