UNPKG

6.69 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 fireStateEvent({
55 state: "initializing" /* FlashStateType.INITIALIZING */,
56 message: `Initialized. Found ${chipFamily}`,
57 details: { done: true },
58 });
59 build = manifest.builds.find((b) => b.chipFamily === chipFamily);
60 if (!build) {
61 fireStateEvent({
62 state: "error" /* FlashStateType.ERROR */,
63 message: `Your ${chipFamily} board is not supported.`,
64 details: { error: "not_supported" /* FlashError.NOT_SUPPORTED */, details: chipFamily },
65 });
66 await resetTransport(transport);
67 await transport.disconnect();
68 return;
69 }
70 fireStateEvent({
71 state: "preparing" /* FlashStateType.PREPARING */,
72 message: "Preparing installation...",
73 details: { done: false },
74 });
75 const manifestURL = new URL(manifestPath, location.toString()).toString();
76 const filePromises = build.parts.map(async (part) => {
77 const url = new URL(part.path, manifestURL).toString();
78 const resp = await fetch(url);
79 if (!resp.ok) {
80 throw new Error(`Downlading firmware ${part.path} failed: ${resp.status}`);
81 }
82 const reader = new FileReader();
83 const blob = await resp.blob();
84 return new Promise((resolve) => {
85 reader.addEventListener("load", () => resolve(reader.result));
86 reader.readAsBinaryString(blob);
87 });
88 });
89 const fileArray = [];
90 let totalSize = 0;
91 for (let part = 0; part < filePromises.length; part++) {
92 try {
93 const data = await filePromises[part];
94 fileArray.push({ data, address: build.parts[part].offset });
95 totalSize += data.length;
96 }
97 catch (err) {
98 fireStateEvent({
99 state: "error" /* FlashStateType.ERROR */,
100 message: err.message,
101 details: {
102 error: "failed_firmware_download" /* FlashError.FAILED_FIRMWARE_DOWNLOAD */,
103 details: err.message,
104 },
105 });
106 await resetTransport(transport);
107 await transport.disconnect();
108 return;
109 }
110 }
111 fireStateEvent({
112 state: "preparing" /* FlashStateType.PREPARING */,
113 message: "Installation prepared",
114 details: { done: true },
115 });
116 if (eraseFirst) {
117 fireStateEvent({
118 state: "erasing" /* FlashStateType.ERASING */,
119 message: "Erasing device...",
120 details: { done: false },
121 });
122 await esploader.eraseFlash();
123 fireStateEvent({
124 state: "erasing" /* FlashStateType.ERASING */,
125 message: "Device erased",
126 details: { done: true },
127 });
128 }
129 fireStateEvent({
130 state: "writing" /* FlashStateType.WRITING */,
131 message: `Writing progress: 0%`,
132 details: {
133 bytesTotal: totalSize,
134 bytesWritten: 0,
135 percentage: 0,
136 },
137 });
138 let totalWritten = 0;
139 try {
140 await esploader.writeFlash({
141 fileArray,
142 flashSize: "keep",
143 flashMode: "keep",
144 flashFreq: "keep",
145 eraseAll: false,
146 compress: true,
147 // report progress
148 reportProgress: (fileIndex, written, total) => {
149 const uncompressedWritten = (written / total) * fileArray[fileIndex].data.length;
150 const newPct = Math.floor(((totalWritten + uncompressedWritten) / totalSize) * 100);
151 // we're done with this file
152 if (written === total) {
153 totalWritten += uncompressedWritten;
154 return;
155 }
156 fireStateEvent({
157 state: "writing" /* FlashStateType.WRITING */,
158 message: `Writing progress: ${newPct}%`,
159 details: {
160 bytesTotal: totalSize,
161 bytesWritten: totalWritten + written,
162 percentage: newPct,
163 },
164 });
165 },
166 });
167 }
168 catch (err) {
169 fireStateEvent({
170 state: "error" /* FlashStateType.ERROR */,
171 message: err.message,
172 details: { error: "write_failed" /* FlashError.WRITE_FAILED */, details: err },
173 });
174 await resetTransport(transport);
175 await transport.disconnect();
176 return;
177 }
178 fireStateEvent({
179 state: "writing" /* FlashStateType.WRITING */,
180 message: "Writing complete",
181 details: {
182 bytesTotal: totalSize,
183 bytesWritten: totalWritten,
184 percentage: 100,
185 },
186 });
187 await sleep(100);
188 console.log("HARD RESET");
189 await resetTransport(transport);
190 console.log("DISCONNECT");
191 await transport.disconnect();
192 fireStateEvent({
193 state: "finished" /* FlashStateType.FINISHED */,
194 message: "All done!",
195 });
196};