diff --git a/bumble/hci.py b/bumble/hci.py index cb4ee8c0..3d849cc2 100644 --- a/bumble/hci.py +++ b/bumble/hci.py @@ -5070,7 +5070,7 @@ class HCI_Event(HCI_Packet): hci_packet_type = HCI_EVENT_PACKET event_names: Dict[int, str] = {} event_classes: Dict[int, Type[HCI_Event]] = {} - vendor_factory: Optional[Callable[[bytes], Optional[HCI_Event]]] = None + vendor_factories: list[Callable[[bytes], Optional[HCI_Event]]] = [] @staticmethod def event(fields=()): @@ -5128,6 +5128,19 @@ def registered(event_class): return event_class + @classmethod + def add_vendor_factory( + cls, factory: Callable[[bytes], Optional[HCI_Event]] + ) -> None: + cls.vendor_factories.append(factory) + + @classmethod + def remove_vendor_factory( + cls, factory: Callable[[bytes], Optional[HCI_Event]] + ) -> None: + if factory in cls.vendor_factories: + cls.vendor_factories.remove(factory) + @classmethod def from_bytes(cls, packet: bytes) -> HCI_Event: event_code = packet[1] @@ -5148,13 +5161,13 @@ def from_bytes(cls, packet: bytes) -> HCI_Event: elif event_code == HCI_VENDOR_EVENT: # Invoke all the registered factories to see if any of them can handle # the event - if cls.vendor_factory: - if event := cls.vendor_factory(parameters): + for vendor_factory in cls.vendor_factories: + if event := vendor_factory(parameters): return event # No factory, or the factory could not create an instance, # return a generic vendor event - return HCI_Event(event_code, parameters) + return HCI_Vendor_Event(data=parameters) else: subclass = HCI_Event.event_classes.get(event_code) if subclass is None: diff --git a/bumble/vendor/android/hci.py b/bumble/vendor/android/hci.py index 0aaa23ae..e89dcdd2 100644 --- a/bumble/vendor/android/hci.py +++ b/bumble/vendor/android/hci.py @@ -299,7 +299,7 @@ def subclass_from_parameters( HCI_Android_Vendor_Event.register_subevents(globals()) -HCI_Event.vendor_factory = HCI_Android_Vendor_Event.subclass_from_parameters +HCI_Event.add_vendor_factory(HCI_Android_Vendor_Event.subclass_from_parameters) # ----------------------------------------------------------------------------- diff --git a/tests/hci_test.py b/tests/hci_test.py index 30ab0d73..ee4ef8a5 100644 --- a/tests/hci_test.py +++ b/tests/hci_test.py @@ -15,6 +15,7 @@ # ----------------------------------------------------------------------------- # Imports # ----------------------------------------------------------------------------- +import struct from bumble.hci import ( HCI_DISCONNECT_COMMAND, @@ -22,6 +23,7 @@ HCI_LE_CODED_PHY_BIT, HCI_LE_READ_BUFFER_SIZE_COMMAND, HCI_RESET_COMMAND, + HCI_VENDOR_EVENT, HCI_SUCCESS, HCI_LE_CONNECTION_COMPLETE_EVENT, HCI_LE_ENHANCED_CONNECTION_COMPLETE_V2_EVENT, @@ -67,6 +69,7 @@ HCI_Read_Local_Version_Information_Command, HCI_Reset_Command, HCI_Set_Event_Mask_Command, + HCI_Vendor_Event, ) @@ -213,6 +216,41 @@ def test_HCI_Number_Of_Completed_Packets_Event(): basic_check(event) +# ----------------------------------------------------------------------------- +def test_HCI_Vendor_Event(): + data = bytes.fromhex('01020304') + event = HCI_Vendor_Event(data=data) + event_bytes = bytes(event) + parsed = HCI_Packet.from_bytes(event_bytes) + assert isinstance(parsed, HCI_Vendor_Event) + assert parsed.data == data + + class HCI_Custom_Event(HCI_Event): + def __init__(self, blabla): + super().__init__(HCI_VENDOR_EVENT, parameters=struct.pack("