@onekeyfe/hd-core 1.2.0-alpha.6 → 1.2.0-alpha.62
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-initialize-timeout.test.ts +56 -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-bootloader-poll.test.ts +200 -0
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
- package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +294 -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 +6058 -2525
- 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 +40 -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 +32 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/api/firmware/getBinary.d.ts +15 -4
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +2 -0
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +9 -1
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/filesystemValidation.d.ts +3 -0
- package/dist/api/helpers/filesystemValidation.d.ts.map +1 -1
- package/dist/api/helpers/paramsValidator.d.ts +1 -0
- package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts +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 +1 -0
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +7 -0
- package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceReboot.d.ts +1 -0
- package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceStatusGet.d.ts +7 -0
- package/dist/api/protocol-v2/DeviceStatusGet.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +27 -0
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -0
- package/dist/api/protocol-v2/FilesystemFormat.d.ts +1 -0
- package/dist/api/protocol-v2/FilesystemFormat.d.ts.map +1 -1
- package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts +1 -0
- package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts.map +1 -1
- package/dist/api/protocol-v2/Ping.d.ts +3 -0
- package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
- package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts +1 -0
- package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
- package/dist/api/protocol-v2/helpers.d.ts +1 -1
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
- package/dist/api/scdo/ScdoGetAddress.d.ts.map +1 -1
- package/dist/api/scdo/ScdoSignMessage.d.ts.map +1 -1
- package/dist/api/scdo/ScdoSignTransaction.d.ts.map +1 -1
- package/dist/api/solana/SolGetAddress.d.ts +1 -0
- package/dist/api/solana/SolGetAddress.d.ts.map +1 -1
- package/dist/api/solana/SolSignMessage.d.ts +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 +45 -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 +1564 -739
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9236 -3918
- 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/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 +14 -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 +24 -13
- package/src/api/FirmwareUpdateV2.ts +386 -113
- package/src/api/FirmwareUpdateV3.ts +266 -68
- package/src/api/FirmwareUpdateV4.ts +1222 -635
- 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 +75 -4
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +772 -0
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +415 -0
- package/src/api/firmware/getBinary.ts +8 -3
- 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 +10 -6
- package/src/api/protocol-v2/DeviceGetOnboardingStatus.ts +21 -0
- package/src/api/protocol-v2/DeviceInfoGet.ts +8 -15
- package/src/api/protocol-v2/DeviceReboot.ts +7 -3
- package/src/api/protocol-v2/DeviceStatusGet.ts +19 -0
- package/src/api/protocol-v2/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 +17 -17
- package/src/api/scdo/ScdoGetAddress.ts +0 -4
- package/src/api/scdo/ScdoSignMessage.ts +0 -4
- package/src/api/scdo/ScdoSignTransaction.ts +0 -4
- package/src/api/solana/SolGetAddress.ts +4 -0
- package/src/api/solana/SolSignMessage.ts +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 -483
- 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 +652 -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 +1 -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 -145
- 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 +186 -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,17 +104,22 @@ 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 };
|
|
103
110
|
type ProtocolV2InstallItem = ProtocolV2TargetBinary & {
|
|
104
111
|
kind: ProtocolV2RemoteComponentTarget['kind'];
|
|
105
112
|
};
|
|
106
|
-
|
|
107
|
-
|
|
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;
|
|
108
123
|
};
|
|
109
124
|
|
|
110
125
|
type ProtocolV2RemoteComponentBinary = ProtocolV2RemoteComponentTarget & {
|
|
@@ -114,7 +129,36 @@ type ProtocolV2RemoteComponentBinary = ProtocolV2RemoteComponentTarget & {
|
|
|
114
129
|
type ProtocolV2RemoteComponentTarget = {
|
|
115
130
|
fileName: string;
|
|
116
131
|
targetId: number;
|
|
117
|
-
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[];
|
|
118
162
|
};
|
|
119
163
|
|
|
120
164
|
type ProtocolV2OkppHeader = {
|
|
@@ -167,18 +211,24 @@ const PROTOCOL_V2_REMOTE_COMPONENT_TARGETS: Readonly<
|
|
|
167
211
|
targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04,
|
|
168
212
|
kind: 'firmware',
|
|
169
213
|
},
|
|
170
|
-
CRATE: {
|
|
171
|
-
fileName: 'resource.bin',
|
|
172
|
-
targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
|
|
173
|
-
kind: 'resource',
|
|
174
|
-
},
|
|
175
214
|
};
|
|
176
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
|
+
|
|
177
227
|
const PROTOCOL_V2_ROMLOADER_UNSUPPORTED_MESSAGE =
|
|
178
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.';
|
|
179
229
|
|
|
180
|
-
// hd-transport
|
|
181
|
-
//
|
|
230
|
+
// hd-transport historically decodes scalar enums as enum-name strings.
|
|
231
|
+
// Map them back to firmware protocol values before internal comparisons.
|
|
182
232
|
const PROTOCOL_V2_TARGET_ID_BY_DECODED_NAME = new Map<string, number>(
|
|
183
233
|
Object.entries(ProtocolV2FirmwareTargetType).map(([key, value]) => [key, value])
|
|
184
234
|
);
|
|
@@ -204,25 +254,12 @@ const isProtocolV2ReconnectProbeError = (error: unknown) => {
|
|
|
204
254
|
);
|
|
205
255
|
};
|
|
206
256
|
|
|
207
|
-
const
|
|
208
|
-
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
209
|
-
return (
|
|
210
|
-
isProtocolV2DeviceDisconnectedError(error) ||
|
|
211
|
-
isProtocolV2ReconnectProbeError(error) ||
|
|
212
|
-
message.includes('libusb_transfer_timed_out') ||
|
|
213
|
-
(message.includes('response timeout') && message.includes('devicefirmwareupdatestatusget')) ||
|
|
214
|
-
message.includes('device not found') ||
|
|
215
|
-
message.includes('transportnotfound')
|
|
216
|
-
);
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const isProtocolV2StartUpdateTransientError = (error: unknown) => {
|
|
257
|
+
const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
|
|
220
258
|
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
221
259
|
return (
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
message.includes('
|
|
225
|
-
(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')
|
|
226
263
|
);
|
|
227
264
|
};
|
|
228
265
|
|
|
@@ -268,13 +305,6 @@ const versionArrayToNumber = (version?: IVersionArray) => {
|
|
|
268
305
|
return version[0] * 0x10000 + version[1] * 0x100 + version[2];
|
|
269
306
|
};
|
|
270
307
|
|
|
271
|
-
const versionStringToArray = (version?: string | null): IVersionArray | undefined => {
|
|
272
|
-
if (!version) return undefined;
|
|
273
|
-
const parts = version.split('.').map(part => Number(part));
|
|
274
|
-
if (parts.length !== 3 || parts.some(part => !Number.isFinite(part))) return undefined;
|
|
275
|
-
return parts as IVersionArray;
|
|
276
|
-
};
|
|
277
|
-
|
|
278
308
|
const compareProtocolV2Versions = (current?: IVersionArray, target?: IVersionArray) => {
|
|
279
309
|
const currentNumber = versionArrayToNumber(current);
|
|
280
310
|
const targetNumber = versionArrayToNumber(target);
|
|
@@ -361,6 +391,33 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
|
|
|
361
391
|
};
|
|
362
392
|
};
|
|
363
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
|
+
|
|
364
421
|
/**
|
|
365
422
|
* FirmwareUpdateV4 is the complete Protocol V2 firmware update flow.
|
|
366
423
|
*
|
|
@@ -370,9 +427,26 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
|
|
|
370
427
|
* - completion waits for target status to finish, reboots to normal, then polls DeviceInfo
|
|
371
428
|
*/
|
|
372
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
|
+
|
|
373
446
|
init() {
|
|
374
447
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
375
448
|
this.requireDeviceMode = [];
|
|
449
|
+
this.unlockPolicy = 'unlock-before-run';
|
|
376
450
|
this.useDevicePassphraseState = false;
|
|
377
451
|
this.skipForceUpdateCheck = true;
|
|
378
452
|
|
|
@@ -393,7 +467,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
393
467
|
|
|
394
468
|
validateParams(payload, [
|
|
395
469
|
{ name: 'chunkSize', type: 'number' },
|
|
396
|
-
{ name: 'resourceBinaries', type: 'array', allowEmpty: true },
|
|
397
470
|
{ name: 'forcedUpdateRes', type: 'boolean' },
|
|
398
471
|
{ name: 'bootloaderBinary', type: 'buffer' },
|
|
399
472
|
{ name: 'romloaderBinary', type: 'buffer' },
|
|
@@ -405,10 +478,64 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
405
478
|
{ name: 'se03Binary', type: 'buffer' },
|
|
406
479
|
{ name: 'se04Binary', type: 'buffer' },
|
|
407
480
|
{ name: 'firmwareType', type: 'string' },
|
|
481
|
+
{ name: 'targetsToUpdate', type: 'array', allowEmpty: true },
|
|
408
482
|
{ name: 'platform', type: 'string' },
|
|
483
|
+
{ name: 'expectedDeviceId', type: 'string' },
|
|
484
|
+
{ name: 'resourceBundleFiles', type: 'array', allowEmpty: true },
|
|
409
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
|
+
}
|
|
410
536
|
|
|
411
537
|
this.params = {
|
|
538
|
+
preparedPlan: payload.preparedPlan,
|
|
412
539
|
chunkSize: payload.chunkSize,
|
|
413
540
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
414
541
|
bootloaderBinary: payload.bootloaderBinary,
|
|
@@ -420,19 +547,29 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
420
547
|
se02Binary: payload.se02Binary,
|
|
421
548
|
se03Binary: payload.se03Binary,
|
|
422
549
|
se04Binary: payload.se04Binary,
|
|
423
|
-
|
|
550
|
+
resourceBundleFiles: payload.resourceBundleFiles,
|
|
424
551
|
firmwareType: payload.firmwareType,
|
|
552
|
+
targetsToUpdate: payload.targetsToUpdate,
|
|
553
|
+
expectedTargetVersions: payload.expectedTargetVersions,
|
|
425
554
|
platform: payload.platform,
|
|
555
|
+
expectedDeviceId: payload.expectedDeviceId,
|
|
556
|
+
artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
|
|
557
|
+
componentArtifacts: payload.componentArtifacts,
|
|
558
|
+
resourceBundleArtifacts: payload.resourceBundleArtifacts,
|
|
426
559
|
};
|
|
427
560
|
}
|
|
428
561
|
|
|
429
|
-
private getProtocolV2FirmwareChunkSize() {
|
|
562
|
+
private getProtocolV2FirmwareChunkSize(direction: 'read' | 'write' = 'write') {
|
|
430
563
|
const payloadChunkSize = Number(this.params?.chunkSize);
|
|
431
564
|
const env = DataManager.getSettings('env');
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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
|
+
}
|
|
436
573
|
if (!Number.isFinite(payloadChunkSize) || payloadChunkSize <= 0) {
|
|
437
574
|
return maxChunkSize;
|
|
438
575
|
}
|
|
@@ -443,69 +580,355 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
443
580
|
}
|
|
444
581
|
|
|
445
582
|
async run() {
|
|
446
|
-
if (!this.device.isProtocolV2()) {
|
|
447
|
-
throw ERRORS.TypedError(
|
|
448
|
-
HardwareErrorCode.RuntimeError,
|
|
449
|
-
'firmwareUpdateV4 requires a Protocol V2 device'
|
|
450
|
-
);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
583
|
Log.debug('FirmwareUpdateV4 strategy: Protocol V2');
|
|
454
584
|
return this.runProtocolV2();
|
|
455
585
|
}
|
|
456
586
|
|
|
457
587
|
private async runProtocolV2() {
|
|
588
|
+
await this.captureProtocolV2PhysicalIdentity();
|
|
458
589
|
const deviceFeatures = await this.getProtocolV2DeviceFeatures();
|
|
459
590
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
460
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
|
+
}
|
|
461
600
|
|
|
462
|
-
let resourceBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
463
601
|
let fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
464
602
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
465
603
|
let installItems: ProtocolV2InstallItem[] | undefined;
|
|
604
|
+
let resourceBundles: ProtocolV2ResourceBundleBinary[] | undefined;
|
|
466
605
|
try {
|
|
467
606
|
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
468
|
-
resourceBinaryMap = await this.prepareResourceBinaries(firmwareType, deviceFeatures);
|
|
469
607
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
470
608
|
bootloaderBinary = this.prepareBootloaderBinary();
|
|
471
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
|
+
}
|
|
472
622
|
const remoteBinaries = await this.prepareRemoteProtocolV2Binaries(
|
|
473
623
|
firmwareType,
|
|
474
624
|
deviceFeatures
|
|
475
625
|
);
|
|
476
|
-
resourceBinaryMap = remoteBinaries.resourceBinaryMap;
|
|
477
626
|
bootloaderBinary = remoteBinaries.bootloaderBinary;
|
|
478
627
|
fwBinaryMap = remoteBinaries.fwBinaryMap;
|
|
479
628
|
installItems = remoteBinaries.installItems;
|
|
480
629
|
}
|
|
630
|
+
const resourceDescriptors = this.prepareProtocolV2ResourceBundles(
|
|
631
|
+
firmwareType,
|
|
632
|
+
deviceFeatures
|
|
633
|
+
);
|
|
634
|
+
resourceBundles = resourceDescriptors?.length
|
|
635
|
+
? await this.materializeProtocolV2ResourceBundles(resourceDescriptors)
|
|
636
|
+
: undefined;
|
|
481
637
|
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
482
638
|
} catch (err) {
|
|
483
|
-
throw
|
|
639
|
+
throw normalizeFirmwarePreparationError(err);
|
|
484
640
|
}
|
|
485
641
|
|
|
486
|
-
if (
|
|
642
|
+
if (!bootloaderBinary && fwBinaryMap.length === 0 && !resourceBundles?.length) {
|
|
487
643
|
throw ERRORS.TypedError(
|
|
488
644
|
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
489
645
|
'No firmware to update'
|
|
490
646
|
);
|
|
491
647
|
}
|
|
492
648
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
await this.executeProtocolV2Update({
|
|
496
|
-
resourceBinaryMap,
|
|
649
|
+
return this.executeProtocolV2Update({
|
|
497
650
|
fwBinaryMap,
|
|
498
651
|
bootloaderBinary,
|
|
499
652
|
...(installItems ? { installItems } : undefined),
|
|
653
|
+
...(resourceBundles?.length ? { resourceBundles } : undefined),
|
|
500
654
|
});
|
|
655
|
+
}
|
|
501
656
|
|
|
502
|
-
|
|
657
|
+
private async openProtocolV2PreparedSource(artifact: FirmwareArtifactReference) {
|
|
658
|
+
const source = await openFirmwareByteSource({
|
|
659
|
+
artifact,
|
|
660
|
+
reader: this.params.artifactReader,
|
|
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
|
+
}
|
|
503
674
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
+
}
|
|
507
686
|
|
|
508
|
-
|
|
687
|
+
private async closeProtocolV2PreparedSources() {
|
|
688
|
+
const sources = this.protocolV2PreparedSources.splice(0);
|
|
689
|
+
await Promise.all(sources.map(source => source.close().catch(() => undefined)));
|
|
690
|
+
}
|
|
691
|
+
|
|
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);
|
|
509
932
|
}
|
|
510
933
|
|
|
511
934
|
private async getProtocolV2DeviceFeatures(): Promise<Features> {
|
|
@@ -519,41 +942,45 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
519
942
|
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Device features not available');
|
|
520
943
|
}
|
|
521
944
|
|
|
522
|
-
private
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
throw ERRORS.TypedError(
|
|
527
|
-
HardwareErrorCode.CallMethodInvalidParameter,
|
|
528
|
-
`Parameter [resourceBinaries.${index}] is of type invalid and should be [buffer].`
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
|
-
});
|
|
945
|
+
private getProtocolV2SerialNumber(deviceInfo: ProtocolV2DeviceInfo) {
|
|
946
|
+
const serialNumber = deviceInfo.hw?.serial_no?.trim();
|
|
947
|
+
return serialNumber || undefined;
|
|
948
|
+
}
|
|
532
949
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
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,
|
|
543
961
|
});
|
|
962
|
+
}
|
|
544
963
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
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);
|
|
554
976
|
}
|
|
555
|
-
|
|
556
|
-
|
|
977
|
+
this.protocolV2ExpectedSerialNumber = serialNumber;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
private async verifyProtocolV2ReconnectIdentity() {
|
|
981
|
+
const deviceInfo = await this.requestProtocolV2PhysicalIdentity();
|
|
982
|
+
this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
|
|
983
|
+
return deviceInfo;
|
|
557
984
|
}
|
|
558
985
|
|
|
559
986
|
private prepareBootloaderBinary(): ArrayBuffer | null {
|
|
@@ -562,25 +989,20 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
562
989
|
|
|
563
990
|
private hasExplicitProtocolV2Payload(fwBinaryMap: ProtocolV2TargetBinary[]) {
|
|
564
991
|
return (
|
|
565
|
-
!!this.params.
|
|
992
|
+
!!this.params.resourceBundleFiles?.length ||
|
|
566
993
|
!!this.params.bootloaderBinary ||
|
|
567
994
|
fwBinaryMap.length > 0
|
|
568
995
|
);
|
|
569
996
|
}
|
|
570
997
|
|
|
571
998
|
private buildProtocolV2InstallItems({
|
|
572
|
-
resourceBinaryMap,
|
|
573
999
|
bootloaderBinary,
|
|
574
1000
|
fwBinaryMap,
|
|
575
1001
|
}: {
|
|
576
|
-
resourceBinaryMap: ProtocolV2TargetBinary[];
|
|
577
1002
|
bootloaderBinary: ArrayBuffer | null;
|
|
578
1003
|
fwBinaryMap: ProtocolV2TargetBinary[];
|
|
579
1004
|
}): ProtocolV2InstallItem[] {
|
|
580
|
-
const installItems: ProtocolV2InstallItem[] =
|
|
581
|
-
...resource,
|
|
582
|
-
kind: 'resource',
|
|
583
|
-
}));
|
|
1005
|
+
const installItems: ProtocolV2InstallItem[] = [];
|
|
584
1006
|
|
|
585
1007
|
if (bootloaderBinary) {
|
|
586
1008
|
installItems.push({
|
|
@@ -630,63 +1052,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
630
1052
|
return target;
|
|
631
1053
|
}
|
|
632
1054
|
|
|
633
|
-
private getProtocolV2ComponentTargetVersion(
|
|
634
|
-
release: IFirmwareReleaseInfo,
|
|
635
|
-
component: IProtocolV2FirmwareComponent,
|
|
636
|
-
target: ProtocolV2RemoteComponentTarget
|
|
637
|
-
) {
|
|
638
|
-
if (component.version) return component.version;
|
|
639
|
-
if (target.targetId === ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER) {
|
|
640
|
-
return release.bootloaderVersion;
|
|
641
|
-
}
|
|
642
|
-
if (
|
|
643
|
-
target.targetId === ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1 ||
|
|
644
|
-
target.targetId === ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2
|
|
645
|
-
) {
|
|
646
|
-
return release.version;
|
|
647
|
-
}
|
|
648
|
-
return undefined;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
private getProtocolV2ComponentCurrentVersion(
|
|
652
|
-
features: Features,
|
|
653
|
-
target: ProtocolV2RemoteComponentTarget
|
|
654
|
-
) {
|
|
655
|
-
switch (target.targetId) {
|
|
656
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER:
|
|
657
|
-
return getDeviceBootloaderVersion(features);
|
|
658
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1:
|
|
659
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2:
|
|
660
|
-
return getDeviceFirmwareVersion(features);
|
|
661
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR:
|
|
662
|
-
return getDeviceBLEFirmwareVersion(features);
|
|
663
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01:
|
|
664
|
-
return versionStringToArray(features.se01Version);
|
|
665
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02:
|
|
666
|
-
return versionStringToArray(features.se02Version);
|
|
667
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03:
|
|
668
|
-
return versionStringToArray(features.se03Version);
|
|
669
|
-
case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04:
|
|
670
|
-
return versionStringToArray(features.se04Version);
|
|
671
|
-
default:
|
|
672
|
-
return undefined;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
private isProtocolV2ComponentVersionSatisfied(
|
|
677
|
-
release: IFirmwareReleaseInfo,
|
|
678
|
-
component: IProtocolV2FirmwareComponent,
|
|
679
|
-
target: ProtocolV2RemoteComponentTarget,
|
|
680
|
-
features: Features
|
|
681
|
-
) {
|
|
682
|
-
const targetVersion = this.getProtocolV2ComponentTargetVersion(release, component, target);
|
|
683
|
-
if (!targetVersion) return false;
|
|
684
|
-
|
|
685
|
-
const currentVersion = this.getProtocolV2ComponentCurrentVersion(features, target);
|
|
686
|
-
const compareResult = compareProtocolV2Versions(currentVersion, targetVersion);
|
|
687
|
-
return compareResult !== undefined && compareResult >= 0;
|
|
688
|
-
}
|
|
689
|
-
|
|
690
1055
|
private getProtocolV2ResourceFilePath(path: string) {
|
|
691
1056
|
if (path.startsWith('vol')) return path;
|
|
692
1057
|
if (path.startsWith('/')) return `vol0:${path}`;
|
|
@@ -709,7 +1074,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
709
1074
|
return null;
|
|
710
1075
|
}
|
|
711
1076
|
|
|
712
|
-
const chunkSize = this.getProtocolV2FirmwareChunkSize();
|
|
1077
|
+
const chunkSize = this.getProtocolV2FirmwareChunkSize('read');
|
|
713
1078
|
const chunks: Uint8Array[] = [];
|
|
714
1079
|
let offset = 0;
|
|
715
1080
|
while (offset < PROTOCOL_V2_OKPP_HEADER_SIZE) {
|
|
@@ -738,95 +1103,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
738
1103
|
return parseProtocolV2OkppHeader(headerBytes);
|
|
739
1104
|
}
|
|
740
1105
|
|
|
741
|
-
private async isProtocolV2ResourcePackageMatched(
|
|
742
|
-
pkg: IProtocolV2ResourceManifestPackage,
|
|
743
|
-
manifestVersion?: IVersionArray
|
|
744
|
-
) {
|
|
745
|
-
try {
|
|
746
|
-
const header = await this.readProtocolV2DeviceFileHeader(pkg.path);
|
|
747
|
-
if (!header) return false;
|
|
748
|
-
|
|
749
|
-
const expectedType = pkg.type ?? 'RESC';
|
|
750
|
-
const expectedVersion = pkg.version ?? manifestVersion;
|
|
751
|
-
if (header.type !== expectedType) return false;
|
|
752
|
-
if (expectedVersion && compareProtocolV2Versions(header.version, expectedVersion) !== 0) {
|
|
753
|
-
return false;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
const expectedPayloadHash = normalizeProtocolV2Hex(pkg.payloadHash);
|
|
757
|
-
if (expectedPayloadHash && header.payloadHash !== expectedPayloadHash) return false;
|
|
758
|
-
|
|
759
|
-
const expectedHeaderHash = normalizeProtocolV2Hex(pkg.headerHash);
|
|
760
|
-
if (expectedHeaderHash && header.headerHash !== expectedHeaderHash) return false;
|
|
761
|
-
|
|
762
|
-
return true;
|
|
763
|
-
} catch (error) {
|
|
764
|
-
Log.log(`Protocol V2 resource package check failed for ${pkg.path}: `, error);
|
|
765
|
-
return false;
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
private async isProtocolV2ResourceManifestSatisfied(
|
|
770
|
-
manifest: IFirmwareReleaseInfo['resourceManifest']
|
|
771
|
-
) {
|
|
772
|
-
if (!manifest?.packages?.length) return false;
|
|
773
|
-
|
|
774
|
-
for (const pkg of manifest.packages) {
|
|
775
|
-
if (!(await this.isProtocolV2ResourcePackageMatched(pkg, manifest.version))) {
|
|
776
|
-
return false;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
return true;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
private getProtocolV2ResourceManifest(
|
|
783
|
-
release: IFirmwareReleaseInfo,
|
|
784
|
-
component: IProtocolV2FirmwareComponent
|
|
785
|
-
) {
|
|
786
|
-
return component.resourceManifest ?? release.resourceManifest;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
private getProtocolV2ResourceComponentFileName(key: string) {
|
|
790
|
-
const safeKey = key.replace(/[^a-z0-9_-]/gi, '_') || 'resource';
|
|
791
|
-
return `resource-${safeKey}.bin`;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
private async shouldInstallRemoteProtocolV2Component(
|
|
795
|
-
release: IFirmwareReleaseInfo,
|
|
796
|
-
key: string,
|
|
797
|
-
component: IProtocolV2FirmwareComponent,
|
|
798
|
-
target: ProtocolV2RemoteComponentTarget,
|
|
799
|
-
features: Features
|
|
800
|
-
) {
|
|
801
|
-
if (target.kind === 'resource') {
|
|
802
|
-
if (
|
|
803
|
-
this.params.forcedUpdateRes ||
|
|
804
|
-
features.bootloaderMode ||
|
|
805
|
-
features.mode === 'bootloader'
|
|
806
|
-
) {
|
|
807
|
-
return true;
|
|
808
|
-
}
|
|
809
|
-
const resourceMatched = await this.isProtocolV2ResourceManifestSatisfied(
|
|
810
|
-
this.getProtocolV2ResourceManifest(release, component)
|
|
811
|
-
);
|
|
812
|
-
if (resourceMatched) {
|
|
813
|
-
Log.log(`[FirmwareUpdateV4] skip Protocol V2 resource component ${key}; manifest matched`);
|
|
814
|
-
}
|
|
815
|
-
return !resourceMatched;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
const versionSatisfied = this.isProtocolV2ComponentVersionSatisfied(
|
|
819
|
-
release,
|
|
820
|
-
component,
|
|
821
|
-
target,
|
|
822
|
-
features
|
|
823
|
-
);
|
|
824
|
-
if (versionSatisfied) {
|
|
825
|
-
Log.log(`[FirmwareUpdateV4] skip Protocol V2 component ${key}; version is up to date`);
|
|
826
|
-
}
|
|
827
|
-
return !versionSatisfied;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
1106
|
private async downloadRemoteProtocolV2Component(
|
|
831
1107
|
key: string,
|
|
832
1108
|
component: IProtocolV2FirmwareComponent
|
|
@@ -840,23 +1116,37 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
840
1116
|
}
|
|
841
1117
|
|
|
842
1118
|
const { binary } = await getSysResourceBinary(component.url);
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
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
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
return {
|
|
1136
|
+
...target,
|
|
1137
|
+
binary,
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
private async prepareRemoteProtocolV2Binaries(firmwareType: EFirmwareType, features: Features) {
|
|
850
1142
|
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
851
1143
|
|
|
852
|
-
const resourceBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
853
1144
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
854
1145
|
const fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
855
1146
|
const installItems: ProtocolV2InstallItem[] = [];
|
|
856
1147
|
|
|
857
1148
|
if (!release) {
|
|
858
1149
|
return {
|
|
859
|
-
resourceBinaryMap,
|
|
860
1150
|
bootloaderBinary,
|
|
861
1151
|
fwBinaryMap,
|
|
862
1152
|
installItems,
|
|
@@ -864,27 +1154,17 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
864
1154
|
}
|
|
865
1155
|
|
|
866
1156
|
const entries = this.getRemoteComponentEntries(release);
|
|
1157
|
+
const targetsToUpdate = new Set(this.params.targetsToUpdate ?? []);
|
|
867
1158
|
|
|
868
1159
|
for (const [key, component] of entries) {
|
|
869
|
-
const
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
features
|
|
876
|
-
);
|
|
877
|
-
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)) {
|
|
878
1166
|
const remoteBinary = await this.downloadRemoteProtocolV2Component(key, component);
|
|
879
|
-
if (remoteBinary.kind === '
|
|
880
|
-
const binaryEntry = {
|
|
881
|
-
fileName: this.getProtocolV2ResourceComponentFileName(key),
|
|
882
|
-
binary: remoteBinary.binary,
|
|
883
|
-
targetId: remoteBinary.targetId,
|
|
884
|
-
};
|
|
885
|
-
resourceBinaryMap.push(binaryEntry);
|
|
886
|
-
installItems.push({ ...binaryEntry, kind: remoteBinary.kind });
|
|
887
|
-
} else if (remoteBinary.kind === 'bootloader') {
|
|
1167
|
+
if (remoteBinary.kind === 'bootloader') {
|
|
888
1168
|
bootloaderBinary = remoteBinary.binary;
|
|
889
1169
|
installItems.push({
|
|
890
1170
|
fileName: remoteBinary.fileName,
|
|
@@ -905,23 +1185,189 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
905
1185
|
}
|
|
906
1186
|
|
|
907
1187
|
return {
|
|
908
|
-
resourceBinaryMap,
|
|
909
1188
|
bootloaderBinary,
|
|
910
1189
|
fwBinaryMap,
|
|
911
1190
|
installItems,
|
|
912
1191
|
};
|
|
913
1192
|
}
|
|
914
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
|
+
|
|
915
1340
|
private isProtocolV2BootloaderMode() {
|
|
916
1341
|
if (typeof this.device.isBootloader === 'function') {
|
|
917
1342
|
return this.device.isBootloader();
|
|
918
1343
|
}
|
|
919
|
-
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';
|
|
920
1358
|
}
|
|
921
1359
|
|
|
922
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
|
+
}
|
|
923
1368
|
if (this.isProtocolV2BootloaderMode()) {
|
|
924
|
-
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;
|
|
925
1371
|
return false;
|
|
926
1372
|
}
|
|
927
1373
|
|
|
@@ -931,6 +1377,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
931
1377
|
this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
|
|
932
1378
|
await wait(1000);
|
|
933
1379
|
await this.waitForProtocolV2BootloaderMode();
|
|
1380
|
+
this.protocolV2ExecutionInLoader = true;
|
|
934
1381
|
return true;
|
|
935
1382
|
} catch (error) {
|
|
936
1383
|
if (error instanceof HardwareError) {
|
|
@@ -955,12 +1402,19 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
955
1402
|
commands: this.device.getCommands(),
|
|
956
1403
|
timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
|
|
957
1404
|
});
|
|
958
|
-
|
|
959
|
-
|
|
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') {
|
|
960
1411
|
return features;
|
|
961
1412
|
}
|
|
962
1413
|
lastError = new Error('Protocol V2 device is reachable but is not in bootloader mode');
|
|
963
1414
|
} catch (error) {
|
|
1415
|
+
if (this.isProtocolV2ReconnectIdentityError(error)) {
|
|
1416
|
+
throw error;
|
|
1417
|
+
}
|
|
964
1418
|
lastError = error;
|
|
965
1419
|
Log.log('Protocol V2 bootloader mode not ready, polling reconnect: ', error);
|
|
966
1420
|
}
|
|
@@ -976,8 +1430,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
976
1430
|
}
|
|
977
1431
|
|
|
978
1432
|
/**
|
|
979
|
-
*
|
|
980
|
-
*
|
|
1433
|
+
* Collect explicit target binaries grouped by DeviceFirmwareTargetType.
|
|
1434
|
+
* Filenames are display-only staging paths because target_id is explicit.
|
|
981
1435
|
*/
|
|
982
1436
|
private collectExplicitTargetBinaries() {
|
|
983
1437
|
const entries: ProtocolV2TargetBinary[] = [];
|
|
@@ -1013,254 +1467,458 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1013
1467
|
return entries;
|
|
1014
1468
|
}
|
|
1015
1469
|
|
|
1470
|
+
private buildProtocolV2ExecutionPhases({
|
|
1471
|
+
installSources,
|
|
1472
|
+
resourceSources,
|
|
1473
|
+
}: {
|
|
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
|
+
}
|
|
1515
|
+
|
|
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'
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
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
|
+
}
|
|
1561
|
+
|
|
1016
1562
|
private async executeProtocolV2Update({
|
|
1017
|
-
resourceBinaryMap,
|
|
1018
1563
|
fwBinaryMap,
|
|
1019
1564
|
bootloaderBinary,
|
|
1020
1565
|
installItems,
|
|
1566
|
+
resourceBundles,
|
|
1021
1567
|
}: {
|
|
1022
|
-
resourceBinaryMap?: ProtocolV2TargetBinary[];
|
|
1023
1568
|
fwBinaryMap?: ProtocolV2TargetBinary[];
|
|
1024
1569
|
bootloaderBinary?: ArrayBuffer | null;
|
|
1025
1570
|
installItems?: ProtocolV2InstallItem[];
|
|
1571
|
+
resourceBundles?: ProtocolV2ResourceBundleBinary[];
|
|
1026
1572
|
}) {
|
|
1027
|
-
const
|
|
1573
|
+
const memoryInstallItems =
|
|
1028
1574
|
installItems ??
|
|
1029
1575
|
this.buildProtocolV2InstallItems({
|
|
1030
|
-
resourceBinaryMap: resourceBinaryMap ?? [],
|
|
1031
|
-
bootloaderBinary: bootloaderBinary ?? null,
|
|
1032
1576
|
fwBinaryMap: fwBinaryMap ?? [],
|
|
1577
|
+
bootloaderBinary: bootloaderBinary ?? null,
|
|
1033
1578
|
});
|
|
1034
|
-
let totalSize = 0;
|
|
1035
|
-
let processedSize = 0;
|
|
1036
|
-
let transferredSize = 0;
|
|
1037
|
-
|
|
1038
|
-
for (const item of orderedInstallItems) totalSize += item.binary.byteLength;
|
|
1039
|
-
|
|
1040
|
-
this.postTipMessage(FirmwareUpdateTipMessage.StartTransferData);
|
|
1041
|
-
const transferStartTime = Date.now();
|
|
1042
|
-
const transferTransport = this.getProtocolV2FirmwareTransferTransport();
|
|
1043
|
-
const chunkSize = this.getProtocolV2FirmwareChunkSize();
|
|
1044
|
-
const onTransferredBytes = (bytes: number) => {
|
|
1045
|
-
transferredSize = bytes;
|
|
1046
|
-
};
|
|
1047
|
-
Log.log(
|
|
1048
|
-
`[FirmwareUpdateV4] transfer started transport=${transferTransport} total=${totalSize} bytes chunk=${chunkSize} bytes`
|
|
1049
|
-
);
|
|
1050
|
-
|
|
1051
|
-
const stagedInstallTargets: ProtocolV2InstallTarget[] = [];
|
|
1052
|
-
|
|
1053
1579
|
try {
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
filePath,
|
|
1062
|
-
processedSize,
|
|
1063
|
-
totalSize,
|
|
1064
|
-
onTransferredBytes,
|
|
1065
|
-
});
|
|
1066
|
-
transferredSize = processedSize;
|
|
1067
|
-
|
|
1068
|
-
stagedInstallTargets.push({
|
|
1069
|
-
...item,
|
|
1070
|
-
path: filePath,
|
|
1071
|
-
});
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
if (totalSize > 0) {
|
|
1075
|
-
this.postProgressMessage(100, 'transferData');
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
const elapsedMs = Date.now() - transferStartTime;
|
|
1079
|
-
Log.log(
|
|
1080
|
-
`[FirmwareUpdateV4] transfer finished transport=${transferTransport} bytes=${totalSize} elapsed=${(
|
|
1081
|
-
elapsedMs / 1000
|
|
1082
|
-
).toFixed(2)}s speed=${formatProtocolV2TransferSpeed(totalSize, elapsedMs)} KB/s`
|
|
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
|
+
}))
|
|
1083
1587
|
);
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
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
|
+
}))
|
|
1090
1597
|
);
|
|
1091
|
-
|
|
1598
|
+
return await this.executeProtocolV2Phases({
|
|
1599
|
+
installSources,
|
|
1600
|
+
resourceSources,
|
|
1601
|
+
});
|
|
1602
|
+
} finally {
|
|
1603
|
+
await this.closeProtocolV2PreparedSources();
|
|
1092
1604
|
}
|
|
1605
|
+
}
|
|
1093
1606
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
};
|
|
1104
|
-
|
|
1105
|
-
for (const item of stagedInstallTargets) {
|
|
1106
|
-
const target = {
|
|
1107
|
-
target_id: item.targetId,
|
|
1108
|
-
path: item.path,
|
|
1109
|
-
};
|
|
1110
|
-
if (item.kind === 'resource') {
|
|
1111
|
-
await flushFirmwareTargets();
|
|
1112
|
-
const resourceTargets = [target];
|
|
1113
|
-
Log.log(
|
|
1114
|
-
`[FirmwareUpdateV4] DeviceFirmwareUpdateRequest resources=${JSON.stringify(
|
|
1115
|
-
resourceTargets
|
|
1116
|
-
)}`
|
|
1117
|
-
);
|
|
1118
|
-
const startResponse = await this.protocolV2StartFirmwareUpdate({
|
|
1119
|
-
targets: resourceTargets,
|
|
1120
|
-
});
|
|
1121
|
-
await this.waitForProtocolV2FirmwareUpdateComplete(resourceTargets, startResponse);
|
|
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`);
|
|
1122
1616
|
} else {
|
|
1123
|
-
|
|
1617
|
+
resourcesToSync.push(resource);
|
|
1618
|
+
totalSize += resource.source.size;
|
|
1124
1619
|
}
|
|
1125
1620
|
}
|
|
1126
1621
|
|
|
1127
|
-
|
|
1128
|
-
|
|
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);
|
|
1632
|
+
}
|
|
1129
1633
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
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,
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1133
1649
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1650
|
+
if (totalSize > 0) {
|
|
1651
|
+
this.postProgressMessage(100, 'transferData');
|
|
1652
|
+
}
|
|
1653
|
+
if (stagedInstallTargets.length === 0) {
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
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);
|
|
1144
1664
|
}
|
|
1145
1665
|
|
|
1146
|
-
private async
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
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
|
+
}
|
|
1154
1716
|
}
|
|
1717
|
+
}
|
|
1718
|
+
throw ERRORS.TypedError(
|
|
1719
|
+
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1720
|
+
`transfer data error: ${getProtocolV2UnknownErrorText(lastError)}`
|
|
1155
1721
|
);
|
|
1156
1722
|
}
|
|
1157
1723
|
|
|
1158
|
-
private
|
|
1159
|
-
return
|
|
1724
|
+
private getProtocolV2InstallItemStagingPath(item: Pick<ProtocolV2InstallItem, 'fileName'>) {
|
|
1725
|
+
return `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${item.fileName}`;
|
|
1160
1726
|
}
|
|
1161
1727
|
|
|
1162
|
-
private async
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
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
|
+
);
|
|
1172
1738
|
}
|
|
1173
|
-
return false;
|
|
1174
1739
|
}
|
|
1175
1740
|
|
|
1176
1741
|
private assertProtocolV2TargetStatus(
|
|
1177
1742
|
statusTargets: ProtocolV2FirmwareUpdateStatusTarget[],
|
|
1178
|
-
expectedTargetIds: Set<number
|
|
1743
|
+
expectedTargetIds: Set<number>,
|
|
1744
|
+
expectedPaths = new Map<number, string>()
|
|
1179
1745
|
) {
|
|
1746
|
+
Log.log(
|
|
1747
|
+
`[FirmwareUpdateV4] DeviceFirmwareUpdateStatus records=${JSON.stringify(statusTargets)}`
|
|
1748
|
+
);
|
|
1180
1749
|
const failedTarget = statusTargets.find(
|
|
1181
1750
|
target =>
|
|
1182
1751
|
expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
|
|
1183
1752
|
isProtocolV2TargetStatusFailed(target.status)
|
|
1184
1753
|
);
|
|
1185
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}`);
|
|
1186
1762
|
throw ERRORS.TypedError(
|
|
1187
1763
|
HardwareErrorCode.FirmwareError,
|
|
1188
|
-
`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
|
+
}`
|
|
1189
1769
|
);
|
|
1190
1770
|
}
|
|
1191
1771
|
|
|
1192
|
-
const
|
|
1193
|
-
target
|
|
1194
|
-
|
|
1195
|
-
|
|
1772
|
+
const matchingTargets = statusTargets.filter(target =>
|
|
1773
|
+
expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1)
|
|
1774
|
+
);
|
|
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)
|
|
1196
1792
|
);
|
|
1197
|
-
|
|
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');
|
|
1198
1824
|
return true;
|
|
1199
1825
|
}
|
|
1200
1826
|
|
|
1201
|
-
|
|
1202
|
-
target =>
|
|
1203
|
-
expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
|
|
1827
|
+
if (expectedTargetIds.size > 0 && matchingTargets.length > 0) {
|
|
1828
|
+
const hasInProgressTarget = matchingTargets.some(target =>
|
|
1204
1829
|
isProtocolV2TargetStatusInProgress(target.status)
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
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');
|
|
1208
1838
|
}
|
|
1209
1839
|
|
|
1210
1840
|
return false;
|
|
1211
1841
|
}
|
|
1212
1842
|
|
|
1213
1843
|
private async waitForProtocolV2FirmwareUpdateComplete(
|
|
1214
|
-
targets: Array<{ target_id: number; path: string }
|
|
1215
|
-
startResponse?: ProtocolV2FirmwareUpdateStartResponse
|
|
1844
|
+
targets: Array<{ target_id: number; path: string }>
|
|
1216
1845
|
) {
|
|
1846
|
+
this.protocolV2FinalStatusVerified = false;
|
|
1217
1847
|
const expectedTargetIds = new Set(targets.map(target => target.target_id));
|
|
1218
|
-
|
|
1219
|
-
const statusTargets = (startResponse.message.records ??
|
|
1220
|
-
[]) as ProtocolV2FirmwareUpdateStatusTarget[];
|
|
1221
|
-
if (this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds)) {
|
|
1222
|
-
return;
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1848
|
+
const expectedPaths = new Map(targets.map(target => [target.target_id, target.path]));
|
|
1226
1849
|
const startTime = Date.now();
|
|
1227
1850
|
let lastError: unknown;
|
|
1228
1851
|
|
|
1229
1852
|
while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
|
|
1230
1853
|
try {
|
|
1231
|
-
|
|
1232
|
-
const
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
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
|
+
}
|
|
1236
1906
|
}
|
|
1237
1907
|
} catch (error) {
|
|
1238
1908
|
lastError = error;
|
|
1909
|
+
if (this.isProtocolV2ReconnectIdentityError(error)) {
|
|
1910
|
+
throw error;
|
|
1911
|
+
}
|
|
1239
1912
|
if (error instanceof HardwareError && error.errorCode === HardwareErrorCode.FirmwareError) {
|
|
1240
1913
|
throw error;
|
|
1241
1914
|
}
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
return;
|
|
1248
|
-
}
|
|
1249
|
-
} catch (reconnectError) {
|
|
1250
|
-
lastError = reconnectError;
|
|
1251
|
-
Log.log(
|
|
1252
|
-
'Protocol V2 firmware install reconnect/normal-mode probe failed: ',
|
|
1253
|
-
reconnectError
|
|
1254
|
-
);
|
|
1255
|
-
}
|
|
1256
|
-
try {
|
|
1257
|
-
await this.pingProtocolV2Device();
|
|
1258
|
-
Log.log('Protocol V2 firmware status unavailable, Ping is ready');
|
|
1259
|
-
} catch (pingError) {
|
|
1260
|
-
lastError = pingError;
|
|
1261
|
-
Log.log('Protocol V2 firmware install Ping polling failed: ', pingError);
|
|
1262
|
-
}
|
|
1915
|
+
if (
|
|
1916
|
+
error instanceof HardwareError &&
|
|
1917
|
+
error.params?.firmwareUpdateCode === 'FirmwareInstallStatusUnavailable'
|
|
1918
|
+
) {
|
|
1919
|
+
throw error;
|
|
1263
1920
|
}
|
|
1921
|
+
Log.log('Protocol V2 firmware install device readiness probe failed: ', error);
|
|
1264
1922
|
}
|
|
1265
1923
|
await wait(1000);
|
|
1266
1924
|
}
|
|
@@ -1272,27 +1930,31 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1272
1930
|
}
|
|
1273
1931
|
|
|
1274
1932
|
private async exitProtocolV2BootloaderToNormal() {
|
|
1275
|
-
this.
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
Log.log('Protocol V2 device is already in normal mode, skip normal reboot');
|
|
1280
|
-
return;
|
|
1281
|
-
}
|
|
1282
|
-
} catch (error) {
|
|
1283
|
-
Log.log('Protocol V2 normal-mode probe before reboot failed: ', error);
|
|
1284
|
-
}
|
|
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.
|
|
1285
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;
|
|
1286
1947
|
}
|
|
1287
1948
|
|
|
1288
1949
|
private async waitForProtocolV2FinalFeatures() {
|
|
1289
1950
|
const features = await this.waitForProtocolV2ReconnectAndFeatures(
|
|
1290
|
-
|
|
1951
|
+
PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT
|
|
1291
1952
|
);
|
|
1292
1953
|
|
|
1293
1954
|
const bootloaderVersion = getDeviceBootloaderVersion(features).join('.');
|
|
1294
1955
|
const bleVersion = getDeviceBLEFirmwareVersion(features).join('.');
|
|
1295
1956
|
const firmwareVersion = getDeviceFirmwareVersion(features).join('.');
|
|
1957
|
+
this.protocolV2LatestFinalFeatures = features;
|
|
1296
1958
|
if (firmwareVersion === '0.0.0') {
|
|
1297
1959
|
Log.warn(
|
|
1298
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.'
|
|
@@ -1306,6 +1968,17 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1306
1968
|
};
|
|
1307
1969
|
}
|
|
1308
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
|
+
|
|
1309
1982
|
private async waitForProtocolV2ReconnectAndFeatures(timeout: number) {
|
|
1310
1983
|
const startTime = Date.now();
|
|
1311
1984
|
let lastError: unknown;
|
|
@@ -1316,11 +1989,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1316
1989
|
const deviceInfo = await requestProtocolV2DeviceInfo({
|
|
1317
1990
|
commands: this.device.getCommands(),
|
|
1318
1991
|
timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
|
|
1319
|
-
//
|
|
1992
|
+
// Completion needs target versions only; keep scope aligned with the request.
|
|
1320
1993
|
request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
|
|
1321
1994
|
});
|
|
1322
|
-
|
|
1323
|
-
|
|
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) {
|
|
1324
2001
|
throw ERRORS.TypedError(
|
|
1325
2002
|
HardwareErrorCode.DeviceNotFound,
|
|
1326
2003
|
'Protocol V2 device is still in bootloader mode'
|
|
@@ -1328,6 +2005,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1328
2005
|
}
|
|
1329
2006
|
return features;
|
|
1330
2007
|
} catch (error) {
|
|
2008
|
+
if (this.isProtocolV2ReconnectIdentityError(error)) {
|
|
2009
|
+
throw error;
|
|
2010
|
+
}
|
|
1331
2011
|
lastError = error;
|
|
1332
2012
|
Log.log('Protocol V2 normal mode not ready, polling Ping: ', error);
|
|
1333
2013
|
await wait(1000);
|
|
@@ -1362,15 +2042,14 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1362
2042
|
},
|
|
1363
2043
|
true
|
|
1364
2044
|
);
|
|
1365
|
-
await this.
|
|
2045
|
+
await this.ensureProtocolV2DeviceAcquired();
|
|
1366
2046
|
this.device.commands.disposed = false;
|
|
1367
2047
|
this.device.getCommands().mainId = this.device.mainId ?? '';
|
|
1368
|
-
await this.device.initialize();
|
|
1369
2048
|
return;
|
|
1370
2049
|
}
|
|
1371
2050
|
|
|
1372
|
-
// App
|
|
1373
|
-
//
|
|
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.
|
|
1374
2053
|
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
|
|
1375
2054
|
connectProtocol: PROTOCOL_V2_CONNECT_PROTOCOL,
|
|
1376
2055
|
});
|
|
@@ -1383,86 +2062,30 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1383
2062
|
deviceList[0].getConnectId()
|
|
1384
2063
|
);
|
|
1385
2064
|
this.device.updateFromCache(deviceList[0]);
|
|
1386
|
-
await this.
|
|
2065
|
+
await this.ensureProtocolV2DeviceAcquired();
|
|
1387
2066
|
this.device.commands.disposed = false;
|
|
1388
2067
|
this.device.getCommands().mainId = this.device.mainId ?? '';
|
|
1389
|
-
await this.device.initialize();
|
|
1390
2068
|
}
|
|
1391
2069
|
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
processedSize?: number;
|
|
1401
|
-
totalSize?: number;
|
|
1402
|
-
onTransferredBytes?: (transferredBytes: number) => void;
|
|
1403
|
-
}) {
|
|
1404
|
-
const chunkSize = this.getProtocolV2FirmwareChunkSize();
|
|
1405
|
-
let offset = 0;
|
|
1406
|
-
const getUploadProgress = (fileOffset: number) => {
|
|
1407
|
-
if (totalSize !== undefined && processedSize !== undefined) {
|
|
1408
|
-
return Math.min(Math.ceil(((processedSize + fileOffset) / totalSize) * 100), 99);
|
|
1409
|
-
}
|
|
1410
|
-
return Math.min(Math.ceil((fileOffset / payload.byteLength) * 100), 99);
|
|
1411
|
-
};
|
|
1412
|
-
|
|
1413
|
-
while (offset < payload.byteLength) {
|
|
1414
|
-
const chunkEnd = Math.min(offset + chunkSize, payload.byteLength);
|
|
1415
|
-
const chunkLength = chunkEnd - offset;
|
|
1416
|
-
const chunk = payload.slice(offset, chunkEnd);
|
|
1417
|
-
const overwrite = offset === 0;
|
|
1418
|
-
const progress = getProtocolV2DeviceTransferProgress(
|
|
1419
|
-
(processedSize ?? 0) + offset,
|
|
1420
|
-
(processedSize ?? 0) + chunkEnd,
|
|
1421
|
-
totalSize ?? payload.byteLength
|
|
1422
|
-
);
|
|
1423
|
-
|
|
1424
|
-
const writeRes = await this.fileWriteWithRetry(
|
|
1425
|
-
filePath,
|
|
1426
|
-
payload.byteLength,
|
|
1427
|
-
offset,
|
|
1428
|
-
chunk,
|
|
1429
|
-
overwrite,
|
|
1430
|
-
progress
|
|
1431
|
-
);
|
|
1432
|
-
const processedByte = Number(writeRes.message.processed_byte);
|
|
1433
|
-
const nextOffset =
|
|
1434
|
-
Number.isFinite(processedByte) && processedByte > offset
|
|
1435
|
-
? processedByte
|
|
1436
|
-
: offset + chunkLength;
|
|
1437
|
-
if (nextOffset <= offset || nextOffset > payload.byteLength) {
|
|
1438
|
-
throw ERRORS.TypedError(
|
|
1439
|
-
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1440
|
-
`invalid processed_byte ${writeRes.message.processed_byte} for offset ${offset}`
|
|
1441
|
-
);
|
|
1442
|
-
}
|
|
1443
|
-
offset = nextOffset;
|
|
1444
|
-
onTransferredBytes?.((processedSize ?? 0) + offset);
|
|
1445
|
-
this.postProgressMessage(getUploadProgress(offset), 'transferData');
|
|
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;
|
|
1446
2078
|
}
|
|
1447
|
-
|
|
1448
|
-
|
|
2079
|
+
await this.device.acquire(PROTOCOL_V2_CONNECT_PROTOCOL, {
|
|
2080
|
+
throwOnRunPromiseError: true,
|
|
2081
|
+
});
|
|
1449
2082
|
}
|
|
1450
2083
|
|
|
1451
|
-
private
|
|
1452
|
-
|
|
1453
|
-
if (env && DataManager.isBleConnect(env)) {
|
|
1454
|
-
return 'BLE';
|
|
1455
|
-
}
|
|
1456
|
-
if (
|
|
1457
|
-
env &&
|
|
1458
|
-
(DataManager.isBrowserWebUsb(env) || DataManager.isDesktopWebUsb(env) || env === 'web')
|
|
1459
|
-
) {
|
|
1460
|
-
return 'WebUSB';
|
|
1461
|
-
}
|
|
1462
|
-
return env ?? 'unknown';
|
|
2084
|
+
private isProtocolV2ReconnectIdentityError(error: unknown) {
|
|
2085
|
+
return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity');
|
|
1463
2086
|
}
|
|
1464
2087
|
|
|
1465
|
-
private async
|
|
2088
|
+
private async fileWriteChunk(
|
|
1466
2089
|
filePath: string,
|
|
1467
2090
|
totalFileSize: number,
|
|
1468
2091
|
offset: number,
|
|
@@ -1470,57 +2093,38 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1470
2093
|
overwrite: boolean,
|
|
1471
2094
|
progress: number | null
|
|
1472
2095
|
): Promise<TypedResponseMessage<'FilesystemFile'>> {
|
|
1473
|
-
const
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
if (writeRes.type
|
|
1487
|
-
if ((writeRes as any).
|
|
1488
|
-
|
|
1489
|
-
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, SESSION_ERROR);
|
|
1490
|
-
}
|
|
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);
|
|
1491
2112
|
}
|
|
1492
|
-
throw ERRORS.TypedError(
|
|
1493
|
-
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1494
|
-
'transfer data error'
|
|
1495
|
-
);
|
|
1496
2113
|
}
|
|
1497
|
-
|
|
1498
|
-
}
|
|
2114
|
+
throw ERRORS.TypedError(HardwareErrorCode.EmmcFileWriteFirmwareError, 'transfer data error');
|
|
2115
|
+
}
|
|
2116
|
+
return writeRes;
|
|
2117
|
+
}
|
|
1499
2118
|
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
return result;
|
|
1505
|
-
} catch (error) {
|
|
1506
|
-
Log.error(`fileWrite error: `, error);
|
|
1507
|
-
retryCount--;
|
|
1508
|
-
if (retryCount === 0) {
|
|
1509
|
-
throw ERRORS.TypedError(
|
|
1510
|
-
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
1511
|
-
'transfer data error'
|
|
1512
|
-
);
|
|
1513
|
-
}
|
|
1514
|
-
const env = DataManager.getSettings('env');
|
|
1515
|
-
if (DataManager.isBleConnect(env)) {
|
|
1516
|
-
await wait(3000);
|
|
1517
|
-
await this.acquireProtocolV2BleDevice();
|
|
1518
|
-
await this.device.initialize();
|
|
1519
|
-
}
|
|
1520
|
-
await wait(2000);
|
|
1521
|
-
}
|
|
2119
|
+
private async recoverProtocolV2FileTransfer() {
|
|
2120
|
+
const env = DataManager.getSettings('env');
|
|
2121
|
+
if (DataManager.isBleConnect(env)) {
|
|
2122
|
+
await wait(3000);
|
|
1522
2123
|
}
|
|
1523
|
-
|
|
2124
|
+
await this.reconnectProtocolV2Device();
|
|
2125
|
+
await this.verifyProtocolV2ReconnectIdentity();
|
|
2126
|
+
await this.device.initialize();
|
|
2127
|
+
await wait(2000);
|
|
1524
2128
|
}
|
|
1525
2129
|
|
|
1526
2130
|
private async acquireProtocolV2BleDevice() {
|
|
@@ -1538,35 +2142,16 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1538
2142
|
targets: Array<{ target_id: number; path: string }>;
|
|
1539
2143
|
}) {
|
|
1540
2144
|
const commands = this.device.getCommands();
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
{
|
|
1550
|
-
intermediateTypes: ['DeviceFirmwareUpdateStatus'],
|
|
1551
|
-
timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT,
|
|
1552
|
-
onIntermediateResponse: (response: { type?: string }) => {
|
|
1553
|
-
if (response.type === 'DeviceFirmwareUpdateStatus') {
|
|
1554
|
-
this.postProgressMessage(99, 'installingFirmware');
|
|
1555
|
-
}
|
|
1556
|
-
},
|
|
1557
|
-
}
|
|
1558
|
-
);
|
|
1559
|
-
} catch (error) {
|
|
1560
|
-
if (isProtocolV2StartUpdateTransientError(error)) {
|
|
1561
|
-
Log.log(
|
|
1562
|
-
'Protocol V2 firmware update request did not return; continue status polling',
|
|
1563
|
-
error
|
|
1564
|
-
);
|
|
1565
|
-
} else {
|
|
1566
|
-
throw error;
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
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.
|
|
1569
2153
|
this.postTipMessage(FirmwareUpdateTipMessage.FirmwareUpdating);
|
|
2154
|
+
this.postProgressMessage(0, 'installingFirmware');
|
|
1570
2155
|
return response;
|
|
1571
2156
|
}
|
|
1572
2157
|
|
|
@@ -1576,9 +2161,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1576
2161
|
const res = await typedCall('DeviceReboot', 'Success', {
|
|
1577
2162
|
reboot_type: rebootType,
|
|
1578
2163
|
});
|
|
2164
|
+
this.device.markProtocolV2Reboot(rebootType);
|
|
1579
2165
|
return res.message;
|
|
1580
2166
|
} catch (error) {
|
|
1581
2167
|
if (isProtocolV2DeviceDisconnectedError(error) || isProtocolV2ReconnectProbeError(error)) {
|
|
2168
|
+
this.device.markProtocolV2Reboot(rebootType);
|
|
1582
2169
|
return { message: 'Device rebooted successfully' };
|
|
1583
2170
|
}
|
|
1584
2171
|
throw error;
|