Skip to content

Commit d4a0cf9

Browse files
committed
Flash app: Update Studio brand assets and reboot controllers via DTR after flashing
Replace the legacy flash page branding with the current Studio brand assets from the monorepo by switching the header logo to the horizontal SVG logotype and updating the favicon, ICO fallback, and apple-touch icon references used by the deployed flash app. Adjust the Spectoda example flash flow to match the observed controller behavior on our hardware adapters: after erase and after successful flashing, reboot the controller through a DTR pulse instead of relying on the generic hard reset path. This keeps the controller booting into the newly flashed firmware on setups where RTS does not drive reset reliably. Also extend the local ignore rules so firmware version helper files in static/fw stay out of git. Impact: the flash page now shows the new brand consistently, local testing remains clean, and the controller should restart into application firmware immediately after flashing.
1 parent 5667663 commit d4a0cf9

7 files changed

Lines changed: 39 additions & 17 deletions

File tree

examples/typescript/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ node/modules
22
.parcel-cache
33
dist
44
package-lock.json
5-
static/fw/*.bin
5+
static/fw/*.bin
6+
static/fw/*.ver
16.9 KB
Loading
-320 Bytes
Binary file not shown.

examples/typescript/assets/favicon.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 10 additions & 0 deletions
Loading

examples/typescript/src/index.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" />
77
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@4.19.0/css/xterm.css" />
88
<link href="https://fonts.googleapis.com/css?family=Orbitron" rel="stylesheet" />
9-
<link rel="icon" href="../assets/apple-touch-icon.png" />
9+
<link rel="icon" type="image/svg+xml" href="../assets/favicon.svg" />
10+
<link rel="alternate icon" href="../assets/favicon.ico" />
11+
<link rel="apple-touch-icon" href="../assets/apple-touch-icon.png" />
1012
<script src="https://cdn.jsdelivr.net/npm/xterm@4.19.0/lib/xterm.min.js"></script>
1113
<script src="https://cdnjs.cloudflare.com/ajax/libs/xterm/4.19.0/addons/fit/fit.min.js"></script>
1214
<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/crypto-js.js"></script>
@@ -121,7 +123,7 @@
121123
</head>
122124
<body>
123125
<div class="header-container">
124-
<img src="../assets/spectoda-logo-1.png" height="32" style="vertical-align: middle" crossorigin />
126+
<img src="../assets/logo_horizontal.svg" height="24" style="vertical-align: middle" crossorigin />
125127
<h1 style="font-size: 16px; margin: 0">Flash tool</h1>
126128
</div>
127129

examples/typescript/src/index.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ declare global {
5151

5252
// Extend HTMLInputElement to include custom data property
5353
interface HTMLInputElementWithData extends HTMLInputElement {
54-
data?: string;
54+
data?: Uint8Array;
5555
}
5656

5757
const term = new Terminal({ cols: 120, rows: 24, fontSize: 14 });
@@ -113,7 +113,8 @@ setStatusMessage(
113113
*/
114114
function handleFileSelect(evt) {
115115
return new Promise((resolve, reject) => {
116-
const file = evt.target.files[0];
116+
const input = evt.target as HTMLInputElementWithData;
117+
const file = input.files?.[0];
117118

118119
if (!file) {
119120
reject("No file selected");
@@ -124,14 +125,10 @@ function handleFileSelect(evt) {
124125

125126
reader.onload = (ev: ProgressEvent<FileReader>) => {
126127
if (ev.target.result) {
127-
// Convert ArrayBuffer to binary string properly
128128
const arrayBuffer = ev.target.result as ArrayBuffer;
129129
const bytes = new Uint8Array(arrayBuffer);
130-
let binaryString = "";
131-
for (let i = 0; i < bytes.length; i++) {
132-
binaryString += String.fromCharCode(bytes[i]);
133-
}
134-
resolve(binaryString);
130+
input.data = bytes;
131+
resolve(bytes);
135132
} else {
136133
reject("FileReader did not return a result");
137134
}
@@ -166,6 +163,15 @@ const espLoaderTerminal = {
166163
},
167164
};
168165

166+
async function rebootIntoFirmware() {
167+
if (!transport) return;
168+
169+
await transport.setDTR(false);
170+
await new Promise((resolve) => setTimeout(resolve, 100));
171+
await transport.setDTR(true);
172+
await new Promise((resolve) => setTimeout(resolve, 300));
173+
}
174+
169175
connectButton.onclick = connectHandler;
170176

171177
/**
@@ -380,7 +386,7 @@ eraseControllerButton.onclick = async () => {
380386
setStatusMessage("Flash erased successfully!", "green");
381387
espLoaderTerminal.writeln("Flash erased successfully!");
382388

383-
await esploader.hardReset();
389+
await rebootIntoFirmware();
384390

385391
// Disconnect transport but keep device for reuse
386392
if (transport) await transport.disconnect();
@@ -593,7 +599,7 @@ programButton.onclick = async () => {
593599
const offSetObj = row.cells[0].childNodes[0] as HTMLInputElement;
594600
const offset = parseInt(offSetObj.value);
595601

596-
const fileObj = row.cells[1].childNodes[0] as ChildNode & { data: string };
602+
const fileObj = row.cells[1].childNodes[0] as ChildNode & { data: Uint8Array };
597603
const progressBar = row.cells[2].childNodes[0];
598604

599605
progressBar.textContent = "0";
@@ -608,16 +614,18 @@ programButton.onclick = async () => {
608614
try {
609615
const flashOptions: FlashOptions = {
610616
fileArray: fileArray,
617+
flashMode: "keep",
618+
flashFreq: "keep",
611619
flashSize: "keep",
612620
eraseAll: false,
613621
compress: true,
614622
reportProgress: (fileIndex, written, total) => {
615623
progressBars[fileIndex].value = (written / total) * 100;
616624
},
617-
calculateMD5Hash: (image) => CryptoJS.MD5(CryptoJS.enc.Latin1.parse(image)),
625+
calculateMD5Hash: (image) => CryptoJS.MD5(CryptoJS.lib.WordArray.create(image)).toString(),
618626
} as FlashOptions;
619627
await esploader.writeFlash(flashOptions);
620-
await esploader.hardReset();
628+
await rebootIntoFirmware();
621629

622630
// Disconnect transport but keep device for reuse
623631
if (transport) await transport.disconnect();
@@ -700,8 +708,8 @@ async function addFile(flashAddress, file) {
700708
if (file) {
701709
setFilesInput(element2, file);
702710
const data = await handleFileSelect({ target: { files: [file] } });
703-
(file as File & { data: string }).data = data as string;
704-
element2.data = data as string;
711+
(file as File & { data: Uint8Array }).data = data as Uint8Array;
712+
element2.data = data as Uint8Array;
705713
}
706714

707715
element2.addEventListener("change", handleFileSelect, false);

0 commit comments

Comments
 (0)