forked from auracaster/bumble_mirror
Merge pull request #534 from hkpeprah/ford/bug/rtk-edimax-2
[Bug] Edimax BLE Dongle Fails After Teardown and Re-Instantiation
This commit is contained in:
@@ -301,6 +301,8 @@ class Driver(common.Driver):
|
|||||||
fw_name: str = ""
|
fw_name: str = ""
|
||||||
config_name: str = ""
|
config_name: str = ""
|
||||||
|
|
||||||
|
POST_RESET_DELAY: float = 0.2
|
||||||
|
|
||||||
DRIVER_INFOS = [
|
DRIVER_INFOS = [
|
||||||
# 8723A
|
# 8723A
|
||||||
DriverInfo(
|
DriverInfo(
|
||||||
@@ -495,12 +497,24 @@ class Driver(common.Driver):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def driver_info_for_host(cls, host):
|
async def driver_info_for_host(cls, host):
|
||||||
await host.send_command(HCI_Reset_Command(), check_result=True)
|
try:
|
||||||
host.ready = True # Needed to let the host know the controller is ready.
|
await host.send_command(
|
||||||
|
HCI_Reset_Command(),
|
||||||
response = await host.send_command(
|
check_result=True,
|
||||||
HCI_Read_Local_Version_Information_Command(), check_result=True
|
response_timeout=cls.POST_RESET_DELAY,
|
||||||
)
|
)
|
||||||
|
host.ready = True # Needed to let the host know the controller is ready.
|
||||||
|
except asyncio.exceptions.TimeoutError:
|
||||||
|
logger.warning("timeout waiting for hci reset, retrying")
|
||||||
|
await host.send_command(HCI_Reset_Command(), check_result=True)
|
||||||
|
host.ready = True
|
||||||
|
|
||||||
|
command = HCI_Read_Local_Version_Information_Command()
|
||||||
|
response = await host.send_command(command, check_result=True)
|
||||||
|
if response.command_opcode != command.op_code:
|
||||||
|
logger.error("failed to probe local version information")
|
||||||
|
return None
|
||||||
|
|
||||||
local_version = response.return_parameters
|
local_version = response.return_parameters
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ class Host(AbortableEventEmitter):
|
|||||||
self.cis_links = {} # CIS links, by connection handle
|
self.cis_links = {} # CIS links, by connection handle
|
||||||
self.sco_links = {} # SCO links, by connection handle
|
self.sco_links = {} # SCO links, by connection handle
|
||||||
self.pending_command = None
|
self.pending_command = None
|
||||||
self.pending_response = None
|
self.pending_response: Optional[asyncio.Future[Any]] = None
|
||||||
self.number_of_supported_advertising_sets = 0
|
self.number_of_supported_advertising_sets = 0
|
||||||
self.maximum_advertising_data_length = 31
|
self.maximum_advertising_data_length = 31
|
||||||
self.local_version = None
|
self.local_version = None
|
||||||
@@ -514,7 +514,9 @@ class Host(AbortableEventEmitter):
|
|||||||
if self.hci_sink:
|
if self.hci_sink:
|
||||||
self.hci_sink.on_packet(bytes(packet))
|
self.hci_sink.on_packet(bytes(packet))
|
||||||
|
|
||||||
async def send_command(self, command, check_result=False):
|
async def send_command(
|
||||||
|
self, command, check_result=False, response_timeout: Optional[int] = None
|
||||||
|
):
|
||||||
# Wait until we can send (only one pending command at a time)
|
# Wait until we can send (only one pending command at a time)
|
||||||
async with self.command_semaphore:
|
async with self.command_semaphore:
|
||||||
assert self.pending_command is None
|
assert self.pending_command is None
|
||||||
@@ -526,12 +528,13 @@ class Host(AbortableEventEmitter):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self.send_hci_packet(command)
|
self.send_hci_packet(command)
|
||||||
response = await self.pending_response
|
await asyncio.wait_for(self.pending_response, timeout=response_timeout)
|
||||||
|
response = self.pending_response.result()
|
||||||
|
|
||||||
# Check the return parameters if required
|
# Check the return parameters if required
|
||||||
if check_result:
|
if check_result:
|
||||||
if isinstance(response, hci.HCI_Command_Status_Event):
|
if isinstance(response, hci.HCI_Command_Status_Event):
|
||||||
status = response.status
|
status = response.status # type: ignore[attr-defined]
|
||||||
elif isinstance(response.return_parameters, int):
|
elif isinstance(response.return_parameters, int):
|
||||||
status = response.return_parameters
|
status = response.return_parameters
|
||||||
elif isinstance(response.return_parameters, bytes):
|
elif isinstance(response.return_parameters, bytes):
|
||||||
@@ -625,14 +628,21 @@ class Host(AbortableEventEmitter):
|
|||||||
|
|
||||||
# Packet Sink protocol (packets coming from the controller via HCI)
|
# Packet Sink protocol (packets coming from the controller via HCI)
|
||||||
def on_packet(self, packet: bytes) -> None:
|
def on_packet(self, packet: bytes) -> None:
|
||||||
|
try:
|
||||||
hci_packet = hci.HCI_Packet.from_bytes(packet)
|
hci_packet = hci.HCI_Packet.from_bytes(packet)
|
||||||
|
except Exception as error:
|
||||||
|
logger.warning(f'!!! error parsing packet from bytes: {error}')
|
||||||
|
return
|
||||||
|
|
||||||
if self.ready or (
|
if self.ready or (
|
||||||
isinstance(hci_packet, hci.HCI_Command_Complete_Event)
|
isinstance(hci_packet, hci.HCI_Command_Complete_Event)
|
||||||
and hci_packet.command_opcode == hci.HCI_RESET_COMMAND
|
and hci_packet.command_opcode == hci.HCI_RESET_COMMAND
|
||||||
):
|
):
|
||||||
self.on_hci_packet(hci_packet)
|
self.on_hci_packet(hci_packet)
|
||||||
else:
|
else:
|
||||||
logger.debug('reset not done, ignoring packet from controller')
|
logger.debug(
|
||||||
|
f'reset not done, ignoring packet from controller: {hci_packet}'
|
||||||
|
)
|
||||||
|
|
||||||
def on_transport_lost(self):
|
def on_transport_lost(self):
|
||||||
# Called by the source when the transport has been lost.
|
# Called by the source when the transport has been lost.
|
||||||
|
|||||||
Reference in New Issue
Block a user