104
|
1 import os
|
|
2
|
|
3 class HexFileException(Exception):
|
233
|
4 pass
|
104
|
5
|
|
6 def parseHexLine(line):
|
233
|
7 """ Parses a hexfile line into three parts """
|
|
8 line = line[1:] # Remove ':'
|
|
9 nums = bytes.fromhex(line)
|
|
10 bytecount = nums[0]
|
|
11 if len(nums) != bytecount + 5:
|
|
12 raise HexFileException('byte count field incorrect')
|
|
13 crc = sum(nums)
|
|
14 if (crc & 0xFF) != 0:
|
|
15 raise HexFileException('crc incorrect')
|
|
16 address = nums[1] * 256 + nums[2]
|
|
17 typ = nums[3]
|
|
18 data = nums[4:-1]
|
|
19 return (address, typ, data)
|
|
20
|
104
|
21
|
|
22 class HexFile:
|
233
|
23 """ Represents an intel hexfile """
|
|
24 def __init__(self, filename=None):
|
104
|
25 self.regions = []
|
|
26 self.startAddress = 0
|
|
27
|
233
|
28 def load(self, f):
|
104
|
29 endOfFile = False
|
|
30 offset = 0
|
|
31 startAddress = 0
|
|
32 curAddress = 0
|
|
33 curData = bytearray()
|
|
34 for line in f:
|
|
35 line = line.strip() # Strip spaces and newlines
|
|
36 if not line: continue # Skip empty lines
|
|
37 if line[0] != ':': continue # Skip lines that do not start with a ':'
|
|
38 if endOfFile: raise HexFileException('hexfile line after end of file record')
|
|
39 address, typ, data = parseHexLine(line)
|
|
40 if typ == 0x0: # Data record
|
|
41 address += offset # Fix address with offset
|
|
42 # Append data
|
|
43 if address == curAddress:
|
|
44 curData += data
|
|
45 curAddress += len(data)
|
|
46 else:
|
|
47 if curData:
|
|
48 self.regions.append(HexFileRegion(startAddress, bytes(curData)))
|
|
49 startAddress = address
|
|
50 curAddress = address + len(data)
|
|
51 curData = bytearray(data)
|
|
52 elif typ == 0x4: # Extended linear address record
|
|
53 offset = ((data[0] << 8) + data[1]) << 16
|
|
54 elif typ == 0x1: # End of file record
|
|
55 if len(data) != 0:
|
|
56 raise HexFileException('end of file record must contain no data')
|
|
57 endOfFile = True
|
|
58 elif typ == 0x5: # Start address record (where IP goes after loading)
|
|
59 self.startAddress = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
|
|
60 else:
|
|
61 raise HexFileException('record type {0} not implemented'.format(typ))
|
|
62 print(hex(address), typ, data)
|
|
63 # After all lines:
|
|
64 if curData:
|
|
65 self.regions.append(HexFileRegion(startAddress, bytes(curData)))
|
233
|
66
|
|
67 def __repr__(self):
|
|
68 i = []
|
|
69 i.append(super().__repr__())
|
|
70 i.append('Start address {0}'.format(hex(self.startAddress)))
|
|
71 for r in self.regions:
|
|
72 i.append(str(r))
|
|
73 return os.linesep.join(i)
|
|
74
|
|
75 def save(self, f):
|
|
76 for r in self.regions:
|
|
77 offset = 0
|
|
78 while offset < len(r.data):
|
|
79 f.write('a')
|
|
80 offset += 16
|
|
81
|
|
82
|
104
|
83 class HexFileRegion:
|
|
84 def __init__(self, address, data = bytes()):
|
|
85 self.address = address
|
|
86 self.data = data
|
|
87 def __repr__(self):
|
|
88 return 'Region at 0x{0:X} of {1} bytes'.format(self.address, len(self.data))
|
|
89
|
233
|
90
|
104
|
91 if __name__ == '__main__':
|
|
92 h = HexFile()
|
|
93 print(h)
|
|
94 """ Test hexfile implementation with some hexfile """
|
233
|
95 h1 = HexFile()
|
|
96 with open('audio.hex', 'r') as f:
|
|
97 h1.load(f)
|
104
|
98 print(h1)
|
|
99
|