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/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.0",
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
  }
Binary file
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
- `SLIP read error at ${resp.length} bytes: ${err.message}`,
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
- `${err.message} at 0x${currentAddr.toString(16)}. Draining buffer and retrying (attempt ${retryCount}/${MAX_RETRIES})...`,
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
@@ -1,5 +1,5 @@
1
1
  // Service Worker for ESP32Tool PWA
2
- const CACHE_NAME = 'esp32tool-v1.6.0';
2
+ const CACHE_NAME = 'esp32tool-v1.6.1';
3
3
  const RUNTIME_CACHE = 'esp32tool-runtime';
4
4
 
5
5
  // Core files to cache on install (relative paths work for any deployment path)