web-flasher-ng/composables/useEspFlasher.ts

161 lines
3.7 KiB
TypeScript
Raw Permalink Normal View History

2024-12-07 16:48:13 +00:00
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
};
};