diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..699b26b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*/__pycache__/* +*.hex +*.dfu diff --git a/Bootup Logos/img2logo.py b/Bootup Logos/img2logo.py index 3e5239f..e4bc7fb 100644 --- a/Bootup Logos/img2logo.py +++ b/Bootup Logos/img2logo.py @@ -1,135 +1,59 @@ #!/usr/bin/env python # coding=utf-8 from __future__ import division -import os, sys, struct, zlib +import argparse +import os, sys +from output_hex import HexOutput +from output_dfu import DFUOutput try: from PIL import Image, ImageOps except ImportError as error: - raise ImportError("{}: {} requres Python Imaging Library (PIL). " - "Install with `pip` or OS-specific package " - "management tool." - .format(error, sys.argv[0])) - -VERSION_STRING = '0.03' - -LCD_WIDTH = 96 -LCD_HEIGHT = 16 -LCD_NUM_BYTES = LCD_WIDTH * LCD_HEIGHT // 8 -LCD_PADDED_SIZE = 1024 - -INTELHEX_DATA_RECORD = 0x00 -INTELHEX_END_OF_FILE_RECORD = 0x01 -INTELHEX_EXTENDED_LINEAR_ADDRESS_RECORD = 0x04 -INTELHEX_BYTES_PER_LINE = 16 -INTELHEX_MINIMUM_SIZE = 4096 - -DFU_PINECIL_ALT = 0 -DFU_PINECIL_VENDOR = 0x28e9 -DFU_PINECIL_PRODUCT = 0x0189 -DFU_LOGO_ADDRESS = 0x0801F800 -DFU_TARGET_NAME = b"Pinecil" -DFU_PREFIX_SIZE = 11 -DFU_SUFFIX_SIZE = 16 - -def split16(word): - """return high and low byte of 16-bit word value as tuple""" - return (word >> 8) & 0xff, word & 0xff - - -def compute_crc(data): - return 0xFFFFFFFF & -zlib.crc32(data) - 1 - - -def intel_hex_line(record_type, offset, data): - """generate a line of data in Intel hex format""" - # length, address offset, record type - record_length = len(data) - yield ':{:02X}{:04X}{:02X}'.format(record_length, offset, record_type) - - # data - for byte in data: - yield "{:02X}".format(byte) - - # compute and write checksum (now using unix style line endings for DFU3.45 compatibility - yield "{:02X}\n".format((((sum(data, # sum data ... - record_length # ... and other ... - + sum(split16(offset)) # ... fields ... - + record_type) # ... on line - & 0xff) # low 8 bits - ^ 0xff) # two's ... - + 1) # ... complement - & 0xff) # low 8 bits - - -def intel_hex(file, bytes_, start_address=0x0): - """write block of data in Intel hex format""" - def write(generator): - file.write(''.join(generator)) - - if len(bytes_) % INTELHEX_BYTES_PER_LINE != 0: - raise ValueError("Program error: Size of LCD data is not evenly divisible by {}" - .format(INTELHEX_BYTES_PER_LINE)) - - address_lo = start_address & 0xffff - address_hi = (start_address >> 16) & 0xffff - - write(intel_hex_line(INTELHEX_EXTENDED_LINEAR_ADDRESS_RECORD, 0, - split16(address_hi))) - - size_written = 0 - while size_written < INTELHEX_MINIMUM_SIZE: - offset = address_lo - for line_start in range(0, len(bytes_), INTELHEX_BYTES_PER_LINE): - write(intel_hex_line(INTELHEX_DATA_RECORD, offset, - bytes_[line_start:line_start + INTELHEX_BYTES_PER_LINE])) - size_written += INTELHEX_BYTES_PER_LINE - if size_written >= INTELHEX_MINIMUM_SIZE: - break - offset += INTELHEX_BYTES_PER_LINE - - write(intel_hex_line(INTELHEX_END_OF_FILE_RECORD, 0, ())) - - -def build_dfu(file, bytes_): - data = b"" - for byte in bytes_: - data += byte.to_bytes(1, byteorder="big") - - data = ( - struct.pack("<2I", DFU_LOGO_ADDRESS, len(data)) + data + raise ImportError( + "{}: {} requres Python Imaging Library (PIL). " + "Install with `pip` (pip3 install pillow) or OS-specific package " + "management tool.".format(error, sys.argv[0]) ) - data = ( - struct.pack( - "<6sBI255s2I", b"Target", DFU_PINECIL_ALT, 1, DFU_TARGET_NAME, len(data), 1 - ) - + data - ) - data = ( - struct.pack( - "<5sBIB", b"DfuSe", 1, DFU_PREFIX_SIZE + len(data) + DFU_SUFFIX_SIZE, 1 - ) - + data - ) - data += struct.pack("<4H3sB", 0, DFU_PINECIL_PRODUCT, DFU_PINECIL_VENDOR, 0x011A, b"UFD", DFU_SUFFIX_SIZE) - crc = compute_crc(data) - data += struct.pack("> 8) & 0xFF, word & 0xFF + + @classmethod + def compute_crc(cls, data): + return 0xFFFFFFFF & -zlib.crc32(data) - 1 + + @classmethod + def intel_hex_line(cls, record_type, offset, data): + """generate a line of data in Intel hex format""" + # length, address offset, record type + record_length = len(data) + yield ":{:02X}{:04X}{:02X}".format(record_length, offset, record_type) + + # data + for byte in data: + yield "{:02X}".format(byte) + + # compute and write checksum (now using unix style line endings for DFU3.45 compatibility + yield "{:02X}\n".format( + ( + ( + ( + sum( + data, # sum data ... + record_length # ... and other ... + + sum(cls.split16(offset)) # ... fields ... + + record_type, + ) # ... on line + & 0xFF + ) # low 8 bits + ^ 0xFF + ) # two's ... + + 1 + ) # ... complement + & 0xFF + ) # low 8 bits + + @classmethod + def writeFile(cls, file_name: str, data: bytearray, data_address: int): + """write block of data in Intel hex format""" + with open(file_name, "w", newline="\r\n") as output: + + def write(generator): + output.write("".join(generator)) + + if len(data) % cls.INTELHEX_BYTES_PER_LINE != 0: + raise ValueError( + "Program error: Size of LCD data is not evenly divisible by {}".format( + cls.INTELHEX_BYTES_PER_LINE + ) + ) + + address_lo = data_address & 0xFFFF + address_hi = (data_address >> 16) & 0xFFFF + + write( + cls.intel_hex_line( + cls.INTELHEX_EXTENDED_LINEAR_ADDRESS_RECORD, + 0, + cls.split16(address_hi), + ) + ) + + size_written = 0 + while size_written < cls.INTELHEX_MINIMUM_SIZE: + offset = address_lo + for line_start in range(0, len(data), cls.INTELHEX_BYTES_PER_LINE): + write( + cls.intel_hex_line( + cls.INTELHEX_DATA_RECORD, + offset, + data[line_start : line_start + cls.INTELHEX_BYTES_PER_LINE], + ) + ) + size_written += cls.INTELHEX_BYTES_PER_LINE + if size_written >= cls.INTELHEX_MINIMUM_SIZE: + break + offset += cls.INTELHEX_BYTES_PER_LINE + + write(cls.intel_hex_line(cls.INTELHEX_END_OF_FILE_RECORD, 0, ())) + + +if __name__ == "__main__": + import sys + + print("DO NOT CALL THIS FILE DIRECTLY") + sys.exit(1)