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