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