@onekeyfe/hd-core 1.2.0-alpha.174 → 1.2.0-alpha.176
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +255 -25
- package/__tests__/protocol-v2.test.ts +73 -40
- package/dist/api/FirmwareUpdateV4.d.ts +2 -2
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/index.js +46 -101
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV4.ts +54 -56
- package/src/core/index.ts +6 -100
|
@@ -14,7 +14,7 @@ describe('FirmwareUpdateV4 install polling', () => {
|
|
|
14
14
|
jest.restoreAllMocks();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
test('
|
|
17
|
+
test('writes the USB Request before polling current install status', async () => {
|
|
18
18
|
const method = new FirmwareUpdateV4({
|
|
19
19
|
id: 1,
|
|
20
20
|
payload: {
|
|
@@ -26,7 +26,22 @@ describe('FirmwareUpdateV4 install polling', () => {
|
|
|
26
26
|
const typedCall = jest
|
|
27
27
|
.fn()
|
|
28
28
|
.mockResolvedValueOnce({ type: 'Success', message: {} })
|
|
29
|
-
.mockResolvedValueOnce({
|
|
29
|
+
.mockResolvedValueOnce({
|
|
30
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
31
|
+
message: { records: [] },
|
|
32
|
+
})
|
|
33
|
+
.mockResolvedValueOnce({
|
|
34
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
35
|
+
message: {
|
|
36
|
+
records: [
|
|
37
|
+
{
|
|
38
|
+
target_id: 4,
|
|
39
|
+
status: 'FW_MGMT_UPDATER_TASK_STATUS_PENDING',
|
|
40
|
+
path: 'vol0:/application_p1.bin',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
})
|
|
30
45
|
.mockResolvedValueOnce({
|
|
31
46
|
type: 'DeviceFirmwareUpdateStatus',
|
|
32
47
|
message: {
|
|
@@ -39,12 +54,17 @@ describe('FirmwareUpdateV4 install polling', () => {
|
|
|
39
54
|
],
|
|
40
55
|
},
|
|
41
56
|
});
|
|
57
|
+
const call = jest.fn().mockResolvedValue({
|
|
58
|
+
type: 'WriteCompleted',
|
|
59
|
+
message: {},
|
|
60
|
+
});
|
|
61
|
+
const setCancelableAction = jest.fn();
|
|
42
62
|
|
|
43
63
|
method.device = {
|
|
44
|
-
getCommands: () => ({ typedCall }),
|
|
64
|
+
getCommands: () => ({ typedCall, call, cancelDevice: jest.fn() }),
|
|
45
65
|
createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
|
|
46
66
|
toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2-usb' }),
|
|
47
|
-
setCancelableAction
|
|
67
|
+
setCancelableAction,
|
|
48
68
|
clearCancelableAction: jest.fn(),
|
|
49
69
|
} as unknown as Device;
|
|
50
70
|
method.postMessage = jest.fn();
|
|
@@ -53,7 +73,10 @@ describe('FirmwareUpdateV4 install polling', () => {
|
|
|
53
73
|
|
|
54
74
|
const firmwareUpdate = method as unknown as {
|
|
55
75
|
protocolV2StartFirmwareUpdate: (params: { targets: typeof targets }) => Promise<void>;
|
|
56
|
-
waitForProtocolV2FirmwareUpdateComplete: (
|
|
76
|
+
waitForProtocolV2FirmwareUpdateComplete: (
|
|
77
|
+
value: typeof targets,
|
|
78
|
+
requireCurrentInstallStatus: boolean
|
|
79
|
+
) => Promise<void>;
|
|
57
80
|
reconnectProtocolV2Device: () => Promise<void>;
|
|
58
81
|
verifyProtocolV2ReconnectIdentity: () => Promise<Record<string, never>>;
|
|
59
82
|
};
|
|
@@ -62,15 +85,155 @@ describe('FirmwareUpdateV4 install polling', () => {
|
|
|
62
85
|
(method as any).isBleReconnect = jest.fn(() => false);
|
|
63
86
|
|
|
64
87
|
await firmwareUpdate.protocolV2StartFirmwareUpdate({ targets });
|
|
65
|
-
await firmwareUpdate.waitForProtocolV2FirmwareUpdateComplete(targets);
|
|
66
88
|
|
|
67
89
|
expect(typedCall.mock.calls[0]).toEqual(['DeviceFirmwareUpdateStage', 'Success', { targets }]);
|
|
68
|
-
expect(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
90
|
+
expect(call).toHaveBeenCalledWith(
|
|
91
|
+
'DeviceFirmwareUpdateRequest',
|
|
92
|
+
{},
|
|
93
|
+
expect.objectContaining({
|
|
94
|
+
returnAfterWrite: true,
|
|
95
|
+
expectedTypes: ['Success'],
|
|
96
|
+
onResponseAfterWrite: expect.any(Function),
|
|
97
|
+
})
|
|
73
98
|
);
|
|
99
|
+
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
100
|
+
|
|
101
|
+
await firmwareUpdate.waitForProtocolV2FirmwareUpdateComplete(targets, true);
|
|
102
|
+
|
|
103
|
+
expect(typedCall.mock.calls[1]?.[0]).toBe('DeviceFirmwareUpdateStatusGet');
|
|
104
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(1, 'installingFirmware');
|
|
105
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
106
|
+
expect(call.mock.invocationCallOrder[0]).toBeLessThan(typedCall.mock.invocationCallOrder[1]);
|
|
107
|
+
expect(setCancelableAction).toHaveBeenCalledTimes(2);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('accepts finished USB status after the Request terminal Success arrives', async () => {
|
|
111
|
+
const method = new FirmwareUpdateV4({
|
|
112
|
+
id: 1,
|
|
113
|
+
payload: {
|
|
114
|
+
method: 'firmwareUpdateV4',
|
|
115
|
+
connectId: 'pro2-usb',
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
const targets = [{ target_id: 4, path: 'vol0:/application_p1.bin' }];
|
|
119
|
+
const typedCall = jest
|
|
120
|
+
.fn()
|
|
121
|
+
.mockResolvedValueOnce({ type: 'Success', message: {} })
|
|
122
|
+
.mockResolvedValueOnce({
|
|
123
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
124
|
+
message: {
|
|
125
|
+
records: [
|
|
126
|
+
{
|
|
127
|
+
target_id: 4,
|
|
128
|
+
status: 'FW_MGMT_UPDATER_TASK_STATUS_FINISHED',
|
|
129
|
+
path: 'vol0:/application_p1.bin',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
const call = jest.fn().mockResolvedValue({
|
|
135
|
+
type: 'WriteCompleted',
|
|
136
|
+
message: {},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
method.device = {
|
|
140
|
+
getCommands: () => ({ typedCall, call, cancelDevice: jest.fn() }),
|
|
141
|
+
createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
|
|
142
|
+
toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2-usb' }),
|
|
143
|
+
setCancelableAction: jest.fn(),
|
|
144
|
+
clearCancelableAction: jest.fn(),
|
|
145
|
+
} as unknown as Device;
|
|
146
|
+
method.postMessage = jest.fn();
|
|
147
|
+
method.postProgressMessage = jest.fn();
|
|
148
|
+
|
|
149
|
+
const firmwareUpdate = method as unknown as {
|
|
150
|
+
protocolV2StartFirmwareUpdate: (params: { targets: typeof targets }) => Promise<void>;
|
|
151
|
+
waitForProtocolV2FirmwareUpdateComplete: (
|
|
152
|
+
value: typeof targets,
|
|
153
|
+
requireCurrentInstallStatus: boolean
|
|
154
|
+
) => Promise<void>;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
await firmwareUpdate.protocolV2StartFirmwareUpdate({ targets });
|
|
158
|
+
const requestOptions = call.mock.calls[0]?.[2] as {
|
|
159
|
+
onResponseAfterWrite: (response: { type: 'Success'; message: Record<string, never> }) => void;
|
|
160
|
+
};
|
|
161
|
+
requestOptions.onResponseAfterWrite({ type: 'Success', message: {} });
|
|
162
|
+
await firmwareUpdate.waitForProtocolV2FirmwareUpdateComplete(targets, true);
|
|
163
|
+
|
|
164
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('reconnects USB when the link is released while writing the Request', async () => {
|
|
168
|
+
const method = new FirmwareUpdateV4({
|
|
169
|
+
id: 1,
|
|
170
|
+
payload: {
|
|
171
|
+
method: 'firmwareUpdateV4',
|
|
172
|
+
connectId: 'pro2-usb',
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
const targets = [{ target_id: 4, path: 'vol0:/application_p1.bin' }];
|
|
176
|
+
const typedCall = jest
|
|
177
|
+
.fn()
|
|
178
|
+
.mockResolvedValueOnce({ type: 'Success', message: {} })
|
|
179
|
+
.mockResolvedValueOnce({
|
|
180
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
181
|
+
message: {
|
|
182
|
+
records: [
|
|
183
|
+
{
|
|
184
|
+
target_id: 4,
|
|
185
|
+
status: 'FW_MGMT_UPDATER_TASK_STATUS_IN_PROGRESS',
|
|
186
|
+
path: 'vol0:/application_p1.bin',
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
},
|
|
190
|
+
})
|
|
191
|
+
.mockResolvedValueOnce({
|
|
192
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
193
|
+
message: {
|
|
194
|
+
records: [
|
|
195
|
+
{
|
|
196
|
+
target_id: 4,
|
|
197
|
+
status: 'FW_MGMT_UPDATER_TASK_STATUS_FINISHED',
|
|
198
|
+
path: 'vol0:/application_p1.bin',
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
const call = jest.fn().mockRejectedValue(new Error('device was disconnected'));
|
|
204
|
+
|
|
205
|
+
method.device = {
|
|
206
|
+
getCommands: () => ({ typedCall, call, cancelDevice: jest.fn() }),
|
|
207
|
+
createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
|
|
208
|
+
toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2-usb' }),
|
|
209
|
+
setCancelableAction: jest.fn(),
|
|
210
|
+
clearCancelableAction: jest.fn(),
|
|
211
|
+
} as unknown as Device;
|
|
212
|
+
method.postMessage = jest.fn();
|
|
213
|
+
method.postProgressMessage = jest.fn();
|
|
214
|
+
|
|
215
|
+
const firmwareUpdate = method as unknown as {
|
|
216
|
+
protocolV2StartFirmwareUpdate: (params: { targets: typeof targets }) => Promise<void>;
|
|
217
|
+
waitForProtocolV2FirmwareUpdateComplete: (
|
|
218
|
+
value: typeof targets,
|
|
219
|
+
requireCurrentInstallStatus: boolean
|
|
220
|
+
) => Promise<void>;
|
|
221
|
+
reconnectProtocolV2Device: (options: { skipProtocolProbe: boolean }) => Promise<void>;
|
|
222
|
+
verifyProtocolV2ReconnectIdentity: () => Promise<Record<string, never>>;
|
|
223
|
+
};
|
|
224
|
+
firmwareUpdate.reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
225
|
+
firmwareUpdate.verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue({});
|
|
226
|
+
(method as any).isBleReconnect = jest.fn(() => false);
|
|
227
|
+
|
|
228
|
+
await firmwareUpdate.protocolV2StartFirmwareUpdate({ targets });
|
|
229
|
+
await firmwareUpdate.waitForProtocolV2FirmwareUpdateComplete(targets, true);
|
|
230
|
+
|
|
231
|
+
expect(firmwareUpdate.reconnectProtocolV2Device).toHaveBeenCalledWith({
|
|
232
|
+
skipProtocolProbe: true,
|
|
233
|
+
});
|
|
234
|
+
expect(firmwareUpdate.verifyProtocolV2ReconnectIdentity).toHaveBeenCalledTimes(1);
|
|
235
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(1, 'installingFirmware');
|
|
236
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
74
237
|
});
|
|
75
238
|
|
|
76
239
|
test('writes the BLE Request and completes only from target status polling', async () => {
|
|
@@ -155,6 +318,67 @@ describe('FirmwareUpdateV4 install polling', () => {
|
|
|
155
318
|
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
156
319
|
});
|
|
157
320
|
|
|
321
|
+
test('confirms App mode when BLE status becomes empty after current install progress', async () => {
|
|
322
|
+
const method = new FirmwareUpdateV4({
|
|
323
|
+
id: 1,
|
|
324
|
+
payload: {
|
|
325
|
+
method: 'firmwareUpdateV4',
|
|
326
|
+
connectId: 'pro2-ble',
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
const targets = [{ target_id: 4, path: 'vol0:/application_p1.bin' }];
|
|
330
|
+
const typedCall = jest
|
|
331
|
+
.fn()
|
|
332
|
+
.mockResolvedValueOnce({
|
|
333
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
334
|
+
message: {
|
|
335
|
+
records: [
|
|
336
|
+
{
|
|
337
|
+
target_id: 4,
|
|
338
|
+
status: 'FW_MGMT_UPDATER_TASK_STATUS_IN_PROGRESS',
|
|
339
|
+
path: 'vol0:/application_p1.bin',
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
},
|
|
343
|
+
})
|
|
344
|
+
.mockResolvedValueOnce({
|
|
345
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
346
|
+
message: { records: [] },
|
|
347
|
+
});
|
|
348
|
+
const reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
349
|
+
const deviceInfo = {};
|
|
350
|
+
const verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(deviceInfo);
|
|
351
|
+
const probeProtocolV2NormalMode = jest.fn().mockResolvedValue(true);
|
|
352
|
+
|
|
353
|
+
method.device = {
|
|
354
|
+
getCommands: () => ({ typedCall }),
|
|
355
|
+
} as unknown as Device;
|
|
356
|
+
method.postProgressMessage = jest.fn();
|
|
357
|
+
|
|
358
|
+
const firmwareUpdate = method as unknown as {
|
|
359
|
+
protocolV2InstallNeedsReconnect: boolean;
|
|
360
|
+
waitForProtocolV2FirmwareUpdateComplete: (
|
|
361
|
+
value: typeof targets,
|
|
362
|
+
requireCurrentInstallStatus: boolean
|
|
363
|
+
) => Promise<void>;
|
|
364
|
+
reconnectProtocolV2Device: (options: { skipProtocolProbe: boolean }) => Promise<void>;
|
|
365
|
+
verifyProtocolV2ReconnectIdentity: () => Promise<typeof deviceInfo>;
|
|
366
|
+
probeProtocolV2NormalMode: (value: typeof deviceInfo) => Promise<boolean>;
|
|
367
|
+
};
|
|
368
|
+
firmwareUpdate.protocolV2InstallNeedsReconnect = true;
|
|
369
|
+
firmwareUpdate.reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
370
|
+
firmwareUpdate.verifyProtocolV2ReconnectIdentity = verifyProtocolV2ReconnectIdentity;
|
|
371
|
+
firmwareUpdate.probeProtocolV2NormalMode = probeProtocolV2NormalMode;
|
|
372
|
+
(method as any).isBleReconnect = jest.fn(() => true);
|
|
373
|
+
|
|
374
|
+
await firmwareUpdate.waitForProtocolV2FirmwareUpdateComplete(targets, true);
|
|
375
|
+
|
|
376
|
+
expect(reconnectProtocolV2Device).toHaveBeenCalledWith({ skipProtocolProbe: true });
|
|
377
|
+
expect(verifyProtocolV2ReconnectIdentity).toHaveBeenCalledTimes(1);
|
|
378
|
+
expect(probeProtocolV2NormalMode).toHaveBeenCalledWith(deviceInfo);
|
|
379
|
+
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
380
|
+
});
|
|
381
|
+
|
|
158
382
|
test('does not send Request when Stage is rejected', async () => {
|
|
159
383
|
const method = new FirmwareUpdateV4({
|
|
160
384
|
id: 1,
|
|
@@ -192,40 +416,46 @@ describe('FirmwareUpdateV4 install polling', () => {
|
|
|
192
416
|
const targets = [{ target_id: 4, path: 'vol0:/application_p1.bin' }];
|
|
193
417
|
const actionCancelledError = ERRORS.TypedError(HardwareErrorCode.ActionCancelled);
|
|
194
418
|
const typedCall = jest.fn().mockImplementation((type: string) => {
|
|
195
|
-
if (type === 'DeviceFirmwareUpdateRequest') {
|
|
196
|
-
return Promise.reject(actionCancelledError);
|
|
197
|
-
}
|
|
198
419
|
if (type === 'DeviceFirmwareUpdateStatusGet') {
|
|
199
|
-
return Promise.
|
|
420
|
+
return Promise.reject(actionCancelledError);
|
|
200
421
|
}
|
|
201
422
|
return Promise.resolve({ type: 'Success', message: {} });
|
|
202
423
|
});
|
|
203
424
|
const call = jest.fn().mockResolvedValue({
|
|
204
|
-
type: '
|
|
205
|
-
message: {
|
|
425
|
+
type: 'WriteCompleted',
|
|
426
|
+
message: {},
|
|
206
427
|
});
|
|
207
428
|
|
|
208
429
|
method.device = {
|
|
209
|
-
getCommands: () => ({ typedCall, call }),
|
|
430
|
+
getCommands: () => ({ typedCall, call, cancelDevice: jest.fn() }),
|
|
210
431
|
createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
|
|
211
432
|
toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2-usb' }),
|
|
212
433
|
setCancelableAction: jest.fn(),
|
|
434
|
+
clearCancelableAction: jest.fn(),
|
|
213
435
|
} as unknown as Device;
|
|
214
436
|
method.postMessage = jest.fn();
|
|
215
437
|
method.postProgressMessage = jest.fn();
|
|
216
438
|
|
|
439
|
+
const firmwareUpdate = method as unknown as {
|
|
440
|
+
protocolV2StartFirmwareUpdate: (params: { targets: typeof targets }) => Promise<void>;
|
|
441
|
+
waitForProtocolV2FirmwareUpdateComplete: (
|
|
442
|
+
value: typeof targets,
|
|
443
|
+
requireCurrentInstallStatus: boolean
|
|
444
|
+
) => Promise<void>;
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
await firmwareUpdate.protocolV2StartFirmwareUpdate({ targets });
|
|
217
448
|
await expect(
|
|
218
|
-
(
|
|
219
|
-
method as unknown as {
|
|
220
|
-
protocolV2StartFirmwareUpdate: (params: { targets: typeof targets }) => Promise<void>;
|
|
221
|
-
}
|
|
222
|
-
).protocolV2StartFirmwareUpdate({ targets })
|
|
449
|
+
firmwareUpdate.waitForProtocolV2FirmwareUpdateComplete(targets, true)
|
|
223
450
|
).rejects.toMatchObject({
|
|
224
451
|
errorCode: HardwareErrorCode.ActionCancelled,
|
|
225
452
|
});
|
|
226
453
|
|
|
227
|
-
expect(
|
|
228
|
-
|
|
454
|
+
expect(call).toHaveBeenCalledWith(
|
|
455
|
+
'DeviceFirmwareUpdateRequest',
|
|
456
|
+
{},
|
|
457
|
+
expect.objectContaining({ returnAfterWrite: true })
|
|
458
|
+
);
|
|
229
459
|
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
230
460
|
});
|
|
231
461
|
|
|
@@ -5401,6 +5401,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5401
5401
|
});
|
|
5402
5402
|
const targets = [{ target_id: 4, path: 'vol1:firmware.bin' }];
|
|
5403
5403
|
const typedCall = jest.fn().mockResolvedValue({ type: 'Success', message: {} });
|
|
5404
|
+
const call = jest.fn().mockResolvedValue({ type: 'WriteCompleted', message: {} });
|
|
5404
5405
|
const cancelDevice = jest.fn().mockResolvedValue(undefined);
|
|
5405
5406
|
let cancelableAction: (() => Promise<unknown>) | undefined;
|
|
5406
5407
|
const interaction = {
|
|
@@ -5413,7 +5414,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5413
5414
|
};
|
|
5414
5415
|
|
|
5415
5416
|
(method as any).device = stubDevice({
|
|
5416
|
-
getCommands: () => ({ typedCall, cancelDevice }),
|
|
5417
|
+
getCommands: () => ({ typedCall, call, cancelDevice }),
|
|
5417
5418
|
createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(interaction),
|
|
5418
5419
|
toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2' }),
|
|
5419
5420
|
setCancelableAction: jest.fn(action => {
|
|
@@ -5442,18 +5443,21 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5442
5443
|
interaction,
|
|
5443
5444
|
},
|
|
5444
5445
|
});
|
|
5445
|
-
expect(
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5446
|
+
expect(call).toHaveBeenCalledWith(
|
|
5447
|
+
'DeviceFirmwareUpdateRequest',
|
|
5448
|
+
{},
|
|
5449
|
+
expect.objectContaining({
|
|
5450
|
+
returnAfterWrite: true,
|
|
5451
|
+
expectedTypes: ['Success'],
|
|
5452
|
+
onResponseAfterWrite: expect.any(Function),
|
|
5453
|
+
})
|
|
5451
5454
|
);
|
|
5455
|
+
expect(typedCall.mock.invocationCallOrder[0]).toBeLessThan(call.mock.invocationCallOrder[0]);
|
|
5452
5456
|
expect((method.postMessage as jest.Mock).mock.invocationCallOrder[0]).toBeLessThan(
|
|
5453
|
-
|
|
5457
|
+
call.mock.invocationCallOrder[0]
|
|
5454
5458
|
);
|
|
5455
5459
|
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
5456
|
-
expect(method.postProgressMessage).
|
|
5460
|
+
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
5457
5461
|
await cancelableAction?.();
|
|
5458
5462
|
expect(cancelDevice).toHaveBeenCalledTimes(1);
|
|
5459
5463
|
});
|
|
@@ -5466,9 +5470,10 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5466
5470
|
},
|
|
5467
5471
|
});
|
|
5468
5472
|
const typedCall = jest.fn().mockRejectedValue(new Error('stage failed'));
|
|
5473
|
+
const call = jest.fn();
|
|
5469
5474
|
|
|
5470
5475
|
(method as any).device = stubDevice({
|
|
5471
|
-
getCommands: () => ({ typedCall }),
|
|
5476
|
+
getCommands: () => ({ typedCall, call }),
|
|
5472
5477
|
});
|
|
5473
5478
|
method.postMessage = jest.fn();
|
|
5474
5479
|
method.postTipMessage = jest.fn();
|
|
@@ -5480,7 +5485,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5480
5485
|
})
|
|
5481
5486
|
).rejects.toThrow('stage failed');
|
|
5482
5487
|
|
|
5483
|
-
expect(
|
|
5488
|
+
expect(call).not.toHaveBeenCalled();
|
|
5484
5489
|
expect(method.postMessage).not.toHaveBeenCalled();
|
|
5485
5490
|
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
5486
5491
|
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
@@ -5493,15 +5498,11 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5493
5498
|
method: 'firmwareUpdateV4',
|
|
5494
5499
|
},
|
|
5495
5500
|
});
|
|
5496
|
-
const typedCall = jest.fn().
|
|
5497
|
-
|
|
5498
|
-
return Promise.reject(new Error('request failed'));
|
|
5499
|
-
}
|
|
5500
|
-
return Promise.resolve({ type: 'Success', message: {} });
|
|
5501
|
-
});
|
|
5501
|
+
const typedCall = jest.fn().mockResolvedValue({ type: 'Success', message: {} });
|
|
5502
|
+
const call = jest.fn().mockRejectedValue(new Error('request failed'));
|
|
5502
5503
|
|
|
5503
5504
|
(method as any).device = stubDevice({
|
|
5504
|
-
getCommands: () => ({ typedCall }),
|
|
5505
|
+
getCommands: () => ({ typedCall, call }),
|
|
5505
5506
|
createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
|
|
5506
5507
|
toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2' }),
|
|
5507
5508
|
});
|
|
@@ -5515,7 +5516,15 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5515
5516
|
})
|
|
5516
5517
|
).rejects.toThrow('request failed');
|
|
5517
5518
|
|
|
5518
|
-
expect(
|
|
5519
|
+
expect(call).toHaveBeenCalledWith(
|
|
5520
|
+
'DeviceFirmwareUpdateRequest',
|
|
5521
|
+
{},
|
|
5522
|
+
expect.objectContaining({
|
|
5523
|
+
returnAfterWrite: true,
|
|
5524
|
+
expectedTypes: ['Success'],
|
|
5525
|
+
onResponseAfterWrite: expect.any(Function),
|
|
5526
|
+
})
|
|
5527
|
+
);
|
|
5519
5528
|
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
5520
5529
|
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
5521
5530
|
});
|
|
@@ -5554,7 +5563,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5554
5563
|
})
|
|
5555
5564
|
);
|
|
5556
5565
|
expect(typedCall).not.toHaveBeenCalledWith('DeviceFirmwareUpdateRequest', 'Success', {});
|
|
5557
|
-
expect((method as any).
|
|
5566
|
+
expect((method as any).protocolV2InstallNeedsReconnect).toBe(true);
|
|
5558
5567
|
});
|
|
5559
5568
|
|
|
5560
5569
|
test.each([
|
|
@@ -5594,7 +5603,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
5594
5603
|
getCommands: () => ({ typedCall }),
|
|
5595
5604
|
});
|
|
5596
5605
|
(method as any).isBleReconnect = jest.fn(() => true);
|
|
5597
|
-
(method as any).
|
|
5606
|
+
(method as any).protocolV2InstallNeedsReconnect = true;
|
|
5598
5607
|
(method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
5599
5608
|
(method as any).verifyProtocolV2ReconnectIdentity = verifyProtocolV2ReconnectIdentity;
|
|
5600
5609
|
method.postProgressMessage = jest.fn();
|
|
@@ -6150,7 +6159,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6150
6159
|
(method as any).device = stubDevice({
|
|
6151
6160
|
getCommands: () => ({ typedCall }),
|
|
6152
6161
|
});
|
|
6153
|
-
(method as any).
|
|
6162
|
+
(method as any).protocolV2InstallTerminalSuccessObserved = true;
|
|
6154
6163
|
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
6155
6164
|
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(deviceInfo);
|
|
6156
6165
|
(method as any).probeProtocolV2NormalMode = jest.fn().mockResolvedValue(true);
|
|
@@ -6196,7 +6205,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6196
6205
|
(method as any).device = stubDevice({
|
|
6197
6206
|
getCommands: () => ({ typedCall }),
|
|
6198
6207
|
});
|
|
6199
|
-
(method as any).
|
|
6208
|
+
(method as any).protocolV2InstallTerminalSuccessObserved = true;
|
|
6200
6209
|
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
6201
6210
|
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(deviceInfo);
|
|
6202
6211
|
(method as any).probeProtocolV2NormalMode = jest.fn().mockResolvedValue(true);
|
|
@@ -9087,27 +9096,28 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
9087
9096
|
expect(writePayloads.map(payload => payload.file.data.byteLength)).toEqual([1960, 1]);
|
|
9088
9097
|
});
|
|
9089
9098
|
|
|
9090
|
-
test('keeps confirmation active
|
|
9099
|
+
test('keeps confirmation active after the Request write until terminal Success arrives', async () => {
|
|
9091
9100
|
const method = new FirmwareUpdateV4({
|
|
9092
9101
|
id: 1,
|
|
9093
9102
|
payload: {
|
|
9094
9103
|
method: 'firmwareUpdateV4',
|
|
9095
9104
|
},
|
|
9096
9105
|
});
|
|
9097
|
-
let
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
}
|
|
9104
|
-
return Promise.resolve({ type: 'Success', message: {} });
|
|
9106
|
+
let onResponseAfterWrite:
|
|
9107
|
+
| ((response: { type: string; message: Record<string, never> }) => void)
|
|
9108
|
+
| undefined;
|
|
9109
|
+
const typedCall = jest.fn().mockResolvedValue({ type: 'Success', message: {} });
|
|
9110
|
+
const call = jest.fn().mockImplementation((_type, _message, options) => {
|
|
9111
|
+
onResponseAfterWrite = options.onResponseAfterWrite;
|
|
9112
|
+
return Promise.resolve({ type: 'WriteCompleted', message: {} });
|
|
9105
9113
|
});
|
|
9114
|
+
const clearCancelableAction = jest.fn();
|
|
9106
9115
|
|
|
9107
9116
|
(method as any).device = stubDevice({
|
|
9108
|
-
getCommands: () => ({ typedCall }),
|
|
9117
|
+
getCommands: () => ({ typedCall, call, cancelDevice: jest.fn() }),
|
|
9109
9118
|
createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
|
|
9110
9119
|
toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2' }),
|
|
9120
|
+
clearCancelableAction,
|
|
9111
9121
|
});
|
|
9112
9122
|
method.postMessage = jest.fn();
|
|
9113
9123
|
method.postProgressMessage = jest.fn();
|
|
@@ -9125,17 +9135,28 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
9125
9135
|
'Success',
|
|
9126
9136
|
{ targets: [{ target_id: 4, path: 'vol1:firmware.bin' }] },
|
|
9127
9137
|
]);
|
|
9128
|
-
expect(
|
|
9138
|
+
expect(call).toHaveBeenCalledWith(
|
|
9139
|
+
'DeviceFirmwareUpdateRequest',
|
|
9140
|
+
{},
|
|
9141
|
+
expect.objectContaining({
|
|
9142
|
+
returnAfterWrite: true,
|
|
9143
|
+
expectedTypes: ['Success'],
|
|
9144
|
+
onResponseAfterWrite: expect.any(Function),
|
|
9145
|
+
})
|
|
9146
|
+
);
|
|
9129
9147
|
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
9130
9148
|
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
9149
|
+
expect(clearCancelableAction).not.toHaveBeenCalled();
|
|
9131
9150
|
|
|
9132
|
-
resolveRequest?.({ type: 'Success', message: {} });
|
|
9133
9151
|
await startPromise;
|
|
9152
|
+
onResponseAfterWrite?.({ type: 'Success', message: {} });
|
|
9153
|
+
expect(clearCancelableAction).toHaveBeenCalledTimes(1);
|
|
9154
|
+
expect((method as any).protocolV2InstallTerminalSuccessObserved).toBe(true);
|
|
9134
9155
|
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
9135
|
-
expect(method.postProgressMessage).
|
|
9156
|
+
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
9136
9157
|
});
|
|
9137
9158
|
|
|
9138
|
-
test('returns after the empty Protocol V2 firmware install request
|
|
9159
|
+
test('returns after the empty Protocol V2 firmware install request is written', async () => {
|
|
9139
9160
|
const method = new FirmwareUpdateV4({
|
|
9140
9161
|
id: 1,
|
|
9141
9162
|
payload: {
|
|
@@ -9146,9 +9167,13 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
9146
9167
|
type: 'Success',
|
|
9147
9168
|
message: { message: 'accepted' },
|
|
9148
9169
|
});
|
|
9170
|
+
const call = jest.fn().mockResolvedValue({
|
|
9171
|
+
type: 'WriteCompleted',
|
|
9172
|
+
message: {},
|
|
9173
|
+
});
|
|
9149
9174
|
|
|
9150
9175
|
(method as any).device = stubDevice({
|
|
9151
|
-
getCommands: () => ({ typedCall }),
|
|
9176
|
+
getCommands: () => ({ typedCall, call, cancelDevice: jest.fn() }),
|
|
9152
9177
|
createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
|
|
9153
9178
|
toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2' }),
|
|
9154
9179
|
});
|
|
@@ -9161,9 +9186,17 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
9161
9186
|
});
|
|
9162
9187
|
|
|
9163
9188
|
expect(typedCall.mock.calls[0][0]).toBe('DeviceFirmwareUpdateStage');
|
|
9164
|
-
expect(
|
|
9189
|
+
expect(call).toHaveBeenCalledWith(
|
|
9190
|
+
'DeviceFirmwareUpdateRequest',
|
|
9191
|
+
{},
|
|
9192
|
+
expect.objectContaining({
|
|
9193
|
+
returnAfterWrite: true,
|
|
9194
|
+
expectedTypes: ['Success'],
|
|
9195
|
+
onResponseAfterWrite: expect.any(Function),
|
|
9196
|
+
})
|
|
9197
|
+
);
|
|
9165
9198
|
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
9166
|
-
expect(method.postProgressMessage).
|
|
9199
|
+
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
9167
9200
|
});
|
|
9168
9201
|
});
|
|
9169
9202
|
|
|
@@ -17,8 +17,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
17
17
|
private protocolV2LatestFinalFeatures?;
|
|
18
18
|
private protocolV2LatestFinalDeviceInfo?;
|
|
19
19
|
private protocolV2InstallBaselineVersions;
|
|
20
|
-
private
|
|
21
|
-
private
|
|
20
|
+
private protocolV2InstallNeedsReconnect;
|
|
21
|
+
private protocolV2InstallTerminalSuccessObserved;
|
|
22
22
|
private protocolV2LastRuntimeProbeFeatures?;
|
|
23
23
|
private protocolV2LastTransferProgress?;
|
|
24
24
|
private protocolV2LastTransferProgressAt;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkD,MAAM,qBAAqB,CAAC;AA0BlG,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AA+B/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AAoErC,wBAAgB,wCAAwC,CACtD,UAAU,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,sBAAsB,EAC9B,0BAA0B,UAAQ,QAiCnC;AAuSD,eAAO,MAAM,oCAAoC,WACvC,WAAW,GAAG,UAAU,eACnB,MAAM,GAAG,SAAS,YAKhC,CAAC;AAEF,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,iBACZ,MAAM,eACR,MAAM,SAsBpB,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,sBAAsB,CAAC,CAAS;IAExC,OAAO,CAAC,oCAAoC,CAAS;IAErD,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAAS;IAElD,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,4BAA4B,CAAqB;IAEzD,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,+BAA+B,CAAC,CAAuB;IAE/D,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkD,MAAM,qBAAqB,CAAC;AA0BlG,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AA+B/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AAoErC,wBAAgB,wCAAwC,CACtD,UAAU,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,sBAAsB,EAC9B,0BAA0B,UAAQ,QAiCnC;AAuSD,eAAO,MAAM,oCAAoC,WACvC,WAAW,GAAG,UAAU,eACnB,MAAM,GAAG,SAAS,YAKhC,CAAC;AAEF,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,iBACZ,MAAM,eACR,MAAM,SAsBpB,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,sBAAsB,CAAC,CAAS;IAExC,OAAO,CAAC,oCAAoC,CAAS;IAErD,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAAS;IAElD,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,4BAA4B,CAAqB;IAEzD,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,+BAA+B,CAAC,CAAuB;IAE/D,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,+BAA+B,CAAS;IAEhD,OAAO,CAAC,wCAAwC,CAAS;IAEzD,OAAO,CAAC,kCAAkC,CAAC,CAAW;IAEtD,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,gCAAgC,CAAK;IAE7C,IAAI;IA6LJ,OAAO,CAAC,8BAA8B;IAwBhC,GAAG;;;;;YAKK,aAAa;YA0Ib,4BAA4B;YAkB5B,0BAA0B;YAY1B,8BAA8B;YAK9B,+BAA+B;YAqG/B,4BAA4B;YA+C5B,0CAA0C;YAkB1C,qCAAqC;YAoFrC,gCAAgC;YAgBhC,uCAAuC;YAmDvC,8BAA8B;IA8B5C,OAAO,CAAC,8BAA8B;IA0BtC,OAAO,CAAC,kCAAkC;IAc1C,OAAO,CAAC,gCAAgC;YAuD1B,2BAA2B;IAmBzC,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,oCAAoC;IAY5C,OAAO,CAAC,4BAA4B;IAUpC,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,8BAA8B;YAMxB,iCAAiC;YAOjC,iCAAiC;YAmBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,mCAAmC;IAe3C,OAAO,CAAC,iCAAiC;IAWzC,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;YAkBlB,iCAAiC;YA6CjC,uCAAuC;YA0CvC,+BAA+B;IAmF7C,OAAO,CAAC,6BAA6B;IAMrC,OAAO,CAAC,gCAAgC;YAM1B,8BAA8B;YAmD9B,kCAAkC;IA+BhD,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,yBAAyB;YAcnB,4BAA4B;IAkBpC,6BAA6B;YAkBrB,+BAA+B;IAkD7C,OAAO,CAAC,6BAA6B;YAkCvB,6BAA6B;YA0B7B,0CAA0C;YA6B1C,uBAAuB;YAiCvB,8BAA8B;YAwE9B,6BAA6B;IA8E3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,8BAA8B;IAiBtC,OAAO,CAAC,4BAA4B;IA6IpC,OAAO,CAAC,6BAA6B;IAcrC,OAAO,CAAC,qCAAqC;IAyB7C,OAAO,CAAC,kCAAkC;IAgB1C,OAAO,CAAC,8CAA8C;YAIxC,uCAAuC;YAiPvC,gCAAgC;YAehC,yBAAyB;IASvC,OAAO,CAAC,2BAA2B;YAMrB,8BAA8B;IAQ5C,OAAO,CAAC,0BAA0B;YAkBpB,mCAAmC;YAWnC,qCAAqC;YAmDrC,yBAAyB;YAgGzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAQ5B,cAAc;YAuCd,6BAA6B;YAW7B,0BAA0B;YAoB1B,6BAA6B;YAoD7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAoClC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAYxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAWpD,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAmE7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBAoFvE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAoClC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAYxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAWpD,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAmE7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBAoFvE,CAAC;AAiqBF,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,WAWpF;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,WAW/E;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,WAQlF;AA0PD,eAAO,MAAM,MAAM,YAAa,WAAW,cAAc,MAAM,SAuG9D,CAAC;AAmGF,eAAO,MAAM,qBAAqB,gFAejC,CAAC;AAiLF,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,YAAY;IAC5C,OAAO,CAAC,cAAc,CAAoB;IAE1C,SAAgB,aAAa,EAAE,MAAM,CAAC;IAEtC,OAAO,CAAC,YAAY,CAAsB;IAE1C,OAAO,CAAC,cAAc,CAAC,CAAgB;IAGvC,OAAO,CAAC,sBAAsB,CAAoC;IAElE,OAAO,CAAC,iBAAiB,CAAoB;;IAS7C,OAAO,CAAC,cAAc;IA6BhB,aAAa,CAAC,OAAO,EAAE,WAAW;IAuExC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAOV,gBAAgB;CAiC/B;AAED,eAAO,MAAM,QAAQ,YAIpB,CAAC;AAEF,eAAO,MAAM,aAAa,uBAYzB,CAAC;AAMF,eAAO,MAAM,IAAI,aACL,eAAe,aACd,GAAG,WACL,6BAA6B,8BAiBvC,CAAC;AAEF,eAAO,MAAM,eAAe;SAKrB,eAAe,CAAC,KAAK,CAAC;eAChB,GAAG;;UASf,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -51982,8 +51982,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51982
51982
|
this.protocolV2CompletedTargetVersions = new Map();
|
|
51983
51983
|
this.protocolV2CompletedTargetIds = new Set();
|
|
51984
51984
|
this.protocolV2InstallBaselineVersions = new Map();
|
|
51985
|
-
this.
|
|
51986
|
-
this.
|
|
51985
|
+
this.protocolV2InstallNeedsReconnect = false;
|
|
51986
|
+
this.protocolV2InstallTerminalSuccessObserved = false;
|
|
51987
51987
|
this.protocolV2LastTransferProgressAt = 0;
|
|
51988
51988
|
}
|
|
51989
51989
|
getSupportedProtocols() {
|
|
@@ -53417,11 +53417,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
53417
53417
|
const expectedPaths = new Map(targets.map(target => [target.target_id, target.path]));
|
|
53418
53418
|
const startTime = Date.now();
|
|
53419
53419
|
let lastError;
|
|
53420
|
-
let shouldReconnect = this.
|
|
53421
|
-
this.
|
|
53420
|
+
let shouldReconnect = this.protocolV2InstallNeedsReconnect;
|
|
53421
|
+
this.protocolV2InstallNeedsReconnect = false;
|
|
53422
53422
|
let deviceInfo;
|
|
53423
53423
|
let bleInstallLinkReady = false;
|
|
53424
|
-
let installEvidenceObserved = this.
|
|
53424
|
+
let installEvidenceObserved = this.protocolV2InstallTerminalSuccessObserved;
|
|
53425
53425
|
let currentInstallStatusObserved = false;
|
|
53426
53426
|
const liveTargetIds = new Set();
|
|
53427
53427
|
while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
|
|
@@ -53436,7 +53436,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
53436
53436
|
: yield this.verifyProtocolV2ReconnectIdentity();
|
|
53437
53437
|
shouldReconnect = false;
|
|
53438
53438
|
}
|
|
53439
|
-
|
|
53439
|
+
let currentDeviceInfo = deviceInfo;
|
|
53440
53440
|
try {
|
|
53441
53441
|
const statusResponse = yield this.device.getCommands().typedCall('DeviceFirmwareUpdateStatusGet', 'DeviceFirmwareUpdateStatus', {
|
|
53442
53442
|
fields: {
|
|
@@ -53445,7 +53445,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
53445
53445
|
path: true,
|
|
53446
53446
|
},
|
|
53447
53447
|
}, { timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT });
|
|
53448
|
-
if (this.
|
|
53448
|
+
if (this.protocolV2InstallTerminalSuccessObserved) {
|
|
53449
53449
|
installEvidenceObserved = true;
|
|
53450
53450
|
}
|
|
53451
53451
|
const statusTargets = ((_a = statusResponse.message.records) !== null && _a !== void 0 ? _a : []);
|
|
@@ -53465,16 +53465,29 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
53465
53465
|
const targetId = normalizeProtocolV2TargetId(target.target_id);
|
|
53466
53466
|
return targetId !== undefined && expectedTargetIds.has(targetId);
|
|
53467
53467
|
});
|
|
53468
|
-
const
|
|
53468
|
+
const hasCurrentInstallEvidence = currentInstallStatusObserved || this.protocolV2InstallTerminalSuccessObserved;
|
|
53469
|
+
const shouldVerifyTargetCompletion = !requireCurrentInstallStatus || hasCurrentInstallEvidence;
|
|
53469
53470
|
if (shouldVerifyTargetCompletion &&
|
|
53470
|
-
this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds, expectedPaths, requireCurrentInstallStatus
|
|
53471
|
+
this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds, expectedPaths, requireCurrentInstallStatus && !this.protocolV2InstallTerminalSuccessObserved
|
|
53472
|
+
? liveTargetIds
|
|
53473
|
+
: undefined)) {
|
|
53471
53474
|
return;
|
|
53472
53475
|
}
|
|
53476
|
+
if (!hasCurrentInstallEvidence) {
|
|
53477
|
+
this.device.setCancelableAction(() => this.device.getCommands().cancelDevice());
|
|
53478
|
+
}
|
|
53473
53479
|
if (requireCurrentInstallStatus &&
|
|
53474
|
-
!
|
|
53480
|
+
!hasCurrentInstallEvidence &&
|
|
53475
53481
|
matchingStatusTargets.length > 0) {
|
|
53476
53482
|
lastError = new Error('Protocol V2 firmware status is stale; waiting for the current install to start');
|
|
53477
53483
|
}
|
|
53484
|
+
if (statusTargets.length === 0 &&
|
|
53485
|
+
!currentDeviceInfo &&
|
|
53486
|
+
bleInstallLinkReady &&
|
|
53487
|
+
installEvidenceObserved) {
|
|
53488
|
+
currentDeviceInfo = yield this.verifyProtocolV2ReconnectIdentity();
|
|
53489
|
+
deviceInfo = currentDeviceInfo;
|
|
53490
|
+
}
|
|
53478
53491
|
if (statusTargets.length === 0 && currentDeviceInfo) {
|
|
53479
53492
|
const isNormalMode = yield this.probeProtocolV2NormalMode(currentDeviceInfo);
|
|
53480
53493
|
if (isNormalMode &&
|
|
@@ -53797,54 +53810,34 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
53797
53810
|
protocolV2StartFirmwareUpdate({ targets, }) {
|
|
53798
53811
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53799
53812
|
this.protocolV2LastRuntimeProbeFeatures = undefined;
|
|
53800
|
-
this.
|
|
53801
|
-
this.
|
|
53813
|
+
this.protocolV2InstallNeedsReconnect = false;
|
|
53814
|
+
this.protocolV2InstallTerminalSuccessObserved = false;
|
|
53802
53815
|
const commands = this.device.getCommands();
|
|
53803
53816
|
yield commands.typedCall('DeviceFirmwareUpdateStage', 'Success', { targets });
|
|
53804
|
-
this.device.setCancelableAction(() =>
|
|
53817
|
+
this.device.setCancelableAction(() => this.device.getCommands().cancelDevice());
|
|
53805
53818
|
const interaction = this.device.createProtocolV2UiPhaseMetadata('button', 'start');
|
|
53806
53819
|
this.postMessage(createUiMessage(UI_REQUEST.REQUEST_BUTTON, Object.assign({ device: this.device.toMessageObject(), source: 'method-lifecycle', reason: 'firmware-update', completion: 'operation-completed', deviceOnly: true, operation: this.name }, (interaction ? { interaction } : {}))));
|
|
53807
|
-
if (this.isBleReconnect()) {
|
|
53808
|
-
try {
|
|
53809
|
-
yield commands.call('DeviceFirmwareUpdateRequest', {}, {
|
|
53810
|
-
returnAfterWrite: true,
|
|
53811
|
-
expectedTypes: ['Success'],
|
|
53812
|
-
onResponseAfterWrite: response => {
|
|
53813
|
-
if (response.type !== 'Success')
|
|
53814
|
-
return;
|
|
53815
|
-
this.protocolV2InstallRequestConfirmed = true;
|
|
53816
|
-
this.device.clearCancelableAction();
|
|
53817
|
-
this.postProgressMessage(1, 'installingFirmware');
|
|
53818
|
-
Log$7.log('[FirmwareUpdateV4] BLE firmware install confirmed by device response');
|
|
53819
|
-
},
|
|
53820
|
-
});
|
|
53821
|
-
Log$7.log('[FirmwareUpdateV4] BLE firmware install request written; continue with status polling');
|
|
53822
|
-
}
|
|
53823
|
-
catch (error) {
|
|
53824
|
-
this.throwIfAborted();
|
|
53825
|
-
if (!isProtocolV2DeviceDisconnectedError(error)) {
|
|
53826
|
-
throw error;
|
|
53827
|
-
}
|
|
53828
|
-
Log$7.log('[FirmwareUpdateV4] BLE transport released while writing install request; continue status polling');
|
|
53829
|
-
this.protocolV2InstallNeedsBleReconnect = true;
|
|
53830
|
-
}
|
|
53831
|
-
return;
|
|
53832
|
-
}
|
|
53833
53820
|
try {
|
|
53834
|
-
yield commands.
|
|
53835
|
-
|
|
53836
|
-
|
|
53837
|
-
|
|
53821
|
+
yield commands.call('DeviceFirmwareUpdateRequest', {}, {
|
|
53822
|
+
returnAfterWrite: true,
|
|
53823
|
+
expectedTypes: ['Success'],
|
|
53824
|
+
onResponseAfterWrite: response => {
|
|
53825
|
+
if (response.type !== 'Success')
|
|
53826
|
+
return;
|
|
53827
|
+
this.protocolV2InstallTerminalSuccessObserved = true;
|
|
53828
|
+
this.device.clearCancelableAction();
|
|
53829
|
+
Log$7.log('[FirmwareUpdateV4] firmware install completed by device response');
|
|
53830
|
+
},
|
|
53831
|
+
});
|
|
53832
|
+
Log$7.log('[FirmwareUpdateV4] firmware install request written; continue with status polling');
|
|
53838
53833
|
}
|
|
53839
53834
|
catch (error) {
|
|
53840
53835
|
this.throwIfAborted();
|
|
53841
53836
|
if (!isProtocolV2DeviceDisconnectedError(error)) {
|
|
53842
53837
|
throw error;
|
|
53843
53838
|
}
|
|
53844
|
-
Log$7.log('[FirmwareUpdateV4]
|
|
53845
|
-
|
|
53846
|
-
this.protocolV2InstallNeedsBleReconnect = true;
|
|
53847
|
-
}
|
|
53839
|
+
Log$7.log('[FirmwareUpdateV4] transport released while writing install request; continue status polling');
|
|
53840
|
+
this.protocolV2InstallNeedsReconnect = true;
|
|
53848
53841
|
}
|
|
53849
53842
|
});
|
|
53850
53843
|
}
|
|
@@ -65191,8 +65184,6 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
65191
65184
|
if ((_g = method.payload) === null || _g === void 0 ? void 0 : _g.onlyConnectBleDevice) {
|
|
65192
65185
|
preWarmCallbackTask === null || preWarmCallbackTask === void 0 ? void 0 : preWarmCallbackTask.resolve();
|
|
65193
65186
|
Log.debug('Call API - only connect ble device: ', device === null || device === void 0 ? void 0 : device.mainId);
|
|
65194
|
-
completeMethodRequestContext(method);
|
|
65195
|
-
requestQueue.releaseTask(method.responseID);
|
|
65196
65187
|
return createResponseMessage(method.responseID, true, null);
|
|
65197
65188
|
}
|
|
65198
65189
|
Log.debug('Call API - setDevice: ', device.mainId);
|
|
@@ -65568,31 +65559,7 @@ function isMissingDetectedProtocolV2Error(method, error) {
|
|
|
65568
65559
|
typeof typedError.message === 'string' &&
|
|
65569
65560
|
typedError.message.includes('Device protocol has not been detected'));
|
|
65570
65561
|
}
|
|
65571
|
-
|
|
65572
|
-
function raceBleAcquire(acquirePromise, abortSignal) {
|
|
65573
|
-
return new Promise((resolve, reject) => {
|
|
65574
|
-
let settled = false;
|
|
65575
|
-
const settle = (fn) => {
|
|
65576
|
-
if (settled)
|
|
65577
|
-
return;
|
|
65578
|
-
settled = true;
|
|
65579
|
-
clearTimeout(deadline);
|
|
65580
|
-
abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.removeEventListener('abort', onAbort);
|
|
65581
|
-
fn();
|
|
65582
|
-
};
|
|
65583
|
-
const onAbort = () => settle(() => reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled)));
|
|
65584
|
-
const deadline = setTimeout(() => settle(() => reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE acquire exceeded ${BLE_ACQUIRE_DEADLINE_MS}ms deadline`))), BLE_ACQUIRE_DEADLINE_MS);
|
|
65585
|
-
acquirePromise.then(value => settle(() => resolve(value)), error => settle(() => reject(error)));
|
|
65586
|
-
if (abortSignal) {
|
|
65587
|
-
if (abortSignal.aborted) {
|
|
65588
|
-
onAbort();
|
|
65589
|
-
return;
|
|
65590
|
-
}
|
|
65591
|
-
abortSignal.addEventListener('abort', onAbort);
|
|
65592
|
-
}
|
|
65593
|
-
});
|
|
65594
|
-
}
|
|
65595
|
-
function connectDeviceForBle(method, device, abortSignal, retryCount = 0) {
|
|
65562
|
+
function connectDeviceForBle(method, device, retryCount = 0) {
|
|
65596
65563
|
var _a;
|
|
65597
65564
|
return __awaiter(this, void 0, void 0, function* () {
|
|
65598
65565
|
try {
|
|
@@ -65607,31 +65574,9 @@ function connectDeviceForBle(method, device, abortSignal, retryCount = 0) {
|
|
|
65607
65574
|
!device.commands ||
|
|
65608
65575
|
device.commands.disposed;
|
|
65609
65576
|
if (shouldAcquire) {
|
|
65610
|
-
|
|
65611
|
-
|
|
65612
|
-
|
|
65613
|
-
}
|
|
65614
|
-
if (!useAcquireGuards) {
|
|
65615
|
-
yield device.acquire(method.payload.connectProtocol, {
|
|
65616
|
-
forceProtocolDetection: method.payload.forceProtocolDetection,
|
|
65617
|
-
});
|
|
65618
|
-
}
|
|
65619
|
-
else {
|
|
65620
|
-
try {
|
|
65621
|
-
yield raceBleAcquire(device.acquire(method.payload.connectProtocol, {
|
|
65622
|
-
forceProtocolDetection: method.payload.forceProtocolDetection,
|
|
65623
|
-
}), abortSignal);
|
|
65624
|
-
}
|
|
65625
|
-
catch (err) {
|
|
65626
|
-
if (err.errorCode === hdShared.HardwareErrorCode.BleTimeoutError &&
|
|
65627
|
-
device.mainId &&
|
|
65628
|
-
device.deviceConnector) {
|
|
65629
|
-
yield device.deviceConnector.disconnect(device.mainId).catch(() => undefined);
|
|
65630
|
-
device.markTransportDisconnected();
|
|
65631
|
-
}
|
|
65632
|
-
throw err;
|
|
65633
|
-
}
|
|
65634
|
-
}
|
|
65577
|
+
yield device.acquire(method.payload.connectProtocol, {
|
|
65578
|
+
forceProtocolDetection: method.payload.forceProtocolDetection,
|
|
65579
|
+
});
|
|
65635
65580
|
}
|
|
65636
65581
|
if ((_a = method.payload) === null || _a === void 0 ? void 0 : _a.onlyConnectBleDevice) {
|
|
65637
65582
|
if (shouldAcquire) {
|
|
@@ -65662,7 +65607,7 @@ function connectDeviceForBle(method, device, abortSignal, retryCount = 0) {
|
|
|
65662
65607
|
const nextRetry = retryCount + 1;
|
|
65663
65608
|
Log.debug(`Bluetooth connection will retry, retry count: ${nextRetry}`);
|
|
65664
65609
|
yield wait(3000);
|
|
65665
|
-
yield connectDeviceForBle(method, device,
|
|
65610
|
+
yield connectDeviceForBle(method, device, nextRetry);
|
|
65666
65611
|
}
|
|
65667
65612
|
else {
|
|
65668
65613
|
throw err;
|
|
@@ -65747,7 +65692,7 @@ const ensureConnected = (_context, method, connectId, pollingId, abortSignal) =>
|
|
|
65747
65692
|
if (tryCount === 1) {
|
|
65748
65693
|
device.beginConnectionAttempt();
|
|
65749
65694
|
}
|
|
65750
|
-
yield connectDeviceForBle(method, device
|
|
65695
|
+
yield connectDeviceForBle(method, device);
|
|
65751
65696
|
}
|
|
65752
65697
|
resolve(device);
|
|
65753
65698
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-core",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.176",
|
|
4
4
|
"description": "Core processes and APIs for communicating with OneKey hardware devices.",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
29
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
28
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.176",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.176",
|
|
30
30
|
"axios": "1.15.2",
|
|
31
31
|
"bignumber.js": "^9.0.2",
|
|
32
32
|
"buffer": "^6.0.3",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"@types/w3c-web-usb": "^1.0.10",
|
|
47
47
|
"@types/web-bluetooth": "^0.0.21"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "a5152148317effe811cde8adecdfe75c28e82657"
|
|
50
50
|
}
|
|
@@ -530,9 +530,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
530
530
|
|
|
531
531
|
private protocolV2InstallBaselineVersions = new Map<number, string>();
|
|
532
532
|
|
|
533
|
-
private
|
|
533
|
+
private protocolV2InstallNeedsReconnect = false;
|
|
534
534
|
|
|
535
|
-
private
|
|
535
|
+
private protocolV2InstallTerminalSuccessObserved = false;
|
|
536
536
|
|
|
537
537
|
private protocolV2LastRuntimeProbeFeatures?: Features;
|
|
538
538
|
|
|
@@ -2441,13 +2441,13 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2441
2441
|
const expectedPaths = new Map(targets.map(target => [target.target_id, target.path]));
|
|
2442
2442
|
const startTime = Date.now();
|
|
2443
2443
|
let lastError: unknown;
|
|
2444
|
-
//
|
|
2445
|
-
//
|
|
2446
|
-
let shouldReconnect = this.
|
|
2447
|
-
this.
|
|
2444
|
+
// The loader may release either USB or BLE as installation starts. Recovery reconnects
|
|
2445
|
+
// directly to status polling without generic Ping or DeviceInfo probes.
|
|
2446
|
+
let shouldReconnect = this.protocolV2InstallNeedsReconnect;
|
|
2447
|
+
this.protocolV2InstallNeedsReconnect = false;
|
|
2448
2448
|
let deviceInfo: ProtocolV2DeviceInfo | undefined;
|
|
2449
2449
|
let bleInstallLinkReady = false;
|
|
2450
|
-
let installEvidenceObserved = this.
|
|
2450
|
+
let installEvidenceObserved = this.protocolV2InstallTerminalSuccessObserved;
|
|
2451
2451
|
let currentInstallStatusObserved = false;
|
|
2452
2452
|
const liveTargetIds = new Set<number>();
|
|
2453
2453
|
|
|
@@ -2465,7 +2465,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2465
2465
|
: await this.verifyProtocolV2ReconnectIdentity();
|
|
2466
2466
|
shouldReconnect = false;
|
|
2467
2467
|
}
|
|
2468
|
-
|
|
2468
|
+
let currentDeviceInfo = deviceInfo;
|
|
2469
2469
|
try {
|
|
2470
2470
|
const statusResponse = await this.device.getCommands().typedCall(
|
|
2471
2471
|
'DeviceFirmwareUpdateStatusGet',
|
|
@@ -2479,7 +2479,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2479
2479
|
},
|
|
2480
2480
|
{ timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT }
|
|
2481
2481
|
);
|
|
2482
|
-
if (this.
|
|
2482
|
+
if (this.protocolV2InstallTerminalSuccessObserved) {
|
|
2483
2483
|
installEvidenceObserved = true;
|
|
2484
2484
|
}
|
|
2485
2485
|
const statusTargets = (statusResponse.message.records ??
|
|
@@ -2502,23 +2502,33 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2502
2502
|
const targetId = normalizeProtocolV2TargetId(target.target_id);
|
|
2503
2503
|
return targetId !== undefined && expectedTargetIds.has(targetId);
|
|
2504
2504
|
});
|
|
2505
|
+
const hasCurrentInstallEvidence =
|
|
2506
|
+
currentInstallStatusObserved || this.protocolV2InstallTerminalSuccessObserved;
|
|
2505
2507
|
const shouldVerifyTargetCompletion =
|
|
2506
|
-
!requireCurrentInstallStatus ||
|
|
2508
|
+
!requireCurrentInstallStatus || hasCurrentInstallEvidence;
|
|
2507
2509
|
if (
|
|
2508
2510
|
shouldVerifyTargetCompletion &&
|
|
2509
2511
|
this.assertProtocolV2TargetStatus(
|
|
2510
2512
|
statusTargets,
|
|
2511
2513
|
expectedTargetIds,
|
|
2512
2514
|
expectedPaths,
|
|
2513
|
-
requireCurrentInstallStatus
|
|
2515
|
+
requireCurrentInstallStatus && !this.protocolV2InstallTerminalSuccessObserved
|
|
2516
|
+
? liveTargetIds
|
|
2517
|
+
: undefined
|
|
2514
2518
|
)
|
|
2515
2519
|
) {
|
|
2516
2520
|
return;
|
|
2517
2521
|
}
|
|
2518
2522
|
|
|
2523
|
+
if (!hasCurrentInstallEvidence) {
|
|
2524
|
+
// A successful status poll clears DeviceCommands' cancel action. Keep cancellation
|
|
2525
|
+
// available while UpdateRequest is still waiting for confirmation on the device.
|
|
2526
|
+
this.device.setCancelableAction(() => this.device.getCommands().cancelDevice());
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2519
2529
|
if (
|
|
2520
2530
|
requireCurrentInstallStatus &&
|
|
2521
|
-
!
|
|
2531
|
+
!hasCurrentInstallEvidence &&
|
|
2522
2532
|
matchingStatusTargets.length > 0
|
|
2523
2533
|
) {
|
|
2524
2534
|
lastError = new Error(
|
|
@@ -2526,6 +2536,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2526
2536
|
);
|
|
2527
2537
|
}
|
|
2528
2538
|
|
|
2539
|
+
if (
|
|
2540
|
+
statusTargets.length === 0 &&
|
|
2541
|
+
!currentDeviceInfo &&
|
|
2542
|
+
bleInstallLinkReady &&
|
|
2543
|
+
installEvidenceObserved
|
|
2544
|
+
) {
|
|
2545
|
+
// BLE install reconnect skips generic probes because loaders may not answer Ping.
|
|
2546
|
+
// Restore the verified identity only after current-install evidence disappears.
|
|
2547
|
+
currentDeviceInfo = await this.verifyProtocolV2ReconnectIdentity();
|
|
2548
|
+
deviceInfo = currentDeviceInfo;
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2529
2551
|
if (statusTargets.length === 0 && currentDeviceInfo) {
|
|
2530
2552
|
const isNormalMode = await this.probeProtocolV2NormalMode(currentDeviceInfo);
|
|
2531
2553
|
if (
|
|
@@ -2960,11 +2982,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2960
2982
|
targets: Array<{ target_id: number; path: string }>;
|
|
2961
2983
|
}) {
|
|
2962
2984
|
this.protocolV2LastRuntimeProbeFeatures = undefined;
|
|
2963
|
-
this.
|
|
2964
|
-
this.
|
|
2985
|
+
this.protocolV2InstallNeedsReconnect = false;
|
|
2986
|
+
this.protocolV2InstallTerminalSuccessObserved = false;
|
|
2965
2987
|
const commands = this.device.getCommands();
|
|
2966
2988
|
await commands.typedCall('DeviceFirmwareUpdateStage', 'Success', { targets });
|
|
2967
|
-
this.device.setCancelableAction(() =>
|
|
2989
|
+
this.device.setCancelableAction(() => this.device.getCommands().cancelDevice());
|
|
2968
2990
|
const interaction = this.device.createProtocolV2UiPhaseMetadata('button', 'start');
|
|
2969
2991
|
this.postMessage(
|
|
2970
2992
|
createUiMessage(UI_REQUEST.REQUEST_BUTTON, {
|
|
@@ -2978,55 +3000,31 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2978
3000
|
})
|
|
2979
3001
|
);
|
|
2980
3002
|
|
|
2981
|
-
if (this.isBleReconnect()) {
|
|
2982
|
-
try {
|
|
2983
|
-
await commands.call(
|
|
2984
|
-
'DeviceFirmwareUpdateRequest',
|
|
2985
|
-
{},
|
|
2986
|
-
{
|
|
2987
|
-
returnAfterWrite: true,
|
|
2988
|
-
expectedTypes: ['Success'],
|
|
2989
|
-
onResponseAfterWrite: response => {
|
|
2990
|
-
if (response.type !== 'Success') return;
|
|
2991
|
-
this.protocolV2InstallRequestConfirmed = true;
|
|
2992
|
-
this.device.clearCancelableAction();
|
|
2993
|
-
this.postProgressMessage(1, 'installingFirmware');
|
|
2994
|
-
Log.log('[FirmwareUpdateV4] BLE firmware install confirmed by device response');
|
|
2995
|
-
},
|
|
2996
|
-
}
|
|
2997
|
-
);
|
|
2998
|
-
Log.log(
|
|
2999
|
-
'[FirmwareUpdateV4] BLE firmware install request written; continue with status polling'
|
|
3000
|
-
);
|
|
3001
|
-
} catch (error) {
|
|
3002
|
-
this.throwIfAborted();
|
|
3003
|
-
if (!isProtocolV2DeviceDisconnectedError(error)) {
|
|
3004
|
-
throw error;
|
|
3005
|
-
}
|
|
3006
|
-
Log.log(
|
|
3007
|
-
'[FirmwareUpdateV4] BLE transport released while writing install request; continue status polling'
|
|
3008
|
-
);
|
|
3009
|
-
this.protocolV2InstallNeedsBleReconnect = true;
|
|
3010
|
-
}
|
|
3011
|
-
return;
|
|
3012
|
-
}
|
|
3013
|
-
|
|
3014
3003
|
try {
|
|
3015
|
-
await commands.
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3004
|
+
await commands.call(
|
|
3005
|
+
'DeviceFirmwareUpdateRequest',
|
|
3006
|
+
{},
|
|
3007
|
+
{
|
|
3008
|
+
returnAfterWrite: true,
|
|
3009
|
+
expectedTypes: ['Success'],
|
|
3010
|
+
onResponseAfterWrite: response => {
|
|
3011
|
+
if (response.type !== 'Success') return;
|
|
3012
|
+
this.protocolV2InstallTerminalSuccessObserved = true;
|
|
3013
|
+
this.device.clearCancelableAction();
|
|
3014
|
+
Log.log('[FirmwareUpdateV4] firmware install completed by device response');
|
|
3015
|
+
},
|
|
3016
|
+
}
|
|
3017
|
+
);
|
|
3018
|
+
Log.log('[FirmwareUpdateV4] firmware install request written; continue with status polling');
|
|
3019
3019
|
} catch (error) {
|
|
3020
3020
|
this.throwIfAborted();
|
|
3021
3021
|
if (!isProtocolV2DeviceDisconnectedError(error)) {
|
|
3022
3022
|
throw error;
|
|
3023
3023
|
}
|
|
3024
3024
|
Log.log(
|
|
3025
|
-
'[FirmwareUpdateV4]
|
|
3025
|
+
'[FirmwareUpdateV4] transport released while writing install request; continue status polling'
|
|
3026
3026
|
);
|
|
3027
|
-
|
|
3028
|
-
this.protocolV2InstallNeedsBleReconnect = true;
|
|
3029
|
-
}
|
|
3027
|
+
this.protocolV2InstallNeedsReconnect = true;
|
|
3030
3028
|
}
|
|
3031
3029
|
}
|
|
3032
3030
|
|
package/src/core/index.ts
CHANGED
|
@@ -415,13 +415,6 @@ const onCallDevice = async (
|
|
|
415
415
|
if (method.payload?.onlyConnectBleDevice) {
|
|
416
416
|
preWarmCallbackTask?.resolve();
|
|
417
417
|
Log.debug('Call API - only connect ble device: ', device?.mainId);
|
|
418
|
-
// This early return bypasses the normal-path bookkeeping at the end of the
|
|
419
|
-
// call. Without it the task leaks and haunts every later queue snapshot
|
|
420
|
-
// and cancel sweep (field log: a completed task lingered for 6 minutes),
|
|
421
|
-
// and the request stays in the active maps, so repeated preconnects pile
|
|
422
|
-
// up phantom work in diagnostics.
|
|
423
|
-
completeMethodRequestContext(method);
|
|
424
|
-
requestQueue.releaseTask(method.responseID);
|
|
425
418
|
return createResponseMessage(method.responseID, true, null);
|
|
426
419
|
}
|
|
427
420
|
|
|
@@ -961,60 +954,7 @@ export function isMissingDetectedProtocolV2Error(method: BaseMethod, error: unkn
|
|
|
961
954
|
* If the Bluetooth connection times out, retry up to 6 times
|
|
962
955
|
* @param retryCount - Current retry count (default 0)
|
|
963
956
|
*/
|
|
964
|
-
|
|
965
|
-
// transport that never settles (field case: Electron main lost an IPC reply,
|
|
966
|
-
// "reply was never sent" after 5 minutes) hangs the call forever and cancel()
|
|
967
|
-
// only takes effect at poll checkpoints. Race acquire against a deadline and
|
|
968
|
-
// the caller's abort signal so the hang is bounded and cancel is immediate.
|
|
969
|
-
const BLE_ACQUIRE_DEADLINE_MS = 60 * 1000;
|
|
970
|
-
|
|
971
|
-
function raceBleAcquire<T>(acquirePromise: Promise<T>, abortSignal?: AbortSignal): Promise<T> {
|
|
972
|
-
return new Promise<T>((resolve, reject) => {
|
|
973
|
-
let settled = false;
|
|
974
|
-
const settle = (fn: () => void) => {
|
|
975
|
-
if (settled) return;
|
|
976
|
-
settled = true;
|
|
977
|
-
clearTimeout(deadline);
|
|
978
|
-
abortSignal?.removeEventListener('abort', onAbort);
|
|
979
|
-
fn();
|
|
980
|
-
};
|
|
981
|
-
const onAbort = () =>
|
|
982
|
-
settle(() => reject(ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled)));
|
|
983
|
-
const deadline = setTimeout(
|
|
984
|
-
() =>
|
|
985
|
-
settle(() =>
|
|
986
|
-
reject(
|
|
987
|
-
ERRORS.TypedError(
|
|
988
|
-
HardwareErrorCode.BleTimeoutError,
|
|
989
|
-
`BLE acquire exceeded ${BLE_ACQUIRE_DEADLINE_MS}ms deadline`
|
|
990
|
-
)
|
|
991
|
-
)
|
|
992
|
-
),
|
|
993
|
-
BLE_ACQUIRE_DEADLINE_MS
|
|
994
|
-
);
|
|
995
|
-
// Attach before any early return so a late settlement of acquirePromise
|
|
996
|
-
// is always consumed — an abort or deadline must never leave the acquire
|
|
997
|
-
// rejection unhandled.
|
|
998
|
-
acquirePromise.then(
|
|
999
|
-
value => settle(() => resolve(value)),
|
|
1000
|
-
error => settle(() => reject(error))
|
|
1001
|
-
);
|
|
1002
|
-
if (abortSignal) {
|
|
1003
|
-
if (abortSignal.aborted) {
|
|
1004
|
-
onAbort();
|
|
1005
|
-
return;
|
|
1006
|
-
}
|
|
1007
|
-
abortSignal.addEventListener('abort', onAbort);
|
|
1008
|
-
}
|
|
1009
|
-
});
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
async function connectDeviceForBle(
|
|
1013
|
-
method: BaseMethod,
|
|
1014
|
-
device: Device,
|
|
1015
|
-
abortSignal?: AbortSignal,
|
|
1016
|
-
retryCount = 0
|
|
1017
|
-
) {
|
|
957
|
+
async function connectDeviceForBle(method: BaseMethod, device: Device, retryCount = 0) {
|
|
1018
958
|
try {
|
|
1019
959
|
if (device.wasInterruptedByUser()) {
|
|
1020
960
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceInterruptedFromUser);
|
|
@@ -1028,43 +968,9 @@ async function connectDeviceForBle(
|
|
|
1028
968
|
!device.commands ||
|
|
1029
969
|
device.commands.disposed;
|
|
1030
970
|
if (shouldAcquire) {
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
// legitimately block on a user-driven system bonding prompt for longer
|
|
1035
|
-
// than any sane deadline. Other envs keep the plain acquire unchanged.
|
|
1036
|
-
const useAcquireGuards = DataManager.getSettings('env') === 'desktop-web-ble';
|
|
1037
|
-
// A cancel landing during the retry backoff must not start a new acquire.
|
|
1038
|
-
if (useAcquireGuards && abortSignal?.aborted) {
|
|
1039
|
-
throw ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled);
|
|
1040
|
-
}
|
|
1041
|
-
if (!useAcquireGuards) {
|
|
1042
|
-
await device.acquire(method.payload.connectProtocol, {
|
|
1043
|
-
forceProtocolDetection: method.payload.forceProtocolDetection,
|
|
1044
|
-
});
|
|
1045
|
-
} else {
|
|
1046
|
-
try {
|
|
1047
|
-
await raceBleAcquire(
|
|
1048
|
-
device.acquire(method.payload.connectProtocol, {
|
|
1049
|
-
forceProtocolDetection: method.payload.forceProtocolDetection,
|
|
1050
|
-
}),
|
|
1051
|
-
abortSignal
|
|
1052
|
-
);
|
|
1053
|
-
} catch (err) {
|
|
1054
|
-
// A deadline hit means the transport is wedged mid-acquire; drop the
|
|
1055
|
-
// link before the retry so it cold-connects instead of stacking a
|
|
1056
|
-
// second connect onto the half-open one.
|
|
1057
|
-
if (
|
|
1058
|
-
err.errorCode === HardwareErrorCode.BleTimeoutError &&
|
|
1059
|
-
device.mainId &&
|
|
1060
|
-
device.deviceConnector
|
|
1061
|
-
) {
|
|
1062
|
-
await device.deviceConnector.disconnect(device.mainId).catch(() => undefined);
|
|
1063
|
-
device.markTransportDisconnected();
|
|
1064
|
-
}
|
|
1065
|
-
throw err;
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
971
|
+
await device.acquire(method.payload.connectProtocol, {
|
|
972
|
+
forceProtocolDetection: method.payload.forceProtocolDetection,
|
|
973
|
+
});
|
|
1068
974
|
}
|
|
1069
975
|
if (method.payload?.onlyConnectBleDevice) {
|
|
1070
976
|
if (shouldAcquire) {
|
|
@@ -1104,7 +1010,7 @@ async function connectDeviceForBle(
|
|
|
1104
1010
|
const nextRetry = retryCount + 1;
|
|
1105
1011
|
Log.debug(`Bluetooth connection will retry, retry count: ${nextRetry}`);
|
|
1106
1012
|
await wait(3000);
|
|
1107
|
-
await connectDeviceForBle(method, device,
|
|
1013
|
+
await connectDeviceForBle(method, device, nextRetry);
|
|
1108
1014
|
} else {
|
|
1109
1015
|
throw err;
|
|
1110
1016
|
}
|
|
@@ -1214,7 +1120,7 @@ const ensureConnected = async (
|
|
|
1214
1120
|
if (tryCount === 1) {
|
|
1215
1121
|
device.beginConnectionAttempt();
|
|
1216
1122
|
}
|
|
1217
|
-
await connectDeviceForBle(method, device
|
|
1123
|
+
await connectDeviceForBle(method, device);
|
|
1218
1124
|
}
|
|
1219
1125
|
resolve(device);
|
|
1220
1126
|
return;
|