annotate python/hexfile.py @ 244:58155c7c4a8e

Add hexutil
author Windel Bouwman
date Wed, 24 Jul 2013 19:47:13 +0200
parents 6259856841a0
children 66912720d712
rev   line source
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
1 import os
244
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
2 import struct
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
3
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
4 class HexFileException(Exception):
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
5 pass
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
6
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
7 def parseHexLine(line):
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
8 """ Parses a hexfile line into three parts """
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
9 line = line[1:] # Remove ':'
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
10 nums = bytes.fromhex(line)
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
11 bytecount = nums[0]
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
12 if len(nums) != bytecount + 5:
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
13 raise HexFileException('byte count field incorrect')
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
14 crc = sum(nums)
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
15 if (crc & 0xFF) != 0:
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
16 raise HexFileException('crc incorrect')
244
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
17 address = struct.unpack('>H', nums[1:3])[0]
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
18 typ = nums[3]
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
19 data = nums[4:-1]
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
20 return (address, typ, data)
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
21
244
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
22 def makeHexLine(address, typ, data=bytes()):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
23 bytecount = len(data)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
24 nums = bytearray()
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
25 nums.append(bytecount)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
26 nums.extend(struct.pack('>H', address))
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
27 nums.append(typ)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
28 nums.extend(data)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
29 crc = sum(nums)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
30 crc = ((~crc) + 1) & 0xFF
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
31 nums.append(crc)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
32 line = ':' + ''.join(['{:02X}'.format(b) for b in nums])
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
33 return line
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
34
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
35 def chunks(data, csize=16):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
36 idx = 0
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
37 while idx < len(data):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
38 s = min(len(data) - idx, csize)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
39 yield data[idx:idx+s]
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
40 idx += s
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
41
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
42 class HexFile:
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
43 """ Represents an intel hexfile """
240
6259856841a0 Remove project
Windel Bouwman
parents: 233
diff changeset
44 def __init__(self):
6259856841a0 Remove project
Windel Bouwman
parents: 233
diff changeset
45 self.regions = []
6259856841a0 Remove project
Windel Bouwman
parents: 233
diff changeset
46 self.startAddress = 0
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
47
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
48 def load(self, f):
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
49 endOfFile = False
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
50 offset = 0
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
51 startAddress = 0
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
52 curAddress = 0
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
53 curData = bytearray()
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
54 for line in f:
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
55 line = line.strip() # Strip spaces and newlines
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
56 if not line: continue # Skip empty lines
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
57 if line[0] != ':': continue # Skip lines that do not start with a ':'
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
58 if endOfFile: raise HexFileException('hexfile line after end of file record')
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
59 address, typ, data = parseHexLine(line)
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
60 if typ == 0x0: # Data record
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
61 address += offset # Fix address with offset
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
62 # Append data
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
63 if address == curAddress:
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
64 curData += data
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
65 curAddress += len(data)
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
66 else:
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
67 if curData:
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
68 self.regions.append(HexFileRegion(startAddress, bytes(curData)))
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
69 startAddress = address
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
70 curAddress = address + len(data)
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
71 curData = bytearray(data)
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
72 elif typ == 0x4: # Extended linear address record
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
73 offset = ((data[0] << 8) + data[1]) << 16
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
74 elif typ == 0x1: # End of file record
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
75 if len(data) != 0:
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
76 raise HexFileException('end of file record must contain no data')
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
77 endOfFile = True
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
78 elif typ == 0x5: # Start address record (where IP goes after loading)
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
79 self.startAddress = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
80 else:
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
81 raise HexFileException('record type {0} not implemented'.format(typ))
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
82 print(hex(address), typ, data)
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
83 # After all lines:
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
84 if curData:
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
85 self.regions.append(HexFileRegion(startAddress, bytes(curData)))
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
86
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
87 def __repr__(self):
244
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
88 return 'Hexfile with {} regions'.format(len(self.regions))
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
89
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
90 def dump(self):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
91 print(self)
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
92 for r in self.regions:
244
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
93 print(r)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
94
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
95 def __eq__(self, other):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
96 regions = self.regions
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
97 oregions = other.regions
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
98 if len(regions) != len(oregions):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
99 return False
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
100 return all(rs == ro for rs, ro in zip(regions, oregions))
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
101
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
102 def addRegion(self, address, data):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
103 r = HexFileRegion(address, data)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
104 # TODO: check touches
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
105 self.regions.append(r)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
106 self.regions.sort(key=lambda r: r.address)
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
107
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
108 def save(self, f):
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
109 for r in self.regions:
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
110 offset = 0
244
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
111 for chunk in chunks(r.data):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
112 print(makeHexLine(r.address + offset, 0x0, bytes(r.data[offset:offset+16])), file=f)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
113 offset += len(chunk)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
114 print(makeHexLine(0, 0x1, bytes()), file=f)
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
115
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
116 class HexFileRegion:
244
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
117 def __init__(self, address, data = bytes()):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
118 self.address = address
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
119 self.data = data
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
120
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
121 def __repr__(self):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
122 return 'Region at 0x{0:X} of {1} bytes'.format(self.address, len(self.data))
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
123
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
124 def __eq__(self, other):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
125 return (self.address, self.data) == (other.address, other.data)
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
126
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
127 @property
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
128 def EndAddress(self):
58155c7c4a8e Add hexutil
Windel Bouwman
parents: 240
diff changeset
129 return self.address + len(self.data)
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
130
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
131
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
132 if __name__ == '__main__':
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
133 h = HexFile()
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
134 print(h)
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
135 """ Test hexfile implementation with some hexfile """
233
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
136 h1 = HexFile()
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
137 with open('audio.hex', 'r') as f:
d3dccf12ca88 Added hexfile tests
Windel Bouwman
parents: 104
diff changeset
138 h1.load(f)
104
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
139 print(h1)
ed230e947dc6 Added hexviewer
windel
parents:
diff changeset
140