tasmota-webserial-esptool 7.0.1 → 7.2.0
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/css/style.css +95 -0
- package/dist/const.js +1 -25
- package/dist/esp_loader.d.ts +4 -2
- package/dist/esp_loader.js +164 -176
- package/dist/struct.js +9 -23
- package/dist/util.js +4 -4
- package/dist/web/index.js +1 -1
- package/eslint.config.js +22 -0
- package/index.html +12 -1
- package/js/modules/esptool.js +1 -1
- package/js/script.js +65 -2
- package/package.json +14 -5
- package/src/const.ts +3 -25
- package/src/esp_loader.ts +184 -204
- package/src/struct.ts +18 -25
- package/src/util.ts +4 -4
- package/.devcontainer/devcontainer.json +0 -22
- package/.github/dependabot.yml +0 -10
- package/.github/workflows/build_upload.yml +0 -75
- package/.github/workflows/ci.yml +0 -30
- package/.prettierignore +0 -1
- package/CHANGELOG_CHIP_VARIANT.md +0 -169
- package/CHIP_VARIANT_SUPPORT.md +0 -184
- package/READ_FLASH_FEATURE.md +0 -130
- package/rollup.config.js +0 -27
- package/tsconfig.json +0 -20
package/src/esp_loader.ts
CHANGED
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
} from "./const";
|
|
63
63
|
import { getStubCode } from "./stubs";
|
|
64
64
|
import { hexFormatter, sleep, slipEncode, toHex } from "./util";
|
|
65
|
-
// @ts-
|
|
65
|
+
// @ts-expect-error pako ESM module doesn't have proper type definitions
|
|
66
66
|
import { deflate } from "pako/dist/pako.esm.mjs";
|
|
67
67
|
import { pack, unpack } from "./struct";
|
|
68
68
|
|
|
@@ -83,6 +83,8 @@ export class ESPLoader extends EventTarget {
|
|
|
83
83
|
private _currentBaudRate: number = ESP_ROM_BAUD;
|
|
84
84
|
private _maxUSBSerialBaudrate?: number;
|
|
85
85
|
private _reader?: ReadableStreamDefaultReader<Uint8Array>;
|
|
86
|
+
private _isESP32S2NativeUSB: boolean = false;
|
|
87
|
+
private _initializationSucceeded: boolean = false;
|
|
86
88
|
|
|
87
89
|
constructor(
|
|
88
90
|
public port: SerialPort,
|
|
@@ -121,8 +123,13 @@ export class ESPLoader extends EventTarget {
|
|
|
121
123
|
> = {
|
|
122
124
|
0x1a86: {
|
|
123
125
|
// QinHeng Electronics
|
|
126
|
+
0x7522: { name: "CH340", maxBaudrate: 460800 },
|
|
124
127
|
0x7523: { name: "CH340", maxBaudrate: 460800 },
|
|
128
|
+
0x7584: { name: "CH340", maxBaudrate: 460800 },
|
|
129
|
+
0x5523: { name: "CH341", maxBaudrate: 2000000 },
|
|
130
|
+
0x55d3: { name: "CH343", maxBaudrate: 6000000 },
|
|
125
131
|
0x55d4: { name: "CH9102", maxBaudrate: 6000000 },
|
|
132
|
+
0x55d8: { name: "CH9101", maxBaudrate: 3000000 },
|
|
126
133
|
},
|
|
127
134
|
0x10c4: {
|
|
128
135
|
// Silicon Labs
|
|
@@ -179,6 +186,10 @@ export class ESPLoader extends EventTarget {
|
|
|
179
186
|
this._maxUSBSerialBaudrate = chipInfo.maxBaudrate;
|
|
180
187
|
this.logger.log(`Max baudrate: ${chipInfo.maxBaudrate}`);
|
|
181
188
|
}
|
|
189
|
+
// Detect ESP32-S2 Native USB
|
|
190
|
+
if (portInfo.usbVendorId === 0x303a && portInfo.usbProductId === 0x2) {
|
|
191
|
+
this._isESP32S2NativeUSB = true;
|
|
192
|
+
}
|
|
182
193
|
}
|
|
183
194
|
|
|
184
195
|
// Don't await this promise so it doesn't block rest of method.
|
|
@@ -193,8 +204,8 @@ export class ESPLoader extends EventTarget {
|
|
|
193
204
|
await this.detectChip();
|
|
194
205
|
|
|
195
206
|
// Read the OTP data for this chip and store into this.efuses array
|
|
196
|
-
|
|
197
|
-
|
|
207
|
+
const FlAddr = getSpiFlashAddresses(this.getChipFamily());
|
|
208
|
+
const AddrMAC = FlAddr.macFuse;
|
|
198
209
|
for (let i = 0; i < 4; i++) {
|
|
199
210
|
this._efuses[i] = await this.readRegister(AddrMAC + 4 * i);
|
|
200
211
|
}
|
|
@@ -202,6 +213,9 @@ export class ESPLoader extends EventTarget {
|
|
|
202
213
|
this.logger.debug(
|
|
203
214
|
`Bootloader flash offset: 0x${FlAddr.flashOffs.toString(16)}`,
|
|
204
215
|
);
|
|
216
|
+
|
|
217
|
+
// Mark initialization as successful
|
|
218
|
+
this._initializationSucceeded = true;
|
|
205
219
|
}
|
|
206
220
|
|
|
207
221
|
/**
|
|
@@ -241,10 +255,10 @@ export class ESPLoader extends EventTarget {
|
|
|
241
255
|
this.logger.debug(
|
|
242
256
|
`Unknown IMAGE_CHIP_ID: ${chipId}, falling back to magic value detection`,
|
|
243
257
|
);
|
|
244
|
-
} catch (
|
|
258
|
+
} catch (error) {
|
|
245
259
|
// GET_SECURITY_INFO not supported, fall back to magic value detection
|
|
246
260
|
this.logger.debug(
|
|
247
|
-
`GET_SECURITY_INFO failed, using magic value detection: ${
|
|
261
|
+
`GET_SECURITY_INFO failed, using magic value detection: ${error}`,
|
|
248
262
|
);
|
|
249
263
|
|
|
250
264
|
// Clear input buffer and re-sync to recover from failed command
|
|
@@ -261,9 +275,9 @@ export class ESPLoader extends EventTarget {
|
|
|
261
275
|
}
|
|
262
276
|
}
|
|
263
277
|
|
|
264
|
-
// Fallback: Use magic value detection for ESP8266, ESP32, ESP32-S2
|
|
265
|
-
|
|
266
|
-
|
|
278
|
+
// Fallback: Use magic value detection for ESP8266, ESP32, ESP32-S2
|
|
279
|
+
const chipMagicValue = await this.readRegister(CHIP_DETECT_MAGIC_REG_ADDR);
|
|
280
|
+
const chip = CHIP_DETECT_MAGIC_VALUES[chipMagicValue >>> 0];
|
|
267
281
|
if (chip === undefined) {
|
|
268
282
|
throw new Error(
|
|
269
283
|
`Unknown Chip: Hex: ${toHex(
|
|
@@ -275,7 +289,6 @@ export class ESPLoader extends EventTarget {
|
|
|
275
289
|
this.chipName = chip.name;
|
|
276
290
|
this.chipFamily = chip.family;
|
|
277
291
|
|
|
278
|
-
// For ESP32-P4 detected via magic value (old revisions), set variant
|
|
279
292
|
if (this.chipFamily === CHIP_FAMILY_ESP32P4) {
|
|
280
293
|
this.chipRevision = await this.getChipRevision();
|
|
281
294
|
this.logger.debug(`ESP32-P4 revision: ${this.chipRevision}`);
|
|
@@ -325,7 +338,7 @@ export class ESPLoader extends EventTarget {
|
|
|
325
338
|
chipId: number;
|
|
326
339
|
apiVersion: number;
|
|
327
340
|
}> {
|
|
328
|
-
const [
|
|
341
|
+
const [, responseData] = await this.checkCommand(
|
|
329
342
|
ESP_GET_SECURITY_INFO,
|
|
330
343
|
[],
|
|
331
344
|
0,
|
|
@@ -377,10 +390,12 @@ export class ESPLoader extends EventTarget {
|
|
|
377
390
|
this._reader = this.port.readable!.getReader();
|
|
378
391
|
|
|
379
392
|
try {
|
|
380
|
-
|
|
393
|
+
let keepReading = true;
|
|
394
|
+
while (keepReading) {
|
|
381
395
|
const { value, done } = await this._reader.read();
|
|
382
396
|
if (done) {
|
|
383
397
|
this._reader.releaseLock();
|
|
398
|
+
keepReading = false;
|
|
384
399
|
break;
|
|
385
400
|
}
|
|
386
401
|
if (!value || value.length === 0) {
|
|
@@ -395,11 +410,25 @@ export class ESPLoader extends EventTarget {
|
|
|
395
410
|
// Track total bytes read from serial port
|
|
396
411
|
this._totalBytesRead += value.length;
|
|
397
412
|
}
|
|
398
|
-
} catch
|
|
399
|
-
|
|
413
|
+
} catch {
|
|
414
|
+
this.logger.error("Read loop got disconnected");
|
|
400
415
|
}
|
|
401
416
|
// Disconnected!
|
|
402
417
|
this.connected = false;
|
|
418
|
+
|
|
419
|
+
// Check if this is ESP32-S2 Native USB that needs port reselection
|
|
420
|
+
// Only trigger reconnect if initialization did NOT succeed (wrong port)
|
|
421
|
+
if (this._isESP32S2NativeUSB && !this._initializationSucceeded) {
|
|
422
|
+
this.logger.log(
|
|
423
|
+
"ESP32-S2 Native USB detected - requesting port reselection",
|
|
424
|
+
);
|
|
425
|
+
this.dispatchEvent(
|
|
426
|
+
new CustomEvent("esp32s2-usb-reconnect", {
|
|
427
|
+
detail: { message: "ESP32-S2 Native USB requires port reselection" },
|
|
428
|
+
}),
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
|
|
403
432
|
this.dispatchEvent(new Event("disconnect"));
|
|
404
433
|
this.logger.debug("Finished read loop");
|
|
405
434
|
}
|
|
@@ -474,11 +503,11 @@ export class ESPLoader extends EventTarget {
|
|
|
474
503
|
* The MAC address burned into the OTP memory of the ESP chip
|
|
475
504
|
*/
|
|
476
505
|
macAddr() {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
506
|
+
const macAddr = new Array(6).fill(0);
|
|
507
|
+
const mac0 = this._efuses[0];
|
|
508
|
+
const mac1 = this._efuses[1];
|
|
509
|
+
const mac2 = this._efuses[2];
|
|
510
|
+
const mac3 = this._efuses[3];
|
|
482
511
|
let oui;
|
|
483
512
|
if (this.chipFamily == CHIP_FAMILY_ESP8266) {
|
|
484
513
|
if (mac3 != 0) {
|
|
@@ -534,9 +563,9 @@ export class ESPLoader extends EventTarget {
|
|
|
534
563
|
if (this.debug) {
|
|
535
564
|
this.logger.debug("Reading from Register " + toHex(reg, 8));
|
|
536
565
|
}
|
|
537
|
-
|
|
566
|
+
const packet = pack("<I", reg);
|
|
538
567
|
await this.sendCommand(ESP_READ_REG, packet);
|
|
539
|
-
|
|
568
|
+
const [val] = await this.getResponse(ESP_READ_REG);
|
|
540
569
|
return val;
|
|
541
570
|
}
|
|
542
571
|
|
|
@@ -554,12 +583,13 @@ export class ESPLoader extends EventTarget {
|
|
|
554
583
|
): Promise<[number, number[]]> {
|
|
555
584
|
timeout = Math.min(timeout, MAX_TIMEOUT);
|
|
556
585
|
await this.sendCommand(opcode, buffer, checksum);
|
|
557
|
-
|
|
586
|
+
const [value, responseData] = await this.getResponse(opcode, timeout);
|
|
558
587
|
|
|
559
|
-
if (
|
|
588
|
+
if (responseData === null) {
|
|
560
589
|
throw new Error("Didn't get enough status bytes");
|
|
561
590
|
}
|
|
562
591
|
|
|
592
|
+
let data = responseData;
|
|
563
593
|
let statusLen = 0;
|
|
564
594
|
|
|
565
595
|
if (this.IS_STUB || this.chipFamily == CHIP_FAMILY_ESP8266) {
|
|
@@ -595,7 +625,7 @@ export class ESPLoader extends EventTarget {
|
|
|
595
625
|
if (data.length < statusLen) {
|
|
596
626
|
throw new Error("Didn't get enough status bytes");
|
|
597
627
|
}
|
|
598
|
-
|
|
628
|
+
const status = data.slice(-statusLen, data.length);
|
|
599
629
|
data = data.slice(0, -statusLen);
|
|
600
630
|
if (this.debug) {
|
|
601
631
|
this.logger.debug("status", status);
|
|
@@ -619,7 +649,7 @@ export class ESPLoader extends EventTarget {
|
|
|
619
649
|
* does not check response
|
|
620
650
|
*/
|
|
621
651
|
async sendCommand(opcode: number, buffer: number[], checksum = 0) {
|
|
622
|
-
|
|
652
|
+
const packet = slipEncode([
|
|
623
653
|
...pack("<BBHI", 0x00, opcode, buffer.length, checksum),
|
|
624
654
|
...buffer,
|
|
625
655
|
]);
|
|
@@ -643,7 +673,7 @@ export class ESPLoader extends EventTarget {
|
|
|
643
673
|
let inEscape = false;
|
|
644
674
|
let readBytes: number[] = [];
|
|
645
675
|
while (true) {
|
|
646
|
-
|
|
676
|
+
const stamp = Date.now();
|
|
647
677
|
readBytes = [];
|
|
648
678
|
while (Date.now() - stamp < timeout) {
|
|
649
679
|
if (this._inputBuffer.length > 0) {
|
|
@@ -655,14 +685,14 @@ export class ESPLoader extends EventTarget {
|
|
|
655
685
|
}
|
|
656
686
|
}
|
|
657
687
|
if (readBytes.length == 0) {
|
|
658
|
-
|
|
688
|
+
const waitingFor = partialPacket === null ? "header" : "content";
|
|
659
689
|
throw new SlipReadError("Timed out waiting for packet " + waitingFor);
|
|
660
690
|
}
|
|
661
691
|
if (this.debug)
|
|
662
692
|
this.logger.debug(
|
|
663
693
|
"Read " + readBytes.length + " bytes: " + hexFormatter(readBytes),
|
|
664
694
|
);
|
|
665
|
-
for (
|
|
695
|
+
for (const b of readBytes) {
|
|
666
696
|
if (partialPacket === null) {
|
|
667
697
|
// waiting for packet header
|
|
668
698
|
if (b == 0xc0) {
|
|
@@ -738,7 +768,7 @@ export class ESPLoader extends EventTarget {
|
|
|
738
768
|
continue;
|
|
739
769
|
}
|
|
740
770
|
|
|
741
|
-
const [resp, opRet,
|
|
771
|
+
const [resp, opRet, , val] = unpack("<BBHI", packet.slice(0, 8));
|
|
742
772
|
if (resp != 1) {
|
|
743
773
|
continue;
|
|
744
774
|
}
|
|
@@ -759,7 +789,7 @@ export class ESPLoader extends EventTarget {
|
|
|
759
789
|
* Calculate checksum of a blob, as it is defined by the ROM
|
|
760
790
|
*/
|
|
761
791
|
checksum(data: number[], state = ESP_CHECKSUM_MAGIC) {
|
|
762
|
-
for (
|
|
792
|
+
for (const b of data) {
|
|
763
793
|
state ^= b;
|
|
764
794
|
}
|
|
765
795
|
return state;
|
|
@@ -772,10 +802,10 @@ export class ESPLoader extends EventTarget {
|
|
|
772
802
|
|
|
773
803
|
try {
|
|
774
804
|
// Send ESP_ROM_BAUD(115200) as the old one if running STUB otherwise 0
|
|
775
|
-
|
|
805
|
+
const buffer = pack("<II", baud, this.IS_STUB ? ESP_ROM_BAUD : 0);
|
|
776
806
|
await this.checkCommand(ESP_CHANGE_BAUDRATE, buffer);
|
|
777
807
|
} catch (e) {
|
|
778
|
-
|
|
808
|
+
this.logger.error(`Baudrate change error: ${e}`);
|
|
779
809
|
throw new Error(
|
|
780
810
|
`Unable to change the baud rate to ${baud}: No response from set baud rate command.`,
|
|
781
811
|
);
|
|
@@ -828,7 +858,7 @@ export class ESPLoader extends EventTarget {
|
|
|
828
858
|
// Restart Readloop
|
|
829
859
|
this.readLoop();
|
|
830
860
|
} catch (e) {
|
|
831
|
-
|
|
861
|
+
this.logger.error(`Reconfigure port error: ${e}`);
|
|
832
862
|
throw new Error(`Unable to change the baud rate to ${baud}: ${e}`);
|
|
833
863
|
}
|
|
834
864
|
}
|
|
@@ -841,7 +871,7 @@ export class ESPLoader extends EventTarget {
|
|
|
841
871
|
async sync() {
|
|
842
872
|
for (let i = 0; i < 5; i++) {
|
|
843
873
|
this._inputBuffer.length = 0;
|
|
844
|
-
|
|
874
|
+
const response = await this._sync();
|
|
845
875
|
if (response) {
|
|
846
876
|
await sleep(SYNC_TIMEOUT);
|
|
847
877
|
return true;
|
|
@@ -861,11 +891,11 @@ export class ESPLoader extends EventTarget {
|
|
|
861
891
|
await this.sendCommand(ESP_SYNC, SYNC_PACKET);
|
|
862
892
|
for (let i = 0; i < 8; i++) {
|
|
863
893
|
try {
|
|
864
|
-
|
|
894
|
+
const [, data] = await this.getResponse(ESP_SYNC, SYNC_TIMEOUT);
|
|
865
895
|
if (data.length > 1 && data[0] == 0 && data[1] == 0) {
|
|
866
896
|
return true;
|
|
867
897
|
}
|
|
868
|
-
} catch
|
|
898
|
+
} catch {
|
|
869
899
|
// If read packet fails.
|
|
870
900
|
}
|
|
871
901
|
}
|
|
@@ -898,10 +928,10 @@ export class ESPLoader extends EventTarget {
|
|
|
898
928
|
) {
|
|
899
929
|
if (binaryData.byteLength >= 8) {
|
|
900
930
|
// unpack the (potential) image header
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
931
|
+
const header = Array.from(new Uint8Array(binaryData, 0, 4));
|
|
932
|
+
const headerMagic = header[0];
|
|
933
|
+
const headerFlashMode = header[2];
|
|
934
|
+
const headerFlashSizeFreq = header[3];
|
|
905
935
|
|
|
906
936
|
this.logger.log(
|
|
907
937
|
`Image header, Magic=${toHex(headerMagic)}, FlashMode=${toHex(
|
|
@@ -910,7 +940,7 @@ export class ESPLoader extends EventTarget {
|
|
|
910
940
|
);
|
|
911
941
|
}
|
|
912
942
|
|
|
913
|
-
|
|
943
|
+
const uncompressedFilesize = binaryData.byteLength;
|
|
914
944
|
let compressedFilesize = 0;
|
|
915
945
|
|
|
916
946
|
let dataToFlash;
|
|
@@ -939,10 +969,10 @@ export class ESPLoader extends EventTarget {
|
|
|
939
969
|
let seq = 0;
|
|
940
970
|
let written = 0;
|
|
941
971
|
let position = 0;
|
|
942
|
-
|
|
943
|
-
|
|
972
|
+
const stamp = Date.now();
|
|
973
|
+
const flashWriteSize = this.getFlashWriteSize();
|
|
944
974
|
|
|
945
|
-
|
|
975
|
+
const filesize = compress ? compressedFilesize : uncompressedFilesize;
|
|
946
976
|
|
|
947
977
|
while (filesize - position > 0) {
|
|
948
978
|
if (this.debug) {
|
|
@@ -1028,8 +1058,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1028
1058
|
await this.flushSerialBuffers();
|
|
1029
1059
|
|
|
1030
1060
|
let eraseSize;
|
|
1031
|
-
|
|
1032
|
-
let flashWriteSize = this.getFlashWriteSize();
|
|
1061
|
+
const flashWriteSize = this.getFlashWriteSize();
|
|
1033
1062
|
if (
|
|
1034
1063
|
!this.IS_STUB &&
|
|
1035
1064
|
[
|
|
@@ -1050,22 +1079,19 @@ export class ESPLoader extends EventTarget {
|
|
|
1050
1079
|
) {
|
|
1051
1080
|
await this.checkCommand(ESP_SPI_ATTACH, new Array(8).fill(0));
|
|
1052
1081
|
}
|
|
1053
|
-
|
|
1082
|
+
const numBlocks = Math.floor((size + flashWriteSize - 1) / flashWriteSize);
|
|
1054
1083
|
if (this.chipFamily == CHIP_FAMILY_ESP8266) {
|
|
1055
1084
|
eraseSize = this.getEraseSize(offset, size);
|
|
1056
1085
|
} else {
|
|
1057
1086
|
eraseSize = size;
|
|
1058
1087
|
}
|
|
1059
1088
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
} else {
|
|
1064
|
-
timeout = timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, size);
|
|
1065
|
-
}
|
|
1089
|
+
const timeout = this.IS_STUB
|
|
1090
|
+
? DEFAULT_TIMEOUT
|
|
1091
|
+
: timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, size);
|
|
1066
1092
|
|
|
1067
|
-
|
|
1068
|
-
buffer = pack("<IIII", eraseSize, numBlocks, flashWriteSize, offset);
|
|
1093
|
+
const stamp = Date.now();
|
|
1094
|
+
let buffer = pack("<IIII", eraseSize, numBlocks, flashWriteSize, offset);
|
|
1069
1095
|
if (
|
|
1070
1096
|
this.chipFamily == CHIP_FAMILY_ESP32 ||
|
|
1071
1097
|
this.chipFamily == CHIP_FAMILY_ESP32S2 ||
|
|
@@ -1109,22 +1135,18 @@ export class ESPLoader extends EventTarget {
|
|
|
1109
1135
|
*
|
|
1110
1136
|
*/
|
|
1111
1137
|
|
|
1112
|
-
async flashDeflBegin(
|
|
1113
|
-
size = 0,
|
|
1114
|
-
compressedSize = 0,
|
|
1115
|
-
offset = 0,
|
|
1116
|
-
encrypted = false,
|
|
1117
|
-
) {
|
|
1138
|
+
async flashDeflBegin(size = 0, compressedSize = 0, offset = 0) {
|
|
1118
1139
|
// Start downloading compressed data to Flash (performs an erase)
|
|
1119
1140
|
// Returns number of blocks to write.
|
|
1120
|
-
|
|
1121
|
-
|
|
1141
|
+
const flashWriteSize = this.getFlashWriteSize();
|
|
1142
|
+
const numBlocks = Math.floor(
|
|
1122
1143
|
(compressedSize + flashWriteSize - 1) / flashWriteSize,
|
|
1123
1144
|
);
|
|
1124
|
-
|
|
1145
|
+
const eraseBlocks = Math.floor(
|
|
1146
|
+
(size + flashWriteSize - 1) / flashWriteSize,
|
|
1147
|
+
);
|
|
1125
1148
|
let writeSize = 0;
|
|
1126
1149
|
let timeout = 0;
|
|
1127
|
-
let buffer;
|
|
1128
1150
|
|
|
1129
1151
|
if (this.IS_STUB) {
|
|
1130
1152
|
writeSize = size; // stub expects number of bytes here, manages erasing internally
|
|
@@ -1133,7 +1155,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1133
1155
|
writeSize = eraseBlocks * flashWriteSize; // ROM expects rounded up to erase block size
|
|
1134
1156
|
timeout = DEFAULT_TIMEOUT;
|
|
1135
1157
|
}
|
|
1136
|
-
buffer = pack("<IIII", writeSize, numBlocks, flashWriteSize, offset);
|
|
1158
|
+
const buffer = pack("<IIII", writeSize, numBlocks, flashWriteSize, offset);
|
|
1137
1159
|
|
|
1138
1160
|
await this.checkCommand(ESP_FLASH_DEFL_BEGIN, buffer, 0, timeout);
|
|
1139
1161
|
|
|
@@ -1141,24 +1163,24 @@ export class ESPLoader extends EventTarget {
|
|
|
1141
1163
|
}
|
|
1142
1164
|
|
|
1143
1165
|
async flashFinish() {
|
|
1144
|
-
|
|
1166
|
+
const buffer = pack("<I", 1);
|
|
1145
1167
|
await this.checkCommand(ESP_FLASH_END, buffer);
|
|
1146
1168
|
}
|
|
1147
1169
|
|
|
1148
1170
|
async flashDeflFinish() {
|
|
1149
|
-
|
|
1171
|
+
const buffer = pack("<I", 1);
|
|
1150
1172
|
await this.checkCommand(ESP_FLASH_DEFL_END, buffer);
|
|
1151
1173
|
}
|
|
1152
1174
|
|
|
1153
1175
|
getBootloaderOffset() {
|
|
1154
|
-
|
|
1155
|
-
|
|
1176
|
+
const bootFlashOffs = getSpiFlashAddresses(this.getChipFamily());
|
|
1177
|
+
const BootldrFlashOffs = bootFlashOffs.flashOffs;
|
|
1156
1178
|
return BootldrFlashOffs;
|
|
1157
1179
|
}
|
|
1158
1180
|
|
|
1159
1181
|
async flashId() {
|
|
1160
|
-
|
|
1161
|
-
|
|
1182
|
+
const SPIFLASH_RDID = 0x9f;
|
|
1183
|
+
const result = await this.runSpiFlashCommand(SPIFLASH_RDID, [], 24);
|
|
1162
1184
|
return result;
|
|
1163
1185
|
}
|
|
1164
1186
|
|
|
@@ -1176,7 +1198,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1176
1198
|
let buffer = pack("<IIII", address, value, mask, delayUs);
|
|
1177
1199
|
if (delayAfterUs > 0) {
|
|
1178
1200
|
// add a dummy write to a date register as an excuse to have a delay
|
|
1179
|
-
buffer.concat(
|
|
1201
|
+
buffer = buffer.concat(
|
|
1180
1202
|
pack(
|
|
1181
1203
|
"<IIII",
|
|
1182
1204
|
getSpiFlashAddresses(this.getChipFamily()).uartDateReg,
|
|
@@ -1195,9 +1217,11 @@ export class ESPLoader extends EventTarget {
|
|
|
1195
1217
|
misoBits: number,
|
|
1196
1218
|
) {
|
|
1197
1219
|
if (spiAddresses.mosiDlenOffs != -1) {
|
|
1198
|
-
//
|
|
1199
|
-
|
|
1200
|
-
|
|
1220
|
+
// Actual MCUs have a more sophisticated way to set up "user" commands
|
|
1221
|
+
const SPI_MOSI_DLEN_REG =
|
|
1222
|
+
spiAddresses.regBase + spiAddresses.mosiDlenOffs;
|
|
1223
|
+
const SPI_MISO_DLEN_REG =
|
|
1224
|
+
spiAddresses.regBase + spiAddresses.misoDlenOffs;
|
|
1201
1225
|
if (mosiBits > 0) {
|
|
1202
1226
|
await this.writeRegister(SPI_MOSI_DLEN_REG, mosiBits - 1);
|
|
1203
1227
|
}
|
|
@@ -1205,19 +1229,19 @@ export class ESPLoader extends EventTarget {
|
|
|
1205
1229
|
await this.writeRegister(SPI_MISO_DLEN_REG, misoBits - 1);
|
|
1206
1230
|
}
|
|
1207
1231
|
} else {
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1232
|
+
const SPI_DATA_LEN_REG = spiAddresses.regBase + spiAddresses.usr1Offs;
|
|
1233
|
+
const SPI_MOSI_BITLEN_S = 17;
|
|
1234
|
+
const SPI_MISO_BITLEN_S = 8;
|
|
1235
|
+
const mosiMask = mosiBits == 0 ? 0 : mosiBits - 1;
|
|
1236
|
+
const misoMask = misoBits == 0 ? 0 : misoBits - 1;
|
|
1237
|
+
const value =
|
|
1214
1238
|
(misoMask << SPI_MISO_BITLEN_S) | (mosiMask << SPI_MOSI_BITLEN_S);
|
|
1215
1239
|
await this.writeRegister(SPI_DATA_LEN_REG, value);
|
|
1216
1240
|
}
|
|
1217
1241
|
}
|
|
1218
1242
|
async waitDone(spiCmdReg: number, spiCmdUsr: number) {
|
|
1219
1243
|
for (let i = 0; i < 10; i++) {
|
|
1220
|
-
|
|
1244
|
+
const cmdValue = await this.readRegister(spiCmdReg);
|
|
1221
1245
|
if ((cmdValue & spiCmdUsr) == 0) {
|
|
1222
1246
|
return;
|
|
1223
1247
|
}
|
|
@@ -1241,23 +1265,23 @@ export class ESPLoader extends EventTarget {
|
|
|
1241
1265
|
// reads back 'read_bits' of reply on MISO. Result is a number.
|
|
1242
1266
|
|
|
1243
1267
|
// SPI_USR register flags
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
// SPI registers, base address differs
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1268
|
+
const SPI_USR_COMMAND = 1 << 31;
|
|
1269
|
+
const SPI_USR_MISO = 1 << 28;
|
|
1270
|
+
const SPI_USR_MOSI = 1 << 27;
|
|
1271
|
+
|
|
1272
|
+
// SPI registers, base address differs
|
|
1273
|
+
const spiAddresses = getSpiFlashAddresses(this.getChipFamily());
|
|
1274
|
+
const base = spiAddresses.regBase;
|
|
1275
|
+
const SPI_CMD_REG = base;
|
|
1276
|
+
const SPI_USR_REG = base + spiAddresses.usrOffs;
|
|
1277
|
+
const SPI_USR2_REG = base + spiAddresses.usr2Offs;
|
|
1278
|
+
const SPI_W0_REG = base + spiAddresses.w0Offs;
|
|
1255
1279
|
|
|
1256
1280
|
// SPI peripheral "command" bitmasks for SPI_CMD_REG
|
|
1257
|
-
|
|
1281
|
+
const SPI_CMD_USR = 1 << 18;
|
|
1258
1282
|
|
|
1259
1283
|
// shift values
|
|
1260
|
-
|
|
1284
|
+
const SPI_USR2_COMMAND_LEN_SHIFT = 28;
|
|
1261
1285
|
|
|
1262
1286
|
if (readBits > 32) {
|
|
1263
1287
|
throw new Error(
|
|
@@ -1270,9 +1294,9 @@ export class ESPLoader extends EventTarget {
|
|
|
1270
1294
|
);
|
|
1271
1295
|
}
|
|
1272
1296
|
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1297
|
+
const dataBits = data.length * 8;
|
|
1298
|
+
const oldSpiUsr = await this.readRegister(SPI_USR_REG);
|
|
1299
|
+
const oldSpiUsr2 = await this.readRegister(SPI_USR2_REG);
|
|
1276
1300
|
|
|
1277
1301
|
let flags = SPI_USR_COMMAND;
|
|
1278
1302
|
|
|
@@ -1293,9 +1317,10 @@ export class ESPLoader extends EventTarget {
|
|
|
1293
1317
|
if (dataBits == 0) {
|
|
1294
1318
|
await this.writeRegister(SPI_W0_REG, 0); // clear data register before we read it
|
|
1295
1319
|
} else {
|
|
1296
|
-
|
|
1320
|
+
const padLen = (4 - (data.length % 4)) % 4;
|
|
1321
|
+
data = data.concat(new Array(padLen).fill(0x00)); // pad to 32-bit multiple
|
|
1297
1322
|
|
|
1298
|
-
|
|
1323
|
+
const words = unpack("I".repeat(Math.floor(data.length / 4)), data);
|
|
1299
1324
|
let nextReg = SPI_W0_REG;
|
|
1300
1325
|
|
|
1301
1326
|
this.logger.debug(`Words Length: ${words.length}`);
|
|
@@ -1311,7 +1336,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1311
1336
|
await this.writeRegister(SPI_CMD_REG, SPI_CMD_USR);
|
|
1312
1337
|
await this.waitDone(SPI_CMD_REG, SPI_CMD_USR);
|
|
1313
1338
|
|
|
1314
|
-
|
|
1339
|
+
const status = await this.readRegister(SPI_W0_REG);
|
|
1315
1340
|
// restore some SPI controller registers
|
|
1316
1341
|
await this.writeRegister(SPI_USR_REG, oldSpiUsr);
|
|
1317
1342
|
await this.writeRegister(SPI_USR2_REG, oldSpiUsr2);
|
|
@@ -1320,9 +1345,9 @@ export class ESPLoader extends EventTarget {
|
|
|
1320
1345
|
async detectFlashSize() {
|
|
1321
1346
|
this.logger.log("Detecting Flash Size");
|
|
1322
1347
|
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1348
|
+
const flashId = await this.flashId();
|
|
1349
|
+
const manufacturer = flashId & 0xff;
|
|
1350
|
+
const flashIdLowbyte = (flashId >> 16) & 0xff;
|
|
1326
1351
|
|
|
1327
1352
|
this.logger.log(`FlashId: ${toHex(flashId)}`);
|
|
1328
1353
|
this.logger.log(`Flash Manufacturer: ${manufacturer.toString(16)}`);
|
|
@@ -1342,10 +1367,10 @@ export class ESPLoader extends EventTarget {
|
|
|
1342
1367
|
* Provides a workaround for the bootloader erase bug on ESP8266.
|
|
1343
1368
|
*/
|
|
1344
1369
|
getEraseSize(offset: number, size: number) {
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1370
|
+
const sectorsPerBlock = 16;
|
|
1371
|
+
const sectorSize = FLASH_SECTOR_SIZE;
|
|
1372
|
+
const numSectors = Math.floor((size + sectorSize - 1) / sectorSize);
|
|
1373
|
+
const startSector = Math.floor(offset / sectorSize);
|
|
1349
1374
|
|
|
1350
1375
|
let headSectors = sectorsPerBlock - (startSector % sectorsPerBlock);
|
|
1351
1376
|
if (numSectors < headSectors) {
|
|
@@ -1397,16 +1422,13 @@ export class ESPLoader extends EventTarget {
|
|
|
1397
1422
|
* ignore errors.
|
|
1398
1423
|
*/
|
|
1399
1424
|
async memFinish(entrypoint = 0) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1425
|
+
const timeout = this.IS_STUB ? DEFAULT_TIMEOUT : MEM_END_ROM_TIMEOUT;
|
|
1426
|
+
const data = pack("<II", entrypoint == 0 ? 1 : 0, entrypoint);
|
|
1402
1427
|
return await this.checkCommand(ESP_MEM_END, data, 0, timeout);
|
|
1403
1428
|
}
|
|
1404
1429
|
|
|
1405
1430
|
async runStub(skipFlashDetection = false): Promise<EspStubLoader> {
|
|
1406
|
-
const stub
|
|
1407
|
-
this.chipFamily,
|
|
1408
|
-
this.chipRevision,
|
|
1409
|
-
);
|
|
1431
|
+
const stub = await getStubCode(this.chipFamily, this.chipRevision);
|
|
1410
1432
|
|
|
1411
1433
|
// No stub available for this chip, return ROM loader
|
|
1412
1434
|
if (stub === null) {
|
|
@@ -1417,32 +1439,29 @@ export class ESPLoader extends EventTarget {
|
|
|
1417
1439
|
}
|
|
1418
1440
|
|
|
1419
1441
|
// We're transferring over USB, right?
|
|
1420
|
-
|
|
1442
|
+
const ramBlock = USB_RAM_BLOCK;
|
|
1421
1443
|
|
|
1422
1444
|
// Upload
|
|
1423
1445
|
this.logger.log("Uploading stub...");
|
|
1424
|
-
for (
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
}
|
|
1436
|
-
await this.memBlock(stub[field].slice(fromOffs, toOffs), seq);
|
|
1446
|
+
for (const field of ["text", "data"] as const) {
|
|
1447
|
+
const fieldData = stub[field];
|
|
1448
|
+
const offset = stub[`${field}_start` as "text_start" | "data_start"];
|
|
1449
|
+
const length = fieldData.length;
|
|
1450
|
+
const blocks = Math.floor((length + ramBlock - 1) / ramBlock);
|
|
1451
|
+
await this.memBegin(length, blocks, ramBlock, offset);
|
|
1452
|
+
for (const seq of Array(blocks).keys()) {
|
|
1453
|
+
const fromOffs = seq * ramBlock;
|
|
1454
|
+
let toOffs = fromOffs + ramBlock;
|
|
1455
|
+
if (toOffs > length) {
|
|
1456
|
+
toOffs = length;
|
|
1437
1457
|
}
|
|
1458
|
+
await this.memBlock(fieldData.slice(fromOffs, toOffs), seq);
|
|
1438
1459
|
}
|
|
1439
1460
|
}
|
|
1440
|
-
await this.memFinish(stub
|
|
1441
|
-
|
|
1442
|
-
let pChar: string;
|
|
1461
|
+
await this.memFinish(stub.entry);
|
|
1443
1462
|
|
|
1444
1463
|
const p = await this.readPacket(500);
|
|
1445
|
-
pChar = String.fromCharCode(...p);
|
|
1464
|
+
const pChar = String.fromCharCode(...p);
|
|
1446
1465
|
|
|
1447
1466
|
if (pChar != "OHAI") {
|
|
1448
1467
|
throw new Error("Failed to start stub. Unexpected response: " + pChar);
|
|
@@ -1459,12 +1478,16 @@ export class ESPLoader extends EventTarget {
|
|
|
1459
1478
|
}
|
|
1460
1479
|
|
|
1461
1480
|
async writeToStream(data: number[]) {
|
|
1462
|
-
|
|
1481
|
+
if (!this.port.writable) {
|
|
1482
|
+
this.logger.debug("Port writable stream not available, skipping write");
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
const writer = this.port.writable.getWriter();
|
|
1463
1486
|
await writer.write(new Uint8Array(data));
|
|
1464
1487
|
try {
|
|
1465
1488
|
writer.releaseLock();
|
|
1466
1489
|
} catch (err) {
|
|
1467
|
-
|
|
1490
|
+
this.logger.error(`Ignoring release lock error: ${err}`);
|
|
1468
1491
|
}
|
|
1469
1492
|
}
|
|
1470
1493
|
|
|
@@ -1473,7 +1496,11 @@ export class ESPLoader extends EventTarget {
|
|
|
1473
1496
|
await this._parent.disconnect();
|
|
1474
1497
|
return;
|
|
1475
1498
|
}
|
|
1476
|
-
|
|
1499
|
+
if (!this.port.writable) {
|
|
1500
|
+
this.logger.debug("Port already closed, skipping disconnect");
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
await this.port.writable.getWriter().close();
|
|
1477
1504
|
await new Promise((resolve) => {
|
|
1478
1505
|
if (!this._reader) {
|
|
1479
1506
|
resolve(undefined);
|
|
@@ -1509,8 +1536,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1509
1536
|
this._reader = undefined;
|
|
1510
1537
|
}
|
|
1511
1538
|
|
|
1512
|
-
await sleep(SYNC_TIMEOUT);
|
|
1513
|
-
|
|
1514
1539
|
// Close port
|
|
1515
1540
|
try {
|
|
1516
1541
|
await this.port.close();
|
|
@@ -1519,9 +1544,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1519
1544
|
this.logger.debug(`Port close error: ${err}`);
|
|
1520
1545
|
}
|
|
1521
1546
|
|
|
1522
|
-
// Wait for port to fully close
|
|
1523
|
-
await sleep(SYNC_TIMEOUT);
|
|
1524
|
-
|
|
1525
1547
|
// Open the port
|
|
1526
1548
|
this.logger.debug("Opening port...");
|
|
1527
1549
|
try {
|
|
@@ -1531,9 +1553,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1531
1553
|
throw new Error(`Failed to open port: ${err}`);
|
|
1532
1554
|
}
|
|
1533
1555
|
|
|
1534
|
-
// Wait for port to be fully ready
|
|
1535
|
-
await sleep(SYNC_TIMEOUT);
|
|
1536
|
-
|
|
1537
1556
|
// Verify port streams are available
|
|
1538
1557
|
if (!this.port.readable || !this.port.writable) {
|
|
1539
1558
|
throw new Error(
|
|
@@ -1548,7 +1567,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1548
1567
|
const savedChipVariant = this.chipVariant;
|
|
1549
1568
|
const savedFlashSize = this.flashSize;
|
|
1550
1569
|
|
|
1551
|
-
// Reinitialize
|
|
1570
|
+
// Reinitialize
|
|
1552
1571
|
await this.hardReset(true);
|
|
1553
1572
|
|
|
1554
1573
|
if (!this._parent) {
|
|
@@ -1560,7 +1579,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1560
1579
|
await this.flushSerialBuffers();
|
|
1561
1580
|
await this.sync();
|
|
1562
1581
|
|
|
1563
|
-
// Restore chip info
|
|
1582
|
+
// Restore chip info
|
|
1564
1583
|
this.chipFamily = savedChipFamily;
|
|
1565
1584
|
this.chipName = savedChipName;
|
|
1566
1585
|
this.chipRevision = savedChipRevision;
|
|
@@ -1574,7 +1593,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1574
1593
|
throw new Error("Port not ready after reconnect");
|
|
1575
1594
|
}
|
|
1576
1595
|
|
|
1577
|
-
// Load stub
|
|
1596
|
+
// Load stub
|
|
1578
1597
|
const stubLoader = await this.runStub(true);
|
|
1579
1598
|
this.logger.debug("Stub loaded");
|
|
1580
1599
|
|
|
@@ -1582,9 +1601,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1582
1601
|
if (this._currentBaudRate !== ESP_ROM_BAUD) {
|
|
1583
1602
|
await stubLoader.setBaudrate(this._currentBaudRate);
|
|
1584
1603
|
|
|
1585
|
-
// Wait for port to be ready after baudrate change
|
|
1586
|
-
await sleep(SYNC_TIMEOUT);
|
|
1587
|
-
|
|
1588
1604
|
// Verify port is still ready after baudrate change
|
|
1589
1605
|
if (!this.port.writable || !this.port.readable) {
|
|
1590
1606
|
throw new Error(
|
|
@@ -1606,22 +1622,14 @@ export class ESPLoader extends EventTarget {
|
|
|
1606
1622
|
* This clears both the application RX buffer and waits for hardware buffers to drain
|
|
1607
1623
|
*/
|
|
1608
1624
|
private async flushSerialBuffers(): Promise<void> {
|
|
1609
|
-
// Clear application
|
|
1625
|
+
// Clear application buffer
|
|
1610
1626
|
if (!this._parent) {
|
|
1611
1627
|
this.__inputBuffer = [];
|
|
1612
1628
|
}
|
|
1613
1629
|
|
|
1614
|
-
// Wait for any pending
|
|
1630
|
+
// Wait for any pending data
|
|
1615
1631
|
await sleep(SYNC_TIMEOUT);
|
|
1616
1632
|
|
|
1617
|
-
// Clear RX buffer again
|
|
1618
|
-
if (!this._parent) {
|
|
1619
|
-
this.__inputBuffer = [];
|
|
1620
|
-
}
|
|
1621
|
-
|
|
1622
|
-
// Wait longer to ensure all stale data has been received and discarded
|
|
1623
|
-
await sleep(SYNC_TIMEOUT * 2);
|
|
1624
|
-
|
|
1625
1633
|
// Final clear
|
|
1626
1634
|
if (!this._parent) {
|
|
1627
1635
|
this.__inputBuffer = [];
|
|
@@ -1653,22 +1661,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1653
1661
|
);
|
|
1654
1662
|
}
|
|
1655
1663
|
|
|
1656
|
-
// Check if we should reconnect BEFORE starting the read
|
|
1657
|
-
// Reconnect if total bytes read >= 4MB to ensure clean state
|
|
1658
|
-
if (this._totalBytesRead >= 4 * 1024 * 1024) {
|
|
1659
|
-
this.logger.log(
|
|
1660
|
-
// `Total bytes read: ${this._totalBytesRead}. Reconnecting before new read...`,
|
|
1661
|
-
`Reconnecting before new read...`,
|
|
1662
|
-
);
|
|
1663
|
-
|
|
1664
|
-
try {
|
|
1665
|
-
await this.reconnect();
|
|
1666
|
-
} catch (err) {
|
|
1667
|
-
// If reconnect fails, throw error - don't continue with potentially broken state
|
|
1668
|
-
throw new Error(`Reconnect failed: ${err}`);
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
1664
|
// Flush serial buffers before flash read operation
|
|
1673
1665
|
await this.flushSerialBuffers();
|
|
1674
1666
|
|
|
@@ -1683,18 +1675,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1683
1675
|
let remainingSize = size;
|
|
1684
1676
|
|
|
1685
1677
|
while (remainingSize > 0) {
|
|
1686
|
-
// Reconnect every 4MB to prevent browser buffer issues
|
|
1687
|
-
if (allData.length > 0 && allData.length % (4 * 1024 * 1024) === 0) {
|
|
1688
|
-
this.logger.debug(
|
|
1689
|
-
`Read ${allData.length} bytes. Reconnecting to clear buffers...`,
|
|
1690
|
-
);
|
|
1691
|
-
try {
|
|
1692
|
-
await this.reconnect();
|
|
1693
|
-
} catch (err) {
|
|
1694
|
-
throw new Error(`Reconnect failed during read: ${err}`);
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
1678
|
const chunkSize = Math.min(CHUNK_SIZE, remainingSize);
|
|
1699
1679
|
let chunkSuccess = false;
|
|
1700
1680
|
let retryCount = 0;
|
|
@@ -1708,8 +1688,8 @@ export class ESPLoader extends EventTarget {
|
|
|
1708
1688
|
);
|
|
1709
1689
|
|
|
1710
1690
|
// Send read flash command for this chunk
|
|
1711
|
-
|
|
1712
|
-
const [res
|
|
1691
|
+
const pkt = pack("<IIII", currentAddr, chunkSize, 0x1000, 1024);
|
|
1692
|
+
const [res] = await this.checkCommand(ESP_READ_FLASH, pkt);
|
|
1713
1693
|
|
|
1714
1694
|
if (res != 0) {
|
|
1715
1695
|
throw new Error("Failed to read memory: " + res);
|
|
@@ -1798,7 +1778,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1798
1778
|
remainingSize -= chunkSize;
|
|
1799
1779
|
|
|
1800
1780
|
this.logger.debug(
|
|
1801
|
-
`Total progress: 0x${allData.length.toString(16)}
|
|
1781
|
+
`Total progress: 0x${allData.length.toString(16)} from 0x${size.toString(16)} bytes`,
|
|
1802
1782
|
);
|
|
1803
1783
|
}
|
|
1804
1784
|
|
|
@@ -1820,27 +1800,26 @@ class EspStubLoader extends ESPLoader {
|
|
|
1820
1800
|
*/
|
|
1821
1801
|
async memBegin(
|
|
1822
1802
|
size: number,
|
|
1823
|
-
|
|
1824
|
-
|
|
1803
|
+
_blocks: number,
|
|
1804
|
+
_blocksize: number,
|
|
1825
1805
|
offset: number,
|
|
1826
|
-
): Promise<
|
|
1827
|
-
|
|
1806
|
+
): Promise<[number, number[]]> {
|
|
1807
|
+
const stub = await getStubCode(this.chipFamily, this.chipRevision);
|
|
1828
1808
|
|
|
1829
1809
|
// Stub may be null for chips without stub support
|
|
1830
1810
|
if (stub === null) {
|
|
1831
|
-
return;
|
|
1811
|
+
return [0, []];
|
|
1832
1812
|
}
|
|
1833
1813
|
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
stub.text_start,
|
|
1841
|
-
stub.text.length,
|
|
1814
|
+
const load_start = offset;
|
|
1815
|
+
const load_end = offset + size;
|
|
1816
|
+
this.logger.debug(
|
|
1817
|
+
`Load range: ${toHex(load_start, 8)}-${toHex(load_end, 8)}`,
|
|
1818
|
+
);
|
|
1819
|
+
this.logger.debug(
|
|
1820
|
+
`Stub data: ${toHex(stub.data_start, 8)}, len: ${stub.data.length}, text: ${toHex(stub.text_start, 8)}, len: ${stub.text.length}`,
|
|
1842
1821
|
);
|
|
1843
|
-
for (
|
|
1822
|
+
for (const [start, end] of [
|
|
1844
1823
|
[stub.data_start, stub.data_start + stub.data.length],
|
|
1845
1824
|
[stub.text_start, stub.text_start + stub.text.length],
|
|
1846
1825
|
]) {
|
|
@@ -1860,6 +1839,7 @@ class EspStubLoader extends ESPLoader {
|
|
|
1860
1839
|
);
|
|
1861
1840
|
}
|
|
1862
1841
|
}
|
|
1842
|
+
return [0, []];
|
|
1863
1843
|
}
|
|
1864
1844
|
|
|
1865
1845
|
/**
|