@@ -312,7 +312,9 @@ <h2>Control</h2>
312312 < option value ="development "> Development</ option >
313313 </ select >
314314 < select id ="baudSelect " aria-label ="Baud rate ">
315- < option value ="115200 " selected > 115200 baud (stable)</ option >
315+ < option value ="460800 "> 460800 baud</ option >
316+ < option value ="921600 "> 921600 baud</ option >
317+ < option value ="115200 "> 115200 baud</ option >
316318 </ select >
317319 </ div >
318320 < div class ="status-line ">
@@ -324,7 +326,7 @@ <h2>Control</h2>
324326 < strong > Erase</ strong > does a full flash erase < span class ="mono "> (esptool erase-flash)</ span > before writing the images.
325327 Only enable it when you have OTA partitions / old firmware and you see bootloops or slot errors.
326328 This web flasher seeds both OTA slots by default by writing the app to < span class ="mono "> 0x20000</ span > and < span class ="mono "> 0x410000</ span > .
327- Web flashing is fixed to < span class ="mono "> 115200 </ span > for reliability. Higher baud changes are currently unstable in < span class ="mono "> esptool-js </ span > over WebSerial on some ESP32-C5 boards .
329+ If the log shows < span class ="mono "> Flash ID: 0 </ span > or an MD5 mismatch, reconnect in ROM mode and retry at < span class ="mono "> 115200 </ span > .
328330 Note: it wipes anything stored in flash (including NVS settings like Wi-Fi creds/config).
329331 </ div >
330332 < div class ="progress " aria-label ="Flash progress ">
@@ -387,7 +389,7 @@ <h2>Browser support</h2>
387389 </ div >
388390 < footer >
389391 Product of < a href ="https://github.com/C5Lab/projectZero/ "> C5Lab/projectZero</ a > -
390- < span id ="pageVersion " class ="mono "> Web flasher v1.0.10 </ span > .
392+ < span id ="pageVersion " class ="mono "> Web flasher v1.0.5 </ span > .
391393 </ footer >
392394
393395 < script type ="module ">
@@ -429,7 +431,6 @@ <h2>Browser support</h2>
429431 isFlashing : false ,
430432 autoFlash : false ,
431433 autoFlashTriggered : false ,
432- usingStub : null ,
433434 monitorPort : null ,
434435 monitorReader : null ,
435436 monitorWriter : null ,
@@ -438,8 +439,7 @@ <h2>Browser support</h2>
438439 monitorConnected : false ,
439440 } ;
440441
441- const PAGE_VERSION = "1.0.10" ;
442- const FLASH_BAUD = 115200 ;
442+ const PAGE_VERSION = "1.0.5" ;
443443 const monitorEncoder = new TextEncoder ( ) ;
444444
445445 const sleep = ( ms ) => new Promise ( ( r ) => setTimeout ( r , ms ) ) ;
@@ -520,7 +520,8 @@ <h2>Browser support</h2>
520520 monitorLog ( `[${ time } ] ${ msg } \n` ) ;
521521 } ;
522522
523- const bytesToBinaryString = ( bytes ) => {
523+ const bufferToBinaryString = ( buffer ) => {
524+ const bytes = new Uint8Array ( buffer ) ;
524525 const chunk = 0x8000 ;
525526 let result = "" ;
526527 for ( let i = 0 ; i < bytes . length ; i += chunk ) {
@@ -529,19 +530,6 @@ <h2>Browser support</h2>
529530 return result ;
530531 } ;
531532
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-
545533 const resolveManifestPath = ( path ) => {
546534 if ( ! path ) return path ;
547535 try {
@@ -674,58 +662,6 @@ <h2>Browser support</h2>
674662 }
675663 } ;
676664
677- const applyEspToolWorkarounds = ( loader ) => {
678- if ( ! loader || loader . __projectZeroPatched ) return ;
679- loader . __projectZeroPatched = true ;
680-
681- const originalRunStub = loader . runStub . bind ( loader ) ;
682- loader . runStub = async ( ) => {
683- const chipName = loader ?. chip ?. CHIP_NAME || "" ;
684- if ( chipName === "ESP32-C5" ) {
685- state . usingStub = false ;
686- log ( "Skipping flasher stub for ESP32-C5. Using ROM bootloader path due to known C5 ECO2 stub flash-write failures." ) ;
687- return loader . chip ;
688- }
689- state . usingStub = true ;
690- return originalRunStub ( ) ;
691- } ;
692-
693- const originalFlashDeflBegin = loader . flashDeflBegin . bind ( loader ) ;
694- loader . flashDeflBegin = async ( size , compsize , offset ) => {
695- const chipName = loader ?. chip ?. CHIP_NAME || "" ;
696- if ( loader . IS_STUB || chipName === "ESP32" || chipName === "ESP8266" ) {
697- return originalFlashDeflBegin ( size , compsize , offset ) ;
698- }
699-
700- const numBlocks = Math . floor ( ( compsize + loader . FLASH_WRITE_SIZE - 1 ) / loader . FLASH_WRITE_SIZE ) ;
701- const eraseBlocks = Math . floor ( ( size + loader . FLASH_WRITE_SIZE - 1 ) / loader . FLASH_WRITE_SIZE ) ;
702- const t1 = Date . now ( ) ;
703- const writeSize = eraseBlocks * loader . FLASH_WRITE_SIZE ;
704- const timeout = loader . timeoutPerMb ( loader . ERASE_REGION_TIMEOUT_PER_MB , writeSize ) ;
705-
706- loader . info ( "Compressed " + size + " bytes to " + compsize + "..." ) ;
707- let pkt = loader . _appendArray ( loader . _intToByteArray ( writeSize ) , loader . _intToByteArray ( numBlocks ) ) ;
708- pkt = loader . _appendArray ( pkt , loader . _intToByteArray ( loader . FLASH_WRITE_SIZE ) ) ;
709- pkt = loader . _appendArray ( pkt , loader . _intToByteArray ( offset ) ) ;
710- pkt = loader . _appendArray ( pkt , loader . _intToByteArray ( 0 ) ) ;
711-
712- await loader . checkCommand (
713- "enter compressed flash mode" ,
714- loader . ESP_FLASH_DEFL_BEGIN ,
715- pkt ,
716- undefined ,
717- undefined ,
718- timeout ,
719- ) ;
720-
721- if ( size !== 0 ) {
722- const elapsed = Date . now ( ) - t1 ;
723- loader . info ( "Took " + elapsed / 1000 + "." + ( elapsed % 1000 ) + "s to erase flash block" ) ;
724- }
725- return numBlocks ;
726- } ;
727- } ;
728-
729665 const connect = async ( ) => {
730666 ensureSupport ( ) ;
731667 if ( state . connected ) {
@@ -750,7 +686,7 @@ <h2>Browser support</h2>
750686 try {
751687 state . port . addEventListener ( "disconnect" , state . onDisconnect ) ;
752688 } catch { }
753- const baud = FLASH_BAUD ;
689+ const baud = parseInt ( ui . baud . value , 10 ) ;
754690 state . transport = new Transport ( state . port , true ) ;
755691 const loaderOptions = {
756692 transport : state . transport ,
@@ -762,9 +698,6 @@ <h2>Browser support</h2>
762698 } ,
763699 debugLogging : false ,
764700 } ;
765- if ( ( parseInt ( ui . baud . value , 10 ) || FLASH_BAUD ) !== FLASH_BAUD ) {
766- log ( `Selected baud overridden to stable ${ FLASH_BAUD } for WebSerial flashing.` ) ;
767- }
768701 setStatus ( `Syncing with chip (hold BOOT + RESET). Timeout ${ Math . round ( CONNECT_TIMEOUT_MS / 1000 ) } s` ) ;
769702 log ( "Syncing with chip" ) ;
770703
@@ -775,8 +708,6 @@ <h2>Browser support</h2>
775708 attempt += 1 ;
776709 try {
777710 state . esploader = new ESPLoader ( loaderOptions ) ;
778- state . usingStub = null ;
779- applyEspToolWorkarounds ( state . esploader ) ;
780711 log ( "Connecting..." ) ;
781712 state . chip = await state . esploader . main ( ) ;
782713 lastErr = null ;
@@ -862,93 +793,11 @@ <h2>Browser support</h2>
862793 log ( `Fetching ${ url } @ 0x${ part . offset . toString ( 16 ) } ` ) ;
863794 const { buf, usedUrl } = await resolveAssetUrl ( url ) ;
864795 log ( `Fetched ${ usedUrl } ` ) ;
865- files . push ( { data : bufferToBinaryString ( buf ) , bytes : new Uint8Array ( buf ) , address : part . offset } ) ;
796+ files . push ( { data : bufferToBinaryString ( buf ) , address : part . offset } ) ;
866797 }
867798 return files ;
868799 } ;
869800
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-
952801const flash = async ( ) => {
953802 ensureSupport ( ) ;
954803 if ( ! state . esploader ) {
@@ -960,20 +809,12 @@ <h2>Browser support</h2>
960809 ui . progress . style . width = "0%" ;
961810 try {
962811 const files = await fetchFiles ( ) ;
963- const flashingFromStub = state . usingStub !== false ;
964- setStatus ( flashingFromStub ? "Uploading stub and flashing" : "Flashing from ROM bootloader" ) ;
812+ setStatus ( "Uploading stub and flashing" ) ;
965813 log ( "Preparing flash writes" ) ;
966- if ( ! flashingFromStub ) {
967- log ( "ROM bootloader mode active. Stub is disabled for ESP32-C5 compatibility." ) ;
968- if ( ui . eraseAll ?. checked ) {
969- setStatus ( "ROM bootloader will erase only the regions being flashed." ) ;
970- log ( "Erase-all requested, but ESP32-C5 ROM mode cannot use stub-only full-chip erase. Proceeding with per-region erase during flash begin." ) ;
971- }
972- }
973814 const flashOptions = {
974815 fileArray : files ,
975816 flashSize : "8MB" ,
976- eraseAll : flashingFromStub && ! ! ui . eraseAll ?. checked ,
817+ eraseAll : ! ! ui . eraseAll ?. checked ,
977818 compress : true ,
978819 reportProgress : ( fileIndex , written , total ) => {
979820 const pct = Math . min ( 100 , Math . round ( ( written / total ) * 100 ) ) ;
@@ -982,13 +823,7 @@ <h2>Browser support</h2>
982823 } ,
983824 calculateMD5Hash : ( image ) => CryptoJS . MD5 ( CryptoJS . enc . Latin1 . parse ( image ) ) ,
984825 } ;
985- const romChipName = state . esploader ?. chip ?. CHIP_NAME || "" ;
986- if ( ! flashingFromStub && romChipName === "ESP32-C5" ) {
987- log ( "Using uncompressed ROM flash path for ESP32-C5 to bypass FLASH_DEFL failures in esptool-js." ) ;
988- await writeFlashViaRom ( state . esploader , files , flashOptions ) ;
989- } else {
990- await state . esploader . writeFlash ( flashOptions ) ;
991- }
826+ await state . esploader . writeFlash ( flashOptions ) ;
992827 await state . esploader . after ( ) ;
993828 ui . progress . style . width = "100%" ;
994829 setStatus ( "Flash complete. Press RESET if the board doesn't reboot." ) ;
0 commit comments