@onekeyfe/hd-core 1.2.0-alpha.6 → 1.2.0-alpha.61

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.
Files changed (734) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +390 -0
  2. package/__tests__/DeviceCommands.test.ts +563 -0
  3. package/__tests__/DeviceEventRegistration.test.ts +49 -0
  4. package/__tests__/chain-params-onekey-compatibility.test.ts +229 -0
  5. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +477 -0
  6. package/__tests__/connectSettings.test.ts +19 -0
  7. package/__tests__/core-dispose.test.ts +34 -0
  8. package/__tests__/core-error-output.test.ts +39 -0
  9. package/__tests__/core-initialization.test.ts +23 -0
  10. package/__tests__/device-connector-protocol.test.ts +81 -0
  11. package/__tests__/device-features-state.test.ts +78 -0
  12. package/__tests__/device-identity.test.ts +52 -0
  13. package/__tests__/device-lifecycle-events.test.ts +351 -0
  14. package/__tests__/device-pool-state.test.ts +166 -0
  15. package/__tests__/device-settings.test.ts +437 -0
  16. package/__tests__/device-state-contract.test.ts +28 -0
  17. package/__tests__/device-state-events.test.ts +286 -0
  18. package/__tests__/device-state-mapper.test.ts +273 -0
  19. package/__tests__/device-state-projector.test.ts +94 -0
  20. package/__tests__/device-state-store.test.ts +82 -0
  21. package/__tests__/device-utils.test.ts +154 -0
  22. package/__tests__/device-wallet-session-store.test.ts +478 -0
  23. package/__tests__/deviceFeaturesUtils.test.ts +39 -0
  24. package/__tests__/deviceSettings.test.ts +113 -0
  25. package/__tests__/deviceUploadNft.test.ts +316 -0
  26. package/__tests__/evmLedgerLegacySafety.test.ts +12 -6
  27. package/__tests__/evmSignTransaction.test.ts +69 -0
  28. package/__tests__/evmSignTypedData.test.ts +80 -0
  29. package/__tests__/filesystemValidation.test.ts +53 -0
  30. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +402 -0
  31. package/__tests__/get-device-state.test.ts +578 -0
  32. package/__tests__/homescreen.test.ts +64 -0
  33. package/__tests__/kaspa-public-types.type-test.ts +16 -0
  34. package/__tests__/kaspa-use-tweak-pro2.test.ts +20 -0
  35. package/__tests__/kaspaSignTransaction.test.ts +578 -0
  36. package/__tests__/known-device-public-types.type-test.ts +3 -0
  37. package/__tests__/logBlockEvent.test.ts +128 -1
  38. package/__tests__/method-protocol-support.test.ts +132 -0
  39. package/__tests__/networkUtils.test.ts +406 -0
  40. package/__tests__/open-wallet-session-error-response.test.ts +43 -0
  41. package/__tests__/open-wallet-session.test.ts +1899 -0
  42. package/__tests__/pro2Nft.test.ts +108 -0
  43. package/__tests__/pro2Wallpaper.test.ts +39 -0
  44. package/__tests__/protocol-binding.test.ts +89 -0
  45. package/__tests__/protocol-v2-bootloader-mode.test.ts +37 -0
  46. package/__tests__/protocol-v2-firmware-targets.test.ts +37 -0
  47. package/__tests__/protocol-v2-ping.test.ts +28 -0
  48. package/__tests__/protocol-v2-resources.test.ts +340 -0
  49. package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
  50. package/__tests__/protocol-v2-unlock-policy.test.ts +245 -0
  51. package/__tests__/protocol-v2.test.ts +6478 -2536
  52. package/__tests__/protocolV2FileWrite.test.ts +244 -0
  53. package/__tests__/protocolV2UiInteraction.test.ts +329 -0
  54. package/__tests__/public-device-state-api.test.ts +275 -0
  55. package/__tests__/public-pro2-api-boundary.test.ts +107 -0
  56. package/__tests__/refresh-device-state.test.ts +101 -0
  57. package/__tests__/request-context-logging.test.ts +16 -0
  58. package/__tests__/search-devices.test.ts +145 -0
  59. package/__tests__/tron-sign-message-init.test.ts +74 -0
  60. package/__tests__/uiProgressThrottle.test.ts +74 -0
  61. package/__tests__/uiPromiseRegistry.test.ts +115 -0
  62. package/dist/api/BaseMethod.d.ts +16 -1
  63. package/dist/api/BaseMethod.d.ts.map +1 -1
  64. package/dist/api/CheckAllFirmwareRelease.d.ts +25 -1
  65. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  66. package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
  67. package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
  68. package/dist/api/CipherKeyValue.d.ts +1 -0
  69. package/dist/api/CipherKeyValue.d.ts.map +1 -1
  70. package/dist/api/ClearSessionCache.d.ts +9 -0
  71. package/dist/api/ClearSessionCache.d.ts.map +1 -0
  72. package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
  73. package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
  74. package/dist/api/DirList.d.ts +1 -0
  75. package/dist/api/DirList.d.ts.map +1 -1
  76. package/dist/api/DirMake.d.ts +1 -0
  77. package/dist/api/DirMake.d.ts.map +1 -1
  78. package/dist/api/DirRemove.d.ts +1 -0
  79. package/dist/api/DirRemove.d.ts.map +1 -1
  80. package/dist/api/FileDelete.d.ts +1 -0
  81. package/dist/api/FileDelete.d.ts.map +1 -1
  82. package/dist/api/FileRead.d.ts +1 -0
  83. package/dist/api/FileRead.d.ts.map +1 -1
  84. package/dist/api/FileWrite.d.ts +2 -0
  85. package/dist/api/FileWrite.d.ts.map +1 -1
  86. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  87. package/dist/api/FirmwareUpdateV2.d.ts +2 -2
  88. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  89. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  90. package/dist/api/FirmwareUpdateV4.d.ts +26 -16
  91. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  92. package/dist/api/GetDeviceState.d.ts +8 -0
  93. package/dist/api/GetDeviceState.d.ts.map +1 -0
  94. package/dist/api/GetFeatures.d.ts +1 -1
  95. package/dist/api/GetFeatures.d.ts.map +1 -1
  96. package/dist/api/GetOnekeyFeatures.d.ts.map +1 -1
  97. package/dist/api/GetPassphraseState.d.ts +2 -6
  98. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  99. package/dist/api/OpenWalletSession.d.ts +8 -0
  100. package/dist/api/OpenWalletSession.d.ts.map +1 -0
  101. package/dist/api/PathInfo.d.ts +1 -0
  102. package/dist/api/PathInfo.d.ts.map +1 -1
  103. package/dist/api/PromptWebDeviceAccess.d.ts.map +1 -1
  104. package/dist/api/SearchDevices.d.ts +3 -0
  105. package/dist/api/SearchDevices.d.ts.map +1 -1
  106. package/dist/api/UploadPortfolio.d.ts +17 -0
  107. package/dist/api/UploadPortfolio.d.ts.map +1 -0
  108. package/dist/api/alephium/AlephiumGetAddress.d.ts.map +1 -1
  109. package/dist/api/alephium/AlephiumSignMessage.d.ts.map +1 -1
  110. package/dist/api/alephium/AlephiumSignTransaction.d.ts.map +1 -1
  111. package/dist/api/algo/AlgoGetAddress.d.ts +1 -0
  112. package/dist/api/algo/AlgoGetAddress.d.ts.map +1 -1
  113. package/dist/api/algo/AlgoSignTransaction.d.ts +1 -0
  114. package/dist/api/algo/AlgoSignTransaction.d.ts.map +1 -1
  115. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +1 -0
  116. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  117. package/dist/api/aptos/AptosGetAddress.d.ts +1 -0
  118. package/dist/api/aptos/AptosGetAddress.d.ts.map +1 -1
  119. package/dist/api/aptos/AptosGetPublicKey.d.ts +1 -0
  120. package/dist/api/aptos/AptosGetPublicKey.d.ts.map +1 -1
  121. package/dist/api/aptos/AptosSignInMessage.d.ts +1 -0
  122. package/dist/api/aptos/AptosSignInMessage.d.ts.map +1 -1
  123. package/dist/api/aptos/AptosSignMessage.d.ts +1 -0
  124. package/dist/api/aptos/AptosSignMessage.d.ts.map +1 -1
  125. package/dist/api/aptos/AptosSignTransaction.d.ts +1 -0
  126. package/dist/api/aptos/AptosSignTransaction.d.ts.map +1 -1
  127. package/dist/api/benfen/BenfenGetAddress.d.ts.map +1 -1
  128. package/dist/api/benfen/BenfenGetPublicKey.d.ts.map +1 -1
  129. package/dist/api/benfen/BenfenSignMessage.d.ts.map +1 -1
  130. package/dist/api/benfen/BenfenSignTransaction.d.ts.map +1 -1
  131. package/dist/api/btc/BTCGetAddress.d.ts +1 -0
  132. package/dist/api/btc/BTCGetAddress.d.ts.map +1 -1
  133. package/dist/api/btc/BTCGetPublicKey.d.ts +1 -0
  134. package/dist/api/btc/BTCGetPublicKey.d.ts.map +1 -1
  135. package/dist/api/btc/BTCSignMessage.d.ts +1 -0
  136. package/dist/api/btc/BTCSignMessage.d.ts.map +1 -1
  137. package/dist/api/btc/BTCSignPsbt.d.ts +1 -0
  138. package/dist/api/btc/BTCSignPsbt.d.ts.map +1 -1
  139. package/dist/api/btc/BTCSignTransaction.d.ts +1 -0
  140. package/dist/api/btc/BTCSignTransaction.d.ts.map +1 -1
  141. package/dist/api/btc/BTCVerifyMessage.d.ts +1 -0
  142. package/dist/api/btc/BTCVerifyMessage.d.ts.map +1 -1
  143. package/dist/api/btc/helpers/versionLimit.d.ts +2 -0
  144. package/dist/api/btc/helpers/versionLimit.d.ts.map +1 -1
  145. package/dist/api/cardano/CardanoGetAddress.d.ts +1 -0
  146. package/dist/api/cardano/CardanoGetAddress.d.ts.map +1 -1
  147. package/dist/api/cardano/CardanoGetPublicKey.d.ts +1 -0
  148. package/dist/api/cardano/CardanoGetPublicKey.d.ts.map +1 -1
  149. package/dist/api/cardano/CardanoSignMessage.d.ts +1 -0
  150. package/dist/api/cardano/CardanoSignMessage.d.ts.map +1 -1
  151. package/dist/api/cardano/CardanoSignTransaction.d.ts +1 -0
  152. package/dist/api/cardano/CardanoSignTransaction.d.ts.map +1 -1
  153. package/dist/api/conflux/ConfluxGetAddress.d.ts +2 -0
  154. package/dist/api/conflux/ConfluxGetAddress.d.ts.map +1 -1
  155. package/dist/api/conflux/ConfluxSignMessage.d.ts +2 -0
  156. package/dist/api/conflux/ConfluxSignMessage.d.ts.map +1 -1
  157. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts +2 -0
  158. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts.map +1 -1
  159. package/dist/api/conflux/ConfluxSignTransaction.d.ts +2 -0
  160. package/dist/api/conflux/ConfluxSignTransaction.d.ts.map +1 -1
  161. package/dist/api/cosmos/CosmosGetAddress.d.ts +1 -0
  162. package/dist/api/cosmos/CosmosGetAddress.d.ts.map +1 -1
  163. package/dist/api/cosmos/CosmosGetPublicKey.d.ts +1 -0
  164. package/dist/api/cosmos/CosmosGetPublicKey.d.ts.map +1 -1
  165. package/dist/api/cosmos/CosmosSignTransaction.d.ts +1 -0
  166. package/dist/api/cosmos/CosmosSignTransaction.d.ts.map +1 -1
  167. package/dist/api/device/DeviceCancel.d.ts +1 -0
  168. package/dist/api/device/DeviceCancel.d.ts.map +1 -1
  169. package/dist/api/device/DeviceChangePin.d.ts +1 -0
  170. package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
  171. package/dist/api/device/DeviceFullyUploadResource.d.ts +1 -2
  172. package/dist/api/device/DeviceFullyUploadResource.d.ts.map +1 -1
  173. package/dist/api/device/DeviceLock.d.ts +1 -0
  174. package/dist/api/device/DeviceLock.d.ts.map +1 -1
  175. package/dist/api/device/DeviceRebootToBoardloader.d.ts +1 -0
  176. package/dist/api/device/DeviceRebootToBoardloader.d.ts.map +1 -1
  177. package/dist/api/device/DeviceRebootToBootloader.d.ts +1 -0
  178. package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
  179. package/dist/api/device/DeviceSettings.d.ts +1 -0
  180. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  181. package/dist/api/device/DeviceSupportFeatures.d.ts +1 -0
  182. package/dist/api/device/DeviceSupportFeatures.d.ts.map +1 -1
  183. package/dist/api/device/DeviceUnlock.d.ts +3 -2
  184. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  185. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  186. package/dist/api/device/DeviceWipe.d.ts +1 -0
  187. package/dist/api/device/DeviceWipe.d.ts.map +1 -1
  188. package/dist/api/device/PreInitialize.d.ts +1 -0
  189. package/dist/api/device/PreInitialize.d.ts.map +1 -1
  190. package/dist/api/dynex/DnxGetAddress.d.ts.map +1 -1
  191. package/dist/api/dynex/DnxSignTransaction.d.ts.map +1 -1
  192. package/dist/api/evm/EVMGetAddress.d.ts +1 -0
  193. package/dist/api/evm/EVMGetAddress.d.ts.map +1 -1
  194. package/dist/api/evm/EVMGetPublicKey.d.ts +1 -0
  195. package/dist/api/evm/EVMGetPublicKey.d.ts.map +1 -1
  196. package/dist/api/evm/EVMSignMessage.d.ts +1 -0
  197. package/dist/api/evm/EVMSignMessage.d.ts.map +1 -1
  198. package/dist/api/evm/EVMSignMessageEIP712.d.ts.map +1 -1
  199. package/dist/api/evm/EVMSignTransaction.d.ts +1 -0
  200. package/dist/api/evm/EVMSignTransaction.d.ts.map +1 -1
  201. package/dist/api/evm/EVMSignTypedData.d.ts +1 -0
  202. package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
  203. package/dist/api/evm/EVMVerifyMessage.d.ts +1 -0
  204. package/dist/api/evm/EVMVerifyMessage.d.ts.map +1 -1
  205. package/dist/api/evm/protocol.d.ts +3 -0
  206. package/dist/api/evm/protocol.d.ts.map +1 -0
  207. package/dist/api/filecoin/FilecoinGetAddress.d.ts +1 -0
  208. package/dist/api/filecoin/FilecoinGetAddress.d.ts.map +1 -1
  209. package/dist/api/filecoin/FilecoinSignTransaction.d.ts +1 -0
  210. package/dist/api/filecoin/FilecoinSignTransaction.d.ts.map +1 -1
  211. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +4 -3
  212. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  213. package/dist/api/firmware/getBinary.d.ts +8 -4
  214. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  215. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  216. package/dist/api/helpers/filesystemValidation.d.ts +3 -0
  217. package/dist/api/helpers/filesystemValidation.d.ts.map +1 -1
  218. package/dist/api/helpers/paramsValidator.d.ts +1 -0
  219. package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
  220. package/dist/api/helpers/protocolV2FileWrite.d.ts +42 -0
  221. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -0
  222. package/dist/api/index.d.ts +9 -25
  223. package/dist/api/index.d.ts.map +1 -1
  224. package/dist/api/kaspa/KaspaGetAddress.d.ts +4 -0
  225. package/dist/api/kaspa/KaspaGetAddress.d.ts.map +1 -1
  226. package/dist/api/kaspa/KaspaSignTransaction.d.ts +9 -1
  227. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  228. package/dist/api/kaspa/helpers/TransferSerialize.d.ts.map +1 -1
  229. package/dist/api/lightning/LnurlAuth.d.ts +0 -4
  230. package/dist/api/lightning/LnurlAuth.d.ts.map +1 -1
  231. package/dist/api/near/NearGetAddress.d.ts +1 -0
  232. package/dist/api/near/NearGetAddress.d.ts.map +1 -1
  233. package/dist/api/near/NearSignTransaction.d.ts +1 -0
  234. package/dist/api/near/NearSignTransaction.d.ts.map +1 -1
  235. package/dist/api/nem/NEMGetAddress.d.ts +1 -0
  236. package/dist/api/nem/NEMGetAddress.d.ts.map +1 -1
  237. package/dist/api/nem/NEMSignTransaction.d.ts +1 -0
  238. package/dist/api/nem/NEMSignTransaction.d.ts.map +1 -1
  239. package/dist/api/neo/NeoGetAddress.d.ts.map +1 -1
  240. package/dist/api/neo/NeoSignTransaction.d.ts.map +1 -1
  241. package/dist/api/nervos/NervosGetAddress.d.ts.map +1 -1
  242. package/dist/api/nervos/NervosSignTransaction.d.ts.map +1 -1
  243. package/dist/api/nexa/NexaGetAddress.d.ts.map +1 -1
  244. package/dist/api/nexa/NexaSignTransaction.d.ts +1 -0
  245. package/dist/api/nexa/NexaSignTransaction.d.ts.map +1 -1
  246. package/dist/api/nostr/NostrDecryptMessage.d.ts +1 -0
  247. package/dist/api/nostr/NostrDecryptMessage.d.ts.map +1 -1
  248. package/dist/api/nostr/NostrEncryptMessage.d.ts +1 -0
  249. package/dist/api/nostr/NostrEncryptMessage.d.ts.map +1 -1
  250. package/dist/api/nostr/NostrGetPublicKey.d.ts +1 -0
  251. package/dist/api/nostr/NostrGetPublicKey.d.ts.map +1 -1
  252. package/dist/api/nostr/NostrSignEvent.d.ts +1 -0
  253. package/dist/api/nostr/NostrSignEvent.d.ts.map +1 -1
  254. package/dist/api/nostr/NostrSignSchnorr.d.ts +1 -0
  255. package/dist/api/nostr/NostrSignSchnorr.d.ts.map +1 -1
  256. package/dist/api/polkadot/PolkadotGetAddress.d.ts +2 -1
  257. package/dist/api/polkadot/PolkadotGetAddress.d.ts.map +1 -1
  258. package/dist/api/polkadot/PolkadotSignTransaction.d.ts +1 -0
  259. package/dist/api/polkadot/PolkadotSignTransaction.d.ts.map +1 -1
  260. package/dist/api/polkadot/networks.d.ts +1 -1
  261. package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts +1 -0
  262. package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts.map +1 -1
  263. package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts +1 -0
  264. package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts.map +1 -1
  265. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +1 -0
  266. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -1
  267. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts +1 -0
  268. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
  269. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +7 -0
  270. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts.map +1 -0
  271. package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
  272. package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
  273. package/dist/api/protocol-v2/DeviceReboot.d.ts +1 -0
  274. package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -1
  275. package/dist/api/protocol-v2/DeviceStatusGet.d.ts +7 -0
  276. package/dist/api/protocol-v2/DeviceStatusGet.d.ts.map +1 -0
  277. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
  278. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
  279. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +27 -0
  280. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -0
  281. package/dist/api/protocol-v2/FilesystemFormat.d.ts +1 -0
  282. package/dist/api/protocol-v2/FilesystemFormat.d.ts.map +1 -1
  283. package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts +1 -0
  284. package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts.map +1 -1
  285. package/dist/api/protocol-v2/Ping.d.ts +3 -0
  286. package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
  287. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts +1 -0
  288. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  289. package/dist/api/protocol-v2/helpers.d.ts +1 -1
  290. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  291. package/dist/api/scdo/ScdoGetAddress.d.ts.map +1 -1
  292. package/dist/api/scdo/ScdoSignMessage.d.ts.map +1 -1
  293. package/dist/api/scdo/ScdoSignTransaction.d.ts.map +1 -1
  294. package/dist/api/solana/SolGetAddress.d.ts +1 -0
  295. package/dist/api/solana/SolGetAddress.d.ts.map +1 -1
  296. package/dist/api/solana/SolSignMessage.d.ts +2 -1
  297. package/dist/api/solana/SolSignMessage.d.ts.map +1 -1
  298. package/dist/api/solana/SolSignOffchainMessage.d.ts +2 -1
  299. package/dist/api/solana/SolSignOffchainMessage.d.ts.map +1 -1
  300. package/dist/api/solana/SolSignTransaction.d.ts +3 -2
  301. package/dist/api/solana/SolSignTransaction.d.ts.map +1 -1
  302. package/dist/api/starcoin/StarcoinGetAddress.d.ts +1 -0
  303. package/dist/api/starcoin/StarcoinGetAddress.d.ts.map +1 -1
  304. package/dist/api/starcoin/StarcoinGetPublicKey.d.ts +1 -0
  305. package/dist/api/starcoin/StarcoinGetPublicKey.d.ts.map +1 -1
  306. package/dist/api/starcoin/StarcoinSignMessage.d.ts +1 -0
  307. package/dist/api/starcoin/StarcoinSignMessage.d.ts.map +1 -1
  308. package/dist/api/starcoin/StarcoinSignTransaction.d.ts +1 -0
  309. package/dist/api/starcoin/StarcoinSignTransaction.d.ts.map +1 -1
  310. package/dist/api/starcoin/StarcoinVerifyMessage.d.ts +1 -0
  311. package/dist/api/starcoin/StarcoinVerifyMessage.d.ts.map +1 -1
  312. package/dist/api/stellar/StellarGetAddress.d.ts +1 -2
  313. package/dist/api/stellar/StellarGetAddress.d.ts.map +1 -1
  314. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -2
  315. package/dist/api/stellar/StellarSignTransaction.d.ts.map +1 -1
  316. package/dist/api/sui/SuiGetAddress.d.ts +2 -1
  317. package/dist/api/sui/SuiGetAddress.d.ts.map +1 -1
  318. package/dist/api/sui/SuiGetPublicKey.d.ts +2 -1
  319. package/dist/api/sui/SuiGetPublicKey.d.ts.map +1 -1
  320. package/dist/api/sui/SuiSignMessage.d.ts +2 -1
  321. package/dist/api/sui/SuiSignMessage.d.ts.map +1 -1
  322. package/dist/api/sui/SuiSignTransaction.d.ts +2 -1
  323. package/dist/api/sui/SuiSignTransaction.d.ts.map +1 -1
  324. package/dist/api/ton/TonGetAddress.d.ts +2 -1
  325. package/dist/api/ton/TonGetAddress.d.ts.map +1 -1
  326. package/dist/api/ton/TonSignData.d.ts +1 -0
  327. package/dist/api/ton/TonSignData.d.ts.map +1 -1
  328. package/dist/api/ton/TonSignMessage.d.ts +2 -1
  329. package/dist/api/ton/TonSignMessage.d.ts.map +1 -1
  330. package/dist/api/ton/TonSignProof.d.ts +2 -1
  331. package/dist/api/ton/TonSignProof.d.ts.map +1 -1
  332. package/dist/api/tron/TronGetAddress.d.ts +1 -0
  333. package/dist/api/tron/TronGetAddress.d.ts.map +1 -1
  334. package/dist/api/tron/TronSignMessage.d.ts +6 -1
  335. package/dist/api/tron/TronSignMessage.d.ts.map +1 -1
  336. package/dist/api/tron/TronSignTransaction.d.ts +2 -1
  337. package/dist/api/tron/TronSignTransaction.d.ts.map +1 -1
  338. package/dist/api/utils.d.ts +2 -1
  339. package/dist/api/utils.d.ts.map +1 -1
  340. package/dist/api/xrp/XrpGetAddress.d.ts +1 -0
  341. package/dist/api/xrp/XrpGetAddress.d.ts.map +1 -1
  342. package/dist/api/xrp/XrpSignTransaction.d.ts +1 -0
  343. package/dist/api/xrp/XrpSignTransaction.d.ts.map +1 -1
  344. package/dist/constants/index.d.ts +1 -1
  345. package/dist/constants/index.d.ts.map +1 -1
  346. package/dist/core/RequestQueue.d.ts.map +1 -1
  347. package/dist/core/deviceEventRegistration.d.ts +13 -0
  348. package/dist/core/deviceEventRegistration.d.ts.map +1 -0
  349. package/dist/core/index.d.ts +3 -1
  350. package/dist/core/index.d.ts.map +1 -1
  351. package/dist/core/uiPromiseRegistry.d.ts +6 -0
  352. package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
  353. package/dist/data-manager/DataManager.d.ts +9 -3
  354. package/dist/data-manager/DataManager.d.ts.map +1 -1
  355. package/dist/data-manager/TransportManager.d.ts.map +1 -1
  356. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  357. package/dist/device/Device.d.ts +71 -17
  358. package/dist/device/Device.d.ts.map +1 -1
  359. package/dist/device/DeviceCommands.d.ts +8 -6
  360. package/dist/device/DeviceCommands.d.ts.map +1 -1
  361. package/dist/device/DeviceConnector.d.ts +3 -2
  362. package/dist/device/DeviceConnector.d.ts.map +1 -1
  363. package/dist/device/DeviceFeaturesState.d.ts +3 -0
  364. package/dist/device/DeviceFeaturesState.d.ts.map +1 -0
  365. package/dist/device/DevicePool.d.ts +5 -2
  366. package/dist/device/DevicePool.d.ts.map +1 -1
  367. package/dist/device/DeviceStateMapper.d.ts +13 -0
  368. package/dist/device/DeviceStateMapper.d.ts.map +1 -0
  369. package/dist/device/DeviceStateProjector.d.ts +7 -0
  370. package/dist/device/DeviceStateProjector.d.ts.map +1 -0
  371. package/dist/device/DeviceStateStore.d.ts +21 -0
  372. package/dist/device/DeviceStateStore.d.ts.map +1 -0
  373. package/dist/device/DeviceWalletSessionStore.d.ts +27 -0
  374. package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -0
  375. package/dist/device/cloneDeviceState.d.ts +2 -0
  376. package/dist/device/cloneDeviceState.d.ts.map +1 -0
  377. package/dist/device/deviceIdentity.d.ts +5 -0
  378. package/dist/device/deviceIdentity.d.ts.map +1 -0
  379. package/dist/deviceProfile/buildDeviceFeatures.d.ts +9 -3
  380. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  381. package/dist/deviceProfile/index.d.ts +0 -1
  382. package/dist/deviceProfile/index.d.ts.map +1 -1
  383. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts +7 -0
  384. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -0
  385. package/dist/events/device.d.ts +16 -2
  386. package/dist/events/device.d.ts.map +1 -1
  387. package/dist/events/logBlockEvent.d.ts +2 -0
  388. package/dist/events/logBlockEvent.d.ts.map +1 -1
  389. package/dist/events/ui-promise.d.ts +4 -2
  390. package/dist/events/ui-promise.d.ts.map +1 -1
  391. package/dist/events/ui-request.d.ts +50 -4
  392. package/dist/events/ui-request.d.ts.map +1 -1
  393. package/dist/events/ui-response.d.ts +10 -2
  394. package/dist/events/ui-response.d.ts.map +1 -1
  395. package/dist/index.d.ts +1593 -773
  396. package/dist/index.js +8507 -3894
  397. package/dist/inject.d.ts +6 -1
  398. package/dist/inject.d.ts.map +1 -1
  399. package/dist/lowLevelInject.d.ts.map +1 -1
  400. package/dist/protocols/protocol-v2/deviceSession.d.ts +7 -0
  401. package/dist/protocols/protocol-v2/deviceSession.d.ts.map +1 -0
  402. package/dist/protocols/protocol-v2/features.d.ts +21 -17
  403. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  404. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
  405. package/dist/protocols/protocol-v2/index.d.ts +3 -2
  406. package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
  407. package/dist/protocols/protocol-v2/resources.d.ts +30 -0
  408. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
  409. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts +17 -0
  410. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -0
  411. package/dist/protocols/protocol-v2/uiInteraction.d.ts +42 -0
  412. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -0
  413. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +2 -0
  414. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -0
  415. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
  416. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
  417. package/dist/protocols/protocol-v2/walletSession.d.ts +27 -0
  418. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -0
  419. package/dist/topLevelInject.d.ts.map +1 -1
  420. package/dist/types/api/checkAllFirmwareRelease.d.ts +27 -4
  421. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  422. package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
  423. package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
  424. package/dist/types/api/deviceSettings.d.ts +11 -2
  425. package/dist/types/api/deviceSettings.d.ts.map +1 -1
  426. package/dist/types/api/deviceUnlock.d.ts +6 -2
  427. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  428. package/dist/types/api/export.d.ts +4 -2
  429. package/dist/types/api/export.d.ts.map +1 -1
  430. package/dist/types/api/firmwareUpdate.d.ts +8 -1
  431. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  432. package/dist/types/api/getDeviceState.d.ts +12 -0
  433. package/dist/types/api/getDeviceState.d.ts.map +1 -0
  434. package/dist/types/api/getFeatures.d.ts.map +1 -1
  435. package/dist/types/api/getOnekeyFeatures.d.ts.map +1 -1
  436. package/dist/types/api/getPassphraseState.d.ts +2 -10
  437. package/dist/types/api/getPassphraseState.d.ts.map +1 -1
  438. package/dist/types/api/index.d.ts +23 -30
  439. package/dist/types/api/index.d.ts.map +1 -1
  440. package/dist/types/api/kaspaSignTransaction.d.ts +42 -4
  441. package/dist/types/api/kaspaSignTransaction.d.ts.map +1 -1
  442. package/dist/types/api/openWalletSession.d.ts +35 -0
  443. package/dist/types/api/openWalletSession.d.ts.map +1 -0
  444. package/dist/types/api/protocolV2.d.ts +18 -84
  445. package/dist/types/api/protocolV2.d.ts.map +1 -1
  446. package/dist/types/api/sessionCache.d.ts +13 -0
  447. package/dist/types/api/sessionCache.d.ts.map +1 -0
  448. package/dist/types/device.d.ts +134 -10
  449. package/dist/types/device.d.ts.map +1 -1
  450. package/dist/types/params.d.ts +1 -0
  451. package/dist/types/params.d.ts.map +1 -1
  452. package/dist/types/settings.d.ts +44 -21
  453. package/dist/types/settings.d.ts.map +1 -1
  454. package/dist/utils/assets.d.ts +2 -1
  455. package/dist/utils/assets.d.ts.map +1 -1
  456. package/dist/utils/deviceFeaturesCompat.d.ts +13 -0
  457. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -0
  458. package/dist/utils/deviceFeaturesUtils.d.ts +10 -3
  459. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  460. package/dist/utils/deviceInfoUtils.d.ts +9 -9
  461. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  462. package/dist/utils/deviceSettings.d.ts +38 -7
  463. package/dist/utils/deviceSettings.d.ts.map +1 -1
  464. package/dist/utils/deviceVersionUtils.d.ts +7 -5
  465. package/dist/utils/deviceVersionUtils.d.ts.map +1 -1
  466. package/dist/utils/homescreen.d.ts +4 -0
  467. package/dist/utils/homescreen.d.ts.map +1 -1
  468. package/dist/utils/index.d.ts +6 -3
  469. package/dist/utils/index.d.ts.map +1 -1
  470. package/dist/utils/networkUtils.d.ts +10 -1
  471. package/dist/utils/networkUtils.d.ts.map +1 -1
  472. package/dist/utils/patch.d.ts +1 -1
  473. package/dist/utils/patch.d.ts.map +1 -1
  474. package/dist/utils/pro2Nft.d.ts +31 -0
  475. package/dist/utils/pro2Nft.d.ts.map +1 -0
  476. package/dist/utils/pro2Wallpaper.d.ts +22 -0
  477. package/dist/utils/pro2Wallpaper.d.ts.map +1 -0
  478. package/dist/utils/tracing.d.ts.map +1 -1
  479. package/dist/utils/uiProgressThrottle.d.ts +3 -0
  480. package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
  481. package/package.json +4 -4
  482. package/src/api/BaseMethod.ts +53 -20
  483. package/src/api/CheckAllFirmwareRelease.ts +340 -1
  484. package/src/api/CheckBootloaderRelease.ts +1 -2
  485. package/src/api/CheckFirmwareRelease.ts +1 -2
  486. package/src/api/CipherKeyValue.ts +4 -0
  487. package/src/api/ClearSessionCache.ts +32 -0
  488. package/src/api/DetectDeviceConnectProtocol.ts +18 -0
  489. package/src/api/DirList.ts +9 -4
  490. package/src/api/DirMake.ts +7 -4
  491. package/src/api/DirRemove.ts +7 -4
  492. package/src/api/FileDelete.ts +7 -4
  493. package/src/api/FileRead.ts +15 -9
  494. package/src/api/FileWrite.ts +26 -181
  495. package/src/api/FirmwareUpdate.ts +17 -14
  496. package/src/api/FirmwareUpdateV2.ts +137 -54
  497. package/src/api/FirmwareUpdateV3.ts +9 -13
  498. package/src/api/FirmwareUpdateV4.ts +805 -626
  499. package/src/api/GetDeviceState.ts +59 -0
  500. package/src/api/GetFeatures.ts +6 -4
  501. package/src/api/GetOnekeyFeatures.ts +1 -75
  502. package/src/api/GetPassphraseState.ts +36 -21
  503. package/src/api/OpenWalletSession.ts +268 -0
  504. package/src/api/PathInfo.ts +9 -4
  505. package/src/api/PromptWebDeviceAccess.ts +2 -7
  506. package/src/api/SearchDevices.ts +31 -4
  507. package/src/api/UploadPortfolio.ts +40 -0
  508. package/src/api/alephium/AlephiumGetAddress.ts +0 -4
  509. package/src/api/alephium/AlephiumSignMessage.ts +0 -4
  510. package/src/api/alephium/AlephiumSignTransaction.ts +2 -6
  511. package/src/api/algo/AlgoGetAddress.ts +4 -0
  512. package/src/api/algo/AlgoSignTransaction.ts +4 -0
  513. package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
  514. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +45 -32
  515. package/src/api/aptos/AptosGetAddress.ts +4 -0
  516. package/src/api/aptos/AptosGetPublicKey.ts +4 -0
  517. package/src/api/aptos/AptosSignInMessage.ts +4 -0
  518. package/src/api/aptos/AptosSignMessage.ts +4 -0
  519. package/src/api/aptos/AptosSignTransaction.ts +4 -0
  520. package/src/api/benfen/BenfenGetAddress.ts +11 -7
  521. package/src/api/benfen/BenfenGetPublicKey.ts +0 -4
  522. package/src/api/benfen/BenfenSignMessage.ts +0 -4
  523. package/src/api/benfen/BenfenSignTransaction.ts +0 -4
  524. package/src/api/btc/BTCGetAddress.ts +8 -1
  525. package/src/api/btc/BTCGetPublicKey.ts +9 -2
  526. package/src/api/btc/BTCSignMessage.ts +8 -1
  527. package/src/api/btc/BTCSignPsbt.ts +4 -0
  528. package/src/api/btc/BTCSignTransaction.ts +8 -1
  529. package/src/api/btc/BTCVerifyMessage.ts +8 -1
  530. package/src/api/btc/helpers/versionLimit.ts +7 -4
  531. package/src/api/cardano/CardanoGetAddress.ts +4 -0
  532. package/src/api/cardano/CardanoGetPublicKey.ts +4 -0
  533. package/src/api/cardano/CardanoSignMessage.ts +5 -1
  534. package/src/api/cardano/CardanoSignTransaction.ts +5 -1
  535. package/src/api/conflux/ConfluxGetAddress.ts +6 -0
  536. package/src/api/conflux/ConfluxSignMessage.ts +6 -0
  537. package/src/api/conflux/ConfluxSignMessageCIP23.ts +6 -0
  538. package/src/api/conflux/ConfluxSignTransaction.ts +8 -5
  539. package/src/api/cosmos/CosmosGetAddress.ts +4 -0
  540. package/src/api/cosmos/CosmosGetPublicKey.ts +4 -0
  541. package/src/api/cosmos/CosmosSignTransaction.ts +4 -0
  542. package/src/api/device/DeviceCancel.ts +5 -0
  543. package/src/api/device/DeviceChangePin.ts +28 -0
  544. package/src/api/device/DeviceFullyUploadResource.ts +4 -5
  545. package/src/api/device/DeviceLock.ts +5 -0
  546. package/src/api/device/DeviceRebootToBoardloader.ts +5 -0
  547. package/src/api/device/DeviceRebootToBootloader.ts +5 -0
  548. package/src/api/device/DeviceSettings.ts +195 -1
  549. package/src/api/device/DeviceSupportFeatures.ts +4 -0
  550. package/src/api/device/DeviceUnlock.ts +21 -3
  551. package/src/api/device/DeviceUpdateBootloader.ts +1 -2
  552. package/src/api/device/DeviceWipe.ts +25 -0
  553. package/src/api/device/PreInitialize.ts +4 -0
  554. package/src/api/dynex/DnxGetAddress.ts +0 -6
  555. package/src/api/dynex/DnxSignTransaction.ts +0 -6
  556. package/src/api/evm/EVMGetAddress.ts +6 -2
  557. package/src/api/evm/EVMGetPublicKey.ts +6 -2
  558. package/src/api/evm/EVMSignMessage.ts +6 -2
  559. package/src/api/evm/EVMSignMessageEIP712.ts +1 -11
  560. package/src/api/evm/EVMSignTransaction.ts +6 -2
  561. package/src/api/evm/EVMSignTypedData.ts +42 -50
  562. package/src/api/evm/EVMVerifyMessage.ts +6 -2
  563. package/src/api/evm/legacyV1/getAddress.ts +2 -2
  564. package/src/api/evm/legacyV1/getPublicKey.ts +2 -2
  565. package/src/api/evm/legacyV1/signMessage.ts +2 -2
  566. package/src/api/evm/legacyV1/signTypedData.ts +2 -2
  567. package/src/api/evm/legacyV1/signTypedHash.ts +2 -2
  568. package/src/api/evm/legacyV1/verifyMessage.ts +2 -2
  569. package/src/api/evm/protocol.ts +6 -0
  570. package/src/api/filecoin/FilecoinGetAddress.ts +4 -0
  571. package/src/api/filecoin/FilecoinSignTransaction.ts +4 -0
  572. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +30 -15
  573. package/src/api/firmware/getBinary.ts +8 -3
  574. package/src/api/firmware/uploadFirmware.ts +17 -4
  575. package/src/api/helpers/batchGetPublickeys.ts +2 -2
  576. package/src/api/helpers/filesystemValidation.ts +61 -0
  577. package/src/api/helpers/paramsValidator.ts +1 -1
  578. package/src/api/helpers/protocolV2FileWrite.ts +338 -0
  579. package/src/api/index.ts +10 -26
  580. package/src/api/kaspa/KaspaGetAddress.ts +7 -0
  581. package/src/api/kaspa/KaspaSignTransaction.ts +369 -29
  582. package/src/api/kaspa/helpers/TransferSerialize.ts +17 -7
  583. package/src/api/lightning/LnurlAuth.ts +0 -4
  584. package/src/api/near/NearGetAddress.ts +4 -0
  585. package/src/api/near/NearSignTransaction.ts +4 -0
  586. package/src/api/nem/NEMGetAddress.ts +4 -0
  587. package/src/api/nem/NEMSignTransaction.ts +4 -0
  588. package/src/api/neo/NeoGetAddress.ts +0 -4
  589. package/src/api/neo/NeoSignTransaction.ts +0 -4
  590. package/src/api/nervos/NervosGetAddress.ts +0 -4
  591. package/src/api/nervos/NervosSignTransaction.ts +2 -6
  592. package/src/api/nexa/NexaGetAddress.ts +0 -4
  593. package/src/api/nexa/NexaSignTransaction.ts +3 -5
  594. package/src/api/nostr/NostrDecryptMessage.ts +4 -0
  595. package/src/api/nostr/NostrEncryptMessage.ts +4 -0
  596. package/src/api/nostr/NostrGetPublicKey.ts +4 -0
  597. package/src/api/nostr/NostrSignEvent.ts +4 -0
  598. package/src/api/nostr/NostrSignSchnorr.ts +4 -0
  599. package/src/api/polkadot/PolkadotGetAddress.ts +4 -0
  600. package/src/api/polkadot/PolkadotSignTransaction.ts +4 -0
  601. package/src/api/polkadot/networks.ts +3 -3
  602. package/src/api/protocol-v2/DeviceFactoryInfoGet.ts +5 -2
  603. package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +5 -2
  604. package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +8 -5
  605. package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +10 -6
  606. package/src/api/protocol-v2/DeviceGetOnboardingStatus.ts +21 -0
  607. package/src/api/protocol-v2/DeviceInfoGet.ts +8 -15
  608. package/src/api/protocol-v2/DeviceReboot.ts +7 -3
  609. package/src/api/protocol-v2/DeviceStatusGet.ts +19 -0
  610. package/src/api/protocol-v2/DeviceUploadNft.ts +197 -0
  611. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +134 -0
  612. package/src/api/protocol-v2/FilesystemFormat.ts +9 -3
  613. package/src/api/protocol-v2/FilesystemPermissionFix.ts +5 -2
  614. package/src/api/protocol-v2/Ping.ts +37 -3
  615. package/src/api/protocol-v2/ProtocolInfoRequest.ts +8 -3
  616. package/src/api/protocol-v2/helpers.ts +17 -17
  617. package/src/api/scdo/ScdoGetAddress.ts +0 -4
  618. package/src/api/scdo/ScdoSignMessage.ts +0 -4
  619. package/src/api/scdo/ScdoSignTransaction.ts +0 -4
  620. package/src/api/solana/SolGetAddress.ts +4 -0
  621. package/src/api/solana/SolSignMessage.ts +5 -1
  622. package/src/api/solana/SolSignOffchainMessage.ts +5 -1
  623. package/src/api/solana/SolSignTransaction.ts +6 -2
  624. package/src/api/starcoin/StarcoinGetAddress.ts +4 -0
  625. package/src/api/starcoin/StarcoinGetPublicKey.ts +4 -0
  626. package/src/api/starcoin/StarcoinSignMessage.ts +4 -0
  627. package/src/api/starcoin/StarcoinSignTransaction.ts +4 -0
  628. package/src/api/starcoin/StarcoinVerifyMessage.ts +4 -0
  629. package/src/api/stellar/StellarGetAddress.ts +1 -10
  630. package/src/api/stellar/StellarSignTransaction.ts +1 -14
  631. package/src/api/sui/SuiGetAddress.ts +5 -1
  632. package/src/api/sui/SuiGetPublicKey.ts +5 -1
  633. package/src/api/sui/SuiSignMessage.ts +5 -1
  634. package/src/api/sui/SuiSignTransaction.ts +5 -1
  635. package/src/api/ton/TonGetAddress.ts +5 -1
  636. package/src/api/ton/TonSignData.ts +5 -1
  637. package/src/api/ton/TonSignMessage.ts +5 -1
  638. package/src/api/ton/TonSignProof.ts +5 -1
  639. package/src/api/tron/TronGetAddress.ts +4 -0
  640. package/src/api/tron/TronSignMessage.ts +19 -8
  641. package/src/api/tron/TronSignTransaction.ts +5 -1
  642. package/src/api/utils.ts +7 -3
  643. package/src/api/xrp/XrpGetAddress.ts +4 -0
  644. package/src/api/xrp/XrpSignTransaction.ts +5 -1
  645. package/src/constants/index.ts +1 -4
  646. package/src/core/RequestQueue.ts +1 -0
  647. package/src/core/deviceEventRegistration.ts +27 -0
  648. package/src/core/index.ts +365 -152
  649. package/src/core/uiPromiseRegistry.ts +63 -0
  650. package/src/data/messages/messages-protocol-v2.json +1138 -441
  651. package/src/data/messages/messages.json +286 -1
  652. package/src/data-manager/DataManager.ts +88 -16
  653. package/src/data-manager/TransportManager.ts +7 -1
  654. package/src/data-manager/connectSettings.ts +4 -0
  655. package/src/device/Device.ts +891 -295
  656. package/src/device/DeviceCommands.ts +193 -158
  657. package/src/device/DeviceConnector.ts +43 -20
  658. package/src/device/DeviceFeaturesState.ts +25 -0
  659. package/src/device/DevicePool.ts +86 -22
  660. package/src/device/DeviceStateMapper.ts +374 -0
  661. package/src/device/DeviceStateProjector.ts +94 -0
  662. package/src/device/DeviceStateStore.ts +201 -0
  663. package/src/device/DeviceWalletSessionStore.ts +144 -0
  664. package/src/device/cloneDeviceState.ts +39 -0
  665. package/src/device/deviceIdentity.ts +18 -0
  666. package/src/deviceProfile/buildDeviceFeatures.ts +223 -189
  667. package/src/deviceProfile/index.ts +0 -1
  668. package/src/deviceProfile/protocolV2DeviceIdentity.ts +35 -0
  669. package/src/events/device.ts +22 -1
  670. package/src/events/logBlockEvent.ts +80 -2
  671. package/src/events/ui-promise.ts +4 -2
  672. package/src/events/ui-request.ts +61 -4
  673. package/src/events/ui-response.ts +12 -2
  674. package/src/inject.ts +73 -43
  675. package/src/lowLevelInject.ts +6 -3
  676. package/src/protocols/protocol-v2/deviceSession.ts +24 -0
  677. package/src/protocols/protocol-v2/features.ts +100 -33
  678. package/src/protocols/protocol-v2/firmware.ts +3 -1
  679. package/src/protocols/protocol-v2/index.ts +8 -1
  680. package/src/protocols/protocol-v2/resources.ts +390 -0
  681. package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +65 -0
  682. package/src/protocols/protocol-v2/uiInteraction.ts +250 -0
  683. package/src/protocols/protocol-v2/unlockPolicy.ts +1 -0
  684. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +118 -0
  685. package/src/protocols/protocol-v2/walletSession.ts +463 -0
  686. package/src/topLevelInject.ts +6 -3
  687. package/src/types/api/checkAllFirmwareRelease.ts +48 -4
  688. package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
  689. package/src/types/api/deviceSettings.ts +26 -2
  690. package/src/types/api/deviceUnlock.ts +13 -2
  691. package/src/types/api/export.ts +9 -0
  692. package/src/types/api/firmwareUpdate.ts +26 -5
  693. package/src/types/api/getDeviceState.ts +19 -0
  694. package/src/types/api/getFeatures.ts +3 -0
  695. package/src/types/api/getOnekeyFeatures.ts +3 -0
  696. package/src/types/api/getPassphraseState.ts +9 -11
  697. package/src/types/api/index.ts +38 -64
  698. package/src/types/api/kaspaSignTransaction.ts +60 -4
  699. package/src/types/api/openWalletSession.ts +54 -0
  700. package/src/types/api/protocolV2.ts +33 -141
  701. package/src/types/api/sessionCache.ts +19 -0
  702. package/src/types/device.ts +200 -10
  703. package/src/types/params.ts +9 -2
  704. package/src/types/settings.ts +76 -24
  705. package/src/utils/assets.ts +4 -1
  706. package/src/utils/deviceFeaturesCompat.ts +185 -0
  707. package/src/utils/deviceFeaturesUtils.ts +65 -47
  708. package/src/utils/deviceInfoUtils.ts +29 -69
  709. package/src/utils/deviceSettings.ts +174 -39
  710. package/src/utils/deviceVersionUtils.ts +25 -44
  711. package/src/utils/findDefectiveBatchDevice.ts +3 -3
  712. package/src/utils/homescreen.ts +36 -0
  713. package/src/utils/index.ts +27 -3
  714. package/src/utils/networkUtils.ts +274 -16
  715. package/src/utils/pro2Nft.ts +142 -0
  716. package/src/utils/pro2Wallpaper.ts +130 -0
  717. package/src/utils/tracing.ts +3 -1
  718. package/src/utils/uiProgressThrottle.ts +63 -0
  719. package/tsconfig.type-tests.json +12 -0
  720. package/dist/api/GetDeviceInfo.d.ts +0 -9
  721. package/dist/api/GetDeviceInfo.d.ts.map +0 -1
  722. package/dist/api/firmware/progressThrottle.d.ts +0 -3
  723. package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
  724. package/dist/api/protocol-v2/FilesystemDiskControl.d.ts +0 -13
  725. package/dist/api/protocol-v2/FilesystemDiskControl.d.ts.map +0 -1
  726. package/dist/deviceProfile/buildDeviceProfile.d.ts +0 -21
  727. package/dist/deviceProfile/buildDeviceProfile.d.ts.map +0 -1
  728. package/dist/types/api/getDeviceInfo.d.ts +0 -87
  729. package/dist/types/api/getDeviceInfo.d.ts.map +0 -1
  730. package/src/api/GetDeviceInfo.ts +0 -145
  731. package/src/api/firmware/progressThrottle.ts +0 -44
  732. package/src/api/protocol-v2/FilesystemDiskControl.ts +0 -50
  733. package/src/deviceProfile/buildDeviceProfile.ts +0 -352
  734. package/src/types/api/getDeviceInfo.ts +0 -101
@@ -1,11 +1,14 @@
1
- import { ERRORS, HardwareError, HardwareErrorCode, wait } from '@onekeyfe/hd-shared';
1
+ import { EDeviceType, ERRORS, HardwareError, HardwareErrorCode, wait } from '@onekeyfe/hd-shared';
2
2
  import {
3
3
  DeviceRebootType,
4
4
  PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
5
5
  PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE,
6
6
  } from '@onekeyfe/hd-transport';
7
+ import { sha256 } from '@noble/hashes/sha256';
7
8
 
8
9
  import { FirmwareUpdateTipMessage, UI_REQUEST } from '../events/ui-request';
10
+ import { validateProtocolV2FilesystemPath } from './helpers/filesystemValidation';
11
+ import { writeProtocolV2File } from './helpers/protocolV2FileWrite';
9
12
  import { validateParams } from './helpers/paramsValidator';
10
13
  import {
11
14
  LoggerNames,
@@ -25,41 +28,51 @@ import {
25
28
  } from '../protocols/protocol-v2';
26
29
  import { requestProtocolV2DeviceInfo } from '../protocols/protocol-v2/features';
27
30
  import {
28
- PROTOCOL_V2_FIRMWARE_UPDATE_RESPONSE_TYPES,
31
+ PROTOCOL_V2_RESOURCE_DEVICE_PATHS,
32
+ buildProtocolV2ResourceUpdatePlan,
33
+ isProtocolV2ResourceFileValid,
34
+ readProtocolV2ResourceInventory,
35
+ } from '../protocols/protocol-v2/resources';
36
+ import {
29
37
  getProtocolV2UnknownErrorText,
30
38
  isProtocolV2DeviceDisconnectedError,
31
39
  } from './protocol-v2/helpers';
32
40
 
33
- import type { FirmwareUpdateV4Params } from '../types/api/firmwareUpdate';
41
+ import type { FirmwareUpdateV4Params, FirmwareUpdateV4Target } from '../types/api/firmwareUpdate';
34
42
  import type { EFirmwareType } from '@onekeyfe/hd-shared';
43
+ import type { ProtocolV2DeviceInfo } from '@onekeyfe/hd-transport';
35
44
  import type { PROTO } from '../constants';
36
45
  import type { TypedResponseMessage } from '../device/DeviceCommands';
37
46
  import type {
38
47
  Features,
39
48
  IFirmwareReleaseInfo,
40
49
  IProtocolV2FirmwareComponent,
41
- IProtocolV2ResourceManifestPackage,
50
+ IProtocolV2Resource,
51
+ IProtocolV2ResourceFile,
42
52
  IVersionArray,
43
53
  } from '../types';
44
54
 
45
55
  const Log = getLogger(LoggerNames.Method);
46
56
 
47
- const SESSION_ERROR = 'session not found';
48
- const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 60 * 1000;
57
+ const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 90 * 1000;
58
+ const PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT = 3 * 60 * 1000;
49
59
  const PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT = 5 * 1000;
50
- const PROTOCOL_V2_START_UPDATE_TIMEOUT = 60 * 1000;
51
- const PROTOCOL_V2_INSTALL_TIMEOUT = 5 * 60 * 1000;
60
+ const PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT = 15 * 1000;
61
+ const PROTOCOL_V2_START_UPDATE_TIMEOUT = 3 * 60 * 1000;
62
+ const PROTOCOL_V2_INSTALL_TIMEOUT = 8 * 60 * 1000;
63
+ const PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT = 30 * 1000;
52
64
  const PROTOCOL_V2_TARGET_STATUS_PENDING = 0;
53
65
  const PROTOCOL_V2_TARGET_STATUS_IN_PROGRESS = 1;
54
66
  const PROTOCOL_V2_TARGET_STATUS_FINISHED = 2;
55
67
  const PROTOCOL_V2_TARGET_STATUS_FAILED_MIN = 3;
56
68
  const PROTOCOL_V2_CONNECT_PROTOCOL = 'V2';
57
- const PROTOCOL_V2_FIRMWARE_STAGING_VOLUME = 'vol1:';
69
+ const PROTOCOL_V2_FIRMWARE_STAGING_VOLUME = 'vol0:/';
58
70
  const PROTOCOL_V2_MIN_FILE_CHUNK_SIZE = 64;
59
71
  const PROTOCOL_V2_CONNECT_RETRY_COUNT = 10;
60
72
  const PROTOCOL_V2_CONNECT_POLL_INTERVAL = 500;
61
73
  const PROTOCOL_V2_CONNECT_SINGLE_TIMEOUT = 75 * 1000;
62
- const PROTOCOL_V2_DEVICE_INFO_READY_TIMEOUT = 60 * 1000;
74
+ const PROTOCOL_V2_DEVICE_INFO_READY_TIMEOUT = 30 * 1000;
75
+ const PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT = 3;
63
76
  const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
64
77
  const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
65
78
  const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
@@ -94,10 +107,7 @@ type ProtocolV2FirmwareUpdateStatusTarget = {
94
107
  path?: string;
95
108
  };
96
109
 
97
- type ProtocolV2FirmwareUpdateStartResponse =
98
- | TypedResponseMessage<'Success'>
99
- | TypedResponseMessage<'DeviceFirmwareUpdateStatus'>
100
- | undefined;
110
+ type ProtocolV2FirmwareUpdateStartResponse = TypedResponseMessage<'Success'>;
101
111
 
102
112
  type ProtocolV2TargetBinary = { fileName: string; binary: ArrayBuffer; targetId: number };
103
113
  type ProtocolV2InstallItem = ProtocolV2TargetBinary & {
@@ -107,6 +117,20 @@ type ProtocolV2InstallTarget = ProtocolV2InstallItem & {
107
117
  path: string;
108
118
  };
109
119
 
120
+ type ProtocolV2FileTransferParams = PROTO.FirmwareUpload & {
121
+ filePath: string;
122
+ processedSize?: number;
123
+ totalSize?: number;
124
+ onTransferredBytes?: (transferredBytes: number) => void;
125
+ };
126
+
127
+ /** Protocol V2 resource file written independently to devicePath through FileWrite. */
128
+ type ProtocolV2ResourceBundleBinary = {
129
+ name: string;
130
+ binary: ArrayBuffer;
131
+ devicePath: string;
132
+ };
133
+
110
134
  type ProtocolV2RemoteComponentBinary = ProtocolV2RemoteComponentTarget & {
111
135
  binary: ArrayBuffer;
112
136
  };
@@ -114,7 +138,7 @@ type ProtocolV2RemoteComponentBinary = ProtocolV2RemoteComponentTarget & {
114
138
  type ProtocolV2RemoteComponentTarget = {
115
139
  fileName: string;
116
140
  targetId: number;
117
- kind: 'bootloader' | 'firmware' | 'resource';
141
+ kind: 'bootloader' | 'firmware';
118
142
  };
119
143
 
120
144
  type ProtocolV2OkppHeader = {
@@ -167,18 +191,24 @@ const PROTOCOL_V2_REMOTE_COMPONENT_TARGETS: Readonly<
167
191
  targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04,
168
192
  kind: 'firmware',
169
193
  },
170
- CRATE: {
171
- fileName: 'resource.bin',
172
- targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
173
- kind: 'resource',
174
- },
175
194
  };
176
195
 
196
+ const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map<number, FirmwareUpdateV4Target>([
197
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER, 'boot'],
198
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1, 'app_v1'],
199
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2, 'app_v2'],
200
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR, 'coprocessor'],
201
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01, 'se01'],
202
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02, 'se02'],
203
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03, 'se03'],
204
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, 'se04'],
205
+ ]);
206
+
177
207
  const PROTOCOL_V2_ROMLOADER_UNSUPPORTED_MESSAGE =
178
208
  'FW_MGMT_TARGET_ROMLOADER is not accepted by the current Pro2 bootloader update request. Flash romloader with the loader-specific flow instead of firmwareUpdateV4.';
179
209
 
180
- // hd-transport 的历史 decode 行为会把单值 enum 输出为枚举名字符串;
181
- // Protocol V2 沿用这个 SDK 语义,内部比较前再映射回固件协议数值。
210
+ // hd-transport historically decodes scalar enums as enum-name strings.
211
+ // Map them back to firmware protocol values before internal comparisons.
182
212
  const PROTOCOL_V2_TARGET_ID_BY_DECODED_NAME = new Map<string, number>(
183
213
  Object.entries(ProtocolV2FirmwareTargetType).map(([key, value]) => [key, value])
184
214
  );
@@ -204,25 +234,12 @@ const isProtocolV2ReconnectProbeError = (error: unknown) => {
204
234
  );
205
235
  };
206
236
 
207
- const isProtocolV2PollingTransientError = (error: unknown) => {
208
- const message = getProtocolV2UnknownErrorText(error).toLowerCase();
209
- return (
210
- isProtocolV2DeviceDisconnectedError(error) ||
211
- isProtocolV2ReconnectProbeError(error) ||
212
- message.includes('libusb_transfer_timed_out') ||
213
- (message.includes('response timeout') && message.includes('devicefirmwareupdatestatusget')) ||
214
- message.includes('device not found') ||
215
- message.includes('transportnotfound')
216
- );
217
- };
218
-
219
- const isProtocolV2StartUpdateTransientError = (error: unknown) => {
237
+ const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
220
238
  const message = getProtocolV2UnknownErrorText(error).toLowerCase();
221
239
  return (
222
- isProtocolV2DeviceDisconnectedError(error) ||
223
- isProtocolV2ReconnectProbeError(error) ||
224
- message.includes('libusb_transfer_timed_out') ||
225
- (message.includes('response timeout') && message.includes('devicefirmwareupdaterequest'))
240
+ message.includes('handler not registered') ||
241
+ message.includes('message handler not found') ||
242
+ message.includes('unsupported message')
226
243
  );
227
244
  };
228
245
 
@@ -263,25 +280,6 @@ const normalizeProtocolV2TargetStatus = (
263
280
 
264
281
  const normalizeProtocolV2Hex = (value?: string) => value?.replace(/^0x/i, '').toLowerCase();
265
282
 
266
- const versionArrayToNumber = (version?: IVersionArray) => {
267
- if (!version) return undefined;
268
- return version[0] * 0x10000 + version[1] * 0x100 + version[2];
269
- };
270
-
271
- const versionStringToArray = (version?: string | null): IVersionArray | undefined => {
272
- if (!version) return undefined;
273
- const parts = version.split('.').map(part => Number(part));
274
- if (parts.length !== 3 || parts.some(part => !Number.isFinite(part))) return undefined;
275
- return parts as IVersionArray;
276
- };
277
-
278
- const compareProtocolV2Versions = (current?: IVersionArray, target?: IVersionArray) => {
279
- const currentNumber = versionArrayToNumber(current);
280
- const targetNumber = versionArrayToNumber(target);
281
- if (currentNumber === undefined || targetNumber === undefined) return undefined;
282
- return currentNumber - targetNumber;
283
- };
284
-
285
283
  const bytesToHex = (bytes: Uint8Array) =>
286
284
  Array.from(bytes)
287
285
  .map(byte => byte.toString(16).padStart(2, '0'))
@@ -361,6 +359,43 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
361
359
  };
362
360
  };
363
361
 
362
+ export const isProtocolV2FirmwareFingerprintValid = (
363
+ binary: ArrayBuffer | Uint8Array,
364
+ fingerprint: string | undefined
365
+ ) => {
366
+ const expectedFingerprint = normalizeProtocolV2Hex(fingerprint);
367
+ if (!expectedFingerprint) return true;
368
+ return bytesToHex(sha256(toProtocolV2Bytes(binary))) === expectedFingerprint;
369
+ };
370
+
371
+ export const assertProtocolV2ReconnectIdentity = (
372
+ expectedSerialNumber?: string,
373
+ actualSerialNumber?: string,
374
+ expectedPath?: string,
375
+ actualPath?: string
376
+ ) => {
377
+ if (expectedSerialNumber && actualSerialNumber) {
378
+ if (actualSerialNumber !== expectedSerialNumber) {
379
+ throw ERRORS.TypedError(
380
+ HardwareErrorCode.DeviceNotFound,
381
+ `Protocol V2 reconnect physical identity mismatch: expected ${expectedSerialNumber}, received ${actualSerialNumber}`
382
+ );
383
+ }
384
+ return;
385
+ }
386
+
387
+ if (expectedPath && actualPath && expectedPath === actualPath) {
388
+ return;
389
+ }
390
+
391
+ throw ERRORS.TypedError(
392
+ HardwareErrorCode.DeviceNotFound,
393
+ `Protocol V2 reconnect physical identity unavailable: expected path ${
394
+ expectedPath ?? 'unknown'
395
+ }, received ${actualPath ?? 'unknown'}`
396
+ );
397
+ };
398
+
364
399
  /**
365
400
  * FirmwareUpdateV4 is the complete Protocol V2 firmware update flow.
366
401
  *
@@ -370,9 +405,18 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
370
405
  * - completion waits for target status to finish, reboots to normal, then polls DeviceInfo
371
406
  */
372
407
  export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareUpdateV4Params> {
408
+ private protocolV2ExpectedSerialNumber?: string;
409
+
410
+ private protocolV2ExpectedPath?: string;
411
+
412
+ getSupportedProtocols() {
413
+ return ['V2'] as const;
414
+ }
415
+
373
416
  init() {
374
417
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
375
418
  this.requireDeviceMode = [];
419
+ this.unlockPolicy = 'unlock-before-run';
376
420
  this.useDevicePassphraseState = false;
377
421
  this.skipForceUpdateCheck = true;
378
422
 
@@ -393,7 +437,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
393
437
 
394
438
  validateParams(payload, [
395
439
  { name: 'chunkSize', type: 'number' },
396
- { name: 'resourceBinaries', type: 'array', allowEmpty: true },
397
440
  { name: 'forcedUpdateRes', type: 'boolean' },
398
441
  { name: 'bootloaderBinary', type: 'buffer' },
399
442
  { name: 'romloaderBinary', type: 'buffer' },
@@ -405,7 +448,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
405
448
  { name: 'se03Binary', type: 'buffer' },
406
449
  { name: 'se04Binary', type: 'buffer' },
407
450
  { name: 'firmwareType', type: 'string' },
451
+ { name: 'targetsToUpdate', type: 'array', allowEmpty: true },
408
452
  { name: 'platform', type: 'string' },
453
+ { name: 'resourceFiles', type: 'array', allowEmpty: true },
409
454
  ]);
410
455
 
411
456
  this.params = {
@@ -420,8 +465,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
420
465
  se02Binary: payload.se02Binary,
421
466
  se03Binary: payload.se03Binary,
422
467
  se04Binary: payload.se04Binary,
423
- resourceBinaries: payload.resourceBinaries,
468
+ resourceFiles: payload.resourceFiles,
424
469
  firmwareType: payload.firmwareType,
470
+ targetsToUpdate: payload.targetsToUpdate,
425
471
  platform: payload.platform,
426
472
  };
427
473
  }
@@ -429,10 +475,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
429
475
  private getProtocolV2FirmwareChunkSize() {
430
476
  const payloadChunkSize = Number(this.params?.chunkSize);
431
477
  const env = DataManager.getSettings('env');
432
- const maxChunkSize =
433
- this.params?.platform === 'native' || (env && DataManager.isBleConnect(env))
434
- ? PROTOCOL_V2_BLE_FILE_CHUNK_SIZE
435
- : PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
478
+ const isBle = this.params?.platform === 'native' || (env && DataManager.isBleConnect(env));
479
+ let maxChunkSize = PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
480
+ if (isBle) {
481
+ maxChunkSize = PROTOCOL_V2_BLE_FILE_CHUNK_SIZE;
482
+ }
436
483
  if (!Number.isFinite(payloadChunkSize) || payloadChunkSize <= 0) {
437
484
  return maxChunkSize;
438
485
  }
@@ -443,62 +490,101 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
443
490
  }
444
491
 
445
492
  async run() {
446
- if (!this.device.isProtocolV2()) {
447
- throw ERRORS.TypedError(
448
- HardwareErrorCode.RuntimeError,
449
- 'firmwareUpdateV4 requires a Protocol V2 device'
450
- );
451
- }
452
-
453
493
  Log.debug('FirmwareUpdateV4 strategy: Protocol V2');
454
494
  return this.runProtocolV2();
455
495
  }
456
496
 
457
497
  private async runProtocolV2() {
498
+ await this.captureProtocolV2PhysicalIdentity();
458
499
  const deviceFeatures = await this.getProtocolV2DeviceFeatures();
459
500
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
460
501
  const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
502
+ const needsRemoteResources =
503
+ !this.params.resourceFiles?.length && !!this.params.targetsToUpdate?.includes('resource');
461
504
 
462
- let resourceBinaryMap: ProtocolV2TargetBinary[] = [];
463
505
  let fwBinaryMap: ProtocolV2TargetBinary[] = [];
464
506
  let bootloaderBinary: ArrayBuffer | null = null;
465
507
  let installItems: ProtocolV2InstallItem[] | undefined;
508
+ let resourceBundles: ProtocolV2ResourceBundleBinary[] | undefined;
466
509
  try {
467
510
  this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
468
- resourceBinaryMap = await this.prepareResourceBinaries(firmwareType, deviceFeatures);
511
+ resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
469
512
  fwBinaryMap = this.collectExplicitTargetBinaries();
470
513
  bootloaderBinary = this.prepareBootloaderBinary();
471
- if (!this.hasExplicitProtocolV2Payload(fwBinaryMap)) {
514
+ const needsRemoteFirmware = !this.hasExplicitProtocolV2Payload(fwBinaryMap);
515
+ const needsRemoteBootResources = !!this.params.targetsToUpdate?.includes('boot_resources');
516
+ if (needsRemoteFirmware || needsRemoteResources || needsRemoteBootResources) {
517
+ // Remote updates must use a freshly fetched config before any reboot or file write.
518
+ await DataManager.forceReloadData({
519
+ requireResources: needsRemoteResources || needsRemoteBootResources,
520
+ });
521
+ }
522
+ if (needsRemoteFirmware) {
472
523
  const remoteBinaries = await this.prepareRemoteProtocolV2Binaries(
473
524
  firmwareType,
474
525
  deviceFeatures
475
526
  );
476
- resourceBinaryMap = remoteBinaries.resourceBinaryMap;
477
527
  bootloaderBinary = remoteBinaries.bootloaderBinary;
478
528
  fwBinaryMap = remoteBinaries.fwBinaryMap;
479
529
  installItems = remoteBinaries.installItems;
480
530
  }
481
- this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
531
+ const bootResourceFiles = await this.prepareProtocolV2BootResources();
532
+ if (bootResourceFiles?.length) {
533
+ resourceBundles = [...(resourceBundles ?? []), ...bootResourceFiles];
534
+ }
535
+ if (!needsRemoteResources) {
536
+ this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
537
+ }
482
538
  } catch (err) {
539
+ if (err instanceof HardwareError && err.errorCode === HardwareErrorCode.NetworkError) {
540
+ throw err;
541
+ }
483
542
  throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
484
543
  }
485
544
 
486
- if (resourceBinaryMap.length === 0 && !bootloaderBinary && fwBinaryMap.length === 0) {
545
+ if (
546
+ !bootloaderBinary &&
547
+ fwBinaryMap.length === 0 &&
548
+ !installItems?.length &&
549
+ !resourceBundles?.length &&
550
+ !needsRemoteResources
551
+ ) {
487
552
  throw ERRORS.TypedError(
488
553
  HardwareErrorCode.FirmwareUpdateDownloadFailed,
489
554
  'No firmware to update'
490
555
  );
491
556
  }
492
557
 
493
- await this.enterProtocolV2BootloaderMode();
558
+ const enteredBootloader = await this.enterProtocolV2BootloaderMode();
559
+
560
+ if (needsRemoteResources) {
561
+ try {
562
+ const stableResources = await this.prepareProtocolV2ResourceBundles();
563
+ resourceBundles = [...(resourceBundles ?? []), ...(stableResources ?? [])];
564
+ this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
565
+ } catch (err) {
566
+ if (enteredBootloader) {
567
+ try {
568
+ await this.exitProtocolV2BootloaderToNormal();
569
+ } catch (restoreError) {
570
+ Log.warn(
571
+ '[FirmwareUpdateV4] failed to restore App mode after resource preparation error:',
572
+ restoreError
573
+ );
574
+ }
575
+ }
576
+ throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
577
+ }
578
+ }
494
579
 
495
580
  await this.executeProtocolV2Update({
496
- resourceBinaryMap,
497
581
  fwBinaryMap,
498
582
  bootloaderBinary,
499
583
  ...(installItems ? { installItems } : undefined),
584
+ ...(resourceBundles?.length ? { resourceBundles } : undefined),
500
585
  });
501
586
 
587
+ this.postTipMessage(FirmwareUpdateTipMessage.SwitchFirmwareReconnectDevice);
502
588
  await this.exitProtocolV2BootloaderToNormal();
503
589
 
504
590
  const versions = await this.waitForProtocolV2FinalFeatures();
@@ -519,41 +605,46 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
519
605
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Device features not available');
520
606
  }
521
607
 
522
- private async prepareResourceBinaries(firmwareType: EFirmwareType, features: Features) {
523
- if (this.params.resourceBinaries?.length) {
524
- this.params.resourceBinaries.forEach((binary, index) => {
525
- if (!(binary instanceof ArrayBuffer)) {
526
- throw ERRORS.TypedError(
527
- HardwareErrorCode.CallMethodInvalidParameter,
528
- `Parameter [resourceBinaries.${index}] is of type invalid and should be [buffer].`
529
- );
530
- }
531
- });
608
+ private getProtocolV2SerialNumber(deviceInfo: ProtocolV2DeviceInfo) {
609
+ const serialNumber = deviceInfo.hw?.serial_no?.trim();
610
+ return serialNumber || undefined;
611
+ }
532
612
 
533
- return this.params.resourceBinaries.map((binary, index) => ({
534
- fileName: `resource-${index + 1}.bin`,
535
- binary,
536
- targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
537
- }));
538
- }
539
- const resourceUrl = DataManager.getSysResourcesLatestRelease({
540
- features,
541
- forcedUpdateRes: this.params.forcedUpdateRes,
542
- firmwareType,
613
+ private assertProtocolV2DeviceInfoIdentity(deviceInfo: ProtocolV2DeviceInfo) {
614
+ assertProtocolV2ReconnectIdentity(
615
+ this.protocolV2ExpectedSerialNumber,
616
+ this.getProtocolV2SerialNumber(deviceInfo),
617
+ this.protocolV2ExpectedPath,
618
+ this.device.originalDescriptor.path
619
+ );
620
+ }
621
+
622
+ private getProtocolV2DeviceInfoTimeout() {
623
+ return this.isBleReconnect()
624
+ ? this.payload.protocolV2DeviceInfoTimeoutMs ?? PROTOCOL_V2_DEVICE_INFO_READY_TIMEOUT
625
+ : PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT;
626
+ }
627
+
628
+ private async requestProtocolV2PhysicalIdentity() {
629
+ return requestProtocolV2DeviceInfo({
630
+ commands: this.device.getCommands(),
631
+ timeoutMs: this.getProtocolV2DeviceInfoTimeout(),
543
632
  });
633
+ }
544
634
 
545
- if (resourceUrl) {
546
- const resource = (await getSysResourceBinary(resourceUrl)).binary;
547
- return [
548
- {
549
- fileName: 'resource.bin',
550
- binary: resource,
551
- targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
552
- },
553
- ];
554
- }
555
- Log.warn('No resource url found');
556
- return [];
635
+ private async captureProtocolV2PhysicalIdentity() {
636
+ const deviceInfo = await this.requestProtocolV2PhysicalIdentity();
637
+ const serialNumber = this.getProtocolV2SerialNumber(deviceInfo);
638
+ const path = this.device.originalDescriptor.path?.trim() || undefined;
639
+ assertProtocolV2ReconnectIdentity(serialNumber, serialNumber, path, path);
640
+ this.protocolV2ExpectedSerialNumber = serialNumber;
641
+ this.protocolV2ExpectedPath = path;
642
+ }
643
+
644
+ private async verifyProtocolV2ReconnectIdentity() {
645
+ const deviceInfo = await this.requestProtocolV2PhysicalIdentity();
646
+ this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
647
+ return deviceInfo;
557
648
  }
558
649
 
559
650
  private prepareBootloaderBinary(): ArrayBuffer | null {
@@ -562,25 +653,20 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
562
653
 
563
654
  private hasExplicitProtocolV2Payload(fwBinaryMap: ProtocolV2TargetBinary[]) {
564
655
  return (
565
- !!this.params.resourceBinaries?.length ||
656
+ !!this.params.resourceFiles?.length ||
566
657
  !!this.params.bootloaderBinary ||
567
658
  fwBinaryMap.length > 0
568
659
  );
569
660
  }
570
661
 
571
662
  private buildProtocolV2InstallItems({
572
- resourceBinaryMap,
573
663
  bootloaderBinary,
574
664
  fwBinaryMap,
575
665
  }: {
576
- resourceBinaryMap: ProtocolV2TargetBinary[];
577
666
  bootloaderBinary: ArrayBuffer | null;
578
667
  fwBinaryMap: ProtocolV2TargetBinary[];
579
668
  }): ProtocolV2InstallItem[] {
580
- const installItems: ProtocolV2InstallItem[] = resourceBinaryMap.map(resource => ({
581
- ...resource,
582
- kind: 'resource',
583
- }));
669
+ const installItems: ProtocolV2InstallItem[] = [];
584
670
 
585
671
  if (bootloaderBinary) {
586
672
  installItems.push({
@@ -630,203 +716,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
630
716
  return target;
631
717
  }
632
718
 
633
- private getProtocolV2ComponentTargetVersion(
634
- release: IFirmwareReleaseInfo,
635
- component: IProtocolV2FirmwareComponent,
636
- target: ProtocolV2RemoteComponentTarget
637
- ) {
638
- if (component.version) return component.version;
639
- if (target.targetId === ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER) {
640
- return release.bootloaderVersion;
641
- }
642
- if (
643
- target.targetId === ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1 ||
644
- target.targetId === ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2
645
- ) {
646
- return release.version;
647
- }
648
- return undefined;
649
- }
650
-
651
- private getProtocolV2ComponentCurrentVersion(
652
- features: Features,
653
- target: ProtocolV2RemoteComponentTarget
654
- ) {
655
- switch (target.targetId) {
656
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER:
657
- return getDeviceBootloaderVersion(features);
658
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1:
659
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2:
660
- return getDeviceFirmwareVersion(features);
661
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR:
662
- return getDeviceBLEFirmwareVersion(features);
663
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01:
664
- return versionStringToArray(features.se01Version);
665
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02:
666
- return versionStringToArray(features.se02Version);
667
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03:
668
- return versionStringToArray(features.se03Version);
669
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04:
670
- return versionStringToArray(features.se04Version);
671
- default:
672
- return undefined;
673
- }
674
- }
675
-
676
- private isProtocolV2ComponentVersionSatisfied(
677
- release: IFirmwareReleaseInfo,
678
- component: IProtocolV2FirmwareComponent,
679
- target: ProtocolV2RemoteComponentTarget,
680
- features: Features
681
- ) {
682
- const targetVersion = this.getProtocolV2ComponentTargetVersion(release, component, target);
683
- if (!targetVersion) return false;
684
-
685
- const currentVersion = this.getProtocolV2ComponentCurrentVersion(features, target);
686
- const compareResult = compareProtocolV2Versions(currentVersion, targetVersion);
687
- return compareResult !== undefined && compareResult >= 0;
688
- }
689
-
690
- private getProtocolV2ResourceFilePath(path: string) {
691
- if (path.startsWith('vol')) return path;
692
- if (path.startsWith('/')) return `vol0:${path}`;
693
- return `vol0:/${path}`;
694
- }
695
-
696
- private async readProtocolV2DeviceFileHeader(path: string) {
697
- const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
698
- const filePath = this.getProtocolV2ResourceFilePath(path);
699
- const pathInfoRes = await typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', {
700
- path: filePath,
701
- });
702
- const fileSize = toProtocolV2FiniteNumber(pathInfoRes.message?.size);
703
- if (
704
- !pathInfoRes.message?.exist ||
705
- pathInfoRes.message?.directory ||
706
- fileSize === undefined ||
707
- fileSize < PROTOCOL_V2_OKPP_HEADER_SIZE
708
- ) {
709
- return null;
710
- }
711
-
712
- const chunkSize = this.getProtocolV2FirmwareChunkSize();
713
- const chunks: Uint8Array[] = [];
714
- let offset = 0;
715
- while (offset < PROTOCOL_V2_OKPP_HEADER_SIZE) {
716
- const readLen = Math.min(chunkSize, PROTOCOL_V2_OKPP_HEADER_SIZE - offset);
717
- const res = await typedCall('FilesystemFileRead', 'FilesystemFile', {
718
- file: {
719
- path: filePath,
720
- offset,
721
- total_size: 0,
722
- },
723
- chunk_len: readLen,
724
- ui_percentage: undefined,
725
- });
726
- const data = toProtocolV2Bytes(res.message?.data);
727
- if (data.byteLength === 0) return null;
728
- chunks.push(data);
729
- offset += data.byteLength;
730
- }
731
-
732
- const headerBytes = new Uint8Array(offset);
733
- let cursor = 0;
734
- chunks.forEach(chunk => {
735
- headerBytes.set(chunk, cursor);
736
- cursor += chunk.byteLength;
737
- });
738
- return parseProtocolV2OkppHeader(headerBytes);
739
- }
740
-
741
- private async isProtocolV2ResourcePackageMatched(
742
- pkg: IProtocolV2ResourceManifestPackage,
743
- manifestVersion?: IVersionArray
744
- ) {
745
- try {
746
- const header = await this.readProtocolV2DeviceFileHeader(pkg.path);
747
- if (!header) return false;
748
-
749
- const expectedType = pkg.type ?? 'RESC';
750
- const expectedVersion = pkg.version ?? manifestVersion;
751
- if (header.type !== expectedType) return false;
752
- if (expectedVersion && compareProtocolV2Versions(header.version, expectedVersion) !== 0) {
753
- return false;
754
- }
755
-
756
- const expectedPayloadHash = normalizeProtocolV2Hex(pkg.payloadHash);
757
- if (expectedPayloadHash && header.payloadHash !== expectedPayloadHash) return false;
758
-
759
- const expectedHeaderHash = normalizeProtocolV2Hex(pkg.headerHash);
760
- if (expectedHeaderHash && header.headerHash !== expectedHeaderHash) return false;
761
-
762
- return true;
763
- } catch (error) {
764
- Log.log(`Protocol V2 resource package check failed for ${pkg.path}: `, error);
765
- return false;
766
- }
767
- }
768
-
769
- private async isProtocolV2ResourceManifestSatisfied(
770
- manifest: IFirmwareReleaseInfo['resourceManifest']
771
- ) {
772
- if (!manifest?.packages?.length) return false;
773
-
774
- for (const pkg of manifest.packages) {
775
- if (!(await this.isProtocolV2ResourcePackageMatched(pkg, manifest.version))) {
776
- return false;
777
- }
778
- }
779
- return true;
780
- }
781
-
782
- private getProtocolV2ResourceManifest(
783
- release: IFirmwareReleaseInfo,
784
- component: IProtocolV2FirmwareComponent
785
- ) {
786
- return component.resourceManifest ?? release.resourceManifest;
787
- }
788
-
789
- private getProtocolV2ResourceComponentFileName(key: string) {
790
- const safeKey = key.replace(/[^a-z0-9_-]/gi, '_') || 'resource';
791
- return `resource-${safeKey}.bin`;
792
- }
793
-
794
- private async shouldInstallRemoteProtocolV2Component(
795
- release: IFirmwareReleaseInfo,
796
- key: string,
797
- component: IProtocolV2FirmwareComponent,
798
- target: ProtocolV2RemoteComponentTarget,
799
- features: Features
800
- ) {
801
- if (target.kind === 'resource') {
802
- if (
803
- this.params.forcedUpdateRes ||
804
- features.bootloaderMode ||
805
- features.mode === 'bootloader'
806
- ) {
807
- return true;
808
- }
809
- const resourceMatched = await this.isProtocolV2ResourceManifestSatisfied(
810
- this.getProtocolV2ResourceManifest(release, component)
811
- );
812
- if (resourceMatched) {
813
- Log.log(`[FirmwareUpdateV4] skip Protocol V2 resource component ${key}; manifest matched`);
814
- }
815
- return !resourceMatched;
816
- }
817
-
818
- const versionSatisfied = this.isProtocolV2ComponentVersionSatisfied(
819
- release,
820
- component,
821
- target,
822
- features
823
- );
824
- if (versionSatisfied) {
825
- Log.log(`[FirmwareUpdateV4] skip Protocol V2 component ${key}; version is up to date`);
826
- }
827
- return !versionSatisfied;
828
- }
829
-
830
719
  private async downloadRemoteProtocolV2Component(
831
720
  key: string,
832
721
  component: IProtocolV2FirmwareComponent
@@ -840,6 +729,22 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
840
729
  }
841
730
 
842
731
  const { binary } = await getSysResourceBinary(component.url);
732
+ if (!isProtocolV2FirmwareFingerprintValid(binary, component.fingerprint)) {
733
+ throw ERRORS.TypedError(
734
+ HardwareErrorCode.RuntimeError,
735
+ `Protocol V2 firmware fingerprint mismatch: ${key}/${component.target}`
736
+ );
737
+ }
738
+ const expectedPayloadHash = normalizeProtocolV2Hex(component.payloadHash);
739
+ if (expectedPayloadHash) {
740
+ const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(binary));
741
+ if (!header || header.payloadHash !== expectedPayloadHash) {
742
+ throw ERRORS.TypedError(
743
+ HardwareErrorCode.RuntimeError,
744
+ `Protocol V2 firmware payload hash mismatch: ${key}/${component.target}`
745
+ );
746
+ }
747
+ }
843
748
  return {
844
749
  ...target,
845
750
  binary,
@@ -849,14 +754,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
849
754
  private async prepareRemoteProtocolV2Binaries(firmwareType: EFirmwareType, features: Features) {
850
755
  const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
851
756
 
852
- const resourceBinaryMap: ProtocolV2TargetBinary[] = [];
853
757
  let bootloaderBinary: ArrayBuffer | null = null;
854
758
  const fwBinaryMap: ProtocolV2TargetBinary[] = [];
855
759
  const installItems: ProtocolV2InstallItem[] = [];
856
760
 
857
761
  if (!release) {
858
762
  return {
859
- resourceBinaryMap,
860
763
  bootloaderBinary,
861
764
  fwBinaryMap,
862
765
  installItems,
@@ -864,27 +767,17 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
864
767
  }
865
768
 
866
769
  const entries = this.getRemoteComponentEntries(release);
770
+ const targetsToUpdate = new Set(this.params.targetsToUpdate ?? []);
867
771
 
868
772
  for (const [key, component] of entries) {
869
- const target = this.getRemoteComponentTarget(key, component);
870
- const shouldInstall = await this.shouldInstallRemoteProtocolV2Component(
871
- release,
872
- key,
873
- component,
874
- target,
875
- features
876
- );
877
- if (shouldInstall) {
773
+ const targetName = component.target?.toUpperCase();
774
+ const target = PROTOCOL_V2_REMOTE_COMPONENT_TARGETS[targetName];
775
+ const updateTarget = target
776
+ ? PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId)
777
+ : undefined;
778
+ if (updateTarget && targetsToUpdate.has(updateTarget)) {
878
779
  const remoteBinary = await this.downloadRemoteProtocolV2Component(key, component);
879
- if (remoteBinary.kind === 'resource') {
880
- const binaryEntry = {
881
- fileName: this.getProtocolV2ResourceComponentFileName(key),
882
- binary: remoteBinary.binary,
883
- targetId: remoteBinary.targetId,
884
- };
885
- resourceBinaryMap.push(binaryEntry);
886
- installItems.push({ ...binaryEntry, kind: remoteBinary.kind });
887
- } else if (remoteBinary.kind === 'bootloader') {
780
+ if (remoteBinary.kind === 'bootloader') {
888
781
  bootloaderBinary = remoteBinary.binary;
889
782
  installItems.push({
890
783
  fileName: remoteBinary.fileName,
@@ -905,32 +798,205 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
905
798
  }
906
799
 
907
800
  return {
908
- resourceBinaryMap,
909
801
  bootloaderBinary,
910
802
  fwBinaryMap,
911
803
  installItems,
912
804
  };
913
805
  }
914
806
 
807
+ private getProtocolV2DeviceType(): EDeviceType.Pro2 | EDeviceType.Neo {
808
+ const deviceType = this.device.getCurrentDeviceType();
809
+ if (deviceType === EDeviceType.Pro2 || deviceType === EDeviceType.Neo) return deviceType;
810
+ throw new Error(`Unsupported Protocol V2 device type: ${deviceType}`);
811
+ }
812
+
813
+ private async prepareProtocolV2BootResources(): Promise<
814
+ ProtocolV2ResourceBundleBinary[] | undefined
815
+ > {
816
+ if (!this.params.targetsToUpdate?.includes('boot_resources')) return undefined;
817
+ const resource = DataManager.getProtocolV2BootResources(this.getProtocolV2DeviceType());
818
+ if (!resource) throw new Error('Missing Protocol V2 boot resources configuration');
819
+
820
+ const files: ProtocolV2ResourceBundleBinary[] = [];
821
+ for (const file of resource.files) {
822
+ Log.log(`[FirmwareUpdateV4] downloading boot resource ${file.devicePath}`);
823
+ const { binary } = await getSysResourceBinary(file.url);
824
+ if (!isProtocolV2ResourceFileValid(binary, file)) {
825
+ throw new Error(`Boot resource file verification failed: ${file.devicePath}`);
826
+ }
827
+ files.push({
828
+ name: file.name ?? file.devicePath.split('/').pop() ?? file.devicePath,
829
+ binary,
830
+ devicePath: file.devicePath,
831
+ });
832
+ }
833
+ return files;
834
+ }
835
+
836
+ private prepareExplicitProtocolV2ResourceFiles(): ProtocolV2ResourceBundleBinary[] | undefined {
837
+ const files = this.params.resourceFiles ?? [];
838
+ if (!files?.length) return undefined;
839
+
840
+ const prepared = files.map((file, index) => {
841
+ const devicePath = validateProtocolV2FilesystemPath(
842
+ file.devicePath,
843
+ `resourceFiles[${index}].devicePath`
844
+ );
845
+ const descriptor = file as typeof file &
846
+ Pick<Partial<IProtocolV2ResourceFile>, 'size' | 'fileHash'>;
847
+ if (descriptor.size !== undefined && descriptor.size !== file.binary.byteLength) {
848
+ throw new Error(`resourceFiles[${index}] size mismatch`);
849
+ }
850
+ if (
851
+ descriptor.fileHash &&
852
+ !isProtocolV2ResourceFileValid(file.binary, {
853
+ size: file.binary.byteLength,
854
+ fileHash: descriptor.fileHash,
855
+ })
856
+ ) {
857
+ throw new Error(`resourceFiles[${index}] SHA-256 mismatch`);
858
+ }
859
+ return {
860
+ name: devicePath.split('/').pop() ?? devicePath,
861
+ binary: file.binary,
862
+ devicePath,
863
+ };
864
+ });
865
+ if (new Set(prepared.map(file => file.devicePath)).size !== prepared.length) {
866
+ throw new Error('resourceFiles contain duplicate devicePath values');
867
+ }
868
+ return prepared;
869
+ }
870
+
871
+ private async prepareProtocolV2ResourceBundles(): Promise<
872
+ ProtocolV2ResourceBundleBinary[] | undefined
873
+ > {
874
+ if (!this.params.targetsToUpdate?.includes('resource')) {
875
+ return undefined;
876
+ }
877
+
878
+ const resources = DataManager.getProtocolV2Resources(this.getProtocolV2DeviceType());
879
+ if (!resources?.length) {
880
+ throw new Error('Missing Pro2 stable resource configuration');
881
+ }
882
+
883
+ const inventory = this.params.forcedUpdateRes
884
+ ? undefined
885
+ : await readProtocolV2ResourceInventory({
886
+ commands: this.device.getCommands(),
887
+ resources,
888
+ chunkSize: this.getProtocolV2FirmwareChunkSize(),
889
+ timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
890
+ });
891
+ const plan = buildProtocolV2ResourceUpdatePlan({
892
+ resources,
893
+ inventory,
894
+ mode: 'bootloader-recovery',
895
+ forced: this.params.forcedUpdateRes,
896
+ });
897
+ Log.log(
898
+ `[FirmwareUpdateV4] Protocol V2 resource plan mode=bootloader-recovery status=${plan.status} count=${plan.resources.length}`
899
+ );
900
+
901
+ const bundles: ProtocolV2ResourceBundleBinary[] = [];
902
+ for (const resource of plan.resources) {
903
+ bundles.push(await this.downloadProtocolV2Resource(resource));
904
+ }
905
+ return bundles;
906
+ }
907
+
908
+ private async downloadProtocolV2Resource(
909
+ resource: IProtocolV2Resource
910
+ ): Promise<ProtocolV2ResourceBundleBinary> {
911
+ Log.log(`[FirmwareUpdateV4] downloading Pro2 resource ${resource.type}`);
912
+ const { binary } = await getSysResourceBinary(resource.url);
913
+ if (!isProtocolV2ResourceFileValid(binary, resource)) {
914
+ throw new Error(`Pro2 resource file verification failed: ${resource.type}`);
915
+ }
916
+ return {
917
+ name: `${resource.type}.okpkg`,
918
+ binary,
919
+ devicePath: PROTOCOL_V2_RESOURCE_DEVICE_PATHS[resource.type],
920
+ };
921
+ }
922
+
923
+ private async syncProtocolV2ResourceBundles(
924
+ bundles: ProtocolV2ResourceBundleBinary[],
925
+ firmwareSize: number
926
+ ): Promise<{ processedSize: number; totalSize: number }> {
927
+ const transferStartTime = Date.now();
928
+ const transferTransport = this.getProtocolV2FirmwareTransferTransport();
929
+
930
+ // Write directly to the device through FileWrite.
931
+ let totalSize = 0;
932
+ for (const b of bundles) totalSize += b.binary.byteLength;
933
+
934
+ const transferTotalSize = totalSize + firmwareSize;
935
+ let processedSize = 0;
936
+ for (const bundle of bundles) {
937
+ Log.log(
938
+ `[FirmwareUpdateV4] syncing resource ${bundle.name} -> ${bundle.devicePath} bytes=${bundle.binary.byteLength}`
939
+ );
940
+ processedSize = await this.protocolV2CommonUpdateProcess({
941
+ payload: bundle.binary,
942
+ filePath: bundle.devicePath,
943
+ processedSize,
944
+ totalSize: transferTotalSize,
945
+ });
946
+ }
947
+
948
+ const elapsedMs = Date.now() - transferStartTime;
949
+ Log.log(
950
+ `[FirmwareUpdateV4] resource sync finished transport=${transferTransport} bytes=${totalSize} elapsed=${(
951
+ elapsedMs / 1000
952
+ ).toFixed(2)}s speed=${formatProtocolV2TransferSpeed(totalSize, elapsedMs)} KB/s`
953
+ );
954
+ return { processedSize, totalSize: transferTotalSize };
955
+ }
956
+
915
957
  private isProtocolV2BootloaderMode() {
916
958
  if (typeof this.device.isBootloader === 'function') {
917
- return this.device.isBootloader();
959
+ return !!this.device.isBootloader();
918
960
  }
919
- return !!this.device.features?.bootloaderMode;
961
+ return (
962
+ this.device.features?.mode === 'bootloader' ||
963
+ (this.device.features?.mode == null && !!this.device.features?.bootloaderMode)
964
+ );
965
+ }
966
+
967
+ private isProtocolV2RomloaderMode() {
968
+ const deviceType = this.device.getCurrentDeviceType();
969
+ if (
970
+ !this.device.isProtocolV2() ||
971
+ (deviceType !== EDeviceType.Pro2 && deviceType !== EDeviceType.Neo)
972
+ ) {
973
+ return false;
974
+ }
975
+ if (typeof this.device.isRomloader === 'function') {
976
+ return this.device.isRomloader();
977
+ }
978
+ return this.device.features?.mode === 'romloader';
920
979
  }
921
980
 
922
981
  async enterProtocolV2BootloaderMode() {
982
+ // romloader is the first update environment and forwards targets to bootloader.
983
+ // It rejects DeviceRebootType.Bootloader, so reuse the current connection.
984
+ if (this.isProtocolV2RomloaderMode()) {
985
+ Log.debug('Protocol V2 device is in romloader mode; start firmware update directly');
986
+ return false;
987
+ }
923
988
  if (this.isProtocolV2BootloaderMode()) {
924
- Log.debug('Protocol V2 device is already in bootloader mode, skip reboot to bootloader');
989
+ Log.debug('Protocol V2 device is already in bootloader mode, skip reboot');
990
+ this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
925
991
  return false;
926
992
  }
927
993
 
928
994
  try {
929
995
  this.postTipMessage(FirmwareUpdateTipMessage.AutoRebootToBootloader);
930
996
  await this.protocolV2Reboot(DeviceRebootType.Bootloader);
931
- this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
932
997
  await wait(1000);
933
998
  await this.waitForProtocolV2BootloaderMode();
999
+ this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
934
1000
  return true;
935
1001
  } catch (error) {
936
1002
  if (error instanceof HardwareError) {
@@ -947,20 +1013,32 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
947
1013
  ) {
948
1014
  const startTime = Date.now();
949
1015
  let lastError: unknown;
1016
+ let shouldReconnect = true;
950
1017
 
951
1018
  while (Date.now() - startTime < timeout) {
952
1019
  try {
953
- await this.reconnectProtocolV2Device();
1020
+ if (shouldReconnect) {
1021
+ await this.reconnectProtocolV2Device();
1022
+ shouldReconnect = false;
1023
+ }
954
1024
  const deviceInfo = await requestProtocolV2DeviceInfo({
955
1025
  commands: this.device.getCommands(),
956
- timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
1026
+ timeoutMs: this.getProtocolV2DeviceInfoTimeout(),
957
1027
  });
958
- const features = this.device.updateProtocolV2Features(deviceInfo);
959
- if (features?.bootloaderMode) {
1028
+ this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
1029
+ const features = await this.device.probeProtocolV2RuntimeState(
1030
+ deviceInfo,
1031
+ PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
1032
+ );
1033
+ if (features?.mode === 'bootloader') {
960
1034
  return features;
961
1035
  }
962
1036
  lastError = new Error('Protocol V2 device is reachable but is not in bootloader mode');
963
1037
  } catch (error) {
1038
+ if (this.isProtocolV2ReconnectIdentityError(error)) {
1039
+ throw error;
1040
+ }
1041
+ shouldReconnect = true;
964
1042
  lastError = error;
965
1043
  Log.log('Protocol V2 bootloader mode not ready, polling reconnect: ', error);
966
1044
  }
@@ -976,8 +1054,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
976
1054
  }
977
1055
 
978
1056
  /**
979
- * 收集按 DeviceFirmwareTargetType 拆分的显式目标二进制。
980
- * 文件名仅用于 staging 路径展示,target_id 已显式给定。
1057
+ * Collect explicit target binaries grouped by DeviceFirmwareTargetType.
1058
+ * Filenames are display-only staging paths because target_id is explicit.
981
1059
  */
982
1060
  private collectExplicitTargetBinaries() {
983
1061
  const entries: ProtocolV2TargetBinary[] = [];
@@ -1014,30 +1092,48 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1014
1092
  }
1015
1093
 
1016
1094
  private async executeProtocolV2Update({
1017
- resourceBinaryMap,
1018
1095
  fwBinaryMap,
1019
1096
  bootloaderBinary,
1020
1097
  installItems,
1098
+ resourceBundles,
1021
1099
  }: {
1022
- resourceBinaryMap?: ProtocolV2TargetBinary[];
1023
1100
  fwBinaryMap?: ProtocolV2TargetBinary[];
1024
1101
  bootloaderBinary?: ArrayBuffer | null;
1025
1102
  installItems?: ProtocolV2InstallItem[];
1103
+ resourceBundles?: ProtocolV2ResourceBundleBinary[];
1026
1104
  }) {
1027
1105
  const orderedInstallItems =
1028
1106
  installItems ??
1029
1107
  this.buildProtocolV2InstallItems({
1030
- resourceBinaryMap: resourceBinaryMap ?? [],
1031
1108
  bootloaderBinary: bootloaderBinary ?? null,
1032
1109
  fwBinaryMap: fwBinaryMap ?? [],
1033
1110
  });
1034
- let totalSize = 0;
1035
- let processedSize = 0;
1036
- let transferredSize = 0;
1037
1111
 
1038
- for (const item of orderedInstallItems) totalSize += item.binary.byteLength;
1112
+ let firmwareSize = 0;
1113
+ for (const item of orderedInstallItems) firmwareSize += item.binary.byteLength;
1039
1114
 
1040
1115
  this.postTipMessage(FirmwareUpdateTipMessage.StartTransferData);
1116
+
1117
+ let processedSize = 0;
1118
+ let totalSize = firmwareSize;
1119
+ if (resourceBundles?.length) {
1120
+ const resourceTransfer = await this.syncProtocolV2ResourceBundles(
1121
+ resourceBundles,
1122
+ firmwareSize
1123
+ );
1124
+ processedSize = resourceTransfer.processedSize;
1125
+ totalSize = resourceTransfer.totalSize;
1126
+ }
1127
+
1128
+ // Skip staging and installation when the update contains resource files only.
1129
+ if (orderedInstallItems.length === 0) {
1130
+ Log.log('[FirmwareUpdateV4] no firmware targets to install (resource files only)');
1131
+ if (totalSize > 0) {
1132
+ this.postProgressMessage(100, 'transferData');
1133
+ }
1134
+ return;
1135
+ }
1136
+ let transferredSize = processedSize;
1041
1137
  const transferStartTime = Date.now();
1042
1138
  const transferTransport = this.getProtocolV2FirmwareTransferTransport();
1043
1139
  const chunkSize = this.getProtocolV2FirmwareChunkSize();
@@ -1064,6 +1160,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1064
1160
  onTransferredBytes,
1065
1161
  });
1066
1162
  transferredSize = processedSize;
1163
+ await this.verifyProtocolV2StagedFile(filePath, item.binary.byteLength);
1067
1164
 
1068
1165
  stagedInstallTargets.push({
1069
1166
  ...item,
@@ -1093,203 +1190,289 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1093
1190
 
1094
1191
  this.postTipMessage(FirmwareUpdateTipMessage.ConfirmOnDevice);
1095
1192
 
1096
- const firmwareTargets: Array<{ target_id: number; path: string }> = [];
1097
- const flushFirmwareTargets = async () => {
1098
- if (firmwareTargets.length === 0) return;
1099
- const targets = firmwareTargets.splice(0, firmwareTargets.length);
1100
- Log.log(`[FirmwareUpdateV4] DeviceFirmwareUpdateRequest targets=${JSON.stringify(targets)}`);
1101
- const startResponse = await this.protocolV2StartFirmwareUpdate({ targets });
1102
- await this.waitForProtocolV2FirmwareUpdateComplete(targets, startResponse);
1103
- };
1104
-
1105
- for (const item of stagedInstallTargets) {
1106
- const target = {
1107
- target_id: item.targetId,
1108
- path: item.path,
1109
- };
1110
- if (item.kind === 'resource') {
1111
- await flushFirmwareTargets();
1112
- const resourceTargets = [target];
1113
- Log.log(
1114
- `[FirmwareUpdateV4] DeviceFirmwareUpdateRequest resources=${JSON.stringify(
1115
- resourceTargets
1116
- )}`
1117
- );
1118
- const startResponse = await this.protocolV2StartFirmwareUpdate({
1119
- targets: resourceTargets,
1120
- });
1121
- await this.waitForProtocolV2FirmwareUpdateComplete(resourceTargets, startResponse);
1122
- } else {
1123
- firmwareTargets.push(target);
1124
- }
1125
- }
1126
-
1127
- await flushFirmwareTargets();
1193
+ const allTargets = stagedInstallTargets.map(item => ({
1194
+ target_id: item.targetId,
1195
+ path: item.path,
1196
+ }));
1197
+ Log.log(`[FirmwareUpdateV4] DeviceFirmwareUpdateRequest targets=${JSON.stringify(allTargets)}`);
1198
+ await this.protocolV2StartFirmwareUpdate({ targets: allTargets });
1199
+ await this.waitForProtocolV2FirmwareUpdateComplete(allTargets);
1128
1200
  }
1129
1201
 
1130
1202
  private getProtocolV2InstallItemStagingPath(item: ProtocolV2InstallItem) {
1131
1203
  return `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${item.fileName}`;
1132
1204
  }
1133
1205
 
1134
- private async queryProtocolV2FirmwareUpdateStatus() {
1206
+ private async verifyProtocolV2StagedFile(path: string, expectedSize: number) {
1135
1207
  const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
1136
- return typedCall(
1137
- 'DeviceFirmwareUpdateStatusGet',
1138
- 'DeviceFirmwareUpdateStatus',
1139
- {},
1140
- {
1141
- timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
1142
- }
1143
- );
1144
- }
1145
-
1146
- private async pingProtocolV2Device() {
1147
- const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
1148
- await typedCall(
1149
- 'Ping',
1150
- 'Success',
1151
- { message: 'firmware-update' },
1152
- {
1153
- timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
1154
- }
1155
- );
1156
- }
1157
-
1158
- private isProtocolV2NormalModeFeatures(features?: Features | null) {
1159
- return !!features && !features.bootloaderMode && features.mode !== 'bootloader';
1160
- }
1161
-
1162
- private async probeProtocolV2NormalMode() {
1163
- const deviceInfo = await requestProtocolV2DeviceInfo({
1164
- commands: this.device.getCommands(),
1165
- timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
1166
- request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
1167
- });
1168
- const features = this.device.updateProtocolV2Features(deviceInfo);
1169
- if (this.isProtocolV2NormalModeFeatures(features)) {
1170
- Log.log('Protocol V2 firmware install finished; device is back in normal mode');
1171
- return true;
1208
+ const response = await typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', { path });
1209
+ const actualSize = toProtocolV2FiniteNumber(response.message?.size);
1210
+ if (!response.message?.exist || response.message?.directory || actualSize !== expectedSize) {
1211
+ throw ERRORS.TypedError(
1212
+ HardwareErrorCode.EmmcFileWriteFirmwareError,
1213
+ `staged file verification failed: path=${path} exist=${!!response.message
1214
+ ?.exist} expected=${expectedSize} actual=${actualSize ?? 'unknown'}`
1215
+ );
1172
1216
  }
1173
- return false;
1174
1217
  }
1175
1218
 
1176
1219
  private assertProtocolV2TargetStatus(
1177
1220
  statusTargets: ProtocolV2FirmwareUpdateStatusTarget[],
1178
1221
  expectedTargetIds: Set<number>
1179
1222
  ) {
1223
+ Log.log(
1224
+ `[FirmwareUpdateV4] DeviceFirmwareUpdateStatus records=${JSON.stringify(statusTargets)}`
1225
+ );
1180
1226
  const failedTarget = statusTargets.find(
1181
1227
  target =>
1182
1228
  expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
1183
1229
  isProtocolV2TargetStatusFailed(target.status)
1184
1230
  );
1185
1231
  if (failedTarget) {
1232
+ const failedTargetDetails = JSON.stringify({
1233
+ targetId: failedTarget.target_id,
1234
+ status: failedTarget.status,
1235
+ payloadVersion: failedTarget.payload_version,
1236
+ path: failedTarget.path,
1237
+ });
1238
+ Log.error(`[FirmwareUpdateV4] firmware install failed target=${failedTargetDetails}`);
1186
1239
  throw ERRORS.TypedError(
1187
1240
  HardwareErrorCode.FirmwareError,
1188
- `Protocol V2 firmware target ${failedTarget.target_id} failed`
1241
+ `Protocol V2 firmware target failed: target=${failedTarget.target_id} status=${
1242
+ failedTarget.status ?? 'unknown'
1243
+ } payloadVersion=${failedTarget.payload_version ?? 'unknown'} path=${
1244
+ failedTarget.path ?? 'unknown'
1245
+ }`
1189
1246
  );
1190
1247
  }
1191
1248
 
1192
- const completedTargets = statusTargets.filter(
1193
- target =>
1194
- expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
1195
- isProtocolV2TargetStatusFinished(target.status)
1249
+ const matchingTargets = statusTargets.filter(target =>
1250
+ expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1)
1196
1251
  );
1197
- if (completedTargets.length === expectedTargetIds.size && expectedTargetIds.size > 0) {
1252
+ const completedTargetIds = new Set<number>();
1253
+ matchingTargets.forEach(target => {
1254
+ const targetId = normalizeProtocolV2TargetId(target.target_id);
1255
+ if (targetId !== undefined && isProtocolV2TargetStatusFinished(target.status)) {
1256
+ completedTargetIds.add(targetId);
1257
+ }
1258
+ });
1259
+ const allExpectedTargetsCompleted =
1260
+ expectedTargetIds.size > 0 &&
1261
+ Array.from(expectedTargetIds).every(targetId => completedTargetIds.has(targetId));
1262
+ if (allExpectedTargetsCompleted) {
1263
+ this.postProgressMessage(100, 'installingFirmware');
1198
1264
  return true;
1199
1265
  }
1200
1266
 
1201
- const inProgressTarget = statusTargets.find(
1202
- target =>
1203
- expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
1267
+ if (expectedTargetIds.size > 0 && matchingTargets.length > 0) {
1268
+ const hasInProgressTarget = matchingTargets.some(target =>
1204
1269
  isProtocolV2TargetStatusInProgress(target.status)
1205
- );
1206
- if (inProgressTarget) {
1207
- this.postProgressMessage(99, 'installingFirmware');
1270
+ );
1271
+ const completedProgress = Math.floor(
1272
+ (completedTargetIds.size / expectedTargetIds.size) * 100
1273
+ );
1274
+ // The protocol exposes no per-target percentage, so report coarse progress by
1275
+ // completed targets and use 1% once work starts to keep the UI responsive.
1276
+ const progress = Math.min(99, Math.max(completedProgress, hasInProgressTarget ? 1 : 0));
1277
+ this.postProgressMessage(progress, 'installingFirmware');
1208
1278
  }
1209
1279
 
1210
1280
  return false;
1211
1281
  }
1212
1282
 
1213
- private async waitForProtocolV2FirmwareUpdateComplete(
1214
- targets: Array<{ target_id: number; path: string }>,
1215
- startResponse?: ProtocolV2FirmwareUpdateStartResponse
1283
+ private getProtocolV2MissingTargetIds(
1284
+ statusTargets: ProtocolV2FirmwareUpdateStatusTarget[],
1285
+ expectedTargetIds: Set<number>
1216
1286
  ) {
1217
- const expectedTargetIds = new Set(targets.map(target => target.target_id));
1218
- if (startResponse?.type === 'DeviceFirmwareUpdateStatus') {
1219
- const statusTargets = (startResponse.message.records ??
1220
- []) as ProtocolV2FirmwareUpdateStatusTarget[];
1221
- if (this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds)) {
1222
- return;
1287
+ const reportedTargetIds = new Set<number>();
1288
+ statusTargets.forEach(target => {
1289
+ const targetId = normalizeProtocolV2TargetId(target.target_id);
1290
+ if (targetId !== undefined) {
1291
+ reportedTargetIds.add(targetId);
1223
1292
  }
1224
- }
1293
+ });
1294
+ return Array.from(expectedTargetIds).filter(targetId => !reportedTargetIds.has(targetId));
1295
+ }
1225
1296
 
1297
+ private async waitForProtocolV2FirmwareUpdateComplete(
1298
+ targets: Array<{ target_id: number; path: string }>
1299
+ ) {
1300
+ const expectedTargetIds = new Set(targets.map(target => target.target_id));
1226
1301
  const startTime = Date.now();
1227
1302
  let lastError: unknown;
1303
+ let shouldReconnect = true;
1304
+ let deviceInfo: ProtocolV2DeviceInfo | undefined;
1305
+ let missingTargetStatusSince: number | undefined;
1306
+ let missingTargetStatusKey: string | undefined;
1307
+ const resetMissingTargetStatusGrace = () => {
1308
+ missingTargetStatusSince = undefined;
1309
+ missingTargetStatusKey = undefined;
1310
+ };
1228
1311
 
1229
1312
  while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
1230
1313
  try {
1231
- const statusRes = await this.queryProtocolV2FirmwareUpdateStatus();
1232
- const statusTargets = (statusRes.message.records ??
1233
- []) as ProtocolV2FirmwareUpdateStatusTarget[];
1234
- if (this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds)) {
1235
- return;
1236
- }
1237
- } catch (error) {
1238
- lastError = error;
1239
- if (error instanceof HardwareError && error.errorCode === HardwareErrorCode.FirmwareError) {
1240
- throw error;
1314
+ if (shouldReconnect) {
1315
+ await this.reconnectProtocolV2Device();
1316
+ deviceInfo = await this.verifyProtocolV2ReconnectIdentity();
1317
+ shouldReconnect = false;
1241
1318
  }
1242
- Log.log('Protocol V2 firmware install status polling failed: ', error);
1243
- if (isProtocolV2PollingTransientError(error)) {
1244
- try {
1245
- await this.reconnectProtocolV2Device();
1246
- if (await this.probeProtocolV2NormalMode()) {
1319
+ const currentDeviceInfo = deviceInfo;
1320
+ try {
1321
+ const statusResponse = await this.device.getCommands().typedCall(
1322
+ 'DeviceFirmwareUpdateStatusGet',
1323
+ 'DeviceFirmwareUpdateStatus',
1324
+ {
1325
+ fields: {
1326
+ status: true,
1327
+ payload_version: true,
1328
+ path: true,
1329
+ },
1330
+ },
1331
+ { timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT }
1332
+ );
1333
+ const statusTargets = (statusResponse.message.records ??
1334
+ []) as ProtocolV2FirmwareUpdateStatusTarget[];
1335
+ if (this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds)) {
1336
+ return;
1337
+ }
1338
+
1339
+ if (
1340
+ statusTargets.length === 0 &&
1341
+ currentDeviceInfo &&
1342
+ (await this.probeProtocolV2NormalMode(currentDeviceInfo))
1343
+ ) {
1344
+ Log.log(
1345
+ '[FirmwareUpdateV4] empty firmware status after confirmed App reboot; update complete'
1346
+ );
1347
+ this.postProgressMessage(100, 'installingFirmware');
1348
+ return;
1349
+ }
1350
+
1351
+ const missingTargetIds = this.getProtocolV2MissingTargetIds(
1352
+ statusTargets,
1353
+ expectedTargetIds
1354
+ );
1355
+ if (missingTargetIds.length > 0) {
1356
+ const now = Date.now();
1357
+ const missingKey = missingTargetIds.join(',');
1358
+ if (missingTargetStatusSince === undefined || missingTargetStatusKey !== missingKey) {
1359
+ missingTargetStatusSince = now;
1360
+ missingTargetStatusKey = missingKey;
1361
+ } else if (
1362
+ now - missingTargetStatusSince >=
1363
+ PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT
1364
+ ) {
1365
+ const reportedTargetIds = statusTargets
1366
+ .map(target => normalizeProtocolV2TargetId(target.target_id))
1367
+ .filter((targetId): targetId is number => targetId !== undefined);
1368
+ throw ERRORS.TypedError(
1369
+ HardwareErrorCode.FirmwareError,
1370
+ `Protocol V2 firmware status is missing requested records: targetIds=${missingKey} reportedTargetIds=${reportedTargetIds.join(
1371
+ ','
1372
+ )}`
1373
+ );
1374
+ }
1375
+ lastError = new Error(
1376
+ `Protocol V2 firmware status is temporarily missing targetIds=${missingKey}`
1377
+ );
1378
+ } else {
1379
+ resetMissingTargetStatusGrace();
1380
+ lastError = new Error('Protocol V2 firmware targets are still installing');
1381
+ }
1382
+ } catch (error) {
1383
+ if (
1384
+ error instanceof HardwareError &&
1385
+ error.errorCode === HardwareErrorCode.FirmwareError
1386
+ ) {
1387
+ throw error;
1388
+ }
1389
+ // Only consecutive full status dumps can prove that a record is absent.
1390
+ // A reboot or transport interruption starts a fresh grace window.
1391
+ resetMissingTargetStatusGrace();
1392
+ // App firmware does not register DeviceFirmwareUpdateStatusGet. Treat the
1393
+ // missing endpoint as completion only after the runtime probe confirms App mode.
1394
+ if (isProtocolV2FirmwareStatusEndpointUnavailable(error)) {
1395
+ if (!currentDeviceInfo) {
1396
+ throw ERRORS.TypedError(
1397
+ HardwareErrorCode.RuntimeError,
1398
+ 'Protocol V2 device identity is unavailable during install polling'
1399
+ );
1400
+ }
1401
+ if (await this.probeProtocolV2NormalMode(currentDeviceInfo)) {
1402
+ Log.log(
1403
+ '[FirmwareUpdateV4] firmware status endpoint unavailable after confirmed App reboot'
1404
+ );
1405
+ this.postProgressMessage(100, 'installingFirmware');
1247
1406
  return;
1248
1407
  }
1249
- } catch (reconnectError) {
1250
- lastError = reconnectError;
1408
+ lastError = new Error(
1409
+ 'Protocol V2 firmware status endpoint is unavailable while the device remains in loader mode'
1410
+ );
1411
+ } else {
1412
+ shouldReconnect = true;
1413
+ deviceInfo = undefined;
1414
+ lastError = error;
1251
1415
  Log.log(
1252
- 'Protocol V2 firmware install reconnect/normal-mode probe failed: ',
1253
- reconnectError
1416
+ '[FirmwareUpdateV4] DeviceFirmwareUpdateStatusGet unavailable during install: ',
1417
+ error
1254
1418
  );
1255
1419
  }
1256
- try {
1257
- await this.pingProtocolV2Device();
1258
- Log.log('Protocol V2 firmware status unavailable, Ping is ready');
1259
- } catch (pingError) {
1260
- lastError = pingError;
1261
- Log.log('Protocol V2 firmware install Ping polling failed: ', pingError);
1262
- }
1263
1420
  }
1421
+ } catch (error) {
1422
+ lastError = error;
1423
+ if (this.isProtocolV2ReconnectIdentityError(error)) {
1424
+ throw error;
1425
+ }
1426
+ if (error instanceof HardwareError && error.errorCode === HardwareErrorCode.FirmwareError) {
1427
+ throw error;
1428
+ }
1429
+ shouldReconnect = true;
1430
+ deviceInfo = undefined;
1431
+ resetMissingTargetStatusGrace();
1432
+ Log.log('Protocol V2 firmware install device readiness probe failed: ', error);
1264
1433
  }
1265
1434
  await wait(1000);
1266
1435
  }
1267
1436
 
1268
1437
  throw ERRORS.TypedError(
1269
1438
  HardwareErrorCode.RuntimeError,
1270
- `Protocol V2 firmware update status timeout: ${this.normalizeErrorMessage(lastError)}`
1439
+ `Protocol V2 firmware update status not complete within ${
1440
+ PROTOCOL_V2_INSTALL_TIMEOUT / 1000
1441
+ }s: ${this.normalizeErrorMessage(lastError)}`
1271
1442
  );
1272
1443
  }
1273
1444
 
1274
1445
  private async exitProtocolV2BootloaderToNormal() {
1275
- this.postTipMessage(FirmwareUpdateTipMessage.SwitchFirmwareReconnectDevice);
1446
+ await this.reconnectProtocolV2Device();
1447
+ const deviceInfo = await this.verifyProtocolV2ReconnectIdentity();
1276
1448
  try {
1277
- await this.reconnectProtocolV2Device();
1278
- if (await this.probeProtocolV2NormalMode()) {
1279
- Log.log('Protocol V2 device is already in normal mode, skip normal reboot');
1449
+ if (await this.probeProtocolV2NormalMode(deviceInfo)) {
1450
+ Log.log('[FirmwareUpdateV4] device already returned to App mode; skip Normal reboot');
1280
1451
  return;
1281
1452
  }
1282
1453
  } catch (error) {
1283
- Log.log('Protocol V2 normal-mode probe before reboot failed: ', error);
1454
+ Log.log('[FirmwareUpdateV4] unable to confirm App mode before Normal reboot: ', error);
1284
1455
  }
1285
1456
  await this.protocolV2Reboot(DeviceRebootType.Normal);
1286
1457
  }
1287
1458
 
1459
+ private async probeProtocolV2NormalMode(deviceInfo: ProtocolV2DeviceInfo) {
1460
+ const features = await this.device.probeProtocolV2RuntimeState(
1461
+ deviceInfo,
1462
+ PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
1463
+ );
1464
+ return features.mode === 'normal' && !features.bootloaderMode;
1465
+ }
1466
+
1288
1467
  private async waitForProtocolV2FinalFeatures() {
1289
1468
  const features = await this.waitForProtocolV2ReconnectAndFeatures(
1290
- PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT
1469
+ PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT
1291
1470
  );
1292
1471
 
1472
+ return this.getProtocolV2VersionResult(features);
1473
+ }
1474
+
1475
+ private getProtocolV2VersionResult(features: Features) {
1293
1476
  const bootloaderVersion = getDeviceBootloaderVersion(features).join('.');
1294
1477
  const bleVersion = getDeviceBLEFirmwareVersion(features).join('.');
1295
1478
  const firmwareVersion = getDeviceFirmwareVersion(features).join('.');
@@ -1309,29 +1492,41 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1309
1492
  private async waitForProtocolV2ReconnectAndFeatures(timeout: number) {
1310
1493
  const startTime = Date.now();
1311
1494
  let lastError: unknown;
1495
+ let shouldReconnect = true;
1312
1496
 
1313
1497
  while (Date.now() - startTime < timeout) {
1314
1498
  try {
1315
- await this.reconnectProtocolV2Device();
1499
+ if (shouldReconnect) {
1500
+ await this.reconnectProtocolV2Device();
1501
+ shouldReconnect = false;
1502
+ }
1316
1503
  const deviceInfo = await requestProtocolV2DeviceInfo({
1317
1504
  commands: this.device.getCommands(),
1318
- timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
1319
- // 更新完成判定只需要各 target 版本号;scope 与请求内容保持一致
1505
+ timeoutMs: this.getProtocolV2DeviceInfoTimeout(),
1506
+ // Completion needs target versions only; keep scope aligned with the request.
1320
1507
  request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
1321
1508
  });
1322
- const features = this.device.updateProtocolV2Features(deviceInfo);
1323
- if (features.bootloaderMode || features.mode === 'bootloader') {
1324
- throw ERRORS.TypedError(
1325
- HardwareErrorCode.DeviceNotFound,
1326
- 'Protocol V2 device is still in bootloader mode'
1327
- );
1509
+ this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
1510
+ const features = await this.device.probeProtocolV2RuntimeState(
1511
+ deviceInfo,
1512
+ PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
1513
+ );
1514
+ if (features.mode === 'normal' && !features.bootloaderMode) {
1515
+ return features;
1328
1516
  }
1329
- return features;
1517
+ lastError = ERRORS.TypedError(
1518
+ HardwareErrorCode.DeviceNotFound,
1519
+ 'Protocol V2 device is still in bootloader mode'
1520
+ );
1330
1521
  } catch (error) {
1522
+ if (this.isProtocolV2ReconnectIdentityError(error)) {
1523
+ throw error;
1524
+ }
1525
+ shouldReconnect = true;
1331
1526
  lastError = error;
1332
1527
  Log.log('Protocol V2 normal mode not ready, polling Ping: ', error);
1333
- await wait(1000);
1334
1528
  }
1529
+ await wait(1000);
1335
1530
  }
1336
1531
 
1337
1532
  throw ERRORS.TypedError(
@@ -1355,54 +1550,101 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1355
1550
  DataManager.isBrowserWebUsb(DataManager.getSettings('env')) &&
1356
1551
  devicesDescriptor.length === 1
1357
1552
  ) {
1553
+ const descriptor = devicesDescriptor[0];
1554
+ if (!this.protocolV2ExpectedSerialNumber && descriptor.path !== this.protocolV2ExpectedPath) {
1555
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound);
1556
+ }
1358
1557
  this.device.updateDescriptor(
1359
1558
  {
1360
- ...devicesDescriptor[0],
1559
+ ...descriptor,
1361
1560
  protocolType: PROTOCOL_V2_CONNECT_PROTOCOL,
1362
1561
  },
1363
1562
  true
1364
1563
  );
1365
- await this.device.acquire(PROTOCOL_V2_CONNECT_PROTOCOL, { throwOnRunPromiseError: true });
1564
+ await this.ensureProtocolV2DeviceAcquired();
1366
1565
  this.device.commands.disposed = false;
1367
1566
  this.device.getCommands().mainId = this.device.mainId ?? '';
1368
- await this.device.initialize();
1369
1567
  return;
1370
1568
  }
1371
1569
 
1372
- // App bootloader 序列号暂时可能不一致。V4 升级重连阶段只接受唯一枚举设备,
1373
- // 避免继续按旧 app connectId 查缓存导致反复输出 path mismatch 日志。
1570
+ // Reinitialize every USB descriptor so DeviceInfo can provide the physical serial.
1571
+ // Enumeration order is not stable and must never decide the reconnect target.
1374
1572
  const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
1375
1573
  connectProtocol: PROTOCOL_V2_CONNECT_PROTOCOL,
1376
1574
  });
1377
- if (deviceList.length !== 1) {
1575
+ const expectedSerialNumber = this.protocolV2ExpectedSerialNumber?.trim();
1576
+ const expectedPath = this.protocolV2ExpectedPath?.trim();
1577
+ const reconnectDevice = deviceList.find(candidate => {
1578
+ const candidateSerialNumber = candidate.getCurrentSerialNo?.().trim();
1579
+ if (expectedSerialNumber && candidateSerialNumber) {
1580
+ return candidateSerialNumber === expectedSerialNumber;
1581
+ }
1582
+ return !!expectedPath && candidate.getConnectId() === expectedPath;
1583
+ });
1584
+ if (!reconnectDevice) {
1378
1585
  throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound);
1379
1586
  }
1380
1587
 
1381
1588
  Log.debug(
1382
- 'Protocol V2 firmware reconnect using single enumerated device:',
1383
- deviceList[0].getConnectId()
1589
+ 'Protocol V2 firmware reconnect using matched device:',
1590
+ reconnectDevice.getConnectId()
1384
1591
  );
1385
- this.device.updateFromCache(deviceList[0]);
1386
- await this.device.acquire(PROTOCOL_V2_CONNECT_PROTOCOL, { throwOnRunPromiseError: true });
1592
+ this.device.updateFromCache(reconnectDevice);
1593
+ await this.ensureProtocolV2DeviceAcquired();
1387
1594
  this.device.commands.disposed = false;
1388
1595
  this.device.getCommands().mainId = this.device.mainId ?? '';
1389
- await this.device.initialize();
1390
1596
  }
1391
1597
 
1392
- private async protocolV2CommonUpdateProcess({
1598
+ /**
1599
+ * After acquiring a USB session, polling reuses its command channel. Reacquire only
1600
+ * after reboot or enumeration changes cause hasDeviceAcquire() to become false.
1601
+ */
1602
+ private async ensureProtocolV2DeviceAcquired() {
1603
+ const commands = this.device.getCommands();
1604
+ if (this.device.hasDeviceAcquire() && !commands.disposed) {
1605
+ return;
1606
+ }
1607
+ await this.device.acquire(PROTOCOL_V2_CONNECT_PROTOCOL, {
1608
+ throwOnRunPromiseError: true,
1609
+ });
1610
+ }
1611
+
1612
+ private isProtocolV2ReconnectIdentityError(error: unknown) {
1613
+ return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity');
1614
+ }
1615
+
1616
+ private async protocolV2CommonUpdateProcess(params: ProtocolV2FileTransferParams) {
1617
+ let lastError: unknown;
1618
+ for (let attempt = 1; attempt <= PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT; attempt += 1) {
1619
+ try {
1620
+ return await this.protocolV2WriteWholeFile(params);
1621
+ } catch (error) {
1622
+ lastError = error;
1623
+ Log.error(
1624
+ `Protocol V2 file transfer failed path=${params.filePath} attempt=${attempt}/${PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT}; restarting from offset 0`,
1625
+ error
1626
+ );
1627
+ if (attempt === PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT) {
1628
+ break;
1629
+ }
1630
+ await this.recoverProtocolV2FileTransfer();
1631
+ }
1632
+ }
1633
+
1634
+ throw ERRORS.TypedError(
1635
+ HardwareErrorCode.EmmcFileWriteFirmwareError,
1636
+ `transfer data error: ${getProtocolV2UnknownErrorText(lastError)}`
1637
+ );
1638
+ }
1639
+
1640
+ private async protocolV2WriteWholeFile({
1393
1641
  payload,
1394
1642
  filePath,
1395
1643
  processedSize,
1396
1644
  totalSize,
1397
1645
  onTransferredBytes,
1398
- }: PROTO.FirmwareUpload & {
1399
- filePath: string;
1400
- processedSize?: number;
1401
- totalSize?: number;
1402
- onTransferredBytes?: (transferredBytes: number) => void;
1403
- }) {
1646
+ }: ProtocolV2FileTransferParams) {
1404
1647
  const chunkSize = this.getProtocolV2FirmwareChunkSize();
1405
- let offset = 0;
1406
1648
  const getUploadProgress = (fileOffset: number) => {
1407
1649
  if (totalSize !== undefined && processedSize !== undefined) {
1408
1650
  return Math.min(Math.ceil(((processedSize + fileOffset) / totalSize) * 100), 99);
@@ -1410,39 +1652,43 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1410
1652
  return Math.min(Math.ceil((fileOffset / payload.byteLength) * 100), 99);
1411
1653
  };
1412
1654
 
1413
- while (offset < payload.byteLength) {
1414
- const chunkEnd = Math.min(offset + chunkSize, payload.byteLength);
1415
- const chunkLength = chunkEnd - offset;
1416
- const chunk = payload.slice(offset, chunkEnd);
1417
- const overwrite = offset === 0;
1418
- const progress = getProtocolV2DeviceTransferProgress(
1419
- (processedSize ?? 0) + offset,
1420
- (processedSize ?? 0) + chunkEnd,
1421
- totalSize ?? payload.byteLength
1422
- );
1423
-
1424
- const writeRes = await this.fileWriteWithRetry(
1425
- filePath,
1426
- payload.byteLength,
1427
- offset,
1428
- chunk,
1429
- overwrite,
1430
- progress
1431
- );
1432
- const processedByte = Number(writeRes.message.processed_byte);
1433
- const nextOffset =
1434
- Number.isFinite(processedByte) && processedByte > offset
1435
- ? processedByte
1436
- : offset + chunkLength;
1437
- if (nextOffset <= offset || nextOffset > payload.byteLength) {
1438
- throw ERRORS.TypedError(
1439
- HardwareErrorCode.EmmcFileWriteFirmwareError,
1440
- `invalid processed_byte ${writeRes.message.processed_byte} for offset ${offset}`
1441
- );
1655
+ try {
1656
+ await writeProtocolV2File({
1657
+ commands: this.device.getCommands(),
1658
+ path: filePath,
1659
+ data: payload,
1660
+ totalSize: payload.byteLength,
1661
+ chunkSize,
1662
+ overwrite: true,
1663
+ append: false,
1664
+ writeWithResponse: true,
1665
+ maxChunkRetries: 0,
1666
+ getUiPercentage: ({ offset, chunkLength }) =>
1667
+ getProtocolV2DeviceTransferProgress(
1668
+ (processedSize ?? 0) + offset,
1669
+ (processedSize ?? 0) + offset + chunkLength,
1670
+ totalSize ?? payload.byteLength
1671
+ ),
1672
+ onProgress: progress => {
1673
+ const transferredBytes = (processedSize ?? 0) + progress.transferredBytes;
1674
+ onTransferredBytes?.(transferredBytes);
1675
+ this.postProgressMessage(getUploadProgress(progress.transferredBytes), 'transferData', {
1676
+ transferredBytes,
1677
+ totalBytes: totalSize ?? payload.byteLength,
1678
+ rateBytesPerSecond: progress.rateBytesPerSecond,
1679
+ elapsedMs: progress.elapsedMs,
1680
+ });
1681
+ },
1682
+ });
1683
+ } catch (error) {
1684
+ if (
1685
+ error instanceof HardwareError &&
1686
+ error.errorCode === HardwareErrorCode.RuntimeError &&
1687
+ error.message.includes('FilesystemFileWrite')
1688
+ ) {
1689
+ throw ERRORS.TypedError(HardwareErrorCode.EmmcFileWriteFirmwareError, error.message);
1442
1690
  }
1443
- offset = nextOffset;
1444
- onTransferredBytes?.((processedSize ?? 0) + offset);
1445
- this.postProgressMessage(getUploadProgress(offset), 'transferData');
1691
+ throw error;
1446
1692
  }
1447
1693
 
1448
1694
  return totalSize !== undefined ? (processedSize ?? 0) + payload.byteLength : 0;
@@ -1462,65 +1708,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1462
1708
  return env ?? 'unknown';
1463
1709
  }
1464
1710
 
1465
- private async fileWriteWithRetry(
1466
- filePath: string,
1467
- totalFileSize: number,
1468
- offset: number,
1469
- chunk: ArrayBuffer | Buffer,
1470
- overwrite: boolean,
1471
- progress: number | null
1472
- ): Promise<TypedResponseMessage<'FilesystemFile'>> {
1473
- const writeFunc = async () => {
1474
- const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
1475
- const writeRes = await typedCall('FilesystemFileWrite', 'FilesystemFile', {
1476
- file: {
1477
- path: filePath,
1478
- offset,
1479
- total_size: totalFileSize,
1480
- data: chunk,
1481
- },
1482
- overwrite,
1483
- append: false,
1484
- ui_percentage: progress ?? undefined,
1485
- });
1486
- if (writeRes.type !== 'FilesystemFile') {
1487
- if ((writeRes as any).type === 'CallMethodError') {
1488
- if (((writeRes as any).message.error ?? '').indexOf(SESSION_ERROR) > -1) {
1489
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, SESSION_ERROR);
1490
- }
1491
- }
1492
- throw ERRORS.TypedError(
1493
- HardwareErrorCode.EmmcFileWriteFirmwareError,
1494
- 'transfer data error'
1495
- );
1496
- }
1497
- return writeRes;
1498
- };
1499
-
1500
- let retryCount = 10;
1501
- while (retryCount > 0) {
1502
- try {
1503
- const result = await writeFunc();
1504
- return result;
1505
- } catch (error) {
1506
- Log.error(`fileWrite error: `, error);
1507
- retryCount--;
1508
- if (retryCount === 0) {
1509
- throw ERRORS.TypedError(
1510
- HardwareErrorCode.EmmcFileWriteFirmwareError,
1511
- 'transfer data error'
1512
- );
1513
- }
1514
- const env = DataManager.getSettings('env');
1515
- if (DataManager.isBleConnect(env)) {
1516
- await wait(3000);
1517
- await this.acquireProtocolV2BleDevice();
1518
- await this.device.initialize();
1519
- }
1520
- await wait(2000);
1521
- }
1711
+ private async recoverProtocolV2FileTransfer() {
1712
+ const env = DataManager.getSettings('env');
1713
+ if (DataManager.isBleConnect(env)) {
1714
+ await wait(3000);
1522
1715
  }
1523
- throw ERRORS.TypedError(HardwareErrorCode.EmmcFileWriteFirmwareError, 'transfer data error');
1716
+ await this.reconnectProtocolV2Device();
1717
+ await this.verifyProtocolV2ReconnectIdentity();
1718
+ await this.device.initialize();
1719
+ await wait(2000);
1524
1720
  }
1525
1721
 
1526
1722
  private async acquireProtocolV2BleDevice() {
@@ -1538,35 +1734,16 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1538
1734
  targets: Array<{ target_id: number; path: string }>;
1539
1735
  }) {
1540
1736
  const commands = this.device.getCommands();
1541
- let response: ProtocolV2FirmwareUpdateStartResponse;
1542
- try {
1543
- response = await commands.typedCall(
1544
- 'DeviceFirmwareUpdateRequest',
1545
- PROTOCOL_V2_FIRMWARE_UPDATE_RESPONSE_TYPES,
1546
- {
1547
- targets,
1548
- },
1549
- {
1550
- intermediateTypes: ['DeviceFirmwareUpdateStatus'],
1551
- timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT,
1552
- onIntermediateResponse: (response: { type?: string }) => {
1553
- if (response.type === 'DeviceFirmwareUpdateStatus') {
1554
- this.postProgressMessage(99, 'installingFirmware');
1555
- }
1556
- },
1557
- }
1558
- );
1559
- } catch (error) {
1560
- if (isProtocolV2StartUpdateTransientError(error)) {
1561
- Log.log(
1562
- 'Protocol V2 firmware update request did not return; continue status polling',
1563
- error
1564
- );
1565
- } else {
1566
- throw error;
1567
- }
1568
- }
1737
+ const response: ProtocolV2FirmwareUpdateStartResponse = await commands.typedCall(
1738
+ 'DeviceFirmwareUpdateRequest',
1739
+ 'Success',
1740
+ { targets },
1741
+ { timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT }
1742
+ );
1743
+ // Success acknowledges that the device accepted installation. End confirmation
1744
+ // and begin status polling only after receiving this ACK.
1569
1745
  this.postTipMessage(FirmwareUpdateTipMessage.FirmwareUpdating);
1746
+ this.postProgressMessage(0, 'installingFirmware');
1570
1747
  return response;
1571
1748
  }
1572
1749
 
@@ -1576,9 +1753,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1576
1753
  const res = await typedCall('DeviceReboot', 'Success', {
1577
1754
  reboot_type: rebootType,
1578
1755
  });
1756
+ this.device.markProtocolV2Reboot(rebootType);
1579
1757
  return res.message;
1580
1758
  } catch (error) {
1581
1759
  if (isProtocolV2DeviceDisconnectedError(error) || isProtocolV2ReconnectProbeError(error)) {
1760
+ this.device.markProtocolV2Reboot(rebootType);
1582
1761
  return { message: 'Device rebooted successfully' };
1583
1762
  }
1584
1763
  throw error;