Clean up Intel HEX utilities

No functional change intended.
This commit is contained in:
Grigori Goronzy 2017-09-24 14:29:19 +02:00
parent ebcfeb467c
commit 8b0fdcb42a

View File

@ -5,201 +5,214 @@
import struct import struct
import codecs import codecs
class IHex(object):
@classmethod
def read(cls, lines):
ihex = cls()
segbase = 0 class IHex:
for line in lines: """Intel HEX parser and writer"""
line = line.strip()
if not line: continue
t, a, d = ihex.parse_line(line) @classmethod
if t == 0x00: def read(cls, lines):
ihex.insert_data(segbase + a, d) """Read Intel HEX data from string or lines"""
ihex = cls()
elif t == 0x01: segbase = 0
break # Should we check for garbage after this? for line in lines:
line = line.strip()
if not line:
continue
elif t == 0x02: t, a, d = ihex.parse_line(line)
ihex.set_mode(16) if t == 0x00:
segbase = struct.unpack(">H", d[0:2])[0] << 4 ihex.insert_data(segbase + a, d)
elif t == 0x03: elif t == 0x01:
ihex.set_mode(16) break # Should we check for garbage after this?
cs, ip = struct.unpack(">2H", d[0:2]) elif t == 0x02:
ihex.set_start((cs, ip)) ihex.set_mode(16)
segbase = struct.unpack(">H", d[0:2])[0] << 4
elif t == 0x04: elif t == 0x03:
ihex.set_mode(32) ihex.set_mode(16)
segbase = struct.unpack(">H", d[0:2])[0] << 16
elif t == 0x05: cs, ip = struct.unpack(">2H", d[0:2])
ihex.set_mode(32) ihex.set_start((cs, ip))
ihex.set_start(struct.unpack(">I", d[0:4])[0])
else: elif t == 0x04:
raise ValueError("Invalid type byte") ihex.set_mode(32)
segbase = struct.unpack(">H", d[0:2])[0] << 16
return ihex elif t == 0x05:
ihex.set_mode(32)
ihex.set_start(struct.unpack(">I", d[0:4])[0])
@classmethod else:
def read_file(cls, fname): raise ValueError("Invalid type byte")
f = open(fname, "rb")
ihex = cls.read(f)
f.close()
return ihex
def __init__(self): return ihex
self.areas = {}
self.start = None
self.mode = 8
self.row_bytes = 16
def set_row_bytes(self, row_bytes): @classmethod
"""Set output hex file row width (bytes represented per row).""" def read_file(cls, fname):
if row_bytes < 1 or row_bytes > 0xff: """Read Intel HEX data from file"""
raise ValueError("Value out of range: (%r)" % row_bytes) f = open(fname, "rb")
self.row_bytes = row_bytes ihex = cls.read(f)
f.close()
return ihex
def extract_data(self, start=None, end=None): def __init__(self):
if start is None: self.areas = {}
start = 0 self.start = None
self.mode = 8
self.row_bytes = 16
if end is None: def set_row_bytes(self, row_bytes):
result = bytearray() """Set output hex file row width (bytes represented per row)."""
if row_bytes < 1 or row_bytes > 0xff:
raise ValueError("Value out of range: (%r)" % row_bytes)
self.row_bytes = row_bytes
for addr, data in self.areas.items(): def extract_data(self, start=None, end=None):
if addr >= start: """Extract binary data"""
if len(result) < (addr - start): if start is None:
result[len(result):addr-start] = bytes(addr-start-len(result)) start = 0
result[addr-start:addr-start+len(data)] = data
return bytes(result) if end is None:
result = bytearray()
else: for addr, data in self.areas.items():
result = bytearray() if addr >= start:
if len(result) < (addr - start):
result[len(result):addr - start] = bytes(
addr - start - len(result))
result[addr - start:addr - start + len(data)] = data
for addr, data in self.areas.items(): return bytes(result)
if addr >= start and addr < end:
data = data[:end-addr]
if len(result) < (addr - start):
result[len(result):addr-start] = bytes(addr-start-len(result))
result[addr-start:addr-start+len(data)] = data
return bytes(result) else:
result = bytearray()
def set_start(self, start=None): for addr, data in self.areas.items():
self.start = start if addr >= start and addr < end:
data = data[:end - addr]
if len(result) < (addr - start):
result[len(result):addr - start] = bytes(
addr - start - len(result))
result[addr - start:addr - start + len(data)] = data
def set_mode(self, mode): return bytes(result)
self.mode = mode
def get_area(self, addr): def set_start(self, start=None):
for start, data in self.areas.items(): self.start = start
end = start + len(data)
if addr >= start and addr <= end:
return start
return None def set_mode(self, mode):
self.mode = mode
def insert_data(self, istart, idata): def get_area(self, addr):
iend = istart + len(idata) for start, data in self.areas.items():
end = start + len(data)
if addr >= start and addr <= end:
return start
area = self.get_area(istart) return None
if area is None:
self.areas[istart] = idata
else: def insert_data(self, istart, idata):
data = self.areas[area] iend = istart + len(idata)
# istart - iend + len(idata) + len(data)
self.areas[area] = data[:istart-area] + idata + data[iend-area:]
def calc_checksum(self, bytes): area = self.get_area(istart)
total = sum(bytes) if area is None:
return (-total) & 0xFF self.areas[istart] = idata
def parse_line(self, rawline): else:
if rawline[0:1] != b":": data = self.areas[area]
raise ValueError("Invalid line start character (%r)" % rawline[0]) # istart - iend + len(idata) + len(data)
self.areas[area] = data[
:istart - area] + idata + data[iend - area:]
try: def calc_checksum(self, data):
#line = rawline[1:].decode("hex") total = sum(data)
line = codecs.decode(rawline[1:], "hex_codec") return (-total) & 0xFF
except:
raise ValueError("Invalid hex data")
length, addr, type = struct.unpack(">BHB", line[:4]) def parse_line(self, rawline):
if rawline[0:1] != b":":
raise ValueError("Invalid line start character (%r)" % rawline[0])
dataend = length + 4 try:
data = line[4:dataend] line = codecs.decode(rawline[1:], "hex_codec")
except:
raise ValueError("Invalid hex data")
#~ print line[dataend:dataend + 2], repr(line) length, addr, line_type = struct.unpack(">BHB", line[:4])
cs1 = line[dataend]
cs2 = self.calc_checksum(line[:dataend])
if cs1 != cs2: dataend = length + 4
raise ValueError("Checksums do not match") data = line[4:dataend]
return (type, addr, data) cs1 = line[dataend]
cs2 = self.calc_checksum(line[:dataend])
def make_line(self, type, addr, data): if cs1 != cs2:
line = struct.pack(">BHB", len(data), addr, type) raise ValueError("Checksums do not match")
line += data
line += chr(self.calc_checksum(line))
#~ return ":" + line.encode("hex")
return ":" + line.encode("hex").upper() + "\r\n"
def write(self): return (line_type, addr, data)
output = ""
for start, data in sorted(self.areas.items()): def make_line(self, line_type, addr, data):
i = 0 line = struct.pack(">BHB", len(data), addr, line_type)
segbase = 0 line += data
line += chr(self.calc_checksum(line))
return ":" + line.encode("hex").upper() + "\r\n"
while i < len(data): def write(self):
chunk = data[i:i + self.row_bytes] """Write Intel HEX data to string"""
output = ""
addr = start for start, data in sorted(self.areas.items()):
newsegbase = segbase i = 0
segbase = 0
if self.mode == 8: while i < len(data):
addr = addr & 0xFFFF chunk = data[i:i + self.row_bytes]
elif self.mode == 16: addr = start
t = addr & 0xFFFF newsegbase = segbase
newsegbase = (addr - t) >> 4
addr = t
if newsegbase != segbase: if self.mode == 8:
output += self.make_line(0x02, 0, struct.pack(">H", newsegbase)) addr = addr & 0xFFFF
segbase = newsegbase
elif self.mode == 32: elif self.mode == 16:
newsegbase = addr >> 16 t = addr & 0xFFFF
addr = addr & 0xFFFF newsegbase = (addr - t) >> 4
addr = t
if newsegbase != segbase: if newsegbase != segbase:
output += self.make_line(0x04, 0, struct.pack(">H", newsegbase)) output += self.make_line(
segbase = newsegbase 0x02, 0, struct.pack(">H", newsegbase))
segbase = newsegbase
output += self.make_line(0x00, addr, chunk) elif self.mode == 32:
newsegbase = addr >> 16
addr = addr & 0xFFFF
i += self.row_bytes if newsegbase != segbase:
start += self.row_bytes output += self.make_line(
0x04, 0, struct.pack(">H", newsegbase))
segbase = newsegbase
if self.start is not None: output += self.make_line(0x00, addr, chunk)
if self.mode == 16:
output += self.make_line(0x03, 0, struct.pack(">2H", self.start[0], self.start[1]))
elif self.mode == 32:
output += self.make_line(0x05, 0, struct.pack(">I", self.start))
output += self.make_line(0x01, 0, "") i += self.row_bytes
return output start += self.row_bytes
def write_file(self, fname): if self.start is not None:
f = open(fname, "w") if self.mode == 16:
f.write(self.write()) output += self.make_line(
f.close() 0x03, 0, struct.pack(">2H", self.start[0], self.start[1]))
elif self.mode == 32:
output += self.make_line(
0x05, 0, struct.pack(">I", self.start))
output += self.make_line(0x01, 0, "")
return output
def write_file(self, fname):
"""Write Intel HEX data to file"""
f = open(fname, "w")
f.write(self.write())
f.close()