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