|
|
@ -10,6 +10,7 @@ import type { ConfigPreset } from '../stores/appStore'; |
|
|
import type { Device } from '../stores/deviceStore'; |
|
|
import type { Device } from '../stores/deviceStore'; |
|
|
import { FirmwareVersion, deviceModels } from '@app/components/PageComponents/Flasher/FlashSettings'; |
|
|
import { FirmwareVersion, deviceModels } from '@app/components/PageComponents/Flasher/FlashSettings'; |
|
|
import { storeInDb, loadFromDb } from './FirmwareDb'; |
|
|
import { storeInDb, loadFromDb } from './FirmwareDb'; |
|
|
|
|
|
import * as esptooljs from "esptool-js"; |
|
|
|
|
|
|
|
|
type DeviceFlashingState = "doNotFlash" | "doFlash" | "idle" | "preparing" | "erasing" | "flashing" | "config" | "done" | "aborted" | "failed"; |
|
|
type DeviceFlashingState = "doNotFlash" | "doFlash" | "idle" | "preparing" | "erasing" | "flashing" | "config" | "done" | "aborted" | "failed"; |
|
|
export type OverallFlashingState = "idle" | "downloading" | "busy" | "waiting"; |
|
|
export type OverallFlashingState = "idle" | "downloading" | "busy" | "waiting"; |
|
|
@ -175,7 +176,7 @@ export class FlashOperation { |
|
|
|
|
|
|
|
|
public state: FlashState = { progress: 0, state: "idle" }; |
|
|
public state: FlashState = { progress: 0, state: "idle" }; |
|
|
public errorReason?: string; |
|
|
public errorReason?: string; |
|
|
private loader?: EspLoader; |
|
|
private loader?: esptooljs.ESPLoader; |
|
|
|
|
|
|
|
|
public constructor(public device: Device, public config: Protobuf.LocalConfig, public callback: (operation: FlashOperation) => void) { |
|
|
public constructor(public device: Device, public config: Protobuf.LocalConfig, public callback: (operation: FlashOperation) => void) { |
|
|
|
|
|
|
|
|
@ -192,7 +193,7 @@ export class FlashOperation { |
|
|
public async flashAndConfigDevice() { |
|
|
public async flashAndConfigDevice() { |
|
|
try { |
|
|
try { |
|
|
await this.flash(); |
|
|
await this.flash(); |
|
|
await this.setConfig(); |
|
|
// await this.setConfig();
|
|
|
this.setState("done"); |
|
|
this.setState("done"); |
|
|
} |
|
|
} |
|
|
catch(e) { |
|
|
catch(e) { |
|
|
@ -206,8 +207,8 @@ export class FlashOperation { |
|
|
const installedVersion = this.device.hardware.firmwareVersion; |
|
|
const installedVersion = this.device.hardware.firmwareVersion; |
|
|
console.log(`Installed firmware verson: ${installedVersion}`); |
|
|
console.log(`Installed firmware verson: ${installedVersion}`); |
|
|
const update = !fullFlash && this.device.nodes.get(this.device.hardware.myNodeNum) !== undefined ; |
|
|
const update = !fullFlash && this.device.nodes.get(this.device.hardware.myNodeNum) !== undefined ; |
|
|
if(update && installedVersion == firmwareToUse.tag) |
|
|
// if(update && installedVersion == firmwareToUse.tag)
|
|
|
return; |
|
|
// return;
|
|
|
|
|
|
|
|
|
const port = await (this.device.connection! as ISerialConnection).disconnect(); |
|
|
const port = await (this.device.connection! as ISerialConnection).disconnect(); |
|
|
if(port === undefined) |
|
|
if(port === undefined) |
|
|
@ -218,37 +219,57 @@ export class FlashOperation { |
|
|
const info = port.getInfo(); |
|
|
const info = port.getInfo(); |
|
|
console.log(`Device info: vendor ${info.usbVendorId}, product ${info.usbProductId}`); |
|
|
console.log(`Device info: vendor ${info.usbVendorId}, product ${info.usbProductId}`); |
|
|
const sections = await getFirmwareSections(deviceModel, update); |
|
|
const sections = await getFirmwareSections(deviceModel, update); |
|
|
await port!.open({baudRate: 115200}); |
|
|
// await port!.open({baudRate: 115200});
|
|
|
this.loader = new EspLoader(port!); |
|
|
|
|
|
|
|
|
debugger; |
|
|
|
|
|
|
|
|
|
|
|
// -----------
|
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
|
|
|
const transport = new esptooljs.Transport(port); |
|
|
|
|
|
this.loader = new esptooljs.ESPLoader(transport, 115200); |
|
|
const loader = this.loader; |
|
|
const loader = this.loader; |
|
|
this.setState("preparing"); |
|
|
this.setState("preparing"); |
|
|
await loader.connect(); |
|
|
await loader.main_fn(); // TODO: This returns some interesting stuff, check it out
|
|
|
await loader.loadStub(); |
|
|
|
|
|
if(sections.length > 1) { |
|
|
if(sections.length > 1) { |
|
|
this.setState("erasing"); |
|
|
this.setState("erasing"); |
|
|
await loader.eraseFlash(); |
|
|
await loader.erase_flash(); |
|
|
} |
|
|
} |
|
|
const thisOp = this; |
|
|
|
|
|
const totalLength = sections.reduce<number>((p, c) => p + c.data.byteLength, 0); |
|
|
const totalLength = sections.reduce<number>((p, c) => p + c.data.byteLength, 0); |
|
|
let bytesFlashed = 0; |
|
|
let bytesFlashed = 0; |
|
|
for (let i = 0; i < sections.length; i++) { |
|
|
let lastIndex = 0; |
|
|
await loader.flashData(sections[i].data, sections[i].offset, function (idx, cnt) { |
|
|
|
|
|
const segSize = sections[i].data.length / cnt; |
|
|
const files = await Promise.all(sections.map(async s => { |
|
|
thisOp.setState("flashing", (bytesFlashed + idx * segSize) / totalLength); |
|
|
// TODO: Move this to loading, also check if this can be handled by loader.ui8ToBstr()
|
|
|
console.log(`Flashing progress: ${bytesFlashed} + ${(idx * segSize).toFixed(2)}/${sections[i].data.length} = ${(bytesFlashed + idx * segSize).toFixed(2)} / ${totalLength}`); |
|
|
const fileReader = new FileReader(); |
|
|
|
|
|
const blob = new Blob([s.data]); |
|
|
|
|
|
const content = await new Promise<string>((resolve, reject) => { |
|
|
|
|
|
fileReader.onloadend = e => resolve(fileReader.result as string); |
|
|
|
|
|
fileReader.onerror = e => reject(fileReader.result as string); |
|
|
|
|
|
fileReader.readAsBinaryString(blob); |
|
|
}); |
|
|
}); |
|
|
bytesFlashed += sections[i].data.byteLength; |
|
|
return { data: content, address: s.offset }; |
|
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
await loader.write_flash(files, "keep", undefined, undefined, false, true, (index, written, total) => { |
|
|
|
|
|
if(index != lastIndex) { |
|
|
|
|
|
bytesFlashed += sections[lastIndex].data.byteLength; |
|
|
|
|
|
lastIndex = index; |
|
|
} |
|
|
} |
|
|
|
|
|
// I don't know what kind of weird size esploader computes but it doesn't match ours
|
|
|
|
|
|
const bytesThisSegment = (written / total) * sections[index].data.byteLength; |
|
|
|
|
|
console.log(`FLASHING PROGRESS ${bytesFlashed + written} / ${totalLength} ... ${bytesFlashed} | ${written} | ${total} | ${index}`); |
|
|
|
|
|
this.setState("flashing", (bytesFlashed + bytesThisSegment) / totalLength); |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
catch (e) { |
|
|
catch (e) { |
|
|
throw e; |
|
|
throw e; |
|
|
} |
|
|
} |
|
|
finally { |
|
|
finally { |
|
|
await this.loader!.disconnect(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
debugger; |
|
|
this.setState("config"); |
|
|
this.setState("config"); |
|
|
await port!.setSignals({requestToSend: true}); |
|
|
await port!.setSignals({requestToSend: true}); |
|
|
await new Promise(r => setTimeout(r, 100)); |
|
|
await new Promise(r => setTimeout(r, 100)); |
|
|
|