@@ -501,13 +501,39 @@ static void handle_flash_program(const uint8_t *data, uint32_t len) {
501501 * Progress: RSP_DATA [sector_done:2LE] [total:2LE] after each sector.
502502 * Final: ACK_OK or ACK_CRC_ERROR.
503503 */
504+ /* Check if a 256-byte page is all 0xFF (erased state).
505+ * Uses word-aligned reads for speed (~0.1µs vs 2ms page program). */
506+ static int page_is_ff (const uint8_t * data , uint32_t len ) {
507+ const uint32_t * w = (const uint32_t * )data ;
508+ for (uint32_t i = 0 ; i < len / 4 ; i ++ )
509+ if (w [i ] != 0xFFFFFFFF ) return 0 ;
510+ return 1 ;
511+ }
512+
513+ /* Erase sector + program non-0xFF pages from buffer */
514+ static void erase_and_program (uint32_t addr , const uint8_t * buf ,
515+ uint32_t bytes , uint32_t page_sz ,
516+ int drain_fifo ) {
517+ flash_erase_sector (addr );
518+ uint32_t offset = 0 ;
519+ while (offset < bytes ) {
520+ uint32_t chunk = bytes - offset ;
521+ if (chunk > page_sz ) chunk = page_sz ;
522+ if (!page_is_ff (& buf [offset ], chunk ))
523+ flash_write_page (addr + offset , & buf [offset ], chunk );
524+ offset += chunk ;
525+ if (drain_fifo ) proto_drain_fifo ();
526+ }
527+ }
528+
504529static void handle_flash_stream (const uint8_t * data , uint32_t len ) {
505- if (len < 12 ) { proto_send_ack (ACK_CRC_ERROR ); return ; }
530+ if (len < 44 ) { proto_send_ack (ACK_CRC_ERROR ); return ; }
506531 if (!flash_readable ) { proto_send_ack (ACK_FLASH_ERROR ); return ; }
507532
508533 uint32_t flash_addr = read_le32 (& data [0 ]);
509534 uint32_t size = read_le32 (& data [4 ]);
510535 uint32_t expected_crc = read_le32 (& data [8 ]);
536+ const uint8_t * bitmap = & data [12 ]; /* 32-byte sector bitmap */
511537
512538 if (size == 0 || flash_addr + size > flash_info .size ) {
513539 proto_send_ack (ACK_FLASH_ERROR );
@@ -539,6 +565,29 @@ static void handle_flash_stream(const uint8_t *data, uint32_t len) {
539565 uint32_t sector_bytes = size - sector_offset ;
540566 if (sector_bytes > sector_sz ) sector_bytes = sector_sz ;
541567
568+ /* Check bitmap: bit=0 means sector is all 0xFF, skip it */
569+ if (!(bitmap [s / 8 ] & (1 << (s % 8 )))) {
570+ /* Still process pending data sector if any */
571+ if (pending_buf >= 0 ) {
572+ erase_and_program (pending_addr , buf [pending_buf ],
573+ pending_bytes , page_sz , 1 );
574+ pending_buf = -1 ;
575+ }
576+
577+ /* Erase this sector (ensure 0xFF state) but don't program */
578+ flash_erase_sector (flash_addr + sector_offset );
579+
580+ /* Send progress — no data to receive */
581+ uint8_t progress [4 ];
582+ progress [0 ] = ((s + 1 ) >> 0 ) & 0xFF ;
583+ progress [1 ] = ((s + 1 ) >> 8 ) & 0xFF ;
584+ progress [2 ] = (num_sectors >> 0 ) & 0xFF ;
585+ progress [3 ] = (num_sectors >> 8 ) & 0xFF ;
586+ proto_send (RSP_DATA , progress , 4 );
587+
588+ continue ; /* Don't touch rx_buf or set new pending */
589+ }
590+
542591 /* Receive sector data into rx_buf.
543592 * No flash operations during receive — UART stays responsive. */
544593 uint32_t buf_received = 0 ;
@@ -575,16 +624,8 @@ static void handle_flash_stream(const uint8_t *data, uint32_t len) {
575624 /* Process previous sector if pending (erase + program).
576625 * Host is streaming next sector into the OTHER buffer right now. */
577626 if (pending_buf >= 0 ) {
578- flash_erase_sector (pending_addr );
579- uint32_t offset = 0 ;
580- while (offset < pending_bytes ) {
581- uint32_t chunk = pending_bytes - offset ;
582- if (chunk > page_sz ) chunk = page_sz ;
583- flash_write_page (pending_addr + offset ,
584- & buf [pending_buf ][offset ], chunk );
585- offset += chunk ;
586- proto_drain_fifo ();
587- }
627+ erase_and_program (pending_addr , buf [pending_buf ],
628+ pending_bytes , page_sz , 1 );
588629 }
589630
590631 /* This sector's buffer becomes the pending one */
@@ -598,15 +639,8 @@ static void handle_flash_stream(const uint8_t *data, uint32_t len) {
598639
599640 /* Process the last sector (no more data to receive) */
600641 if (pending_buf >= 0 ) {
601- flash_erase_sector (pending_addr );
602- uint32_t offset = 0 ;
603- while (offset < pending_bytes ) {
604- uint32_t chunk = pending_bytes - offset ;
605- if (chunk > page_sz ) chunk = page_sz ;
606- flash_write_page (pending_addr + offset ,
607- & buf [pending_buf ][offset ], chunk );
608- offset += chunk ;
609- }
642+ erase_and_program (pending_addr , buf [pending_buf ],
643+ pending_bytes , page_sz , 0 );
610644 }
611645
612646 proto_send_ack (ACK_OK );
0 commit comments