161 lines
No EOL
3.7 KiB
TypeScript
161 lines
No EOL
3.7 KiB
TypeScript
import { ESPLoader, Transport, type FlashOptions } from 'esptool-js';
|
|
import { serial } from "web-serial-polyfill";
|
|
|
|
|
|
|
|
|
|
export const useEspFlasher = (term) => {
|
|
const isConnected = ref(false);
|
|
const flashProgress = ref(0);
|
|
const status = ref('');
|
|
const error = ref('');
|
|
|
|
const espLoaderTerminal = {
|
|
clean() {
|
|
term.clear();
|
|
},
|
|
writeLine(data) {
|
|
term.writeln(data);
|
|
},
|
|
write(data) {
|
|
term.write(data);
|
|
},
|
|
};
|
|
|
|
let port = null;
|
|
let espLoader: ESPLoader = null;
|
|
let transport: Transport;
|
|
|
|
const SERIAL_FILTERS: SerialPortFilter[] = [
|
|
{ usbVendorId: 0x1a86 }, // QinHeng Electronics CH340
|
|
{ usbVendorId: 0x303a } // Espressif USB JTAG/serial debug unit
|
|
];
|
|
|
|
const connect = async () => {
|
|
try {
|
|
if (transport) {
|
|
await disconnect();
|
|
}
|
|
const serialLib = !navigator.serial && navigator.usb ? serial : navigator.serial;
|
|
|
|
if (port === null) {
|
|
port = await serialLib.requestPort({
|
|
filters: SERIAL_FILTERS
|
|
});
|
|
|
|
// await port.open({ baudRate: 115200 });
|
|
|
|
transport = new Transport(port, true);
|
|
}
|
|
|
|
espLoader = new ESPLoader({
|
|
transport,
|
|
baudrate: 115200,
|
|
terminal: espLoaderTerminal,
|
|
logger: (message: string) => {
|
|
status.value = "LOG: " + message;
|
|
}
|
|
});
|
|
|
|
// await espLoader.connect();
|
|
// await espLoader.sync();
|
|
|
|
const chipInfo = await espLoader.main();
|
|
status.value = `Connected to ${chipInfo}`;
|
|
|
|
// await espLoader.loadStub();
|
|
|
|
isConnected.value = true;
|
|
error.value = '';
|
|
} catch (err: any) {
|
|
error.value = err.message;
|
|
isConnected.value = false;
|
|
await disconnect();
|
|
}
|
|
};
|
|
|
|
const flash = async (manifest: FirmwareManifest, eraseFlash: boolean) => {
|
|
if (!espLoader || !isConnected.value) {
|
|
error.value = 'Not connected to device';
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const build = manifest.builds[0];
|
|
|
|
if (eraseFlash) {
|
|
status.value = 'Erasing flash...';
|
|
await espLoader.eraseFlash();
|
|
}
|
|
|
|
const fileArray = [];
|
|
|
|
status.value = `Flashing ${manifest.name}...`;
|
|
|
|
for (const part of build.parts) {
|
|
const response = await fetch(part.path);
|
|
const uint8Array = new Uint8Array(await response.arrayBuffer());
|
|
const buffer = Array.from(uint8Array)
|
|
.map(byte => String.fromCharCode(byte))
|
|
.join('');
|
|
fileArray.push({ data: buffer, address: part.offset });
|
|
}
|
|
|
|
const flashOptions: FlashOptions = {
|
|
fileArray: fileArray,
|
|
flashSize: "keep",
|
|
eraseAll: false,
|
|
compress: true,
|
|
reportProgress: (fileIndex, written, total) => {
|
|
flashProgress.value = Math.round((written / total) * 100);
|
|
},
|
|
} as FlashOptions;
|
|
|
|
await espLoader.writeFlash(
|
|
flashOptions
|
|
);
|
|
|
|
status.value = 'Flash complete!';
|
|
flashProgress.value = 100;
|
|
espLoader.hardReset();
|
|
} catch (err: any) {
|
|
error.value = err.message;
|
|
}
|
|
};
|
|
|
|
const disconnect = async () => {
|
|
if (transport) {
|
|
await transport.disconnect();
|
|
transport = null;
|
|
}
|
|
if (espLoader) {
|
|
espLoader = null;
|
|
}
|
|
isConnected.value = false;
|
|
status.value = '';
|
|
port = null;
|
|
flashProgress.value = 0;
|
|
};
|
|
|
|
const reset = async() => {
|
|
// console.log(transport)
|
|
// // if (transport) {
|
|
// await transport.setDTR(false);
|
|
// await new Promise((resolve) => setTimeout(resolve, 100));
|
|
// await transport.setDTR(true);
|
|
// //}
|
|
await espLoader.hardReset();
|
|
await disconnect();
|
|
}
|
|
|
|
return {
|
|
isConnected,
|
|
flashProgress,
|
|
status,
|
|
error,
|
|
connect,
|
|
flash,
|
|
disconnect,
|
|
reset
|
|
};
|
|
}; |