mirror of
https://github.com/google/bumble.git
synced 2026-05-09 04:08:02 +00:00
Allow register HCI packets with custom names
This commit is contained in:
@@ -2291,7 +2291,7 @@ class HCI_Command(HCI_Packet):
|
|||||||
hci_packet_type = HCI_COMMAND_PACKET
|
hci_packet_type = HCI_COMMAND_PACKET
|
||||||
command_names: dict[int, str] = {}
|
command_names: dict[int, str] = {}
|
||||||
command_classes: dict[int, type[HCI_Command]] = {}
|
command_classes: dict[int, type[HCI_Command]] = {}
|
||||||
op_code: int = -1
|
op_code: int
|
||||||
fields: Fields = ()
|
fields: Fields = ()
|
||||||
return_parameters_fields: Fields = ()
|
return_parameters_fields: Fields = ()
|
||||||
_parameters: bytes = b''
|
_parameters: bytes = b''
|
||||||
@@ -2304,10 +2304,14 @@ class HCI_Command(HCI_Packet):
|
|||||||
Decorator used to declare and register subclasses
|
Decorator used to declare and register subclasses
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
# Subclasses may set parameters as ClassVar, or inferred from class name.
|
||||||
|
if not hasattr(subclass, 'name'):
|
||||||
subclass.name = subclass.__name__.upper()
|
subclass.name = subclass.__name__.upper()
|
||||||
subclass.op_code = key_with_value(subclass.command_names, subclass.name)
|
if not hasattr(subclass, 'op_code'):
|
||||||
if subclass.op_code is None:
|
op_code = key_with_value(subclass.command_names, subclass.name)
|
||||||
|
if op_code is None:
|
||||||
raise KeyError(f'command {subclass.name} not found in command_names')
|
raise KeyError(f'command {subclass.name} not found in command_names')
|
||||||
|
subclass.op_code = op_code
|
||||||
|
|
||||||
if dataclasses.is_dataclass(subclass):
|
if dataclasses.is_dataclass(subclass):
|
||||||
subclass.fields = HCI_Object.fields_from_dataclass(subclass)
|
subclass.fields = HCI_Object.fields_from_dataclass(subclass)
|
||||||
@@ -2350,11 +2354,12 @@ class HCI_Command(HCI_Packet):
|
|||||||
command.parameters = parameters
|
command.parameters = parameters
|
||||||
return command
|
return command
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def command_name(op_code):
|
def command_name(cls, op_code: int) -> str:
|
||||||
name = HCI_Command.command_names.get(op_code)
|
if name := cls.command_names.get(op_code):
|
||||||
if name is not None:
|
|
||||||
return name
|
return name
|
||||||
|
if (subclass := cls.command_classes.get(op_code)) and subclass.name:
|
||||||
|
return subclass.name
|
||||||
return f'[OGF=0x{op_code >> 10:02x}, OCF=0x{op_code & 0x3FF:04x}]'
|
return f'[OGF=0x{op_code >> 10:02x}, OCF=0x{op_code & 0x3FF:04x}]'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -5598,7 +5603,7 @@ class HCI_Event(HCI_Packet):
|
|||||||
event_names: dict[int, str] = {}
|
event_names: dict[int, str] = {}
|
||||||
event_classes: dict[int, type[HCI_Event]] = {}
|
event_classes: dict[int, type[HCI_Event]] = {}
|
||||||
vendor_factories: list[Callable[[bytes], Optional[HCI_Event]]] = []
|
vendor_factories: list[Callable[[bytes], Optional[HCI_Event]]] = []
|
||||||
event_code: int = -1
|
event_code: int
|
||||||
fields: Fields = ()
|
fields: Fields = ()
|
||||||
_parameters: bytes = b''
|
_parameters: bytes = b''
|
||||||
|
|
||||||
@@ -5609,12 +5614,17 @@ class HCI_Event(HCI_Packet):
|
|||||||
'''
|
'''
|
||||||
Decorator used to declare and register subclasses
|
Decorator used to declare and register subclasses
|
||||||
'''
|
'''
|
||||||
|
# Subclasses may set parameters as ClassVar, or inferred from class name.
|
||||||
|
if not hasattr(subclass, 'name'):
|
||||||
subclass.name = subclass.__name__.upper()
|
subclass.name = subclass.__name__.upper()
|
||||||
subclass.event_code = key_with_value(subclass.event_names, subclass.name)
|
if not hasattr(subclass, 'event_code'):
|
||||||
subclass.fields = HCI_Object.fields_from_dataclass(subclass)
|
event_code = key_with_value(subclass.event_names, subclass.name)
|
||||||
if subclass.event_code is None:
|
if event_code is None:
|
||||||
raise KeyError(f'event {subclass.name} not found in event_names')
|
raise KeyError(f'event {subclass.name} not found in event_names')
|
||||||
|
subclass.event_code = event_code
|
||||||
|
|
||||||
|
if dataclasses.is_dataclass(subclass):
|
||||||
|
subclass.fields = HCI_Object.fields_from_dataclass(subclass)
|
||||||
|
|
||||||
# Register a factory for this class
|
# Register a factory for this class
|
||||||
cls.event_classes[subclass.event_code] = subclass
|
cls.event_classes[subclass.event_code] = subclass
|
||||||
@@ -5630,9 +5640,11 @@ class HCI_Event(HCI_Packet):
|
|||||||
and event_name.endswith('_EVENT')
|
and event_name.endswith('_EVENT')
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def event_name(event_code):
|
def event_name(cls, event_code: int) -> str:
|
||||||
return name_or_number(HCI_Event.event_names, event_code)
|
if (subclass := cls.event_classes.get(event_code)) and subclass.name:
|
||||||
|
return subclass.name
|
||||||
|
return name_or_number(cls.event_names, event_code)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def register_events(symbols: dict[str, Any]) -> None:
|
def register_events(symbols: dict[str, Any]) -> None:
|
||||||
@@ -5758,7 +5770,7 @@ class HCI_Extended_Event(HCI_Event):
|
|||||||
|
|
||||||
subevent_names: dict[int, str] = {}
|
subevent_names: dict[int, str] = {}
|
||||||
subevent_classes: dict[int, type[HCI_Extended_Event]] = {}
|
subevent_classes: dict[int, type[HCI_Extended_Event]] = {}
|
||||||
subevent_code: int = -1
|
subevent_code: int
|
||||||
_parameters: bytes = b''
|
_parameters: bytes = b''
|
||||||
|
|
||||||
_ExtendedEvent = TypeVar("_ExtendedEvent", bound="HCI_Extended_Event")
|
_ExtendedEvent = TypeVar("_ExtendedEvent", bound="HCI_Extended_Event")
|
||||||
@@ -5769,14 +5781,20 @@ class HCI_Extended_Event(HCI_Event):
|
|||||||
'''
|
'''
|
||||||
Decorator used to declare and register subclasses
|
Decorator used to declare and register subclasses
|
||||||
'''
|
'''
|
||||||
|
# Subclasses may set parameters as ClassVar, or inferred from class name.
|
||||||
|
if not hasattr(subclass, 'name'):
|
||||||
subclass.name = subclass.__name__.upper()
|
subclass.name = subclass.__name__.upper()
|
||||||
subclass.subevent_code = key_with_value(subclass.subevent_names, subclass.name)
|
if not hasattr(subclass, 'subevent_code'):
|
||||||
if subclass.subevent_code is None:
|
subevent_code = key_with_value(subclass.subevent_names, subclass.name)
|
||||||
|
if subevent_code is None:
|
||||||
raise KeyError(f'subevent {subclass.name} not found in subevent_names')
|
raise KeyError(f'subevent {subclass.name} not found in subevent_names')
|
||||||
|
subclass.subevent_code = subevent_code
|
||||||
|
|
||||||
|
if dataclasses.is_dataclass(subclass):
|
||||||
|
subclass.fields = HCI_Object.fields_from_dataclass(subclass)
|
||||||
|
|
||||||
# Register a factory for this class
|
# Register a factory for this class
|
||||||
cls.subevent_classes[subclass.subevent_code] = subclass
|
cls.subevent_classes[subclass.subevent_code] = subclass
|
||||||
subclass.fields = HCI_Object.fields_from_dataclass(subclass)
|
|
||||||
|
|
||||||
return subclass
|
return subclass
|
||||||
|
|
||||||
@@ -5793,10 +5811,11 @@ class HCI_Extended_Event(HCI_Event):
|
|||||||
self._parameters = parameters
|
self._parameters = parameters
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def subevent_name(cls, subevent_code):
|
def subevent_name(cls, subevent_code: int) -> str:
|
||||||
subevent_name = cls.subevent_names.get(subevent_code)
|
if subevent_name := cls.subevent_names.get(subevent_code):
|
||||||
if subevent_name is not None:
|
|
||||||
return subevent_name
|
return subevent_name
|
||||||
|
if (subclass := cls.subevent_classes.get(subevent_code)) and subclass.name:
|
||||||
|
return subclass.name
|
||||||
|
|
||||||
return f'{cls.__name__.upper()}[0x{subevent_code:02X}]'
|
return f'{cls.__name__.upper()}[0x{subevent_code:02X}]'
|
||||||
|
|
||||||
|
|||||||
@@ -238,6 +238,15 @@ def test_HCI_Command():
|
|||||||
command = hci.HCI_Command(op_code=0x5566, parameters=bytes.fromhex('AABBCC'))
|
command = hci.HCI_Command(op_code=0x5566, parameters=bytes.fromhex('AABBCC'))
|
||||||
basic_check(command)
|
basic_check(command)
|
||||||
|
|
||||||
|
@hci.HCI_Command.command
|
||||||
|
class CustomCommand(hci.HCI_Command):
|
||||||
|
op_code = 0x7788
|
||||||
|
name = 'Custom Command'
|
||||||
|
|
||||||
|
basic_check(CustomCommand())
|
||||||
|
assert CustomCommand().op_code == 0x7788
|
||||||
|
assert CustomCommand().name == 'Custom Command'
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|||||||
Reference in New Issue
Block a user