UNPKG

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