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