Skip to content

Commit faf3bea

Browse files
committed
flash fix #5
1 parent f6ec1ba commit faf3bea

1 file changed

Lines changed: 105 additions & 5 deletions

File tree

docs/janos_flash.html

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ <h2>Browser support</h2>
438438
monitorConnected: false,
439439
};
440440

441-
const PAGE_VERSION = "1.0.8";
441+
const PAGE_VERSION = "1.0.9";
442442
const FLASH_BAUD = 115200;
443443
const monitorEncoder = new TextEncoder();
444444

@@ -520,8 +520,7 @@ <h2>Browser support</h2>
520520
monitorLog(`[${time}] ${msg}\n`);
521521
};
522522

523-
const bufferToBinaryString = (buffer) => {
524-
const bytes = new Uint8Array(buffer);
523+
const bytesToBinaryString = (bytes) => {
525524
const chunk = 0x8000;
526525
let result = "";
527526
for (let i = 0; i < bytes.length; i += chunk) {
@@ -530,6 +529,19 @@ <h2>Browser support</h2>
530529
return result;
531530
};
532531

532+
const bufferToBinaryString = (buffer) => bytesToBinaryString(new Uint8Array(buffer));
533+
534+
const padBytesTo = (data, alignment, padCharacter = 0xff) => {
535+
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
536+
const padMod = bytes.length % alignment;
537+
if (padMod === 0) return bytes;
538+
const padding = new Uint8Array(alignment - padMod).fill(padCharacter);
539+
const padded = new Uint8Array(bytes.length + padding.length);
540+
padded.set(bytes, 0);
541+
padded.set(padding, bytes.length);
542+
return padded;
543+
};
544+
533545
const resolveManifestPath = (path) => {
534546
if (!path) return path;
535547
try {
@@ -850,11 +862,93 @@ <h2>Browser support</h2>
850862
log(`Fetching ${url} @ 0x${part.offset.toString(16)}`);
851863
const { buf, usedUrl } = await resolveAssetUrl(url);
852864
log(`Fetched ${usedUrl}`);
853-
files.push({ data: bufferToBinaryString(buf), address: part.offset });
865+
files.push({ data: bufferToBinaryString(buf), bytes: new Uint8Array(buf), address: part.offset });
854866
}
855867
return files;
856868
};
857869

870+
const writeFlashViaRom = async (loader, files, flashOptions) => {
871+
if (!loader) throw new Error("ESP loader is not ready");
872+
873+
loader.info("Using uncompressed ROM flash path for ESP32-C5 to avoid compressed-flash failures.");
874+
875+
if (flashOptions.flashSize && flashOptions.flashSize !== "keep") {
876+
const flashEnd = loader.flashSizeBytes(flashOptions.flashSize);
877+
for (let i = 0; i < files.length; i += 1) {
878+
const size = files[i]?.bytes?.length ?? files[i]?.data?.length ?? 0;
879+
if (size + files[i].address > flashEnd) {
880+
throw new Error(`File ${i + 1} doesn't fit in the available flash`);
881+
}
882+
}
883+
}
884+
885+
for (let i = 0; i < files.length; i += 1) {
886+
let image = files[i].bytes instanceof Uint8Array
887+
? new Uint8Array(files[i].bytes)
888+
: loader.bstrToUi8(files[i].data || "");
889+
890+
if (image.length === 0) continue;
891+
892+
image = padBytesTo(image, 4);
893+
const address = files[i].address;
894+
image = await loader._updateImageFlashParams(
895+
image,
896+
address,
897+
flashOptions.flashMode,
898+
flashOptions.flashFreq,
899+
flashOptions.flashSize,
900+
);
901+
902+
const calcmd5 = flashOptions.calculateMD5Hash
903+
? String(flashOptions.calculateMD5Hash(bytesToBinaryString(image)))
904+
: null;
905+
906+
const totalBytes = image.length;
907+
const blocks = await loader.flashBegin(totalBytes, address);
908+
let seq = 0;
909+
let imageOffset = 0;
910+
let timeout = loader.DEFAULT_TIMEOUT || 3000;
911+
if (flashOptions.reportProgress) flashOptions.reportProgress(i, 0, totalBytes);
912+
913+
const t1 = Date.now();
914+
while (imageOffset < image.length) {
915+
const blockSize = Math.min(loader.FLASH_WRITE_SIZE, image.length - imageOffset);
916+
const block = image.slice(imageOffset, imageOffset + blockSize);
917+
const pct = Math.min(100, Math.floor((100 * (seq + 1)) / Math.max(blocks, 1)));
918+
loader.info(`Writing at 0x${(address + imageOffset).toString(16)}... (${pct}%)`);
919+
920+
if (typeof loader.timeoutPerMb === "function") {
921+
timeout = Math.max(loader.DEFAULT_TIMEOUT || 3000, loader.timeoutPerMb(loader.ERASE_WRITE_TIMEOUT_PER_MB, block.length));
922+
}
923+
924+
await loader.flashBlock(block, seq, timeout);
925+
imageOffset += blockSize;
926+
seq += 1;
927+
928+
if (flashOptions.reportProgress) {
929+
flashOptions.reportProgress(i, imageOffset, totalBytes);
930+
}
931+
}
932+
933+
await loader.flashFinish(false, timeout);
934+
935+
const elapsedSeconds = ((Date.now() - t1) / 1000).toFixed(3);
936+
loader.info(`Wrote ${totalBytes} bytes at 0x${address.toString(16)} in ${elapsedSeconds} seconds.`);
937+
938+
if (calcmd5) {
939+
loader.info("File md5: " + calcmd5);
940+
const flashMd5 = await loader.flashMd5sum(address, totalBytes);
941+
loader.info("Flash md5: " + flashMd5);
942+
if (String(flashMd5) !== calcmd5) {
943+
throw new Error("MD5 of file does not match data in flash!");
944+
}
945+
loader.info("Hash of data verified.");
946+
}
947+
}
948+
949+
loader.info("Leaving...");
950+
};
951+
858952
const flash = async () => {
859953
ensureSupport();
860954
if (!state.esploader) {
@@ -889,7 +983,13 @@ <h2>Browser support</h2>
889983
},
890984
calculateMD5Hash: (image) => CryptoJS.MD5(CryptoJS.enc.Latin1.parse(image)),
891985
};
892-
await state.esploader.writeFlash(flashOptions);
986+
const romChipName = state.esploader?.chip?.CHIP_NAME || "";
987+
if (!flashingFromStub && romChipName === "ESP32-C5") {
988+
log("Using uncompressed ROM flash path for ESP32-C5 to bypass FLASH_DEFL failures in esptool-js.");
989+
await writeFlashViaRom(state.esploader, files, flashOptions);
990+
} else {
991+
await state.esploader.writeFlash(flashOptions);
992+
}
893993
await state.esploader.after();
894994
ui.progress.style.width = "100%";
895995
setStatus("Flash complete. Press RESET if the board doesn't reboot.");

0 commit comments

Comments
 (0)