diff --git a/spi_flash_programmer.ino b/spi_flash_programmer.ino index 9e11b84..7d6c4f1 100755 --- a/spi_flash_programmer.ino +++ b/spi_flash_programmer.ino @@ -9,7 +9,9 @@ #define COMMAND_HELP '?' #define COMMAND_BUFFER_CRC 'h' #define COMMAND_BUFFER_LOAD 'l' +#define COMMAND_BUFFER_LOAD_BINARY 'L' #define COMMAND_BUFFER_STORE 's' +#define COMMAND_BUFFER_STORE_BINARY 'S' #define COMMAND_FLASH_READ 'r' #define COMMAND_FLASH_WRITE 'w' #define COMMAND_FLASH_ERASE_SECTOR 'k' @@ -39,8 +41,10 @@ #define PAGE_SIZE 256 void dump_buffer(void); +void dump_buffer_binary(void); void dump_buffer_crc(void); int8_t read_into_buffer(void); +int8_t read_into_buffer_binary(void); void erase_all(void); void erase_sector(uint32_t address); @@ -158,6 +162,12 @@ void loop() Serial.println(); break; + case COMMAND_BUFFER_LOAD_BINARY: + Serial.print(COMMAND_BUFFER_LOAD_BINARY); // Echo OK + dump_buffer_binary(); + Serial.println(); + break; + case COMMAND_BUFFER_CRC: Serial.print(COMMAND_BUFFER_CRC); // Echo OK dump_buffer_crc(); @@ -174,6 +184,16 @@ void loop() dump_buffer_crc(); break; + case COMMAND_BUFFER_STORE_BINARY: + if (!read_into_buffer_binary()) { + Serial.print(COMMAND_ERROR); // Echo Error + break; + } + + Serial.print(COMMAND_BUFFER_STORE_BINARY); // Echo OK + dump_buffer_crc(); + break; + case COMMAND_WRITE_PROTECTION_CHECK: Serial.print(COMMAND_WRITE_PROTECTION_CHECK); // Echo OK impl_write_protection_check(); @@ -326,6 +346,15 @@ void dump_buffer(void) } } +void dump_buffer_binary(void) +{ + uint16_t counter; + + for(counter = 0; counter < PAGE_SIZE; counter++) { + Serial.write(buffer[counter]); + } +} + void dump_buffer_crc(void) { uint32_t crc = crc_buffer(); @@ -349,6 +378,22 @@ int8_t read_into_buffer(void) return 1; } +int8_t read_into_buffer_binary(void) +{ + uint16_t counter; + int16_t c; + + for(counter = 0; counter < PAGE_SIZE; counter++) { + do { + c = Serial.read(); + } while(c == -1); + + buffer[counter] = (uint8_t) c; + } + + return 1; +} + int8_t read_nibble(void) { int16_t c; @@ -762,4 +807,3 @@ void impl_jedec_id_read(void) write_hex_u8(SPI.transfer(0x0)); digitalWrite(nCsIo, HIGH); } - diff --git a/spi_flash_programmer_client.py b/spi_flash_programmer_client.py index 10637ea..0e40e44 100755 --- a/spi_flash_programmer_client.py +++ b/spi_flash_programmer_client.py @@ -13,7 +13,9 @@ COMMAND_BUFFER_CRC = 'h' COMMAND_BUFFER_LOAD = 'l' +COMMAND_BUFFER_LOAD_BINARY = 'L' COMMAND_BUFFER_STORE = 's' +COMMAND_BUFFER_STORE_BINARY = 'S' COMMAND_FLASH_READ = 'r' COMMAND_FLASH_WRITE = 'w' @@ -85,8 +87,6 @@ def __init__(self, port, baud_rate, debug='off', sector_size=DEFAULT_SECTOR_SIZE self.sock = serial.Serial(port, baud_rate, timeout=1) self._debug('Serial connection opened successfully') - time.sleep(2) # Wait for the Arduino bootloader - def _debug(self, message, level=DEBUG_NORMAL): if self.debug >= level: logDebug(message, level) @@ -295,6 +295,43 @@ def _readPage(self, page, tries=3): self._debug('Page read tries exceeded') return None + def _readPageBinary(self, page, tries=3): + """Read a page from the flash and receive it's contents""" + self._debug('Command: FLASH_READ_PAGE %d' % page) + + # Load page into the buffer + crc = self._loadPageMultiple(page, tries) + + for _ in range(tries): + # Dump the buffer + self._sendCommand(COMMAND_BUFFER_LOAD_BINARY) + + # Wait for data start + if not self._waitForMessage(COMMAND_BUFFER_LOAD_BINARY): + self._debug('Invalid / no response for BUFFER_LOAD_BINARY command') + continue + + # Load successful -> read sector + data = self._readExactly(self.page_size) + if data is None: + self._debug('Invalid / no response for page data') + continue + + try: + if crc == binascii.crc32(data): + self._debug('CRC did match with read data') + return data + else: + self._debug('CRC did not match with read data') + continue + + except TypeError: + self._debug('CRC could not be parsed') + continue + + self._debug('Page read tries exceeded') + return None + def _writePage(self, page, data): """Write a page into the buffer and instruct a page write operation @@ -326,7 +363,51 @@ def _writePage(self, page, data): # Write page self._sendCommand('%s%08x' % (COMMAND_FLASH_WRITE, page)) - time.sleep(.2) # Sleep 200 ms + + if not self._waitForMessage(COMMAND_FLASH_WRITE): + self._debug('Invalid / no response for FLASH_WRITE command') + return False + + # Read back page + # Fail if we can't read what we wrote + read_crc = self._loadPageMultiple(page) + if read_crc is None: + self._debug('Invalid / no CRC response for flash write') + return False + + return (read_crc == expected_crc) + + def _writePageBinary(self, page, data): + """Write a page into the buffer and instruct a page write operation + + This operation checks the written data with a generated checksum. + """ + assert len(data) == self.page_size, (len(data), data) + + # Write the page and verify that it was written correctly. + expected_crc = binascii.crc32(data) + + self.sock.write(bytes(COMMAND_BUFFER_STORE_BINARY,ENCODING) + data) + self.sock.flush() + if not self._waitForMessage(COMMAND_BUFFER_STORE_BINARY): + self._debug('Invalid / no response for BUFFER_STORE_BINARY command') + return False + + # This shouldn't fail if we're using a reliable connection. + crc = self._readExactly(8).decode(ENCODING) + if crc is None: + self._debug('Invalid / no CRC response for buffer write') + return None + + try: + if int(crc, 16) != expected_crc: + return None + except ValueError: + self._debug('Could not decode CRC') + return None + + # Write page + self._sendCommand('%s%08x' % (COMMAND_FLASH_WRITE, page)) if not self._waitForMessage(COMMAND_FLASH_WRITE): self._debug('Invalid / no response for FLASH_WRITE command') @@ -376,7 +457,7 @@ def _writeSectors(self, offset, data, tries=3): data_index = page_data_index * self.page_size page_index = pages_offset + page_data_index - if self._writePage(page_index, data[data_index: data_index + self.page_size]): + if self._writePageBinary(page_index, data[data_index: data_index + self.page_size]): bar.show(page_data_index + 1) continue @@ -560,7 +641,7 @@ def readToFile(self, filename, flash_offset=0, length=DEFAULT_FLASH_SIZE): bar.show(page) page_index = pages_offset + page - data = self._readPage(page_index) + data = self._readPageBinary(page_index) if data is not None: file.write(data) continue