""" # TOP2049 Open Source programming suite # # Utility functions # # Copyright (c) 2009-2011 Michael Buesch # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ import sys import re import math import random class TOPException(Exception): pass if sys.version_info[0] == 2: # Python 2.x def byte2int(byte): return ord(byte) def int2byte(integer): return chr(integer) else: # Python 3.x def byte2int(byte): return int(byte[0]) def int2byte(integer): return bytes( (integer, ) ) def hex2bin(hexdata): assert(len(hexdata) % 2 == 0) bindata = map(lambda i: int2byte(int(hexdata[i:i+2], 16)), range(0, len(hexdata), 2)) return b"".join(bindata) def byte2hex(byte): return "%02X" % byte2int(byte) def bytes2hex(bindata): if not bindata: return "" return "".join(map(byte2hex, bindata)) def byte2ascii(c): ci = byte2int(c) if ci >= 32 and ci <= 126: return c.decode("ASCII") return "." def bytes2ascii(bindata): if not bindata: return "" return "".join(map(byte2ascii, bindata)) def str2bool(string): string = str(string).lower().strip() if string in ("false", "off", "no"): return False if string in ("true", "on", "yes"): return True try: return bool(int(string, 10)) except (ValueError), e: pass return None def genRandomBlob(size): blob = map(lambda x: int2byte(random.randint(0, 0xFF)), range(0, size)) return b"".join(blob) def bit(bitNr): return 1 << bitNr def nrBitsSet(integer): count = 0 while integer: count += (integer & 1) integer >>= 1 return count def roundup(x, y): x, y = int(x), int(y) return ((x + (y - 1)) // y) * y hexdump_re = re.compile(r"0x[0-9a-fA-F]+:\s+([0-9a-fA-F\s]+)\s*.*") def parseHexdump(dump): try: bin = [] for line in dump.splitlines(): line = line.strip() if not line: continue m = hexdump_re.match(line) if not m: raise TOPException("Invalid hexdump format (regex failure)") bytes = m.group(1).replace(" ", "") if len(bytes) % 2 != 0: raise TOPException("Invalid hexdump format (odd bytestring len)") for i in range(0, len(bytes), 2): byte = int(bytes[i:i+2], 16) bin.append(int2byte(byte)) return b"".join(bin) except (ValueError), e: raise TOPException("Invalid hexdump format (Integer error)") def generateHexdump(mem): ret = "" asc = "" for i in range(0, len(mem)): if i % 16 == 0 and i != 0: ret += " " + asc + "\n" asc = "" if i % 16 == 0: ret += "0x%04X: " % i c = byte2int(mem[i]) ret += "%02X" % c if (i % 2 != 0): ret += " " asc += byte2ascii(mem[i]) ret += " " + asc + "\n\n" return ret def dumpMem(mem): sys.stdout.write(generateHexdump(mem)) class IO_ihex(object): TYPE_DATA = 0 TYPE_EOF = 1 TYPE_ESAR = 2 TYPE_SSAR = 3 TYPE_ELAR = 4 TYPE_SLAR = 5 def autodetect(self, data): try: self.toBinary(data) except (TOPException), e: return False return True def toBinary(self, ihexData, addressRange=None, defaultBytes=b"\xFF"): bin = [] checksumWarned = False doublewriteWarned = False addrBias = addressRange.startAddress if addressRange else 0 try: lines = ihexData.splitlines() hiAddr = 0 segment = 0 for line in lines: line = line.strip() if len(line) == 0: continue if len(line) < 11 or (len(line) - 1) % 2 != 0: raise TOPException("Invalid IHEX format (length error)") if line[0] != ':': raise TOPException("Invalid IHEX format (magic error)") count = int(line[1:3], 16) if len(line) != count * 2 + 11: raise TOPException("Invalid IHEX format (count error)") addr = (int(line[3:5], 16) << 8) | int(line[5:7], 16) addr |= hiAddr << 16 addr += segment * 16 if hiAddr and segment: print("WARNING: IHEX has ESAR and ELAR record") type = int(line[7:9], 16) checksum = 0 for i in range(1, len(line), 2): byte = int(line[i:i+2], 16) checksum = (checksum + byte) & 0xFF checksum = checksum & 0xFF if checksum != 0 and not checksumWarned: checksumWarned = True print "WARNING: Invalid IHEX format (checksum error)" if type == self.TYPE_EOF: break if type == self.TYPE_ESAR: if count != 2: raise TOPException("Invalid IHEX format (inval ESAR)") segment = (int(line[9:11], 16) << 8) | int(line[11:13], 16) continue if type == self.TYPE_ELAR: if count != 2: raise TOPException("Invalid IHEX format (inval ELAR)") hiAddr = (int(line[9:11], 16) << 8) | int(line[11:13], 16) continue if addressRange and addr < addressRange.startAddress: continue if addressRange and addr > addressRange.endAddress: continue if type == self.TYPE_DATA: if len(bin) < addr - addrBias + count: # Reallocate bytesToAdd = addr - addrBias + count - len(bin) for i in range(bytesToAdd): defOffs = len(bin) % len(defaultBytes) bin += [ defaultBytes[defOffs], ] for i in range(9, 9 + count * 2, 2): byte = int2byte(int(line[i:i+2], 16)) offset = (i - 9) // 2 + addr - addrBias if bin[offset] != defaultBytes[offset % len(defaultBytes)] and \ not doublewriteWarned: doublewriteWarned = True print "Invalid IHEX format (Wrote twice to same location)" bin[offset] = byte continue raise TOPException("Invalid IHEX format (unsup type %d)" % type) except ValueError: raise TOPException("Invalid IHEX format (digit format)") return b"".join(bin) def fromBinary(self, binData): ihex = [] addr = 0 for i in range(0, len(binData), 16): if addr > 0xFFFF: checksum = 0 ihex.append(":%02X%04X%02X" % (2, 0, self.TYPE_ELAR)) checksum += 2 + 0 + 0 + self.TYPE_ELAR a = (addr >> 16) & 0xFFFF ihex.append("%04X" % a) checksum += ((a >> 8) & 0xFF) + (a & 0xFF) checksum = ((checksum ^ 0xFF) + 1) & 0xFF ihex.append("%02X\n" % checksum) addr -= 0xFFFF checksum = 0 size = min(len(binData) - i, 16) ihex.append(":%02X%04X%02X" % (size, addr, self.TYPE_DATA)) checksum += size + ((addr >> 8) & 0xFF) + (addr & 0xFF) + self.TYPE_DATA for j in range(0, size): data = byte2int(binData[i + j]) checksum = (checksum + data) & 0xFF ihex.append("%02X" % data) checksum = ((checksum ^ 0xFF) + 1) & 0xFF ihex.append("%02X\n" % checksum) addr += size ihex.append(":00000001FF\n") return "".join(ihex) class IO_ahex(object): def autodetect(self, data): try: self.toBinary(data) except (TOPException), e: return False return True def toBinary(self, data, addressRange=None, defaultBytes=b"\xFF"): # defaultBytes is ignored binData = parseHexdump(data) if addressRange: binData = binData[addressRange.startAddress : addressRange.endAddress + 1] return binData def fromBinary(self, data): return generateHexdump(data) class IO_binary(object): def autodetect(self, data): return True def toBinary(self, data, addressRange=None, defaultBytes=b"\xFF"): # defaultBytes is ignored if addressRange: data = data[addressRange.startAddress : addressRange.endAddress + 1] return data def fromBinary(self, data): return data def IO_autodetect(data): "Returns an IO_... object for the data." if IO_ihex().autodetect(data): return IO_ihex elif IO_ahex().autodetect(data): return IO_ahex elif IO_binary().autodetect(data): return IO_binary assert(0) # Can't reach, because binary will always match.