diff --git a/intelhex/__init__.py b/intelhex/__init__.py index 155f17f..dde980a 100644 --- a/intelhex/__init__.py +++ b/intelhex/__init__.py @@ -67,13 +67,21 @@ class _DeprecatedParam(object): class IntelHex(object): ''' Intel HEX file reader. ''' - def __init__(self, source=None): + def __init__(self, source=None, overlap='error'): ''' Constructor. If source specified, object will be initialized with the contents of source. Otherwise the object will be empty. @param source source for initialization (file name of HEX file, file object, addr dict or other IntelHex object) + @param overlap defines behavior for overlapping addresses + during hex file loading: + - 'error': raises AddressOverlapError (default) + - 'ignore': keeps the original data, discards new data + - 'replace': replaces the original data with new data + + Note: this parameter currently only affects loading + from HEX files via loadhex or during initialization. ''' # public members self.padding = 0x0FF @@ -84,6 +92,11 @@ def __init__(self, source=None): self._buf = {} self._offset = 0 + # overlap setting for hex loading + if overlap not in ('error', 'ignore', 'replace'): + raise ValueError("overlap argument should be either 'error', 'ignore' or 'replace'") + self._overlap_check = overlap + if source is not None: if isinstance(source, StrType) or getattr(source, "read", None): # load hex file @@ -140,11 +153,17 @@ def _decode_record(self, s, line=0): if record_type == 0: # data record addr += self._offset - for i in range_g(4, 4+record_length): - if not self._buf.get(addr, None) is None: - raise AddressOverlapError(address=addr, line=line) - self._buf[addr] = bin[i] - addr += 1 # FIXME: addr should be wrapped + base_addr = addr # Start address for this record's data + for i in range_g(record_length): + current_addr = base_addr + i + # Check for overlap based on self._overlap_check setting + if current_addr in self._buf: + if self._overlap_check == 'error': + raise AddressOverlapError(address=current_addr, line=line) + elif self._overlap_check == 'ignore': + continue # Skip assignment for this byte + # Assign if address doesn't exist OR if overlap is 'replace' + self._buf[current_addr] = bin[4+i] # BUT after 02 record (at 64K boundary) # and after 04 record (at 4G boundary) @@ -184,8 +203,8 @@ def _decode_record(self, s, line=0): raise DuplicateStartAddressRecordError(line=line) self.start_addr = {'EIP': (bin[4]*16777216 + bin[5]*65536 + - bin[6]*256 + - bin[7]), + bin[6]*256 + + bin[7]), } def loadhex(self, fobj): diff --git a/intelhex/test.py b/intelhex/test.py index 2aff575..1b1278d 100755 --- a/intelhex/test.py +++ b/intelhex/test.py @@ -1576,6 +1576,36 @@ def test_eof(self): # EOF should raise special exception self.assertRaises(_EndOfFile, self.decode_record, ':00000001FF') + def test_overlap_options(self): + # Hex file with overlapping data + overlapping_hex = """\ +:020000001122CB +:02000100334486 +:00000001FF +""" + # Test 'error' (default) + ih_error = IntelHex() + ih_error._decode_record(':020000001122CB') # First record ok + self.assertRaisesMsg(AddressOverlapError, + 'Hex file has data overlap at address 0x1 ' + 'on line 1', + ih_error._decode_record, + ':02000100334486', 1) + + # Test 'ignore' + ih_ignore = IntelHex(overlap='ignore') + ih_ignore.loadhex(StringIO(overlapping_hex)) + self.assertEqual(ih_ignore[0], 0x11) + self.assertEqual(ih_ignore[1], 0x22) # Should keep the first value (0x22) + self.assertEqual(ih_ignore[2], 0x44) + + # Test 'replace' + ih_replace = IntelHex(overlap='replace') + ih_replace.loadhex(StringIO(overlapping_hex)) + self.assertEqual(ih_replace[0], 0x11) + self.assertEqual(ih_replace[1], 0x33) # Should be replaced with the second value (0x33) + self.assertEqual(ih_replace[2], 0x44) + #/class TestDecodeHexRecords