forked from auracaster/bumble_mirror
Add connection parameter update from peripheral
This commit is contained in:
committed by
David Duarte
parent
80824f3fc1
commit
783b2d70a5
@@ -142,6 +142,10 @@ class ConnectionError(BaseError): # pylint: disable=redefined-builtin
|
|||||||
self.peer_address = peer_address
|
self.peer_address = peer_address
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionParameterUpdateError(BaseError):
|
||||||
|
"""Connection Parameter Update Error"""
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# UUID
|
# UUID
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ from .core import (
|
|||||||
BT_LE_TRANSPORT,
|
BT_LE_TRANSPORT,
|
||||||
BT_PERIPHERAL_ROLE,
|
BT_PERIPHERAL_ROLE,
|
||||||
AdvertisingData,
|
AdvertisingData,
|
||||||
|
ConnectionParameterUpdateError,
|
||||||
CommandTimeoutError,
|
CommandTimeoutError,
|
||||||
ConnectionPHY,
|
ConnectionPHY,
|
||||||
InvalidStateError,
|
InvalidStateError,
|
||||||
@@ -723,6 +724,7 @@ class Connection(CompositeEventEmitter):
|
|||||||
connection_interval_max,
|
connection_interval_max,
|
||||||
max_latency,
|
max_latency,
|
||||||
supervision_timeout,
|
supervision_timeout,
|
||||||
|
use_l2cap=False,
|
||||||
):
|
):
|
||||||
return await self.device.update_connection_parameters(
|
return await self.device.update_connection_parameters(
|
||||||
self,
|
self,
|
||||||
@@ -730,6 +732,7 @@ class Connection(CompositeEventEmitter):
|
|||||||
connection_interval_max,
|
connection_interval_max,
|
||||||
max_latency,
|
max_latency,
|
||||||
supervision_timeout,
|
supervision_timeout,
|
||||||
|
use_l2cap=use_l2cap,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def set_phy(self, tx_phys=None, rx_phys=None, phy_options=None):
|
async def set_phy(self, tx_phys=None, rx_phys=None, phy_options=None):
|
||||||
@@ -2110,11 +2113,30 @@ class Device(CompositeEventEmitter):
|
|||||||
supervision_timeout,
|
supervision_timeout,
|
||||||
min_ce_length=0,
|
min_ce_length=0,
|
||||||
max_ce_length=0,
|
max_ce_length=0,
|
||||||
):
|
use_l2cap=False,
|
||||||
|
) -> None:
|
||||||
'''
|
'''
|
||||||
NOTE: the name of the parameters may look odd, but it just follows the names
|
NOTE: the name of the parameters may look odd, but it just follows the names
|
||||||
used in the Bluetooth spec.
|
used in the Bluetooth spec.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
if use_l2cap:
|
||||||
|
if connection.role != BT_PERIPHERAL_ROLE:
|
||||||
|
raise InvalidStateError(
|
||||||
|
'only peripheral can update connection parameters with l2cap'
|
||||||
|
)
|
||||||
|
l2cap_result = (
|
||||||
|
await self.l2cap_channel_manager.update_connection_parameters(
|
||||||
|
connection,
|
||||||
|
connection_interval_min,
|
||||||
|
connection_interval_max,
|
||||||
|
max_latency,
|
||||||
|
supervision_timeout,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if l2cap_result != l2cap.L2CAP_CONNECTION_PARAMETERS_ACCEPTED_RESULT:
|
||||||
|
raise ConnectionParameterUpdateError(l2cap_result)
|
||||||
|
|
||||||
result = await self.send_command(
|
result = await self.send_command(
|
||||||
HCI_LE_Connection_Update_Command(
|
HCI_LE_Connection_Update_Command(
|
||||||
connection_handle=connection.handle,
|
connection_handle=connection.handle,
|
||||||
@@ -2124,7 +2146,7 @@ class Device(CompositeEventEmitter):
|
|||||||
supervision_timeout=supervision_timeout,
|
supervision_timeout=supervision_timeout,
|
||||||
min_ce_length=min_ce_length,
|
min_ce_length=min_ce_length,
|
||||||
max_ce_length=max_ce_length,
|
max_ce_length=max_ce_length,
|
||||||
)
|
) # type: ignore[call-arg]
|
||||||
)
|
)
|
||||||
if result.status != HCI_Command_Status_Event.PENDING:
|
if result.status != HCI_Command_Status_Event.PENDING:
|
||||||
raise HCI_StatusError(result)
|
raise HCI_StatusError(result)
|
||||||
|
|||||||
@@ -1387,6 +1387,7 @@ class ChannelManager:
|
|||||||
le_coc_requests: Dict[int, L2CAP_LE_Credit_Based_Connection_Request]
|
le_coc_requests: Dict[int, L2CAP_LE_Credit_Based_Connection_Request]
|
||||||
fixed_channels: Dict[int, Optional[Callable[[int, bytes], Any]]]
|
fixed_channels: Dict[int, Optional[Callable[[int, bytes], Any]]]
|
||||||
_host: Optional[Host]
|
_host: Optional[Host]
|
||||||
|
connection_parameters_update_response: Optional[asyncio.Future[int]]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -1408,6 +1409,7 @@ class ChannelManager:
|
|||||||
self.le_coc_requests = {} # LE CoC connection requests, by identifier
|
self.le_coc_requests = {} # LE CoC connection requests, by identifier
|
||||||
self.extended_features = extended_features
|
self.extended_features = extended_features
|
||||||
self.connectionless_mtu = connectionless_mtu
|
self.connectionless_mtu = connectionless_mtu
|
||||||
|
self.connection_parameters_update_response = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def host(self) -> Host:
|
def host(self) -> Host:
|
||||||
@@ -1865,11 +1867,45 @@ class ChannelManager:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def update_connection_parameters(
|
||||||
|
self,
|
||||||
|
connection: Connection,
|
||||||
|
interval_min: int,
|
||||||
|
interval_max: int,
|
||||||
|
latency: int,
|
||||||
|
timeout: int,
|
||||||
|
) -> int:
|
||||||
|
# Check that there isn't already a request pending
|
||||||
|
if self.connection_parameters_update_response:
|
||||||
|
raise InvalidStateError('request already pending')
|
||||||
|
self.connection_parameters_update_response = (
|
||||||
|
asyncio.get_running_loop().create_future()
|
||||||
|
)
|
||||||
|
self.send_control_frame(
|
||||||
|
connection,
|
||||||
|
L2CAP_LE_SIGNALING_CID,
|
||||||
|
L2CAP_Connection_Parameter_Update_Request(
|
||||||
|
interval_min=interval_min,
|
||||||
|
interval_max=interval_max,
|
||||||
|
latency=latency,
|
||||||
|
timeout=timeout,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return await self.connection_parameters_update_response
|
||||||
|
|
||||||
def on_l2cap_connection_parameter_update_response(
|
def on_l2cap_connection_parameter_update_response(
|
||||||
self, connection: Connection, cid: int, response
|
self, connection: Connection, cid: int, response
|
||||||
) -> None:
|
) -> None:
|
||||||
# TODO: check response
|
if self.connection_parameters_update_response:
|
||||||
pass
|
self.connection_parameters_update_response.set_result(response.result)
|
||||||
|
self.connection_parameters_update_response = None
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
color(
|
||||||
|
'received l2cap_connection_parameter_update_response without a pending request',
|
||||||
|
'red',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def on_l2cap_le_credit_based_connection_request(
|
def on_l2cap_le_credit_based_connection_request(
|
||||||
self, connection: Connection, cid: int, request
|
self, connection: Connection, cid: int, request
|
||||||
|
|||||||
Reference in New Issue
Block a user