Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions bumble/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -2072,6 +2072,10 @@ class DeviceConfiguration:
io_capability: int = pairing.PairingDelegate.IoCapability.NO_OUTPUT_NO_INPUT
gap_service_enabled: bool = True
gatt_service_enabled: bool = True
enhanced_retransmission_supported: bool = False
l2cap_extended_features: Sequence[int] = (
l2cap.L2CAP_Information_Request.ExtendedFeatures.FIXED_CHANNELS,
)

def __post_init__(self) -> None:
self.gatt_services: list[dict[str, Any]] = []
Expand Down Expand Up @@ -2341,14 +2345,18 @@ def __init__(
) -> None:
super().__init__()

# Use the initial config or a default
config = config or DeviceConfiguration()
self.config = config

self._host = None
self.powered_on = False
self.auto_restart_inquiry = True
self.command_timeout = 10 # seconds
self.gatt_server = gatt_server.Server(self)
self.sdp_server = sdp.Server(self)
self.l2cap_channel_manager = l2cap.ChannelManager(
[l2cap.L2CAP_Information_Request.EXTENDED_FEATURE_FIXED_CHANNELS]
config.l2cap_extended_features
)
self.advertisement_accumulators = {} # Accumulators, by address
self.periodic_advertising_syncs = []
Expand Down Expand Up @@ -2383,10 +2391,6 @@ def __init__(
# Own address type cache
self.connect_own_address_type = None

# Use the initial config or a default
config = config or DeviceConfiguration()
self.config = config

self.name = config.name
self.public_address = hci.Address.ANY
self.random_address = config.address
Expand Down
27 changes: 13 additions & 14 deletions bumble/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,9 @@ async def send_command(command: hci.HCI_Command) -> None:

asyncio.create_task(send_command(command))

def send_l2cap_pdu(self, connection_handle: int, cid: int, pdu: bytes) -> None:
def send_l2cap_pdu(
self, connection_handle: int, cid: int, pdu: bytes, with_fcs: bool = False
) -> None:
if not (connection := self.connections.get(connection_handle)):
logger.warning(f'connection 0x{connection_handle:04X} not found')
return
Expand All @@ -719,26 +721,23 @@ def send_l2cap_pdu(self, connection_handle: int, cid: int, pdu: bytes) -> None:
return

# Create a PDU
l2cap_pdu = bytes(L2CAP_PDU(cid, pdu))
l2cap_pdu = L2CAP_PDU(cid, pdu).to_bytes(with_fcs)

# Send the data to the controller via ACL packets
bytes_remaining = len(l2cap_pdu)
offset = 0
pb_flag = 0
while bytes_remaining:
data_total_length = min(bytes_remaining, packet_queue.max_packet_size)
max_packet_size = packet_queue.max_packet_size
for offset in range(0, len(l2cap_pdu), max_packet_size):
pdu = l2cap_pdu[offset : offset + max_packet_size]
acl_packet = hci.HCI_AclDataPacket(
connection_handle=connection_handle,
pb_flag=pb_flag,
pb_flag=1 if offset > 0 else 0,
bc_flag=0,
data_total_length=data_total_length,
data=l2cap_pdu[offset : offset + data_total_length],
data_total_length=len(pdu),
data=pdu,
)
logger.debug(
'>>> ACL packet enqueue: (Handle=0x%04X) %s', connection_handle, pdu
)
logger.debug(f'>>> ACL packet enqueue: (CID={cid}) {acl_packet}')
packet_queue.enqueue(acl_packet, connection_handle)
pb_flag = 1
offset += data_total_length
bytes_remaining -= data_total_length

def get_data_packet_queue(self, connection_handle: int) -> DataPacketQueue | None:
if connection := self.connections.get(connection_handle):
Expand Down
Loading
Loading