@onekeyfe/hd-core 1.2.0-alpha.3 → 1.2.0-alpha.31

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