Skip to content

Commit

Permalink
A step toward web based AVR flashing
Browse files Browse the repository at this point in the history
This can now send an AVR firmware to the device. It doesn't yet successfully reboot to user mode by itself, though
  • Loading branch information
obra committed Sep 21, 2023
1 parent 77d6c47 commit b84f1a8
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 127 deletions.
1 change: 0 additions & 1 deletion src/api/flash.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,3 @@ export const RebootMessage = {
},
clear: "CLEAR",
};

46 changes: 28 additions & 18 deletions src/api/flash/AVR109Flasher.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,36 @@ const oldflash = async (board, port, filename, options) => {
};

const flash = async (port, filecontents, options) => {
var enc = new TextDecoder("utf-8");
var hexAsText = enc.decode(filecontents);
console.log("flash", { port, filecontents, options, hexAsText });
return new Promise((resolve, reject) => {
try {
//parse intel hex
const flashData = parseIntelHex(filecontents);

//open & close
// Wait for the serial port to open.
port.open({ baudRate: 57600 });
(async () => {
try {
//parse intel hex
const flashData = parseIntelHex(hexAsText);
console.log("Flashdata is ", flashData);
//open & close
// Wait for the serial port to open.
// Wait for the serial port to open.
if (port.readable && port.writable) {
await port.close();
}
await port.open({ baudRate: 57600 });

//open writing facilities
const writer = port.writable.getWriter();
//open reading stream
const reader = port.readable.getReader();
flashDevice(writer, reader, flashData);
} catch (e) {
console.error("Error during flash", { error: e });
reject(e);
} finally {
port.close();
}
//open writing facilities
const writer = await port.writable.getWriter();
//open reading stream
const reader = await port.readable.getReader();
await flashDevice(writer, reader, flashData);
console.log("Flash done");
} catch (e) {
console.error("Error during flash", { error: e });
reject(e);
} finally {
await port.close();
}
})();
});
};

Expand Down
7 changes: 6 additions & 1 deletion src/api/flash/IntelHexParser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
const fromHexString = (hexString) => {
new Uint8Array(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
console.log("fromHexString", { hexString });
const result = new Uint8Array(
hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
);
console.log("fromHexString", { result });
return result;
};
// <!-- Intel HEX parser by https://github.com/bminer/intel-hex.js -->
//Intel Hex record types
Expand Down
13 changes: 8 additions & 5 deletions src/api/flash/flashDevice.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const AVR109States = {
};

const decoder = new TextDecoder();
const encoder = new TextEncoder();

export const flashDevice = async (writer, reader, flashData) => {
// Listen to data coming from the serial device.
Expand Down Expand Up @@ -45,7 +46,7 @@ export const flashDevice = async (writer, reader, flashData) => {
/****************/
switch (state) {
case AVR109States.UNINITIALIZED:
if (!responseString?.equals("CATERIN")) {
if (responseString !== "CATERIN") {
console.log(
'error: unexpected RX value in state 0, waited for "CATERIN"'
);
Expand Down Expand Up @@ -128,19 +129,21 @@ export const setPageAddress = async (writer, address) => {
await writeToDevice(writer, data);
};
const deviceRespondedOk = (responseString) => {
return responseString?.equals(AVR109_RESPONSE_OK);
return responseString === AVR109_RESPONSE_OK;
};
export async function sendCommand(writer, command) {
await writeToDevice(writer, command);
const commandAsArrayBuffer = encoder.encode(command);
await writeToDevice(writer, commandAsArrayBuffer);
}
const writeToDevice = async (writer, data) => {
console.log("writing", data);
await writer.write(data);
await delay(5);
};

export const rebootToApplicationMode = async (port, writer, reader) => {
reader ||= port.readable.getReader();
writer ||= port.writable.getWriter();
reader ||= port.readable?.getReader();
writer ||= port.writable?.getWriter();
console.log("Exiting bootloader");
//finish flashing and exit bootloader
await sendCommand(writer, AVR109_CMD_EXIT_BOOTLOADER);
Expand Down
1 change: 0 additions & 1 deletion src/api/focus.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import Macros from "./focus/macros";
import Keymap, { OnlyCustom } from "./focus/keymap";
import LayerNames from "./focus/layernames";


global.chrysalis_focus_instance = null;

export const delay = (ms) => new Promise((res) => setTimeout(res, ms));
Expand Down
2 changes: 0 additions & 2 deletions src/renderer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/


import React from "react";
import { createRoot } from "react-dom/client";

Expand All @@ -26,7 +25,6 @@ import { GlobalContextProvider } from "./components/GlobalContext";
import { Error } from "./Error";
import "./i18n"; // to initialize the i18n system


// Enable Hot Module Reload in dev
if (module.hot) module.hot.accept();

Expand Down
1 change: 0 additions & 1 deletion src/renderer/routerHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/


import { createHistory, createMemorySource } from "@gatsbyjs/reach-router";

const source = createMemorySource("/sanity-check");
Expand Down
75 changes: 26 additions & 49 deletions src/renderer/screens/FirmwareUpdate.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import { RebootMessage } from "@api/flash";
import { delay } from "@api/flash/utils";
import Focus from "@api/focus";
import { ActiveDevice } from "../ActiveDevice";

import CheckIcon from "@mui/icons-material/Check";
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
import Alert from "@mui/material/Alert";
Expand All @@ -33,7 +35,7 @@ import ConfirmationDialog from "@renderer/components/ConfirmationDialog";
import { GlobalContext } from "@renderer/components/GlobalContext";
import { PageTitle } from "@renderer/components/PageTitle";
import { toast } from "@renderer/components/Toast";
import React, { useContext, useState } from "react";
import React, { useContext, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connectToSerialport } from "../utils/connectToSerialport";
import BootloaderWarning from "./FirmwareUpdate/BootloaderWarning";
Expand All @@ -47,10 +49,11 @@ import UpdateDescription from "./FirmwareUpdate/UpdateDescription";
const FirmwareUpdate = (props) => {
const focus = new Focus();
const globalContext = useContext(GlobalContext);
const [activeDevice] = globalContext.state.activeDevice;
const [activeDevice, setActiveDevice] = globalContext.state.activeDevice;

const [firmwareFilename, setFirmwareFilename] = useState("");
const [selectedFirmwareType, setSelectedFirmwareType] = useState("default");
const [firmwareContent, setFirmwareContent] = useState(null);

const [flashNotificationMsg, setFlashNotificationMsg] = useState(
RebootMessage.clear
Expand All @@ -64,7 +67,7 @@ const FirmwareUpdate = (props) => {
const [activeStep, setActiveStep] = useState(-1);
const [flashSteps, setFlashSteps] = useState([]);
const [progress, setProgress] = useState("idle");
const [factoryReset, setFactoryReset] = useState(isBootloader);
const [factoryReset, setFactoryReset] = useState(!!isBootloader);
const [promptForBootloaderConnection, setPromptForBootloaderConnection] =
useState(false);

Expand All @@ -83,9 +86,9 @@ const FirmwareUpdate = (props) => {
return cVendor + "/" + cProduct + "/default." + firmwareType;
};

const doFactoryReset = async (filename) => {
const doFactoryReset = async () => {
const tasksInBootloaderMode = async () => {
await flashDeviceFirmwareFromBootloader(filename);
await flashDeviceFirmwareFromBootloader(firmwareContent);

await onStepChange("reconnect");
await reconnectAfterFlashing();
Expand All @@ -106,22 +109,23 @@ const FirmwareUpdate = (props) => {
return;
};

const flashDeviceFirmwareFromBootloader = async (filename) => {
const flashDeviceFirmwareFromBootloader = async () => {
const options = [];

const flasher = activeDevice.getFlasher();
await onStepChange("flash");
await flasher.flash(activeDevice.port, filename, options); // TODO what is options
console.log(focus);
await flasher.flash(focus._port, firmwareContent, options); // TODO what is options
await flasher.rebootToApplicationMode(
activeDevice.port,
focus._port,
activeDevice.focusDeviceDescriptor()
);
await reportSuccessfulFlashing();
return;
};

const updateDeviceFirmware = async (filename) => {
const updateDeviceFirmware = async () => {
if (activeDevice.bootloaderDetected()) {
await flashDeviceFirmwareFromBootloader(filename);
await flashDeviceFirmwareFromBootloader(firmwareContent);
return;
} else {
await onStepChange("saveEEPROM");
Expand All @@ -131,7 +135,7 @@ const FirmwareUpdate = (props) => {
const tasksInBootloaderMode = async () => {
console.trace();
console.log("Runing tasks in bootloader mode");
await flashDeviceFirmwareFromBootloader(filename);
await flashDeviceFirmwareFromBootloader(firmwareContent);

await onStepChange("reconnect");

Expand All @@ -140,6 +144,7 @@ const FirmwareUpdate = (props) => {
await reconnectAfterFlashing();
await onStepChange("restoreEEPROM");
await activeDevice.restoreEEPROM(saveKey);
await reportSuccessfulFlashing();
};

await rebootToBootloader();
Expand Down Expand Up @@ -218,40 +223,9 @@ const FirmwareUpdate = (props) => {
* - If not found for N attempts, show a notification
***/

console.log("set the callback");
setAfterBootloaderConnectCallback(() => {
callback;
});
setPromptForBootloaderConnection(true);

let bootloaderFound = false;
let attempts = 0;
while (!bootloaderFound) {
const deviceInApplicationMode = await activeDevice.focusDetected();
try {
await activeDevice.focus.reboot();
} catch (e) {
// Log the error, but otherwise ignore it.
console.error("Error during reboot", { error: e });
}
// Wait a few seconds to let the device properly reboot into bootloadermode, and enumerate.

await delay(2000);

bootloaderFound = await activeDevice.bootloaderDetected();
attempts += 1;

if (bootloaderFound) break;
setAfterBootloaderConnectCallback(() => callback);

if (attempts == NOTIFICATION_THRESHOLD) {
setFlashNotificationMsg(
deviceInApplicationMode
? RebootMessage.enter.stillApplication
: RebootMessage.enter.notFound
);
}
}
setFlashNotificationMsg(RebootMessage.clear);
setPromptForBootloaderConnection(true);
};

const onStepChange = async (desiredState) => {
Expand Down Expand Up @@ -295,11 +269,11 @@ const FirmwareUpdate = (props) => {

try {
if (factoryReset) {
await doFactoryReset("file");
await doFactoryReset();
} else {
await updateDeviceFirmware("file");
await updateDeviceFirmware();
}
setActiveStep(flashSteps.length); // set our state to the last step
// setActiveStep(flashSteps.length); // set our state to the last step
} catch (e) {
console.error("Error while uploading firmware", { error: e });
setProgress("error");
Expand All @@ -309,7 +283,9 @@ const FirmwareUpdate = (props) => {
setConfirmationOpen(false);
return;
}
};

const reportSuccessfulFlashing = () => {
setProgress("success");
console.info("Successfully flashed");
return new Promise((resolve) => {
Expand Down Expand Up @@ -343,6 +319,7 @@ const FirmwareUpdate = (props) => {
<FirmwareSelect
selectedFirmware={[selectedFirmwareType, setSelectedFirmwareType]}
firmwareFilename={[firmwareFilename, setFirmwareFilename]}
firmwareContent={[firmwareContent, setFirmwareContent]}
/>

<Box sx={{ mb: 2 }}>
Expand Down Expand Up @@ -400,7 +377,7 @@ const FirmwareUpdate = (props) => {
open={promptForBootloaderConnection}
title={"You need to do something TKTKTK"}
onConfirm={() => {
connectToSerialport().then(() => {
connectToSerialport().then((focus) => {
console.debug("connected to serial port");
setPromptForBootloaderConnection(false);
console.log("Runnign in onconfirm");
Expand Down
Loading

0 comments on commit b84f1a8

Please sign in to comment.