@onekeyfe/hd-core 1.2.0-alpha.8 → 1.2.0-alpha.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +390 -0
- package/__tests__/DeviceCommands.test.ts +563 -0
- package/__tests__/DeviceEventRegistration.test.ts +49 -0
- package/__tests__/chain-params-onekey-compatibility.test.ts +229 -0
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +492 -0
- package/__tests__/check-firmware-release-protocol-v2.test.ts +164 -0
- package/__tests__/connectSettings.test.ts +45 -5
- package/__tests__/core-dispose.test.ts +34 -0
- package/__tests__/core-error-output.test.ts +39 -0
- package/__tests__/core-initialization.test.ts +23 -0
- package/__tests__/device-connector-protocol.test.ts +81 -0
- package/__tests__/device-features-state.test.ts +78 -0
- package/__tests__/device-identity.test.ts +52 -0
- package/__tests__/device-initialize-timeout.test.ts +56 -0
- package/__tests__/device-lifecycle-events.test.ts +351 -0
- package/__tests__/device-pool-state.test.ts +166 -0
- package/__tests__/device-settings.test.ts +437 -0
- package/__tests__/device-state-contract.test.ts +28 -0
- package/__tests__/device-state-events.test.ts +286 -0
- package/__tests__/device-state-mapper.test.ts +288 -0
- package/__tests__/device-state-projector.test.ts +114 -0
- package/__tests__/device-state-store.test.ts +109 -0
- package/__tests__/device-utils.test.ts +154 -0
- package/__tests__/device-wallet-session-store.test.ts +478 -0
- package/__tests__/deviceFeaturesUtils.test.ts +39 -0
- package/__tests__/devicePoolBootloaderPath.test.ts +64 -0
- package/__tests__/deviceSettings.test.ts +113 -0
- package/__tests__/deviceUploadNft.test.ts +316 -0
- package/__tests__/evmLedgerLegacySafety.test.ts +12 -6
- package/__tests__/evmSignTransaction.test.ts +69 -0
- package/__tests__/evmSignTypedData.test.ts +80 -0
- package/__tests__/filesystemValidation.test.ts +53 -0
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +175 -0
- package/__tests__/firmware-update/device-update-bootloader.test.ts +87 -0
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
- package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
- package/__tests__/firmware-update/firmware-preparation-error.test.ts +27 -0
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +200 -0
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
- package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +394 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +593 -0
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +231 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +457 -0
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +121 -0
- package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
- package/__tests__/get-device-state.test.ts +578 -0
- package/__tests__/homescreen.test.ts +81 -0
- package/__tests__/kaspa-public-types.type-test.ts +16 -0
- package/__tests__/kaspa-use-tweak-pro2.test.ts +20 -0
- package/__tests__/kaspaSignTransaction.test.ts +578 -0
- package/__tests__/known-device-public-types.type-test.ts +3 -0
- package/__tests__/logBlockEvent.test.ts +128 -1
- package/__tests__/method-protocol-support.test.ts +144 -0
- package/__tests__/networkUtils.test.ts +406 -0
- package/__tests__/open-wallet-session-error-response.test.ts +43 -0
- package/__tests__/open-wallet-session.test.ts +1899 -0
- package/__tests__/pro2Nft.test.ts +108 -0
- package/__tests__/pro2Wallpaper.test.ts +39 -0
- package/__tests__/protocol-binding.test.ts +89 -0
- package/__tests__/protocol-v2-bootloader-mode.test.ts +37 -0
- package/__tests__/protocol-v2-firmware-targets.test.ts +85 -0
- package/__tests__/protocol-v2-ping.test.ts +28 -0
- package/__tests__/protocol-v2-resources.test.ts +250 -0
- package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
- package/__tests__/protocol-v2-unlock-policy.test.ts +308 -0
- package/__tests__/protocol-v2.test.ts +7034 -2497
- package/__tests__/protocolV2FileWrite.test.ts +285 -0
- package/__tests__/protocolV2UiInteraction.test.ts +329 -0
- package/__tests__/public-device-state-api.test.ts +275 -0
- package/__tests__/public-pro2-api-boundary.test.ts +107 -0
- package/__tests__/refresh-device-state.test.ts +101 -0
- package/__tests__/request-context-logging.test.ts +16 -0
- package/__tests__/search-devices.test.ts +145 -0
- package/__tests__/tron-sign-message-init.test.ts +74 -0
- package/__tests__/uiProgressThrottle.test.ts +74 -0
- package/__tests__/uiPromiseRegistry.test.ts +115 -0
- package/dist/api/BaseMethod.d.ts +16 -1
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts +25 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBLEFirmwareRelease.d.ts +2 -1
- package/dist/api/CheckBLEFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBootloaderRelease.d.ts +3 -2
- package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
- package/dist/api/CheckFirmwareRelease.d.ts +2 -1
- package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CipherKeyValue.d.ts +1 -0
- package/dist/api/CipherKeyValue.d.ts.map +1 -1
- package/dist/api/ClearSessionCache.d.ts +9 -0
- package/dist/api/ClearSessionCache.d.ts.map +1 -0
- package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
- package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
- package/dist/api/DirList.d.ts +1 -0
- package/dist/api/DirList.d.ts.map +1 -1
- package/dist/api/DirMake.d.ts +1 -0
- package/dist/api/DirMake.d.ts.map +1 -1
- package/dist/api/DirRemove.d.ts +1 -0
- package/dist/api/DirRemove.d.ts.map +1 -1
- package/dist/api/FileDelete.d.ts +1 -0
- package/dist/api/FileDelete.d.ts.map +1 -1
- package/dist/api/FileRead.d.ts +1 -0
- package/dist/api/FileRead.d.ts.map +1 -1
- package/dist/api/FileWrite.d.ts +2 -0
- package/dist/api/FileWrite.d.ts.map +1 -1
- package/dist/api/FirmwareUpdate.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +12 -2
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +7 -3
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +47 -18
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetDeviceState.d.ts +8 -0
- package/dist/api/GetDeviceState.d.ts.map +1 -0
- package/dist/api/GetFeatures.d.ts +1 -1
- package/dist/api/GetFeatures.d.ts.map +1 -1
- package/dist/api/GetOnekeyFeatures.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts +2 -6
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts +8 -0
- package/dist/api/OpenWalletSession.d.ts.map +1 -0
- package/dist/api/PathInfo.d.ts +1 -0
- package/dist/api/PathInfo.d.ts.map +1 -1
- package/dist/api/PromptWebDeviceAccess.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts +3 -0
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts +17 -0
- package/dist/api/UploadPortfolio.d.ts.map +1 -0
- package/dist/api/alephium/AlephiumGetAddress.d.ts.map +1 -1
- package/dist/api/alephium/AlephiumSignMessage.d.ts.map +1 -1
- package/dist/api/alephium/AlephiumSignTransaction.d.ts.map +1 -1
- package/dist/api/algo/AlgoGetAddress.d.ts +1 -0
- package/dist/api/algo/AlgoGetAddress.d.ts.map +1 -1
- package/dist/api/algo/AlgoSignTransaction.d.ts +1 -0
- package/dist/api/algo/AlgoSignTransaction.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +1 -0
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/aptos/AptosGetAddress.d.ts +1 -0
- package/dist/api/aptos/AptosGetAddress.d.ts.map +1 -1
- package/dist/api/aptos/AptosGetPublicKey.d.ts +1 -0
- package/dist/api/aptos/AptosGetPublicKey.d.ts.map +1 -1
- package/dist/api/aptos/AptosSignInMessage.d.ts +1 -0
- package/dist/api/aptos/AptosSignInMessage.d.ts.map +1 -1
- package/dist/api/aptos/AptosSignMessage.d.ts +1 -0
- package/dist/api/aptos/AptosSignMessage.d.ts.map +1 -1
- package/dist/api/aptos/AptosSignTransaction.d.ts +1 -0
- package/dist/api/aptos/AptosSignTransaction.d.ts.map +1 -1
- package/dist/api/benfen/BenfenGetAddress.d.ts.map +1 -1
- package/dist/api/benfen/BenfenGetPublicKey.d.ts.map +1 -1
- package/dist/api/benfen/BenfenSignMessage.d.ts.map +1 -1
- package/dist/api/benfen/BenfenSignTransaction.d.ts.map +1 -1
- package/dist/api/btc/BTCGetAddress.d.ts +1 -0
- package/dist/api/btc/BTCGetAddress.d.ts.map +1 -1
- package/dist/api/btc/BTCGetPublicKey.d.ts +1 -0
- package/dist/api/btc/BTCGetPublicKey.d.ts.map +1 -1
- package/dist/api/btc/BTCSignMessage.d.ts +1 -0
- package/dist/api/btc/BTCSignMessage.d.ts.map +1 -1
- package/dist/api/btc/BTCSignPsbt.d.ts +1 -0
- package/dist/api/btc/BTCSignPsbt.d.ts.map +1 -1
- package/dist/api/btc/BTCSignTransaction.d.ts +1 -0
- package/dist/api/btc/BTCSignTransaction.d.ts.map +1 -1
- package/dist/api/btc/BTCVerifyMessage.d.ts +1 -0
- package/dist/api/btc/BTCVerifyMessage.d.ts.map +1 -1
- package/dist/api/btc/helpers/versionLimit.d.ts +2 -0
- package/dist/api/btc/helpers/versionLimit.d.ts.map +1 -1
- package/dist/api/cardano/CardanoGetAddress.d.ts +1 -0
- package/dist/api/cardano/CardanoGetAddress.d.ts.map +1 -1
- package/dist/api/cardano/CardanoGetPublicKey.d.ts +1 -0
- package/dist/api/cardano/CardanoGetPublicKey.d.ts.map +1 -1
- package/dist/api/cardano/CardanoSignMessage.d.ts +1 -0
- package/dist/api/cardano/CardanoSignMessage.d.ts.map +1 -1
- package/dist/api/cardano/CardanoSignTransaction.d.ts +1 -0
- package/dist/api/cardano/CardanoSignTransaction.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxGetAddress.d.ts +2 -0
- package/dist/api/conflux/ConfluxGetAddress.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignMessage.d.ts +2 -0
- package/dist/api/conflux/ConfluxSignMessage.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts +2 -0
- package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignTransaction.d.ts +2 -0
- package/dist/api/conflux/ConfluxSignTransaction.d.ts.map +1 -1
- package/dist/api/cosmos/CosmosGetAddress.d.ts +1 -0
- package/dist/api/cosmos/CosmosGetAddress.d.ts.map +1 -1
- package/dist/api/cosmos/CosmosGetPublicKey.d.ts +1 -0
- package/dist/api/cosmos/CosmosGetPublicKey.d.ts.map +1 -1
- package/dist/api/cosmos/CosmosSignTransaction.d.ts +1 -0
- package/dist/api/cosmos/CosmosSignTransaction.d.ts.map +1 -1
- package/dist/api/device/DeviceCancel.d.ts +1 -0
- package/dist/api/device/DeviceCancel.d.ts.map +1 -1
- package/dist/api/device/DeviceChangePin.d.ts +1 -0
- package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
- package/dist/api/device/DeviceFullyUploadResource.d.ts +1 -2
- package/dist/api/device/DeviceFullyUploadResource.d.ts.map +1 -1
- package/dist/api/device/DeviceLock.d.ts +1 -0
- package/dist/api/device/DeviceLock.d.ts.map +1 -1
- package/dist/api/device/DeviceRebootToBoardloader.d.ts +1 -0
- package/dist/api/device/DeviceRebootToBoardloader.d.ts.map +1 -1
- package/dist/api/device/DeviceRebootToBootloader.d.ts +1 -0
- package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts +1 -0
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/device/DeviceSupportFeatures.d.ts +1 -0
- package/dist/api/device/DeviceSupportFeatures.d.ts.map +1 -1
- package/dist/api/device/DeviceUnlock.d.ts +3 -2
- package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts +1 -0
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/device/PreInitialize.d.ts +1 -0
- package/dist/api/device/PreInitialize.d.ts.map +1 -1
- package/dist/api/dynex/DnxGetAddress.d.ts.map +1 -1
- package/dist/api/dynex/DnxSignTransaction.d.ts.map +1 -1
- package/dist/api/evm/EVMGetAddress.d.ts +1 -0
- package/dist/api/evm/EVMGetAddress.d.ts.map +1 -1
- package/dist/api/evm/EVMGetPublicKey.d.ts +1 -0
- package/dist/api/evm/EVMGetPublicKey.d.ts.map +1 -1
- package/dist/api/evm/EVMSignMessage.d.ts +1 -0
- package/dist/api/evm/EVMSignMessage.d.ts.map +1 -1
- package/dist/api/evm/EVMSignMessageEIP712.d.ts.map +1 -1
- package/dist/api/evm/EVMSignTransaction.d.ts +1 -0
- package/dist/api/evm/EVMSignTransaction.d.ts.map +1 -1
- package/dist/api/evm/EVMSignTypedData.d.ts +1 -0
- package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
- package/dist/api/evm/EVMVerifyMessage.d.ts +1 -0
- package/dist/api/evm/EVMVerifyMessage.d.ts.map +1 -1
- package/dist/api/evm/protocol.d.ts +3 -0
- package/dist/api/evm/protocol.d.ts.map +1 -0
- package/dist/api/filecoin/FilecoinGetAddress.d.ts +1 -0
- package/dist/api/filecoin/FilecoinGetAddress.d.ts.map +1 -1
- package/dist/api/filecoin/FilecoinSignTransaction.d.ts +1 -0
- package/dist/api/filecoin/FilecoinSignTransaction.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +25 -0
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
- package/dist/api/firmware/FirmwarePreparationError.d.ts +3 -0
- package/dist/api/firmware/FirmwarePreparationError.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +12 -3
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +25 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +32 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/api/firmware/getBinary.d.ts +15 -4
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/protocolV2Release.d.ts +33 -0
- package/dist/api/firmware/protocolV2Release.d.ts.map +1 -0
- package/dist/api/firmware/updateBootloader.d.ts +2 -0
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +9 -1
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/filesystemValidation.d.ts +3 -0
- package/dist/api/helpers/filesystemValidation.d.ts.map +1 -1
- package/dist/api/helpers/paramsValidator.d.ts +1 -0
- package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts +43 -0
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -0
- package/dist/api/index.d.ts +9 -25
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/kaspa/KaspaGetAddress.d.ts +4 -0
- package/dist/api/kaspa/KaspaGetAddress.d.ts.map +1 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts +9 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
- package/dist/api/kaspa/helpers/TransferSerialize.d.ts.map +1 -1
- package/dist/api/lightning/LnurlAuth.d.ts +0 -4
- package/dist/api/lightning/LnurlAuth.d.ts.map +1 -1
- package/dist/api/near/NearGetAddress.d.ts +1 -0
- package/dist/api/near/NearGetAddress.d.ts.map +1 -1
- package/dist/api/near/NearSignTransaction.d.ts +1 -0
- package/dist/api/near/NearSignTransaction.d.ts.map +1 -1
- package/dist/api/nem/NEMGetAddress.d.ts +1 -0
- package/dist/api/nem/NEMGetAddress.d.ts.map +1 -1
- package/dist/api/nem/NEMSignTransaction.d.ts +1 -0
- package/dist/api/nem/NEMSignTransaction.d.ts.map +1 -1
- package/dist/api/neo/NeoGetAddress.d.ts.map +1 -1
- package/dist/api/neo/NeoSignTransaction.d.ts.map +1 -1
- package/dist/api/nervos/NervosGetAddress.d.ts.map +1 -1
- package/dist/api/nervos/NervosSignTransaction.d.ts.map +1 -1
- package/dist/api/nexa/NexaGetAddress.d.ts.map +1 -1
- package/dist/api/nexa/NexaSignTransaction.d.ts +1 -0
- package/dist/api/nexa/NexaSignTransaction.d.ts.map +1 -1
- package/dist/api/nostr/NostrDecryptMessage.d.ts +1 -0
- package/dist/api/nostr/NostrDecryptMessage.d.ts.map +1 -1
- package/dist/api/nostr/NostrEncryptMessage.d.ts +1 -0
- package/dist/api/nostr/NostrEncryptMessage.d.ts.map +1 -1
- package/dist/api/nostr/NostrGetPublicKey.d.ts +1 -0
- package/dist/api/nostr/NostrGetPublicKey.d.ts.map +1 -1
- package/dist/api/nostr/NostrSignEvent.d.ts +1 -0
- package/dist/api/nostr/NostrSignEvent.d.ts.map +1 -1
- package/dist/api/nostr/NostrSignSchnorr.d.ts +1 -0
- package/dist/api/nostr/NostrSignSchnorr.d.ts.map +1 -1
- package/dist/api/polkadot/PolkadotGetAddress.d.ts +2 -1
- package/dist/api/polkadot/PolkadotGetAddress.d.ts.map +1 -1
- package/dist/api/polkadot/PolkadotSignTransaction.d.ts +1 -0
- package/dist/api/polkadot/PolkadotSignTransaction.d.ts.map +1 -1
- package/dist/api/polkadot/networks.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts +1 -0
- package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts +1 -0
- package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +1 -0
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts +1 -0
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +7 -0
- package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceReboot.d.ts +1 -0
- package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceStatusGet.d.ts +7 -0
- package/dist/api/protocol-v2/DeviceStatusGet.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +27 -0
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -0
- package/dist/api/protocol-v2/FilesystemFormat.d.ts +1 -0
- package/dist/api/protocol-v2/FilesystemFormat.d.ts.map +1 -1
- package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts +1 -0
- package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts.map +1 -1
- package/dist/api/protocol-v2/Ping.d.ts +3 -0
- package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
- package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts +1 -0
- package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
- package/dist/api/protocol-v2/helpers.d.ts +1 -1
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
- package/dist/api/scdo/ScdoGetAddress.d.ts.map +1 -1
- package/dist/api/scdo/ScdoSignMessage.d.ts.map +1 -1
- package/dist/api/scdo/ScdoSignTransaction.d.ts.map +1 -1
- package/dist/api/solana/SolGetAddress.d.ts +1 -0
- package/dist/api/solana/SolGetAddress.d.ts.map +1 -1
- package/dist/api/solana/SolSignMessage.d.ts +2 -1
- package/dist/api/solana/SolSignMessage.d.ts.map +1 -1
- package/dist/api/solana/SolSignOffchainMessage.d.ts +2 -1
- package/dist/api/solana/SolSignOffchainMessage.d.ts.map +1 -1
- package/dist/api/solana/SolSignTransaction.d.ts +3 -2
- package/dist/api/solana/SolSignTransaction.d.ts.map +1 -1
- package/dist/api/starcoin/StarcoinGetAddress.d.ts +1 -0
- package/dist/api/starcoin/StarcoinGetAddress.d.ts.map +1 -1
- package/dist/api/starcoin/StarcoinGetPublicKey.d.ts +1 -0
- package/dist/api/starcoin/StarcoinGetPublicKey.d.ts.map +1 -1
- package/dist/api/starcoin/StarcoinSignMessage.d.ts +1 -0
- package/dist/api/starcoin/StarcoinSignMessage.d.ts.map +1 -1
- package/dist/api/starcoin/StarcoinSignTransaction.d.ts +1 -0
- package/dist/api/starcoin/StarcoinSignTransaction.d.ts.map +1 -1
- package/dist/api/starcoin/StarcoinVerifyMessage.d.ts +1 -0
- package/dist/api/starcoin/StarcoinVerifyMessage.d.ts.map +1 -1
- package/dist/api/stellar/StellarGetAddress.d.ts +1 -2
- package/dist/api/stellar/StellarGetAddress.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +2 -3
- package/dist/api/stellar/StellarSignTransaction.d.ts.map +1 -1
- package/dist/api/sui/SuiGetAddress.d.ts +2 -1
- package/dist/api/sui/SuiGetAddress.d.ts.map +1 -1
- package/dist/api/sui/SuiGetPublicKey.d.ts +2 -1
- package/dist/api/sui/SuiGetPublicKey.d.ts.map +1 -1
- package/dist/api/sui/SuiSignMessage.d.ts +2 -1
- package/dist/api/sui/SuiSignMessage.d.ts.map +1 -1
- package/dist/api/sui/SuiSignTransaction.d.ts +2 -1
- package/dist/api/sui/SuiSignTransaction.d.ts.map +1 -1
- package/dist/api/ton/TonGetAddress.d.ts +2 -1
- package/dist/api/ton/TonGetAddress.d.ts.map +1 -1
- package/dist/api/ton/TonSignData.d.ts +1 -0
- package/dist/api/ton/TonSignData.d.ts.map +1 -1
- package/dist/api/ton/TonSignMessage.d.ts +2 -1
- package/dist/api/ton/TonSignMessage.d.ts.map +1 -1
- package/dist/api/ton/TonSignProof.d.ts +2 -1
- package/dist/api/ton/TonSignProof.d.ts.map +1 -1
- package/dist/api/tron/TronGetAddress.d.ts +1 -0
- package/dist/api/tron/TronGetAddress.d.ts.map +1 -1
- package/dist/api/tron/TronSignMessage.d.ts +6 -1
- package/dist/api/tron/TronSignMessage.d.ts.map +1 -1
- package/dist/api/tron/TronSignTransaction.d.ts +2 -1
- package/dist/api/tron/TronSignTransaction.d.ts.map +1 -1
- package/dist/api/utils.d.ts +4 -1
- package/dist/api/utils.d.ts.map +1 -1
- package/dist/api/xrp/XrpGetAddress.d.ts +1 -0
- package/dist/api/xrp/XrpGetAddress.d.ts.map +1 -1
- package/dist/api/xrp/XrpSignTransaction.d.ts +1 -0
- package/dist/api/xrp/XrpSignTransaction.d.ts.map +1 -1
- package/dist/constants/index.d.ts +1 -1
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/core/RequestQueue.d.ts.map +1 -1
- package/dist/core/deviceEventRegistration.d.ts +13 -0
- package/dist/core/deviceEventRegistration.d.ts.map +1 -0
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/uiPromiseRegistry.d.ts +6 -0
- package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
- package/dist/data-manager/DataManager.d.ts +9 -3
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/Device.d.ts +72 -17
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +8 -6
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DeviceConnector.d.ts +4 -3
- package/dist/device/DeviceConnector.d.ts.map +1 -1
- package/dist/device/DeviceFeaturesState.d.ts +3 -0
- package/dist/device/DeviceFeaturesState.d.ts.map +1 -0
- package/dist/device/DevicePool.d.ts +6 -2
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts +13 -0
- package/dist/device/DeviceStateMapper.d.ts.map +1 -0
- package/dist/device/DeviceStateProjector.d.ts +7 -0
- package/dist/device/DeviceStateProjector.d.ts.map +1 -0
- package/dist/device/DeviceStateStore.d.ts +21 -0
- package/dist/device/DeviceStateStore.d.ts.map +1 -0
- package/dist/device/DeviceWalletSessionStore.d.ts +27 -0
- package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -0
- package/dist/device/cloneDeviceState.d.ts +2 -0
- package/dist/device/cloneDeviceState.d.ts.map +1 -0
- package/dist/device/deviceIdentity.d.ts +5 -0
- package/dist/device/deviceIdentity.d.ts.map +1 -0
- package/dist/deviceProfile/buildDeviceFeatures.d.ts +9 -3
- package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
- package/dist/deviceProfile/index.d.ts +0 -1
- package/dist/deviceProfile/index.d.ts.map +1 -1
- package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts +7 -0
- package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -0
- package/dist/events/device.d.ts +16 -2
- package/dist/events/device.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts +2 -0
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-promise.d.ts +4 -2
- package/dist/events/ui-promise.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +50 -4
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/events/ui-response.d.ts +10 -2
- package/dist/events/ui-response.d.ts.map +1 -1
- package/dist/index.d.ts +1818 -770
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11157 -4209
- package/dist/inject.d.ts +6 -1
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/deviceSession.d.ts +7 -0
- package/dist/protocols/protocol-v2/deviceSession.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/features.d.ts +21 -17
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/index.d.ts +3 -2
- package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +29 -0
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts +17 -0
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/uiInteraction.d.ts +42 -0
- package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts +2 -0
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts +27 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -0
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +48 -9
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkBLEFirmwareRelease.d.ts +2 -13
- package/dist/types/api/checkBLEFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkBootloaderRelease.d.ts +2 -6
- package/dist/types/api/checkBootloaderRelease.d.ts.map +1 -1
- package/dist/types/api/checkFirmwareRelease.d.ts +2 -13
- package/dist/types/api/checkFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkFirmwareTypeAvailable.d.ts +2 -2
- package/dist/types/api/checkFirmwareTypeAvailable.d.ts.map +1 -1
- package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
- package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
- package/dist/types/api/deviceSettings.d.ts +11 -2
- package/dist/types/api/deviceSettings.d.ts.map +1 -1
- package/dist/types/api/deviceUnlock.d.ts +6 -2
- package/dist/types/api/deviceUnlock.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +9 -3
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +76 -1
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts +28 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/types/api/getDeviceState.d.ts +12 -0
- package/dist/types/api/getDeviceState.d.ts.map +1 -0
- package/dist/types/api/getFeatures.d.ts.map +1 -1
- package/dist/types/api/getOnekeyFeatures.d.ts.map +1 -1
- package/dist/types/api/getPassphraseState.d.ts +2 -10
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +34 -31
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/kaspaSignTransaction.d.ts +42 -4
- package/dist/types/api/kaspaSignTransaction.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +35 -0
- package/dist/types/api/openWalletSession.d.ts.map +1 -0
- package/dist/types/api/protocolV2.d.ts +18 -84
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/api/protocolV2ResourceManifest.d.ts +17 -0
- package/dist/types/api/protocolV2ResourceManifest.d.ts.map +1 -0
- package/dist/types/api/sessionCache.d.ts +13 -0
- package/dist/types/api/sessionCache.d.ts.map +1 -0
- package/dist/types/device.d.ts +142 -10
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/params.d.ts +1 -0
- package/dist/types/params.d.ts.map +1 -1
- package/dist/types/settings.d.ts +69 -22
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/assets.d.ts +2 -1
- package/dist/utils/assets.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts +14 -0
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -0
- package/dist/utils/deviceFeaturesUtils.d.ts +10 -3
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts +9 -9
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/deviceSettings.d.ts +38 -7
- package/dist/utils/deviceSettings.d.ts.map +1 -1
- package/dist/utils/deviceVersionUtils.d.ts +7 -5
- package/dist/utils/deviceVersionUtils.d.ts.map +1 -1
- package/dist/utils/homescreen.d.ts +4 -0
- package/dist/utils/homescreen.d.ts.map +1 -1
- package/dist/utils/index.d.ts +6 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/networkUtils.d.ts +10 -1
- package/dist/utils/networkUtils.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/dist/utils/pro2Nft.d.ts +31 -0
- package/dist/utils/pro2Nft.d.ts.map +1 -0
- package/dist/utils/pro2Wallpaper.d.ts +22 -0
- package/dist/utils/pro2Wallpaper.d.ts.map +1 -0
- package/dist/utils/tracing.d.ts.map +1 -1
- package/dist/utils/uiProgressThrottle.d.ts +3 -0
- package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +53 -20
- package/src/api/CheckAllFirmwareRelease.ts +380 -4
- package/src/api/CheckBLEFirmwareRelease.ts +41 -3
- package/src/api/CheckBootloaderRelease.ts +41 -3
- package/src/api/CheckFirmwareRelease.ts +38 -5
- package/src/api/CipherKeyValue.ts +4 -0
- package/src/api/ClearSessionCache.ts +32 -0
- package/src/api/DetectDeviceConnectProtocol.ts +18 -0
- package/src/api/DirList.ts +9 -4
- package/src/api/DirMake.ts +7 -4
- package/src/api/DirRemove.ts +7 -4
- package/src/api/FileDelete.ts +7 -4
- package/src/api/FileRead.ts +15 -9
- package/src/api/FileWrite.ts +26 -181
- package/src/api/FirmwareUpdate.ts +30 -15
- package/src/api/FirmwareUpdateV2.ts +385 -115
- package/src/api/FirmwareUpdateV3.ts +274 -71
- package/src/api/FirmwareUpdateV4.ts +1465 -660
- package/src/api/GetDeviceState.ts +59 -0
- package/src/api/GetFeatures.ts +6 -4
- package/src/api/GetOnekeyFeatures.ts +1 -75
- package/src/api/GetPassphraseState.ts +36 -21
- package/src/api/OpenWalletSession.ts +268 -0
- package/src/api/PathInfo.ts +9 -4
- package/src/api/PromptWebDeviceAccess.ts +2 -7
- package/src/api/SearchDevices.ts +31 -4
- package/src/api/UploadPortfolio.ts +58 -0
- package/src/api/alephium/AlephiumGetAddress.ts +0 -4
- package/src/api/alephium/AlephiumSignMessage.ts +0 -4
- package/src/api/alephium/AlephiumSignTransaction.ts +2 -6
- package/src/api/algo/AlgoGetAddress.ts +4 -0
- package/src/api/algo/AlgoSignTransaction.ts +4 -0
- package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +45 -32
- package/src/api/aptos/AptosGetAddress.ts +4 -0
- package/src/api/aptos/AptosGetPublicKey.ts +4 -0
- package/src/api/aptos/AptosSignInMessage.ts +4 -0
- package/src/api/aptos/AptosSignMessage.ts +4 -0
- package/src/api/aptos/AptosSignTransaction.ts +4 -0
- package/src/api/benfen/BenfenGetAddress.ts +11 -7
- package/src/api/benfen/BenfenGetPublicKey.ts +0 -4
- package/src/api/benfen/BenfenSignMessage.ts +0 -4
- package/src/api/benfen/BenfenSignTransaction.ts +0 -4
- package/src/api/btc/BTCGetAddress.ts +8 -1
- package/src/api/btc/BTCGetPublicKey.ts +9 -2
- package/src/api/btc/BTCSignMessage.ts +8 -1
- package/src/api/btc/BTCSignPsbt.ts +4 -0
- package/src/api/btc/BTCSignTransaction.ts +8 -1
- package/src/api/btc/BTCVerifyMessage.ts +8 -1
- package/src/api/btc/helpers/versionLimit.ts +7 -4
- package/src/api/cardano/CardanoGetAddress.ts +4 -0
- package/src/api/cardano/CardanoGetPublicKey.ts +4 -0
- package/src/api/cardano/CardanoSignMessage.ts +5 -1
- package/src/api/cardano/CardanoSignTransaction.ts +5 -1
- package/src/api/conflux/ConfluxGetAddress.ts +6 -0
- package/src/api/conflux/ConfluxSignMessage.ts +6 -0
- package/src/api/conflux/ConfluxSignMessageCIP23.ts +6 -0
- package/src/api/conflux/ConfluxSignTransaction.ts +8 -5
- package/src/api/cosmos/CosmosGetAddress.ts +4 -0
- package/src/api/cosmos/CosmosGetPublicKey.ts +4 -0
- package/src/api/cosmos/CosmosSignTransaction.ts +4 -0
- package/src/api/device/DeviceCancel.ts +5 -0
- package/src/api/device/DeviceChangePin.ts +28 -0
- package/src/api/device/DeviceFullyUploadResource.ts +4 -5
- package/src/api/device/DeviceLock.ts +5 -0
- package/src/api/device/DeviceRebootToBoardloader.ts +5 -0
- package/src/api/device/DeviceRebootToBootloader.ts +5 -0
- package/src/api/device/DeviceSettings.ts +195 -1
- package/src/api/device/DeviceSupportFeatures.ts +4 -0
- package/src/api/device/DeviceUnlock.ts +21 -3
- package/src/api/device/DeviceUpdateBootloader.ts +126 -8
- package/src/api/device/DeviceWipe.ts +25 -0
- package/src/api/device/PreInitialize.ts +4 -0
- package/src/api/dynex/DnxGetAddress.ts +0 -6
- package/src/api/dynex/DnxSignTransaction.ts +0 -6
- package/src/api/evm/EVMGetAddress.ts +6 -2
- package/src/api/evm/EVMGetPublicKey.ts +6 -2
- package/src/api/evm/EVMSignMessage.ts +6 -2
- package/src/api/evm/EVMSignMessageEIP712.ts +1 -11
- package/src/api/evm/EVMSignTransaction.ts +6 -2
- package/src/api/evm/EVMSignTypedData.ts +42 -50
- package/src/api/evm/EVMVerifyMessage.ts +6 -2
- package/src/api/evm/legacyV1/getAddress.ts +2 -2
- package/src/api/evm/legacyV1/getPublicKey.ts +2 -2
- package/src/api/evm/legacyV1/signMessage.ts +2 -2
- package/src/api/evm/legacyV1/signTypedData.ts +2 -2
- package/src/api/evm/legacyV1/signTypedHash.ts +2 -2
- package/src/api/evm/legacyV1/verifyMessage.ts +2 -2
- package/src/api/evm/protocol.ts +6 -0
- package/src/api/filecoin/FilecoinGetAddress.ts +4 -0
- package/src/api/filecoin/FilecoinSignTransaction.ts +4 -0
- package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
- package/src/api/firmware/FirmwareHostBinding.ts +100 -0
- package/src/api/firmware/FirmwarePreparationError.ts +12 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +102 -16
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +772 -0
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +449 -0
- package/src/api/firmware/getBinary.ts +8 -3
- package/src/api/firmware/protocolV2Release.ts +166 -0
- package/src/api/firmware/updateBootloader.ts +19 -4
- package/src/api/firmware/uploadFirmware.ts +157 -26
- package/src/api/helpers/batchGetPublickeys.ts +2 -2
- package/src/api/helpers/filesystemValidation.ts +61 -0
- package/src/api/helpers/paramsValidator.ts +1 -1
- package/src/api/helpers/protocolV2FileWrite.ts +392 -0
- package/src/api/index.ts +10 -26
- package/src/api/kaspa/KaspaGetAddress.ts +7 -0
- package/src/api/kaspa/KaspaSignTransaction.ts +369 -29
- package/src/api/kaspa/helpers/TransferSerialize.ts +17 -7
- package/src/api/lightning/LnurlAuth.ts +0 -4
- package/src/api/near/NearGetAddress.ts +4 -0
- package/src/api/near/NearSignTransaction.ts +4 -0
- package/src/api/nem/NEMGetAddress.ts +4 -0
- package/src/api/nem/NEMSignTransaction.ts +4 -0
- package/src/api/neo/NeoGetAddress.ts +0 -4
- package/src/api/neo/NeoSignTransaction.ts +0 -4
- package/src/api/nervos/NervosGetAddress.ts +0 -4
- package/src/api/nervos/NervosSignTransaction.ts +2 -6
- package/src/api/nexa/NexaGetAddress.ts +0 -4
- package/src/api/nexa/NexaSignTransaction.ts +3 -5
- package/src/api/nostr/NostrDecryptMessage.ts +4 -0
- package/src/api/nostr/NostrEncryptMessage.ts +4 -0
- package/src/api/nostr/NostrGetPublicKey.ts +4 -0
- package/src/api/nostr/NostrSignEvent.ts +4 -0
- package/src/api/nostr/NostrSignSchnorr.ts +4 -0
- package/src/api/polkadot/PolkadotGetAddress.ts +4 -0
- package/src/api/polkadot/PolkadotSignTransaction.ts +4 -0
- package/src/api/polkadot/networks.ts +3 -3
- package/src/api/protocol-v2/DeviceFactoryInfoGet.ts +5 -2
- package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +5 -2
- package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +8 -5
- package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +10 -6
- package/src/api/protocol-v2/DeviceGetOnboardingStatus.ts +21 -0
- package/src/api/protocol-v2/DeviceInfoGet.ts +8 -15
- package/src/api/protocol-v2/DeviceReboot.ts +7 -3
- package/src/api/protocol-v2/DeviceStatusGet.ts +19 -0
- package/src/api/protocol-v2/DeviceUploadNft.ts +197 -0
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +134 -0
- package/src/api/protocol-v2/FilesystemFormat.ts +9 -3
- package/src/api/protocol-v2/FilesystemPermissionFix.ts +5 -2
- package/src/api/protocol-v2/Ping.ts +37 -3
- package/src/api/protocol-v2/ProtocolInfoRequest.ts +8 -3
- package/src/api/protocol-v2/helpers.ts +17 -17
- package/src/api/scdo/ScdoGetAddress.ts +0 -4
- package/src/api/scdo/ScdoSignMessage.ts +0 -4
- package/src/api/scdo/ScdoSignTransaction.ts +0 -4
- package/src/api/solana/SolGetAddress.ts +4 -0
- package/src/api/solana/SolSignMessage.ts +5 -1
- package/src/api/solana/SolSignOffchainMessage.ts +5 -1
- package/src/api/solana/SolSignTransaction.ts +6 -2
- package/src/api/starcoin/StarcoinGetAddress.ts +4 -0
- package/src/api/starcoin/StarcoinGetPublicKey.ts +4 -0
- package/src/api/starcoin/StarcoinSignMessage.ts +4 -0
- package/src/api/starcoin/StarcoinSignTransaction.ts +4 -0
- package/src/api/starcoin/StarcoinVerifyMessage.ts +4 -0
- package/src/api/stellar/StellarGetAddress.ts +1 -10
- package/src/api/stellar/StellarSignTransaction.ts +1 -14
- package/src/api/sui/SuiGetAddress.ts +5 -1
- package/src/api/sui/SuiGetPublicKey.ts +5 -1
- package/src/api/sui/SuiSignMessage.ts +5 -1
- package/src/api/sui/SuiSignTransaction.ts +5 -1
- package/src/api/ton/TonGetAddress.ts +5 -1
- package/src/api/ton/TonSignData.ts +5 -1
- package/src/api/ton/TonSignMessage.ts +5 -1
- package/src/api/ton/TonSignProof.ts +5 -1
- package/src/api/tron/TronGetAddress.ts +4 -0
- package/src/api/tron/TronSignMessage.ts +19 -8
- package/src/api/tron/TronSignTransaction.ts +5 -1
- package/src/api/utils.ts +32 -3
- package/src/api/xrp/XrpGetAddress.ts +4 -0
- package/src/api/xrp/XrpSignTransaction.ts +5 -1
- package/src/constants/index.ts +1 -4
- package/src/core/RequestQueue.ts +1 -0
- package/src/core/deviceEventRegistration.ts +27 -0
- package/src/core/index.ts +381 -152
- package/src/core/uiPromiseRegistry.ts +63 -0
- package/src/data/messages/messages-protocol-v2.json +1138 -441
- package/src/data/messages/messages.json +286 -1
- package/src/data-manager/DataManager.ts +132 -41
- package/src/data-manager/TransportManager.ts +7 -1
- package/src/data-manager/connectSettings.ts +11 -0
- package/src/device/Device.ts +898 -296
- package/src/device/DeviceCommands.ts +193 -158
- package/src/device/DeviceConnector.ts +44 -21
- package/src/device/DeviceFeaturesState.ts +25 -0
- package/src/device/DevicePool.ts +101 -23
- package/src/device/DeviceStateMapper.ts +416 -0
- package/src/device/DeviceStateProjector.ts +152 -0
- package/src/device/DeviceStateStore.ts +232 -0
- package/src/device/DeviceWalletSessionStore.ts +144 -0
- package/src/device/cloneDeviceState.ts +39 -0
- package/src/device/deviceIdentity.ts +18 -0
- package/src/deviceProfile/buildDeviceFeatures.ts +223 -189
- package/src/deviceProfile/index.ts +0 -1
- package/src/deviceProfile/protocolV2DeviceIdentity.ts +35 -0
- package/src/events/device.ts +22 -1
- package/src/events/logBlockEvent.ts +80 -2
- package/src/events/ui-promise.ts +4 -2
- package/src/events/ui-request.ts +61 -4
- package/src/events/ui-response.ts +12 -2
- package/src/index.ts +12 -0
- package/src/inject.ts +97 -45
- package/src/lowLevelInject.ts +11 -4
- package/src/protocols/protocol-v2/deviceSession.ts +24 -0
- package/src/protocols/protocol-v2/features.ts +100 -33
- package/src/protocols/protocol-v2/firmware.ts +3 -1
- package/src/protocols/protocol-v2/index.ts +8 -1
- package/src/protocols/protocol-v2/resources.ts +257 -0
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +65 -0
- package/src/protocols/protocol-v2/uiInteraction.ts +250 -0
- package/src/protocols/protocol-v2/unlockPolicy.ts +1 -0
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +131 -0
- package/src/protocols/protocol-v2/walletSession.ts +463 -0
- package/src/topLevelInject.ts +11 -4
- package/src/types/api/checkAllFirmwareRelease.ts +72 -9
- package/src/types/api/checkBLEFirmwareRelease.ts +4 -13
- package/src/types/api/checkBootloaderRelease.ts +2 -6
- package/src/types/api/checkFirmwareRelease.ts +2 -13
- package/src/types/api/checkFirmwareTypeAvailable.ts +2 -2
- package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
- package/src/types/api/deviceSettings.ts +26 -2
- package/src/types/api/deviceUnlock.ts +13 -2
- package/src/types/api/deviceUpdateBootloader.ts +6 -0
- package/src/types/api/export.ts +37 -1
- package/src/types/api/firmwareUpdate.ts +101 -5
- package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
- package/src/types/api/firmwareUpdatePlan.ts +38 -0
- package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
- package/src/types/api/getDeviceState.ts +19 -0
- package/src/types/api/getFeatures.ts +3 -0
- package/src/types/api/getOnekeyFeatures.ts +3 -0
- package/src/types/api/getPassphraseState.ts +9 -11
- package/src/types/api/index.ts +54 -64
- package/src/types/api/kaspaSignTransaction.ts +60 -4
- package/src/types/api/openWalletSession.ts +54 -0
- package/src/types/api/protocolV2.ts +33 -141
- package/src/types/api/protocolV2ResourceManifest.ts +19 -0
- package/src/types/api/sessionCache.ts +19 -0
- package/src/types/device.ts +216 -10
- package/src/types/params.ts +9 -2
- package/src/types/settings.ts +86 -24
- package/src/utils/assets.ts +4 -1
- package/src/utils/deviceFeaturesCompat.ts +191 -0
- package/src/utils/deviceFeaturesUtils.ts +65 -47
- package/src/utils/deviceInfoUtils.ts +29 -69
- package/src/utils/deviceSettings.ts +174 -39
- package/src/utils/deviceVersionUtils.ts +25 -44
- package/src/utils/findDefectiveBatchDevice.ts +3 -3
- package/src/utils/homescreen.ts +40 -0
- package/src/utils/index.ts +27 -3
- package/src/utils/networkUtils.ts +274 -16
- package/src/utils/pro2Nft.ts +142 -0
- package/src/utils/pro2Wallpaper.ts +130 -0
- package/src/utils/tracing.ts +3 -1
- package/src/utils/uiProgressThrottle.ts +63 -0
- package/tsconfig.type-tests.json +12 -0
- package/dist/api/GetDeviceInfo.d.ts +0 -9
- package/dist/api/GetDeviceInfo.d.ts.map +0 -1
- package/dist/api/firmware/progressThrottle.d.ts +0 -3
- package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
- package/dist/api/protocol-v2/FilesystemDiskControl.d.ts +0 -13
- package/dist/api/protocol-v2/FilesystemDiskControl.d.ts.map +0 -1
- package/dist/deviceProfile/buildDeviceProfile.d.ts +0 -21
- package/dist/deviceProfile/buildDeviceProfile.d.ts.map +0 -1
- package/dist/types/api/getDeviceInfo.d.ts +0 -87
- package/dist/types/api/getDeviceInfo.d.ts.map +0 -1
- package/src/api/GetDeviceInfo.ts +0 -145
- package/src/api/firmware/progressThrottle.ts +0 -44
- package/src/api/protocol-v2/FilesystemDiskControl.ts +0 -50
- package/src/deviceProfile/buildDeviceProfile.ts +0 -352
- package/src/types/api/getDeviceInfo.ts +0 -101
|
@@ -1,21 +1,27 @@
|
|
|
1
|
-
import { ERRORS, HardwareError, HardwareErrorCode, wait } from '@onekeyfe/hd-shared';
|
|
1
|
+
import { EDeviceType, ERRORS, HardwareError, HardwareErrorCode, wait } from '@onekeyfe/hd-shared';
|
|
2
2
|
import {
|
|
3
3
|
DeviceRebootType,
|
|
4
4
|
PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
|
|
5
|
+
PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE,
|
|
6
|
+
PROTOCOL_V2_BLE_FIRMWARE_FILE_CHUNK_SIZE,
|
|
5
7
|
PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE,
|
|
6
8
|
} from '@onekeyfe/hd-transport';
|
|
9
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
7
10
|
|
|
8
11
|
import { FirmwareUpdateTipMessage, UI_REQUEST } from '../events/ui-request';
|
|
12
|
+
import { validateProtocolV2FilesystemPath } from './helpers/filesystemValidation';
|
|
9
13
|
import { validateParams } from './helpers/paramsValidator';
|
|
10
14
|
import {
|
|
11
15
|
LoggerNames,
|
|
12
16
|
getDeviceBLEFirmwareVersion,
|
|
13
17
|
getDeviceBootloaderVersion,
|
|
14
18
|
getDeviceFirmwareVersion,
|
|
19
|
+
getDeviceType,
|
|
15
20
|
getFirmwareType,
|
|
16
21
|
getLogger,
|
|
17
22
|
} from '../utils';
|
|
18
23
|
import { getSysResourceBinary } from './firmware/getBinary';
|
|
24
|
+
import { normalizeFirmwarePreparationError } from './firmware/FirmwarePreparationError';
|
|
19
25
|
import { DataManager } from '../data-manager';
|
|
20
26
|
import { FirmwareUpdateBaseMethod } from './firmware/FirmwareUpdateBaseMethod';
|
|
21
27
|
import { DevicePool } from '../device/DevicePool';
|
|
@@ -24,47 +30,87 @@ import {
|
|
|
24
30
|
ProtocolV2FirmwareTargetType,
|
|
25
31
|
} from '../protocols/protocol-v2';
|
|
26
32
|
import { requestProtocolV2DeviceInfo } from '../protocols/protocol-v2/features';
|
|
33
|
+
import { isProtocolV2ResourceFileValid } from '../protocols/protocol-v2/resources';
|
|
27
34
|
import {
|
|
28
|
-
PROTOCOL_V2_FIRMWARE_UPDATE_RESPONSE_TYPES,
|
|
29
35
|
getProtocolV2UnknownErrorText,
|
|
30
36
|
isProtocolV2DeviceDisconnectedError,
|
|
31
37
|
} from './protocol-v2/helpers';
|
|
38
|
+
import { openFirmwareByteSource, writeFirmwareByteSource } from './firmware/FirmwareArtifactSource';
|
|
39
|
+
import { resolveFirmwareUpdateHostBinding } from './firmware/FirmwareHostBinding';
|
|
40
|
+
import {
|
|
41
|
+
assertFirmwareUpdatePreparedPlanBinding,
|
|
42
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
43
|
+
} from './firmware/FirmwareUpdatePreparedPlan';
|
|
32
44
|
|
|
33
|
-
import type {
|
|
45
|
+
import type {
|
|
46
|
+
FirmwareArtifactReference,
|
|
47
|
+
FirmwareUpdateV4Params,
|
|
48
|
+
FirmwareUpdateV4Target,
|
|
49
|
+
} from '../types/api/firmwareUpdate';
|
|
34
50
|
import type { EFirmwareType } from '@onekeyfe/hd-shared';
|
|
35
|
-
import type {
|
|
51
|
+
import type { ProtocolV2DeviceInfo } from '@onekeyfe/hd-transport';
|
|
36
52
|
import type { TypedResponseMessage } from '../device/DeviceCommands';
|
|
37
53
|
import type {
|
|
38
54
|
Features,
|
|
39
55
|
IFirmwareReleaseInfo,
|
|
40
56
|
IProtocolV2FirmwareComponent,
|
|
41
|
-
IProtocolV2ResourceManifestPackage,
|
|
42
57
|
IVersionArray,
|
|
43
58
|
} from '../types';
|
|
59
|
+
import type { FirmwareByteSource } from './firmware/FirmwareArtifactSource';
|
|
44
60
|
|
|
45
61
|
const Log = getLogger(LoggerNames.Method);
|
|
46
62
|
|
|
63
|
+
// Restored after a rebase dropped the declaration while keeping its use in
|
|
64
|
+
// fileWriteChunk; without it that error branch throws ReferenceError instead of
|
|
65
|
+
// the intended typed session error.
|
|
47
66
|
const SESSION_ERROR = 'session not found';
|
|
48
|
-
const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT =
|
|
67
|
+
const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 90 * 1000;
|
|
68
|
+
const PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT = 3 * 60 * 1000;
|
|
49
69
|
const PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT = 5 * 1000;
|
|
50
|
-
const
|
|
51
|
-
const
|
|
70
|
+
const PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT = 15 * 1000;
|
|
71
|
+
const PROTOCOL_V2_START_UPDATE_TIMEOUT = 3 * 60 * 1000;
|
|
72
|
+
const PROTOCOL_V2_INSTALL_TIMEOUT = 8 * 60 * 1000;
|
|
73
|
+
const PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT = 30 * 1000;
|
|
52
74
|
const PROTOCOL_V2_TARGET_STATUS_PENDING = 0;
|
|
53
75
|
const PROTOCOL_V2_TARGET_STATUS_IN_PROGRESS = 1;
|
|
54
76
|
const PROTOCOL_V2_TARGET_STATUS_FINISHED = 2;
|
|
55
77
|
const PROTOCOL_V2_TARGET_STATUS_FAILED_MIN = 3;
|
|
56
78
|
const PROTOCOL_V2_CONNECT_PROTOCOL = 'V2';
|
|
57
|
-
const PROTOCOL_V2_FIRMWARE_STAGING_VOLUME = '
|
|
79
|
+
const PROTOCOL_V2_FIRMWARE_STAGING_VOLUME = 'vol0:/';
|
|
58
80
|
const PROTOCOL_V2_MIN_FILE_CHUNK_SIZE = 64;
|
|
59
81
|
const PROTOCOL_V2_CONNECT_RETRY_COUNT = 10;
|
|
60
82
|
const PROTOCOL_V2_CONNECT_POLL_INTERVAL = 500;
|
|
61
83
|
const PROTOCOL_V2_CONNECT_SINGLE_TIMEOUT = 75 * 1000;
|
|
62
|
-
const PROTOCOL_V2_DEVICE_INFO_READY_TIMEOUT =
|
|
84
|
+
const PROTOCOL_V2_DEVICE_INFO_READY_TIMEOUT = 30 * 1000;
|
|
85
|
+
const PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT = 3;
|
|
86
|
+
const PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE = 'FirmwareInstallStatusConflict';
|
|
63
87
|
const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
|
|
64
88
|
const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
|
|
65
89
|
const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
|
|
66
90
|
const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
|
|
67
91
|
|
|
92
|
+
const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set<FirmwareUpdateV4Target>(['se03', 'se04']);
|
|
93
|
+
|
|
94
|
+
export function assertProtocolV2FirmwareTargetsSupported(
|
|
95
|
+
deviceType: EDeviceType | string | undefined,
|
|
96
|
+
params: FirmwareUpdateV4Params
|
|
97
|
+
) {
|
|
98
|
+
const unsupportedTargets = new Set(
|
|
99
|
+
(params.targetsToUpdate ?? []).filter(target => PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS.has(target))
|
|
100
|
+
);
|
|
101
|
+
if (params.se03Binary) unsupportedTargets.add('se03');
|
|
102
|
+
if (params.se04Binary) unsupportedTargets.add('se04');
|
|
103
|
+
|
|
104
|
+
if (!unsupportedTargets.size || deviceType === EDeviceType.Pro2) return;
|
|
105
|
+
|
|
106
|
+
const targetList = Array.from(unsupportedTargets).join(', ');
|
|
107
|
+
const message =
|
|
108
|
+
deviceType === EDeviceType.Neo
|
|
109
|
+
? `Neo only supports SE01 and SE02; unsupported firmware targets: ${targetList}`
|
|
110
|
+
: `Cannot safely update ${targetList} without a confirmed Pro2 device type`;
|
|
111
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotSupportMethod, message);
|
|
112
|
+
}
|
|
113
|
+
|
|
68
114
|
const getProtocolV2DeviceTransferProgress = (
|
|
69
115
|
bytesBeforeChunk: number,
|
|
70
116
|
bytesAfterChunk: number,
|
|
@@ -82,11 +128,6 @@ const getProtocolV2DeviceTransferProgress = (
|
|
|
82
128
|
return Math.min(Math.max(Math.ceil((bytesAfterChunk / totalBytes) * 100), 1), 99);
|
|
83
129
|
};
|
|
84
130
|
|
|
85
|
-
const formatProtocolV2TransferSpeed = (bytes: number, elapsedMs: number) => {
|
|
86
|
-
const safeElapsedMs = Math.max(elapsedMs, 1);
|
|
87
|
-
return (bytes / 1024 / (safeElapsedMs / 1000)).toFixed(2);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
131
|
type ProtocolV2FirmwareUpdateStatusTarget = {
|
|
91
132
|
target_id: number | string;
|
|
92
133
|
status?: number | string;
|
|
@@ -94,17 +135,20 @@ type ProtocolV2FirmwareUpdateStatusTarget = {
|
|
|
94
135
|
path?: string;
|
|
95
136
|
};
|
|
96
137
|
|
|
97
|
-
type ProtocolV2FirmwareUpdateStartResponse =
|
|
98
|
-
| TypedResponseMessage<'Success'>
|
|
99
|
-
| TypedResponseMessage<'DeviceFirmwareUpdateStatus'>
|
|
100
|
-
| undefined;
|
|
138
|
+
type ProtocolV2FirmwareUpdateStartResponse = TypedResponseMessage<'Success'>;
|
|
101
139
|
|
|
102
140
|
type ProtocolV2TargetBinary = { fileName: string; binary: ArrayBuffer; targetId: number };
|
|
103
141
|
type ProtocolV2InstallItem = ProtocolV2TargetBinary & {
|
|
104
142
|
kind: ProtocolV2RemoteComponentTarget['kind'];
|
|
105
143
|
};
|
|
106
|
-
|
|
107
|
-
|
|
144
|
+
/** Protocol V2 resource file written independently to devicePath through FileWrite. */
|
|
145
|
+
type ProtocolV2ResourceBundleBinary = {
|
|
146
|
+
name: string;
|
|
147
|
+
binary: ArrayBuffer;
|
|
148
|
+
devicePath: string;
|
|
149
|
+
version?: IVersionArray;
|
|
150
|
+
payloadHash?: string;
|
|
151
|
+
headerHash?: string;
|
|
108
152
|
};
|
|
109
153
|
|
|
110
154
|
type ProtocolV2RemoteComponentBinary = ProtocolV2RemoteComponentTarget & {
|
|
@@ -114,7 +158,36 @@ type ProtocolV2RemoteComponentBinary = ProtocolV2RemoteComponentTarget & {
|
|
|
114
158
|
type ProtocolV2RemoteComponentTarget = {
|
|
115
159
|
fileName: string;
|
|
116
160
|
targetId: number;
|
|
117
|
-
kind: 'bootloader' | 'firmware'
|
|
161
|
+
kind: 'bootloader' | 'firmware';
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
type ProtocolV2InstallSource = {
|
|
165
|
+
fileName: string;
|
|
166
|
+
source: FirmwareByteSource;
|
|
167
|
+
targetId: number;
|
|
168
|
+
kind: ProtocolV2RemoteComponentTarget['kind'];
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
type ProtocolV2ResourceBundleSource = {
|
|
172
|
+
name: string;
|
|
173
|
+
source: FirmwareByteSource;
|
|
174
|
+
devicePath: string;
|
|
175
|
+
version?: IVersionArray;
|
|
176
|
+
payloadHash?: string;
|
|
177
|
+
headerHash?: string;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
type ProtocolV2ExecutionPhaseKind =
|
|
181
|
+
| 'resource-sync'
|
|
182
|
+
| 'bootloader-install'
|
|
183
|
+
| 'bootloader-verify'
|
|
184
|
+
| 'component-install'
|
|
185
|
+
| 'final-verify';
|
|
186
|
+
|
|
187
|
+
type ProtocolV2ExecutionPhase = {
|
|
188
|
+
kind: ProtocolV2ExecutionPhaseKind;
|
|
189
|
+
installSources: ProtocolV2InstallSource[];
|
|
190
|
+
resourceSources: ProtocolV2ResourceBundleSource[];
|
|
118
191
|
};
|
|
119
192
|
|
|
120
193
|
type ProtocolV2OkppHeader = {
|
|
@@ -167,18 +240,40 @@ const PROTOCOL_V2_REMOTE_COMPONENT_TARGETS: Readonly<
|
|
|
167
240
|
targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04,
|
|
168
241
|
kind: 'firmware',
|
|
169
242
|
},
|
|
170
|
-
CRATE: {
|
|
171
|
-
fileName: 'resource.bin',
|
|
172
|
-
targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
|
|
173
|
-
kind: 'resource',
|
|
174
|
-
},
|
|
175
243
|
};
|
|
176
244
|
|
|
245
|
+
const PROTOCOL_V2_FIRMWARE_STAGING_PATHS = new Set(
|
|
246
|
+
Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(
|
|
247
|
+
target => `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${target.fileName}`
|
|
248
|
+
)
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
252
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH = `${PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH}.staging`;
|
|
253
|
+
|
|
254
|
+
const resolveProtocolV2ResourceWritePath = (devicePath: string) => {
|
|
255
|
+
const normalizedPath = devicePath.replace(/^vol0:(?!\/)/i, 'vol0:/').toLowerCase();
|
|
256
|
+
return normalizedPath === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH
|
|
257
|
+
? PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH
|
|
258
|
+
: devicePath;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map<number, FirmwareUpdateV4Target>([
|
|
262
|
+
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER, 'boot'],
|
|
263
|
+
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1, 'app_v1'],
|
|
264
|
+
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2, 'app_v2'],
|
|
265
|
+
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR, 'coprocessor'],
|
|
266
|
+
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01, 'se01'],
|
|
267
|
+
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02, 'se02'],
|
|
268
|
+
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03, 'se03'],
|
|
269
|
+
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, 'se04'],
|
|
270
|
+
]);
|
|
271
|
+
|
|
177
272
|
const PROTOCOL_V2_ROMLOADER_UNSUPPORTED_MESSAGE =
|
|
178
273
|
'FW_MGMT_TARGET_ROMLOADER is not accepted by the current Pro2 bootloader update request. Flash romloader with the loader-specific flow instead of firmwareUpdateV4.';
|
|
179
274
|
|
|
180
|
-
// hd-transport
|
|
181
|
-
//
|
|
275
|
+
// hd-transport historically decodes scalar enums as enum-name strings.
|
|
276
|
+
// Map them back to firmware protocol values before internal comparisons.
|
|
182
277
|
const PROTOCOL_V2_TARGET_ID_BY_DECODED_NAME = new Map<string, number>(
|
|
183
278
|
Object.entries(ProtocolV2FirmwareTargetType).map(([key, value]) => [key, value])
|
|
184
279
|
);
|
|
@@ -204,27 +299,20 @@ const isProtocolV2ReconnectProbeError = (error: unknown) => {
|
|
|
204
299
|
);
|
|
205
300
|
};
|
|
206
301
|
|
|
207
|
-
const
|
|
302
|
+
const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
|
|
208
303
|
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
209
304
|
return (
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
message.includes('
|
|
213
|
-
(message.includes('response timeout') && message.includes('devicefirmwareupdatestatusget')) ||
|
|
214
|
-
message.includes('device not found') ||
|
|
215
|
-
message.includes('transportnotfound')
|
|
305
|
+
message.includes('handler not registered') ||
|
|
306
|
+
message.includes('message handler not found') ||
|
|
307
|
+
message.includes('unsupported message')
|
|
216
308
|
);
|
|
217
309
|
};
|
|
218
310
|
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
message.includes('libusb_transfer_timed_out') ||
|
|
225
|
-
(message.includes('response timeout') && message.includes('devicefirmwareupdaterequest'))
|
|
226
|
-
);
|
|
227
|
-
};
|
|
311
|
+
const isProtocolV2TerminalInstallStatusError = (error: unknown) =>
|
|
312
|
+
error instanceof HardwareError &&
|
|
313
|
+
(error.errorCode === HardwareErrorCode.FirmwareError ||
|
|
314
|
+
error.errorCode === HardwareErrorCode.FirmwareVerificationFailed ||
|
|
315
|
+
error.params?.firmwareUpdateCode === PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE);
|
|
228
316
|
|
|
229
317
|
const isProtocolV2TargetStatusFinished = (status: ProtocolV2FirmwareUpdateStatusTarget['status']) =>
|
|
230
318
|
normalizeProtocolV2TargetStatus(status) === PROTOCOL_V2_TARGET_STATUS_FINISHED;
|
|
@@ -268,13 +356,6 @@ const versionArrayToNumber = (version?: IVersionArray) => {
|
|
|
268
356
|
return version[0] * 0x10000 + version[1] * 0x100 + version[2];
|
|
269
357
|
};
|
|
270
358
|
|
|
271
|
-
const versionStringToArray = (version?: string | null): IVersionArray | undefined => {
|
|
272
|
-
if (!version) return undefined;
|
|
273
|
-
const parts = version.split('.').map(part => Number(part));
|
|
274
|
-
if (parts.length !== 3 || parts.some(part => !Number.isFinite(part))) return undefined;
|
|
275
|
-
return parts as IVersionArray;
|
|
276
|
-
};
|
|
277
|
-
|
|
278
359
|
const compareProtocolV2Versions = (current?: IVersionArray, target?: IVersionArray) => {
|
|
279
360
|
const currentNumber = versionArrayToNumber(current);
|
|
280
361
|
const targetNumber = versionArrayToNumber(target);
|
|
@@ -361,6 +442,43 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
|
|
|
361
442
|
};
|
|
362
443
|
};
|
|
363
444
|
|
|
445
|
+
export const isProtocolV2FirmwareFingerprintValid = (
|
|
446
|
+
binary: ArrayBuffer | Uint8Array,
|
|
447
|
+
fingerprint: string | undefined
|
|
448
|
+
) => {
|
|
449
|
+
const expectedFingerprint = normalizeProtocolV2Hex(fingerprint);
|
|
450
|
+
if (!expectedFingerprint) return true;
|
|
451
|
+
return bytesToHex(sha256(toProtocolV2Bytes(binary))) === expectedFingerprint;
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
export const assertProtocolV2ReconnectIdentity = (
|
|
455
|
+
expectedSerialNumber?: string,
|
|
456
|
+
actualSerialNumber?: string,
|
|
457
|
+
expectedPath?: string,
|
|
458
|
+
actualPath?: string
|
|
459
|
+
) => {
|
|
460
|
+
if (expectedSerialNumber && actualSerialNumber) {
|
|
461
|
+
if (actualSerialNumber !== expectedSerialNumber) {
|
|
462
|
+
throw ERRORS.TypedError(
|
|
463
|
+
HardwareErrorCode.DeviceNotFound,
|
|
464
|
+
`Protocol V2 reconnect physical identity mismatch: expected ${expectedSerialNumber}, received ${actualSerialNumber}`
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (expectedPath && actualPath && expectedPath === actualPath) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
throw ERRORS.TypedError(
|
|
475
|
+
HardwareErrorCode.DeviceNotFound,
|
|
476
|
+
`Protocol V2 reconnect physical identity unavailable: expected path ${
|
|
477
|
+
expectedPath ?? 'unknown'
|
|
478
|
+
}, received ${actualPath ?? 'unknown'}`
|
|
479
|
+
);
|
|
480
|
+
};
|
|
481
|
+
|
|
364
482
|
/**
|
|
365
483
|
* FirmwareUpdateV4 is the complete Protocol V2 firmware update flow.
|
|
366
484
|
*
|
|
@@ -370,9 +488,28 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
|
|
|
370
488
|
* - completion waits for target status to finish, reboots to normal, then polls DeviceInfo
|
|
371
489
|
*/
|
|
372
490
|
export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareUpdateV4Params> {
|
|
491
|
+
private protocolV2ExpectedSerialNumber?: string;
|
|
492
|
+
|
|
493
|
+
private protocolV2ExpectedPath?: string;
|
|
494
|
+
|
|
495
|
+
getSupportedProtocols() {
|
|
496
|
+
return ['V2'] as const;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
private protocolV2PreparedSources: FirmwareByteSource[] = [];
|
|
500
|
+
|
|
501
|
+
private protocolV2ExecutionInLoader = false;
|
|
502
|
+
|
|
503
|
+
private protocolV2CompletedTargetVersions = new Map<number, number>();
|
|
504
|
+
|
|
505
|
+
private protocolV2LatestFinalFeatures?: Features;
|
|
506
|
+
|
|
507
|
+
private protocolV2FinalStatusVerified = false;
|
|
508
|
+
|
|
373
509
|
init() {
|
|
374
510
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
375
511
|
this.requireDeviceMode = [];
|
|
512
|
+
this.unlockPolicy = 'unlock-before-run';
|
|
376
513
|
this.useDevicePassphraseState = false;
|
|
377
514
|
this.skipForceUpdateCheck = true;
|
|
378
515
|
|
|
@@ -393,7 +530,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
393
530
|
|
|
394
531
|
validateParams(payload, [
|
|
395
532
|
{ name: 'chunkSize', type: 'number' },
|
|
396
|
-
{ name: 'resourceBinaries', type: 'array', allowEmpty: true },
|
|
397
533
|
{ name: 'forcedUpdateRes', type: 'boolean' },
|
|
398
534
|
{ name: 'bootloaderBinary', type: 'buffer' },
|
|
399
535
|
{ name: 'romloaderBinary', type: 'buffer' },
|
|
@@ -405,10 +541,64 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
405
541
|
{ name: 'se03Binary', type: 'buffer' },
|
|
406
542
|
{ name: 'se04Binary', type: 'buffer' },
|
|
407
543
|
{ name: 'firmwareType', type: 'string' },
|
|
544
|
+
{ name: 'targetsToUpdate', type: 'array', allowEmpty: true },
|
|
408
545
|
{ name: 'platform', type: 'string' },
|
|
546
|
+
{ name: 'expectedDeviceId', type: 'string' },
|
|
547
|
+
{ name: 'resourceFiles', type: 'array', allowEmpty: true },
|
|
409
548
|
]);
|
|
549
|
+
if (
|
|
550
|
+
payload.expectedDeviceId !== undefined &&
|
|
551
|
+
(payload.expectedDeviceId.length === 0 || payload.expectedDeviceId.length > 160)
|
|
552
|
+
) {
|
|
553
|
+
throw ERRORS.TypedError(
|
|
554
|
+
HardwareErrorCode.CallMethodInvalidParameter,
|
|
555
|
+
'Protocol V2 expected device identity is invalid'
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
const hostBinding =
|
|
559
|
+
payload.preparedPlan || payload.componentArtifacts || payload.resourceBundleArtifacts
|
|
560
|
+
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration)
|
|
561
|
+
: undefined;
|
|
562
|
+
if (hostBinding) {
|
|
563
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
564
|
+
preparedPlan: payload.preparedPlan,
|
|
565
|
+
executor: 'v4',
|
|
566
|
+
platform: payload.platform,
|
|
567
|
+
scopeTargets: [
|
|
568
|
+
'boot',
|
|
569
|
+
'app_v1',
|
|
570
|
+
'app_v2',
|
|
571
|
+
'coprocessor',
|
|
572
|
+
'resource',
|
|
573
|
+
'se01',
|
|
574
|
+
'se02',
|
|
575
|
+
'se03',
|
|
576
|
+
'se04',
|
|
577
|
+
],
|
|
578
|
+
bindings: [
|
|
579
|
+
...Object.entries(payload.componentArtifacts ?? {}).flatMap(([target, artifact]) =>
|
|
580
|
+
artifact
|
|
581
|
+
? [
|
|
582
|
+
{
|
|
583
|
+
target: target as Exclude<FirmwareUpdateV4Target, 'resource'>,
|
|
584
|
+
artifact,
|
|
585
|
+
},
|
|
586
|
+
]
|
|
587
|
+
: []
|
|
588
|
+
),
|
|
589
|
+
...(payload.resourceBundleArtifacts ?? []).map(
|
|
590
|
+
(entry: { name: string; artifact: FirmwareArtifactReference }) => ({
|
|
591
|
+
target: 'resource' as const,
|
|
592
|
+
logicalName: entry.name,
|
|
593
|
+
artifact: entry.artifact,
|
|
594
|
+
})
|
|
595
|
+
),
|
|
596
|
+
],
|
|
597
|
+
});
|
|
598
|
+
}
|
|
410
599
|
|
|
411
600
|
this.params = {
|
|
601
|
+
preparedPlan: payload.preparedPlan,
|
|
412
602
|
chunkSize: payload.chunkSize,
|
|
413
603
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
414
604
|
bootloaderBinary: payload.bootloaderBinary,
|
|
@@ -420,19 +610,33 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
420
610
|
se02Binary: payload.se02Binary,
|
|
421
611
|
se03Binary: payload.se03Binary,
|
|
422
612
|
se04Binary: payload.se04Binary,
|
|
423
|
-
|
|
613
|
+
resourceFiles: payload.resourceFiles,
|
|
424
614
|
firmwareType: payload.firmwareType,
|
|
615
|
+
targetsToUpdate: payload.targetsToUpdate,
|
|
616
|
+
expectedTargetVersions: payload.expectedTargetVersions,
|
|
425
617
|
platform: payload.platform,
|
|
618
|
+
expectedDeviceId: payload.expectedDeviceId,
|
|
619
|
+
artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
|
|
620
|
+
componentArtifacts: payload.componentArtifacts,
|
|
621
|
+
resourceBundleArtifacts: payload.resourceBundleArtifacts,
|
|
426
622
|
};
|
|
427
623
|
}
|
|
428
624
|
|
|
429
|
-
private getProtocolV2FirmwareChunkSize() {
|
|
625
|
+
private getProtocolV2FirmwareChunkSize(direction: 'read' | 'write', filePath?: string) {
|
|
430
626
|
const payloadChunkSize = Number(this.params?.chunkSize);
|
|
431
627
|
const env = DataManager.getSettings('env');
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
628
|
+
const isBle = this.params?.platform === 'native' || (env && DataManager.isBleConnect(env));
|
|
629
|
+
let maxChunkSize = PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
|
|
630
|
+
if (isBle) {
|
|
631
|
+
if (direction === 'read') {
|
|
632
|
+
maxChunkSize = PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE;
|
|
633
|
+
} else {
|
|
634
|
+
// Firmware staging writes tolerate a larger BLE chunk than generic filesystem writes.
|
|
635
|
+
maxChunkSize = PROTOCOL_V2_FIRMWARE_STAGING_PATHS.has(filePath ?? '')
|
|
636
|
+
? PROTOCOL_V2_BLE_FIRMWARE_FILE_CHUNK_SIZE
|
|
637
|
+
: PROTOCOL_V2_BLE_FILE_CHUNK_SIZE;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
436
640
|
if (!Number.isFinite(payloadChunkSize) || payloadChunkSize <= 0) {
|
|
437
641
|
return maxChunkSize;
|
|
438
642
|
}
|
|
@@ -443,69 +647,401 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
443
647
|
}
|
|
444
648
|
|
|
445
649
|
async run() {
|
|
446
|
-
if (!this.device.isProtocolV2()) {
|
|
447
|
-
throw ERRORS.TypedError(
|
|
448
|
-
HardwareErrorCode.RuntimeError,
|
|
449
|
-
'firmwareUpdateV4 requires a Protocol V2 device'
|
|
450
|
-
);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
650
|
Log.debug('FirmwareUpdateV4 strategy: Protocol V2');
|
|
454
651
|
return this.runProtocolV2();
|
|
455
652
|
}
|
|
456
653
|
|
|
457
654
|
private async runProtocolV2() {
|
|
655
|
+
await this.captureProtocolV2PhysicalIdentity();
|
|
458
656
|
const deviceFeatures = await this.getProtocolV2DeviceFeatures();
|
|
657
|
+
const currentDeviceType = this.device.getCurrentDeviceType();
|
|
658
|
+
const capabilityDeviceType =
|
|
659
|
+
currentDeviceType === EDeviceType.Pro2 || currentDeviceType === EDeviceType.Neo
|
|
660
|
+
? currentDeviceType
|
|
661
|
+
: getDeviceType(deviceFeatures);
|
|
662
|
+
assertProtocolV2FirmwareTargetsSupported(capabilityDeviceType, this.params);
|
|
459
663
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
460
664
|
const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
|
|
665
|
+
this.validateExpectedTargetVersions();
|
|
666
|
+
|
|
667
|
+
if (
|
|
668
|
+
(this.params.componentArtifacts && Object.keys(this.params.componentArtifacts).length > 0) ||
|
|
669
|
+
this.params.resourceBundleArtifacts?.length
|
|
670
|
+
) {
|
|
671
|
+
return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
672
|
+
}
|
|
673
|
+
const hasExplicitResourceFiles = !!this.params.resourceFiles?.length;
|
|
674
|
+
const wantsResources = !!this.params.targetsToUpdate?.includes('resource');
|
|
675
|
+
const needsPreparedResources = !hasExplicitResourceFiles && wantsResources;
|
|
461
676
|
|
|
462
|
-
let resourceBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
463
677
|
let fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
464
678
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
465
679
|
let installItems: ProtocolV2InstallItem[] | undefined;
|
|
680
|
+
let resourceBundles: ProtocolV2ResourceBundleBinary[] | undefined;
|
|
466
681
|
try {
|
|
467
682
|
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
468
|
-
|
|
683
|
+
resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
|
|
469
684
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
470
685
|
bootloaderBinary = this.prepareBootloaderBinary();
|
|
471
|
-
|
|
686
|
+
const needsRemoteFirmware = !this.hasExplicitProtocolV2Payload(fwBinaryMap);
|
|
687
|
+
if (needsPreparedResources) {
|
|
688
|
+
throw ERRORS.TypedError(
|
|
689
|
+
HardwareErrorCode.RuntimeError,
|
|
690
|
+
'Protocol V2 resource manifest must be prepared by the external firmware host',
|
|
691
|
+
{
|
|
692
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
693
|
+
}
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
if (
|
|
697
|
+
needsRemoteFirmware &&
|
|
698
|
+
(this.params.artifactReader ||
|
|
699
|
+
DataManager.getSettings('firmwareManifestMode') === 'external-only')
|
|
700
|
+
) {
|
|
701
|
+
throw ERRORS.TypedError(
|
|
702
|
+
HardwareErrorCode.RuntimeError,
|
|
703
|
+
'Protocol V2 firmware artifacts must be prepared by the external firmware host',
|
|
704
|
+
{
|
|
705
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
706
|
+
}
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
if (needsRemoteFirmware) {
|
|
710
|
+
// Remote updates must use a freshly fetched config before any reboot or file write.
|
|
711
|
+
await DataManager.forceReloadData();
|
|
712
|
+
}
|
|
713
|
+
if (needsRemoteFirmware) {
|
|
472
714
|
const remoteBinaries = await this.prepareRemoteProtocolV2Binaries(
|
|
473
715
|
firmwareType,
|
|
474
716
|
deviceFeatures
|
|
475
717
|
);
|
|
476
|
-
resourceBinaryMap = remoteBinaries.resourceBinaryMap;
|
|
477
718
|
bootloaderBinary = remoteBinaries.bootloaderBinary;
|
|
478
719
|
fwBinaryMap = remoteBinaries.fwBinaryMap;
|
|
479
720
|
installItems = remoteBinaries.installItems;
|
|
480
721
|
}
|
|
481
722
|
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
482
723
|
} catch (err) {
|
|
483
|
-
|
|
724
|
+
if (
|
|
725
|
+
typeof err === 'object' &&
|
|
726
|
+
err !== null &&
|
|
727
|
+
'params' in err &&
|
|
728
|
+
(err as HardwareError).params?.firmwareUpdateCode === 'FirmwareArtifactsNotPrepared'
|
|
729
|
+
) {
|
|
730
|
+
throw err;
|
|
731
|
+
}
|
|
732
|
+
if (err instanceof HardwareError && err.errorCode === HardwareErrorCode.NetworkError) {
|
|
733
|
+
throw err;
|
|
734
|
+
}
|
|
735
|
+
throw normalizeFirmwarePreparationError(err);
|
|
484
736
|
}
|
|
485
737
|
|
|
486
|
-
if (
|
|
738
|
+
if (
|
|
739
|
+
!bootloaderBinary &&
|
|
740
|
+
fwBinaryMap.length === 0 &&
|
|
741
|
+
!installItems?.length &&
|
|
742
|
+
!resourceBundles?.length
|
|
743
|
+
) {
|
|
487
744
|
throw ERRORS.TypedError(
|
|
488
745
|
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
489
746
|
'No firmware to update'
|
|
490
747
|
);
|
|
491
748
|
}
|
|
492
749
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
await this.executeProtocolV2Update({
|
|
496
|
-
resourceBinaryMap,
|
|
750
|
+
return this.executeProtocolV2Update({
|
|
497
751
|
fwBinaryMap,
|
|
498
752
|
bootloaderBinary,
|
|
499
753
|
...(installItems ? { installItems } : undefined),
|
|
754
|
+
...(resourceBundles?.length ? { resourceBundles } : undefined),
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
private async openProtocolV2PreparedSource(artifact: FirmwareArtifactReference) {
|
|
759
|
+
const source = await openFirmwareByteSource({
|
|
760
|
+
artifact,
|
|
761
|
+
reader: this.params.artifactReader,
|
|
500
762
|
});
|
|
763
|
+
if (!source) {
|
|
764
|
+
throw ERRORS.TypedError(
|
|
765
|
+
HardwareErrorCode.RuntimeError,
|
|
766
|
+
`Firmware artifact ${artifact.artifactRef} is not prepared`,
|
|
767
|
+
{
|
|
768
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
769
|
+
}
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
this.protocolV2PreparedSources.push(source);
|
|
773
|
+
return source;
|
|
774
|
+
}
|
|
501
775
|
|
|
502
|
-
|
|
776
|
+
private async openProtocolV2MemorySource(binary: ArrayBuffer) {
|
|
777
|
+
const source = await openFirmwareByteSource({ binary });
|
|
778
|
+
if (!source) {
|
|
779
|
+
throw ERRORS.TypedError(
|
|
780
|
+
HardwareErrorCode.RuntimeError,
|
|
781
|
+
'Protocol V2 firmware binary is empty'
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
this.protocolV2PreparedSources.push(source);
|
|
785
|
+
return source;
|
|
786
|
+
}
|
|
503
787
|
|
|
504
|
-
|
|
505
|
-
this.
|
|
506
|
-
|
|
788
|
+
private async closeProtocolV2PreparedSources() {
|
|
789
|
+
const sources = this.protocolV2PreparedSources.splice(0);
|
|
790
|
+
await Promise.all(sources.map(source => source.close().catch(() => undefined)));
|
|
791
|
+
}
|
|
507
792
|
|
|
508
|
-
|
|
793
|
+
private async prepareProtocolV2InstallSources(
|
|
794
|
+
firmwareType: EFirmwareType,
|
|
795
|
+
features: Features
|
|
796
|
+
): Promise<ProtocolV2InstallSource[]> {
|
|
797
|
+
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
798
|
+
if (!release) {
|
|
799
|
+
throw ERRORS.TypedError(
|
|
800
|
+
HardwareErrorCode.RuntimeError,
|
|
801
|
+
'Protocol V2 firmware release is unavailable'
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
const componentArtifacts = this.params.componentArtifacts ?? {};
|
|
805
|
+
const requestedTargets = new Set(
|
|
806
|
+
this.params.targetsToUpdate ?? (Object.keys(componentArtifacts) as FirmwareUpdateV4Target[])
|
|
807
|
+
);
|
|
808
|
+
const installSources: ProtocolV2InstallSource[] = [];
|
|
809
|
+
const preparedTargets = new Set<FirmwareUpdateV4Target>();
|
|
810
|
+
|
|
811
|
+
for (const [key, component] of this.getRemoteComponentEntries(release)) {
|
|
812
|
+
const target = this.getRemoteComponentTarget(key, component);
|
|
813
|
+
const updateTarget = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId);
|
|
814
|
+
if (updateTarget && updateTarget !== 'resource' && requestedTargets.has(updateTarget)) {
|
|
815
|
+
const artifact = componentArtifacts[updateTarget];
|
|
816
|
+
if (!artifact) {
|
|
817
|
+
throw ERRORS.TypedError(
|
|
818
|
+
HardwareErrorCode.RuntimeError,
|
|
819
|
+
`Protocol V2 ${updateTarget} artifact is not prepared`,
|
|
820
|
+
{
|
|
821
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
822
|
+
artifactName: updateTarget,
|
|
823
|
+
}
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
installSources.push({
|
|
827
|
+
...target,
|
|
828
|
+
source: await this.openProtocolV2PreparedSource(artifact),
|
|
829
|
+
});
|
|
830
|
+
preparedTargets.add(updateTarget);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
const unknownTarget = Array.from(requestedTargets).find(
|
|
835
|
+
target => target !== 'resource' && !preparedTargets.has(target)
|
|
836
|
+
);
|
|
837
|
+
if (unknownTarget) {
|
|
838
|
+
throw ERRORS.TypedError(
|
|
839
|
+
HardwareErrorCode.RuntimeError,
|
|
840
|
+
`Protocol V2 release does not contain requested target ${unknownTarget}`
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
return installSources;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
private async prepareProtocolV2ResourceSources(
|
|
847
|
+
firmwareType: EFirmwareType,
|
|
848
|
+
features: Features
|
|
849
|
+
): Promise<ProtocolV2ResourceBundleSource[]> {
|
|
850
|
+
const preparedArtifacts = this.params.resourceBundleArtifacts ?? [];
|
|
851
|
+
const resourceRequested =
|
|
852
|
+
this.params.targetsToUpdate?.includes('resource') || preparedArtifacts.length > 0;
|
|
853
|
+
if (!resourceRequested) {
|
|
854
|
+
return [];
|
|
855
|
+
}
|
|
856
|
+
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
857
|
+
const descriptors = release?.resourceBundles ?? [];
|
|
858
|
+
const artifactByName = new Map(
|
|
859
|
+
preparedArtifacts.map(item => [item.name, item.artifact] as const)
|
|
860
|
+
);
|
|
861
|
+
const sources: ProtocolV2ResourceBundleSource[] = [];
|
|
862
|
+
for (const descriptor of descriptors) {
|
|
863
|
+
const artifact = artifactByName.get(descriptor.name);
|
|
864
|
+
if (!artifact) {
|
|
865
|
+
throw ERRORS.TypedError(
|
|
866
|
+
HardwareErrorCode.RuntimeError,
|
|
867
|
+
`Protocol V2 resource bundle ${descriptor.name} is not prepared`,
|
|
868
|
+
{
|
|
869
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
870
|
+
artifactName: descriptor.name,
|
|
871
|
+
}
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
const devicePath = validateProtocolV2FilesystemPath(
|
|
875
|
+
descriptor.devicePath,
|
|
876
|
+
'resourceBundles[].devicePath'
|
|
877
|
+
);
|
|
878
|
+
sources.push({
|
|
879
|
+
name: descriptor.name,
|
|
880
|
+
source: await this.openProtocolV2PreparedSource(artifact),
|
|
881
|
+
devicePath,
|
|
882
|
+
version: descriptor.version,
|
|
883
|
+
payloadHash: descriptor.payloadHash,
|
|
884
|
+
headerHash: descriptor.headerHash,
|
|
885
|
+
});
|
|
886
|
+
artifactByName.delete(descriptor.name);
|
|
887
|
+
}
|
|
888
|
+
if (artifactByName.size > 0) {
|
|
889
|
+
throw ERRORS.TypedError(
|
|
890
|
+
HardwareErrorCode.RuntimeError,
|
|
891
|
+
`Protocol V2 release does not contain resource bundle ${artifactByName.keys().next().value}`
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
return sources;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
private async runProtocolV2PreparedArtifacts(features: Features, firmwareType: EFirmwareType) {
|
|
898
|
+
try {
|
|
899
|
+
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
900
|
+
const installSources = await this.prepareProtocolV2InstallSources(firmwareType, features);
|
|
901
|
+
const explicitResourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
|
|
902
|
+
const resourceSources = explicitResourceBundles?.length
|
|
903
|
+
? await Promise.all(
|
|
904
|
+
explicitResourceBundles.map(async bundle => ({
|
|
905
|
+
name: bundle.name,
|
|
906
|
+
source: await this.openProtocolV2MemorySource(bundle.binary),
|
|
907
|
+
devicePath: bundle.devicePath,
|
|
908
|
+
version: bundle.version,
|
|
909
|
+
payloadHash: bundle.payloadHash,
|
|
910
|
+
headerHash: bundle.headerHash,
|
|
911
|
+
}))
|
|
912
|
+
)
|
|
913
|
+
: await this.prepareProtocolV2ResourceSources(firmwareType, features);
|
|
914
|
+
if (installSources.length === 0 && resourceSources.length === 0) {
|
|
915
|
+
throw ERRORS.TypedError(
|
|
916
|
+
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
917
|
+
'No firmware to update'
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
921
|
+
|
|
922
|
+
return await this.executeProtocolV2SourceUpdate({
|
|
923
|
+
installSources,
|
|
924
|
+
resourceSources,
|
|
925
|
+
});
|
|
926
|
+
} finally {
|
|
927
|
+
await this.closeProtocolV2PreparedSources();
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
private validateExpectedTargetVersions() {
|
|
932
|
+
const expected = this.params.expectedTargetVersions;
|
|
933
|
+
if (expected === undefined) return;
|
|
934
|
+
if (typeof expected !== 'object' || expected === null || Array.isArray(expected)) {
|
|
935
|
+
throw ERRORS.TypedError(
|
|
936
|
+
HardwareErrorCode.RuntimeError,
|
|
937
|
+
'Protocol V2 expected target versions are invalid'
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
for (const [target, version] of Object.entries(expected)) {
|
|
941
|
+
if (
|
|
942
|
+
!Array.from(PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.values()).includes(
|
|
943
|
+
target as FirmwareUpdateV4Target
|
|
944
|
+
) ||
|
|
945
|
+
typeof version !== 'string' ||
|
|
946
|
+
!/^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/u.test(version) ||
|
|
947
|
+
version.length > 64
|
|
948
|
+
) {
|
|
949
|
+
throw ERRORS.TypedError(
|
|
950
|
+
HardwareErrorCode.RuntimeError,
|
|
951
|
+
'Protocol V2 expected target version is invalid'
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
private getExpectedProtocolV2TargetVersion(targetId: number) {
|
|
958
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(targetId);
|
|
959
|
+
const version = target ? this.params?.expectedTargetVersions?.[target] : undefined;
|
|
960
|
+
if (!version) return undefined;
|
|
961
|
+
const parts = version.split(/[+-]/u, 1)[0].split('.').map(Number);
|
|
962
|
+
if (
|
|
963
|
+
parts.length !== 3 ||
|
|
964
|
+
parts.some(part => !Number.isSafeInteger(part) || part < 0 || part > 0xff)
|
|
965
|
+
) {
|
|
966
|
+
return undefined;
|
|
967
|
+
}
|
|
968
|
+
return parts[0] * 0x10000 + parts[1] * 0x100 + parts[2];
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
private assertExpectedProtocolV2Versions(targets?: readonly FirmwareUpdateV4Target[]) {
|
|
972
|
+
const expected = this.params?.expectedTargetVersions;
|
|
973
|
+
if (!expected) return;
|
|
974
|
+
const features = this.protocolV2LatestFinalFeatures;
|
|
975
|
+
const requestedTargets = this.getProtocolV2RequestedTargets();
|
|
976
|
+
const applicationTargets = requestedTargets.filter(
|
|
977
|
+
target => target === 'app_v1' || target === 'app_v2'
|
|
978
|
+
);
|
|
979
|
+
const visibleVersions: Partial<Record<FirmwareUpdateV4Target, string>> = {
|
|
980
|
+
boot: features ? getDeviceBootloaderVersion(features).join('.') : undefined,
|
|
981
|
+
coprocessor: features ? getDeviceBLEFirmwareVersion(features).join('.') : undefined,
|
|
982
|
+
se01: features?.se01Version ?? undefined,
|
|
983
|
+
se02: features?.se02Version ?? undefined,
|
|
984
|
+
se03: features?.se03Version ?? undefined,
|
|
985
|
+
se04: features?.se04Version ?? undefined,
|
|
986
|
+
};
|
|
987
|
+
if (features && applicationTargets.length === 1) {
|
|
988
|
+
visibleVersions[applicationTargets[0]] = getDeviceFirmwareVersion(features).join('.');
|
|
989
|
+
}
|
|
990
|
+
const expectedEntries = (
|
|
991
|
+
Object.entries(expected) as Array<[FirmwareUpdateV4Target, string]>
|
|
992
|
+
).filter(([target]) => !targets || targets.includes(target));
|
|
993
|
+
for (const [target, expectedVersion] of expectedEntries) {
|
|
994
|
+
const targetId = Array.from(PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.entries()).find(
|
|
995
|
+
([, mappedTarget]) => mappedTarget === target
|
|
996
|
+
)?.[0];
|
|
997
|
+
const statusVersion =
|
|
998
|
+
targetId === undefined ? undefined : this.protocolV2CompletedTargetVersions.get(targetId);
|
|
999
|
+
const observedVersion =
|
|
1000
|
+
statusVersion === undefined
|
|
1001
|
+
? visibleVersions[target]
|
|
1002
|
+
: `${Math.floor(statusVersion / 0x10000) % 0x100}.${
|
|
1003
|
+
Math.floor(statusVersion / 0x100) % 0x100
|
|
1004
|
+
}.${statusVersion % 0x100}`;
|
|
1005
|
+
if (!observedVersion) {
|
|
1006
|
+
if (this.protocolV2FinalStatusVerified) {
|
|
1007
|
+
Log.warn(
|
|
1008
|
+
`Protocol V2 target ${target} has no observable final version; completed target status is authoritative`
|
|
1009
|
+
);
|
|
1010
|
+
} else {
|
|
1011
|
+
throw ERRORS.TypedError(
|
|
1012
|
+
HardwareErrorCode.FirmwareVerificationFailed,
|
|
1013
|
+
`Protocol V2 target ${target} has no observable final version after status fallback`
|
|
1014
|
+
);
|
|
1015
|
+
}
|
|
1016
|
+
} else if (observedVersion !== expectedVersion) {
|
|
1017
|
+
throw ERRORS.TypedError(
|
|
1018
|
+
HardwareErrorCode.FirmwareVerificationFailed,
|
|
1019
|
+
`Protocol V2 target ${target} reached ${observedVersion}, expected ${expectedVersion}`
|
|
1020
|
+
);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
private getProtocolV2RequestedTargets(): FirmwareUpdateV4Target[] {
|
|
1026
|
+
if (this.params.targetsToUpdate?.length) {
|
|
1027
|
+
return [...new Set(this.params.targetsToUpdate)];
|
|
1028
|
+
}
|
|
1029
|
+
const targets = new Set<FirmwareUpdateV4Target>();
|
|
1030
|
+
Object.keys(this.params.componentArtifacts ?? {}).forEach(target =>
|
|
1031
|
+
targets.add(target as FirmwareUpdateV4Target)
|
|
1032
|
+
);
|
|
1033
|
+
if (this.params.resourceBundleArtifacts?.length || this.params.resourceFiles?.length) {
|
|
1034
|
+
targets.add('resource');
|
|
1035
|
+
}
|
|
1036
|
+
if (this.params.bootloaderBinary) targets.add('boot');
|
|
1037
|
+
if (this.params.applicationP1Binary) targets.add('app_v1');
|
|
1038
|
+
if (this.params.applicationP2Binary) targets.add('app_v2');
|
|
1039
|
+
if (this.params.coprocessorBinary) targets.add('coprocessor');
|
|
1040
|
+
if (this.params.se01Binary) targets.add('se01');
|
|
1041
|
+
if (this.params.se02Binary) targets.add('se02');
|
|
1042
|
+
if (this.params.se03Binary) targets.add('se03');
|
|
1043
|
+
if (this.params.se04Binary) targets.add('se04');
|
|
1044
|
+
return Array.from(targets);
|
|
509
1045
|
}
|
|
510
1046
|
|
|
511
1047
|
private async getProtocolV2DeviceFeatures(): Promise<Features> {
|
|
@@ -519,41 +1055,55 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
519
1055
|
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Device features not available');
|
|
520
1056
|
}
|
|
521
1057
|
|
|
522
|
-
private
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
throw ERRORS.TypedError(
|
|
527
|
-
HardwareErrorCode.CallMethodInvalidParameter,
|
|
528
|
-
`Parameter [resourceBinaries.${index}] is of type invalid and should be [buffer].`
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
|
-
});
|
|
1058
|
+
private getProtocolV2SerialNumber(deviceInfo: ProtocolV2DeviceInfo) {
|
|
1059
|
+
const serialNumber = deviceInfo.hw?.serial_no?.trim();
|
|
1060
|
+
return serialNumber || undefined;
|
|
1061
|
+
}
|
|
532
1062
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
1063
|
+
private assertProtocolV2DeviceInfoIdentity(deviceInfo: ProtocolV2DeviceInfo) {
|
|
1064
|
+
assertProtocolV2ReconnectIdentity(
|
|
1065
|
+
this.protocolV2ExpectedSerialNumber,
|
|
1066
|
+
this.getProtocolV2SerialNumber(deviceInfo),
|
|
1067
|
+
this.protocolV2ExpectedPath,
|
|
1068
|
+
this.device.originalDescriptor.path
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
private getProtocolV2DeviceInfoTimeout() {
|
|
1073
|
+
return this.isBleReconnect()
|
|
1074
|
+
? this.payload.protocolV2DeviceInfoTimeoutMs ?? PROTOCOL_V2_DEVICE_INFO_READY_TIMEOUT
|
|
1075
|
+
: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
private async requestProtocolV2PhysicalIdentity() {
|
|
1079
|
+
return requestProtocolV2DeviceInfo({
|
|
1080
|
+
commands: this.device.getCommands(),
|
|
1081
|
+
timeoutMs: this.getProtocolV2DeviceInfoTimeout(),
|
|
543
1082
|
});
|
|
1083
|
+
}
|
|
544
1084
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
1085
|
+
private async captureProtocolV2PhysicalIdentity() {
|
|
1086
|
+
const deviceInfo = await this.requestProtocolV2PhysicalIdentity();
|
|
1087
|
+
const serialNumber = this.getProtocolV2SerialNumber(deviceInfo);
|
|
1088
|
+
const path = this.device.originalDescriptor?.path?.trim() || undefined;
|
|
1089
|
+
if (this.params?.preparedPlan) {
|
|
1090
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
1091
|
+
preparedPlan: this.params.preparedPlan,
|
|
1092
|
+
deviceIdentity: serialNumber,
|
|
1093
|
+
});
|
|
1094
|
+
} else if (this.params?.expectedDeviceId) {
|
|
1095
|
+
assertProtocolV2ReconnectIdentity(this.params?.expectedDeviceId, serialNumber);
|
|
1096
|
+
} else {
|
|
1097
|
+
assertProtocolV2ReconnectIdentity(serialNumber, serialNumber, path, path);
|
|
554
1098
|
}
|
|
555
|
-
|
|
556
|
-
|
|
1099
|
+
this.protocolV2ExpectedSerialNumber = serialNumber;
|
|
1100
|
+
this.protocolV2ExpectedPath = path;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
private async verifyProtocolV2ReconnectIdentity() {
|
|
1104
|
+
const deviceInfo = await this.requestProtocolV2PhysicalIdentity();
|
|
1105
|
+
this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
|
|
1106
|
+
return deviceInfo;
|
|
557
1107
|
}
|
|
558
1108
|
|
|
559
1109
|
private prepareBootloaderBinary(): ArrayBuffer | null {
|
|
@@ -562,25 +1112,20 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
562
1112
|
|
|
563
1113
|
private hasExplicitProtocolV2Payload(fwBinaryMap: ProtocolV2TargetBinary[]) {
|
|
564
1114
|
return (
|
|
565
|
-
!!this.params.
|
|
1115
|
+
!!this.params.resourceFiles?.length ||
|
|
566
1116
|
!!this.params.bootloaderBinary ||
|
|
567
1117
|
fwBinaryMap.length > 0
|
|
568
1118
|
);
|
|
569
1119
|
}
|
|
570
1120
|
|
|
571
1121
|
private buildProtocolV2InstallItems({
|
|
572
|
-
resourceBinaryMap,
|
|
573
1122
|
bootloaderBinary,
|
|
574
1123
|
fwBinaryMap,
|
|
575
1124
|
}: {
|
|
576
|
-
resourceBinaryMap: ProtocolV2TargetBinary[];
|
|
577
1125
|
bootloaderBinary: ArrayBuffer | null;
|
|
578
1126
|
fwBinaryMap: ProtocolV2TargetBinary[];
|
|
579
1127
|
}): ProtocolV2InstallItem[] {
|
|
580
|
-
const installItems: ProtocolV2InstallItem[] =
|
|
581
|
-
...resource,
|
|
582
|
-
kind: 'resource',
|
|
583
|
-
}));
|
|
1128
|
+
const installItems: ProtocolV2InstallItem[] = [];
|
|
584
1129
|
|
|
585
1130
|
if (bootloaderBinary) {
|
|
586
1131
|
installItems.push({
|
|
@@ -630,64 +1175,137 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
630
1175
|
return target;
|
|
631
1176
|
}
|
|
632
1177
|
|
|
633
|
-
private
|
|
634
|
-
|
|
635
|
-
component: IProtocolV2FirmwareComponent
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
if (component.
|
|
639
|
-
|
|
640
|
-
|
|
1178
|
+
private async downloadRemoteProtocolV2Component(
|
|
1179
|
+
key: string,
|
|
1180
|
+
component: IProtocolV2FirmwareComponent
|
|
1181
|
+
): Promise<ProtocolV2RemoteComponentBinary> {
|
|
1182
|
+
const target = this.getRemoteComponentTarget(key, component);
|
|
1183
|
+
if (!component.url) {
|
|
1184
|
+
throw ERRORS.TypedError(
|
|
1185
|
+
HardwareErrorCode.RuntimeError,
|
|
1186
|
+
`Missing Protocol V2 firmware component url: ${key}/${component.target}`
|
|
1187
|
+
);
|
|
641
1188
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
1189
|
+
|
|
1190
|
+
const { binary } = await getSysResourceBinary(component.url);
|
|
1191
|
+
if (!isProtocolV2FirmwareFingerprintValid(binary, component.fingerprint)) {
|
|
1192
|
+
throw ERRORS.TypedError(
|
|
1193
|
+
HardwareErrorCode.RuntimeError,
|
|
1194
|
+
`Protocol V2 firmware fingerprint mismatch: ${key}/${component.target}`
|
|
1195
|
+
);
|
|
647
1196
|
}
|
|
648
|
-
|
|
1197
|
+
const expectedPayloadHash = normalizeProtocolV2Hex(component.payloadHash);
|
|
1198
|
+
if (expectedPayloadHash) {
|
|
1199
|
+
const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(binary));
|
|
1200
|
+
if (!header || header.payloadHash !== expectedPayloadHash) {
|
|
1201
|
+
throw ERRORS.TypedError(
|
|
1202
|
+
HardwareErrorCode.RuntimeError,
|
|
1203
|
+
`Protocol V2 firmware payload hash mismatch: ${key}/${component.target}`
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
return {
|
|
1208
|
+
...target,
|
|
1209
|
+
binary,
|
|
1210
|
+
};
|
|
649
1211
|
}
|
|
650
1212
|
|
|
651
|
-
private
|
|
652
|
-
features
|
|
653
|
-
target: ProtocolV2RemoteComponentTarget
|
|
654
|
-
) {
|
|
655
|
-
switch (target.targetId) {
|
|
656
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER:
|
|
657
|
-
return getDeviceBootloaderVersion(features);
|
|
658
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1:
|
|
659
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2:
|
|
660
|
-
return getDeviceFirmwareVersion(features);
|
|
661
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR:
|
|
662
|
-
return getDeviceBLEFirmwareVersion(features);
|
|
663
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01:
|
|
664
|
-
return versionStringToArray(features.se01Version);
|
|
665
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02:
|
|
666
|
-
return versionStringToArray(features.se02Version);
|
|
667
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03:
|
|
668
|
-
return versionStringToArray(features.se03Version);
|
|
669
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04:
|
|
670
|
-
return versionStringToArray(features.se04Version);
|
|
671
|
-
default:
|
|
672
|
-
return undefined;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
private isProtocolV2ComponentVersionSatisfied(
|
|
677
|
-
release: IFirmwareReleaseInfo,
|
|
678
|
-
component: IProtocolV2FirmwareComponent,
|
|
679
|
-
target: ProtocolV2RemoteComponentTarget,
|
|
680
|
-
features: Features
|
|
681
|
-
) {
|
|
682
|
-
const targetVersion = this.getProtocolV2ComponentTargetVersion(release, component, target);
|
|
683
|
-
if (!targetVersion) return false;
|
|
684
|
-
|
|
685
|
-
const currentVersion = this.getProtocolV2ComponentCurrentVersion(features, target);
|
|
686
|
-
const compareResult = compareProtocolV2Versions(currentVersion, targetVersion);
|
|
687
|
-
return compareResult !== undefined && compareResult >= 0;
|
|
688
|
-
}
|
|
1213
|
+
private async prepareRemoteProtocolV2Binaries(firmwareType: EFirmwareType, features: Features) {
|
|
1214
|
+
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
689
1215
|
|
|
690
|
-
|
|
1216
|
+
let bootloaderBinary: ArrayBuffer | null = null;
|
|
1217
|
+
const fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
1218
|
+
const installItems: ProtocolV2InstallItem[] = [];
|
|
1219
|
+
|
|
1220
|
+
if (!release) {
|
|
1221
|
+
return {
|
|
1222
|
+
bootloaderBinary,
|
|
1223
|
+
fwBinaryMap,
|
|
1224
|
+
installItems,
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
const entries = this.getRemoteComponentEntries(release);
|
|
1229
|
+
const targetsToUpdate = new Set(this.params.targetsToUpdate ?? []);
|
|
1230
|
+
|
|
1231
|
+
for (const [key, component] of entries) {
|
|
1232
|
+
const targetName = component.target?.toUpperCase();
|
|
1233
|
+
const target = PROTOCOL_V2_REMOTE_COMPONENT_TARGETS[targetName];
|
|
1234
|
+
const updateTarget = target
|
|
1235
|
+
? PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId)
|
|
1236
|
+
: undefined;
|
|
1237
|
+
if (updateTarget && targetsToUpdate.has(updateTarget)) {
|
|
1238
|
+
const remoteBinary = await this.downloadRemoteProtocolV2Component(key, component);
|
|
1239
|
+
if (remoteBinary.kind === 'bootloader') {
|
|
1240
|
+
bootloaderBinary = remoteBinary.binary;
|
|
1241
|
+
installItems.push({
|
|
1242
|
+
fileName: remoteBinary.fileName,
|
|
1243
|
+
binary: remoteBinary.binary,
|
|
1244
|
+
targetId: remoteBinary.targetId,
|
|
1245
|
+
kind: remoteBinary.kind,
|
|
1246
|
+
});
|
|
1247
|
+
} else {
|
|
1248
|
+
const binaryEntry = {
|
|
1249
|
+
fileName: remoteBinary.fileName,
|
|
1250
|
+
binary: remoteBinary.binary,
|
|
1251
|
+
targetId: remoteBinary.targetId,
|
|
1252
|
+
};
|
|
1253
|
+
fwBinaryMap.push(binaryEntry);
|
|
1254
|
+
installItems.push({ ...binaryEntry, kind: remoteBinary.kind });
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
return {
|
|
1260
|
+
bootloaderBinary,
|
|
1261
|
+
fwBinaryMap,
|
|
1262
|
+
installItems,
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
private prepareExplicitProtocolV2ResourceFiles(): ProtocolV2ResourceBundleBinary[] | undefined {
|
|
1267
|
+
const files = this.params.resourceFiles ?? [];
|
|
1268
|
+
if (!files?.length) return undefined;
|
|
1269
|
+
|
|
1270
|
+
const prepared = files.map((file, index) => {
|
|
1271
|
+
const devicePath = validateProtocolV2FilesystemPath(
|
|
1272
|
+
file.devicePath,
|
|
1273
|
+
`resourceFiles[${index}].devicePath`
|
|
1274
|
+
);
|
|
1275
|
+
const descriptor = file as typeof file & Partial<{ size: number; fileHash: string }>;
|
|
1276
|
+
if (descriptor.size !== undefined && descriptor.size !== file.binary.byteLength) {
|
|
1277
|
+
throw new Error(`resourceFiles[${index}] size mismatch`);
|
|
1278
|
+
}
|
|
1279
|
+
if (
|
|
1280
|
+
descriptor.fileHash &&
|
|
1281
|
+
!isProtocolV2ResourceFileValid(file.binary, {
|
|
1282
|
+
size: file.binary.byteLength,
|
|
1283
|
+
fileHash: descriptor.fileHash,
|
|
1284
|
+
})
|
|
1285
|
+
) {
|
|
1286
|
+
throw new Error(`resourceFiles[${index}] SHA-256 mismatch`);
|
|
1287
|
+
}
|
|
1288
|
+
const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(file.binary));
|
|
1289
|
+
return {
|
|
1290
|
+
name: devicePath.split('/').pop() ?? devicePath,
|
|
1291
|
+
binary: file.binary,
|
|
1292
|
+
devicePath,
|
|
1293
|
+
...(header
|
|
1294
|
+
? {
|
|
1295
|
+
version: header.version,
|
|
1296
|
+
payloadHash: header.payloadHash,
|
|
1297
|
+
headerHash: header.headerHash,
|
|
1298
|
+
}
|
|
1299
|
+
: {}),
|
|
1300
|
+
};
|
|
1301
|
+
});
|
|
1302
|
+
if (new Set(prepared.map(file => file.devicePath)).size !== prepared.length) {
|
|
1303
|
+
throw new Error('resourceFiles contain duplicate devicePath values');
|
|
1304
|
+
}
|
|
1305
|
+
return prepared;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
private getProtocolV2ResourceFilePath(path: string) {
|
|
691
1309
|
if (path.startsWith('vol')) return path;
|
|
692
1310
|
if (path.startsWith('/')) return `vol0:${path}`;
|
|
693
1311
|
return `vol0:/${path}`;
|
|
@@ -709,7 +1327,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
709
1327
|
return null;
|
|
710
1328
|
}
|
|
711
1329
|
|
|
712
|
-
const chunkSize = this.getProtocolV2FirmwareChunkSize();
|
|
1330
|
+
const chunkSize = this.getProtocolV2FirmwareChunkSize('read');
|
|
713
1331
|
const chunks: Uint8Array[] = [];
|
|
714
1332
|
let offset = 0;
|
|
715
1333
|
while (offset < PROTOCOL_V2_OKPP_HEADER_SIZE) {
|
|
@@ -738,202 +1356,81 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
738
1356
|
return parseProtocolV2OkppHeader(headerBytes);
|
|
739
1357
|
}
|
|
740
1358
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
1359
|
+
/** Compare the downloaded and installed okpkg headers before transferring a resource. */
|
|
1360
|
+
private async isProtocolV2ResourceBundleUpToDate(
|
|
1361
|
+
bundle: Pick<
|
|
1362
|
+
ProtocolV2ResourceBundleSource,
|
|
1363
|
+
'name' | 'devicePath' | 'version' | 'payloadHash' | 'headerHash'
|
|
1364
|
+
>
|
|
1365
|
+
): Promise<boolean> {
|
|
1366
|
+
if (this.params?.forcedUpdateRes) return false;
|
|
1367
|
+
if (!bundle.payloadHash || !bundle.headerHash) return false;
|
|
1368
|
+
|
|
745
1369
|
try {
|
|
746
|
-
const header = await this.readProtocolV2DeviceFileHeader(
|
|
1370
|
+
const header = await this.readProtocolV2DeviceFileHeader(bundle.devicePath);
|
|
747
1371
|
if (!header) return false;
|
|
748
1372
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
if (expectedVersion && compareProtocolV2Versions(header.version, expectedVersion) !== 0) {
|
|
753
|
-
return false;
|
|
1373
|
+
if (bundle.version) {
|
|
1374
|
+
const cmp = compareProtocolV2Versions(header.version, bundle.version);
|
|
1375
|
+
if (cmp === undefined || cmp !== 0) return false;
|
|
754
1376
|
}
|
|
755
|
-
|
|
756
|
-
const
|
|
757
|
-
if (expectedPayloadHash
|
|
758
|
-
|
|
759
|
-
const expectedHeaderHash = normalizeProtocolV2Hex(pkg.headerHash);
|
|
760
|
-
if (expectedHeaderHash && header.headerHash !== expectedHeaderHash) return false;
|
|
761
|
-
|
|
1377
|
+
const expectedPayloadHash = normalizeProtocolV2Hex(bundle.payloadHash);
|
|
1378
|
+
const expectedHeaderHash = normalizeProtocolV2Hex(bundle.headerHash);
|
|
1379
|
+
if (!expectedPayloadHash || header.payloadHash !== expectedPayloadHash) return false;
|
|
1380
|
+
if (!expectedHeaderHash || header.headerHash !== expectedHeaderHash) return false;
|
|
762
1381
|
return true;
|
|
763
1382
|
} catch (error) {
|
|
764
|
-
Log.log(`
|
|
1383
|
+
Log.log(`[FirmwareUpdateV4] RESC bundle ${bundle.name} header check failed: `, error);
|
|
765
1384
|
return false;
|
|
766
1385
|
}
|
|
767
1386
|
}
|
|
768
1387
|
|
|
769
|
-
private
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
if (!manifest?.packages?.length) return false;
|
|
773
|
-
|
|
774
|
-
for (const pkg of manifest.packages) {
|
|
775
|
-
if (!(await this.isProtocolV2ResourcePackageMatched(pkg, manifest.version))) {
|
|
776
|
-
return false;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
return true;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
private getProtocolV2ResourceManifest(
|
|
783
|
-
release: IFirmwareReleaseInfo,
|
|
784
|
-
component: IProtocolV2FirmwareComponent
|
|
785
|
-
) {
|
|
786
|
-
return component.resourceManifest ?? release.resourceManifest;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
private getProtocolV2ResourceComponentFileName(key: string) {
|
|
790
|
-
const safeKey = key.replace(/[^a-z0-9_-]/gi, '_') || 'resource';
|
|
791
|
-
if (safeKey === 'resource') {
|
|
792
|
-
return PROTOCOL_V2_REMOTE_COMPONENT_TARGETS.CRATE.fileName;
|
|
793
|
-
}
|
|
794
|
-
return `resource-${safeKey}.bin`;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
private async shouldInstallRemoteProtocolV2Component(
|
|
798
|
-
release: IFirmwareReleaseInfo,
|
|
799
|
-
key: string,
|
|
800
|
-
component: IProtocolV2FirmwareComponent,
|
|
801
|
-
target: ProtocolV2RemoteComponentTarget,
|
|
802
|
-
features: Features
|
|
803
|
-
) {
|
|
804
|
-
if (target.kind === 'resource') {
|
|
805
|
-
if (
|
|
806
|
-
this.params.forcedUpdateRes ||
|
|
807
|
-
features.bootloaderMode ||
|
|
808
|
-
features.mode === 'bootloader'
|
|
809
|
-
) {
|
|
810
|
-
return true;
|
|
811
|
-
}
|
|
812
|
-
const resourceMatched = await this.isProtocolV2ResourceManifestSatisfied(
|
|
813
|
-
this.getProtocolV2ResourceManifest(release, component)
|
|
814
|
-
);
|
|
815
|
-
if (resourceMatched) {
|
|
816
|
-
Log.log(`[FirmwareUpdateV4] skip Protocol V2 resource component ${key}; manifest matched`);
|
|
817
|
-
}
|
|
818
|
-
return !resourceMatched;
|
|
1388
|
+
private isProtocolV2BootloaderMode() {
|
|
1389
|
+
if (typeof this.device.isBootloader === 'function') {
|
|
1390
|
+
return !!this.device.isBootloader();
|
|
819
1391
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
component,
|
|
824
|
-
target,
|
|
825
|
-
features
|
|
1392
|
+
return (
|
|
1393
|
+
this.device.features?.mode === 'bootloader' ||
|
|
1394
|
+
(this.device.features?.mode == null && !!this.device.features?.bootloaderMode)
|
|
826
1395
|
);
|
|
827
|
-
if (versionSatisfied) {
|
|
828
|
-
Log.log(`[FirmwareUpdateV4] skip Protocol V2 component ${key}; version is up to date`);
|
|
829
|
-
}
|
|
830
|
-
return !versionSatisfied;
|
|
831
1396
|
}
|
|
832
1397
|
|
|
833
|
-
private
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
HardwareErrorCode.RuntimeError,
|
|
841
|
-
`Missing Protocol V2 firmware component url: ${key}/${component.target}`
|
|
842
|
-
);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
const { binary } = await getSysResourceBinary(component.url);
|
|
846
|
-
return {
|
|
847
|
-
...target,
|
|
848
|
-
binary,
|
|
849
|
-
};
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
private async prepareRemoteProtocolV2Binaries(firmwareType: EFirmwareType, features: Features) {
|
|
853
|
-
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
854
|
-
|
|
855
|
-
const resourceBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
856
|
-
let bootloaderBinary: ArrayBuffer | null = null;
|
|
857
|
-
const fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
858
|
-
const installItems: ProtocolV2InstallItem[] = [];
|
|
859
|
-
|
|
860
|
-
if (!release) {
|
|
861
|
-
return {
|
|
862
|
-
resourceBinaryMap,
|
|
863
|
-
bootloaderBinary,
|
|
864
|
-
fwBinaryMap,
|
|
865
|
-
installItems,
|
|
866
|
-
};
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
const entries = this.getRemoteComponentEntries(release);
|
|
870
|
-
|
|
871
|
-
for (const [key, component] of entries) {
|
|
872
|
-
const target = this.getRemoteComponentTarget(key, component);
|
|
873
|
-
const shouldInstall = await this.shouldInstallRemoteProtocolV2Component(
|
|
874
|
-
release,
|
|
875
|
-
key,
|
|
876
|
-
component,
|
|
877
|
-
target,
|
|
878
|
-
features
|
|
879
|
-
);
|
|
880
|
-
if (shouldInstall) {
|
|
881
|
-
const remoteBinary = await this.downloadRemoteProtocolV2Component(key, component);
|
|
882
|
-
if (remoteBinary.kind === 'resource') {
|
|
883
|
-
const binaryEntry = {
|
|
884
|
-
fileName: this.getProtocolV2ResourceComponentFileName(key),
|
|
885
|
-
binary: remoteBinary.binary,
|
|
886
|
-
targetId: remoteBinary.targetId,
|
|
887
|
-
};
|
|
888
|
-
resourceBinaryMap.push(binaryEntry);
|
|
889
|
-
installItems.push({ ...binaryEntry, kind: remoteBinary.kind });
|
|
890
|
-
} else if (remoteBinary.kind === 'bootloader') {
|
|
891
|
-
bootloaderBinary = remoteBinary.binary;
|
|
892
|
-
installItems.push({
|
|
893
|
-
fileName: remoteBinary.fileName,
|
|
894
|
-
binary: remoteBinary.binary,
|
|
895
|
-
targetId: remoteBinary.targetId,
|
|
896
|
-
kind: remoteBinary.kind,
|
|
897
|
-
});
|
|
898
|
-
} else {
|
|
899
|
-
const binaryEntry = {
|
|
900
|
-
fileName: remoteBinary.fileName,
|
|
901
|
-
binary: remoteBinary.binary,
|
|
902
|
-
targetId: remoteBinary.targetId,
|
|
903
|
-
};
|
|
904
|
-
fwBinaryMap.push(binaryEntry);
|
|
905
|
-
installItems.push({ ...binaryEntry, kind: remoteBinary.kind });
|
|
906
|
-
}
|
|
907
|
-
}
|
|
1398
|
+
private isProtocolV2RomloaderMode() {
|
|
1399
|
+
const deviceType = this.device.getCurrentDeviceType();
|
|
1400
|
+
if (
|
|
1401
|
+
!this.device.isProtocolV2() ||
|
|
1402
|
+
(deviceType !== EDeviceType.Pro2 && deviceType !== EDeviceType.Neo)
|
|
1403
|
+
) {
|
|
1404
|
+
return false;
|
|
908
1405
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
resourceBinaryMap,
|
|
912
|
-
bootloaderBinary,
|
|
913
|
-
fwBinaryMap,
|
|
914
|
-
installItems,
|
|
915
|
-
};
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
private isProtocolV2BootloaderMode() {
|
|
919
|
-
if (typeof this.device.isBootloader === 'function') {
|
|
920
|
-
return this.device.isBootloader();
|
|
1406
|
+
if (typeof this.device.isRomloader === 'function') {
|
|
1407
|
+
return this.device.isRomloader();
|
|
921
1408
|
}
|
|
922
|
-
return
|
|
1409
|
+
return this.device.features?.mode === 'romloader';
|
|
923
1410
|
}
|
|
924
1411
|
|
|
925
1412
|
async enterProtocolV2BootloaderMode() {
|
|
1413
|
+
// romloader is the first update environment and forwards targets to bootloader.
|
|
1414
|
+
// It rejects DeviceRebootType.Bootloader, so reuse the current connection.
|
|
1415
|
+
if (this.isProtocolV2RomloaderMode()) {
|
|
1416
|
+
Log.debug('Protocol V2 device is in romloader mode; start firmware update directly');
|
|
1417
|
+
this.protocolV2ExecutionInLoader = true;
|
|
1418
|
+
return false;
|
|
1419
|
+
}
|
|
926
1420
|
if (this.isProtocolV2BootloaderMode()) {
|
|
927
|
-
Log.debug('Protocol V2 device is already in bootloader mode, skip reboot
|
|
1421
|
+
Log.debug('Protocol V2 device is already in bootloader mode, skip reboot');
|
|
1422
|
+
this.protocolV2ExecutionInLoader = true;
|
|
1423
|
+
this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
|
|
928
1424
|
return false;
|
|
929
1425
|
}
|
|
930
1426
|
|
|
931
1427
|
try {
|
|
932
1428
|
this.postTipMessage(FirmwareUpdateTipMessage.AutoRebootToBootloader);
|
|
933
1429
|
await this.protocolV2Reboot(DeviceRebootType.Bootloader);
|
|
934
|
-
this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
|
|
935
1430
|
await wait(1000);
|
|
936
1431
|
await this.waitForProtocolV2BootloaderMode();
|
|
1432
|
+
this.protocolV2ExecutionInLoader = true;
|
|
1433
|
+
this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
|
|
937
1434
|
return true;
|
|
938
1435
|
} catch (error) {
|
|
939
1436
|
if (error instanceof HardwareError) {
|
|
@@ -950,20 +1447,32 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
950
1447
|
) {
|
|
951
1448
|
const startTime = Date.now();
|
|
952
1449
|
let lastError: unknown;
|
|
1450
|
+
let shouldReconnect = true;
|
|
953
1451
|
|
|
954
1452
|
while (Date.now() - startTime < timeout) {
|
|
955
1453
|
try {
|
|
956
|
-
|
|
1454
|
+
if (shouldReconnect) {
|
|
1455
|
+
await this.reconnectProtocolV2Device();
|
|
1456
|
+
shouldReconnect = false;
|
|
1457
|
+
}
|
|
957
1458
|
const deviceInfo = await requestProtocolV2DeviceInfo({
|
|
958
1459
|
commands: this.device.getCommands(),
|
|
959
|
-
timeoutMs:
|
|
1460
|
+
timeoutMs: this.getProtocolV2DeviceInfoTimeout(),
|
|
960
1461
|
});
|
|
961
|
-
|
|
962
|
-
|
|
1462
|
+
this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
|
|
1463
|
+
const features = await this.device.probeProtocolV2RuntimeState(
|
|
1464
|
+
deviceInfo,
|
|
1465
|
+
PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
|
|
1466
|
+
);
|
|
1467
|
+
if (features?.mode === 'bootloader') {
|
|
963
1468
|
return features;
|
|
964
1469
|
}
|
|
965
1470
|
lastError = new Error('Protocol V2 device is reachable but is not in bootloader mode');
|
|
966
1471
|
} catch (error) {
|
|
1472
|
+
if (this.isProtocolV2ReconnectIdentityError(error)) {
|
|
1473
|
+
throw error;
|
|
1474
|
+
}
|
|
1475
|
+
shouldReconnect = true;
|
|
967
1476
|
lastError = error;
|
|
968
1477
|
Log.log('Protocol V2 bootloader mode not ready, polling reconnect: ', error);
|
|
969
1478
|
}
|
|
@@ -979,8 +1488,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
979
1488
|
}
|
|
980
1489
|
|
|
981
1490
|
/**
|
|
982
|
-
*
|
|
983
|
-
*
|
|
1491
|
+
* Collect explicit target binaries grouped by DeviceFirmwareTargetType.
|
|
1492
|
+
* Filenames are display-only staging paths because target_id is explicit.
|
|
984
1493
|
*/
|
|
985
1494
|
private collectExplicitTargetBinaries() {
|
|
986
1495
|
const entries: ProtocolV2TargetBinary[] = [];
|
|
@@ -1016,261 +1525,602 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1016
1525
|
return entries;
|
|
1017
1526
|
}
|
|
1018
1527
|
|
|
1528
|
+
private buildProtocolV2ExecutionPhases({
|
|
1529
|
+
installSources,
|
|
1530
|
+
resourceSources,
|
|
1531
|
+
}: {
|
|
1532
|
+
installSources: ProtocolV2InstallSource[];
|
|
1533
|
+
resourceSources: ProtocolV2ResourceBundleSource[];
|
|
1534
|
+
}): ProtocolV2ExecutionPhase[] {
|
|
1535
|
+
const phases: ProtocolV2ExecutionPhase[] = [];
|
|
1536
|
+
const bootloaderSources = installSources.filter(source => source.kind === 'bootloader');
|
|
1537
|
+
if (bootloaderSources.length > 0) {
|
|
1538
|
+
phases.push(
|
|
1539
|
+
{
|
|
1540
|
+
kind: 'bootloader-install',
|
|
1541
|
+
installSources: bootloaderSources,
|
|
1542
|
+
resourceSources: [],
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
kind: 'bootloader-verify',
|
|
1546
|
+
installSources: [],
|
|
1547
|
+
resourceSources: [],
|
|
1548
|
+
}
|
|
1549
|
+
);
|
|
1550
|
+
}
|
|
1551
|
+
if (resourceSources.length > 0) {
|
|
1552
|
+
phases.push({
|
|
1553
|
+
kind: 'resource-sync',
|
|
1554
|
+
installSources: [],
|
|
1555
|
+
resourceSources,
|
|
1556
|
+
});
|
|
1557
|
+
}
|
|
1558
|
+
const componentSources = installSources.filter(source => source.kind !== 'bootloader');
|
|
1559
|
+
if (componentSources.length > 0) {
|
|
1560
|
+
phases.push({
|
|
1561
|
+
kind: 'component-install',
|
|
1562
|
+
installSources: componentSources,
|
|
1563
|
+
resourceSources: [],
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
phases.push({
|
|
1567
|
+
kind: 'final-verify',
|
|
1568
|
+
installSources: [],
|
|
1569
|
+
resourceSources: [],
|
|
1570
|
+
});
|
|
1571
|
+
return phases;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
private async executeProtocolV2Phases({
|
|
1575
|
+
installSources,
|
|
1576
|
+
resourceSources,
|
|
1577
|
+
}: {
|
|
1578
|
+
installSources: ProtocolV2InstallSource[];
|
|
1579
|
+
resourceSources: ProtocolV2ResourceBundleSource[];
|
|
1580
|
+
}) {
|
|
1581
|
+
const phases = this.buildProtocolV2ExecutionPhases({
|
|
1582
|
+
installSources,
|
|
1583
|
+
resourceSources,
|
|
1584
|
+
});
|
|
1585
|
+
for (const phase of phases) {
|
|
1586
|
+
if (phase.kind === 'final-verify') {
|
|
1587
|
+
return this.completeProtocolV2FinalVerification();
|
|
1588
|
+
}
|
|
1589
|
+
if (phase.kind === 'resource-sync') {
|
|
1590
|
+
await this.enterProtocolV2BootloaderMode();
|
|
1591
|
+
await this.executeProtocolV2TransferPhase(phase);
|
|
1592
|
+
} else if (phase.kind === 'bootloader-install' || phase.kind === 'component-install') {
|
|
1593
|
+
await this.enterProtocolV2BootloaderMode();
|
|
1594
|
+
await this.executeProtocolV2TransferPhase(phase);
|
|
1595
|
+
await this.exitProtocolV2BootloaderToNormal();
|
|
1596
|
+
} else if (phase.kind === 'bootloader-verify') {
|
|
1597
|
+
await this.waitForProtocolV2FinalFeatures();
|
|
1598
|
+
this.assertExpectedProtocolV2Versions(['boot']);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
throw ERRORS.TypedError(
|
|
1602
|
+
HardwareErrorCode.RuntimeError,
|
|
1603
|
+
'Protocol V2 execution has no final verification phase'
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
private async executeProtocolV2SourceUpdate({
|
|
1608
|
+
installSources,
|
|
1609
|
+
resourceSources,
|
|
1610
|
+
}: {
|
|
1611
|
+
installSources: ProtocolV2InstallSource[];
|
|
1612
|
+
resourceSources: ProtocolV2ResourceBundleSource[];
|
|
1613
|
+
}) {
|
|
1614
|
+
return this.executeProtocolV2Phases({
|
|
1615
|
+
installSources,
|
|
1616
|
+
resourceSources,
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1019
1620
|
private async executeProtocolV2Update({
|
|
1020
|
-
resourceBinaryMap,
|
|
1021
1621
|
fwBinaryMap,
|
|
1022
1622
|
bootloaderBinary,
|
|
1023
1623
|
installItems,
|
|
1624
|
+
resourceBundles,
|
|
1024
1625
|
}: {
|
|
1025
|
-
resourceBinaryMap?: ProtocolV2TargetBinary[];
|
|
1026
1626
|
fwBinaryMap?: ProtocolV2TargetBinary[];
|
|
1027
1627
|
bootloaderBinary?: ArrayBuffer | null;
|
|
1028
1628
|
installItems?: ProtocolV2InstallItem[];
|
|
1629
|
+
resourceBundles?: ProtocolV2ResourceBundleBinary[];
|
|
1029
1630
|
}) {
|
|
1030
|
-
const
|
|
1631
|
+
const memoryInstallItems =
|
|
1031
1632
|
installItems ??
|
|
1032
1633
|
this.buildProtocolV2InstallItems({
|
|
1033
|
-
resourceBinaryMap: resourceBinaryMap ?? [],
|
|
1034
|
-
bootloaderBinary: bootloaderBinary ?? null,
|
|
1035
1634
|
fwBinaryMap: fwBinaryMap ?? [],
|
|
1635
|
+
bootloaderBinary: bootloaderBinary ?? null,
|
|
1036
1636
|
});
|
|
1037
|
-
let totalSize = 0;
|
|
1038
|
-
let processedSize = 0;
|
|
1039
|
-
let transferredSize = 0;
|
|
1040
|
-
|
|
1041
|
-
for (const item of orderedInstallItems) totalSize += item.binary.byteLength;
|
|
1042
|
-
|
|
1043
|
-
this.postTipMessage(FirmwareUpdateTipMessage.StartTransferData);
|
|
1044
|
-
const transferStartTime = Date.now();
|
|
1045
|
-
const transferTransport = this.getProtocolV2FirmwareTransferTransport();
|
|
1046
|
-
const chunkSize = this.getProtocolV2FirmwareChunkSize();
|
|
1047
|
-
const onTransferredBytes = (bytes: number) => {
|
|
1048
|
-
transferredSize = bytes;
|
|
1049
|
-
};
|
|
1050
|
-
Log.log(
|
|
1051
|
-
`[FirmwareUpdateV4] transfer started transport=${transferTransport} total=${totalSize} bytes chunk=${chunkSize} bytes`
|
|
1052
|
-
);
|
|
1053
|
-
|
|
1054
|
-
const stagedInstallTargets: ProtocolV2InstallTarget[] = [];
|
|
1055
|
-
|
|
1056
1637
|
try {
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1638
|
+
const installSources = await Promise.all(
|
|
1639
|
+
memoryInstallItems.map(async item => ({
|
|
1640
|
+
fileName: item.fileName,
|
|
1641
|
+
source: await this.openProtocolV2MemorySource(item.binary),
|
|
1642
|
+
targetId: item.targetId,
|
|
1643
|
+
kind: item.kind,
|
|
1644
|
+
}))
|
|
1645
|
+
);
|
|
1646
|
+
const resourceSources = await Promise.all(
|
|
1647
|
+
(resourceBundles ?? []).map(async bundle => ({
|
|
1648
|
+
name: bundle.name,
|
|
1649
|
+
source: await this.openProtocolV2MemorySource(bundle.binary),
|
|
1650
|
+
devicePath: bundle.devicePath,
|
|
1651
|
+
version: bundle.version,
|
|
1652
|
+
payloadHash: bundle.payloadHash,
|
|
1653
|
+
headerHash: bundle.headerHash,
|
|
1654
|
+
}))
|
|
1655
|
+
);
|
|
1656
|
+
return await this.executeProtocolV2Phases({
|
|
1657
|
+
installSources,
|
|
1658
|
+
resourceSources,
|
|
1659
|
+
});
|
|
1660
|
+
} finally {
|
|
1661
|
+
await this.closeProtocolV2PreparedSources();
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1070
1664
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1665
|
+
private async executeProtocolV2TransferPhase({
|
|
1666
|
+
installSources,
|
|
1667
|
+
resourceSources,
|
|
1668
|
+
}: ProtocolV2ExecutionPhase) {
|
|
1669
|
+
let totalSize = installSources.reduce((total, item) => total + item.source.size, 0);
|
|
1670
|
+
const resourcesToSync: ProtocolV2ResourceBundleSource[] = [];
|
|
1671
|
+
for (const resource of resourceSources) {
|
|
1672
|
+
if (await this.isProtocolV2ResourceBundleUpToDate(resource)) {
|
|
1673
|
+
Log.log(`[FirmwareUpdateV4] skip RESC bundle ${resource.name}; already up to date`);
|
|
1674
|
+
} else {
|
|
1675
|
+
resourcesToSync.push(resource);
|
|
1676
|
+
totalSize += resource.source.size;
|
|
1075
1677
|
}
|
|
1678
|
+
}
|
|
1076
1679
|
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1680
|
+
this.postTipMessage(FirmwareUpdateTipMessage.StartTransferData);
|
|
1681
|
+
let processedSize = 0;
|
|
1682
|
+
for (const resource of resourcesToSync) {
|
|
1683
|
+
// The bootloader keeps its live resource package mounted. FatFs rejects
|
|
1684
|
+
// replacing an open file, so early boot promotes this staging file before mounting it.
|
|
1685
|
+
const writePath = resolveProtocolV2ResourceWritePath(resource.devicePath);
|
|
1686
|
+
processedSize = await this.protocolV2SourceUpdateProcess({
|
|
1687
|
+
source: resource.source,
|
|
1688
|
+
filePath: writePath,
|
|
1689
|
+
processedSize,
|
|
1690
|
+
totalSize,
|
|
1691
|
+
});
|
|
1692
|
+
await this.verifyProtocolV2StagedFile(writePath, resource.source.size);
|
|
1693
|
+
}
|
|
1080
1694
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1695
|
+
const stagedInstallTargets: Array<{ targetId: number; path: string }> = [];
|
|
1696
|
+
for (const item of installSources) {
|
|
1697
|
+
const filePath = this.getProtocolV2InstallItemStagingPath(item);
|
|
1698
|
+
processedSize = await this.protocolV2SourceUpdateProcess({
|
|
1699
|
+
source: item.source,
|
|
1700
|
+
filePath,
|
|
1701
|
+
processedSize,
|
|
1702
|
+
totalSize,
|
|
1703
|
+
});
|
|
1704
|
+
await this.verifyProtocolV2StagedFile(filePath, item.source.size);
|
|
1705
|
+
stagedInstallTargets.push({
|
|
1706
|
+
targetId: item.targetId,
|
|
1707
|
+
path: filePath,
|
|
1708
|
+
});
|
|
1095
1709
|
}
|
|
1096
1710
|
|
|
1097
|
-
|
|
1711
|
+
if (totalSize > 0) {
|
|
1712
|
+
this.postProgressMessage(100, 'transferData');
|
|
1713
|
+
}
|
|
1714
|
+
if (stagedInstallTargets.length === 0) {
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1098
1717
|
|
|
1099
|
-
|
|
1718
|
+
this.postTipMessage(FirmwareUpdateTipMessage.ConfirmOnDevice);
|
|
1719
|
+
const targets = stagedInstallTargets.map(item => ({
|
|
1100
1720
|
target_id: item.targetId,
|
|
1101
1721
|
path: item.path,
|
|
1102
1722
|
}));
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
await this.waitForProtocolV2FirmwareUpdateComplete(allTargets, startResponse);
|
|
1723
|
+
await this.protocolV2StartFirmwareUpdate({ targets });
|
|
1724
|
+
await this.waitForProtocolV2FirmwareUpdateComplete(targets);
|
|
1106
1725
|
}
|
|
1107
1726
|
|
|
1108
|
-
private
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1727
|
+
private async protocolV2SourceUpdateProcess({
|
|
1728
|
+
source,
|
|
1729
|
+
filePath,
|
|
1730
|
+
processedSize,
|
|
1731
|
+
totalSize,
|
|
1732
|
+
}: {
|
|
1733
|
+
source: FirmwareByteSource;
|
|
1734
|
+
filePath: string;
|
|
1735
|
+
processedSize: number;
|
|
1736
|
+
totalSize: number;
|
|
1737
|
+
}) {
|
|
1738
|
+
let lastError: unknown;
|
|
1739
|
+
for (let attempt = 1; attempt <= PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT; attempt += 1) {
|
|
1740
|
+
try {
|
|
1741
|
+
const transferStartedAt = Date.now();
|
|
1742
|
+
await writeFirmwareByteSource({
|
|
1743
|
+
source,
|
|
1744
|
+
chunkSize: this.getProtocolV2FirmwareChunkSize('write', filePath),
|
|
1745
|
+
write: async ({ data, sourceOffset, length, first }) => {
|
|
1746
|
+
const chunkEnd = sourceOffset + length;
|
|
1747
|
+
const deviceProgress = getProtocolV2DeviceTransferProgress(
|
|
1748
|
+
processedSize + sourceOffset,
|
|
1749
|
+
processedSize + chunkEnd,
|
|
1750
|
+
totalSize
|
|
1751
|
+
);
|
|
1752
|
+
const response = await this.fileWriteChunk(
|
|
1753
|
+
filePath,
|
|
1754
|
+
source.size,
|
|
1755
|
+
sourceOffset,
|
|
1756
|
+
data,
|
|
1757
|
+
first,
|
|
1758
|
+
deviceProgress
|
|
1759
|
+
);
|
|
1760
|
+
const rawProcessedByte = response.message.processed_byte;
|
|
1761
|
+
const nextOffset = rawProcessedByte === undefined ? chunkEnd : Number(rawProcessedByte);
|
|
1762
|
+
if (!Number.isFinite(nextOffset) || nextOffset !== chunkEnd) {
|
|
1763
|
+
throw ERRORS.TypedError(
|
|
1764
|
+
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1765
|
+
`invalid processed_byte ${rawProcessedByte} for offset ${sourceOffset}`
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
const transferredBytes = processedSize + chunkEnd;
|
|
1769
|
+
const elapsedMs = Math.max(Date.now() - transferStartedAt, 0);
|
|
1770
|
+
this.postProgressMessage(
|
|
1771
|
+
Math.min(Math.ceil((transferredBytes / totalSize) * 100), 99),
|
|
1772
|
+
'transferData',
|
|
1773
|
+
{
|
|
1774
|
+
transferredBytes,
|
|
1775
|
+
totalBytes: totalSize,
|
|
1776
|
+
rateBytesPerSecond:
|
|
1777
|
+
elapsedMs > 0 ? Math.round((chunkEnd / elapsedMs) * 1000) : undefined,
|
|
1778
|
+
elapsedMs,
|
|
1779
|
+
}
|
|
1780
|
+
);
|
|
1781
|
+
return length;
|
|
1782
|
+
},
|
|
1783
|
+
});
|
|
1784
|
+
return processedSize + source.size;
|
|
1785
|
+
} catch (error) {
|
|
1786
|
+
lastError = error;
|
|
1787
|
+
if (attempt < PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT) {
|
|
1788
|
+
await this.recoverProtocolV2FileTransfer();
|
|
1789
|
+
}
|
|
1132
1790
|
}
|
|
1791
|
+
}
|
|
1792
|
+
throw ERRORS.TypedError(
|
|
1793
|
+
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1794
|
+
`transfer data error: ${getProtocolV2UnknownErrorText(lastError)}`
|
|
1133
1795
|
);
|
|
1134
1796
|
}
|
|
1135
1797
|
|
|
1136
|
-
private
|
|
1137
|
-
return
|
|
1798
|
+
private getProtocolV2InstallItemStagingPath(item: Pick<ProtocolV2InstallItem, 'fileName'>) {
|
|
1799
|
+
return `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${item.fileName}`;
|
|
1138
1800
|
}
|
|
1139
1801
|
|
|
1140
|
-
private async
|
|
1141
|
-
const
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1802
|
+
private async verifyProtocolV2StagedFile(path: string, expectedSize: number) {
|
|
1803
|
+
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
1804
|
+
const response = await typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', { path });
|
|
1805
|
+
const actualSize = toProtocolV2FiniteNumber(response.message?.size);
|
|
1806
|
+
if (!response.message?.exist || response.message?.directory || actualSize !== expectedSize) {
|
|
1807
|
+
throw ERRORS.TypedError(
|
|
1808
|
+
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1809
|
+
`staged file verification failed: path=${path} exist=${!!response.message
|
|
1810
|
+
?.exist} expected=${expectedSize} actual=${actualSize ?? 'unknown'}`
|
|
1811
|
+
);
|
|
1150
1812
|
}
|
|
1151
|
-
return false;
|
|
1152
1813
|
}
|
|
1153
1814
|
|
|
1154
1815
|
private assertProtocolV2TargetStatus(
|
|
1155
1816
|
statusTargets: ProtocolV2FirmwareUpdateStatusTarget[],
|
|
1156
|
-
expectedTargetIds: Set<number
|
|
1817
|
+
expectedTargetIds: Set<number>,
|
|
1818
|
+
expectedPaths = new Map<number, string>()
|
|
1157
1819
|
) {
|
|
1820
|
+
Log.log(
|
|
1821
|
+
`[FirmwareUpdateV4] DeviceFirmwareUpdateStatus records=${JSON.stringify(statusTargets)}`
|
|
1822
|
+
);
|
|
1158
1823
|
const failedTarget = statusTargets.find(
|
|
1159
1824
|
target =>
|
|
1160
1825
|
expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
|
|
1161
1826
|
isProtocolV2TargetStatusFailed(target.status)
|
|
1162
1827
|
);
|
|
1163
1828
|
if (failedTarget) {
|
|
1829
|
+
const failedTargetDetails = JSON.stringify({
|
|
1830
|
+
targetId: failedTarget.target_id,
|
|
1831
|
+
status: failedTarget.status,
|
|
1832
|
+
payloadVersion: failedTarget.payload_version,
|
|
1833
|
+
path: failedTarget.path,
|
|
1834
|
+
});
|
|
1835
|
+
Log.error(`[FirmwareUpdateV4] firmware install failed target=${failedTargetDetails}`);
|
|
1164
1836
|
throw ERRORS.TypedError(
|
|
1165
1837
|
HardwareErrorCode.FirmwareError,
|
|
1166
|
-
`Protocol V2 firmware target
|
|
1838
|
+
`Protocol V2 firmware target failed: target=${failedTarget.target_id} status=${
|
|
1839
|
+
failedTarget.status ?? 'unknown'
|
|
1840
|
+
} payloadVersion=${failedTarget.payload_version ?? 'unknown'} path=${
|
|
1841
|
+
failedTarget.path ?? 'unknown'
|
|
1842
|
+
}`
|
|
1167
1843
|
);
|
|
1168
1844
|
}
|
|
1169
1845
|
|
|
1170
|
-
const
|
|
1171
|
-
target
|
|
1172
|
-
|
|
1173
|
-
|
|
1846
|
+
const matchingTargets = statusTargets.filter(target =>
|
|
1847
|
+
expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1)
|
|
1848
|
+
);
|
|
1849
|
+
const seenTargetIds = new Set<number>();
|
|
1850
|
+
for (const target of matchingTargets) {
|
|
1851
|
+
const targetId = normalizeProtocolV2TargetId(target.target_id);
|
|
1852
|
+
if (
|
|
1853
|
+
targetId === undefined ||
|
|
1854
|
+
seenTargetIds.has(targetId) ||
|
|
1855
|
+
(target.path && expectedPaths.get(targetId) && target.path !== expectedPaths.get(targetId))
|
|
1856
|
+
) {
|
|
1857
|
+
throw ERRORS.TypedError(
|
|
1858
|
+
HardwareErrorCode.RuntimeError,
|
|
1859
|
+
`Protocol V2 install status conflicts with target ${target.target_id}`,
|
|
1860
|
+
{
|
|
1861
|
+
firmwareUpdateCode: PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE,
|
|
1862
|
+
}
|
|
1863
|
+
);
|
|
1864
|
+
}
|
|
1865
|
+
seenTargetIds.add(targetId);
|
|
1866
|
+
}
|
|
1867
|
+
const completedTargets = matchingTargets.filter(target =>
|
|
1868
|
+
isProtocolV2TargetStatusFinished(target.status)
|
|
1174
1869
|
);
|
|
1175
|
-
|
|
1870
|
+
const completedTargetIds = new Set<number>();
|
|
1871
|
+
completedTargets.forEach(target => {
|
|
1872
|
+
const targetId = normalizeProtocolV2TargetId(target.target_id);
|
|
1873
|
+
if (targetId !== undefined) {
|
|
1874
|
+
completedTargetIds.add(targetId);
|
|
1875
|
+
}
|
|
1876
|
+
});
|
|
1877
|
+
if (completedTargetIds.size === expectedTargetIds.size && expectedTargetIds.size > 0) {
|
|
1878
|
+
for (const target of completedTargets) {
|
|
1879
|
+
const targetId = normalizeProtocolV2TargetId(target.target_id);
|
|
1880
|
+
const payloadVersion = toProtocolV2FiniteNumber(target.payload_version);
|
|
1881
|
+
if (targetId === undefined) {
|
|
1882
|
+
throw ERRORS.TypedError(
|
|
1883
|
+
HardwareErrorCode.RuntimeError,
|
|
1884
|
+
'Protocol V2 completed target identity is invalid'
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
const expectedVersion = this.getExpectedProtocolV2TargetVersion(targetId);
|
|
1888
|
+
if (expectedVersion !== undefined && payloadVersion !== undefined) {
|
|
1889
|
+
if (payloadVersion !== expectedVersion) {
|
|
1890
|
+
throw ERRORS.TypedError(
|
|
1891
|
+
HardwareErrorCode.FirmwareVerificationFailed,
|
|
1892
|
+
`Protocol V2 target ${targetId} reached payload version ${payloadVersion}, expected ${expectedVersion}`
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
if (payloadVersion !== undefined) {
|
|
1897
|
+
this.protocolV2CompletedTargetVersions.set(targetId, payloadVersion);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
this.postProgressMessage(100, 'installingFirmware');
|
|
1176
1901
|
return true;
|
|
1177
1902
|
}
|
|
1178
1903
|
|
|
1179
|
-
|
|
1180
|
-
target =>
|
|
1181
|
-
expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
|
|
1904
|
+
if (expectedTargetIds.size > 0 && matchingTargets.length > 0) {
|
|
1905
|
+
const hasInProgressTarget = matchingTargets.some(target =>
|
|
1182
1906
|
isProtocolV2TargetStatusInProgress(target.status)
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1907
|
+
);
|
|
1908
|
+
const completedProgress = Math.floor(
|
|
1909
|
+
(completedTargetIds.size / expectedTargetIds.size) * 100
|
|
1910
|
+
);
|
|
1911
|
+
// The protocol exposes no per-target percentage, so report coarse progress by
|
|
1912
|
+
// completed targets and use 1% once work starts to keep the UI responsive.
|
|
1913
|
+
const progress = Math.min(99, Math.max(completedProgress, hasInProgressTarget ? 1 : 0));
|
|
1914
|
+
this.postProgressMessage(progress, 'installingFirmware');
|
|
1186
1915
|
}
|
|
1187
1916
|
|
|
1188
1917
|
return false;
|
|
1189
1918
|
}
|
|
1190
1919
|
|
|
1191
|
-
private
|
|
1192
|
-
|
|
1193
|
-
|
|
1920
|
+
private getProtocolV2MissingTargetIds(
|
|
1921
|
+
statusTargets: ProtocolV2FirmwareUpdateStatusTarget[],
|
|
1922
|
+
expectedTargetIds: Set<number>
|
|
1194
1923
|
) {
|
|
1195
|
-
const
|
|
1196
|
-
|
|
1197
|
-
const
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
return;
|
|
1924
|
+
const reportedTargetIds = new Set<number>();
|
|
1925
|
+
statusTargets.forEach(target => {
|
|
1926
|
+
const targetId = normalizeProtocolV2TargetId(target.target_id);
|
|
1927
|
+
if (targetId !== undefined) {
|
|
1928
|
+
reportedTargetIds.add(targetId);
|
|
1201
1929
|
}
|
|
1202
|
-
}
|
|
1930
|
+
});
|
|
1931
|
+
return Array.from(expectedTargetIds).filter(targetId => !reportedTargetIds.has(targetId));
|
|
1932
|
+
}
|
|
1203
1933
|
|
|
1934
|
+
private async waitForProtocolV2FirmwareUpdateComplete(
|
|
1935
|
+
targets: Array<{ target_id: number; path: string }>
|
|
1936
|
+
) {
|
|
1937
|
+
this.protocolV2FinalStatusVerified = false;
|
|
1938
|
+
const expectedTargetIds = new Set(targets.map(target => target.target_id));
|
|
1939
|
+
const expectedPaths = new Map(targets.map(target => [target.target_id, target.path]));
|
|
1204
1940
|
const startTime = Date.now();
|
|
1205
1941
|
let lastError: unknown;
|
|
1942
|
+
let shouldReconnect = true;
|
|
1943
|
+
let deviceInfo: ProtocolV2DeviceInfo | undefined;
|
|
1944
|
+
let missingTargetStatusSince: number | undefined;
|
|
1945
|
+
let missingTargetStatusKey: string | undefined;
|
|
1946
|
+
const resetMissingTargetStatusGrace = () => {
|
|
1947
|
+
missingTargetStatusSince = undefined;
|
|
1948
|
+
missingTargetStatusKey = undefined;
|
|
1949
|
+
};
|
|
1206
1950
|
|
|
1207
1951
|
while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
|
|
1208
1952
|
try {
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
return;
|
|
1953
|
+
if (shouldReconnect) {
|
|
1954
|
+
await this.reconnectProtocolV2Device();
|
|
1955
|
+
deviceInfo = await this.verifyProtocolV2ReconnectIdentity();
|
|
1956
|
+
shouldReconnect = false;
|
|
1214
1957
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1958
|
+
const currentDeviceInfo = deviceInfo;
|
|
1959
|
+
try {
|
|
1960
|
+
const statusResponse = await this.device.getCommands().typedCall(
|
|
1961
|
+
'DeviceFirmwareUpdateStatusGet',
|
|
1962
|
+
'DeviceFirmwareUpdateStatus',
|
|
1963
|
+
{
|
|
1964
|
+
fields: {
|
|
1965
|
+
status: true,
|
|
1966
|
+
payload_version: true,
|
|
1967
|
+
path: true,
|
|
1968
|
+
},
|
|
1969
|
+
},
|
|
1970
|
+
{ timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT }
|
|
1971
|
+
);
|
|
1972
|
+
const statusTargets = (statusResponse.message.records ??
|
|
1973
|
+
[]) as ProtocolV2FirmwareUpdateStatusTarget[];
|
|
1974
|
+
if (this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds, expectedPaths)) {
|
|
1975
|
+
this.protocolV2FinalStatusVerified = true;
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
if (
|
|
1980
|
+
statusTargets.length === 0 &&
|
|
1981
|
+
currentDeviceInfo &&
|
|
1982
|
+
(await this.probeProtocolV2NormalMode(currentDeviceInfo))
|
|
1983
|
+
) {
|
|
1984
|
+
Log.log(
|
|
1985
|
+
'[FirmwareUpdateV4] empty firmware status after confirmed App reboot; update complete'
|
|
1986
|
+
);
|
|
1987
|
+
this.postProgressMessage(100, 'installingFirmware');
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
const missingTargetIds = this.getProtocolV2MissingTargetIds(
|
|
1992
|
+
statusTargets,
|
|
1993
|
+
expectedTargetIds
|
|
1994
|
+
);
|
|
1995
|
+
if (missingTargetIds.length > 0) {
|
|
1996
|
+
const now = Date.now();
|
|
1997
|
+
const missingKey = missingTargetIds.join(',');
|
|
1998
|
+
if (missingTargetStatusSince === undefined || missingTargetStatusKey !== missingKey) {
|
|
1999
|
+
missingTargetStatusSince = now;
|
|
2000
|
+
missingTargetStatusKey = missingKey;
|
|
2001
|
+
} else if (
|
|
2002
|
+
now - missingTargetStatusSince >=
|
|
2003
|
+
PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT
|
|
2004
|
+
) {
|
|
2005
|
+
const reportedTargetIds = statusTargets
|
|
2006
|
+
.map(target => normalizeProtocolV2TargetId(target.target_id))
|
|
2007
|
+
.filter((targetId): targetId is number => targetId !== undefined);
|
|
2008
|
+
throw ERRORS.TypedError(
|
|
2009
|
+
HardwareErrorCode.FirmwareError,
|
|
2010
|
+
`Protocol V2 firmware status is missing requested records: targetIds=${missingKey} reportedTargetIds=${reportedTargetIds.join(
|
|
2011
|
+
','
|
|
2012
|
+
)}`
|
|
2013
|
+
);
|
|
2014
|
+
}
|
|
2015
|
+
lastError = new Error(
|
|
2016
|
+
`Protocol V2 firmware status is temporarily missing targetIds=${missingKey}`
|
|
2017
|
+
);
|
|
2018
|
+
} else {
|
|
2019
|
+
resetMissingTargetStatusGrace();
|
|
2020
|
+
lastError = new Error('Protocol V2 firmware targets are still installing');
|
|
2021
|
+
}
|
|
2022
|
+
} catch (error) {
|
|
2023
|
+
if (isProtocolV2TerminalInstallStatusError(error)) {
|
|
2024
|
+
throw error;
|
|
2025
|
+
}
|
|
2026
|
+
// Only consecutive full status dumps can prove that a record is absent.
|
|
2027
|
+
// A reboot or transport interruption starts a fresh grace window.
|
|
2028
|
+
resetMissingTargetStatusGrace();
|
|
2029
|
+
// App firmware does not register DeviceFirmwareUpdateStatusGet. Treat the
|
|
2030
|
+
// missing endpoint as completion only after the runtime probe confirms App mode.
|
|
2031
|
+
if (isProtocolV2FirmwareStatusEndpointUnavailable(error)) {
|
|
2032
|
+
if (!currentDeviceInfo) {
|
|
2033
|
+
throw ERRORS.TypedError(
|
|
2034
|
+
HardwareErrorCode.RuntimeError,
|
|
2035
|
+
'Protocol V2 device identity is unavailable during install polling'
|
|
2036
|
+
);
|
|
2037
|
+
}
|
|
2038
|
+
if (await this.probeProtocolV2NormalMode(currentDeviceInfo)) {
|
|
2039
|
+
Log.log(
|
|
2040
|
+
'[FirmwareUpdateV4] firmware status endpoint unavailable after confirmed App reboot'
|
|
2041
|
+
);
|
|
2042
|
+
this.postProgressMessage(100, 'installingFirmware');
|
|
1225
2043
|
return;
|
|
1226
2044
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
2045
|
+
lastError = new Error(
|
|
2046
|
+
'Protocol V2 firmware status endpoint is unavailable while the device remains in loader mode'
|
|
2047
|
+
);
|
|
2048
|
+
} else {
|
|
2049
|
+
shouldReconnect = true;
|
|
2050
|
+
deviceInfo = undefined;
|
|
2051
|
+
lastError = error;
|
|
1229
2052
|
Log.log(
|
|
1230
|
-
'
|
|
1231
|
-
|
|
2053
|
+
'[FirmwareUpdateV4] DeviceFirmwareUpdateStatusGet unavailable during install: ',
|
|
2054
|
+
error
|
|
1232
2055
|
);
|
|
1233
2056
|
}
|
|
1234
|
-
try {
|
|
1235
|
-
await this.pingProtocolV2Device();
|
|
1236
|
-
Log.log('Protocol V2 firmware status unavailable, Ping is ready');
|
|
1237
|
-
} catch (pingError) {
|
|
1238
|
-
lastError = pingError;
|
|
1239
|
-
Log.log('Protocol V2 firmware install Ping polling failed: ', pingError);
|
|
1240
|
-
}
|
|
1241
2057
|
}
|
|
2058
|
+
} catch (error) {
|
|
2059
|
+
lastError = error;
|
|
2060
|
+
if (this.isProtocolV2ReconnectIdentityError(error)) {
|
|
2061
|
+
throw error;
|
|
2062
|
+
}
|
|
2063
|
+
if (isProtocolV2TerminalInstallStatusError(error)) {
|
|
2064
|
+
throw error;
|
|
2065
|
+
}
|
|
2066
|
+
if (
|
|
2067
|
+
error instanceof HardwareError &&
|
|
2068
|
+
error.params?.firmwareUpdateCode === 'FirmwareInstallStatusUnavailable'
|
|
2069
|
+
) {
|
|
2070
|
+
throw error;
|
|
2071
|
+
}
|
|
2072
|
+
shouldReconnect = true;
|
|
2073
|
+
deviceInfo = undefined;
|
|
2074
|
+
resetMissingTargetStatusGrace();
|
|
2075
|
+
Log.log('Protocol V2 firmware install device readiness probe failed: ', error);
|
|
1242
2076
|
}
|
|
1243
2077
|
await wait(1000);
|
|
1244
2078
|
}
|
|
1245
2079
|
|
|
1246
2080
|
throw ERRORS.TypedError(
|
|
1247
2081
|
HardwareErrorCode.RuntimeError,
|
|
1248
|
-
`Protocol V2 firmware update status
|
|
2082
|
+
`Protocol V2 firmware update status not complete within ${
|
|
2083
|
+
PROTOCOL_V2_INSTALL_TIMEOUT / 1000
|
|
2084
|
+
}s: ${this.normalizeErrorMessage(lastError)}`
|
|
1249
2085
|
);
|
|
1250
2086
|
}
|
|
1251
2087
|
|
|
1252
2088
|
private async exitProtocolV2BootloaderToNormal() {
|
|
1253
|
-
this.
|
|
2089
|
+
await this.reconnectProtocolV2Device();
|
|
2090
|
+
const deviceInfo = await this.verifyProtocolV2ReconnectIdentity();
|
|
1254
2091
|
try {
|
|
1255
|
-
await this.
|
|
1256
|
-
|
|
1257
|
-
Log.log('Protocol V2 device is already in normal mode, skip normal reboot');
|
|
2092
|
+
if (await this.probeProtocolV2NormalMode(deviceInfo)) {
|
|
2093
|
+
Log.log('[FirmwareUpdateV4] device already returned to App mode; skip Normal reboot');
|
|
1258
2094
|
return;
|
|
1259
2095
|
}
|
|
1260
2096
|
} catch (error) {
|
|
1261
|
-
Log.log('
|
|
2097
|
+
Log.log('[FirmwareUpdateV4] unable to confirm App mode before Normal reboot: ', error);
|
|
1262
2098
|
}
|
|
1263
2099
|
await this.protocolV2Reboot(DeviceRebootType.Normal);
|
|
2100
|
+
this.protocolV2ExecutionInLoader = false;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
private async probeProtocolV2NormalMode(deviceInfo: ProtocolV2DeviceInfo) {
|
|
2104
|
+
const features = await this.device.probeProtocolV2RuntimeState(
|
|
2105
|
+
deviceInfo,
|
|
2106
|
+
PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
|
|
2107
|
+
);
|
|
2108
|
+
return features.mode === 'normal' && !features.bootloaderMode;
|
|
1264
2109
|
}
|
|
1265
2110
|
|
|
1266
2111
|
private async waitForProtocolV2FinalFeatures() {
|
|
1267
2112
|
const features = await this.waitForProtocolV2ReconnectAndFeatures(
|
|
1268
|
-
|
|
2113
|
+
PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT
|
|
1269
2114
|
);
|
|
1270
2115
|
|
|
2116
|
+
return this.getProtocolV2VersionResult(features);
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
private getProtocolV2VersionResult(features: Features) {
|
|
1271
2120
|
const bootloaderVersion = getDeviceBootloaderVersion(features).join('.');
|
|
1272
2121
|
const bleVersion = getDeviceBLEFirmwareVersion(features).join('.');
|
|
1273
2122
|
const firmwareVersion = getDeviceFirmwareVersion(features).join('.');
|
|
2123
|
+
this.protocolV2LatestFinalFeatures = features;
|
|
1274
2124
|
if (firmwareVersion === '0.0.0') {
|
|
1275
2125
|
Log.warn(
|
|
1276
2126
|
'Protocol V2 firmware update finished but app firmware version is still 0.0.0. This is allowed for Pro2 debug BLE-only update flows.'
|
|
@@ -1284,32 +2134,55 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1284
2134
|
};
|
|
1285
2135
|
}
|
|
1286
2136
|
|
|
2137
|
+
private async completeProtocolV2FinalVerification() {
|
|
2138
|
+
if (this.protocolV2ExecutionInLoader || this.isProtocolV2BootloaderMode()) {
|
|
2139
|
+
await this.exitProtocolV2BootloaderToNormal();
|
|
2140
|
+
}
|
|
2141
|
+
const versions = await this.waitForProtocolV2FinalFeatures();
|
|
2142
|
+
this.assertExpectedProtocolV2Versions();
|
|
2143
|
+
this.postTipMessage(FirmwareUpdateTipMessage.FirmwareUpdateCompleted);
|
|
2144
|
+
DevicePool.resetState();
|
|
2145
|
+
return versions;
|
|
2146
|
+
}
|
|
2147
|
+
|
|
1287
2148
|
private async waitForProtocolV2ReconnectAndFeatures(timeout: number) {
|
|
1288
2149
|
const startTime = Date.now();
|
|
1289
2150
|
let lastError: unknown;
|
|
2151
|
+
let shouldReconnect = true;
|
|
1290
2152
|
|
|
1291
2153
|
while (Date.now() - startTime < timeout) {
|
|
1292
2154
|
try {
|
|
1293
|
-
|
|
2155
|
+
if (shouldReconnect) {
|
|
2156
|
+
await this.reconnectProtocolV2Device();
|
|
2157
|
+
shouldReconnect = false;
|
|
2158
|
+
}
|
|
1294
2159
|
const deviceInfo = await requestProtocolV2DeviceInfo({
|
|
1295
2160
|
commands: this.device.getCommands(),
|
|
1296
|
-
timeoutMs:
|
|
1297
|
-
//
|
|
2161
|
+
timeoutMs: this.getProtocolV2DeviceInfoTimeout(),
|
|
2162
|
+
// Completion needs target versions only; keep scope aligned with the request.
|
|
1298
2163
|
request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
|
|
1299
2164
|
});
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
2165
|
+
this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
|
|
2166
|
+
const features = await this.device.probeProtocolV2RuntimeState(
|
|
2167
|
+
deviceInfo,
|
|
2168
|
+
PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
|
|
2169
|
+
);
|
|
2170
|
+
if (features.mode === 'normal' && !features.bootloaderMode) {
|
|
2171
|
+
return features;
|
|
1306
2172
|
}
|
|
1307
|
-
|
|
2173
|
+
lastError = ERRORS.TypedError(
|
|
2174
|
+
HardwareErrorCode.DeviceNotFound,
|
|
2175
|
+
'Protocol V2 device is still in bootloader mode'
|
|
2176
|
+
);
|
|
1308
2177
|
} catch (error) {
|
|
2178
|
+
if (this.isProtocolV2ReconnectIdentityError(error)) {
|
|
2179
|
+
throw error;
|
|
2180
|
+
}
|
|
2181
|
+
shouldReconnect = true;
|
|
1309
2182
|
lastError = error;
|
|
1310
2183
|
Log.log('Protocol V2 normal mode not ready, polling Ping: ', error);
|
|
1311
|
-
await wait(1000);
|
|
1312
2184
|
}
|
|
2185
|
+
await wait(1000);
|
|
1313
2186
|
}
|
|
1314
2187
|
|
|
1315
2188
|
throw ERRORS.TypedError(
|
|
@@ -1333,114 +2206,74 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1333
2206
|
DataManager.isBrowserWebUsb(DataManager.getSettings('env')) &&
|
|
1334
2207
|
devicesDescriptor.length === 1
|
|
1335
2208
|
) {
|
|
2209
|
+
const descriptor = devicesDescriptor[0];
|
|
2210
|
+
if (!this.protocolV2ExpectedSerialNumber && descriptor.path !== this.protocolV2ExpectedPath) {
|
|
2211
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound);
|
|
2212
|
+
}
|
|
1336
2213
|
this.device.updateDescriptor(
|
|
1337
2214
|
{
|
|
1338
|
-
...
|
|
2215
|
+
...descriptor,
|
|
1339
2216
|
protocolType: PROTOCOL_V2_CONNECT_PROTOCOL,
|
|
1340
2217
|
},
|
|
1341
2218
|
true
|
|
1342
2219
|
);
|
|
1343
|
-
await this.
|
|
2220
|
+
await this.ensureProtocolV2DeviceAcquired();
|
|
1344
2221
|
this.device.commands.disposed = false;
|
|
1345
2222
|
this.device.getCommands().mainId = this.device.mainId ?? '';
|
|
1346
|
-
await this.device.initialize();
|
|
1347
2223
|
return;
|
|
1348
2224
|
}
|
|
1349
2225
|
|
|
1350
|
-
//
|
|
1351
|
-
//
|
|
2226
|
+
// Reinitialize every USB descriptor so DeviceInfo can provide the physical serial.
|
|
2227
|
+
// Enumeration order is not stable and must never decide the reconnect target.
|
|
1352
2228
|
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
|
|
1353
2229
|
connectProtocol: PROTOCOL_V2_CONNECT_PROTOCOL,
|
|
1354
2230
|
});
|
|
1355
|
-
|
|
2231
|
+
const expectedSerialNumber = this.protocolV2ExpectedSerialNumber?.trim();
|
|
2232
|
+
const expectedPath = this.protocolV2ExpectedPath?.trim();
|
|
2233
|
+
const reconnectDevice = deviceList.find(candidate => {
|
|
2234
|
+
const candidateSerialNumber = candidate.getCurrentSerialNo?.().trim();
|
|
2235
|
+
if (expectedSerialNumber && candidateSerialNumber) {
|
|
2236
|
+
return candidateSerialNumber === expectedSerialNumber;
|
|
2237
|
+
}
|
|
2238
|
+
return !!expectedPath && candidate.getConnectId() === expectedPath;
|
|
2239
|
+
});
|
|
2240
|
+
if (!reconnectDevice) {
|
|
1356
2241
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound);
|
|
1357
2242
|
}
|
|
1358
2243
|
|
|
1359
2244
|
Log.debug(
|
|
1360
|
-
'Protocol V2 firmware reconnect using
|
|
1361
|
-
|
|
2245
|
+
'Protocol V2 firmware reconnect using matched device:',
|
|
2246
|
+
reconnectDevice.getConnectId()
|
|
1362
2247
|
);
|
|
1363
|
-
this.device.updateFromCache(
|
|
1364
|
-
await this.
|
|
2248
|
+
this.device.updateFromCache(reconnectDevice);
|
|
2249
|
+
await this.ensureProtocolV2DeviceAcquired();
|
|
1365
2250
|
this.device.commands.disposed = false;
|
|
1366
2251
|
this.device.getCommands().mainId = this.device.mainId ?? '';
|
|
1367
|
-
await this.device.initialize();
|
|
1368
2252
|
}
|
|
1369
2253
|
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
processedSize?: number;
|
|
1379
|
-
totalSize?: number;
|
|
1380
|
-
onTransferredBytes?: (transferredBytes: number) => void;
|
|
1381
|
-
}) {
|
|
1382
|
-
const chunkSize = this.getProtocolV2FirmwareChunkSize();
|
|
1383
|
-
let offset = 0;
|
|
1384
|
-
const getUploadProgress = (fileOffset: number) => {
|
|
1385
|
-
if (totalSize !== undefined && processedSize !== undefined) {
|
|
1386
|
-
return Math.min(Math.ceil(((processedSize + fileOffset) / totalSize) * 100), 99);
|
|
1387
|
-
}
|
|
1388
|
-
return Math.min(Math.ceil((fileOffset / payload.byteLength) * 100), 99);
|
|
1389
|
-
};
|
|
1390
|
-
|
|
1391
|
-
while (offset < payload.byteLength) {
|
|
1392
|
-
const chunkEnd = Math.min(offset + chunkSize, payload.byteLength);
|
|
1393
|
-
const chunkLength = chunkEnd - offset;
|
|
1394
|
-
const chunk = payload.slice(offset, chunkEnd);
|
|
1395
|
-
const overwrite = offset === 0;
|
|
1396
|
-
const progress = getProtocolV2DeviceTransferProgress(
|
|
1397
|
-
(processedSize ?? 0) + offset,
|
|
1398
|
-
(processedSize ?? 0) + chunkEnd,
|
|
1399
|
-
totalSize ?? payload.byteLength
|
|
1400
|
-
);
|
|
1401
|
-
|
|
1402
|
-
const writeRes = await this.fileWriteWithRetry(
|
|
1403
|
-
filePath,
|
|
1404
|
-
payload.byteLength,
|
|
1405
|
-
offset,
|
|
1406
|
-
chunk,
|
|
1407
|
-
overwrite,
|
|
1408
|
-
progress
|
|
1409
|
-
);
|
|
1410
|
-
const processedByte = Number(writeRes.message.processed_byte);
|
|
1411
|
-
const nextOffset =
|
|
1412
|
-
Number.isFinite(processedByte) && processedByte > offset
|
|
1413
|
-
? processedByte
|
|
1414
|
-
: offset + chunkLength;
|
|
1415
|
-
if (nextOffset <= offset || nextOffset > payload.byteLength) {
|
|
1416
|
-
throw ERRORS.TypedError(
|
|
1417
|
-
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1418
|
-
`invalid processed_byte ${writeRes.message.processed_byte} for offset ${offset}`
|
|
1419
|
-
);
|
|
1420
|
-
}
|
|
1421
|
-
offset = nextOffset;
|
|
1422
|
-
onTransferredBytes?.((processedSize ?? 0) + offset);
|
|
1423
|
-
this.postProgressMessage(getUploadProgress(offset), 'transferData');
|
|
2254
|
+
/**
|
|
2255
|
+
* After acquiring a USB session, polling reuses its command channel. Reacquire only
|
|
2256
|
+
* after reboot or enumeration changes cause hasDeviceAcquire() to become false.
|
|
2257
|
+
*/
|
|
2258
|
+
private async ensureProtocolV2DeviceAcquired() {
|
|
2259
|
+
const commands = this.device.getCommands();
|
|
2260
|
+
if (this.device.hasDeviceAcquire() && !commands.disposed) {
|
|
2261
|
+
return;
|
|
1424
2262
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
2263
|
+
await this.device.acquire(PROTOCOL_V2_CONNECT_PROTOCOL, {
|
|
2264
|
+
throwOnRunPromiseError: true,
|
|
2265
|
+
});
|
|
1427
2266
|
}
|
|
1428
2267
|
|
|
1429
|
-
private
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
env &&
|
|
1436
|
-
(DataManager.isBrowserWebUsb(env) || DataManager.isDesktopWebUsb(env) || env === 'web')
|
|
1437
|
-
) {
|
|
1438
|
-
return 'WebUSB';
|
|
1439
|
-
}
|
|
1440
|
-
return env ?? 'unknown';
|
|
2268
|
+
private isProtocolV2ReconnectIdentityError(error: unknown) {
|
|
2269
|
+
// A serial can be temporarily unavailable while Loader starts, and BLE has no stable path.
|
|
2270
|
+
// Keep polling unless the device explicitly reports a different serial.
|
|
2271
|
+
return this.normalizeErrorMessage(error).includes(
|
|
2272
|
+
'Protocol V2 reconnect physical identity mismatch'
|
|
2273
|
+
);
|
|
1441
2274
|
}
|
|
1442
2275
|
|
|
1443
|
-
private async
|
|
2276
|
+
private async fileWriteChunk(
|
|
1444
2277
|
filePath: string,
|
|
1445
2278
|
totalFileSize: number,
|
|
1446
2279
|
offset: number,
|
|
@@ -1448,9 +2281,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1448
2281
|
overwrite: boolean,
|
|
1449
2282
|
progress: number | null
|
|
1450
2283
|
): Promise<TypedResponseMessage<'FilesystemFile'>> {
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1453
|
-
|
|
2284
|
+
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
2285
|
+
const writeRes = await typedCall(
|
|
2286
|
+
'FilesystemFileWrite',
|
|
2287
|
+
'FilesystemFile',
|
|
2288
|
+
{
|
|
1454
2289
|
file: {
|
|
1455
2290
|
path: filePath,
|
|
1456
2291
|
offset,
|
|
@@ -1460,45 +2295,32 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1460
2295
|
overwrite,
|
|
1461
2296
|
append: false,
|
|
1462
2297
|
ui_percentage: progress ?? undefined,
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, SESSION_ERROR);
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
throw ERRORS.TypedError(
|
|
1471
|
-
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1472
|
-
'transfer data error'
|
|
1473
|
-
);
|
|
2298
|
+
},
|
|
2299
|
+
{
|
|
2300
|
+
writeWithResponse: false,
|
|
2301
|
+
onWriteCompleted: () => undefined,
|
|
1474
2302
|
}
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
try {
|
|
1481
|
-
const result = await writeFunc();
|
|
1482
|
-
return result;
|
|
1483
|
-
} catch (error) {
|
|
1484
|
-
Log.error(`fileWrite error: `, error);
|
|
1485
|
-
retryCount--;
|
|
1486
|
-
if (retryCount === 0) {
|
|
1487
|
-
throw ERRORS.TypedError(
|
|
1488
|
-
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1489
|
-
'transfer data error'
|
|
1490
|
-
);
|
|
1491
|
-
}
|
|
1492
|
-
const env = DataManager.getSettings('env');
|
|
1493
|
-
if (DataManager.isBleConnect(env)) {
|
|
1494
|
-
await wait(3000);
|
|
1495
|
-
await this.acquireProtocolV2BleDevice();
|
|
1496
|
-
await this.device.initialize();
|
|
2303
|
+
);
|
|
2304
|
+
if (writeRes.type !== 'FilesystemFile') {
|
|
2305
|
+
if ((writeRes as any).type === 'CallMethodError') {
|
|
2306
|
+
if (((writeRes as any).message.error ?? '').indexOf(SESSION_ERROR) > -1) {
|
|
2307
|
+
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, SESSION_ERROR);
|
|
1497
2308
|
}
|
|
1498
|
-
await wait(2000);
|
|
1499
2309
|
}
|
|
2310
|
+
throw ERRORS.TypedError(HardwareErrorCode.EmmcFileWriteFirmwareError, 'transfer data error');
|
|
2311
|
+
}
|
|
2312
|
+
return writeRes;
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
private async recoverProtocolV2FileTransfer() {
|
|
2316
|
+
const env = DataManager.getSettings('env');
|
|
2317
|
+
if (DataManager.isBleConnect(env)) {
|
|
2318
|
+
await wait(3000);
|
|
1500
2319
|
}
|
|
1501
|
-
|
|
2320
|
+
await this.reconnectProtocolV2Device();
|
|
2321
|
+
await this.verifyProtocolV2ReconnectIdentity();
|
|
2322
|
+
await this.device.initialize();
|
|
2323
|
+
await wait(2000);
|
|
1502
2324
|
}
|
|
1503
2325
|
|
|
1504
2326
|
private async acquireProtocolV2BleDevice() {
|
|
@@ -1516,35 +2338,16 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1516
2338
|
targets: Array<{ target_id: number; path: string }>;
|
|
1517
2339
|
}) {
|
|
1518
2340
|
const commands = this.device.getCommands();
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
{
|
|
1528
|
-
intermediateTypes: ['DeviceFirmwareUpdateStatus'],
|
|
1529
|
-
timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT,
|
|
1530
|
-
onIntermediateResponse: (response: { type?: string }) => {
|
|
1531
|
-
if (response.type === 'DeviceFirmwareUpdateStatus') {
|
|
1532
|
-
this.postProgressMessage(99, 'installingFirmware');
|
|
1533
|
-
}
|
|
1534
|
-
},
|
|
1535
|
-
}
|
|
1536
|
-
);
|
|
1537
|
-
} catch (error) {
|
|
1538
|
-
if (isProtocolV2StartUpdateTransientError(error)) {
|
|
1539
|
-
Log.log(
|
|
1540
|
-
'Protocol V2 firmware update request did not return; continue status polling',
|
|
1541
|
-
error
|
|
1542
|
-
);
|
|
1543
|
-
} else {
|
|
1544
|
-
throw error;
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
2341
|
+
const response: ProtocolV2FirmwareUpdateStartResponse = await commands.typedCall(
|
|
2342
|
+
'DeviceFirmwareUpdateRequest',
|
|
2343
|
+
'Success',
|
|
2344
|
+
{ targets },
|
|
2345
|
+
{ timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT }
|
|
2346
|
+
);
|
|
2347
|
+
// Success acknowledges that the device accepted installation. End confirmation
|
|
2348
|
+
// and begin status polling only after receiving this ACK.
|
|
1547
2349
|
this.postTipMessage(FirmwareUpdateTipMessage.FirmwareUpdating);
|
|
2350
|
+
this.postProgressMessage(0, 'installingFirmware');
|
|
1548
2351
|
return response;
|
|
1549
2352
|
}
|
|
1550
2353
|
|
|
@@ -1554,9 +2357,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1554
2357
|
const res = await typedCall('DeviceReboot', 'Success', {
|
|
1555
2358
|
reboot_type: rebootType,
|
|
1556
2359
|
});
|
|
2360
|
+
this.device.markProtocolV2Reboot(rebootType);
|
|
1557
2361
|
return res.message;
|
|
1558
2362
|
} catch (error) {
|
|
1559
2363
|
if (isProtocolV2DeviceDisconnectedError(error) || isProtocolV2ReconnectProbeError(error)) {
|
|
2364
|
+
this.device.markProtocolV2Reboot(rebootType);
|
|
1560
2365
|
return { message: 'Device rebooted successfully' };
|
|
1561
2366
|
}
|
|
1562
2367
|
throw error;
|