comparison python/hexfile.py @ 245:66912720d712

Added grinder
author Windel Bouwman
date Wed, 24 Jul 2013 22:40:29 +0200
parents 58155c7c4a8e
children f254b87258e6
comparison
equal deleted inserted replaced
244:58155c7c4a8e 245:66912720d712
1 import os 1 import os
2 import struct 2 import struct
3 import binascii
4
5 DATA = 0
6 EOF = 1
7 EXTLINADR = 4
3 8
4 class HexFileException(Exception): 9 class HexFileException(Exception):
5 pass 10 pass
6 11
7 def parseHexLine(line): 12 def parseHexLine(line):
27 nums.append(typ) 32 nums.append(typ)
28 nums.extend(data) 33 nums.extend(data)
29 crc = sum(nums) 34 crc = sum(nums)
30 crc = ((~crc) + 1) & 0xFF 35 crc = ((~crc) + 1) & 0xFF
31 nums.append(crc) 36 nums.append(crc)
32 line = ':' + ''.join(['{:02X}'.format(b) for b in nums]) 37 line = ':' + binascii.hexlify(nums).decode('ascii')
33 return line 38 return line
34 39
35 def chunks(data, csize=16): 40 def chunks(data, csize=16):
36 idx = 0 41 idx = 0
37 while idx < len(data): 42 while idx < len(data):
38 s = min(len(data) - idx, csize) 43 s = min(len(data) - idx, csize)
39 yield data[idx:idx+s] 44 yield data[idx:idx+s]
40 idx += s 45 idx += s
41 46
47 def hexfields(f):
48 for line in f:
49 line = line.strip() # Strip spaces and newlines
50 if not line:
51 continue # Skip empty lines
52 if line[0] != ':':
53 continue # Skip lines that do not start with a ':'
54 yield parseHexLine(line)
55
56
42 class HexFile: 57 class HexFile:
43 """ Represents an intel hexfile """ 58 """ Represents an intel hexfile """
44 def __init__(self): 59 def __init__(self):
45 self.regions = [] 60 self.regions = []
46 self.startAddress = 0 61 self.startAddress = 0
47 62
48 def load(self, f): 63 def load(self, f):
49 endOfFile = False 64 endOfFile = False
50 offset = 0 65 ext = 0
51 startAddress = 0 66 for address, typ, data in hexfields(f):
52 curAddress = 0 67 if endOfFile:
53 curData = bytearray() 68 raise HexFileException('hexfile line after end of file record')
54 for line in f:
55 line = line.strip() # Strip spaces and newlines
56 if not line: continue # Skip empty lines
57 if line[0] != ':': continue # Skip lines that do not start with a ':'
58 if endOfFile: raise HexFileException('hexfile line after end of file record')
59 address, typ, data = parseHexLine(line)
60 if typ == 0x0: # Data record 69 if typ == 0x0: # Data record
61 address += offset # Fix address with offset 70 self.addRegion(address + ext, data)
62 # Append data 71 elif typ == EXTLINADR: # Extended linear address record
63 if address == curAddress: 72 ext = (struct.unpack('>H', data[0:2])[0]) << 16
64 curData += data 73 elif typ == EOF: # End of file record
65 curAddress += len(data) 74 if len(data) != 0:
66 else: 75 raise HexFileException('end of file not empty')
67 if curData: 76 endOfFile = True
68 self.regions.append(HexFileRegion(startAddress, bytes(curData)))
69 startAddress = address
70 curAddress = address + len(data)
71 curData = bytearray(data)
72 elif typ == 0x4: # Extended linear address record
73 offset = ((data[0] << 8) + data[1]) << 16
74 elif typ == 0x1: # End of file record
75 if len(data) != 0:
76 raise HexFileException('end of file record must contain no data')
77 endOfFile = True
78 elif typ == 0x5: # Start address record (where IP goes after loading) 77 elif typ == 0x5: # Start address record (where IP goes after loading)
79 self.startAddress = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3] 78 self.startAddress = struct.unpack('>I', data[0:4])[0]
80 else: 79 else:
81 raise HexFileException('record type {0} not implemented'.format(typ)) 80 raise HexFileException('record type {0} not implemented'.format(typ))
82 print(hex(address), typ, data)
83 # After all lines:
84 if curData:
85 self.regions.append(HexFileRegion(startAddress, bytes(curData)))
86 81
87 def __repr__(self): 82 def __repr__(self):
88 return 'Hexfile with {} regions'.format(len(self.regions)) 83 return 'Hexfile with {} regions'.format(len(self.regions))
89 84
90 def dump(self): 85 def dump(self):
99 return False 94 return False
100 return all(rs == ro for rs, ro in zip(regions, oregions)) 95 return all(rs == ro for rs, ro in zip(regions, oregions))
101 96
102 def addRegion(self, address, data): 97 def addRegion(self, address, data):
103 r = HexFileRegion(address, data) 98 r = HexFileRegion(address, data)
104 # TODO: check touches
105 self.regions.append(r) 99 self.regions.append(r)
100 self.check()
101
102 def check(self):
106 self.regions.sort(key=lambda r: r.address) 103 self.regions.sort(key=lambda r: r.address)
104 if len(self.regions) > 1:
105 for r1, r2 in zip(self.regions[:-1], self.regions[1:]):
106 if r1.EndAddress > r2.address:
107 raise HexFileException('Overlapping regions')
108 change = True
109 while change and len(self.regions) > 1:
110 change = False
111 for r1, r2 in zip(self.regions[:-1], self.regions[1:]):
112 if r1.EndAddress == r2.address:
113 r1.addData(r2.data)
114 self.regions.remove(r2)
115 change = True
116
107 117
108 def save(self, f): 118 def save(self, f):
119 def emit(address, typ, data=bytes()):
120 print(makeHexLine(address, typ, data), file=f)
109 for r in self.regions: 121 for r in self.regions:
110 offset = 0 122 ext = r.address & 0xFFFF0000
123 emit(0, EXTLINADR, struct.pack('>H', ext >> 16))
124 address = r.address - ext
111 for chunk in chunks(r.data): 125 for chunk in chunks(r.data):
112 print(makeHexLine(r.address + offset, 0x0, bytes(r.data[offset:offset+16])), file=f) 126 if address >= 0x10000:
113 offset += len(chunk) 127 ext += 0x10000
114 print(makeHexLine(0, 0x1, bytes()), file=f) 128 emit(0, EXTLINADR, struct.pack('>H', ext >> 16))
129 address -= 0x10000
130 emit(address, DATA, chunk)
131 address += len(chunk)
132 emit(0, EOF)
115 133
116 class HexFileRegion: 134 class HexFileRegion:
117 def __init__(self, address, data = bytes()): 135 def __init__(self, address, data = bytes()):
118 self.address = address 136 self.address = address
119 self.data = data 137 self.data = data
120 138
121 def __repr__(self): 139 def __repr__(self):
122 return 'Region at 0x{0:X} of {1} bytes'.format(self.address, len(self.data)) 140 return 'Region at 0x{:08X} of {} bytes'.format(self.address, len(self.data))
123 141
124 def __eq__(self, other): 142 def __eq__(self, other):
125 return (self.address, self.data) == (other.address, other.data) 143 return (self.address, self.data) == (other.address, other.data)
144
145 def addData(self, d):
146 self.data = self.data + d
126 147
127 @property 148 @property
128 def EndAddress(self): 149 def EndAddress(self):
129 return self.address + len(self.data) 150 return self.address + len(self.data)
130 151
131 152
132 if __name__ == '__main__':
133 h = HexFile()
134 print(h)
135 """ Test hexfile implementation with some hexfile """
136 h1 = HexFile()
137 with open('audio.hex', 'r') as f:
138 h1.load(f)
139 print(h1)
140