Skip to content

Commit eb64deb

Browse files
authored
Merge pull request #893 from zxzxwu/le-emu
Emulation: Support LE Read features
2 parents 1330e83 + c158f25 commit eb64deb

3 files changed

Lines changed: 48 additions & 9 deletions

File tree

bumble/controller.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,20 @@ def on_ll_control_pdu(
544544
self.on_le_cis_disconnected(packet.cig_id, packet.cis_id)
545545
case ll.EncReq():
546546
self.on_le_encrypted(connection)
547+
case ll.FeatureReq() | ll.PeripheralFeatureReq():
548+
connection.send_ll_control_pdu(
549+
ll.FeatureRsp(
550+
feature_set=self.le_features.value.to_bytes(8, 'little')
551+
)
552+
)
553+
case ll.FeatureRsp(feature_set):
554+
self.send_hci_packet(
555+
hci.HCI_LE_Read_Remote_Features_Complete_Event(
556+
status=hci.HCI_ErrorCode.SUCCESS,
557+
connection_handle=connection.handle,
558+
le_features=feature_set,
559+
)
560+
)
547561

548562
def on_ll_advertising_pdu(self, packet: ll.AdvertisingPdu) -> None:
549563
logger.debug("[%s] <<< Advertising PDU: %s", self.name, packet)
@@ -2084,7 +2098,7 @@ def on_hci_le_read_remote_features_command(
20842098

20852099
handle = command.connection_handle
20862100

2087-
if not self.find_connection_by_handle(handle):
2101+
if not (connection := self.find_le_connection_by_handle(handle)):
20882102
self._send_hci_command_status(
20892103
hci.HCI_ErrorCode.INVALID_COMMAND_PARAMETERS_ERROR, command.op_code
20902104
)
@@ -2093,14 +2107,16 @@ def on_hci_le_read_remote_features_command(
20932107
# First, say that the command is pending
20942108
self._send_hci_command_status(hci.HCI_COMMAND_STATUS_PENDING, command.op_code)
20952109

2096-
# Then send the remote features
2097-
self.send_hci_packet(
2098-
hci.HCI_LE_Read_Remote_Features_Complete_Event(
2099-
status=hci.HCI_ErrorCode.SUCCESS,
2100-
connection_handle=handle,
2101-
le_features=bytes.fromhex('dd40000000000000'),
2110+
if connection.role == hci.Role.CENTRAL:
2111+
connection.send_ll_control_pdu(
2112+
ll.FeatureReq(feature_set=self.le_features.value.to_bytes(8, 'little'))
2113+
)
2114+
else:
2115+
connection.send_ll_control_pdu(
2116+
ll.PeripheralFeatureReq(
2117+
feature_set=self.le_features.value.to_bytes(8, 'little')
2118+
)
21022119
)
2103-
)
21042120
return None
21052121

21062122
def on_hci_le_rand_command(

bumble/ll.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,24 @@ class CisTerminateInd(ControlPdu):
198198
cig_id: int
199199
cis_id: int
200200
error_code: int
201+
202+
203+
@dataclasses.dataclass
204+
class FeatureReq(ControlPdu):
205+
opcode = ControlPdu.Opcode.LL_FEATURE_REQ
206+
207+
feature_set: bytes
208+
209+
210+
@dataclasses.dataclass
211+
class FeatureRsp(ControlPdu):
212+
opcode = ControlPdu.Opcode.LL_FEATURE_RSP
213+
214+
feature_set: bytes
215+
216+
217+
@dataclasses.dataclass
218+
class PeripheralFeatureReq(ControlPdu):
219+
opcode = ControlPdu.Opcode.LL_PERIPHERAL_FEATURE_REQ
220+
221+
feature_set: bytes

tests/device_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,9 @@ async def test_get_remote_le_features():
466466
devices = TwoDevices()
467467
await devices.setup_connection()
468468

469-
assert (await devices.connections[0].get_remote_le_features()) is not None
469+
assert (
470+
await devices.connections[0].get_remote_le_features()
471+
) == devices.controllers[1].le_features
470472

471473

472474
# -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)