From 5fa3d45ab023d2e7276a6925fe31fe2fa08fcf9d Mon Sep 17 00:00:00 2001 From: Martin Varmuza Date: Mon, 27 Jan 2025 14:16:44 +0100 Subject: [PATCH] fix(connect): edgecase where device is not detected during fw update using the old bridge --- .../connect/src/core/onCallFirmwareUpdate.ts | 37 ++++++++++++++++++- packages/connect/src/device/Device.ts | 14 ++++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/packages/connect/src/core/onCallFirmwareUpdate.ts b/packages/connect/src/core/onCallFirmwareUpdate.ts index 878eb7a415a..4aae939379f 100644 --- a/packages/connect/src/core/onCallFirmwareUpdate.ts +++ b/packages/connect/src/core/onCallFirmwareUpdate.ts @@ -96,8 +96,37 @@ const waitForReconnectedDevice = async ( } catch { /* empty */ } + + // general logic (DeviceList/Device) refuses to call getFeatures if the reported descriptor has a session. + // the reason for session to be still there is this scenario: + // 1. reboot to bootloader is called + // 2. old bridge uses cca 200ms enumeration loop. If device appears on usb in the right time, bridge does not consider it + // a disconnect and it does not flush sessions + // 3. listen now reported a new device in bootloader mode but it still has the session from the previous device in normal mode + // 4. now we automatically take the device, as if user clicked on the "use device here button" + + if ( + reconnectedDevice && + !reconnectedDevice.features && + reconnectedDevice.handshakeFinished + ) { + log.debug( + 'onCallFirmwareUpdate', + 'we were unable to read device.features on the first interaction after seeing it, retrying...', + ); + try { + // todo: it keeps printing warning "Previous call is still running" on reconnect from bl to normal + await reconnectedDevice.run(undefined, { + skipFirmwareChecks: true, + skipLanguageChecks: true, + }); + } catch { + // empty + } + } + i++; - log.debug('onCallFirmwareUpdate', 'waiting for device to reconnect', i); + log.debug('onCallFirmwareUpdate', '...still waiting for device to reconnect', i); } while ( !abortSignal.aborted && (!reconnectedDevice?.features || @@ -123,7 +152,10 @@ const waitForReconnectedDevice = async ( registerEvents(reconnectedDevice, postMessage); await reconnectedDevice.waitForFirstRun(); - await reconnectedDevice.acquire(); + + if (!reconnectedDevice.isUsedHere()) { + await reconnectedDevice.acquire(); + } return reconnectedDevice; }; @@ -267,6 +299,7 @@ const firmwareCheck = async ( progress: 0, }), ); + const { hash, challenge } = calculateFirmwareHash( device.features.major_version, stripped, diff --git a/packages/connect/src/device/Device.ts b/packages/connect/src/device/Device.ts index d7fd46a99b8..ae5a1db9425 100644 --- a/packages/connect/src/device/Device.ts +++ b/packages/connect/src/device/Device.ts @@ -69,6 +69,8 @@ type RunOptions = { skipFinalReload?: boolean; keepSession?: boolean; useCardanoDerivation?: boolean; + skipFirmwareChecks?: boolean; + skipLanguageChecks?: boolean; }; export const GET_FEATURES_TIMEOUT = 3_000; @@ -203,6 +205,9 @@ export class Device extends TypedEmitter { private sessionDfd?: Deferred; + // todo: marek will solve this + public handshakeFinished = false; + constructor({ id, transport, descriptor, listener }: DeviceParams) { super(); @@ -385,6 +390,8 @@ export class Device extends TypedEmitter { } } + this.handshakeFinished = true; + return; } } @@ -590,10 +597,13 @@ export class Device extends TypedEmitter { } } - await this.checkFirmwareHashWithRetries(); - await this.checkFirmwareRevisionWithRetries(); + if (!options.skipFirmwareChecks) { + await this.checkFirmwareHashWithRetries(); + await this.checkFirmwareRevisionWithRetries(); + } if ( + !options.skipLanguageChecks && this.features?.language && !this.features.language_version_matches && this.atLeast('2.7.0')