classic: update Device.connect to allow parallels connection creation

According to the specification nothing prevent the Host from creating
multiple connections at the same time. This commit add this mechanisme
by matching the `connection` and `connection_failure` events against the
peer address.
This commit is contained in:
Abel Lucas
2022-10-19 16:39:06 +00:00
parent eb8556ccf6
commit 7208fd6642
2 changed files with 28 additions and 11 deletions
+26 -9
View File
@@ -1144,7 +1144,7 @@ class Device(CompositeEventEmitter):
transport = BT_LE_TRANSPORT
# Check that there isn't already a pending connection
if self.is_connecting:
if transport == BT_LE_TRANSPORT and self.is_connecting:
raise InvalidStateError('connection already pending')
if type(peer_address) is str:
@@ -1155,10 +1155,22 @@ class Device(CompositeEventEmitter):
logger.debug('looking for peer by name')
peer_address = await self.find_peer_by_name(peer_address, transport) # TODO: timeout
def on_connection(connection):
if transport == BT_LE_TRANSPORT or (
# match BR/EDR connection event against peer address
connection.transport == transport and connection.peer_address == peer_address):
pending_connection.set_result(connection)
def on_connection_failure(error):
if transport == BT_LE_TRANSPORT or (
# match BR/EDR connection failure event against peer address
error.transport == transport and error.peer_address == peer_address):
pending_connection.set_exception(error)
# Create a future so that we can wait for the connection's result
pending_connection = asyncio.get_running_loop().create_future()
self.on('connection', pending_connection.set_result)
self.on('connection_failure', pending_connection.set_exception)
self.on('connection', on_connection)
self.on('connection_failure', on_connection_failure)
try:
# Tell the controller to connect
@@ -1248,7 +1260,8 @@ class Device(CompositeEventEmitter):
raise HCI_StatusError(result)
# Wait for the connection process to complete
self.connecting = True
if transport == BT_LE_TRANSPORT:
self.connecting = True
if timeout is None:
return await pending_connection
else:
@@ -1265,9 +1278,10 @@ class Device(CompositeEventEmitter):
except ConnectionError:
raise TimeoutError()
finally:
self.remove_listener('connection', pending_connection.set_result)
self.remove_listener('connection_failure', pending_connection.set_exception)
self.connecting = False
self.remove_listener('connection', on_connection)
self.remove_listener('connection_failure', on_connection_failure)
if transport == BT_LE_TRANSPORT:
self.connecting = False
@asynccontextmanager
async def connect_as_gatt(self, peer_address):
@@ -1704,11 +1718,11 @@ class Device(CompositeEventEmitter):
asyncio.create_task(new_connection())
@host_event_handler
def on_connection_failure(self, connection_handle, error_code):
def on_connection_failure(self, transport, connection_handle, peer_address, error_code):
logger.debug(f'*** Connection failed: {HCI_Constant.error_name(error_code)}')
# For directed advertising, this means a timeout
if self.advertising and self.advertising_type.is_directed:
if transport == BT_LE_TRANSPORT and self.advertising and self.advertising_type.is_directed:
self.advertising = False
# Notify listeners
@@ -1717,6 +1731,9 @@ class Device(CompositeEventEmitter):
'hci',
HCI_Constant.error_name(error_code)
)
error.transport = transport
error.connection_handle = connection_handle # FIXME: Connection handle sounds to be a dummy value here
error.peer_address = peer_address
self.emit('connection_failure', error)
@host_event_handler
+2 -2
View File
@@ -383,7 +383,7 @@ class Host(EventEmitter):
logger.debug(f'### CONNECTION FAILED: {event.status}')
# Notify the listeners
self.emit('connection_failure', event.connection_handle, event.status)
self.emit('connection_failure', BT_LE_TRANSPORT, event.connection_handle, event.peer_address, event.status)
def on_hci_le_enhanced_connection_complete_event(self, event):
# Just use the same implementation as for the non-enhanced event for now
@@ -413,7 +413,7 @@ class Host(EventEmitter):
logger.debug(f'### BR/EDR CONNECTION FAILED: {event.status}')
# Notify the client
self.emit('connection_failure', event.connection_handle, event.status)
self.emit('connection_failure', BT_BR_EDR_TRANSPORT, event.connection_handle, event.bd_addr, event.status)
def on_hci_disconnection_complete_event(self, event):
# Find the connection