@esp-vision/device-core 0.4.1 → 0.4.2
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.2 (unreleased)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Route browser ROM reset calls through the active flash stub after upload, preserving its two-byte status decoder during P4 watchdog register writes; report reset failure diagnostics without invalidating successful firmware verification.
|
|
8
|
+
|
|
3
9
|
## 0.4.1 (unreleased)
|
|
4
10
|
|
|
5
11
|
### Fixed
|
package/package.json
CHANGED
|
@@ -15,6 +15,13 @@ export function browserRomCompatibility(loader) {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
// runStub returns a separate loader. Its command replies use two status bytes;
|
|
19
|
+
// the ROM loader still expects four and cannot issue reset register writes.
|
|
20
|
+
let activeStub
|
|
21
|
+
const hardReset = loader.hardReset
|
|
22
|
+
loader.hardReset = function (...args) {
|
|
23
|
+
return activeStub ? activeStub.hardReset(...args) : hardReset.apply(this, args)
|
|
24
|
+
}
|
|
18
25
|
const runStub = loader.runStub
|
|
19
26
|
loader.runStub = async function (skipFlashDetection = false) {
|
|
20
27
|
const memFinish = this.memFinish, packet = this.readPacket
|
|
@@ -34,6 +41,7 @@ export function browserRomCompatibility(loader) {
|
|
|
34
41
|
const stub = await runStub.call(this, skipFlashDetection)
|
|
35
42
|
if (!stub.IS_STUB) throw new Error('This device has no supported browser flash stub')
|
|
36
43
|
browserStubCompatibility(stub)
|
|
44
|
+
activeStub = stub
|
|
37
45
|
return stub
|
|
38
46
|
} finally { this.memFinish = memFinish; this.readPacket = packet }
|
|
39
47
|
}
|
package/src/firmware_flash.js
CHANGED
|
@@ -112,7 +112,10 @@ export class FirmwareFlashSession {
|
|
|
112
112
|
}
|
|
113
113
|
await this.reset()
|
|
114
114
|
}
|
|
115
|
-
catch
|
|
115
|
+
catch (error) {
|
|
116
|
+
onPhase('Firmware verified. Automatic reset did not complete; wait for runtime reconnection or press RESET.')
|
|
117
|
+
return { verified: true, needsReset: true, resetError: { code: error?.code ?? 'RESET_FAILED', message: error?.message ?? String(error) } }
|
|
118
|
+
}
|
|
116
119
|
onPhase('Firmware verified and reset. Reconnect in the IDE to verify EV-MUX v4.')
|
|
117
120
|
return { verified: true, needsReset: false }
|
|
118
121
|
} catch (error) { this.state = 'error'; throw error }
|
package/tests/check-browser.mjs
CHANGED
|
@@ -23,7 +23,7 @@ try {
|
|
|
23
23
|
assert.ok(Object.keys(result.metafile.inputs).some(path => path.includes('stubs/esp32p4.json')))
|
|
24
24
|
assert.ok(Object.keys(result.metafile.inputs).some(path => path.includes('stubs/esp32s31.json')))
|
|
25
25
|
assert.ok(!Object.keys(result.metafile.inputs).some(path => /src\/(node|cli)/.test(path)))
|
|
26
|
-
const context = vm.createContext({ EventTarget, URL, TextDecoder, TextEncoder, Uint8Array, AbortController, setTimeout, clearTimeout, console, crypto: webcrypto, structuredClone })
|
|
26
|
+
const context = vm.createContext({ atob, btoa, EventTarget, URL, TextDecoder, TextEncoder, Uint8Array, AbortController, setTimeout, clearTimeout, console, crypto: webcrypto, structuredClone })
|
|
27
27
|
vm.runInContext(code, context)
|
|
28
28
|
let opens = 0, closes = 0
|
|
29
29
|
const adapter = context.DeviceCore.openBrowserRom({ port: {
|
|
@@ -46,6 +46,29 @@ try {
|
|
|
46
46
|
raw._inputBuffer.push(0xc0, 0xdb, 0x47, 0xc0)
|
|
47
47
|
await assert.rejects(raw.readPacket(100), /Invalid SLIP escape/)
|
|
48
48
|
}
|
|
49
|
+
// Exercise real upstream stub status decoding. A ROM reset consumes four
|
|
50
|
+
// status bytes while the running stub replies with two; route reset to it.
|
|
51
|
+
{
|
|
52
|
+
const raw = new context.DeviceCore.TestLoader({ getInfo: () => ({ usbVendorId: 0x303a, usbProductId: 0x1001 }) }, { log() {}, error() {}, debug() {} })
|
|
53
|
+
raw.chipFamily = 0x3280; raw.chipRevision = 302
|
|
54
|
+
raw.memBegin = raw.memBlock = raw.memFinish = async () => {}
|
|
55
|
+
raw.readPacket = async () => new Uint8Array([79, 72, 65, 73])
|
|
56
|
+
context.DeviceCore.testCompatibility(raw)
|
|
57
|
+
const stub = await raw.runStub(true)
|
|
58
|
+
let writes = 0
|
|
59
|
+
stub.detectUsbConnectionType = async () => true
|
|
60
|
+
stub.getUsbMode = async () => ({ mode: 'usb-jtag-serial' })
|
|
61
|
+
stub.sendCommand = async () => { writes++ }
|
|
62
|
+
stub.getResponse = async () => [0, new Uint8Array([0, 0])]
|
|
63
|
+
// Confirm the original ROM instance rejects the exact same stub response.
|
|
64
|
+
raw.detectUsbConnectionType = stub.detectUsbConnectionType
|
|
65
|
+
raw.getUsbMode = stub.getUsbMode
|
|
66
|
+
raw.sendCommand = async () => {}
|
|
67
|
+
raw.getResponse = stub.getResponse
|
|
68
|
+
await assert.rejects(context.DeviceCore.TestLoader.prototype.hardReset.call(raw), /status|response|enough/i)
|
|
69
|
+
await raw.hardReset()
|
|
70
|
+
assert.equal(writes, 4, 'P4 watchdog writes must use the running stub status decoder')
|
|
71
|
+
}
|
|
49
72
|
const prototype = context.DeviceCore.TestLoader.prototype
|
|
50
73
|
const originals = Object.fromEntries(['initialize', 'disconnect', 'getSecurityInfo', 'runStub', 'hardReset'].map(key => [key, prototype[key]]))
|
|
51
74
|
let initializeCalls = 0, disconnectCalls = 0
|
|
@@ -115,6 +138,7 @@ try {
|
|
|
115
138
|
async flashData() { writes++; writing.abort() },
|
|
116
139
|
async readFlash(offset) { return offset === 32768 ? table : data },
|
|
117
140
|
async readRegister() { return 0 },
|
|
141
|
+
async hardReset() { resets++ },
|
|
118
142
|
}
|
|
119
143
|
}
|
|
120
144
|
prototype.hardReset = async () => { resets++ }
|
|
@@ -80,7 +80,10 @@ test('failed readback never reports verified or resets the device', async () =>
|
|
|
80
80
|
})
|
|
81
81
|
test('reset failure returns verified with explicit manual reset requirement', async () => {
|
|
82
82
|
const f = await fixture(); f.loader.hardReset = async () => { throw new Error('reset unavailable') }
|
|
83
|
-
|
|
83
|
+
const result = await f.device.firmware.update(f.request)
|
|
84
|
+
assert.equal(result.needsReset, true)
|
|
85
|
+
assert.equal(result.verified, true)
|
|
86
|
+
assert.deepEqual(result.resetError, { code: 'RESET_FAILED', message: 'reset unavailable' })
|
|
84
87
|
})
|
|
85
88
|
|
|
86
89
|
test('firmware check lists all board versions and selects an explicit older version', async () => {
|