UNPKG

7.16 kBJavaScriptView Raw
1import { Transport, ESPLoader } from "esptool-js";
2import { sleep } from "./util/sleep";
3const resetTransport = async (transport) => {
4 await transport.device.setSignals({
5 dataTerminalReady: false,
6 requestToSend: true,
7 });
8 await sleep(250);
9 await transport.device.setSignals({
10 dataTerminalReady: false,
11 requestToSend: false,
12 });
13 await sleep(250);
14};
15export const flash = async (onEvent, port, manifestPath, manifest, eraseFirst) => {
16 let build;
17 let chipFamily;
18 const fireStateEvent = (stateUpdate) => onEvent({
19 ...stateUpdate,
20 manifest,
21 build,
22 chipFamily,
23 });
24 const transport = new Transport(port);
25 const esploader = new ESPLoader({
26 transport,
27 baudrate: 115200,
28 romBaudrate: 115200,
29 enableTracing: false,
30 });
31 // For debugging
32 window.esploader = esploader;
33 fireStateEvent({
34 state: "initializing" /* FlashStateType.INITIALIZING */,
35 message: "Initializing...",
36 details: { done: false },
37 });
38 try {
39 await esploader.main();
40 await esploader.flashId();
41 }
42 catch (err) {
43 console.error(err);
44 fireStateEvent({
45 state: "error" /* FlashStateType.ERROR */,
46 message: "Failed to initialize. Try resetting your device or holding the BOOT button while clicking INSTALL.",
47 details: { error: "failed_initialize" /* FlashError.FAILED_INITIALIZING */, details: err },
48 });
49 await resetTransport(transport);
50 await transport.disconnect();
51 return;
52 }
53 chipFamily = esploader.chip.CHIP_NAME;
54 if (!esploader.chip.ROM_TEXT) {
55 fireStateEvent({
56 state: "error" /* FlashStateType.ERROR */,
57 message: `Chip ${chipFamily} is not supported`,
58 details: {
59 error: "not_supported" /* FlashError.NOT_SUPPORTED */,
60 details: `Chip ${chipFamily} is not supported`,
61 },
62 });
63 await resetTransport(transport);
64 await transport.disconnect();
65 return;
66 }
67 fireStateEvent({
68 state: "initializing" /* FlashStateType.INITIALIZING */,
69 message: `Initialized. Found ${chipFamily}`,
70 details: { done: true },
71 });
72 build = manifest.builds.find((b) => b.chipFamily === chipFamily);
73 if (!build) {
74 fireStateEvent({
75 state: "error" /* FlashStateType.ERROR */,
76 message: `Your ${chipFamily} board is not supported.`,
77 details: { error: "not_supported" /* FlashError.NOT_SUPPORTED */, details: chipFamily },
78 });
79 await resetTransport(transport);
80 await transport.disconnect();
81 return;
82 }
83 fireStateEvent({
84 state: "preparing" /* FlashStateType.PREPARING */,
85 message: "Preparing installation...",
86 details: { done: false },
87 });
88 const manifestURL = new URL(manifestPath, location.toString()).toString();
89 const filePromises = build.parts.map(async (part) => {
90 const url = new URL(part.path, manifestURL).toString();
91 const resp = await fetch(url);
92 if (!resp.ok) {
93 throw new Error(`Downlading firmware ${part.path} failed: ${resp.status}`);
94 }
95 const reader = new FileReader();
96 const blob = await resp.blob();
97 return new Promise((resolve) => {
98 reader.addEventListener("load", () => resolve(reader.result));
99 reader.readAsBinaryString(blob);
100 });
101 });
102 const fileArray = [];
103 let totalSize = 0;
104 for (let part = 0; part < filePromises.length; part++) {
105 try {
106 const data = await filePromises[part];
107 fileArray.push({ data, address: build.parts[part].offset });
108 totalSize += data.length;
109 }
110 catch (err) {
111 fireStateEvent({
112 state: "error" /* FlashStateType.ERROR */,
113 message: err.message,
114 details: {
115 error: "failed_firmware_download" /* FlashError.FAILED_FIRMWARE_DOWNLOAD */,
116 details: err.message,
117 },
118 });
119 await resetTransport(transport);
120 await transport.disconnect();
121 return;
122 }
123 }
124 fireStateEvent({
125 state: "preparing" /* FlashStateType.PREPARING */,
126 message: "Installation prepared",
127 details: { done: true },
128 });
129 if (eraseFirst) {
130 fireStateEvent({
131 state: "erasing" /* FlashStateType.ERASING */,
132 message: "Erasing device...",
133 details: { done: false },
134 });
135 await esploader.eraseFlash();
136 fireStateEvent({
137 state: "erasing" /* FlashStateType.ERASING */,
138 message: "Device erased",
139 details: { done: true },
140 });
141 }
142 fireStateEvent({
143 state: "writing" /* FlashStateType.WRITING */,
144 message: `Writing progress: 0%`,
145 details: {
146 bytesTotal: totalSize,
147 bytesWritten: 0,
148 percentage: 0,
149 },
150 });
151 let totalWritten = 0;
152 try {
153 await esploader.writeFlash({
154 fileArray,
155 flashSize: "keep",
156 flashMode: "keep",
157 flashFreq: "keep",
158 eraseAll: false,
159 compress: true,
160 // report progress
161 reportProgress: (fileIndex, written, total) => {
162 const uncompressedWritten = (written / total) * fileArray[fileIndex].data.length;
163 const newPct = Math.floor(((totalWritten + uncompressedWritten) / totalSize) * 100);
164 // we're done with this file
165 if (written === total) {
166 totalWritten += uncompressedWritten;
167 return;
168 }
169 fireStateEvent({
170 state: "writing" /* FlashStateType.WRITING */,
171 message: `Writing progress: ${newPct}%`,
172 details: {
173 bytesTotal: totalSize,
174 bytesWritten: totalWritten + written,
175 percentage: newPct,
176 },
177 });
178 },
179 });
180 }
181 catch (err) {
182 fireStateEvent({
183 state: "error" /* FlashStateType.ERROR */,
184 message: err.message,
185 details: { error: "write_failed" /* FlashError.WRITE_FAILED */, details: err },
186 });
187 await resetTransport(transport);
188 await transport.disconnect();
189 return;
190 }
191 fireStateEvent({
192 state: "writing" /* FlashStateType.WRITING */,
193 message: "Writing complete",
194 details: {
195 bytesTotal: totalSize,
196 bytesWritten: totalWritten,
197 percentage: 100,
198 },
199 });
200 await sleep(100);
201 console.log("HARD RESET");
202 await resetTransport(transport);
203 console.log("DISCONNECT");
204 await transport.disconnect();
205 fireStateEvent({
206 state: "finished" /* FlashStateType.FINISHED */,
207 message: "All done!",
208 });
209};