comparison python/utils/hexfile.py @ 292:534b94b40aa8

Fixup reorganize
author Windel Bouwman
date Wed, 27 Nov 2013 08:06:42 +0100
parents python/hexfile.py@6ed3d3a82a63
children b145f8e6050b
comparison
equal deleted inserted replaced
290:7b38782ed496 292:534b94b40aa8
1 import os
2 import struct
3 import binascii
4
5 DATA = 0
6 EOF = 1
7 EXTLINADR = 4
8
9 class HexFileException(Exception):
10 pass
11
12
13 def parseHexLine(line):
14 """ Parses a hexfile line into three parts """
15 line = line[1:] # Remove ':'
16 nums = bytes.fromhex(line)
17 bytecount = nums[0]
18 if len(nums) != bytecount + 5:
19 raise HexFileException('byte count field incorrect')
20 crc = sum(nums)
21 if (crc & 0xFF) != 0:
22 raise HexFileException('crc incorrect')
23 address = struct.unpack('>H', nums[1:3])[0]
24 typ = nums[3]
25 data = nums[4:-1]
26 return (address, typ, data)
27
28 def makeHexLine(address, typ, data=bytes()):
29 bytecount = len(data)
30 nums = bytearray()
31 nums.append(bytecount)
32 nums.extend(struct.pack('>H', address))
33 nums.append(typ)
34 nums.extend(data)
35 crc = sum(nums)
36 crc = ((~crc) + 1) & 0xFF
37 nums.append(crc)
38 line = ':' + binascii.hexlify(nums).decode('ascii')
39 return line
40
41 def chunks(data, csize=16):
42 idx = 0
43 while idx < len(data):
44 s = min(len(data) - idx, csize)
45 yield data[idx:idx+s]
46 idx += s
47
48 def hexfields(f):
49 for line in f:
50 line = line.strip() # Strip spaces and newlines
51 if not line:
52 continue # Skip empty lines
53 if line[0] != ':':
54 continue # Skip lines that do not start with a ':'
55 yield parseHexLine(line)
56
57
58 class HexFile:
59 """ Represents an intel hexfile """
60 def __init__(self):
61 self.regions = []
62 self.startAddress = 0
63
64 def load(self, f):
65 endOfFile = False
66 ext = 0
67 for address, typ, data in hexfields(f):
68 if endOfFile:
69 raise HexFileException('hexfile line after end of file record')
70 if typ == 0x0: # Data record
71 self.addRegion(address + ext, data)
72 elif typ == EXTLINADR: # Extended linear address record
73 ext = (struct.unpack('>H', data[0:2])[0]) << 16
74 elif typ == EOF: # End of file record
75 if len(data) != 0:
76 raise HexFileException('end of file not empty')
77 endOfFile = True
78 elif typ == 0x5: # Start address record (where IP goes after loading)
79 self.startAddress = struct.unpack('>I', data[0:4])[0]
80 else:
81 raise HexFileException('record type {0} not implemented'.format(typ))
82
83 def __repr__(self):
84 size = sum(len(r.data) for r in self.regions)
85 return 'Hexfile containing {} bytes'.format(size)
86
87 def dump(self):
88 print(self)
89 for r in self.regions:
90 print(r)
91
92 def __eq__(self, other):
93 regions = self.regions
94 oregions = other.regions
95 if len(regions) != len(oregions):
96 return False
97 return all(rs == ro for rs, ro in zip(regions, oregions))
98
99 def addRegion(self, address, data):
100 r = HexFileRegion(address, data)
101 self.regions.append(r)
102 self.check()
103
104 def check(self):
105 self.regions.sort(key=lambda r: r.address)
106 change = True
107 while change and len(self.regions) > 1:
108 change = False
109 for r1, r2 in zip(self.regions[:-1], self.regions[1:]):
110 if r1.EndAddress == r2.address:
111 r1.addData(r2.data)
112 self.regions.remove(r2)
113 change = True
114 elif r1.EndAddress > r2.address:
115 raise HexFileException('Overlapping regions')
116
117 def merge(self, other):
118 for r in other.regions:
119 self.addRegion(r.address, r.data)
120
121 def save(self, f):
122 def emit(address, typ, data=bytes()):
123 print(makeHexLine(address, typ, data), file=f)
124 for r in self.regions:
125 ext = r.address & 0xFFFF0000
126 emit(0, EXTLINADR, struct.pack('>H', ext >> 16))
127 address = r.address - ext
128 for chunk in chunks(r.data):
129 if address >= 0x10000:
130 ext += 0x10000
131 emit(0, EXTLINADR, struct.pack('>H', ext >> 16))
132 address -= 0x10000
133 emit(address, DATA, chunk)
134 address += len(chunk)
135 emit(0, EOF)
136
137
138 class HexFileRegion:
139 def __init__(self, address, data = bytes()):
140 self.address = address
141 self.data = data
142
143 def __repr__(self):
144 return 'Region at 0x{:08X} of {} bytes'.format(self.address, len(self.data))
145
146 def __eq__(self, other):
147 return (self.address, self.data) == (other.address, other.data)
148
149 def addData(self, d):
150 self.data = self.data + d
151
152 @property
153 def EndAddress(self):
154 return self.address + len(self.data)