bumble 0.0.208__py3-none-any.whl → 0.0.210__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/a2dp.py +7 -7
- bumble/apps/auracast.py +37 -29
- bumble/apps/bench.py +9 -7
- bumble/apps/console.py +1 -1
- bumble/apps/lea_unicast/app.py +6 -2
- bumble/apps/pair.py +4 -3
- bumble/apps/player/player.py +3 -3
- bumble/apps/rfcomm_bridge.py +1 -1
- bumble/apps/speaker/speaker.py +4 -2
- bumble/att.py +12 -5
- bumble/avc.py +5 -5
- bumble/avdtp.py +9 -10
- bumble/avrcp.py +18 -19
- bumble/bridge.py +2 -2
- bumble/controller.py +13 -15
- bumble/core.py +61 -60
- bumble/device.py +193 -162
- bumble/drivers/__init__.py +2 -2
- bumble/gap.py +1 -1
- bumble/gatt.py +16 -0
- bumble/gatt_adapters.py +3 -3
- bumble/gatt_client.py +27 -21
- bumble/gatt_server.py +9 -10
- bumble/hci.py +109 -90
- bumble/hfp.py +3 -3
- bumble/hid.py +4 -3
- bumble/host.py +30 -19
- bumble/keys.py +3 -3
- bumble/l2cap.py +21 -19
- bumble/link.py +5 -6
- bumble/pairing.py +3 -3
- bumble/pandora/__init__.py +5 -5
- bumble/pandora/host.py +30 -23
- bumble/pandora/l2cap.py +2 -2
- bumble/pandora/security.py +17 -19
- bumble/pandora/utils.py +2 -2
- bumble/profiles/aics.py +6 -6
- bumble/profiles/ancs.py +513 -0
- bumble/profiles/ascs.py +17 -10
- bumble/profiles/asha.py +5 -5
- bumble/profiles/bass.py +1 -1
- bumble/profiles/csip.py +10 -10
- bumble/profiles/gatt_service.py +12 -12
- bumble/profiles/hap.py +16 -16
- bumble/profiles/mcp.py +26 -24
- bumble/profiles/pacs.py +6 -6
- bumble/profiles/pbp.py +1 -1
- bumble/profiles/vcs.py +6 -4
- bumble/profiles/vocs.py +3 -3
- bumble/rfcomm.py +8 -8
- bumble/sdp.py +1 -1
- bumble/smp.py +39 -33
- bumble/transport/__init__.py +24 -19
- bumble/transport/android_emulator.py +8 -4
- bumble/transport/android_netsim.py +8 -5
- bumble/transport/common.py +5 -1
- bumble/transport/file.py +1 -1
- bumble/transport/hci_socket.py +1 -1
- bumble/transport/pty.py +1 -1
- bumble/transport/pyusb.py +3 -3
- bumble/transport/serial.py +1 -1
- bumble/transport/tcp_client.py +1 -1
- bumble/transport/tcp_server.py +1 -1
- bumble/transport/udp.py +1 -1
- bumble/transport/unix.py +1 -1
- bumble/transport/usb.py +1 -3
- bumble/transport/vhci.py +2 -2
- bumble/transport/ws_client.py +6 -1
- bumble/transport/ws_server.py +1 -1
- bumble/utils.py +89 -76
- {bumble-0.0.208.dist-info → bumble-0.0.210.dist-info}/METADATA +3 -2
- {bumble-0.0.208.dist-info → bumble-0.0.210.dist-info}/RECORD +77 -76
- {bumble-0.0.208.dist-info → bumble-0.0.210.dist-info}/WHEEL +1 -1
- {bumble-0.0.208.dist-info → bumble-0.0.210.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.208.dist-info → bumble-0.0.210.dist-info/licenses}/LICENSE +0 -0
- {bumble-0.0.208.dist-info → bumble-0.0.210.dist-info}/top_level.txt +0 -0
bumble/hci.py
CHANGED
|
@@ -24,21 +24,23 @@ import logging
|
|
|
24
24
|
import secrets
|
|
25
25
|
import struct
|
|
26
26
|
from typing import Any, Callable, Dict, Iterable, List, Optional, Type, Union, ClassVar
|
|
27
|
+
from typing_extensions import Self
|
|
27
28
|
|
|
28
29
|
from bumble import crypto
|
|
29
30
|
from bumble.colors import color
|
|
30
31
|
from bumble.core import (
|
|
31
|
-
|
|
32
|
+
PhysicalTransport,
|
|
32
33
|
AdvertisingData,
|
|
33
34
|
DeviceClass,
|
|
34
35
|
InvalidArgumentError,
|
|
35
36
|
InvalidPacketError,
|
|
36
37
|
ProtocolError,
|
|
38
|
+
PhysicalTransport,
|
|
37
39
|
bit_flags_to_strings,
|
|
38
40
|
name_or_number,
|
|
39
41
|
padded_bytes,
|
|
40
42
|
)
|
|
41
|
-
from bumble
|
|
43
|
+
from bumble import utils
|
|
42
44
|
|
|
43
45
|
|
|
44
46
|
# -----------------------------------------------------------------------------
|
|
@@ -94,7 +96,7 @@ def map_class_of_device(class_of_device):
|
|
|
94
96
|
)
|
|
95
97
|
|
|
96
98
|
|
|
97
|
-
def phy_list_to_bits(phys: Optional[Iterable[
|
|
99
|
+
def phy_list_to_bits(phys: Optional[Iterable[Phy]]) -> int:
|
|
98
100
|
if phys is None:
|
|
99
101
|
return 0
|
|
100
102
|
|
|
@@ -700,30 +702,22 @@ HCI_ERROR_NAMES[HCI_SUCCESS] = 'HCI_SUCCESS'
|
|
|
700
702
|
HCI_COMMAND_STATUS_PENDING = 0
|
|
701
703
|
|
|
702
704
|
|
|
705
|
+
class Phy(enum.IntEnum):
|
|
706
|
+
LE_1M = 1
|
|
707
|
+
LE_2M = 2
|
|
708
|
+
LE_CODED = 3
|
|
709
|
+
|
|
710
|
+
|
|
703
711
|
# ACL
|
|
704
712
|
HCI_ACL_PB_FIRST_NON_FLUSHABLE = 0
|
|
705
713
|
HCI_ACL_PB_CONTINUATION = 1
|
|
706
714
|
HCI_ACL_PB_FIRST_FLUSHABLE = 2
|
|
707
715
|
HCI_ACK_PB_COMPLETE_L2CAP = 3
|
|
708
716
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
HCI_ROLE_NAMES = {
|
|
714
|
-
HCI_CENTRAL_ROLE: 'CENTRAL',
|
|
715
|
-
HCI_PERIPHERAL_ROLE: 'PERIPHERAL'
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
# LE PHY Types
|
|
719
|
-
HCI_LE_1M_PHY = 1
|
|
720
|
-
HCI_LE_2M_PHY = 2
|
|
721
|
-
HCI_LE_CODED_PHY = 3
|
|
722
|
-
|
|
723
|
-
HCI_LE_PHY_NAMES = {
|
|
724
|
-
HCI_LE_1M_PHY: 'LE 1M',
|
|
725
|
-
HCI_LE_2M_PHY: 'LE 2M',
|
|
726
|
-
HCI_LE_CODED_PHY: 'LE Coded'
|
|
717
|
+
HCI_LE_PHY_NAMES: dict[int,str] = {
|
|
718
|
+
Phy.LE_1M: 'LE 1M',
|
|
719
|
+
Phy.LE_2M: 'LE 2M',
|
|
720
|
+
Phy.LE_CODED: 'LE Coded'
|
|
727
721
|
}
|
|
728
722
|
|
|
729
723
|
HCI_LE_1M_PHY_BIT = 0
|
|
@@ -732,26 +726,20 @@ HCI_LE_CODED_PHY_BIT = 2
|
|
|
732
726
|
|
|
733
727
|
HCI_LE_PHY_BIT_NAMES = ['LE_1M_PHY', 'LE_2M_PHY', 'LE_CODED_PHY']
|
|
734
728
|
|
|
735
|
-
HCI_LE_PHY_TYPE_TO_BIT = {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
729
|
+
HCI_LE_PHY_TYPE_TO_BIT: dict[Phy, int] = {
|
|
730
|
+
Phy.LE_1M: HCI_LE_1M_PHY_BIT,
|
|
731
|
+
Phy.LE_2M: HCI_LE_2M_PHY_BIT,
|
|
732
|
+
Phy.LE_CODED: HCI_LE_CODED_PHY_BIT,
|
|
739
733
|
}
|
|
740
734
|
|
|
741
735
|
|
|
742
|
-
class Phy(enum.IntEnum):
|
|
743
|
-
LE_1M = HCI_LE_1M_PHY
|
|
744
|
-
LE_2M = HCI_LE_2M_PHY
|
|
745
|
-
LE_CODED = HCI_LE_CODED_PHY
|
|
746
|
-
|
|
747
|
-
|
|
748
736
|
class PhyBit(enum.IntFlag):
|
|
749
737
|
LE_1M = 1 << HCI_LE_1M_PHY_BIT
|
|
750
738
|
LE_2M = 1 << HCI_LE_2M_PHY_BIT
|
|
751
739
|
LE_CODED = 1 << HCI_LE_CODED_PHY_BIT
|
|
752
740
|
|
|
753
741
|
|
|
754
|
-
class CsRole(OpenIntEnum):
|
|
742
|
+
class CsRole(utils.OpenIntEnum):
|
|
755
743
|
INITIATOR = 0x00
|
|
756
744
|
REFLECTOR = 0x01
|
|
757
745
|
|
|
@@ -761,7 +749,7 @@ class CsRoleMask(enum.IntFlag):
|
|
|
761
749
|
REFLECTOR = 0x02
|
|
762
750
|
|
|
763
751
|
|
|
764
|
-
class CsSyncPhy(OpenIntEnum):
|
|
752
|
+
class CsSyncPhy(utils.OpenIntEnum):
|
|
765
753
|
LE_1M = 1
|
|
766
754
|
LE_2M = 2
|
|
767
755
|
LE_2M_2BT = 3
|
|
@@ -772,7 +760,7 @@ class CsSyncPhySupported(enum.IntFlag):
|
|
|
772
760
|
LE_2M_2BT = 0x02
|
|
773
761
|
|
|
774
762
|
|
|
775
|
-
class RttType(OpenIntEnum):
|
|
763
|
+
class RttType(utils.OpenIntEnum):
|
|
776
764
|
AA_ONLY = 0x00
|
|
777
765
|
SOUNDING_SEQUENCE_32_BIT = 0x01
|
|
778
766
|
SOUNDING_SEQUENCE_96_BIT = 0x02
|
|
@@ -782,7 +770,7 @@ class RttType(OpenIntEnum):
|
|
|
782
770
|
RANDOM_SEQUENCE_128_BIT = 0x06
|
|
783
771
|
|
|
784
772
|
|
|
785
|
-
class CsSnr(OpenIntEnum):
|
|
773
|
+
class CsSnr(utils.OpenIntEnum):
|
|
786
774
|
SNR_18_DB = 0x00
|
|
787
775
|
SNR_21_DB = 0x01
|
|
788
776
|
SNR_24_DB = 0x02
|
|
@@ -791,26 +779,39 @@ class CsSnr(OpenIntEnum):
|
|
|
791
779
|
NOT_APPLIED = 0xFF
|
|
792
780
|
|
|
793
781
|
|
|
794
|
-
class CsDoneStatus(OpenIntEnum):
|
|
782
|
+
class CsDoneStatus(utils.OpenIntEnum):
|
|
795
783
|
ALL_RESULTS_COMPLETED = 0x00
|
|
796
784
|
PARTIAL = 0x01
|
|
797
785
|
ABORTED = 0x0F
|
|
798
786
|
|
|
799
787
|
|
|
800
|
-
class CsProcedureAbortReason(OpenIntEnum):
|
|
788
|
+
class CsProcedureAbortReason(utils.OpenIntEnum):
|
|
801
789
|
NO_ABORT = 0x00
|
|
802
790
|
LOCAL_HOST_OR_REMOTE_REQUEST = 0x01
|
|
803
791
|
CHANNEL_MAP_UPDATE_INSTANT_PASSED = 0x02
|
|
804
792
|
UNSPECIFIED = 0x0F
|
|
805
793
|
|
|
806
794
|
|
|
807
|
-
class CsSubeventAbortReason(OpenIntEnum):
|
|
795
|
+
class CsSubeventAbortReason(utils.OpenIntEnum):
|
|
808
796
|
NO_ABORT = 0x00
|
|
809
797
|
LOCAL_HOST_OR_REMOTE_REQUEST = 0x01
|
|
810
798
|
NO_CS_SYNC_RECEIVED = 0x02
|
|
811
799
|
SCHEDULING_CONFLICT_OR_LIMITED_RESOURCES = 0x03
|
|
812
800
|
UNSPECIFIED = 0x0F
|
|
813
801
|
|
|
802
|
+
class Role(enum.IntEnum):
|
|
803
|
+
CENTRAL = 0
|
|
804
|
+
PERIPHERAL = 1
|
|
805
|
+
|
|
806
|
+
# For Backward Compatibility.
|
|
807
|
+
HCI_CENTRAL_ROLE = Role.CENTRAL
|
|
808
|
+
HCI_PERIPHERAL_ROLE = Role.PERIPHERAL
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
HCI_LE_1M_PHY = Phy.LE_1M
|
|
812
|
+
HCI_LE_2M_PHY = Phy.LE_2M
|
|
813
|
+
HCI_LE_CODED_PHY = Phy.LE_CODED
|
|
814
|
+
|
|
814
815
|
|
|
815
816
|
# Connection Parameters
|
|
816
817
|
HCI_CONNECTION_INTERVAL_MS_PER_UNIT = 1.25
|
|
@@ -889,10 +890,15 @@ HCI_LINK_TYPE_NAMES = {
|
|
|
889
890
|
}
|
|
890
891
|
|
|
891
892
|
# Address types
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
893
|
+
class AddressType(utils.OpenIntEnum):
|
|
894
|
+
PUBLIC_DEVICE = 0x00
|
|
895
|
+
RANDOM_DEVICE = 0x01
|
|
896
|
+
PUBLIC_IDENTITY = 0x02
|
|
897
|
+
RANDOM_IDENTITY = 0x03
|
|
898
|
+
# (Directed Only) Address is RPA, but controller cannot resolve.
|
|
899
|
+
UNABLE_TO_RESOLVE = 0xFE
|
|
900
|
+
# (Extended Only) No address.
|
|
901
|
+
ANONYMOUS = 0xFF
|
|
896
902
|
|
|
897
903
|
# Supported Commands Masks
|
|
898
904
|
# See Bluetooth spec @ 6.27 SUPPORTED COMMANDS
|
|
@@ -1233,7 +1239,7 @@ HCI_SUPPORTED_COMMANDS_MASKS = {
|
|
|
1233
1239
|
|
|
1234
1240
|
# LE Supported Features
|
|
1235
1241
|
# See Bluetooth spec @ Vol 6, Part B, 4.6 FEATURE SUPPORT
|
|
1236
|
-
class LeFeature(OpenIntEnum):
|
|
1242
|
+
class LeFeature(utils.OpenIntEnum):
|
|
1237
1243
|
LE_ENCRYPTION = 0
|
|
1238
1244
|
CONNECTION_PARAMETERS_REQUEST_PROCEDURE = 1
|
|
1239
1245
|
EXTENDED_REJECT_INDICATION = 2
|
|
@@ -1531,7 +1537,7 @@ RTT_TYPE_SPEC = {'size': 1, 'mapper': lambda x: RttType(x).name}
|
|
|
1531
1537
|
CS_SNR_SPEC = {'size': 1, 'mapper': lambda x: CsSnr(x).name}
|
|
1532
1538
|
|
|
1533
1539
|
|
|
1534
|
-
class CodecID(OpenIntEnum):
|
|
1540
|
+
class CodecID(utils.OpenIntEnum):
|
|
1535
1541
|
# fmt: off
|
|
1536
1542
|
U_LOG = 0x00
|
|
1537
1543
|
A_LOG = 0x01
|
|
@@ -1582,8 +1588,8 @@ class HCI_Constant:
|
|
|
1582
1588
|
return HCI_ERROR_NAMES.get(status, f'0x{status:02X}')
|
|
1583
1589
|
|
|
1584
1590
|
@staticmethod
|
|
1585
|
-
def role_name(role):
|
|
1586
|
-
return
|
|
1591
|
+
def role_name(role: int) -> str:
|
|
1592
|
+
return Role(role).name
|
|
1587
1593
|
|
|
1588
1594
|
@staticmethod
|
|
1589
1595
|
def le_phy_name(phy):
|
|
@@ -1949,17 +1955,10 @@ class Address:
|
|
|
1949
1955
|
address[0] is the LSB of the address, address[5] is the MSB.
|
|
1950
1956
|
'''
|
|
1951
1957
|
|
|
1952
|
-
PUBLIC_DEVICE_ADDRESS =
|
|
1953
|
-
RANDOM_DEVICE_ADDRESS =
|
|
1954
|
-
PUBLIC_IDENTITY_ADDRESS =
|
|
1955
|
-
RANDOM_IDENTITY_ADDRESS =
|
|
1956
|
-
|
|
1957
|
-
ADDRESS_TYPE_NAMES = {
|
|
1958
|
-
PUBLIC_DEVICE_ADDRESS: 'PUBLIC_DEVICE_ADDRESS',
|
|
1959
|
-
RANDOM_DEVICE_ADDRESS: 'RANDOM_DEVICE_ADDRESS',
|
|
1960
|
-
PUBLIC_IDENTITY_ADDRESS: 'PUBLIC_IDENTITY_ADDRESS',
|
|
1961
|
-
RANDOM_IDENTITY_ADDRESS: 'RANDOM_IDENTITY_ADDRESS',
|
|
1962
|
-
}
|
|
1958
|
+
PUBLIC_DEVICE_ADDRESS = AddressType.PUBLIC_DEVICE
|
|
1959
|
+
RANDOM_DEVICE_ADDRESS = AddressType.RANDOM_DEVICE
|
|
1960
|
+
PUBLIC_IDENTITY_ADDRESS = AddressType.PUBLIC_IDENTITY
|
|
1961
|
+
RANDOM_IDENTITY_ADDRESS = AddressType.RANDOM_IDENTITY
|
|
1963
1962
|
|
|
1964
1963
|
# Type declarations
|
|
1965
1964
|
NIL: Address
|
|
@@ -1969,40 +1968,44 @@ class Address:
|
|
|
1969
1968
|
# pylint: disable-next=unnecessary-lambda
|
|
1970
1969
|
ADDRESS_TYPE_SPEC = {'size': 1, 'mapper': lambda x: Address.address_type_name(x)}
|
|
1971
1970
|
|
|
1972
|
-
@
|
|
1973
|
-
def address_type_name(address_type):
|
|
1974
|
-
return
|
|
1971
|
+
@classmethod
|
|
1972
|
+
def address_type_name(cls: type[Self], address_type: int) -> str:
|
|
1973
|
+
return AddressType(address_type).name
|
|
1975
1974
|
|
|
1976
|
-
@
|
|
1977
|
-
def from_string_for_transport(
|
|
1978
|
-
|
|
1975
|
+
@classmethod
|
|
1976
|
+
def from_string_for_transport(
|
|
1977
|
+
cls: type[Self], string: str, transport: PhysicalTransport
|
|
1978
|
+
) -> Self:
|
|
1979
|
+
if transport == PhysicalTransport.BR_EDR:
|
|
1979
1980
|
address_type = Address.PUBLIC_DEVICE_ADDRESS
|
|
1980
1981
|
else:
|
|
1981
1982
|
address_type = Address.RANDOM_DEVICE_ADDRESS
|
|
1982
|
-
return
|
|
1983
|
+
return cls(string, address_type)
|
|
1983
1984
|
|
|
1984
|
-
@
|
|
1985
|
-
def parse_address(data, offset):
|
|
1985
|
+
@classmethod
|
|
1986
|
+
def parse_address(cls: type[Self], data: bytes, offset: int) -> tuple[int, Self]:
|
|
1986
1987
|
# Fix the type to a default value. This is used for parsing type-less Classic
|
|
1987
1988
|
# addresses
|
|
1988
|
-
return
|
|
1989
|
-
data, offset, Address.PUBLIC_DEVICE_ADDRESS
|
|
1990
|
-
)
|
|
1989
|
+
return cls.parse_address_with_type(data, offset, Address.PUBLIC_DEVICE_ADDRESS)
|
|
1991
1990
|
|
|
1992
|
-
@
|
|
1993
|
-
def parse_random_address(
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
)
|
|
1991
|
+
@classmethod
|
|
1992
|
+
def parse_random_address(
|
|
1993
|
+
cls: type[Self], data: bytes, offset: int
|
|
1994
|
+
) -> tuple[int, Self]:
|
|
1995
|
+
return cls.parse_address_with_type(data, offset, Address.RANDOM_DEVICE_ADDRESS)
|
|
1997
1996
|
|
|
1998
|
-
@
|
|
1999
|
-
def parse_address_with_type(
|
|
2000
|
-
|
|
1997
|
+
@classmethod
|
|
1998
|
+
def parse_address_with_type(
|
|
1999
|
+
cls: type[Self], data: bytes, offset: int, address_type: AddressType
|
|
2000
|
+
) -> tuple[int, Self]:
|
|
2001
|
+
return offset + 6, cls(data[offset : offset + 6], address_type)
|
|
2001
2002
|
|
|
2002
|
-
@
|
|
2003
|
-
def parse_address_preceded_by_type(
|
|
2004
|
-
|
|
2005
|
-
|
|
2003
|
+
@classmethod
|
|
2004
|
+
def parse_address_preceded_by_type(
|
|
2005
|
+
cls: type[Self], data: bytes, offset: int
|
|
2006
|
+
) -> tuple[int, Self]:
|
|
2007
|
+
address_type = AddressType(data[offset - 1])
|
|
2008
|
+
return cls.parse_address_with_type(data, offset, address_type)
|
|
2006
2009
|
|
|
2007
2010
|
@classmethod
|
|
2008
2011
|
def generate_static_address(cls) -> Address:
|
|
@@ -2042,8 +2045,10 @@ class Address:
|
|
|
2042
2045
|
)
|
|
2043
2046
|
|
|
2044
2047
|
def __init__(
|
|
2045
|
-
self,
|
|
2046
|
-
|
|
2048
|
+
self,
|
|
2049
|
+
address: Union[bytes, str],
|
|
2050
|
+
address_type: AddressType = RANDOM_DEVICE_ADDRESS,
|
|
2051
|
+
) -> None:
|
|
2047
2052
|
'''
|
|
2048
2053
|
Initialize an instance. `address` may be a byte array in little-endian
|
|
2049
2054
|
format, or a hex string in big-endian format (with optional ':'
|
|
@@ -4878,6 +4883,20 @@ class HCI_LE_Periodic_Advertising_Sync_Transfer_Command(HCI_Command):
|
|
|
4878
4883
|
'''
|
|
4879
4884
|
|
|
4880
4885
|
|
|
4886
|
+
# -----------------------------------------------------------------------------
|
|
4887
|
+
@HCI_Command.command(
|
|
4888
|
+
fields=[('connection_handle', 2), ('service_data', 2), ('advertising_handle', 1)],
|
|
4889
|
+
return_parameters_fields=[
|
|
4890
|
+
('status', STATUS_SPEC),
|
|
4891
|
+
('connection_handle', 2),
|
|
4892
|
+
],
|
|
4893
|
+
)
|
|
4894
|
+
class HCI_LE_Periodic_Advertising_Set_Info_Transfer_Command(HCI_Command):
|
|
4895
|
+
'''
|
|
4896
|
+
See Bluetooth spec @ 7.8.90 LE Periodic Advertising Set Info Transfer Command
|
|
4897
|
+
'''
|
|
4898
|
+
|
|
4899
|
+
|
|
4881
4900
|
# -----------------------------------------------------------------------------
|
|
4882
4901
|
@HCI_Command.command(
|
|
4883
4902
|
fields=[
|
|
@@ -5351,11 +5370,11 @@ class HCI_LE_CS_Create_Config_Command(HCI_Command):
|
|
|
5351
5370
|
See Bluetooth spec @ 7.8.137 LE CS Create Config command
|
|
5352
5371
|
'''
|
|
5353
5372
|
|
|
5354
|
-
class ChannelSelectionType(OpenIntEnum):
|
|
5373
|
+
class ChannelSelectionType(utils.OpenIntEnum):
|
|
5355
5374
|
ALGO_3B = 0
|
|
5356
5375
|
ALGO_3C = 1
|
|
5357
5376
|
|
|
5358
|
-
class Ch3cShape(OpenIntEnum):
|
|
5377
|
+
class Ch3cShape(utils.OpenIntEnum):
|
|
5359
5378
|
HAT = 0x00
|
|
5360
5379
|
X = 0x01
|
|
5361
5380
|
|
|
@@ -6184,13 +6203,13 @@ class HCI_LE_Periodic_Advertising_Report_Event(HCI_LE_Meta_Event):
|
|
|
6184
6203
|
TX_POWER_INFORMATION_NOT_AVAILABLE = 0x7F
|
|
6185
6204
|
RSSI_NOT_AVAILABLE = 0x7F
|
|
6186
6205
|
|
|
6187
|
-
class CteType(OpenIntEnum):
|
|
6206
|
+
class CteType(utils.OpenIntEnum):
|
|
6188
6207
|
AOA_CONSTANT_TONE_EXTENSION = 0x00
|
|
6189
6208
|
AOD_CONSTANT_TONE_EXTENSION_1US = 0x01
|
|
6190
6209
|
AOD_CONSTANT_TONE_EXTENSION_2US = 0x02
|
|
6191
6210
|
NO_CONSTANT_TONE_EXTENSION = 0xFF
|
|
6192
6211
|
|
|
6193
|
-
class DataStatus(OpenIntEnum):
|
|
6212
|
+
class DataStatus(utils.OpenIntEnum):
|
|
6194
6213
|
DATA_COMPLETE = 0x00
|
|
6195
6214
|
DATA_INCOMPLETE_MORE_TO_COME = 0x01
|
|
6196
6215
|
DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME = 0x02
|
|
@@ -6571,7 +6590,7 @@ class HCI_LE_CS_Config_Complete_Event(HCI_LE_Meta_Event):
|
|
|
6571
6590
|
See Bluetooth spec @ 7.7.65.42 LE CS Config Complete event
|
|
6572
6591
|
'''
|
|
6573
6592
|
|
|
6574
|
-
class Action(OpenIntEnum):
|
|
6593
|
+
class Action(utils.OpenIntEnum):
|
|
6575
6594
|
REMOVED = 0
|
|
6576
6595
|
CREATED = 1
|
|
6577
6596
|
|
|
@@ -6623,7 +6642,7 @@ class HCI_LE_CS_Procedure_Enable_Complete_Event(HCI_LE_Meta_Event):
|
|
|
6623
6642
|
See Bluetooth spec @ 7.7.65.43 LE CS Procedure Enable Complete event
|
|
6624
6643
|
'''
|
|
6625
6644
|
|
|
6626
|
-
class State(OpenIntEnum):
|
|
6645
|
+
class State(utils.OpenIntEnum):
|
|
6627
6646
|
DISABLED = 0
|
|
6628
6647
|
ENABLED = 1
|
|
6629
6648
|
|
|
@@ -6965,7 +6984,7 @@ class HCI_QOS_Setup_Complete_Event(HCI_Event):
|
|
|
6965
6984
|
See Bluetooth spec @ 7.7.13 QoS Setup Complete Event
|
|
6966
6985
|
'''
|
|
6967
6986
|
|
|
6968
|
-
class ServiceType(OpenIntEnum):
|
|
6987
|
+
class ServiceType(utils.OpenIntEnum):
|
|
6969
6988
|
NO_TRAFFIC_AVAILABLE = 0x00
|
|
6970
6989
|
BEST_EFFORT_AVAILABLE = 0x01
|
|
6971
6990
|
GUARANTEED_AVAILABLE = 0x02
|
bumble/hfp.py
CHANGED
|
@@ -24,7 +24,6 @@ import asyncio
|
|
|
24
24
|
import dataclasses
|
|
25
25
|
import enum
|
|
26
26
|
import traceback
|
|
27
|
-
import pyee
|
|
28
27
|
import re
|
|
29
28
|
from typing import (
|
|
30
29
|
Dict,
|
|
@@ -45,6 +44,7 @@ from bumble import at
|
|
|
45
44
|
from bumble import device
|
|
46
45
|
from bumble import rfcomm
|
|
47
46
|
from bumble import sdp
|
|
47
|
+
from bumble import utils
|
|
48
48
|
from bumble.colors import color
|
|
49
49
|
from bumble.core import (
|
|
50
50
|
ProtocolError,
|
|
@@ -690,7 +690,7 @@ class HfIndicatorState:
|
|
|
690
690
|
current_status: int = 0
|
|
691
691
|
|
|
692
692
|
|
|
693
|
-
class HfProtocol(
|
|
693
|
+
class HfProtocol(utils.EventEmitter):
|
|
694
694
|
"""
|
|
695
695
|
Implementation for the Hands-Free side of the Hands-Free profile.
|
|
696
696
|
|
|
@@ -1146,7 +1146,7 @@ class HfProtocol(pyee.EventEmitter):
|
|
|
1146
1146
|
logger.error(traceback.format_exc())
|
|
1147
1147
|
|
|
1148
1148
|
|
|
1149
|
-
class AgProtocol(
|
|
1149
|
+
class AgProtocol(utils.EventEmitter):
|
|
1150
1150
|
"""
|
|
1151
1151
|
Implementation for the Audio-Gateway side of the Hands-Free profile.
|
|
1152
1152
|
|
bumble/hid.py
CHANGED
|
@@ -22,11 +22,12 @@ import enum
|
|
|
22
22
|
import struct
|
|
23
23
|
|
|
24
24
|
from abc import ABC, abstractmethod
|
|
25
|
-
from pyee import EventEmitter
|
|
26
25
|
from typing import Optional, Callable
|
|
27
26
|
from typing_extensions import override
|
|
28
27
|
|
|
29
|
-
from bumble import l2cap
|
|
28
|
+
from bumble import l2cap
|
|
29
|
+
from bumble import device
|
|
30
|
+
from bumble import utils
|
|
30
31
|
from bumble.core import InvalidStateError, ProtocolError
|
|
31
32
|
from bumble.hci import Address
|
|
32
33
|
|
|
@@ -195,7 +196,7 @@ class SendHandshakeMessage(Message):
|
|
|
195
196
|
|
|
196
197
|
|
|
197
198
|
# -----------------------------------------------------------------------------
|
|
198
|
-
class HID(ABC, EventEmitter):
|
|
199
|
+
class HID(ABC, utils.EventEmitter):
|
|
199
200
|
l2cap_ctrl_channel: Optional[l2cap.ClassicChannel] = None
|
|
200
201
|
l2cap_intr_channel: Optional[l2cap.ClassicChannel] = None
|
|
201
202
|
connection: Optional[device.Connection] = None
|
bumble/host.py
CHANGED
|
@@ -34,7 +34,6 @@ from typing import (
|
|
|
34
34
|
TYPE_CHECKING,
|
|
35
35
|
)
|
|
36
36
|
|
|
37
|
-
import pyee
|
|
38
37
|
|
|
39
38
|
from bumble.colors import color
|
|
40
39
|
from bumble.l2cap import L2CAP_PDU
|
|
@@ -42,16 +41,16 @@ from bumble.snoop import Snooper
|
|
|
42
41
|
from bumble import drivers
|
|
43
42
|
from bumble import hci
|
|
44
43
|
from bumble.core import (
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
PhysicalTransport,
|
|
45
|
+
PhysicalTransport,
|
|
47
46
|
ConnectionPHY,
|
|
48
47
|
ConnectionParameters,
|
|
49
48
|
)
|
|
50
|
-
from bumble
|
|
49
|
+
from bumble import utils
|
|
51
50
|
from bumble.transport.common import TransportLostError
|
|
52
51
|
|
|
53
52
|
if TYPE_CHECKING:
|
|
54
|
-
from .transport.common import TransportSink, TransportSource
|
|
53
|
+
from bumble.transport.common import TransportSink, TransportSource
|
|
55
54
|
|
|
56
55
|
|
|
57
56
|
# -----------------------------------------------------------------------------
|
|
@@ -61,7 +60,7 @@ logger = logging.getLogger(__name__)
|
|
|
61
60
|
|
|
62
61
|
|
|
63
62
|
# -----------------------------------------------------------------------------
|
|
64
|
-
class DataPacketQueue(
|
|
63
|
+
class DataPacketQueue(utils.EventEmitter):
|
|
65
64
|
"""
|
|
66
65
|
Flow-control queue for host->controller data packets (ACL, ISO).
|
|
67
66
|
|
|
@@ -186,7 +185,11 @@ class DataPacketQueue(pyee.EventEmitter):
|
|
|
186
185
|
# -----------------------------------------------------------------------------
|
|
187
186
|
class Connection:
|
|
188
187
|
def __init__(
|
|
189
|
-
self,
|
|
188
|
+
self,
|
|
189
|
+
host: Host,
|
|
190
|
+
handle: int,
|
|
191
|
+
peer_address: hci.Address,
|
|
192
|
+
transport: PhysicalTransport,
|
|
190
193
|
):
|
|
191
194
|
self.host = host
|
|
192
195
|
self.handle = handle
|
|
@@ -195,7 +198,7 @@ class Connection:
|
|
|
195
198
|
self.transport = transport
|
|
196
199
|
acl_packet_queue: Optional[DataPacketQueue] = (
|
|
197
200
|
host.le_acl_packet_queue
|
|
198
|
-
if transport ==
|
|
201
|
+
if transport == PhysicalTransport.LE
|
|
199
202
|
else host.acl_packet_queue
|
|
200
203
|
)
|
|
201
204
|
assert acl_packet_queue
|
|
@@ -230,7 +233,7 @@ class IsoLink:
|
|
|
230
233
|
|
|
231
234
|
|
|
232
235
|
# -----------------------------------------------------------------------------
|
|
233
|
-
class Host(
|
|
236
|
+
class Host(utils.EventEmitter):
|
|
234
237
|
connections: Dict[int, Connection]
|
|
235
238
|
cis_links: Dict[int, IsoLink]
|
|
236
239
|
bis_links: Dict[int, IsoLink]
|
|
@@ -962,7 +965,7 @@ class Host(AbortableEventEmitter):
|
|
|
962
965
|
self,
|
|
963
966
|
event.connection_handle,
|
|
964
967
|
event.peer_address,
|
|
965
|
-
|
|
968
|
+
PhysicalTransport.LE,
|
|
966
969
|
)
|
|
967
970
|
self.connections[event.connection_handle] = connection
|
|
968
971
|
|
|
@@ -975,11 +978,11 @@ class Host(AbortableEventEmitter):
|
|
|
975
978
|
self.emit(
|
|
976
979
|
'connection',
|
|
977
980
|
event.connection_handle,
|
|
978
|
-
|
|
981
|
+
PhysicalTransport.LE,
|
|
979
982
|
event.peer_address,
|
|
980
983
|
getattr(event, 'local_resolvable_private_address', None),
|
|
981
984
|
getattr(event, 'peer_resolvable_private_address', None),
|
|
982
|
-
event.role,
|
|
985
|
+
hci.Role(event.role),
|
|
983
986
|
connection_parameters,
|
|
984
987
|
)
|
|
985
988
|
else:
|
|
@@ -987,7 +990,10 @@ class Host(AbortableEventEmitter):
|
|
|
987
990
|
|
|
988
991
|
# Notify the listeners
|
|
989
992
|
self.emit(
|
|
990
|
-
'connection_failure',
|
|
993
|
+
'connection_failure',
|
|
994
|
+
PhysicalTransport.LE,
|
|
995
|
+
event.peer_address,
|
|
996
|
+
event.status,
|
|
991
997
|
)
|
|
992
998
|
|
|
993
999
|
def on_hci_le_enhanced_connection_complete_event(self, event):
|
|
@@ -1012,7 +1018,7 @@ class Host(AbortableEventEmitter):
|
|
|
1012
1018
|
self,
|
|
1013
1019
|
event.connection_handle,
|
|
1014
1020
|
event.bd_addr,
|
|
1015
|
-
|
|
1021
|
+
PhysicalTransport.BR_EDR,
|
|
1016
1022
|
)
|
|
1017
1023
|
self.connections[event.connection_handle] = connection
|
|
1018
1024
|
|
|
@@ -1020,7 +1026,7 @@ class Host(AbortableEventEmitter):
|
|
|
1020
1026
|
self.emit(
|
|
1021
1027
|
'connection',
|
|
1022
1028
|
event.connection_handle,
|
|
1023
|
-
|
|
1029
|
+
PhysicalTransport.BR_EDR,
|
|
1024
1030
|
event.bd_addr,
|
|
1025
1031
|
None,
|
|
1026
1032
|
None,
|
|
@@ -1032,7 +1038,10 @@ class Host(AbortableEventEmitter):
|
|
|
1032
1038
|
|
|
1033
1039
|
# Notify the client
|
|
1034
1040
|
self.emit(
|
|
1035
|
-
'connection_failure',
|
|
1041
|
+
'connection_failure',
|
|
1042
|
+
PhysicalTransport.BR_EDR,
|
|
1043
|
+
event.bd_addr,
|
|
1044
|
+
event.status,
|
|
1036
1045
|
)
|
|
1037
1046
|
|
|
1038
1047
|
def on_hci_disconnection_complete_event(self, event):
|
|
@@ -1279,7 +1288,8 @@ class Host(AbortableEventEmitter):
|
|
|
1279
1288
|
logger.debug('no long term key provider')
|
|
1280
1289
|
long_term_key = None
|
|
1281
1290
|
else:
|
|
1282
|
-
long_term_key = await
|
|
1291
|
+
long_term_key = await utils.cancel_on_event(
|
|
1292
|
+
self,
|
|
1283
1293
|
'flush',
|
|
1284
1294
|
# pylint: disable-next=not-callable
|
|
1285
1295
|
self.long_term_key_provider(
|
|
@@ -1337,7 +1347,7 @@ class Host(AbortableEventEmitter):
|
|
|
1337
1347
|
f'role change for {event.bd_addr}: '
|
|
1338
1348
|
f'{hci.HCI_Constant.role_name(event.new_role)}'
|
|
1339
1349
|
)
|
|
1340
|
-
self.emit('role_change', event.bd_addr, event.new_role)
|
|
1350
|
+
self.emit('role_change', event.bd_addr, hci.Role(event.new_role))
|
|
1341
1351
|
else:
|
|
1342
1352
|
logger.debug(
|
|
1343
1353
|
f'role change for {event.bd_addr} failed: '
|
|
@@ -1437,7 +1447,8 @@ class Host(AbortableEventEmitter):
|
|
|
1437
1447
|
logger.debug('no link key provider')
|
|
1438
1448
|
link_key = None
|
|
1439
1449
|
else:
|
|
1440
|
-
link_key = await
|
|
1450
|
+
link_key = await utils.cancel_on_event(
|
|
1451
|
+
self,
|
|
1441
1452
|
'flush',
|
|
1442
1453
|
# pylint: disable-next=not-callable
|
|
1443
1454
|
self.link_key_provider(event.bd_addr),
|
bumble/keys.py
CHANGED
|
@@ -28,11 +28,11 @@ import json
|
|
|
28
28
|
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type
|
|
29
29
|
from typing_extensions import Self
|
|
30
30
|
|
|
31
|
-
from .colors import color
|
|
32
|
-
from .hci import Address
|
|
31
|
+
from bumble.colors import color
|
|
32
|
+
from bumble.hci import Address
|
|
33
33
|
|
|
34
34
|
if TYPE_CHECKING:
|
|
35
|
-
from .device import Device
|
|
35
|
+
from bumble.device import Device
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
# -----------------------------------------------------------------------------
|