Mercurial > lcfOS
view python/hexfile.py @ 244:58155c7c4a8e
Add hexutil
author | Windel Bouwman |
---|---|
date | Wed, 24 Jul 2013 19:47:13 +0200 |
parents | 6259856841a0 |
children | 66912720d712 |
line wrap: on
line source
import os import struct class HexFileException(Exception): pass def parseHexLine(line): """ Parses a hexfile line into three parts """ line = line[1:] # Remove ':' nums = bytes.fromhex(line) bytecount = nums[0] if len(nums) != bytecount + 5: raise HexFileException('byte count field incorrect') crc = sum(nums) if (crc & 0xFF) != 0: raise HexFileException('crc incorrect') address = struct.unpack('>H', nums[1:3])[0] typ = nums[3] data = nums[4:-1] return (address, typ, data) def makeHexLine(address, typ, data=bytes()): bytecount = len(data) nums = bytearray() nums.append(bytecount) nums.extend(struct.pack('>H', address)) nums.append(typ) nums.extend(data) crc = sum(nums) crc = ((~crc) + 1) & 0xFF nums.append(crc) line = ':' + ''.join(['{:02X}'.format(b) for b in nums]) return line def chunks(data, csize=16): idx = 0 while idx < len(data): s = min(len(data) - idx, csize) yield data[idx:idx+s] idx += s class HexFile: """ Represents an intel hexfile """ def __init__(self): self.regions = [] self.startAddress = 0 def load(self, f): endOfFile = False offset = 0 startAddress = 0 curAddress = 0 curData = bytearray() for line in f: line = line.strip() # Strip spaces and newlines if not line: continue # Skip empty lines if line[0] != ':': continue # Skip lines that do not start with a ':' if endOfFile: raise HexFileException('hexfile line after end of file record') address, typ, data = parseHexLine(line) if typ == 0x0: # Data record address += offset # Fix address with offset # Append data if address == curAddress: curData += data curAddress += len(data) else: if curData: self.regions.append(HexFileRegion(startAddress, bytes(curData))) startAddress = address curAddress = address + len(data) curData = bytearray(data) elif typ == 0x4: # Extended linear address record offset = ((data[0] << 8) + data[1]) << 16 elif typ == 0x1: # End of file record if len(data) != 0: raise HexFileException('end of file record must contain no data') endOfFile = True elif typ == 0x5: # Start address record (where IP goes after loading) self.startAddress = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3] else: raise HexFileException('record type {0} not implemented'.format(typ)) print(hex(address), typ, data) # After all lines: if curData: self.regions.append(HexFileRegion(startAddress, bytes(curData))) def __repr__(self): return 'Hexfile with {} regions'.format(len(self.regions)) def dump(self): print(self) for r in self.regions: print(r) def __eq__(self, other): regions = self.regions oregions = other.regions if len(regions) != len(oregions): return False return all(rs == ro for rs, ro in zip(regions, oregions)) def addRegion(self, address, data): r = HexFileRegion(address, data) # TODO: check touches self.regions.append(r) self.regions.sort(key=lambda r: r.address) def save(self, f): for r in self.regions: offset = 0 for chunk in chunks(r.data): print(makeHexLine(r.address + offset, 0x0, bytes(r.data[offset:offset+16])), file=f) offset += len(chunk) print(makeHexLine(0, 0x1, bytes()), file=f) class HexFileRegion: def __init__(self, address, data = bytes()): self.address = address self.data = data def __repr__(self): return 'Region at 0x{0:X} of {1} bytes'.format(self.address, len(self.data)) def __eq__(self, other): return (self.address, self.data) == (other.address, other.data) @property def EndAddress(self): return self.address + len(self.data) if __name__ == '__main__': h = HexFile() print(h) """ Test hexfile implementation with some hexfile """ h1 = HexFile() with open('audio.hex', 'r') as f: h1.load(f) print(h1)