tasmota-webserial-esptool 6.0.2 → 6.1.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/.devcontainer/devcontainer.json +13 -13
- package/.github/workflows/build_upload.yml +4 -4
- package/README.md +1 -1
- package/css/dark.css +6 -4
- package/css/light.css +5 -2
- package/dist/const.d.ts +35 -1
- package/dist/const.js +80 -1
- package/dist/esp_loader.js +15 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/stubs/esp32.json +7 -1
- package/dist/stubs/esp32c2.json +7 -0
- package/dist/stubs/esp32c3.json +7 -1
- package/dist/stubs/esp32c6.json +7 -0
- package/dist/stubs/esp32h2.json +7 -0
- package/dist/stubs/esp32s2.json +7 -1
- package/dist/stubs/esp32s3.json +7 -1
- package/dist/stubs/index.js +10 -1
- package/dist/web/esp32-d51f885c.js +1 -0
- package/dist/web/esp32c2-f0222390.js +1 -0
- package/dist/web/esp32c3-9f5fd05b.js +1 -0
- package/dist/web/esp32c6-e911f438.js +1 -0
- package/dist/web/esp32h2-19e099dc.js +1 -0
- package/dist/web/esp32s2-da1a4fa1.js +1 -0
- package/dist/web/esp32s3-d79eec99.js +1 -0
- package/dist/web/index.js +1 -1
- package/js/esptool.js +599 -495
- package/js/modules/esp32-d51f885c.js +1 -0
- package/js/modules/esp32c2-f0222390.js +1 -0
- package/js/modules/esp32c3-9f5fd05b.js +1 -0
- package/js/modules/esp32c6-e911f438.js +1 -0
- package/js/modules/esp32h2-19e099dc.js +1 -0
- package/js/modules/esp32s2-da1a4fa1.js +1 -0
- package/js/modules/esp32s3-d79eec99.js +1 -0
- package/js/modules/esptool.js +1 -1
- package/js/script.js +1 -1
- package/js/utilities.js +132 -98
- package/license.md +0 -1
- package/package.json +2 -2
- package/script/build +5 -0
- package/src/const.ts +84 -1
- package/src/esp_loader.ts +17 -2
- package/src/index.ts +1 -0
- package/src/stubs/esp32.json +7 -1
- package/src/stubs/esp32c2.json +7 -1
- package/src/stubs/esp32c3.json +7 -1
- package/src/stubs/esp32c6.json +7 -0
- package/src/stubs/esp32h2.json +7 -1
- package/src/stubs/esp32s2.json +7 -1
- package/src/stubs/esp32s3.json +7 -1
- package/src/stubs/index.ts +10 -1
- package/stubs/esp32.json +5 -5
- package/stubs/esp32c2.json +7 -1
- package/stubs/esp32c3.json +5 -5
- package/stubs/esp32c6.json +5 -5
- package/stubs/esp32h2.json +7 -1
- package/stubs/esp32s2.json +5 -5
- package/stubs/esp32s3.json +5 -5
- package/stubs/esp8266.json +5 -5
- package/dist/web/esp32-a2dcbc2e.js +0 -1
- package/dist/web/esp32c3-18e9678b.js +0 -1
- package/dist/web/esp32s2-3109ccc6.js +0 -1
- package/dist/web/esp32s3-c1dbd867.js +0 -1
- package/js/modules/esp32-a2dcbc2e.js +0 -1
- package/js/modules/esp32c3-18e9678b.js +0 -1
- package/js/modules/esp32s2-3109ccc6.js +0 -1
- package/js/modules/esp32s3-c1dbd867.js +0 -1
package/js/esptool.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
3
|
let port;
|
|
4
4
|
let reader;
|
|
@@ -7,36 +7,36 @@ let outputStream;
|
|
|
7
7
|
let inputBuffer = [];
|
|
8
8
|
|
|
9
9
|
const esp8266FlashSizes = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
"512KB": 0x00,
|
|
11
|
+
"256KB": 0x10,
|
|
12
|
+
"1MB": 0x20,
|
|
13
|
+
"2MB": 0x30,
|
|
14
|
+
"4MB": 0x40,
|
|
15
|
+
"2MB-c1": 0x50,
|
|
16
|
+
"4MB-c1": 0x60,
|
|
17
|
+
"8MB": 0x80,
|
|
18
|
+
"16MB": 0x90,
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
const esp32FlashSizes = {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
"1MB": 0x00,
|
|
23
|
+
"2MB": 0x10,
|
|
24
|
+
"4MB": 0x20,
|
|
25
|
+
"8MB": 0x30,
|
|
26
|
+
"16MB": 0x40,
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
const flashMode = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
qio: 0,
|
|
31
|
+
qout: 1,
|
|
32
|
+
dio: 2,
|
|
33
|
+
dout: 3,
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
const flashFreq = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
37
|
+
"40m": 0,
|
|
38
|
+
"80m": 0xf,
|
|
39
|
+
};
|
|
40
40
|
|
|
41
41
|
// Defaults
|
|
42
42
|
// Flash Frequency: 40m
|
|
@@ -46,15 +46,17 @@ const flashFreq = {
|
|
|
46
46
|
const ESP_ROM_BAUD = 115200;
|
|
47
47
|
const FLASH_WRITE_SIZE = 0x400;
|
|
48
48
|
const STUBLOADER_FLASH_WRITE_SIZE = 0x4000;
|
|
49
|
-
const FLASH_SECTOR_SIZE = 0x1000;
|
|
49
|
+
const FLASH_SECTOR_SIZE = 0x1000; // Flash sector size, minimum unit of erase.
|
|
50
50
|
|
|
51
|
-
const SYNC_PACKET = toByteArray(
|
|
51
|
+
const SYNC_PACKET = toByteArray(
|
|
52
|
+
"\x07\x07\x12 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"
|
|
53
|
+
);
|
|
52
54
|
const CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000;
|
|
53
55
|
const ESP8266 = 0x8266;
|
|
54
56
|
const ESP32 = 0x32;
|
|
55
57
|
const ESP32S2 = 0x3252;
|
|
56
58
|
const ESP32S3 = 0x3253;
|
|
57
|
-
const ESP32C3 =
|
|
59
|
+
const ESP32C3 = 0x32c3;
|
|
58
60
|
|
|
59
61
|
// Commands supported by ESP8266 ROM bootloader
|
|
60
62
|
const ESP_FLASH_BEGIN = 0x02;
|
|
@@ -65,33 +67,32 @@ const ESP_MEM_END = 0x06;
|
|
|
65
67
|
const ESP_MEM_DATA = 0x07;
|
|
66
68
|
const ESP_SYNC = 0x08;
|
|
67
69
|
const ESP_WRITE_REG = 0x09;
|
|
68
|
-
const ESP_READ_REG =
|
|
70
|
+
const ESP_READ_REG = 0x0a;
|
|
69
71
|
|
|
70
72
|
// Some comands supported by ESP32 ROM bootloader (or -8266 w/ stub)
|
|
71
|
-
const ESP_SPI_SET_PARAMS =
|
|
72
|
-
const ESP_SPI_ATTACH =
|
|
73
|
-
const ESP_READ_FLASH_SLOW
|
|
74
|
-
const ESP_CHANGE_BAUDRATE =
|
|
75
|
-
const ESP_FLASH_DEFL_BEGIN = 0x10
|
|
76
|
-
const ESP_FLASH_DEFL_DATA
|
|
77
|
-
const ESP_FLASH_DEFL_END
|
|
73
|
+
const ESP_SPI_SET_PARAMS = 0x0b;
|
|
74
|
+
const ESP_SPI_ATTACH = 0x0d;
|
|
75
|
+
const ESP_READ_FLASH_SLOW = 0x0e; // ROM only, much slower than the stub flash read
|
|
76
|
+
const ESP_CHANGE_BAUDRATE = 0x0f;
|
|
77
|
+
const ESP_FLASH_DEFL_BEGIN = 0x10;
|
|
78
|
+
const ESP_FLASH_DEFL_DATA = 0x11;
|
|
79
|
+
const ESP_FLASH_DEFL_END = 0x12;
|
|
78
80
|
const ESP_SPI_FLASH_MD5 = 0x13;
|
|
79
81
|
|
|
80
82
|
// Commands supported by ESP32-S2/S3/C3/C6 ROM bootloader only
|
|
81
83
|
const ESP_GET_SECURITY_INFO = 0x14;
|
|
82
84
|
|
|
83
85
|
// Some commands supported by stub only
|
|
84
|
-
const ESP_ERASE_FLASH =
|
|
85
|
-
const ESP_ERASE_REGION =
|
|
86
|
-
const ESP_READ_FLASH =
|
|
87
|
-
const ESP_RUN_USER_CODE =
|
|
86
|
+
const ESP_ERASE_FLASH = 0xd0;
|
|
87
|
+
const ESP_ERASE_REGION = 0xd1;
|
|
88
|
+
const ESP_READ_FLASH = 0xd2;
|
|
89
|
+
const ESP_RUN_USER_CODE = 0xd3;
|
|
88
90
|
|
|
89
91
|
// Response code(s) sent by ROM
|
|
90
92
|
const ROM_INVALID_RECV_MSG = 0x05;
|
|
91
93
|
|
|
92
94
|
// Initial state for the checksum routine
|
|
93
|
-
const ESP_CHECKSUM_MAGIC =
|
|
94
|
-
|
|
95
|
+
const ESP_CHECKSUM_MAGIC = 0xef;
|
|
95
96
|
|
|
96
97
|
const UART_DATE_REG_ADDR = 0x60000078;
|
|
97
98
|
|
|
@@ -100,123 +101,122 @@ const ESP_RAM_BLOCK = 0x1800;
|
|
|
100
101
|
|
|
101
102
|
// Timeouts
|
|
102
103
|
const DEFAULT_TIMEOUT = 3000;
|
|
103
|
-
const CHIP_ERASE_TIMEOUT = 120000;
|
|
104
|
-
const MAX_TIMEOUT = CHIP_ERASE_TIMEOUT * 2;
|
|
105
|
-
const SYNC_TIMEOUT = 100;
|
|
106
|
-
const ERASE_REGION_TIMEOUT_PER_MB = 30000;
|
|
104
|
+
const CHIP_ERASE_TIMEOUT = 120000; // timeout for full chip erase in ms
|
|
105
|
+
const MAX_TIMEOUT = CHIP_ERASE_TIMEOUT * 2; // longest any command can run in ms
|
|
106
|
+
const SYNC_TIMEOUT = 100; // timeout for syncing with bootloader in ms
|
|
107
|
+
const ERASE_REGION_TIMEOUT_PER_MB = 30000; // timeout (per megabyte) for erasing a region in ms
|
|
107
108
|
const MEM_END_ROM_TIMEOUT = 500;
|
|
108
109
|
|
|
109
|
-
|
|
110
110
|
const supportedChips = {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
111
|
+
ESP8266: {
|
|
112
|
+
chipId: ESP8266,
|
|
113
|
+
chipName: "ESP8266EX",
|
|
114
|
+
magicVal: [0xfff0c101],
|
|
115
|
+
baseFuseAddr: 0x3ff00050,
|
|
116
|
+
macFuseAddr: 0x3ff00050,
|
|
117
|
+
stubFile: "esp8266",
|
|
118
|
+
spiRegBase: 0x60000200,
|
|
119
|
+
spiUsrOffs: 0x1c,
|
|
120
|
+
spiUsr1Offs: 0x20,
|
|
121
|
+
spiUsr2Offs: 0x24,
|
|
122
|
+
spiMosiDlenOffs: null,
|
|
123
|
+
spiMisoDlenOffs: null,
|
|
124
|
+
spiW0Offs: 0x40,
|
|
125
|
+
},
|
|
126
|
+
ESP32: {
|
|
127
|
+
chipId: ESP32,
|
|
128
|
+
chipName: "ESP32",
|
|
129
|
+
magicVal: [0x00f01d83],
|
|
130
|
+
baseFuseAddr: 0x3ff5a000,
|
|
131
|
+
macFuseAddr: 0x3ff5a000,
|
|
132
|
+
stubFile: "esp32",
|
|
133
|
+
spiRegBase: 0x3ff42000,
|
|
134
|
+
spiUsrOffs: 0x1c,
|
|
135
|
+
spiUsr1Offs: 0x20,
|
|
136
|
+
spiUsr2Offs: 0x24,
|
|
137
|
+
spiMosiDlenOffs: 0x28,
|
|
138
|
+
spiMisoDlenOffs: 0x2c,
|
|
139
|
+
spiW0Offs: 0x80,
|
|
140
|
+
},
|
|
141
|
+
ESP32S2: {
|
|
142
|
+
chipId: ESP32S2,
|
|
143
|
+
chipName: "ESP32-S2",
|
|
144
|
+
magicVal: [0x000007c6],
|
|
145
|
+
baseFuseAddr: 0x3f41a000,
|
|
146
|
+
macFuseAddr: 0x3f41a044,
|
|
147
|
+
stubFile: "esp32s2",
|
|
148
|
+
spiRegBase: 0x3f402000,
|
|
149
|
+
spiUsrOffs: 0x18,
|
|
150
|
+
spiUsr1Offs: 0x1c,
|
|
151
|
+
spiUsr2Offs: 0x20,
|
|
152
|
+
spiMosiDlenOffs: 0x24,
|
|
153
|
+
spiMisoDlenOffs: 0x28,
|
|
154
|
+
spiW0Offs: 0x58,
|
|
155
|
+
},
|
|
156
|
+
ESP32S3: {
|
|
157
|
+
chipId: ESP32S3,
|
|
158
|
+
chipName: "ESP32-S3",
|
|
159
|
+
magicVal: [0x9],
|
|
160
|
+
baseFuseAddr: 0x60007000,
|
|
161
|
+
macFuseAddr: 0x60007044,
|
|
162
|
+
stubFile: "esp32s3",
|
|
163
|
+
spiRegBase: 0x60002000,
|
|
164
|
+
spiUsrOffs: 0x18,
|
|
165
|
+
spiUsr1Offs: 0x1c,
|
|
166
|
+
spiUsr2Offs: 0x20,
|
|
167
|
+
spiMosiDlenOffs: 0x24,
|
|
168
|
+
spiMisoDlenOffs: 0x28,
|
|
169
|
+
spiW0Offs: 0x58,
|
|
170
|
+
},
|
|
171
|
+
ESP32C3: {
|
|
172
|
+
chipId: ESP32C3,
|
|
173
|
+
chipName: "ESP32-C3",
|
|
174
|
+
magicVal: [0x6921506f, 0x1b31506f],
|
|
175
|
+
baseFuseAddr: 0x60008800,
|
|
176
|
+
macFuseAddr: 0x60008800 + 0x044,
|
|
177
|
+
stubFile: "esp32c3",
|
|
178
|
+
spiRegBase: 0x60002000,
|
|
179
|
+
spiUsrOffs: 0x18,
|
|
180
|
+
spiUsr1Offs: 0x1c,
|
|
181
|
+
spiUsr2Offs: 0x20,
|
|
182
|
+
spiMosiDlenOffs: 0x24,
|
|
183
|
+
spiMisoDlenOffs: 0x28,
|
|
184
|
+
spiW0Offs: 0x58,
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
187
|
|
|
188
188
|
class EspLoader {
|
|
189
189
|
constructor(params) {
|
|
190
190
|
this._chipfamily = null;
|
|
191
|
-
this.readTimeout = 3000;
|
|
191
|
+
this.readTimeout = 3000; // Arbitrary number for now. This should be set more dynamically in the command() function
|
|
192
192
|
this._efuses = new Array(4).fill(0);
|
|
193
193
|
this._flashsize = 4 * 1024 * 1024;
|
|
194
194
|
if (this.isFunction(params.updateProgress)) {
|
|
195
|
-
this.updateProgress = params.updateProgress
|
|
195
|
+
this.updateProgress = params.updateProgress;
|
|
196
196
|
} else {
|
|
197
|
-
this.updateProgress = null
|
|
197
|
+
this.updateProgress = null;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
if (this.isFunction(params.logMsg)) {
|
|
201
|
-
this.logMsg = params.logMsg
|
|
201
|
+
this.logMsg = params.logMsg;
|
|
202
202
|
} else {
|
|
203
|
-
this.logMsg = console.log
|
|
203
|
+
this.logMsg = console.log;
|
|
204
204
|
}
|
|
205
205
|
this.debug = params.debug;
|
|
206
206
|
if (this.isFunction(params.debugMsg)) {
|
|
207
|
-
this._debugMsg = params.debugMsg
|
|
207
|
+
this._debugMsg = params.debugMsg;
|
|
208
208
|
} else {
|
|
209
|
-
this._debugMsg = this.logMsg()
|
|
209
|
+
this._debugMsg = this.logMsg();
|
|
210
210
|
}
|
|
211
211
|
this.IS_STUB = false;
|
|
212
212
|
this.syncStubDetected = false;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
isFunction(functionObj) {
|
|
216
|
-
return functionObj && {}.toString.call(functionObj) ===
|
|
216
|
+
return functionObj && {}.toString.call(functionObj) === "[object Function]";
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
toHex(value, size=2) {
|
|
219
|
+
toHex(value, size = 2) {
|
|
220
220
|
return "0x" + value.toString(16).toUpperCase().padStart(size, "0");
|
|
221
221
|
}
|
|
222
222
|
|
|
@@ -232,19 +232,19 @@ class EspLoader {
|
|
|
232
232
|
* 0xdb is replaced with 0xdb 0xdd and 0xc0 is replaced with 0xdb 0xdc
|
|
233
233
|
*/
|
|
234
234
|
slipEncode(buffer) {
|
|
235
|
-
let encoded = [
|
|
235
|
+
let encoded = [0xc0];
|
|
236
236
|
for (let byte of buffer) {
|
|
237
|
-
if (byte ==
|
|
238
|
-
encoded = encoded.concat([
|
|
239
|
-
} else if (byte ==
|
|
240
|
-
encoded = encoded.concat([
|
|
237
|
+
if (byte == 0xdb) {
|
|
238
|
+
encoded = encoded.concat([0xdb, 0xdd]);
|
|
239
|
+
} else if (byte == 0xc0) {
|
|
240
|
+
encoded = encoded.concat([0xdb, 0xdc]);
|
|
241
241
|
} else {
|
|
242
242
|
encoded.push(byte);
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
|
-
encoded.push(
|
|
245
|
+
encoded.push(0xc0);
|
|
246
246
|
return encoded;
|
|
247
|
-
}
|
|
247
|
+
}
|
|
248
248
|
|
|
249
249
|
/**
|
|
250
250
|
* @name macAddr
|
|
@@ -259,40 +259,40 @@ class EspLoader {
|
|
|
259
259
|
let oui;
|
|
260
260
|
if (this._chipfamily == ESP8266) {
|
|
261
261
|
if (mac3 != 0) {
|
|
262
|
-
oui = [(mac3 >> 16) &
|
|
263
|
-
} else if (((mac1 >> 16) &
|
|
264
|
-
oui = [0x18,
|
|
265
|
-
} else if (((mac1 >> 16) &
|
|
266
|
-
oui = [
|
|
262
|
+
oui = [(mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff];
|
|
263
|
+
} else if (((mac1 >> 16) & 0xff) == 0) {
|
|
264
|
+
oui = [0x18, 0xfe, 0x34];
|
|
265
|
+
} else if (((mac1 >> 16) & 0xff) == 1) {
|
|
266
|
+
oui = [0xac, 0xd0, 0x74];
|
|
267
267
|
} else {
|
|
268
|
-
throw
|
|
268
|
+
throw "Couldnt determine OUI";
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
macAddr[0] = oui[0];
|
|
272
272
|
macAddr[1] = oui[1];
|
|
273
273
|
macAddr[2] = oui[2];
|
|
274
|
-
macAddr[3] = (mac1 >> 8) &
|
|
275
|
-
macAddr[4] = mac1 &
|
|
276
|
-
macAddr[5] = (mac0 >> 24) &
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
274
|
+
macAddr[3] = (mac1 >> 8) & 0xff;
|
|
275
|
+
macAddr[4] = mac1 & 0xff;
|
|
276
|
+
macAddr[5] = (mac0 >> 24) & 0xff;
|
|
277
|
+
} else if (this._chipfamily == ESP32) {
|
|
278
|
+
macAddr[0] = (mac2 >> 8) & 0xff;
|
|
279
|
+
macAddr[1] = mac2 & 0xff;
|
|
280
|
+
macAddr[2] = (mac1 >> 24) & 0xff;
|
|
281
|
+
macAddr[3] = (mac1 >> 16) & 0xff;
|
|
282
|
+
macAddr[4] = (mac1 >> 8) & 0xff;
|
|
283
|
+
macAddr[5] = mac1 & 0xff;
|
|
284
|
+
} else if ([ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)) {
|
|
285
|
+
macAddr[0] = (mac1 >> 8) & 0xff;
|
|
286
|
+
macAddr[1] = mac1 & 0xff;
|
|
287
|
+
macAddr[2] = (mac0 >> 24) & 0xff;
|
|
288
|
+
macAddr[3] = (mac0 >> 16) & 0xff;
|
|
289
|
+
macAddr[4] = (mac0 >> 8) & 0xff;
|
|
290
|
+
macAddr[5] = mac0 & 0xff;
|
|
291
291
|
} else {
|
|
292
|
-
throw
|
|
292
|
+
throw "Unknown chip family";
|
|
293
293
|
}
|
|
294
294
|
return macAddr;
|
|
295
|
-
}
|
|
295
|
+
}
|
|
296
296
|
|
|
297
297
|
debugMsg(debugLevel, ...values) {
|
|
298
298
|
if (this.debug) {
|
|
@@ -310,7 +310,7 @@ class EspLoader {
|
|
|
310
310
|
for (let i = 0; i < 4; i++) {
|
|
311
311
|
this._efuses[i] = await this.readRegister(chipInfo.macFuseAddr + 4 * i);
|
|
312
312
|
}
|
|
313
|
-
}
|
|
313
|
+
}
|
|
314
314
|
|
|
315
315
|
/**
|
|
316
316
|
* @name readRegister
|
|
@@ -324,26 +324,34 @@ class EspLoader {
|
|
|
324
324
|
await this.command(ESP_READ_REG, packet);
|
|
325
325
|
let [val, data] = await this.getResponse(ESP_READ_REG);
|
|
326
326
|
return val;
|
|
327
|
-
}
|
|
327
|
+
}
|
|
328
328
|
|
|
329
329
|
/**
|
|
330
330
|
* @name writeRegister
|
|
331
331
|
* Write to a register within the ESP chip RAM, returns a 4-element list
|
|
332
332
|
*/
|
|
333
|
-
async writeRegister(
|
|
333
|
+
async writeRegister(
|
|
334
|
+
addr,
|
|
335
|
+
value,
|
|
336
|
+
mask = 0xffffffff,
|
|
337
|
+
delayUs = 0,
|
|
338
|
+
delayAfterUs = 0
|
|
339
|
+
) {
|
|
334
340
|
if (this.debug) {
|
|
335
341
|
this.debugMsg(1, "Writing to Register " + this.toHex(addr, 8));
|
|
336
342
|
}
|
|
337
343
|
let packet = struct.pack("<IIII", addr, value, mask, delayUs);
|
|
338
344
|
if (delayAfterUs > 0) {
|
|
339
|
-
packet = packet.concat(
|
|
345
|
+
packet = packet.concat(
|
|
346
|
+
struct.pack("<IIII", UART_DATE_REG_ADDR, 0, 0, delayAfterUs)
|
|
347
|
+
);
|
|
340
348
|
}
|
|
341
349
|
let returnVal = await this.checkCommand(ESP_WRITE_REG, packet);
|
|
342
350
|
return returnVal;
|
|
343
|
-
}
|
|
351
|
+
}
|
|
344
352
|
|
|
345
353
|
sleep(ms) {
|
|
346
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
354
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
347
355
|
}
|
|
348
356
|
|
|
349
357
|
/**
|
|
@@ -352,10 +360,10 @@ class EspLoader {
|
|
|
352
360
|
*/
|
|
353
361
|
async chipType() {
|
|
354
362
|
if (this._chipfamily === null) {
|
|
355
|
-
this._chipfamily = await this.detectChip()
|
|
363
|
+
this._chipfamily = await this.detectChip();
|
|
356
364
|
}
|
|
357
365
|
return this._chipfamily;
|
|
358
|
-
}
|
|
366
|
+
}
|
|
359
367
|
|
|
360
368
|
getChipInfo(chipId) {
|
|
361
369
|
// Loop through supported chips and return the data for that chip
|
|
@@ -365,7 +373,7 @@ class EspLoader {
|
|
|
365
373
|
}
|
|
366
374
|
}
|
|
367
375
|
|
|
368
|
-
throw
|
|
376
|
+
throw "Chip Id is not Supported";
|
|
369
377
|
}
|
|
370
378
|
|
|
371
379
|
async detectChip() {
|
|
@@ -374,10 +382,10 @@ class EspLoader {
|
|
|
374
382
|
// Loop through magicValues and if the value matches, then the key is the chip ID
|
|
375
383
|
for (const [key, value] of Object.entries(supportedChips)) {
|
|
376
384
|
if (value["magicVal"].includes(chipMagicValue)) {
|
|
377
|
-
return value["chipId"]
|
|
385
|
+
return value["chipId"];
|
|
378
386
|
}
|
|
379
387
|
}
|
|
380
|
-
throw
|
|
388
|
+
throw "Unable to detect Chip";
|
|
381
389
|
}
|
|
382
390
|
|
|
383
391
|
/**
|
|
@@ -395,7 +403,7 @@ class EspLoader {
|
|
|
395
403
|
}
|
|
396
404
|
}
|
|
397
405
|
return chipInfo.chipName;
|
|
398
|
-
}
|
|
406
|
+
}
|
|
399
407
|
|
|
400
408
|
/**
|
|
401
409
|
* @name checkCommand
|
|
@@ -403,27 +411,29 @@ class EspLoader {
|
|
|
403
411
|
* return a tuple with the value and data.
|
|
404
412
|
* See the ESP Serial Protocol for more details on what value/data are
|
|
405
413
|
*/
|
|
406
|
-
async checkCommand(opcode, buffer, checksum=0, timeout=DEFAULT_TIMEOUT) {
|
|
414
|
+
async checkCommand(opcode, buffer, checksum = 0, timeout = DEFAULT_TIMEOUT) {
|
|
407
415
|
timeout = Math.min(timeout, MAX_TIMEOUT);
|
|
408
416
|
await this.command(opcode, buffer, checksum);
|
|
409
417
|
let [value, data] = await this.getResponse(opcode, timeout);
|
|
410
418
|
let statusLen;
|
|
411
419
|
if (data !== null) {
|
|
412
420
|
if (this.IS_STUB) {
|
|
413
|
-
|
|
421
|
+
statusLen = 2;
|
|
414
422
|
} else if (this._chipfamily == ESP8266) {
|
|
415
|
-
|
|
416
|
-
} else if (
|
|
417
|
-
|
|
423
|
+
statusLen = 2;
|
|
424
|
+
} else if (
|
|
425
|
+
[ESP32, ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)
|
|
426
|
+
) {
|
|
427
|
+
statusLen = 4;
|
|
418
428
|
} else {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
429
|
+
if ([2, 4].includes(data.length)) {
|
|
430
|
+
statusLen = data.length;
|
|
431
|
+
}
|
|
422
432
|
}
|
|
423
433
|
}
|
|
424
434
|
|
|
425
435
|
if (data === null || data.length < statusLen) {
|
|
426
|
-
throw
|
|
436
|
+
throw "Didn't get enough status bytes";
|
|
427
437
|
}
|
|
428
438
|
let status = data.slice(-statusLen, data.length);
|
|
429
439
|
data = data.slice(0, -statusLen);
|
|
@@ -434,9 +444,9 @@ class EspLoader {
|
|
|
434
444
|
}
|
|
435
445
|
if (status[0] == 1) {
|
|
436
446
|
if (status[1] == ROM_INVALID_RECV_MSG) {
|
|
437
|
-
throw
|
|
447
|
+
throw "Invalid (unsupported) command " + this.toHex(opcode);
|
|
438
448
|
} else {
|
|
439
|
-
throw
|
|
449
|
+
throw "Command failure error code " + this.toHex(status[1]);
|
|
440
450
|
}
|
|
441
451
|
}
|
|
442
452
|
|
|
@@ -444,33 +454,41 @@ class EspLoader {
|
|
|
444
454
|
return data;
|
|
445
455
|
}
|
|
446
456
|
return value;
|
|
447
|
-
}
|
|
457
|
+
}
|
|
448
458
|
|
|
449
459
|
/**
|
|
450
460
|
* @name timeoutPerMb
|
|
451
461
|
* Scales timeouts which are size-specific
|
|
452
462
|
*/
|
|
453
463
|
timeoutPerMb(secondsPerMb, sizeBytes) {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}
|
|
464
|
+
let result = Math.floor(secondsPerMb * (sizeBytes / 0x1e6));
|
|
465
|
+
if (result < DEFAULT_TIMEOUT) {
|
|
466
|
+
return DEFAULT_TIMEOUT;
|
|
467
|
+
}
|
|
468
|
+
return result;
|
|
469
|
+
}
|
|
460
470
|
|
|
461
471
|
/**
|
|
462
472
|
* @name command
|
|
463
473
|
* Send a slip-encoded, checksummed command over the UART,
|
|
464
474
|
* does not check response
|
|
465
475
|
*/
|
|
466
|
-
async command(opcode, buffer, checksum=0) {
|
|
476
|
+
async command(opcode, buffer, checksum = 0) {
|
|
467
477
|
//inputBuffer = []; // Reset input buffer
|
|
468
478
|
let packet = struct.pack("<BBHI", 0x00, opcode, buffer.length, checksum);
|
|
469
479
|
packet = packet.concat(buffer);
|
|
470
480
|
packet = this.slipEncode(packet);
|
|
471
|
-
this.debugMsg(
|
|
481
|
+
this.debugMsg(
|
|
482
|
+
2,
|
|
483
|
+
"Writing " +
|
|
484
|
+
packet.length +
|
|
485
|
+
" byte" +
|
|
486
|
+
(packet.length == 1 ? "" : "s") +
|
|
487
|
+
":",
|
|
488
|
+
packet
|
|
489
|
+
);
|
|
472
490
|
await this.writeToStream(packet);
|
|
473
|
-
}
|
|
491
|
+
}
|
|
474
492
|
|
|
475
493
|
/**
|
|
476
494
|
* @name connect
|
|
@@ -485,19 +503,19 @@ class EspLoader {
|
|
|
485
503
|
try {
|
|
486
504
|
// support chrome < 86
|
|
487
505
|
await port.open({ baudrate: ESP_ROM_BAUD, baudRate: ESP_ROM_BAUD });
|
|
488
|
-
} catch(e) {
|
|
506
|
+
} catch (e) {
|
|
489
507
|
port = null;
|
|
490
508
|
throw e;
|
|
491
509
|
}
|
|
492
510
|
|
|
493
511
|
const signals = await port.getSignals();
|
|
494
512
|
|
|
495
|
-
this.logMsg("Connected successfully.")
|
|
513
|
+
this.logMsg("Connected successfully.");
|
|
496
514
|
|
|
497
|
-
this.logMsg("Try to reset.")
|
|
515
|
+
this.logMsg("Try to reset.");
|
|
498
516
|
await port.setSignals({ dataTerminalReady: false, requestToSend: true });
|
|
499
517
|
await port.setSignals({ dataTerminalReady: true, requestToSend: false });
|
|
500
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
518
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
501
519
|
|
|
502
520
|
outputStream = port.writable;
|
|
503
521
|
inputStream = port.readable;
|
|
@@ -537,7 +555,7 @@ class EspLoader {
|
|
|
537
555
|
}
|
|
538
556
|
|
|
539
557
|
hexFormatter(bytes) {
|
|
540
|
-
return "[" + bytes.map(value => this.toHex(value)).join(", ") + "]"
|
|
558
|
+
return "[" + bytes.map((value) => this.toHex(value)).join(", ") + "]";
|
|
541
559
|
}
|
|
542
560
|
|
|
543
561
|
/**
|
|
@@ -552,57 +570,86 @@ class EspLoader {
|
|
|
552
570
|
let partialPacket = null;
|
|
553
571
|
let inEscape = false;
|
|
554
572
|
let readBytes = [];
|
|
555
|
-
this.debugMsg(2, "Read Timeout", this.readTimeout)
|
|
573
|
+
this.debugMsg(2, "Read Timeout", this.readTimeout);
|
|
556
574
|
while (true) {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
if (readBytes.length == 0) {
|
|
568
|
-
let waitingFor = partialPacket === null ? "header" : "content";
|
|
569
|
-
this.debugMsg(1, "Timed out waiting for packet " + waitingFor);
|
|
570
|
-
console.error("Timed out waiting for packet " + waitingFor)
|
|
571
|
-
throw new SlipReadError("Timed out waiting for packet " + waitingFor);
|
|
575
|
+
let stamp = Date.now();
|
|
576
|
+
readBytes = [];
|
|
577
|
+
while (Date.now() - stamp < this.readTimeout) {
|
|
578
|
+
if (inputBuffer.length > 0) {
|
|
579
|
+
readBytes.push(inputBuffer.shift());
|
|
580
|
+
break;
|
|
581
|
+
} else {
|
|
582
|
+
await this.sleep(10);
|
|
572
583
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
this.
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
584
|
+
}
|
|
585
|
+
if (readBytes.length == 0) {
|
|
586
|
+
let waitingFor = partialPacket === null ? "header" : "content";
|
|
587
|
+
this.debugMsg(1, "Timed out waiting for packet " + waitingFor);
|
|
588
|
+
console.error("Timed out waiting for packet " + waitingFor);
|
|
589
|
+
throw new SlipReadError("Timed out waiting for packet " + waitingFor);
|
|
590
|
+
}
|
|
591
|
+
this.debugMsg(
|
|
592
|
+
2,
|
|
593
|
+
"Read " + readBytes.length + " bytes: " + this.hexFormatter(readBytes)
|
|
594
|
+
);
|
|
595
|
+
for (let b of readBytes) {
|
|
596
|
+
if (partialPacket === null) {
|
|
597
|
+
// waiting for packet header
|
|
598
|
+
if (b == 0xc0) {
|
|
599
|
+
partialPacket = [];
|
|
600
|
+
} else {
|
|
601
|
+
this.debugMsg(
|
|
602
|
+
1,
|
|
603
|
+
"Read invalid data: " + this.hexFormatter(readBytes)
|
|
604
|
+
);
|
|
605
|
+
this.debugMsg(
|
|
606
|
+
1,
|
|
607
|
+
"Remaining data in serial buffer: " +
|
|
608
|
+
this.hexFormatter(inputBuffer)
|
|
609
|
+
);
|
|
610
|
+
throw new SlipReadError(
|
|
611
|
+
"Invalid head of packet (" + this.toHex(b) + ")"
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
} else if (inEscape) {
|
|
615
|
+
// part-way through escape sequence
|
|
616
|
+
inEscape = false;
|
|
617
|
+
if (b == 0xdc) {
|
|
618
|
+
partialPacket.push(0xc0);
|
|
619
|
+
} else if (b == 0xdd) {
|
|
620
|
+
partialPacket.push(0xdb);
|
|
621
|
+
} else {
|
|
622
|
+
this.debugMsg(
|
|
623
|
+
1,
|
|
624
|
+
"Read invalid data: " + this.hexFormatter(readBytes)
|
|
625
|
+
);
|
|
626
|
+
this.debugMsg(
|
|
627
|
+
1,
|
|
628
|
+
"Remaining data in serial buffer: " +
|
|
629
|
+
this.hexFormatter(inputBuffer)
|
|
630
|
+
);
|
|
631
|
+
throw new SlipReadError(
|
|
632
|
+
"Invalid SLIP escape (0xdb, " + this.toHex(b) + ")"
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
} else if (b == 0xdb) {
|
|
636
|
+
// start of escape sequence
|
|
637
|
+
inEscape = true;
|
|
638
|
+
} else if (b == 0xc0) {
|
|
639
|
+
// end of packet
|
|
640
|
+
this.debugMsg(
|
|
641
|
+
2,
|
|
642
|
+
"Received full packet: " + this.hexFormatter(partialPacket)
|
|
643
|
+
);
|
|
644
|
+
return partialPacket;
|
|
645
|
+
partialPacket = null;
|
|
646
|
+
} else {
|
|
647
|
+
// normal byte in packet
|
|
648
|
+
partialPacket.push(b);
|
|
603
649
|
}
|
|
604
650
|
}
|
|
605
|
-
|
|
651
|
+
}
|
|
652
|
+
return "";
|
|
606
653
|
}
|
|
607
654
|
|
|
608
655
|
/**
|
|
@@ -611,69 +658,71 @@ class EspLoader {
|
|
|
611
658
|
* out the value/data and returns as a tuple of (value, data) where
|
|
612
659
|
* each is a list of bytes
|
|
613
660
|
*/
|
|
614
|
-
async getResponse(opcode, timeout=DEFAULT_TIMEOUT) {
|
|
661
|
+
async getResponse(opcode, timeout = DEFAULT_TIMEOUT) {
|
|
615
662
|
this.readTimeout = timeout;
|
|
616
663
|
let packet;
|
|
617
664
|
let packetLength = 0;
|
|
618
665
|
let resp, opRet, lenRet, val, data;
|
|
619
666
|
for (let i = 0; i < 100; i++) {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
667
|
+
try {
|
|
668
|
+
packet = await this.readPacket();
|
|
669
|
+
} catch (e) {
|
|
670
|
+
this.debugMsg(
|
|
671
|
+
1,
|
|
672
|
+
"Timed out after " + this.readTimeout + " milliseconds"
|
|
673
|
+
);
|
|
674
|
+
return [null, null];
|
|
675
|
+
}
|
|
626
676
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
677
|
+
if (packet.length < 8) {
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
630
680
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
681
|
+
[resp, opRet, lenRet, val] = struct.unpack("<BBHI", packet.slice(0, 8));
|
|
682
|
+
if (resp != 1) {
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
data = packet.slice(8);
|
|
686
|
+
if (opcode == null || opRet == opcode) {
|
|
687
|
+
return [val, data];
|
|
688
|
+
}
|
|
689
|
+
if (data[0] != 0 && data[1] == ROM_INVALID_RECV_MSG) {
|
|
690
|
+
inputBuffer = [];
|
|
691
|
+
throw "Invalid (unsupported) command " + this.toHex(opcode);
|
|
692
|
+
}
|
|
643
693
|
}
|
|
644
|
-
throw
|
|
645
|
-
}
|
|
694
|
+
throw "Response doesn't match request";
|
|
695
|
+
}
|
|
646
696
|
|
|
647
|
-
/**
|
|
697
|
+
/**
|
|
648
698
|
* @name read
|
|
649
699
|
* Read response data and decodes the slip packet.
|
|
650
700
|
* Keeps reading until we hit the timeout or get
|
|
651
701
|
* a packet closing byte
|
|
652
702
|
*/
|
|
653
|
-
async readBuffer(timeout=DEFAULT_TIMEOUT) {
|
|
703
|
+
async readBuffer(timeout = DEFAULT_TIMEOUT) {
|
|
654
704
|
this.readTimeout = timeout;
|
|
655
705
|
let packet;
|
|
656
706
|
try {
|
|
657
707
|
packet = await this.readPacket();
|
|
658
|
-
} catch(e) {
|
|
708
|
+
} catch (e) {
|
|
659
709
|
this.debugMsg(1, "Timed out after " + this.readTimeout + " milliseconds");
|
|
660
710
|
return null;
|
|
661
711
|
}
|
|
662
712
|
|
|
663
713
|
return packet;
|
|
664
|
-
}
|
|
665
|
-
|
|
714
|
+
}
|
|
666
715
|
|
|
667
716
|
/**
|
|
668
717
|
* @name checksum
|
|
669
718
|
* Calculate checksum of a blob, as it is defined by the ROM
|
|
670
719
|
*/
|
|
671
|
-
checksum(data, state=ESP_CHECKSUM_MAGIC) {
|
|
720
|
+
checksum(data, state = ESP_CHECKSUM_MAGIC) {
|
|
672
721
|
for (let b of data) {
|
|
673
722
|
state ^= b;
|
|
674
723
|
}
|
|
675
724
|
return state;
|
|
676
|
-
}
|
|
725
|
+
}
|
|
677
726
|
|
|
678
727
|
setPortBaudRate(baud) {
|
|
679
728
|
if (this.getChromeVersion() < 86) {
|
|
@@ -705,10 +754,14 @@ class EspLoader {
|
|
|
705
754
|
//inputBuffer = [];
|
|
706
755
|
this.logMsg("Changed baud rate to " + baud);
|
|
707
756
|
} catch (e) {
|
|
708
|
-
throw(
|
|
757
|
+
throw (
|
|
758
|
+
"Unable to change the baud rate, please try setting the connection speed from " +
|
|
759
|
+
baud +
|
|
760
|
+
" to 115200 and reconnecting."
|
|
761
|
+
);
|
|
709
762
|
}
|
|
710
763
|
}
|
|
711
|
-
}
|
|
764
|
+
}
|
|
712
765
|
|
|
713
766
|
/**
|
|
714
767
|
* @name sync
|
|
@@ -716,20 +769,20 @@ class EspLoader {
|
|
|
716
769
|
* ESP ROM bootloader, we will retry a few times
|
|
717
770
|
*/
|
|
718
771
|
async sync() {
|
|
719
|
-
this.logMsg("Performing sync...")
|
|
772
|
+
this.logMsg("Performing sync...");
|
|
720
773
|
for (let i = 0; i < 5; i++) {
|
|
721
|
-
inputBuffer = []
|
|
774
|
+
inputBuffer = [];
|
|
722
775
|
let response = await this._sync();
|
|
723
776
|
if (response) {
|
|
724
777
|
await this.sleep(100);
|
|
725
|
-
this.logMsg("Successfully synced.")
|
|
778
|
+
this.logMsg("Successfully synced.");
|
|
726
779
|
return true;
|
|
727
780
|
}
|
|
728
781
|
await this.sleep(100);
|
|
729
782
|
}
|
|
730
783
|
|
|
731
|
-
throw
|
|
732
|
-
}
|
|
784
|
+
throw "Couldn't sync to ESP. Try resetting.";
|
|
785
|
+
}
|
|
733
786
|
|
|
734
787
|
/**
|
|
735
788
|
* @name _sync
|
|
@@ -739,10 +792,10 @@ class EspLoader {
|
|
|
739
792
|
async _sync() {
|
|
740
793
|
await this.command(ESP_SYNC, SYNC_PACKET);
|
|
741
794
|
let [val, data] = await this.getResponse(ESP_SYNC, SYNC_TIMEOUT);
|
|
742
|
-
this.syncStubDetected =
|
|
795
|
+
this.syncStubDetected = val === 0 ? 1 : 0;
|
|
743
796
|
for (let i = 0; i < 8; i++) {
|
|
744
797
|
let [val, data] = await this.getResponse(ESP_SYNC, SYNC_TIMEOUT);
|
|
745
|
-
this.syncStubDetected &=
|
|
798
|
+
this.syncStubDetected &= val === 0 ? 1 : 0;
|
|
746
799
|
if (data === null) {
|
|
747
800
|
continue;
|
|
748
801
|
}
|
|
@@ -751,15 +804,15 @@ class EspLoader {
|
|
|
751
804
|
}
|
|
752
805
|
}
|
|
753
806
|
return false;
|
|
754
|
-
}
|
|
807
|
+
}
|
|
755
808
|
|
|
756
809
|
/**
|
|
757
810
|
* @name getFlashWriteSize
|
|
758
811
|
* Get the Flash write size based on the chip
|
|
759
812
|
*/
|
|
760
813
|
getFlashWriteSize() {
|
|
761
|
-
|
|
762
|
-
}
|
|
814
|
+
return FLASH_WRITE_SIZE;
|
|
815
|
+
}
|
|
763
816
|
|
|
764
817
|
/**
|
|
765
818
|
* @name flashData
|
|
@@ -768,7 +821,7 @@ class EspLoader {
|
|
|
768
821
|
* verify memory. ESP8266 does not have checksum memory verification in
|
|
769
822
|
* ROM
|
|
770
823
|
*/
|
|
771
|
-
async flashData(binaryData, offset=0, part=0) {
|
|
824
|
+
async flashData(binaryData, offset = 0, part = 0) {
|
|
772
825
|
let filesize = binaryData.byteLength;
|
|
773
826
|
this.logMsg("\nWriting data with filesize: " + filesize);
|
|
774
827
|
let blocks = await this.flashBegin(filesize, offset);
|
|
@@ -781,7 +834,7 @@ class EspLoader {
|
|
|
781
834
|
let flashWriteSize = this.getFlashWriteSize();
|
|
782
835
|
|
|
783
836
|
while (filesize - position > 0) {
|
|
784
|
-
let percentage = Math.floor(100 * (seq + 1) / blocks);
|
|
837
|
+
let percentage = Math.floor((100 * (seq + 1)) / blocks);
|
|
785
838
|
/*this.logMsg(
|
|
786
839
|
"Writing at " + this.toHex(address + seq * flashWriteSize, 8) + "... (" + percentage + " %)"
|
|
787
840
|
);*/
|
|
@@ -789,19 +842,27 @@ class EspLoader {
|
|
|
789
842
|
this.updateProgress(part, percentage);
|
|
790
843
|
}
|
|
791
844
|
if (filesize - position >= flashWriteSize) {
|
|
792
|
-
block = Array.from(
|
|
845
|
+
block = Array.from(
|
|
846
|
+
new Uint8Array(binaryData, position, flashWriteSize)
|
|
847
|
+
);
|
|
793
848
|
} else {
|
|
794
849
|
// Pad the last block
|
|
795
|
-
block = Array.from(
|
|
796
|
-
|
|
850
|
+
block = Array.from(
|
|
851
|
+
new Uint8Array(binaryData, position, filesize - position)
|
|
852
|
+
);
|
|
853
|
+
block = block.concat(
|
|
854
|
+
new Array(flashWriteSize - block.length).fill(0xff)
|
|
855
|
+
);
|
|
797
856
|
}
|
|
798
857
|
await this.flashBlock(block, seq);
|
|
799
858
|
seq += 1;
|
|
800
859
|
written += block.length;
|
|
801
860
|
position += flashWriteSize;
|
|
802
861
|
}
|
|
803
|
-
this.logMsg(
|
|
804
|
-
|
|
862
|
+
this.logMsg(
|
|
863
|
+
"Took " + (Date.now() - stamp) + "ms to write " + filesize + " bytes"
|
|
864
|
+
);
|
|
865
|
+
}
|
|
805
866
|
|
|
806
867
|
/**
|
|
807
868
|
* @name flashDeflBegin
|
|
@@ -811,31 +872,34 @@ class EspLoader {
|
|
|
811
872
|
async flashDeflBegin(size, compsize, offset) {
|
|
812
873
|
let params;
|
|
813
874
|
let flashWriteSize = this.getFlashWriteSize();
|
|
814
|
-
let numBlocks = Math.floor(
|
|
875
|
+
let numBlocks = Math.floor(
|
|
876
|
+
(compsize + flashWriteSize - 1) / flashWriteSize
|
|
877
|
+
);
|
|
815
878
|
let eraseBlocks = Math.floor((size + flashWriteSize - 1) / flashWriteSize);
|
|
816
879
|
|
|
817
|
-
let stamp = Date.now()
|
|
880
|
+
let stamp = Date.now();
|
|
818
881
|
let writeSize, timeout;
|
|
819
882
|
if (this.IS_STUB) {
|
|
820
|
-
|
|
821
|
-
|
|
883
|
+
writeSize = size; // stub expects number of bytes here, manages erasing internally
|
|
884
|
+
timeout = DEFAULT_TIMEOUT;
|
|
822
885
|
} else {
|
|
823
|
-
|
|
824
|
-
|
|
886
|
+
writeSize = eraseBlocks * self.FLASH_WRITE_SIZE; // ROM expects rounded up to erase block size
|
|
887
|
+
timeout = this.timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, writeSize);
|
|
825
888
|
}
|
|
826
|
-
this.logMsg("Compressed " + size + " bytes to " + compsize + "...")
|
|
827
|
-
params = struct.pack(
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
889
|
+
this.logMsg("Compressed " + size + " bytes to " + compsize + "...");
|
|
890
|
+
params = struct.pack("<IIII", writeSize, numBlocks, flashWriteSize, offset);
|
|
891
|
+
if (
|
|
892
|
+
[ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily) &&
|
|
893
|
+
!this.IS_STUB
|
|
894
|
+
) {
|
|
895
|
+
params = params.concat(struct.pack("<I", 0));
|
|
832
896
|
}
|
|
833
897
|
|
|
834
898
|
await this.checkCommand(ESP_FLASH_DEFL_BEGIN, params, 0, timeout);
|
|
835
899
|
|
|
836
900
|
if (size != 0 && !this.IS_STUB) {
|
|
837
|
-
|
|
838
|
-
|
|
901
|
+
// (stub erases as it writes, but ROM loaders erase on begin)
|
|
902
|
+
this.logMsg("Took " + (Date.now() - stamp) + "ms to erase flash block");
|
|
839
903
|
}
|
|
840
904
|
return numBlocks;
|
|
841
905
|
}
|
|
@@ -844,49 +908,55 @@ class EspLoader {
|
|
|
844
908
|
* @name flashDeflBlock
|
|
845
909
|
* Write block to flash, send compressed
|
|
846
910
|
*/
|
|
847
|
-
async flashDeflBlock(data, seq, timeout=DEFAULT_TIMEOUT) {
|
|
911
|
+
async flashDeflBlock(data, seq, timeout = DEFAULT_TIMEOUT) {
|
|
848
912
|
await this.checkCommand(
|
|
849
913
|
ESP_FLASH_DEFL_DATA,
|
|
850
914
|
struct.pack("<IIII", data.length, seq, 0, 0).concat(data),
|
|
851
915
|
this.checksum(data),
|
|
852
|
-
timeout
|
|
916
|
+
timeout
|
|
853
917
|
);
|
|
854
|
-
}
|
|
918
|
+
}
|
|
855
919
|
|
|
856
920
|
/**
|
|
857
921
|
* @name flashDeflFinish
|
|
858
922
|
* Write block to flash, send compressed
|
|
859
923
|
*/
|
|
860
|
-
async flashDeflFinish(reboot=false) {
|
|
924
|
+
async flashDeflFinish(reboot = false) {
|
|
861
925
|
if (!reboot && !this.IS_STUB) {
|
|
862
926
|
// skip sending flash_finish to ROM loader, as this
|
|
863
927
|
// exits the bootloader. Stub doesn't do this.
|
|
864
928
|
return;
|
|
865
929
|
}
|
|
866
|
-
let pkt = struct.pack(
|
|
930
|
+
let pkt = struct.pack("<I", reboot ? 0 : 1);
|
|
867
931
|
await this.checkCommand(ESP_FLASH_DEFL_END, pkt);
|
|
868
|
-
}
|
|
932
|
+
}
|
|
869
933
|
|
|
870
934
|
/**
|
|
871
935
|
* @name flashBegin
|
|
872
936
|
* Prepare for flashing by attaching SPI chip and erasing the
|
|
873
937
|
* number of blocks requred.
|
|
874
938
|
*/
|
|
875
|
-
async flashBegin(size=0, offset=0, encrypted=false) {
|
|
939
|
+
async flashBegin(size = 0, offset = 0, encrypted = false) {
|
|
876
940
|
let buffer;
|
|
877
941
|
let flashWriteSize = this.getFlashWriteSize();
|
|
878
942
|
if (!this.IS_STUB) {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
943
|
+
if ([ESP32, ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)) {
|
|
944
|
+
await this.checkCommand(ESP_SPI_ATTACH, new Array(8).fill(0));
|
|
945
|
+
}
|
|
882
946
|
}
|
|
883
947
|
//let flashId = await this.flashId();
|
|
884
948
|
|
|
885
949
|
if (this._chipfamily == ESP32) {
|
|
886
950
|
// We are hardcoded for 4MB flash on ESP32
|
|
887
951
|
buffer = struct.pack(
|
|
888
|
-
|
|
889
|
-
|
|
952
|
+
"<IIIIII",
|
|
953
|
+
0,
|
|
954
|
+
this._flashsize,
|
|
955
|
+
0x10000,
|
|
956
|
+
4096,
|
|
957
|
+
256,
|
|
958
|
+
0xffff
|
|
959
|
+
);
|
|
890
960
|
await this.checkCommand(ESP_SPI_SET_PARAMS, buffer);
|
|
891
961
|
}
|
|
892
962
|
let numBlocks = Math.floor((size + flashWriteSize - 1) / flashWriteSize);
|
|
@@ -900,41 +970,51 @@ class EspLoader {
|
|
|
900
970
|
}
|
|
901
971
|
|
|
902
972
|
let stamp = Date.now();
|
|
903
|
-
buffer = struct.pack(
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
));
|
|
973
|
+
buffer = struct.pack("<IIII", eraseSize, numBlocks, flashWriteSize, offset);
|
|
974
|
+
if (
|
|
975
|
+
[ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily) &&
|
|
976
|
+
!this.IS_STUB
|
|
977
|
+
) {
|
|
978
|
+
buffer = buffer.concat(struct.pack("<I", encrypted ? 1 : 0));
|
|
910
979
|
}
|
|
911
980
|
this.logMsg(
|
|
912
|
-
|
|
981
|
+
"Erase size " +
|
|
982
|
+
eraseSize +
|
|
983
|
+
", blocks " +
|
|
984
|
+
numBlocks +
|
|
985
|
+
", block size " +
|
|
986
|
+
flashWriteSize +
|
|
987
|
+
", offset " +
|
|
988
|
+
this.toHex(offset, 4) +
|
|
989
|
+
", encrypted " +
|
|
990
|
+
(encrypted ? "yes" : "no")
|
|
913
991
|
);
|
|
914
992
|
await this.checkCommand(ESP_FLASH_BEGIN, buffer, 0, timeout);
|
|
915
993
|
if (size != 0 && !this.IS_STUB) {
|
|
916
|
-
this.logMsg(
|
|
994
|
+
this.logMsg(
|
|
995
|
+
"Took " + (Date.now() - stamp) + "ms to erase " + numBlocks + " bytes"
|
|
996
|
+
);
|
|
917
997
|
}
|
|
918
998
|
return numBlocks;
|
|
919
|
-
}
|
|
999
|
+
}
|
|
920
1000
|
|
|
921
1001
|
/**
|
|
922
1002
|
* @name flashBlock
|
|
923
1003
|
* Send one block of data to program into SPI Flash memory
|
|
924
1004
|
*/
|
|
925
|
-
|
|
1005
|
+
async flashBlock(data, seq, timeout = DEFAULT_TIMEOUT) {
|
|
926
1006
|
await this.checkCommand(
|
|
927
1007
|
ESP_FLASH_DATA,
|
|
928
1008
|
struct.pack("<IIII", data.length, seq, 0, 0).concat(data),
|
|
929
1009
|
this.checksum(data),
|
|
930
|
-
timeout
|
|
1010
|
+
timeout
|
|
931
1011
|
);
|
|
932
|
-
}
|
|
1012
|
+
}
|
|
933
1013
|
|
|
934
1014
|
async flashFinish() {
|
|
935
|
-
let buffer = struct.pack(
|
|
1015
|
+
let buffer = struct.pack("<I", 1);
|
|
936
1016
|
await this.checkCommand(ESP_FLASH_END, buffer);
|
|
937
|
-
}
|
|
1017
|
+
}
|
|
938
1018
|
|
|
939
1019
|
/**
|
|
940
1020
|
* @name runSpiflashCommand
|
|
@@ -946,140 +1026,153 @@ class EspLoader {
|
|
|
946
1026
|
* After writing command byte, writes 'data' to MOSI and then
|
|
947
1027
|
* reads back 'read_bits' of reply on MISO. Result is a number.
|
|
948
1028
|
*/
|
|
949
|
-
async runSpiflashCommand(
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
// SPI registers, base address differs ESP32* vs 8266
|
|
961
|
-
const base = chipInfo.spiRegBase
|
|
962
|
-
const SPI_CMD_REG = base + 0x00
|
|
963
|
-
const SPI_ADDR_REG = base + 0x04
|
|
964
|
-
const SPI_USR_REG = base + chipInfo.spiUsrOffs
|
|
965
|
-
const SPI_USR1_REG = base + chipInfo.spiUsr1Offs
|
|
966
|
-
const SPI_USR2_REG = base + chipInfo.spiUsr2Offs
|
|
967
|
-
const SPI_W0_REG = base + chipInfo.spiW0Offs
|
|
968
|
-
|
|
969
|
-
// shift values
|
|
970
|
-
const SPI_USR2_COMMAND_LEN_SHIFT = 28
|
|
971
|
-
const SPI_USR_ADDR_LEN_SHIFT = 26
|
|
972
|
-
|
|
973
|
-
// SPI peripheral "command" bitmasks for SPI_CMD_REG
|
|
974
|
-
const SPI_CMD_USR = (1 << 18);
|
|
975
|
-
|
|
976
|
-
let setDataLengths;
|
|
977
|
-
let flags;
|
|
978
|
-
//following two registers are ESP32 and later chips only
|
|
979
|
-
if (chipInfo.spiMosiDlenOffs != null) {
|
|
980
|
-
// ESP32 and later chips have a more sophisticated way to set up "user" commands
|
|
981
|
-
setDataLengths = async function(mosi_bits, miso_bits) {
|
|
982
|
-
const SPI_MOSI_DLEN_REG = base + chipInfo.spiMosiDlenOffs;
|
|
983
|
-
const SPI_MISO_DLEN_REG = base + chipInfo.spiMisoDlenOffs;
|
|
984
|
-
if (mosi_bits > 0) {
|
|
985
|
-
await this.writeRegister(SPI_MOSI_DLEN_REG, mosi_bits - 1);
|
|
986
|
-
}
|
|
987
|
-
if (miso_bits > 0) {
|
|
988
|
-
await this.writeRegister(SPI_MISO_DLEN_REG, miso_bits - 1);
|
|
989
|
-
}
|
|
990
|
-
flags = 0;
|
|
991
|
-
if (dummyLen > 0) {
|
|
992
|
-
flags |= (dummyLen - 1);
|
|
993
|
-
}
|
|
994
|
-
if (addrLen > 0) {
|
|
995
|
-
flags |= (addrLen - 1) << SPI_USR_ADDR_LEN_SHIFT;
|
|
996
|
-
}
|
|
997
|
-
if (flags) {
|
|
998
|
-
await this.writeRegister(SPI_USR1_REG, flags);
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
} else {
|
|
1002
|
-
setDataLengths = async function (mosi_bits, miso_bits) {
|
|
1003
|
-
const SPI_DATA_LEN_REG = SPI_USR1_REG;
|
|
1004
|
-
const SPI_MOSI_BITLEN_S = 17;
|
|
1005
|
-
const SPI_MISO_BITLEN_S = 8;
|
|
1006
|
-
let mosi_mask = (mosi_bits == 0) ? 0 : (mosi_bits - 1);
|
|
1007
|
-
let miso_mask = (miso_bits == 0) ? 0 : (miso_bits - 1);
|
|
1008
|
-
flags = (miso_mask << SPI_MISO_BITLEN_S) | (mosi_mask << SPI_MOSI_BITLEN_S);
|
|
1009
|
-
if (dummyLen > 0) {
|
|
1010
|
-
flags |= (dummyLen - 1);
|
|
1011
|
-
}
|
|
1012
|
-
if (addrLen > 0) {
|
|
1013
|
-
flags |= (addrLen - 1) << SPI_USR_ADDR_LEN_SHIFT;
|
|
1014
|
-
}
|
|
1015
|
-
await this.writeRegister(SPI_DATA_LEN_REG, flags);
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
setDataLengths = setDataLengths.bind(this);
|
|
1019
|
-
if (readBits > 32) {
|
|
1020
|
-
throw new FatalError("Reading more than 32 bits back from a SPI flash operation is unsupported")
|
|
1021
|
-
}
|
|
1022
|
-
if (data.length > 64) {
|
|
1023
|
-
throw new FatalError("Writing more than 64 bytes of data with one SPI command is unsupported")
|
|
1024
|
-
}
|
|
1029
|
+
async runSpiflashCommand(
|
|
1030
|
+
spiflashCommand,
|
|
1031
|
+
data = [],
|
|
1032
|
+
readBits = 0,
|
|
1033
|
+
addr = null,
|
|
1034
|
+
addrLen = 0,
|
|
1035
|
+
dummyLen = 0
|
|
1036
|
+
) {
|
|
1037
|
+
let chipType = await this.chipType();
|
|
1038
|
+
let chipInfo = this.getChipInfo(chipType);
|
|
1025
1039
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1040
|
+
// SPI_USR register flags
|
|
1041
|
+
const SPI_USR_COMMAND = 1 << 31;
|
|
1042
|
+
const SPI_USR_ADDR = 1 << 30;
|
|
1043
|
+
const SPI_USR_DUMMY = 1 << 29;
|
|
1044
|
+
const SPI_USR_MISO = 1 << 28;
|
|
1045
|
+
const SPI_USR_MOSI = 1 << 27;
|
|
1046
|
+
|
|
1047
|
+
// SPI registers, base address differs ESP32* vs 8266
|
|
1048
|
+
const base = chipInfo.spiRegBase;
|
|
1049
|
+
const SPI_CMD_REG = base + 0x00;
|
|
1050
|
+
const SPI_ADDR_REG = base + 0x04;
|
|
1051
|
+
const SPI_USR_REG = base + chipInfo.spiUsrOffs;
|
|
1052
|
+
const SPI_USR1_REG = base + chipInfo.spiUsr1Offs;
|
|
1053
|
+
const SPI_USR2_REG = base + chipInfo.spiUsr2Offs;
|
|
1054
|
+
const SPI_W0_REG = base + chipInfo.spiW0Offs;
|
|
1055
|
+
|
|
1056
|
+
// shift values
|
|
1057
|
+
const SPI_USR2_COMMAND_LEN_SHIFT = 28;
|
|
1058
|
+
const SPI_USR_ADDR_LEN_SHIFT = 26;
|
|
1059
|
+
|
|
1060
|
+
// SPI peripheral "command" bitmasks for SPI_CMD_REG
|
|
1061
|
+
const SPI_CMD_USR = 1 << 18;
|
|
1062
|
+
|
|
1063
|
+
let setDataLengths;
|
|
1064
|
+
let flags;
|
|
1065
|
+
//following two registers are ESP32 and later chips only
|
|
1066
|
+
if (chipInfo.spiMosiDlenOffs != null) {
|
|
1067
|
+
// ESP32 and later chips have a more sophisticated way to set up "user" commands
|
|
1068
|
+
setDataLengths = async function (mosi_bits, miso_bits) {
|
|
1069
|
+
const SPI_MOSI_DLEN_REG = base + chipInfo.spiMosiDlenOffs;
|
|
1070
|
+
const SPI_MISO_DLEN_REG = base + chipInfo.spiMisoDlenOffs;
|
|
1071
|
+
if (mosi_bits > 0) {
|
|
1072
|
+
await this.writeRegister(SPI_MOSI_DLEN_REG, mosi_bits - 1);
|
|
1035
1073
|
}
|
|
1036
|
-
if (
|
|
1037
|
-
|
|
1074
|
+
if (miso_bits > 0) {
|
|
1075
|
+
await this.writeRegister(SPI_MISO_DLEN_REG, miso_bits - 1);
|
|
1038
1076
|
}
|
|
1077
|
+
flags = 0;
|
|
1039
1078
|
if (dummyLen > 0) {
|
|
1040
|
-
|
|
1079
|
+
flags |= dummyLen - 1;
|
|
1041
1080
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
await this.writeRegister(SPI_USR2_REG,
|
|
1045
|
-
(7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand)
|
|
1046
|
-
if (addr != null && addrLen > 0) {
|
|
1047
|
-
await this.writeRegister(SPI_ADDR_REG, addr);
|
|
1081
|
+
if (addrLen > 0) {
|
|
1082
|
+
flags |= (addrLen - 1) << SPI_USR_ADDR_LEN_SHIFT;
|
|
1048
1083
|
}
|
|
1049
|
-
if (
|
|
1050
|
-
|
|
1051
|
-
} else {
|
|
1052
|
-
data = data.concat(new Array(4 - data.length).fill(0)); // pad to 32-bit multiple
|
|
1053
|
-
let words = struct.unpack("I" * Math.floor(data.length / 4), data);
|
|
1054
|
-
let next_reg = SPI_W0_REG;
|
|
1055
|
-
for (let word of words) {
|
|
1056
|
-
await this.writeRegister(next_reg, word)
|
|
1057
|
-
next_reg += 4;
|
|
1058
|
-
}
|
|
1084
|
+
if (flags) {
|
|
1085
|
+
await this.writeRegister(SPI_USR1_REG, flags);
|
|
1059
1086
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1087
|
+
};
|
|
1088
|
+
} else {
|
|
1089
|
+
setDataLengths = async function (mosi_bits, miso_bits) {
|
|
1090
|
+
const SPI_DATA_LEN_REG = SPI_USR1_REG;
|
|
1091
|
+
const SPI_MOSI_BITLEN_S = 17;
|
|
1092
|
+
const SPI_MISO_BITLEN_S = 8;
|
|
1093
|
+
let mosi_mask = mosi_bits == 0 ? 0 : mosi_bits - 1;
|
|
1094
|
+
let miso_mask = miso_bits == 0 ? 0 : miso_bits - 1;
|
|
1095
|
+
flags =
|
|
1096
|
+
(miso_mask << SPI_MISO_BITLEN_S) | (mosi_mask << SPI_MOSI_BITLEN_S);
|
|
1097
|
+
if (dummyLen > 0) {
|
|
1098
|
+
flags |= dummyLen - 1;
|
|
1099
|
+
}
|
|
1100
|
+
if (addrLen > 0) {
|
|
1101
|
+
flags |= (addrLen - 1) << SPI_USR_ADDR_LEN_SHIFT;
|
|
1069
1102
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1103
|
+
await this.writeRegister(SPI_DATA_LEN_REG, flags);
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
setDataLengths = setDataLengths.bind(this);
|
|
1107
|
+
if (readBits > 32) {
|
|
1108
|
+
throw new FatalError(
|
|
1109
|
+
"Reading more than 32 bits back from a SPI flash operation is unsupported"
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
if (data.length > 64) {
|
|
1113
|
+
throw new FatalError(
|
|
1114
|
+
"Writing more than 64 bytes of data with one SPI command is unsupported"
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1072
1117
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1118
|
+
let dataBits = data.length * 8;
|
|
1119
|
+
let old_spi_usr = await this.readRegister(SPI_USR_REG);
|
|
1120
|
+
let old_spi_usr2 = await this.readRegister(SPI_USR2_REG);
|
|
1121
|
+
flags = SPI_USR_COMMAND;
|
|
1122
|
+
if (readBits > 0) {
|
|
1123
|
+
flags |= SPI_USR_MISO;
|
|
1124
|
+
}
|
|
1125
|
+
if (dataBits > 0) {
|
|
1126
|
+
flags |= SPI_USR_MOSI;
|
|
1127
|
+
}
|
|
1128
|
+
if (addrLen > 0) {
|
|
1129
|
+
flags |= SPI_USR_ADDR;
|
|
1130
|
+
}
|
|
1131
|
+
if (dummyLen > 0) {
|
|
1132
|
+
flags |= SPI_USR_DUMMY;
|
|
1133
|
+
}
|
|
1134
|
+
await setDataLengths(dataBits, readBits);
|
|
1135
|
+
await this.writeRegister(SPI_USR_REG, flags);
|
|
1136
|
+
await this.writeRegister(
|
|
1137
|
+
SPI_USR2_REG,
|
|
1138
|
+
(7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand
|
|
1139
|
+
);
|
|
1140
|
+
if (addr != null && addrLen > 0) {
|
|
1141
|
+
await this.writeRegister(SPI_ADDR_REG, addr);
|
|
1142
|
+
}
|
|
1143
|
+
if (dataBits == 0) {
|
|
1144
|
+
await this.writeRegister(SPI_W0_REG, 0); // clear data register before we read it
|
|
1145
|
+
} else {
|
|
1146
|
+
data = data.concat(new Array(4 - data.length).fill(0)); // pad to 32-bit multiple
|
|
1147
|
+
let words = struct.unpack("I" * Math.floor(data.length / 4), data);
|
|
1148
|
+
let next_reg = SPI_W0_REG;
|
|
1149
|
+
for (let word of words) {
|
|
1150
|
+
await this.writeRegister(next_reg, word);
|
|
1151
|
+
next_reg += 4;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
await this.writeRegister(SPI_CMD_REG, SPI_CMD_USR);
|
|
1078
1155
|
|
|
1079
|
-
|
|
1156
|
+
let waitDone = async function () {
|
|
1157
|
+
for (let i = 0; i < 10; i++) {
|
|
1158
|
+
if (((await this.readRegister(SPI_CMD_REG)) & SPI_CMD_USR) == 0) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
throw new FatalError("SPI command did not complete in time");
|
|
1163
|
+
};
|
|
1164
|
+
waitDone = waitDone.bind(this);
|
|
1165
|
+
await waitDone();
|
|
1166
|
+
|
|
1167
|
+
let status = await this.readRegister(SPI_W0_REG);
|
|
1168
|
+
// restore some SPI controller registers
|
|
1169
|
+
await this.writeRegister(SPI_USR_REG, old_spi_usr);
|
|
1170
|
+
await this.writeRegister(SPI_USR2_REG, old_spi_usr2);
|
|
1171
|
+
return status;
|
|
1172
|
+
}
|
|
1080
1173
|
|
|
1081
1174
|
async flashId() {
|
|
1082
|
-
const SPIFLASH_RDID =
|
|
1175
|
+
const SPIFLASH_RDID = 0x9f;
|
|
1083
1176
|
|
|
1084
1177
|
return await this.runSpiflashCommand(SPIFLASH_RDID, [], 24);
|
|
1085
1178
|
}
|
|
@@ -1104,13 +1197,13 @@ class EspLoader {
|
|
|
1104
1197
|
}
|
|
1105
1198
|
|
|
1106
1199
|
if (numSectors < 2 * headSectors) {
|
|
1107
|
-
return Math.floor((numSectors + 1) / 2 * sectorSize);
|
|
1200
|
+
return Math.floor(((numSectors + 1) / 2) * sectorSize);
|
|
1108
1201
|
}
|
|
1109
1202
|
|
|
1110
1203
|
return (numSectors - headSectors) * sectorSize;
|
|
1111
|
-
}
|
|
1204
|
+
}
|
|
1112
1205
|
|
|
1113
|
-
|
|
1206
|
+
/**
|
|
1114
1207
|
* @name memBegin (592)
|
|
1115
1208
|
* Start downloading an application image to RAM
|
|
1116
1209
|
*/
|
|
@@ -1121,17 +1214,30 @@ class EspLoader {
|
|
|
1121
1214
|
let load_end = offset + size;
|
|
1122
1215
|
for (let [start, end] of [
|
|
1123
1216
|
[stub.data_start, stub.data_start + stub.data.length],
|
|
1124
|
-
[stub.text_start, stub.text_start + stub.text.length]
|
|
1125
|
-
) {
|
|
1217
|
+
[stub.text_start, stub.text_start + stub.text.length],
|
|
1218
|
+
]) {
|
|
1126
1219
|
if (load_start < end && load_end > start) {
|
|
1127
|
-
throw
|
|
1128
|
-
|
|
1129
|
-
|
|
1220
|
+
throw (
|
|
1221
|
+
"Software loader is resident at " +
|
|
1222
|
+
this.toHex(start, 8) +
|
|
1223
|
+
"-" +
|
|
1224
|
+
this.toHex(end, 8) +
|
|
1225
|
+
". " +
|
|
1226
|
+
"Can't load binary at overlapping address range " +
|
|
1227
|
+
this.toHex(load_start, 8) +
|
|
1228
|
+
"-" +
|
|
1229
|
+
this.toHex(load_end, 8) +
|
|
1230
|
+
". " +
|
|
1231
|
+
"Try changing the binary loading address."
|
|
1232
|
+
);
|
|
1130
1233
|
}
|
|
1131
1234
|
}
|
|
1132
1235
|
}
|
|
1133
1236
|
|
|
1134
|
-
return this.checkCommand(
|
|
1237
|
+
return this.checkCommand(
|
|
1238
|
+
ESP_MEM_BEGIN,
|
|
1239
|
+
struct.pack("<IIII", size, blocks, blocksize, offset)
|
|
1240
|
+
);
|
|
1135
1241
|
}
|
|
1136
1242
|
|
|
1137
1243
|
/**
|
|
@@ -1141,7 +1247,7 @@ class EspLoader {
|
|
|
1141
1247
|
async memBlock(data, seq) {
|
|
1142
1248
|
return await this.checkCommand(
|
|
1143
1249
|
ESP_MEM_DATA,
|
|
1144
|
-
struct.pack(
|
|
1250
|
+
struct.pack("<IIII", data.length, seq, 0, 0).concat(data),
|
|
1145
1251
|
this.checksum(data)
|
|
1146
1252
|
);
|
|
1147
1253
|
}
|
|
@@ -1155,14 +1261,14 @@ class EspLoader {
|
|
|
1155
1261
|
* before the transmit FIFO is empty. So in these cases we set a short timeout and
|
|
1156
1262
|
* ignore errors.
|
|
1157
1263
|
*/
|
|
1158
|
-
async memFinish(entrypoint=0) {
|
|
1264
|
+
async memFinish(entrypoint = 0) {
|
|
1159
1265
|
let timeout = this.IS_STUB ? DEFAULT_TIMEOUT : MEM_END_ROM_TIMEOUT;
|
|
1160
|
-
let data = struct.pack(
|
|
1266
|
+
let data = struct.pack("<II", parseInt(entrypoint == 0), entrypoint);
|
|
1161
1267
|
try {
|
|
1162
1268
|
return await this.checkCommand(ESP_MEM_END, data, 0, timeout);
|
|
1163
1269
|
} catch (e) {
|
|
1164
1270
|
if (this.IS_STUB) {
|
|
1165
|
-
throw
|
|
1271
|
+
throw e;
|
|
1166
1272
|
}
|
|
1167
1273
|
}
|
|
1168
1274
|
}
|
|
@@ -1171,7 +1277,7 @@ class EspLoader {
|
|
|
1171
1277
|
let chipType = await this.chipType();
|
|
1172
1278
|
let chipInfo = this.getChipInfo(chipType);
|
|
1173
1279
|
|
|
1174
|
-
let response = await fetch(
|
|
1280
|
+
let response = await fetch("stubs/" + chipInfo.stubFile + ".json");
|
|
1175
1281
|
let stubcode = await response.json();
|
|
1176
1282
|
|
|
1177
1283
|
// Base64 decode the text and data
|
|
@@ -1188,14 +1294,14 @@ class EspLoader {
|
|
|
1188
1294
|
// Based on current chip, we return the appropriate Rom class
|
|
1189
1295
|
}
|
|
1190
1296
|
|
|
1191
|
-
async runStub(stub=null) {
|
|
1297
|
+
async runStub(stub = null) {
|
|
1192
1298
|
if (stub === null) {
|
|
1193
1299
|
stub = await this.getStubCode();
|
|
1194
1300
|
}
|
|
1195
1301
|
|
|
1196
1302
|
if (this.syncStubDetected || this.IS_STUB) {
|
|
1197
|
-
|
|
1198
|
-
|
|
1303
|
+
this.logMsg("Stub is already running. No upload is necessary.");
|
|
1304
|
+
return this.stubClass;
|
|
1199
1305
|
}
|
|
1200
1306
|
|
|
1201
1307
|
let ramBlock = ESP_RAM_BLOCK;
|
|
@@ -1205,8 +1311,8 @@ class EspLoader {
|
|
|
1205
1311
|
}
|
|
1206
1312
|
|
|
1207
1313
|
// Upload
|
|
1208
|
-
this.logMsg("Uploading stub...")
|
|
1209
|
-
for (let field of [
|
|
1314
|
+
this.logMsg("Uploading stub...");
|
|
1315
|
+
for (let field of ["text", "data"]) {
|
|
1210
1316
|
if (Object.keys(stub).includes(field)) {
|
|
1211
1317
|
let offset = stub[field + "_start"];
|
|
1212
1318
|
let length = stub[field].length;
|
|
@@ -1222,13 +1328,13 @@ class EspLoader {
|
|
|
1222
1328
|
}
|
|
1223
1329
|
}
|
|
1224
1330
|
}
|
|
1225
|
-
this.logMsg("Running stub...")
|
|
1226
|
-
await this.memFinish(stub[
|
|
1331
|
+
this.logMsg("Running stub...");
|
|
1332
|
+
await this.memFinish(stub["entry"]);
|
|
1227
1333
|
|
|
1228
1334
|
let p = await this.readBuffer(500);
|
|
1229
1335
|
p = String.fromCharCode(...p);
|
|
1230
1336
|
|
|
1231
|
-
if (p !=
|
|
1337
|
+
if (p != "OHAI") {
|
|
1232
1338
|
throw "Failed to start stub. Unexpected response: " + p;
|
|
1233
1339
|
}
|
|
1234
1340
|
this.logMsg("Stub is now running...");
|
|
@@ -1258,35 +1364,33 @@ class EspStubLoader extends EspLoader {
|
|
|
1258
1364
|
*/
|
|
1259
1365
|
async eraseFlash() {
|
|
1260
1366
|
await this.checkCommand(ESP_ERASE_FLASH, [], 0, CHIP_ERASE_TIMEOUT);
|
|
1261
|
-
}
|
|
1367
|
+
}
|
|
1262
1368
|
|
|
1263
1369
|
/**
|
|
1264
1370
|
* @name getFlashWriteSize
|
|
1265
1371
|
* Get the Flash write size based on the chip
|
|
1266
1372
|
*/
|
|
1267
1373
|
getFlashWriteSize() {
|
|
1268
|
-
|
|
1269
|
-
}
|
|
1374
|
+
return STUBLOADER_FLASH_WRITE_SIZE;
|
|
1375
|
+
}
|
|
1270
1376
|
}
|
|
1271
1377
|
|
|
1272
|
-
class Esp32StubLoader extends EspStubLoader {
|
|
1273
|
-
|
|
1274
|
-
}
|
|
1378
|
+
class Esp32StubLoader extends EspStubLoader {}
|
|
1275
1379
|
|
|
1276
1380
|
/*
|
|
1277
1381
|
Represents error when NVS Partition size given is insufficient
|
|
1278
1382
|
to accomodate the data in the given csv file
|
|
1279
1383
|
*/
|
|
1280
1384
|
class SlipReadError extends Error {
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1385
|
+
constructor(message) {
|
|
1386
|
+
super(message);
|
|
1387
|
+
this.name = "SlipReadError";
|
|
1388
|
+
}
|
|
1285
1389
|
}
|
|
1286
1390
|
|
|
1287
1391
|
class FatalError extends Error {
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1392
|
+
constructor(message) {
|
|
1393
|
+
super(message);
|
|
1394
|
+
this.name = "FatalError";
|
|
1395
|
+
}
|
|
1292
1396
|
}
|