Browse Source

Start on cancelling flashing; however, it doesn't work yet

Malte Grimm 3 years ago
parent
commit
bdacb1fa86
  1. 10
      src/components/Dashboard.tsx
  2. 95
      src/core/flashing/Flasher.ts
  3. 3
      src/core/stores/deviceStore.ts

10
src/components/Dashboard.tsx

@ -22,7 +22,7 @@ import { DeviceConfig } from "@app/pages/Config/DeviceConfig";
import { ISerialConnection, Protobuf } from "@meshtastic/meshtasticjs"; import { ISerialConnection, Protobuf } from "@meshtastic/meshtasticjs";
import { SidebarButton } from "./UI/Sidebar/sidebarButton"; import { SidebarButton } from "./UI/Sidebar/sidebarButton";
import { ConfigSelectButton } from "./UI/ConfigSelectButton"; import { ConfigSelectButton } from "./UI/ConfigSelectButton";
import { setup, FlashOperation, FlashState, nextBatch, OverallFlashingState } from "@app/core/flashing/Flasher"; import { setup, FlashOperation, FlashState, nextBatch, OverallFlashingState, cancel } from "@app/core/flashing/Flasher";
import { randId } from "@app/core/utils/randId"; import { randId } from "@app/core/utils/randId";
import { subscribeAll } from "@app/core/subscriptions"; import { subscribeAll } from "@app/core/subscriptions";
import { connect } from "http2"; import { connect } from "http2";
@ -51,8 +51,7 @@ export const Dashboard = () => {
subscribeAll(device, connection); subscribeAll(device, connection);
}; };
const connectToAll = async () => { const connectToAll = async () => {
const dev = await navigator.serial.getPorts(); const dev = await navigator.serial.getPorts();
debugger;
dev.filter(d => d.readable === null).forEach(d => onConnect(d)); dev.filter(d => d.readable === null).forEach(d => onConnect(d));
}; };
if(!initTest) { if(!initTest) {
@ -143,6 +142,11 @@ const DeviceList = ({devices, rootConfig, totalConfigCount}: {devices: Device[],
{cancelButtonVisible && <Button {cancelButtonVisible && <Button
className="ml-1 p-2" className="ml-1 p-2"
variant={"destructive"} variant={"destructive"}
onClick={() => {
if(!confirm("Cancel flashing?"))
return;
cancel();
}}
> >
<XIcon/> <XIcon/>
</Button>} </Button>}

95
src/core/flashing/Flasher.ts

@ -3,12 +3,13 @@ import { ConfigPreset, useAppStore } from "../stores/appStore";
import type { Device } from "../stores/deviceStore"; import type { Device } from "../stores/deviceStore";
import { EspLoader } from "@toit/esptool.js"; import { EspLoader } from "@toit/esptool.js";
type DeviceFlashingState = "doNotFlash" | "doFlash" | "idle" | "connecting" | "erasing" | "flashing" | "config" | "done"; type DeviceFlashingState = "doNotFlash" | "doFlash" | "idle" | "connecting" | "erasing" | "flashing" | "config" | "done" | "aborted" | "failed";
export type OverallFlashingState = "idle" | "busy" | "waiting"; export type OverallFlashingState = "idle" | "busy" | "waiting";
const sections: {data: Uint8Array, offset: number}[] = [ ]; const sections: {data: Uint8Array, offset: number}[] = [ ];
let configQueue: Protobuf.LocalConfig[] = []; let configQueue: Protobuf.LocalConfig[] = [];
let firmwareAvailable: boolean = false; let firmwareAvailable: boolean = false;
let operations: FlashOperation[] = [];
let callback: (flashState: OverallFlashingState) => void; let callback: (flashState: OverallFlashingState) => void;
export async function setup(configs: ConfigPreset[], overallCallback: (flashState: OverallFlashingState) => void) { export async function setup(configs: ConfigPreset[], overallCallback: (flashState: OverallFlashingState) => void) {
@ -32,12 +33,17 @@ export async function nextBatch(devices: Device[], flashStates: FlashState[], de
console.warn("Too many devices!"); console.warn("Too many devices!");
devices = devices.slice(0, configQueue.length); devices = devices.slice(0, configQueue.length);
} }
const operations = devices.map((dev, index) => new FlashOperation(dev, configQueue[index], deviceCallback)); operations = devices.map((dev, index) => new FlashOperation(dev, configQueue[index], deviceCallback));
operations.forEach((o, i) => o.state = flashStates[i]); operations.forEach((o, i) => o.state = flashStates[i]);
configQueue = configQueue.slice(operations.length) configQueue = configQueue.slice(operations.length)
console.log(`New config queue count: ${configQueue.length}`); console.log(`New config queue count: ${configQueue.length}`);
Promise.allSettled(operations.map(op => flashDevice(op))).then(p => handleFlashingDone()); Promise.allSettled(operations.map(op => op.flash())).then(p => handleFlashingDone());
}
export function cancel() {
operations.forEach(o => o.cancel());
callback("idle");
} }
function handleFlashingDone() { function handleFlashingDone() {
@ -65,42 +71,10 @@ async function downloadFirmware(path: string, offset: number, slot: number) {
} }
async function flashDevice(state: FlashOperation) {
const port = await (state.device.connection! as ISerialConnection).freePort();
await port!.open({baudRate: 115200});
const loader = new EspLoader(port!);
state.setState("connecting");
await loader.connect();
await loader.loadStub();
state.setState("erasing");
await new Promise(resolve => setTimeout(resolve, 2000));
// try {
// await loader.eraseFlash();
// for (let i = 0; i < 3; i++) {
// await loader.flashData(sections[i].data, sections[i].offset, function (idx, cnt) {
// state.setState("flashing", (1/3) * idx/cnt);
// });
// }
// } finally {
// await loader.disconnect();
// }
// port!.setSignals({requestToSend: true});
// await new Promise(r => setTimeout(r, 100));
// port!.setSignals({requestToSend: false});
// await port!.close();
// (state.device.connection! as ISerialConnection).connect({
// port,
// baudRate: 115200,
// concurrentLogOutput: true
// });
state.setState("done", 0);
}
export class FlashOperation { export class FlashOperation {
public state: FlashState = { progress: 0, state: "idle" }; public state: FlashState = { progress: 0, state: "idle" };
private loader?: 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) {
@ -113,6 +87,53 @@ export class FlashOperation {
this.callback(this); this.callback(this);
} }
public async flash() {
let port;
try {
port = await (this.device.connection! as ISerialConnection).freePort();
await port!.open({baudRate: 115200});
this.loader = new EspLoader(port!);
const loader = this.loader;
this.setState("connecting");
await loader.connect();
await loader.loadStub();
this.setState("erasing");
await new Promise(resolve => setTimeout(resolve, 2000));
await loader.eraseFlash();
const lul = this;
for (let i = 0; i < 3; i++) {
await loader.flashData(sections[i].data, sections[i].offset, function (idx, cnt) {
lul.setState("flashing", (1/3) * (i + idx/cnt));
});
}
}
catch (e) {
debugger;
this.setState("failed");
return;
}
finally {
await this.loader!.disconnect();
debugger;
}
port!.setSignals({requestToSend: true});
await new Promise(r => setTimeout(r, 100));
port!.setSignals({requestToSend: false});
await port!.close();
(this.device.connection! as ISerialConnection).connect({
port,
baudRate: 115200,
concurrentLogOutput: true
});
this.setState("done", 0);
}
public async cancel() {
debugger;
await this.loader?.disconnect();
this.setState("aborted");
}
} }
export interface FlashState { export interface FlashState {

3
src/core/stores/deviceStore.ts

@ -340,8 +340,7 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
setFlashState: (state) => { setFlashState: (state) => {
set( set(
produce<DeviceState>((draft) => { produce<DeviceState>((draft) => {
const device = draft.devices.get(id); const device = draft.devices.get(id);
debugger;
if (device) { if (device) {
device.flashState = state; device.flashState = state;
} }

Loading…
Cancel
Save