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