1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 '''Intel HEX file format reader and converter.
35
36 @author Alexander Belchenko (bialix AT ukr net)
37 @version 1.2
38 '''
39
40
41 __docformat__ = "javadoc"
42
43
44 from array import array
45 from binascii import hexlify, unhexlify
46 from bisect import bisect_right
47 import os
48
49
51 ''' Intel HEX file reader. '''
52
54 ''' Constructor. If source specified, object will be initialized
55 with the contents of source. Otherwise the object will be empty.
56
57 @param source source for initialization
58 (file name of HEX file, file object, addr dict or
59 other IntelHex object)
60 '''
61
62 self.padding = 0x0FF
63
64 self.start_addr = None
65
66
67 self._buf = {}
68 self._offset = 0
69
70 if source is not None:
71 if isinstance(source, basestring) or getattr(source, "read", None):
72
73 self.loadhex(source)
74 elif isinstance(source, dict):
75 self.fromdict(source)
76 elif isinstance(source, IntelHex):
77 self.padding = source.padding
78 if source.start_addr:
79 self.start_addr = source.start_addr.copy()
80 self._buf = source._buf.copy()
81 else:
82 raise ValueError("source: bad initializer type")
83
85 '''Decode one record of HEX file.
86
87 @param s line with HEX record.
88 @param line line number (for error messages).
89
90 @raise EndOfFile if EOF record encountered.
91 '''
92 s = s.rstrip('\r\n')
93 if not s:
94 return
95
96 if s[0] == ':':
97 try:
98 bin = array('B', unhexlify(s[1:]))
99 except TypeError:
100
101 raise HexRecordError(line=line)
102 length = len(bin)
103 if length < 5:
104 raise HexRecordError(line=line)
105 else:
106 raise HexRecordError(line=line)
107
108 record_length = bin[0]
109 if length != (5 + record_length):
110 raise RecordLengthError(line=line)
111
112 addr = bin[1]*256 + bin[2]
113
114 record_type = bin[3]
115 if not (0 <= record_type <= 5):
116 raise RecordTypeError(line=line)
117
118 crc = sum(bin)
119 crc &= 0x0FF
120 if crc != 0:
121 raise RecordChecksumError(line=line)
122
123 if record_type == 0:
124
125 addr += self._offset
126 for i in xrange(4, 4+record_length):
127 if not self._buf.get(addr, None) is None:
128 raise AddressOverlapError(address=addr, line=line)
129 self._buf[addr] = bin[i]
130 addr += 1
131
132
133
134 elif record_type == 1:
135
136 if record_length != 0:
137 raise EOFRecordError(line=line)
138 raise _EndOfFile
139
140 elif record_type == 2:
141
142 if record_length != 2 or addr != 0:
143 raise ExtendedSegmentAddressRecordError(line=line)
144 self._offset = (bin[4]*256 + bin[5]) * 16
145
146 elif record_type == 4:
147
148 if record_length != 2 or addr != 0:
149 raise ExtendedLinearAddressRecordError(line=line)
150 self._offset = (bin[4]*256 + bin[5]) * 65536
151
152 elif record_type == 3:
153
154 if record_length != 4 or addr != 0:
155 raise StartSegmentAddressRecordError(line=line)
156 if self.start_addr:
157 raise DuplicateStartAddressRecordError(line=line)
158 self.start_addr = {'CS': bin[4]*256 + bin[5],
159 'IP': bin[6]*256 + bin[7],
160 }
161
162 elif record_type == 5:
163
164 if record_length != 4 or addr != 0:
165 raise StartLinearAddressRecordError(line=line)
166 if self.start_addr:
167 raise DuplicateStartAddressRecordError(line=line)
168 self.start_addr = {'EIP': (bin[4]*16777216 +
169 bin[5]*65536 +
170 bin[6]*256 +
171 bin[7]),
172 }
173
175 """Load hex file into internal buffer. This is not necessary
176 if object was initialized with source set. This will overwrite
177 addresses if object was already initialized.
178
179 @param fobj file name or file-like object
180 """
181 if getattr(fobj, "read", None) is None:
182 fobj = file(fobj, "r")
183 fclose = fobj.close
184 else:
185 fclose = None
186
187 self._offset = 0
188 line = 0
189
190 try:
191 decode = self._decode_record
192 try:
193 for s in fobj:
194 line += 1
195 decode(s, line)
196 except _EndOfFile:
197 pass
198 finally:
199 if fclose:
200 fclose()
201
202 - def loadbin(self, fobj, offset=0):
203 """Load bin file into internal buffer. Not needed if source set in
204 constructor. This will overwrite addresses without warning
205 if object was already initialized.
206
207 @param fobj file name or file-like object
208 @param offset starting address offset
209 """
210 fread = getattr(fobj, "read", None)
211 if fread is None:
212 f = file(fobj, "rb")
213 fread = f.read
214 fclose = f.close
215 else:
216 fclose = None
217
218 try:
219 for b in array('B', fread()):
220 self._buf[offset] = b
221 offset += 1
222 finally:
223 if fclose:
224 fclose()
225
227 """Load data file into internal buffer. Preferred wrapper over
228 loadbin or loadhex.
229
230 @param fobj file name or file-like object
231 @param format file format ("hex" or "bin")
232 """
233 if format == "hex":
234 self.loadhex(fobj)
235 elif format == "bin":
236 self.loadbin(fobj)
237 else:
238 raise ValueError('format should be either "hex" or "bin";'
239 ' got %r instead' % format)
240
241
242 fromfile = loadfile
243
245 """Load data from dictionary. Dictionary should contain int keys
246 representing addresses. Values should be the data to be stored in
247 those addresses in unsigned char form (i.e. not strings).
248 The dictionary may contain the key, ``start_addr``
249 to indicate the starting address of the data as described in README.
250
251 The contents of the dict will be merged with this object and will
252 overwrite any conflicts. This function is not necessary if the
253 object was initialized with source specified.
254 """
255 s = dikt.copy()
256 start_addr = s.get('start_addr')
257 if s.has_key('start_addr'):
258 del s['start_addr']
259 for k in s.keys():
260 if type(k) not in (int, long) or k < 0:
261 raise ValueError('Source dictionary should have only int keys')
262 self._buf.update(s)
263 if start_addr is not None:
264 self.start_addr = start_addr
265
267 """Return default values for start and end if they are None
268 """
269 if start is None:
270 start = min(self._buf.keys())
271 if end is None:
272 end = max(self._buf.keys())
273 if start > end:
274 start, end = end, start
275 return start, end
276
277 - def tobinarray(self, start=None, end=None, pad=None):
278 ''' Convert this object to binary form as array. If start and end
279 unspecified, they will be inferred from the data.
280 @param start start address of output bytes.
281 @param end end address of output bytes (inclusive).
282 @param pad fill empty spaces with this value
283 (if None used self.padding).
284 @return array of unsigned char data.
285 '''
286 if pad is None:
287 pad = self.padding
288
289 bin = array('B')
290
291 if self._buf == {} and None in (start, end):
292 return bin
293
294 start, end = self._get_start_end(start, end)
295
296 for i in xrange(start, end+1):
297 bin.append(self._buf.get(i, pad))
298
299 return bin
300
301 - def tobinstr(self, start=None, end=None, pad=0xFF):
302 ''' Convert to binary form and return as a string.
303 @param start start address of output bytes.
304 @param end end address of output bytes (inclusive).
305 @param pad fill empty spaces with this value
306 (if None used self.padding).
307 @return string of binary data.
308 '''
309 return self.tobinarray(start, end, pad).tostring()
310
311 - def tobinfile(self, fobj, start=None, end=None, pad=0xFF):
312 '''Convert to binary and write to file.
313
314 @param fobj file name or file object for writing output bytes.
315 @param start start address of output bytes.
316 @param end end address of output bytes (inclusive).
317 @param pad fill empty spaces with this value
318 (if None used self.padding).
319 '''
320 if getattr(fobj, "write", None) is None:
321 fobj = file(fobj, "wb")
322 close_fd = True
323 else:
324 close_fd = False
325
326 fobj.write(self.tobinstr(start, end, pad))
327
328 if close_fd:
329 fobj.close()
330
332 '''Convert to python dictionary.
333
334 @return dict suitable for initializing another IntelHex object.
335 '''
336 r = {}
337 r.update(self._buf)
338 if self.start_addr:
339 r['start_addr'] = self.start_addr
340 return r
341
343 '''Returns all used addresses in sorted order.
344 @return list of occupied data addresses in sorted order.
345 '''
346 aa = self._buf.keys()
347 aa.sort()
348 return aa
349
351 '''Get minimal address of HEX content.
352 @return minimal address or None if no data
353 '''
354 aa = self._buf.keys()
355 if aa == []:
356 return None
357 else:
358 return min(aa)
359
361 '''Get maximal address of HEX content.
362 @return maximal address or None if no data
363 '''
364 aa = self._buf.keys()
365 if aa == []:
366 return None
367 else:
368 return max(aa)
369
371 ''' Get requested byte from address.
372 @param addr address of byte.
373 @return byte if address exists in HEX file, or self.padding
374 if no data found.
375 '''
376 t = type(addr)
377 if t in (int, long):
378 if addr < 0:
379 raise TypeError('Address should be >= 0.')
380 return self._buf.get(addr, self.padding)
381 elif t == slice:
382 addresses = self._buf.keys()
383 ih = IntelHex()
384 if addresses:
385 addresses.sort()
386 start = addr.start or addresses[0]
387 stop = addr.stop or (addresses[-1]+1)
388 step = addr.step or 1
389 for i in xrange(start, stop, step):
390 x = self._buf.get(i)
391 if x is not None:
392 ih[i] = x
393 return ih
394 else:
395 raise TypeError('Address has unsupported type: %s' % t)
396
398 """Set byte at address."""
399 t = type(addr)
400 if t in (int, long):
401 if addr < 0:
402 raise TypeError('Address should be >= 0.')
403 self._buf[addr] = byte
404 elif t == slice:
405 addresses = self._buf.keys()
406 if not isinstance(byte, (list, tuple)):
407 raise ValueError('Slice operation expects sequence of bytes')
408 start = addr.start
409 stop = addr.stop
410 step = addr.step or 1
411 if None not in (start, stop):
412 ra = range(start, stop, step)
413 if len(ra) != len(byte):
414 raise ValueError('Length of bytes sequence does not match '
415 'address range')
416 elif (start, stop) == (None, None):
417 raise TypeError('Unsupported address range')
418 elif start is None:
419 start = stop - len(byte)
420 elif stop is None:
421 stop = start + len(byte)
422 if start < 0:
423 raise TypeError('start address cannot be negative')
424 if stop < 0:
425 raise TypeError('stop address cannot be negative')
426 j = 0
427 for i in xrange(start, stop, step):
428 self._buf[i] = byte[j]
429 j += 1
430 else:
431 raise TypeError('Address has unsupported type: %s' % t)
432
434 """Delete byte at address."""
435 t = type(addr)
436 if t in (int, long):
437 if addr < 0:
438 raise TypeError('Address should be >= 0.')
439 del self._buf[addr]
440 elif t == slice:
441 addresses = self._buf.keys()
442 if addresses:
443 addresses.sort()
444 start = addr.start or addresses[0]
445 stop = addr.stop or (addresses[-1]+1)
446 step = addr.step or 1
447 for i in xrange(start, stop, step):
448 x = self._buf.get(i)
449 if x is not None:
450 del self._buf[i]
451 else:
452 raise TypeError('Address has unsupported type: %s' % t)
453
455 """Return count of bytes with real values."""
456 return len(self._buf.keys())
457
459 """Write data to file f in HEX format.
460
461 @param f filename or file-like object for writing
462 @param write_start_addr enable or disable writing start address
463 record to file (enabled by default).
464 If there is no start address in obj, nothing
465 will be written regardless of this setting.
466 """
467 fwrite = getattr(f, "write", None)
468 if fwrite:
469 fobj = f
470 fclose = None
471 else:
472 fobj = file(f, 'w')
473 fwrite = fobj.write
474 fclose = fobj.close
475
476
477
478
479
480 table = ''.join(chr(i).upper() for i in range(256))
481
482
483 if self.start_addr and write_start_addr:
484 keys = self.start_addr.keys()
485 keys.sort()
486 bin = array('B', '\0'*9)
487 if keys == ['CS','IP']:
488
489 bin[0] = 4
490 bin[1] = 0
491 bin[2] = 0
492 bin[3] = 3
493 cs = self.start_addr['CS']
494 bin[4] = (cs >> 8) & 0x0FF
495 bin[5] = cs & 0x0FF
496 ip = self.start_addr['IP']
497 bin[6] = (ip >> 8) & 0x0FF
498 bin[7] = ip & 0x0FF
499 bin[8] = (-sum(bin)) & 0x0FF
500 fwrite(':' + hexlify(bin.tostring()).translate(table) + '\n')
501 elif keys == ['EIP']:
502
503 bin[0] = 4
504 bin[1] = 0
505 bin[2] = 0
506 bin[3] = 5
507 eip = self.start_addr['EIP']
508 bin[4] = (eip >> 24) & 0x0FF
509 bin[5] = (eip >> 16) & 0x0FF
510 bin[6] = (eip >> 8) & 0x0FF
511 bin[7] = eip & 0x0FF
512 bin[8] = (-sum(bin)) & 0x0FF
513 fwrite(':' + hexlify(bin.tostring()).translate(table) + '\n')
514 else:
515 if fclose:
516 fclose()
517 raise InvalidStartAddressValueError(start_addr=self.start_addr)
518
519
520 addresses = self._buf.keys()
521 addresses.sort()
522 addr_len = len(addresses)
523 if addr_len:
524 minaddr = addresses[0]
525 maxaddr = addresses[-1]
526
527 if maxaddr > 65535:
528 need_offset_record = True
529 else:
530 need_offset_record = False
531 high_ofs = 0
532
533 cur_addr = minaddr
534 cur_ix = 0
535
536 while cur_addr <= maxaddr:
537 if need_offset_record:
538 bin = array('B', '\0'*7)
539 bin[0] = 2
540 bin[1] = 0
541 bin[2] = 0
542 bin[3] = 4
543 high_ofs = int(cur_addr/65536)
544 bytes = divmod(high_ofs, 256)
545 bin[4] = bytes[0]
546 bin[5] = bytes[1]
547 bin[6] = (-sum(bin)) & 0x0FF
548 fwrite(':' + hexlify(bin.tostring()).translate(table) + '\n')
549
550 while True:
551
552 low_addr = cur_addr & 0x0FFFF
553
554 chain_len = min(15, 65535-low_addr, maxaddr-cur_addr)
555
556
557 stop_addr = cur_addr + chain_len
558 if chain_len:
559 ix = bisect_right(addresses, stop_addr,
560 cur_ix,
561 min(cur_ix+chain_len+1, addr_len))
562 chain_len = ix - cur_ix
563
564
565
566
567 else:
568 chain_len = 1
569
570 bin = array('B', '\0'*(5+chain_len))
571 bytes = divmod(low_addr, 256)
572 bin[1] = bytes[0]
573 bin[2] = bytes[1]
574 bin[3] = 0
575 try:
576 for i in range(chain_len):
577 bin[4+i] = self._buf[cur_addr+i]
578 except KeyError:
579
580 chain_len = i
581 bin = bin[:5+i]
582 bin[0] = chain_len
583 bin[4+chain_len] = (-sum(bin)) & 0x0FF
584 fwrite(':' + hexlify(bin.tostring()).translate(table) + '\n')
585
586
587 cur_ix += chain_len
588 if cur_ix < addr_len:
589 cur_addr = addresses[cur_ix]
590 else:
591 cur_addr = maxaddr + 1
592 break
593 high_addr = int(cur_addr/65536)
594 if high_addr > high_ofs:
595 break
596
597
598 fwrite(":00000001FF\n")
599 if fclose:
600 fclose()
601
602 - def tofile(self, fobj, format):
603 """Write data to hex or bin file. Preferred method over tobin or tohex.
604
605 @param fobj file name or file-like object
606 @param format file format ("hex" or "bin")
607 """
608 if format == 'hex':
609 self.write_hex_file(fobj)
610 elif format == 'bin':
611 self.tobinfile(fobj)
612 else:
613 raise ValueError('format should be either "hex" or "bin";'
614 ' got %r instead' % format)
615
616 - def gets(self, addr, length):
617 """Get string of bytes from given address. If any entries are blank
618 from addr through addr+length, a NotEnoughDataError exception will
619 be raised. Padding is not used."""
620 a = array('B', '\0'*length)
621 try:
622 for i in xrange(length):
623 a[i] = self._buf[addr+i]
624 except KeyError:
625 raise NotEnoughDataError(address=addr, length=length)
626 return a.tostring()
627
628 - def puts(self, addr, s):
629 """Put string of bytes at given address. Will overwrite any previous
630 entries.
631 """
632 a = array('B', s)
633 for i in xrange(len(s)):
634 self._buf[addr+i] = a[i]
635
637 """Get zero-terminated string from given address. Will raise
638 NotEnoughDataError exception if a hole is encountered before a 0.
639 """
640 i = 0
641 try:
642 while True:
643 if self._buf[addr+i] == 0:
644 break
645 i += 1
646 except KeyError:
647 raise NotEnoughDataError(msg=('Bad access at 0x%X: '
648 'not enough data to read zero-terminated string') % addr)
649 return self.gets(addr, i)
650
651 - def putsz(self, addr, s):
652 """Put string in object at addr and append terminating zero at end."""
653 self.puts(addr, s)
654 self._buf[addr+len(s)] = 0
655
656 - def dump(self, tofile=None):
657 """Dump object content to specified file object or to stdout if None.
658 Format is a hexdump with some header information at the beginning,
659 addresses on the left, and data on right.
660
661 @param tofile file-like object to dump to
662 """
663
664 if tofile is None:
665 import sys
666 tofile = sys.stdout
667
668 if self.start_addr is not None:
669 cs = self.start_addr.get('CS')
670 ip = self.start_addr.get('IP')
671 eip = self.start_addr.get('EIP')
672 if eip is not None and cs is None and ip is None:
673 tofile.write('EIP = 0x%08X\n' % eip)
674 elif eip is None and cs is not None and ip is not None:
675 tofile.write('CS = 0x%04X, IP = 0x%04X\n' % (cs, ip))
676 else:
677 tofile.write('start_addr = %r\n' % start_addr)
678
679 addresses = self._buf.keys()
680 if addresses:
681 addresses.sort()
682 minaddr = addresses[0]
683 maxaddr = addresses[-1]
684 startaddr = int(minaddr/16)*16
685 endaddr = int(maxaddr/16+1)*16
686 maxdigits = max(len(str(endaddr)), 4)
687 templa = '%%0%dX' % maxdigits
688 range16 = range(16)
689 for i in xrange(startaddr, endaddr, 16):
690 tofile.write(templa % i)
691 tofile.write(' ')
692 s = []
693 for j in range16:
694 x = self._buf.get(i+j)
695 if x is not None:
696 tofile.write(' %02X' % x)
697 if 32 <= x < 128:
698 s.append(chr(x))
699 else:
700 s.append('.')
701 else:
702 tofile.write(' --')
703 s.append(' ')
704 tofile.write(' |' + ''.join(s) + '|\n')
705
706 - def merge(this, other, overlap='error'):
707 """Merge content of other IntelHex object to this object.
708 @param other other IntelHex object.
709 @param overlap action on overlap of data or starting addr:
710 - error: raising OverlapError;
711 - ignore: ignore other data and keep this data
712 in overlapping region;
713 - replace: replace this data with other data
714 in overlapping region.
715
716 @raise TypeError if other is not instance of IntelHex
717 @raise ValueError if other is the same object as this
718 @raise ValueError if overlap argument has incorrect value
719 @raise AddressOverlapError on overlapped data
720 """
721
722 if not isinstance(other, IntelHex):
723 raise TypeError('other should be IntelHex object')
724 if other is this:
725 raise ValueError("Can't merge itself")
726 if overlap not in ('error', 'ignore', 'replace'):
727 raise ValueError("overlap argument should be either "
728 "'error', 'ignore' or 'replace'")
729
730 this_buf = this._buf
731 other_buf = other._buf
732 for i in other_buf:
733 if i in this_buf:
734 if overlap == 'error':
735 raise AddressOverlapError(
736 'Data overlapped at address 0x%X' % i)
737 elif overlap == 'ignore':
738 continue
739 this_buf[i] = other_buf[i]
740
741 if this.start_addr != other.start_addr:
742 if this.start_addr is None:
743 this.start_addr = other.start_addr
744 elif other.start_addr is None:
745 pass
746 else:
747 if overlap == 'error':
748 raise AddressOverlapError(
749 'Starting addresses are different')
750 elif overlap == 'replace':
751 this.start_addr = other.start_addr
752
753
754
756 """Access to data as 16-bit words."""
757
759 """Construct class from HEX file
760 or from instance of ordinary IntelHex class. If IntelHex object
761 is passed as source, the original IntelHex object should not be used
762 again because this class will alter it. This class leaves padding
763 alone unless it was precisely 0xFF. In that instance it is sign
764 extended to 0xFFFF.
765
766 @param source file name of HEX file or file object
767 or instance of ordinary IntelHex class.
768 Will also accept dictionary from todict method.
769 """
770 if isinstance(source, IntelHex):
771
772 self.padding = source.padding
773
774 self._buf = source._buf
775 self._offset = source._offset
776 else:
777 IntelHex.__init__(self, source)
778
779 if self.padding == 0x0FF:
780 self.padding = 0x0FFFF
781
783 """Get 16-bit word from address.
784 Raise error if only one byte from the pair is set.
785 We assume a Little Endian interpretation of the hex file.
786
787 @param addr16 address of word (addr8 = 2 * addr16).
788 @return word if bytes exists in HEX file, or self.padding
789 if no data found.
790 """
791 addr1 = addr16 * 2
792 addr2 = addr1 + 1
793 byte1 = self._buf.get(addr1, None)
794 byte2 = self._buf.get(addr2, None)
795
796 if byte1 != None and byte2 != None:
797 return byte1 | (byte2 << 8)
798
799 if byte1 == None and byte2 == None:
800 return self.padding
801
802 raise BadAccess16bit(address=addr16)
803
805 """Sets the address at addr16 to word assuming Little Endian mode.
806 """
807 addr_byte = addr16 * 2
808 bytes = divmod(word, 256)
809 self._buf[addr_byte] = bytes[1]
810 self._buf[addr_byte+1] = bytes[0]
811
813 '''Get minimal address of HEX content in 16-bit mode.
814
815 @return minimal address used in this object
816 '''
817 aa = self._buf.keys()
818 if aa == []:
819 return 0
820 else:
821 return min(aa)/2
822
824 '''Get maximal address of HEX content in 16-bit mode.
825
826 @return maximal address used in this object
827 '''
828 aa = self._buf.keys()
829 if aa == []:
830 return 0
831 else:
832 return max(aa)/2
833
834
835
836
837 -def hex2bin(fin, fout, start=None, end=None, size=None, pad=0xFF):
838 """Hex-to-Bin convertor engine.
839 @return 0 if all OK
840
841 @param fin input hex file (filename or file-like object)
842 @param fout output bin file (filename or file-like object)
843 @param start start of address range (optional)
844 @param end end of address range (inclusive; optional)
845 @param size size of resulting file (in bytes) (optional)
846 @param pad padding byte (optional)
847 """
848 try:
849 h = IntelHex(fin)
850 except HexReaderError, e:
851 print "ERROR: bad HEX file: %s" % str(e)
852 return 1
853
854
855 if size != None and size != 0:
856 if end == None:
857 if start == None:
858 start = h.minaddr()
859 end = start + size - 1
860 else:
861 if (end+1) >= size:
862 start = end + 1 - size
863 else:
864 start = 0
865
866 try:
867 h.tobinfile(fout, start, end, pad)
868 except IOError, e:
869 print "ERROR: Could not write to file: %s: %s" % (fout, str(e))
870 return 1
871
872 return 0
873
874
875
877 """Simple bin-to-hex convertor.
878 @return 0 if all OK
879
880 @param fin input bin file (filename or file-like object)
881 @param fout output hex file (filename or file-like object)
882 @param offset starting address offset for loading bin
883 """
884 h = IntelHex()
885 try:
886 h.loadbin(fin, offset)
887 except IOError, e:
888 print 'ERROR: unable to load bin file:', str(e)
889 return 1
890
891 try:
892 h.tofile(fout, format='hex')
893 except IOError, e:
894 print "ERROR: Could not write to file: %s: %s" % (fout, str(e))
895 return 1
896
897 return 0
898
899
900
902 """Helper methods to build valid ihex records."""
903
905 """Takes a list of bytes, computes the checksum, and outputs the entire
906 record as a string. bytes should be the hex record without the colon
907 or final checksum.
908
909 @param bytes list of byte values so far to pack into record.
910 @return String representation of one HEX record
911 """
912 assert len(bytes) >= 4
913
914 s = (-sum(bytes)) & 0x0FF
915 bin = array('B', bytes + [s])
916 return ':' + hexlify(bin.tostring()).upper()
917 _from_bytes = staticmethod(_from_bytes)
918
919 - def data(offset, bytes):
920 """Return Data record. This constructs the full record, including
921 the length information, the record type (0x00), the
922 checksum, and the offset.
923
924 @param offset load offset of first byte.
925 @param bytes list of byte values to pack into record.
926
927 @return String representation of one HEX record
928 """
929 assert 0 <= offset < 65536
930 assert 0 < len(bytes) < 256
931 b = [len(bytes), (offset>>8)&0x0FF, offset&0x0FF, 0x00] + bytes
932 return Record._from_bytes(b)
933 data = staticmethod(data)
934
936 """Return End of File record as a string.
937 @return String representation of Intel Hex EOF record
938 """
939 return ':00000001FF'
940 eof = staticmethod(eof)
941
943 """Return Extended Segment Address Record.
944 @param usba Upper Segment Base Address.
945
946 @return String representation of Intel Hex USBA record.
947 """
948 b = [2, 0, 0, 0x02, (usba>>8)&0x0FF, usba&0x0FF]
949 return Record._from_bytes(b)
950 extended_segment_address = staticmethod(extended_segment_address)
951
953 """Return Start Segment Address Record.
954 @param cs 16-bit value for CS register.
955 @param ip 16-bit value for IP register.
956
957 @return String representation of Intel Hex SSA record.
958 """
959 b = [4, 0, 0, 0x03, (cs>>8)&0x0FF, cs&0x0FF,
960 (ip>>8)&0x0FF, ip&0x0FF]
961 return Record._from_bytes(b)
962 start_segment_address = staticmethod(start_segment_address)
963
965 """Return Extended Linear Address Record.
966 @param ulba Upper Linear Base Address.
967
968 @return String representation of Intel Hex ELA record.
969 """
970 b = [2, 0, 0, 0x04, (ulba>>8)&0x0FF, ulba&0x0FF]
971 return Record._from_bytes(b)
972 extended_linear_address = staticmethod(extended_linear_address)
973
975 """Return Start Linear Address Record.
976 @param eip 32-bit linear address for the EIP register.
977
978 @return String representation of Intel Hex SLA record.
979 """
980 b = [4, 0, 0, 0x05, (eip>>24)&0x0FF, (eip>>16)&0x0FF,
981 (eip>>8)&0x0FF, eip&0x0FF]
982 return Record._from_bytes(b)
983 start_linear_address = staticmethod(start_linear_address)
984
985
987 """Special error class to use with _get_file_and_addr_range."""
988 pass
989
991 """Special method for hexmerge.py script to split file notation
992 into 3 parts: (filename, start, end)
993
994 @raise _BadFileNotation when string cannot be safely split.
995 """
996 if _support_drive_letter is None:
997 _support_drive_letter = (os.name == 'nt')
998 drive = ''
999 if _support_drive_letter:
1000 if s[1:2] == ':' and s[0].upper() in ''.join([chr(i) for i in range(ord('A'), ord('Z')+1)]):
1001 drive = s[:2]
1002 s = s[2:]
1003 parts = s.split(':')
1004 n = len(parts)
1005 if n == 1:
1006 fname = parts[0]
1007 fstart = None
1008 fend = None
1009 elif n != 3:
1010 raise _BadFileNotation
1011 else:
1012 fname = parts[0]
1013 def ascii_hex_to_int(ascii):
1014 if ascii is not None:
1015 try:
1016 return int(ascii, 16)
1017 except ValueError:
1018 raise _BadFileNotation
1019 return ascii
1020 fstart = ascii_hex_to_int(parts[1] or None)
1021 fend = ascii_hex_to_int(parts[2] or None)
1022 return drive+fname, fstart, fend
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1049 '''Base Exception class for IntelHex module'''
1050
1051 _fmt = 'IntelHex base error'
1052
1054 """Initialize the Exception with the given message.
1055 """
1056 self.msg = msg
1057 for key, value in kw.items():
1058 setattr(self, key, value)
1059
1061 """Return the message in this Exception."""
1062 if self.msg:
1063 return self.msg
1064 try:
1065 return self._fmt % self.__dict__
1066 except (NameError, ValueError, KeyError), e:
1067 return 'Unprintable exception %s: %s' \
1068 % (self.__class__.__name__, str(e))
1069
1071 """Used for internal needs only."""
1072 _fmt = 'EOF record reached -- signal to stop read file'
1073
1075 _fmt = 'Hex reader base error'
1076
1078 _fmt = 'Hex file has data overlap at address 0x%(address)X on line %(line)d'
1079
1080
1081
1082
1084 _fmt = 'Hex file contains invalid record at line %(line)d'
1085
1086
1088 _fmt = 'Record at line %(line)d has invalid length'
1089
1091 _fmt = 'Record at line %(line)d has invalid record type'
1092
1094 _fmt = 'Record at line %(line)d has invalid checksum'
1095
1097 _fmt = 'File has invalid End-of-File record'
1098
1099
1101 _fmt = 'Base class for extended address exceptions'
1102
1104 _fmt = 'Invalid Extended Segment Address Record at line %(line)d'
1105
1107 _fmt = 'Invalid Extended Linear Address Record at line %(line)d'
1108
1109
1111 _fmt = 'Base class for start address exceptions'
1112
1114 _fmt = 'Invalid Start Segment Address Record at line %(line)d'
1115
1117 _fmt = 'Invalid Start Linear Address Record at line %(line)d'
1118
1120 _fmt = 'Start Address Record appears twice at line %(line)d'
1121
1123 _fmt = 'Invalid start address value: %(start_addr)s'
1124
1125
1127 _fmt = ('Bad access at 0x%(address)X: '
1128 'not enough data to read %(length)d contiguous bytes')
1129
1131 _fmt = 'Bad access at 0x%(address)X: not enough data to read 16 bit value'
1132