From 6b6bddfdc8f685580926f81218ee9cc003d52620 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 14 May 2024 08:58:08 -0400 Subject: [PATCH] adding pre-commit and running reformater --- .pre-commit-config.yaml | 49 +++ README.md | 6 +- _config.yml | 2 +- examples/test.py | 42 ++- src/isp_programmer/IODevices.py | 17 +- src/isp_programmer/ISPConnection.py | 434 ++++++++++++++---------- src/isp_programmer/__init__.py | 4 - src/isp_programmer/cli.py | 125 +++++-- src/isp_programmer/lpctools_parts.def | 1 - src/isp_programmer/parts_definitions.py | 51 +-- src/isp_programmer/tools.py | 25 +- 11 files changed, 485 insertions(+), 271 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ce040c1 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,49 @@ +exclude: '^docs/|/migrations/|devcontainer.json' +default_stages: [commit] + +default_language_version: + python: python3.11 + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-json + - id: check-toml + - id: check-xml + - id: check-yaml + - id: debug-statements + - id: check-builtin-literals + - id: check-case-conflict + - id: check-docstring-first + - id: detect-private-key + + - repo: https://github.com/adamchainz/django-upgrade + rev: '1.16.0' + hooks: + - id: django-upgrade + args: ['--target-version', '4.2'] + + # Run the Ruff linter. + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.3.2 + hooks: + # Linter + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + # Formatter + - id: ruff-format + + - repo: https://github.com/Riverside-Healthcare/djLint + rev: v1.34.1 + hooks: + - id: djlint-reformat-django + - id: djlint-django + +# sets up .pre-commit-ci.yaml to ensure pre-commit dependencies stay up to date +ci: + autoupdate_schedule: weekly + skip: [] + submodules: false diff --git a/README.md b/README.md index 19c16f0..ebfd531 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ fails the chip will boot back into the ISP mode. The image is then written from the top most page down to the first page. The first sector contains the valid image checksum so a failed write will keep the device in ISP mode instead of just being bricked. - + ## Chip Families Supported: LPC84x @@ -22,7 +22,7 @@ keep the device in ISP mode instead of just being bricked. NXP chips with 1kB sector sizes should work by adding their information to the lpctools_parts.def configuration file. -The configuration file is identical to that used by the lpctools project +The configuration file is identical to that used by the lpctools project ## Usage @@ -38,7 +38,7 @@ The configuration file is identical to that used by the lpctools project NXPISP is a python3 package and can be installed using pip. Clone the repository, enter the directory with setup.py in it and run pip install . -The default location for the configuration file is at /etc/lpctools_parts.def. +The default location for the configuration file is at /etc/lpctools_parts.def. The file can either be copied there or the path passed in when calling the tool with the --config_file/-f flag. diff --git a/_config.yml b/_config.yml index fc24e7a..8bbf794 100644 --- a/_config.yml +++ b/_config.yml @@ -1 +1 @@ -theme: jekyll-theme-hacker \ No newline at end of file +theme: jekyll-theme-hacker diff --git a/examples/test.py b/examples/test.py index 900775b..64f5606 100644 --- a/examples/test.py +++ b/examples/test.py @@ -1,33 +1,47 @@ import logging from time import sleep import timeout_decorator -from isp_programmer import tools, UartDevice, GetPartDescriptor, MassErase, \ - InitConnection, ISPConnection, ReadImage, WriteBinaryToFlash, \ - ChipDescription, ReadSector +from isp_programmer import ( + tools, + UartDevice, + GetPartDescriptor, + MassErase, + InitConnection, + ISPConnection, + ReadImage, + WriteBinaryToFlash, + ChipDescription, + ReadSector, +) retry = tools.retry calc_crc = tools.calc_crc -def SetupChip(baudrate: int, crystal_frequency: int, chip_file: str, sleep_time: float = 1): +def SetupChip( + baudrate: int, crystal_frequency: int, chip_file: str, sleep_time: float = 1 +): device = "/dev/ttyUSB0" kStartingBaudRate = baudrate iodevice = UartDevice(device, baudrate=kStartingBaudRate) isp = ISPConnection(iodevice) - #print(baudrate, device, crystal_frequency, chip_file) + # print(baudrate, device, crystal_frequency, chip_file) InitConnection(isp) - part_id = retry(isp.ReadPartID, count=100, exception=timeout_decorator.TimeoutError)() + part_id = retry( + isp.ReadPartID, count=100, exception=timeout_decorator.TimeoutError + )() descriptor = GetPartDescriptor(chip_file, part_id) logging.info(f"{part_id}, {descriptor}") chip = ChipDescription(descriptor) - chip.CrystalFrequency = crystal_frequency#12000#khz == 30MHz + chip.CrystalFrequency = crystal_frequency # 12000#khz == 30MHz - print("Setting new baudrate %d"%baudrate) + print("Setting new baudrate %d" % baudrate) isp.baud_rate = baudrate return isp, chip + def main(imagein): isp, chip = SetupChip(9600, 12000, "./lpctools_parts.def") # Clear chip, write, read @@ -38,9 +52,9 @@ def main(imagein): logging.info(f"image length: {len(image)} {image}") assert len(image) == 0 # Test for blank chip logging.info("Checking Sectors are blank") - assert isp.CheckSectorsBlank(0, chip.SectorCount-1) + assert isp.CheckSectorsBlank(0, chip.SectorCount - 1) - expected_data = bytes([0xff]*chip.sector_bytes) + expected_data = bytes([0xFF] * chip.sector_bytes) crc_expected = calc_crc(expected_data) # Read first sector @@ -48,7 +62,9 @@ def main(imagein): isp.WriteToRam(chip.RAMStartWrite, expected_data) sleep(0.1) isp.reset() - first_sector = retry(isp.ReadMemory, count=2, exception=(UserWarning, timeout_decorator.TimeoutError))(chip.RAMStartWrite, chip.sector_bytes) + first_sector = retry( + isp.ReadMemory, count=2, exception=(UserWarning, timeout_decorator.TimeoutError) + )(chip.RAMStartWrite, chip.sector_bytes) # first_sector = chip.ReadSector(0) assert first_sector == expected_data # crc_calculated = chip.ReadCRC(chip.FlashRange[0], chip.sector_bytes) @@ -59,7 +75,7 @@ def main(imagein): logging.info("RAM CRC check passed") data = b"hello world" - data += bytes([0xff] *(chip.sector_bytes - len(data))) + data += bytes([0xFF] * (chip.sector_bytes - len(data))) assert len(data) == chip.sector_bytes crc_expected = calc_crc(data) WriteBinaryToFlash(isp, chip, data, 0) @@ -80,7 +96,7 @@ def main(imagein): if __name__ == "__main__": logging.basicConfig() - logging.getLogger().setLevel(logging.DEBUG-2) + logging.getLogger().setLevel(logging.DEBUG - 2) # imagein = "../blinky845.hex" imagein = "../blinky845MAX.hex" main(imagein) diff --git a/src/isp_programmer/IODevices.py b/src/isp_programmer/IODevices.py index 3b31908..acb2eb4 100644 --- a/src/isp_programmer/IODevices.py +++ b/src/isp_programmer/IODevices.py @@ -4,7 +4,8 @@ class IODevice: - ''' Generic for a byte IO device''' + """Generic for a byte IO device""" + def read_byte(self): pass @@ -28,7 +29,8 @@ def ReadLine(self): class MockUart(IODevice): - '''Mock IO device for testing''' + """Mock IO device for testing""" + def __init__(self, port: str = "/dev/ttyUSB0", baudrate: int = 9600): self.baudrate = baudrate self.port = port @@ -47,8 +49,14 @@ def GetBaudrate(self): class UartDevice(IODevice): - '''Serial IO device wrapper around pyserial''' - def __init__(self, port: str = "/dev/ttyUSB0", baudrate: int = 9600, timeout: float = kTimeout): + """Serial IO device wrapper around pyserial""" + + def __init__( + self, + port: str = "/dev/ttyUSB0", + baudrate: int = 9600, + timeout: float = kTimeout, + ): self.uart = Serial(port, baudrate, xonxoff=False, timeout=timeout) self.read = self.uart.read self.read_all = self.uart.read_all @@ -71,4 +79,3 @@ def ReadLine(self): return bytes(line).decode("utf-8") except UnicodeDecodeError: raise TimeoutError - diff --git a/src/isp_programmer/ISPConnection.py b/src/isp_programmer/ISPConnection.py index 21b3aa9..d8a8066 100644 --- a/src/isp_programmer/ISPConnection.py +++ b/src/isp_programmer/ISPConnection.py @@ -15,51 +15,43 @@ kTimeout = 1 -BAUDRATES = ( - 9600, - 19200, - 38400, - 57600, - 115200, - 230400, - 460800 -) +BAUDRATES = (9600, 19200, 38400, 57600, 115200, 230400, 460800) NXPReturnCodes = { - "CMD_SUCCESS" : 0x0, - "INVALID_COMMAND" : 0x1, - "SRC_ADDR_ERROR" : 0x2, - "DST_ADDR_ERROR" : 0x3, - "SRC_ADDR_NOT_MAPPED" : 0x4, - "DST_ADDR_NOT_MAPPED" : 0x5, - "COUNT_ERROR" : 0x6, - "INVALID_SECTOR/INVALID_PAGE" : 0x7, - "SECTOR_NOT_BLANK" : 0x8, - "SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION" : 0x9, - "COMPARE_ERROR" : 0xa, - "BUSY" : 0xb, - "PARAM_ERROR" : 0xc, - "ADDR_ERROR" : 0xd, - "ADDR_NOT_MAPPED" : 0xe, - "CMD_LOCKED" : 0xf, - "INVALID_CODE" : 0x10, - "INVALID_BAUD_RATE" : 0x11, - "INVALID_STOP_BIT" : 0x12, - "CODE_READ_PROTECTION_ENABLED" : 0x13, - "Unused 1" : 0x14, - "USER_CODE_CHECKSUM" : 0x15, - "Unused 2" : 0x16, - "EFRO_NO_POWER" : 0x17, - "FLASH_NO_POWER" : 0x18, - "Unused 3" : 0x19, - "Unused 4" : 0x1a, - "FLASH_NO_CLOCK" : 0x1b, - "REINVOKE_ISP_CONFIG" : 0x1c, - "NO_VALID_IMAGE" : 0x1d, - "FAIM_NO_POWER" : 0x1e, - "FAIM_NO_CLOCK" : 0x1f, - "NoStatusResponse" : 0xff, + "CMD_SUCCESS": 0x0, + "INVALID_COMMAND": 0x1, + "SRC_ADDR_ERROR": 0x2, + "DST_ADDR_ERROR": 0x3, + "SRC_ADDR_NOT_MAPPED": 0x4, + "DST_ADDR_NOT_MAPPED": 0x5, + "COUNT_ERROR": 0x6, + "INVALID_SECTOR/INVALID_PAGE": 0x7, + "SECTOR_NOT_BLANK": 0x8, + "SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION": 0x9, + "COMPARE_ERROR": 0xA, + "BUSY": 0xB, + "PARAM_ERROR": 0xC, + "ADDR_ERROR": 0xD, + "ADDR_NOT_MAPPED": 0xE, + "CMD_LOCKED": 0xF, + "INVALID_CODE": 0x10, + "INVALID_BAUD_RATE": 0x11, + "INVALID_STOP_BIT": 0x12, + "CODE_READ_PROTECTION_ENABLED": 0x13, + "Unused 1": 0x14, + "USER_CODE_CHECKSUM": 0x15, + "Unused 2": 0x16, + "EFRO_NO_POWER": 0x17, + "FLASH_NO_POWER": 0x18, + "Unused 3": 0x19, + "Unused 4": 0x1A, + "FLASH_NO_CLOCK": 0x1B, + "REINVOKE_ISP_CONFIG": 0x1C, + "NO_VALID_IMAGE": 0x1D, + "FAIM_NO_POWER": 0x1E, + "FAIM_NO_CLOCK": 0x1F, + "NoStatusResponse": 0xFF, } @@ -76,24 +68,26 @@ def _return_code_success(code: int) -> bool: def _raise_return_code_error(code: int, call_name: str) -> None: - ''' + """ Each command returns a code, check if the code is a success, throws a UserWarning if not - ''' + """ if not _return_code_success(code): raise UserWarning( - f"Return Code Failure in {call_name} {_get_error_code_name(code)} {code}") + f"Return Code Failure in {call_name} {_get_error_code_name(code)} {code}" + ) class ISPConnection: - ''' + """ ISPConnection abstracts the interface to the chip, wrapping all responses and ensuring a reliable connection - ''' + """ + kNewLine = "\r\n" StatusRespLength = len(kNewLine) + 1 kWordSize = 4 # 32 bit device - #Parity = None - #DataBits = 8 - #StopBits = 1 + # Parity = None + # DataBits = 8 + # StopBits = 1 SyncString = f"Synchronized{kNewLine}" SyncStringBytes = bytes(SyncString, encoding="utf-8") SyncVerifiedString = f"OK{kNewLine}" @@ -104,7 +98,7 @@ def __init__(self, iodevice: IODevice): self._return_code_sleep = 0.05 self._serial_sleep = 10e-3 self.iodevice = iodevice - self.data_buffer_in : Deque[int] = deque() + self.data_buffer_in: Deque[int] = deque() self.echo_on = True @property @@ -143,17 +137,17 @@ def _write_serial(self, out: bytes) -> None: self._delay_write_serial(out) else: self.iodevice.write(out) - logging.log(logging.DEBUG-1, f"Write: [{out}]") + logging.log(logging.DEBUG - 1, f"Write: [{out}]") def _flush(self): self.iodevice.flush() @timeout(kTimeout) def _read_line(self) -> str: - ''' + """ Read until a new line is found. Timesout if no data pulled - ''' + """ line = self.iodevice.ReadLine() return line @@ -164,32 +158,39 @@ def _clear_buffer(self): self.data_buffer_in.clear() def _read(self): - ''' + """ Reads input buffer and stores in buffer - ''' + """ data_in = self.iodevice.read_all() dstr = bytes("".join([chr(ch) for ch in data_in]), "utf-8") if data_in: - logging.log(logging.DEBUG-1, f"_read: <{dstr}>") + logging.log(logging.DEBUG - 1, f"_read: <{dstr}>") self.data_buffer_in.extend(data_in) def _clear_serial(self): for _ in range(2): - tools.retry(self._read, count=10, exception=timeout_decorator.TimeoutError, raise_on_fail=False)() + tools.retry( + self._read, + count=10, + exception=timeout_decorator.TimeoutError, + raise_on_fail=False, + )() self._clear_buffer() self._flush() def _get_return_code(self, command_string: str) -> int: - ''' + """ No exceptions are thrown. - ''' + """ time.sleep(self._return_code_sleep) try: resp = self._read_line() if resp.strip() == command_string.strip(): - logging.getLogger().debug("Command was echoed, Discarding line: %s", resp) + logging.getLogger().debug( + "Command was echoed, Discarding line: %s", resp + ) resp = self._read_line() - #if self.echo_on: # discard echo + # if self.echo_on: # discard echo # logging.getLogger().debug("ECHO ON, Discarding line: %s", resp) # resp = self._read_line() except (timeout_decorator.TimeoutError, TimeoutError): @@ -201,16 +202,16 @@ def _get_return_code(self, command_string: str) -> int: logging.getLogger().debug("%s: %s", command_string, resp) return int(resp.strip()) - def _write(self, string : bytes) -> None: + def _write(self, string: bytes) -> None: logging.debug(string) assert isinstance(string, bytes) self._write_serial(string) # self._write_serial(bytes(self.kNewLine, encoding = "utf-8")) def _write_command(self, command_string: str) -> int: - ''' + """ Takes the command string, return the response code - ''' + """ new_line = self.kNewLine self._write(bytes(f"{command_string}{new_line}", encoding="utf-8")) return self._get_return_code(command_string) @@ -222,40 +223,40 @@ def write_newline(self): self._write(bytes(self.kNewLine, encoding="utf-8")) def Unlock(self): - ''' + """ Enables Flash Write, Erase, & Go - ''' + """ response_code = self._write_command("U 23130") _raise_return_code_error(response_code, "Unlock") def SetBaudRate(self, baud_rate: int, stop_bits: int = 1): - ''' + """ Baud Depends of FAIM config, stopbit is 1 or 2 - ''' + """ response_code = self._write_command(f"B {baud_rate} {stop_bits}") _raise_return_code_error(response_code, "Set Baudrate") def SetEcho(self, on: bool = True): - ''' + """ ISP echos host when enabled - ''' + """ command = f"A {on : d}" response_code = self._write_command(command) _raise_return_code_error(response_code, "Set Echo") self.echo_on = on def WriteToRam(self, start: int, data: bytes): - ''' + """ Send command Receive command success The data sheet claims a verification string is sent at the end of a transfer but it does not. - ''' - assert len(data)%self.kWordSize == 0 + """ + assert len(data) % self.kWordSize == 0 function_name = "Write to RAM" logging.info("%s %d bytes", function_name, len(data)) - #when transfer is complete the handler sends OK + # when transfer is complete the handler sends OK response_code = self._write_command(f"W {start} {len(data)}") _raise_return_code_error(response_code, function_name) self._write(data) # Stream data after confirmation @@ -268,10 +269,10 @@ def WriteToRam(self, start: int, data: bytes): @timeout(10) def ReadMemory(self, start: int, num_bytes: int): - ''' + """ Send command with newline, receive response code\r\n - ''' - assert num_bytes%self.kWordSize == 0 # On a word boundary + """ + assert num_bytes % self.kWordSize == 0 # On a word boundary function = "ReadMemory" logging.info(function) @@ -281,7 +282,9 @@ def ReadMemory(self, start: int, num_bytes: int): _raise_return_code_error(response_code, function) while len(self.data_buffer_in) < num_bytes: - logging.debug(f"{function}: bytes in {len(self.data_buffer_in)}/{num_bytes}") + logging.debug( + f"{function}: bytes in {len(self.data_buffer_in)}/{num_bytes}" + ) time.sleep(0.1) self._read() # Command success is sent at the end of the transferr @@ -301,20 +304,24 @@ def PrepSectorsForWrite(self, start: int, end: int): _raise_return_code_error(response_code, "Prep Sectors") def CopyRAMToFlash(self, flash_address: int, ram_address: int, num_bytes: int): - response_code = self._write_command(f"C {flash_address} {ram_address} {num_bytes}") + response_code = self._write_command( + f"C {flash_address} {ram_address} {num_bytes}" + ) _raise_return_code_error(response_code, "Copy RAM To Flash") # time.sleep(.2) def Go(self, address: int, thumb_mode: bool = False): - ''' + """ Start executing code at the specified spot. Should not expect a response back. - ''' + """ mode = "" if thumb_mode: - mode = 'T' + mode = "T" response_code = self._write_command(f"G {address} {mode}") - if response_code != self.ReturnCodes["NoStatusResponse"]: # Don't expect a response code from this + if ( + response_code != self.ReturnCodes["NoStatusResponse"] + ): # Don't expect a response code from this _raise_return_code_error(response_code, "Go") def EraseSector(self, start: int, end: int): @@ -326,9 +333,9 @@ def ErasePages(self, start: int, end: int): _raise_return_code_error(response_code, "Erase Pages") def CheckSectorsBlank(self, start: int, end: int) -> bool: - ''' + """ Raises user warning if the command fails - ''' + """ assert start <= end response_code = self._write_command(f"I {start} {end}") if response_code == 8: @@ -339,29 +346,37 @@ def CheckSectorsBlank(self, start: int, end: int) -> bool: except timeout_decorator.TimeoutError: pass - if response_code not in (NXPReturnCodes["CMD_SUCCESS"], NXPReturnCodes["SECTOR_NOT_BLANK"]): + if response_code not in ( + NXPReturnCodes["CMD_SUCCESS"], + NXPReturnCodes["SECTOR_NOT_BLANK"], + ): _raise_return_code_error(response_code, "Blank Check Sectors") return _return_code_success(response_code) def ReadPartID(self) -> str: - ''' + """ Throws no exception - ''' + """ response_code = self._write_command("J") _raise_return_code_error(response_code, "Read Part ID") - resp = tools.retry(self._read_line, count=1, exception=timeout_decorator.TimeoutError, raise_on_fail=False)() + resp = tools.retry( + self._read_line, + count=1, + exception=timeout_decorator.TimeoutError, + raise_on_fail=False, + )() try: - return int(resp) # handle none type passed + return int(resp) # handle none type passed except ValueError: pass return resp def ReadBootCodeVersion(self): - ''' + """ LPC84x sends a 0x1a first for some reason. Also the boot version seems to be Minor then Major not like the docs say - ''' + """ response_code = self._write_command("K") _raise_return_code_error(response_code, "Read Bootcode Version") minor = 0 @@ -374,19 +389,24 @@ def ReadBootCodeVersion(self): pass return f"{major}.{minor}" - def MemoryLocationsEqual(self, address1: int, address2: int, num_bytes: int) -> bool: - ''' + def MemoryLocationsEqual( + self, address1: int, address2: int, num_bytes: int + ) -> bool: + """ Checks to see if two sections in the memory map are equal. Raises a user warning if the command fails - ''' + """ command = f"M {address1} {address2} {num_bytes} {self.kNewLine}" self._write(bytes(command, encoding="utf-8")) response_code = self._get_return_code(command) - if response_code not in (NXPReturnCodes["CMD_SUCCESS"], NXPReturnCodes["COMPARE_ERROR"]): + if response_code not in ( + NXPReturnCodes["CMD_SUCCESS"], + NXPReturnCodes["COMPARE_ERROR"], + ): _raise_return_code_error(response_code, "Compare") if response_code == NXPReturnCodes["COMPARE_ERROR"]: - # Will return first location of mismatched location if the response is COMPARE_ERROR + # Will return first location of mismatched location if the response is COMPARE_ERROR try: _ = self._read_line() # discard the comparison @@ -395,20 +415,20 @@ def MemoryLocationsEqual(self, address1: int, address2: int, num_bytes: int) -> return _return_code_success(response_code) def ReadUID(self): - ''' + """ Raises timeout exception - ''' + """ response_code = self._write_command("N") _raise_return_code_error(response_code, "Read UID") uuids = [] for _ in range(4): uuids.append(self._read_line()) - return " ".join(["0x%08x"%int(uid) for uid in uuids]) + return " ".join(["0x%08x" % int(uid) for uid in uuids]) def ReadCRC(self, address: int, num_bytes: int) -> int: - ''' + """ Command echos the response then the value of the CRC - ''' + """ function = "Read CRC" command = f"S {address} {num_bytes}" @@ -417,7 +437,9 @@ def ReadCRC(self, address: int, num_bytes: int) -> int: _raise_return_code_error(response_code, function) return int(self._read_line()) - def ReadFlashSig(self, start: int, end: int, wait_states: int = 2, mode: int = 0) -> str: + def ReadFlashSig( + self, start: int, end: int, wait_states: int = 2, mode: int = 0 + ) -> str: assert start < end response_code = self._write_command(f"Z {start} {end} {wait_states} {mode}") _raise_return_code_error(response_code, "Read Flash Signature") @@ -432,11 +454,11 @@ def ReadWriteFAIM(self): _raise_return_code_error(response_code, "Read Write FAIM") def SetCrystalFrequency(self, frequency_khz: int): - self._write(bytes(f"{frequency_khz} {self.kNewLine}" , encoding="utf-8")) + self._write(bytes(f"{frequency_khz} {self.kNewLine}", encoding="utf-8")) verified = False for _ in range(3): try: - frame_in = self._read_line()#Should be OK\r\n + frame_in = self._read_line() # Should be OK\r\n if self.SyncVerifiedString in frame_in: verified = True break @@ -446,7 +468,7 @@ def SetCrystalFrequency(self, frequency_khz: int): raise UserWarning("Verification Failure") def SyncConnection(self): - ''' + """ - A ? synchronizes the autobaud 1. Send a ? 2. Receive "Synchronized" @@ -459,9 +481,9 @@ def SyncConnection(self): serial buffer is overflowed. Therefore try sending a single '?' and checking for the response. Otherwise send another '?' at a time until a response comes back or n number of characters have been sent. - ''' + """ self.reset() - sync_char = '?' + sync_char = "?" # > ?\n self._write(bytes(sync_char, "utf-8")) byte_in = self.iodevice.read() @@ -476,15 +498,17 @@ def SyncConnection(self): valid_response = self.SyncString.strip()[1:] in frame_in # < Synchronized\n - logging.debug(f"Sync string comparison {repr(frame_in)}, {self.SyncString.strip()}, {valid_response}") + logging.debug( + f"Sync string comparison {repr(frame_in)}, {self.SyncString.strip()}, {valid_response}" + ) if not valid_response: raise UserWarning("Syncronization Failure") - #self._flush() + # self._flush() logging.debug(f"Echoing sync string, {repr(self.SyncStringBytes)}") time.sleep(0.1) - self._write(self.SyncStringBytes) # echo SyncString + self._write(self.SyncStringBytes) # echo SyncString self.write_newline() self.write_newline() # > Synchronized\n @@ -508,15 +532,15 @@ def SyncConnection(self): logging.debug(f"{frame_in}") - if not(self.SyncVerifiedString.strip() in frame_in): + if self.SyncVerifiedString.strip() not in frame_in: raise UserWarning("Verification Failure") logging.info("Syncronization Successful") self._write(bytes(self.kNewLine, encoding="utf-8")) self.reset() time.sleep(0.1) - self._write(bytes("A 1"+self.kNewLine, encoding="utf-8")) - #time.sleep(0.1) + self._write(bytes("A 1" + self.kNewLine, encoding="utf-8")) + # time.sleep(0.1) try: frame_in = self._read_line() @@ -528,21 +552,21 @@ def SyncConnection(self): class ChipDescription: - ''' + """ Wraps a chip description line and exposes it as a class - ''' + """ + kWordSize = 4 # 32 bit kPageSizeBytes = 64 SectorSizePages = 16 - CRCLocation = 0x000002fc + CRCLocation = 0x000002FC CRCValues = { - "NO_ISP": 0x4e697370, - "CRP1" : 0x12345678, - "CRP2" : 0x87654321, - "CRP3" : 0x43218765, + "NO_ISP": 0x4E697370, + "CRP1": 0x12345678, + "CRP2": 0x87654321, + "CRP3": 0x43218765, } - def __init__(self, descriptor: dict): self.RAMRange = [0, 0] self.RAMBufferSize = 0 @@ -551,52 +575,55 @@ def __init__(self, descriptor: dict): descriptor: dict for name in dict(descriptor): self.__setattr__(name, descriptor[name]) - self.CrystalFrequency = 12000#khz == 30MHz + self.CrystalFrequency = 12000 # khz == 30MHz self.kCheckSumLocation = 7 # 0x0000001c @property - def MaxByteTransfer (self): + def MaxByteTransfer(self): return self.RAMBufferSize @property def sector_bytes(self): - sector_bytes = self.SectorSizePages*self.kPageSizeBytes - assert sector_bytes%self.kWordSize == 0 + sector_bytes = self.SectorSizePages * self.kPageSizeBytes + assert sector_bytes % self.kWordSize == 0 assert sector_bytes <= self.MaxByteTransfer return sector_bytes def FlashAddressLegal(self, address): - return (self.FlashRange[0] <= address <= self.FlashRange[1]) + return self.FlashRange[0] <= address <= self.FlashRange[1] def FlashRangeLegal(self, address, length): logging.info(f"Flash range {self.FlashRange} {address} {length}") - return self.FlashAddressLegal(address) and\ - self.FlashAddressLegal(address + length - 1) and\ - length <= self.FlashRange[1] - self.FlashRange[0] and\ - address%self.kPageSizeBytes == 0 + return ( + self.FlashAddressLegal(address) + and self.FlashAddressLegal(address + length - 1) + and length <= self.FlashRange[1] - self.FlashRange[0] + and address % self.kPageSizeBytes == 0 + ) def RamAddressLegal(self, address): return self.RAMRange[0] <= address <= self.RAMRange[1] def RamRangeLegal(self, address, length): - return self.RamAddressLegal(address) and\ - self.RamAddressLegal(address + length - 1) and\ - length <= self.RAMRange[1] - self.RAMRange[0] and\ - address%self.kWordSize == 0 + return ( + self.RamAddressLegal(address) + and self.RamAddressLegal(address + length - 1) + and length <= self.RAMRange[1] - self.RAMRange[0] + and address % self.kWordSize == 0 + ) +# Script tools -''' -Script tools -''' +assert ( + tools.calc_crc(bytes([0xFF] * 1024)) == 3090874356 +) # Check the software crc algorithm -assert tools.calc_crc(bytes([0xff]*1024)) == 3090874356 # Check the software crc algorithm - def RemoveBootableCheckSum(vector_table_loc: int, image: bytes) -> bytes: - ''' + """ Erases only the checksum, making the image invalid. The chip will reset into the ISP now. - ''' + """ kuint32_t_size = 4 MakeBootable(vector_table_loc, image) image_list = list(image) @@ -611,15 +638,16 @@ def GetCheckSumedVectorTable(vector_table_loc: int, orig_image: bytes) -> bytes: kuint32_t_size = 4 # Make byte array into list of little endian 32 bit words - intvecs = struct.unpack("<%dI"%vector_table_size, - orig_image[:vector_table_size * kuint32_t_size]) + intvecs = struct.unpack( + "<%dI" % vector_table_size, orig_image[: vector_table_size * kuint32_t_size] + ) # calculate the checksum over the interrupt vectors intvecs_list = list(intvecs[:vector_table_size]) - intvecs_list[vector_table_loc] = 0 # clear csum value + intvecs_list[vector_table_loc] = 0 # clear csum value csum = tools.CalculateCheckSum(intvecs_list) intvecs_list[vector_table_loc] = csum - vector_table_bytes = b'' + vector_table_bytes = b"" for vecval in intvecs_list: vector_table_bytes += struct.pack(" bytes: def MakeBootable(vector_table_loc: int, orig_image: bytes) -> bytes: vector_table_bytes = GetCheckSumedVectorTable(vector_table_loc, orig_image) - image = vector_table_bytes + orig_image[len(vector_table_bytes):] + image = vector_table_bytes + orig_image[len(vector_table_bytes) :] return image def CheckFlashWrite(isp: ISPConnection, data, flash_address: int) -> bool: - ''' + """ Read Memory and compare it to what was written - baud_rate''' + baud_rate""" data_read = isp.ReadMemory(flash_address, len(data)) @@ -647,8 +675,10 @@ def CheckFlashWrite(isp: ISPConnection, data, flash_address: int) -> bool: return data == data_read -def WriteFlashSector(isp: ISPConnection, chip: ChipDescription, sector: int, data: bytes): - ''' +def WriteFlashSector( + isp: ISPConnection, chip: ChipDescription, sector: int, data: bytes +): + """ Safe way to write to flash sector. Basic approach: 1. Write bytes to ram @@ -660,12 +690,17 @@ def WriteFlashSector(isp: ISPConnection, chip: ChipDescription, sector: int, dat To make this more robust we check that each step has completed successfully. After writing RAM check that the CRC matches the data in. After writing the Flash repeat the test - ''' + """ flash_write_sleep = 0.01 ram_write_sleep = 0.01 ram_address = chip.RAMStartWrite - flash_address = chip.FlashRange[0] + sector*chip.sector_bytes - logging.info("\nWriting Sector: %d\tFlash Address: %x\tRAM Address: %x", sector, flash_address, ram_address) + flash_address = chip.FlashRange[0] + sector * chip.sector_bytes + logging.info( + "\nWriting Sector: %d\tFlash Address: %x\tRAM Address: %x", + sector, + flash_address, + ram_address, + ) assert len(data) == chip.sector_bytes # data += bytes(chip.sector_bytes - len(data)) @@ -683,7 +718,9 @@ def WriteFlashSector(isp: ISPConnection, chip: ChipDescription, sector: int, dat time.sleep(ram_write_sleep) isp.reset() time.sleep(ram_write_sleep) - ram_crc = tools.retry(isp.ReadCRC, count=5, exception=(UserWarning, ValueError))(ram_address, num_bytes=len(data)) + ram_crc = tools.retry(isp.ReadCRC, count=5, exception=(UserWarning, ValueError))( + ram_address, num_bytes=len(data) + ) # ram_crc = isp.ReadCRC(ram_address, num_bytes=len(data)) isp.reset() @@ -714,8 +751,10 @@ def WriteFlashSector(isp: ISPConnection, chip: ChipDescription, sector: int, dat isp.CopyRAMToFlash(flash_address, ram_address, chip.sector_bytes) time.sleep(flash_write_sleep) - flash_crc = tools.retry(isp.ReadCRC, count=5, exception=[UserWarning])(flash_address, num_bytes=len(data)) - #flash_crc = isp.ReadCRC() + flash_crc = tools.retry(isp.ReadCRC, count=5, exception=[UserWarning])( + flash_address, num_bytes=len(data) + ) + # flash_crc = isp.ReadCRC() assert flash_crc == data_crc assert isp.MemoryLocationsEqual(flash_address, ram_address, chip.sector_bytes) @@ -724,62 +763,82 @@ def WriteSector(isp: ISPConnection, chip: ChipDescription, sector: int, data: by assert len(data) > 0 if len(data) != chip.sector_bytes: # Fill data buffer to match write size - data += bytes([0xff] *(chip.sector_bytes - len(data))) + data += bytes([0xFF] * (chip.sector_bytes - len(data))) WriteFlashSector(isp, chip, sector, data) - #assert isp.ReadSector(sector) == data_chunk + # assert isp.ReadSector(sector) == data_chunk -def WriteBinaryToFlash(isp: ISPConnection, chip: ChipDescription, image: bytes, start_sector: int, flash_write_sleep : float = 0.05) -> int: - ''' +def WriteBinaryToFlash( + isp: ISPConnection, + chip: ChipDescription, + image: bytes, + start_sector: int, + flash_write_sleep: float = 0.05, +) -> int: + """ Take the image as bytes object. Break the image into sectors and write each in reverse order. On completion return the flash signature which cna be stored for validity checking - ''' + """ flash_write_sleep = 0.05 assert isinstance(image, bytes) logging.info("Program Length: %d", len(image)) sector_count = tools.calc_sector_count(image, chip.sector_bytes) if start_sector + sector_count > chip.SectorCount: - logging.error(f"Invalid sector count\t Start: {start_sector}\tCount: {sector_count}\tEnd: {chip.SectorCount}") + logging.error( + f"Invalid sector count\t Start: {start_sector}\tCount: {sector_count}\tEnd: {chip.SectorCount}" + ) return isp.Unlock() for sector in reversed(range(start_sector, start_sector + sector_count)): logging.info(f"\nWriting Sector {sector}") - data_chunk = image[(sector-start_sector) * chip.sector_bytes : (sector - start_sector + 1) * chip.sector_bytes] + data_chunk = image[ + (sector - start_sector) * chip.sector_bytes : (sector - start_sector + 1) + * chip.sector_bytes + ] WriteSector(isp, chip, sector, data_chunk) time.sleep(flash_write_sleep) - assert chip.FlashAddressLegal(chip.FlashRange[0]) and chip.FlashAddressLegal(chip.FlashRange[1]) - ''' Flash signature reading is only supported for some chips and is partially impimented for others. + assert chip.FlashAddressLegal(chip.FlashRange[0]) and chip.FlashAddressLegal( + chip.FlashRange[1] + ) + """ Flash signature reading is only supported for some chips and is partially impimented for others. time.sleep(0.5) chip_flash_sig = isp.ReadFlashSig(chip.FlashRange[0], chip.FlashRange[1]) logging.info(f"Flash Signature: {chip_flash_sig}") logging.info("Programming Complete.") return chip_flash_sig - ''' + """ -def WriteImage(isp: ISPConnection, chip: ChipDescription, imagein: bytes, flash_write_sleep : float = 0.05): - ''' +def WriteImage( + isp: ISPConnection, + chip: ChipDescription, + imagein: bytes, + flash_write_sleep: float = 0.05, +): + """ 1. Overwrite first sector which clears the checksum bytes making the image unbootable, preventing bricking 2. Read the binary file into memory as a bytes object 3. Write the checksum to the image 4. Write the image in reverse order, the checksum will only be written once the entire valid image is written - ''' + """ # make not bootable isp.Unlock() - WriteSector(isp, chip, 0, bytes([0xde]*chip.sector_bytes)) + WriteSector(isp, chip, 0, bytes([0xDE] * chip.sector_bytes)) - #image = RemoveBootableCheckSum(chip.kCheckSumLocation, prog) + # image = RemoveBootableCheckSum(chip.kCheckSumLocation, prog) image = MakeBootable(chip.kCheckSumLocation, imagein) - WriteBinaryToFlash(isp, chip, image, start_sector=0, flash_write_sleep=flash_write_sleep) + WriteBinaryToFlash( + isp, chip, image, start_sector=0, flash_write_sleep=flash_write_sleep + ) def FindFirstBlankSector(isp: ISPConnection, chip) -> int: - ''' + """ Returns the first blank sector, returns the last sector on failure - ''' + """ for sector in range(chip.SectorCount): sector_blank = isp.CheckSectorsBlank(sector, chip.SectorCount - 1) logging.getLogger().debug("Sector %d Blank: %d", sector, sector_blank) @@ -789,8 +848,7 @@ def FindFirstBlankSector(isp: ISPConnection, chip) -> int: def ReadSector(isp: ISPConnection, chip: ChipDescription, sector: int) -> bytes: - - start = sector*chip.sector_bytes + start = sector * chip.sector_bytes assert chip.FlashRangeLegal(start, chip.sector_bytes) return isp.ReadMemory(start, chip.sector_bytes) @@ -816,8 +874,16 @@ def MassErase(isp: ISPConnection, chip: ChipDescription): isp.EraseSector(0, last_sector) -def SetupChip(baudrate: int, device: object, crystal_frequency: int, chip_file: str, no_sync: bool = False, sleep_time : float = 1, serial_sleep: float = 0): - ''' +def SetupChip( + baudrate: int, + device: object, + crystal_frequency: int, + chip_file: str, + no_sync: bool = False, + sleep_time: float = 1, + serial_sleep: float = 0, +): + """ :param int baudrate: The baudrate to set or use. If no_sync is True this baudrate is assumed to already be set :param str device: Serial port :param float crystal_frequency: On board oscillator @@ -833,9 +899,9 @@ def SetupChip(baudrate: int, device: object, crystal_frequency: int, chip_file: + Tries to sync the connection + Sets the baudrate + Reads the chip ID and returns the matching chip description - ''' + """ - if(no_sync): + if no_sync: kStartingBaudRate = baudrate else: kStartingBaudRate = BAUDRATES[0] @@ -863,14 +929,14 @@ def SetupChip(baudrate: int, device: object, crystal_frequency: int, chip_file: chip = ChipDescription(descriptor) chip.CrystalFrequency = crystal_frequency - print("Setting new baudrate %d"%baudrate) + print("Setting new baudrate %d" % baudrate) isp.SetBaudRate(baudrate) # set the chips baudrate isp.baud_rate = baudrate # change the driver baudrate return isp, chip def read_image_file_to_bin(image_file: str): - extension = os.path.splitext(image_file)[-1].lstrip('.').lower() + extension = os.path.splitext(image_file)[-1].lstrip(".").lower() ih = IntelHex() ih.fromfile(image_file, format=extension) return ih.tobinarray() diff --git a/src/isp_programmer/__init__.py b/src/isp_programmer/__init__.py index 2a8cb90..e69de29 100644 --- a/src/isp_programmer/__init__.py +++ b/src/isp_programmer/__init__.py @@ -1,4 +0,0 @@ -from .IODevices import IODevice, MockUart, UartDevice -from .parts_definitions import GetPartDescriptor -from . import tools -from . ISPConnection import ISPConnection, ChipDescription, WriteImage, MassErase, CheckFlashWrite, WriteBinaryToFlash, ReadImage, ReadSector, SetupChip, read_image_file_to_bin, BAUDRATES diff --git a/src/isp_programmer/cli.py b/src/isp_programmer/cli.py index ae1d472..5eede42 100644 --- a/src/isp_programmer/cli.py +++ b/src/isp_programmer/cli.py @@ -1,23 +1,42 @@ import os import logging import click -from .ISPConnection import UartDevice, BAUDRATES, ISPConnection, SetupChip, MassErase, read_image_file_to_bin, ReadImage, WriteBinaryToFlash, WriteImage +from .ISPConnection import ( + UartDevice, + BAUDRATES, + ISPConnection, + SetupChip, + MassErase, + read_image_file_to_bin, + ReadImage, + WriteBinaryToFlash, + WriteImage, +) _chip_defs = os.path.join(os.path.dirname(__file__), "lpctools_parts.def") + @click.group() -@click.option('--device', '-d', default='/dev/ttyUSB0', help='Serial device') -@click.option('--baud', '-b', type=int, default=BAUDRATES[0], help='Baudrate') -@click.option('--crystal-frequency', '-c', type=int, default=12000, - help="Crystal frequency of chip in khz") -@click.option('--config-file', '-f', default=_chip_defs, - help='Parts definition file') -@click.option('--echo', is_flag=True) -@click.option('--no-sync', is_flag=True) -@click.option('--sleep-time', '-s', type=float, default=0.25, help='Sleep time between commands') -@click.option('--serial-sleep', type=float, default=0, help='Sleep time between serial bytes') -@click.option('--debug', is_flag=True) +@click.option("--device", "-d", default="/dev/ttyUSB0", help="Serial device") +@click.option("--baud", "-b", type=int, default=BAUDRATES[0], help="Baudrate") +@click.option( + "--crystal-frequency", + "-c", + type=int, + default=12000, + help="Crystal frequency of chip in khz", +) +@click.option("--config-file", "-f", default=_chip_defs, help="Parts definition file") +@click.option("--echo", is_flag=True) +@click.option("--no-sync", is_flag=True) +@click.option( + "--sleep-time", "-s", type=float, default=0.25, help="Sleep time between commands" +) +@click.option( + "--serial-sleep", type=float, default=0, help="Sleep time between serial bytes" +) +@click.option("--debug", is_flag=True) @click.pass_context def gr1(ctx, **kwargs): ctx.ensure_object(dict) @@ -33,7 +52,7 @@ def gr1(ctx, **kwargs): @gr1.command("sync", help="Read the chip ID and boot code") @click.pass_context def cli_sync(ctx): - iodevice = UartDevice(ctx.obj['device'], baudrate=ctx.obj['baud']) + iodevice = UartDevice(ctx.obj["device"], baudrate=ctx.obj["baud"]) isp = ISPConnection(iodevice) isp.SyncConnection() @@ -41,49 +60,91 @@ def cli_sync(ctx): @gr1.command("query-chip", help="Read the chip ID and boot code") @click.pass_context def cli_QueryChip(ctx): - iodevice = UartDevice(ctx.obj['device'], baudrate=ctx.obj['baud']) + iodevice = UartDevice(ctx.obj["device"], baudrate=ctx.obj["baud"]) isp = ISPConnection(iodevice) boot_version = isp.ReadBootCodeVersion() uid = isp.ReadUID() part_id = isp.ReadPartID() - logging.info("Part ID: 0x%x\tPart UID: %s\tBoot Code Version: %s", part_id, uid, boot_version) + logging.info( + "Part ID: 0x%x\tPart UID: %s\tBoot Code Version: %s", part_id, uid, boot_version + ) @gr1.command("erase", help="Erase entire chip") @click.pass_context def cli_MassErase(ctx): - isp, chip = SetupChip(ctx.obj['baud'], ctx.obj['device'], ctx.obj['crystal_frequency'], ctx.obj['config_file'], ctx.obj['no_sync'], ctx.obj['sleep_time'], serial_sleep=ctx.obj['serial_sleep']) + isp, chip = SetupChip( + ctx.obj["baud"], + ctx.obj["device"], + ctx.obj["crystal_frequency"], + ctx.obj["config_file"], + ctx.obj["no_sync"], + ctx.obj["sleep_time"], + serial_sleep=ctx.obj["serial_sleep"], + ) MassErase(isp, chip) logging.info("Mass Erase Successful") -@click.option('--start_sector', type=int, default=0, required=True, help='Sector to write to') -@click.option('--imagein', type=str, required=True, help='Location of hex file to program') +@click.option( + "--start_sector", type=int, default=0, required=True, help="Sector to write to" +) +@click.option( + "--imagein", type=str, required=True, help="Location of hex file to program" +) @gr1.command("write-flash", help="Write a specific flash sector") @click.pass_context def cli_WriteFlash(ctx, imagein, start_sector): - isp, chip = SetupChip(ctx.obj['baud'], ctx.obj['device'], ctx.obj['crystal_frequency'], ctx.obj['config_file'], ctx.obj['no_sync'], ctx.obj['sleep_time'], serial_sleep=ctx.obj['serial_sleep']) + isp, chip = SetupChip( + ctx.obj["baud"], + ctx.obj["device"], + ctx.obj["crystal_frequency"], + ctx.obj["config_file"], + ctx.obj["no_sync"], + ctx.obj["sleep_time"], + serial_sleep=ctx.obj["serial_sleep"], + ) image = read_image_file_to_bin(imagein) WriteBinaryToFlash(isp=isp, chip=chip, image=image, start_sector=start_sector) -@click.option('--imagein', type=str, required=True, help='Location of hex file to program') +@click.option( + "--imagein", type=str, required=True, help="Location of hex file to program" +) @gr1.command("write-image", help="Write image") @click.pass_context def cli_WriteImage(ctx, imagein): - isp, chip = SetupChip(ctx.obj['baud'], ctx.obj['device'], ctx.obj['crystal_frequency'], ctx.obj['config_file'], ctx.obj['no_sync'], ctx.obj['sleep_time'], serial_sleep=ctx.obj['serial_sleep']) + isp, chip = SetupChip( + ctx.obj["baud"], + ctx.obj["device"], + ctx.obj["crystal_frequency"], + ctx.obj["config_file"], + ctx.obj["no_sync"], + ctx.obj["sleep_time"], + serial_sleep=ctx.obj["serial_sleep"], + ) image = read_image_file_to_bin(imagein) WriteImage(isp, chip, image) isp.Go(0) -@click.option('--imagein', type=str, required=True, help='Location of hex file to program') -@gr1.command("fast-write-image", help='Test CRC and exit if it matches the flash') +@click.option( + "--imagein", type=str, required=True, help="Location of hex file to program" +) +@gr1.command("fast-write-image", help="Test CRC and exit if it matches the flash") @click.pass_context def cli_FastWriteImage(ctx, imagein): - isp, chip = SetupChip(ctx.obj['baud'], ctx.obj['device'], ctx.obj['crystal_frequency'], ctx.obj['config_file'], ctx.obj['no_sync'], ctx.obj['sleep_time'], serial_sleep=ctx.obj['serial_sleep']) + isp, chip = SetupChip( + ctx.obj["baud"], + ctx.obj["device"], + ctx.obj["crystal_frequency"], + ctx.obj["config_file"], + ctx.obj["no_sync"], + ctx.obj["sleep_time"], + serial_sleep=ctx.obj["serial_sleep"], + ) image = read_image_file_to_bin(imagein) - image_read = ReadImage(isp, chip)[:len(image)] + image_read = ReadImage(isp, chip)[: len(image)] if bytes(image) == image_read: logging.getLogger().info("Already programmed") else: @@ -91,14 +152,22 @@ def cli_FastWriteImage(ctx, imagein): isp.Go(0) -@click.option('--imageout', type=str, required=True, help='Name of hex file output') +@click.option("--imageout", type=str, required=True, help="Name of hex file output") @gr1.command("read-image", help="Read the chip image") @click.pass_context def cli_ReadImage(ctx, imageout: str): - isp, chip = SetupChip(ctx.obj['baud'], ctx.obj['device'], ctx.obj['crystal_frequency'], ctx.obj['config_file'], ctx.obj['no_sync'], ctx.obj['sleep_time'], serial_sleep=ctx.obj['serial_sleep']) + isp, chip = SetupChip( + ctx.obj["baud"], + ctx.obj["device"], + ctx.obj["crystal_frequency"], + ctx.obj["config_file"], + ctx.obj["no_sync"], + ctx.obj["sleep_time"], + serial_sleep=ctx.obj["serial_sleep"], + ) image = ReadImage(isp, chip) logging.getLogger().debug(image) - with open(imageout, 'wb') as f: + with open(imageout, "wb") as f: f.write(image) diff --git a/src/isp_programmer/lpctools_parts.def b/src/isp_programmer/lpctools_parts.def index 107ed7d..2085ce2 100644 --- a/src/isp_programmer/lpctools_parts.def +++ b/src/isp_programmer/lpctools_parts.def @@ -45,4 +45,3 @@ 0x00008221, LPC822M201JHI33, 0x00000000, 0x4000, 32, 0x04, 0x10000000, 0x1000, 0x600, 0x800, 0 0x00008242, LPC824M101JDH20, 0x00000000, 0x8000, 32, 0x04, 0x10000000, 0x2000, 0x600, 0x800, 0 0x00008241, LPC824M201JHI33, 0x00000000, 0x8000, 32, 0x04, 0x10000000, 0x2000, 0x600, 0x800, 0 - diff --git a/src/isp_programmer/parts_definitions.py b/src/isp_programmer/parts_definitions.py index d7e1051..8759cb4 100644 --- a/src/isp_programmer/parts_definitions.py +++ b/src/isp_programmer/parts_definitions.py @@ -1,25 +1,26 @@ -''' +""" Parser for the lpctools file, read into a data frame that is consitant with other formats -''' +""" + import pandas import numpy as np column_names = [ - "part id", - "name", - "FlashStart", - "FlashEnd", - "FlashSize", - "SectorCount", - "ResetVectorOffset", - "RAMStart", - "RAMEnd", - "RAMSize", - "RAMBufferOffset", - "RAMBufferSize", - "UU Encode", - "RAMStartWrite", + "part id", + "name", + "FlashStart", + "FlashEnd", + "FlashSize", + "SectorCount", + "ResetVectorOffset", + "RAMStart", + "RAMEnd", + "RAMSize", + "RAMBufferOffset", + "RAMBufferSize", + "UU Encode", + "RAMStartWrite", ] @@ -43,9 +44,9 @@ def read_lpcparts_string(string: str): f = string.splitlines() for line in f: - if not line.strip() or line.strip()[0] == '#': + if not line.strip() or line.strip()[0] == "#": continue - split_line = line.strip().split(',') + split_line = line.strip().split(",") for column, index in lpc_tools_column_locations.items(): value = split_line[index].strip() try: @@ -68,10 +69,10 @@ def read_lpcparts_string(string: str): def ReadChipFile(fname: str) -> pandas.DataFrame: - ''' + """ Reads an lpcparts style file to a dataframe - ''' - with open(fname, 'r') as f: + """ + with open(fname, "r") as f: df = read_lpcparts_string(f.read()) return df @@ -88,16 +89,16 @@ def GetPartDescriptorLine(fname: str, partid: int) -> list: def GetPartDescriptor(fname: str, partid: int) -> dict: descriptor = GetPartDescriptorLine(fname, partid) if descriptor is None: - raise UserWarning("Warning chip %s not found in file %s"%(hex(partid), fname)) + raise UserWarning("Warning chip %s not found in file %s" % (hex(partid), fname)) return descriptor def check_parts_definition_dataframe(df): - ''' + """ Takes the standard layout dataframe, check the field validity - ''' + """ valid = True for _, line in df.iterrows(): if line["RAMRange"][1] - line["RAMRange"][0] + 1 != line["RAMSize"]: - valid=False + valid = False return valid diff --git a/src/isp_programmer/tools.py b/src/isp_programmer/tools.py index d93408c..b7ee116 100644 --- a/src/isp_programmer/tools.py +++ b/src/isp_programmer/tools.py @@ -5,6 +5,7 @@ from pycrc.algorithms import Crc import timeout_decorator + def collection_to_string(arr): return "".join([chr(ch) for ch in arr]) @@ -14,14 +15,20 @@ def CalculateCheckSum(frame) -> int: csum = 0 for entry in frame: csum += entry - return (1<<32) - (csum % (1<<32)) + return (1 << 32) - (csum % (1 << 32)) def Crc32(frame: bytes) -> int: # CRC32 - polynomial = 0x104c11db6 - crc = Crc(width=32, poly=polynomial, reflect_in=True, - xor_in=(1<<32)-1, reflect_out=True, xor_out=0x00) + polynomial = 0x104C11DB6 + crc = Crc( + width=32, + poly=polynomial, + reflect_in=True, + xor_in=(1 << 32) - 1, + reflect_out=True, + xor_out=0x00, + ) crc_calc = crc.bit_by_bit(frame) return crc_calc @@ -31,12 +38,14 @@ def calc_crc(frame: bytes): # return Crc32(frame) -def retry(_func=None, *, count=2, exception=timeout_decorator.TimeoutError, raise_on_fail=True): +def retry( + _func=None, *, count=2, exception=timeout_decorator.TimeoutError, raise_on_fail=True +): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): value = None - for i in range(1, count+1): + for i in range(1, count + 1): try: assert func value = func(*args, **kwargs) @@ -46,11 +55,13 @@ def wrapper(*args, **kwargs): if i >= count and raise_on_fail: raise UserWarning(f"{_func} retry exceeded {count}") return value + return wrapper + if _func is None: return decorator return decorator(_func) def calc_sector_count(image, sector_bytes): - return int(math.ceil(len(image)/sector_bytes)) + return int(math.ceil(len(image) / sector_bytes))