esp32tool 1.6.0 → 1.6.1
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/README.md +1 -1
- package/apple-touch-icon.png +0 -0
- package/dist/esp_loader.js +3 -13
- package/dist/web/index.js +1 -1
- package/icons/icon-128.png +0 -0
- package/icons/icon-144.png +0 -0
- package/icons/icon-152.png +0 -0
- package/icons/icon-192.png +0 -0
- package/icons/icon-384.png +0 -0
- package/icons/icon-512.png +0 -0
- package/icons/icon-72.png +0 -0
- package/icons/icon-96.png +0 -0
- package/js/modules/esptool.js +1 -1
- package/js/nvs-editor.js +1 -78
- package/package.json +5 -2
- package/screenshots/desktop.png +0 -0
- package/screenshots/mobile.png +0 -0
- package/src/esp_loader.ts +3 -16
- package/sw.js +1 -1
package/js/nvs-editor.js
CHANGED
|
@@ -387,83 +387,6 @@ export class NVSEditor {
|
|
|
387
387
|
this.modified = true;
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
-
static _parseIntStrict(s, label, min, max) {
|
|
391
|
-
const n = Number(s);
|
|
392
|
-
if (!Number.isFinite(n) || !Number.isInteger(n) || n < min || n > max)
|
|
393
|
-
throw new Error(`${label} must be an integer in [${min}, ${max}], got: ${s}`);
|
|
394
|
-
return n;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/** Write a primitive value back to an existing entry at item.offset */
|
|
398
|
-
_writeValue(item, newValue) {
|
|
399
|
-
const off = item.offset;
|
|
400
|
-
switch (item.datatype) {
|
|
401
|
-
case 0x01: { const v = NVSEditor._parseIntStrict(newValue, 'U8', 0, 255); this.data[off + 24] = v; break; }
|
|
402
|
-
case 0x02: { const v = parseInt(newValue, 10); if (!Number.isFinite(v) || v < 0 || v > 65535) throw new Error('U16 must be 0-65535'); this.data[off + 24] = v & 0xFF; this.data[off + 25] = (v >> 8) & 0xFF; break; }
|
|
403
|
-
case 0x04: { const v = parseInt(newValue, 10); if (!Number.isFinite(v) || v < 0 || v > 4294967295) throw new Error('U32 must be 0-4294967295'); const dv = new DataView(this.data.buffer, off + 24, 4); dv.setUint32(0, v >>> 0, true); break; }
|
|
404
|
-
case 0x08: { let v; try { v = BigInt(newValue); } catch(e) { throw new Error('U64 must be valid BigInt'); } if (v < 0n || v > 0xFFFFFFFFFFFFFFFFn) throw new Error('U64 out of range'); const dv = new DataView(this.data.buffer, off + 24, 8); dv.setBigUint64(0, v, true); break; }
|
|
405
|
-
case 0x11: { const v = parseInt(newValue, 10); if (!Number.isFinite(v) || v < -128 || v > 127) throw new Error('I8 must be -128 to 127'); this.data[off + 24] = v < 0 ? v + 256 : v; break; }
|
|
406
|
-
case 0x12: { const v = parseInt(newValue, 10); if (!Number.isFinite(v) || v < -32768 || v > 32767) throw new Error('I16 must be -32768 to 32767'); const dv = new DataView(this.data.buffer, off + 24, 2); dv.setInt16(0, v, true); break; }
|
|
407
|
-
case 0x14: { const v = parseInt(newValue, 10); if (!Number.isFinite(v) || v < -2147483648 || v > 2147483647) throw new Error('I32 must be -2147483648 to 2147483647'); const dv = new DataView(this.data.buffer, off + 24, 4); dv.setInt32(0, v, true); break; }
|
|
408
|
-
case 0x18: { let v; try { v = BigInt(newValue); } catch(e) { throw new Error('I64 must be valid BigInt'); } if (v < -0x8000000000000000n || v > 0x7FFFFFFFFFFFFFFFn) throw new Error('I64 out of range'); const dv = new DataView(this.data.buffer, off + 24, 8); dv.setBigInt64(0, v, true); break; }
|
|
409
|
-
case 0x21: { // String – rewrite in-place with trailing NUL
|
|
410
|
-
const enc = new TextEncoder().encode(newValue);
|
|
411
|
-
const maxPayload = (item.span - 1) * 32;
|
|
412
|
-
// Create NUL-terminated buffer
|
|
413
|
-
const encWithNul = new Uint8Array(enc.length + 1);
|
|
414
|
-
encWithNul.set(enc, 0);
|
|
415
|
-
encWithNul[enc.length] = 0;
|
|
416
|
-
if (encWithNul.length > maxPayload) { alert('String too long for existing slot (max ' + maxPayload + ' bytes)'); return; }
|
|
417
|
-
// Update size (includes NUL)
|
|
418
|
-
this.data[off + 24] = encWithNul.length & 0xFF;
|
|
419
|
-
this.data[off + 25] = (encWithNul.length >> 8) & 0xFF;
|
|
420
|
-
// Clear old data
|
|
421
|
-
this.data.fill(0xFF, off + 32, off + 32 + maxPayload);
|
|
422
|
-
// Write new data with NUL
|
|
423
|
-
this.data.set(encWithNul, off + 32);
|
|
424
|
-
// Update data CRC over NUL-terminated buffer
|
|
425
|
-
const crc = NVSEditor.crc32(encWithNul);
|
|
426
|
-
const dv = new DataView(this.data.buffer, off + 28, 4);
|
|
427
|
-
dv.setUint32(0, crc, true);
|
|
428
|
-
break;
|
|
429
|
-
}
|
|
430
|
-
case 0x42: { // Blob – rewrite hex bytes in-place
|
|
431
|
-
const hexBytes = newValue.split(/[\s,]+/).filter(b => b).map(b => parseInt(b, 16));
|
|
432
|
-
if (hexBytes.some(b => isNaN(b) || b < 0 || b > 255)) { alert('Invalid hex bytes'); return; }
|
|
433
|
-
const blobData = new Uint8Array(hexBytes);
|
|
434
|
-
const maxPayload = (item.span - 1) * 32;
|
|
435
|
-
if (blobData.length > maxPayload) { alert('Blob too long for existing slot (max ' + maxPayload + ' bytes)'); return; }
|
|
436
|
-
// Update size
|
|
437
|
-
this.data[off + 24] = blobData.length & 0xFF;
|
|
438
|
-
this.data[off + 25] = (blobData.length >> 8) & 0xFF;
|
|
439
|
-
// Clear old data
|
|
440
|
-
this.data.fill(0xFF, off + 32, off + 32 + maxPayload);
|
|
441
|
-
// Write new data
|
|
442
|
-
this.data.set(blobData, off + 32);
|
|
443
|
-
// Update data CRC
|
|
444
|
-
const crc = NVSEditor.crc32(blobData);
|
|
445
|
-
const dv = new DataView(this.data.buffer, off + 28, 4);
|
|
446
|
-
dv.setUint32(0, crc, true);
|
|
447
|
-
break;
|
|
448
|
-
}
|
|
449
|
-
case 0x48: { // Blob Index – edit totalSize
|
|
450
|
-
const v = parseInt(newValue, 10);
|
|
451
|
-
if (!Number.isFinite(v) || v < 0 || v > 0xFFFFFFFF) { alert('Invalid total size (must be 0-4294967295)'); return; }
|
|
452
|
-
const dv = new DataView(this.data.buffer, off + 24, 4);
|
|
453
|
-
dv.setUint32(0, v, true);
|
|
454
|
-
break;
|
|
455
|
-
}
|
|
456
|
-
default:
|
|
457
|
-
alert('Editing this type is not supported');
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
// Recalculate header CRC
|
|
461
|
-
const hcrc = NVSEditor.crc32Header(this.data, off);
|
|
462
|
-
const dv = new DataView(this.data.buffer, off + 4, 4);
|
|
463
|
-
dv.setUint32(0, hcrc, true);
|
|
464
|
-
this.modified = true;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
390
|
// ─────── UI ───────
|
|
468
391
|
|
|
469
392
|
_buildUI() {
|
|
@@ -614,7 +537,7 @@ export class NVSEditor {
|
|
|
614
537
|
<span class="nvs-page-state">${page.state}</span>
|
|
615
538
|
<span>Page @ 0x${page.offset.toString(16).toUpperCase()}</span>
|
|
616
539
|
<span>Seq: ${page.seq}</span>
|
|
617
|
-
<span>Version: ${page.version}</span>
|
|
540
|
+
<span>Version: ${page.version === 0xFF ? 'v1' : page.version === 0xFE ? 'v2' : page.version}</span>
|
|
618
541
|
<span>${page.items.length} entries</span>
|
|
619
542
|
</div>`;
|
|
620
543
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "esp32tool",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Flash & Read ESP devices using WebSerial, Electron, and also Android mobile via WebUSB",
|
|
6
6
|
"main": "electron/main.cjs",
|
|
@@ -78,6 +78,9 @@
|
|
|
78
78
|
},
|
|
79
79
|
"overrides": {
|
|
80
80
|
"tmp": "^0.2.4",
|
|
81
|
-
"tar": "^7.5.6"
|
|
81
|
+
"tar": "^7.5.6",
|
|
82
|
+
"ajv": "^8.18.0",
|
|
83
|
+
"minimatch": "^10.2.1",
|
|
84
|
+
"@electron/asar": "^4.0.1"
|
|
82
85
|
}
|
|
83
86
|
}
|
package/screenshots/desktop.png
CHANGED
|
Binary file
|
package/screenshots/mobile.png
CHANGED
|
Binary file
|
package/src/esp_loader.ts
CHANGED
|
@@ -4468,7 +4468,7 @@ export class ESPLoader extends EventTarget {
|
|
|
4468
4468
|
} catch (err) {
|
|
4469
4469
|
if (err instanceof SlipReadError) {
|
|
4470
4470
|
this.logger.debug(
|
|
4471
|
-
|
|
4471
|
+
`${err.message} at byte 0x${resp.length.toString(16)}`,
|
|
4472
4472
|
);
|
|
4473
4473
|
|
|
4474
4474
|
// Send empty SLIP frame to abort the stub's read operation
|
|
@@ -4622,22 +4622,9 @@ export class ESPLoader extends EventTarget {
|
|
|
4622
4622
|
if (err instanceof SlipReadError) {
|
|
4623
4623
|
if (retryCount <= MAX_RETRIES) {
|
|
4624
4624
|
this.logger.debug(
|
|
4625
|
-
|
|
4625
|
+
`Cleared buffer and retrying (attempt ${retryCount}/${MAX_RETRIES})...`,
|
|
4626
4626
|
);
|
|
4627
|
-
|
|
4628
|
-
try {
|
|
4629
|
-
await this.drainInputBuffer(200);
|
|
4630
|
-
|
|
4631
|
-
// Clear application buffer
|
|
4632
|
-
await this.flushSerialBuffers();
|
|
4633
|
-
|
|
4634
|
-
// Wait before retry to let hardware settle
|
|
4635
|
-
await sleep(SYNC_TIMEOUT);
|
|
4636
|
-
|
|
4637
|
-
// Continue to retry the same chunk (will send NEW read command)
|
|
4638
|
-
} catch (drainErr) {
|
|
4639
|
-
this.logger.debug(`Buffer drain error: ${drainErr}`);
|
|
4640
|
-
}
|
|
4627
|
+
// Continue to retry the same chunk (will send NEW read command)
|
|
4641
4628
|
} else {
|
|
4642
4629
|
// All retries exhausted - attempt recovery by reloading stub
|
|
4643
4630
|
// IMPORTANT: Do NOT close port to keep ESP32 in bootloader mode
|
package/sw.js
CHANGED