Mercurial > lcfOS
changeset 244:58155c7c4a8e
Add hexutil
author | Windel Bouwman |
---|---|
date | Wed, 24 Jul 2013 19:47:13 +0200 |
parents | ef683881c64e |
children | 66912720d712 |
files | python/hexfile.py python/hexutil.py python/st-flash.py python/testhexfile.py |
diffstat | 4 files changed, 153 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/python/hexfile.py Tue Jul 23 16:50:02 2013 +0200 +++ b/python/hexfile.py Wed Jul 24 19:47:13 2013 +0200 @@ -1,4 +1,5 @@ import os +import struct class HexFileException(Exception): pass @@ -13,11 +14,30 @@ crc = sum(nums) if (crc & 0xFF) != 0: raise HexFileException('crc incorrect') - address = nums[1] * 256 + nums[2] + address = struct.unpack('>H', nums[1:3])[0] typ = nums[3] data = nums[4:-1] return (address, typ, data) +def makeHexLine(address, typ, data=bytes()): + bytecount = len(data) + nums = bytearray() + nums.append(bytecount) + nums.extend(struct.pack('>H', address)) + nums.append(typ) + nums.extend(data) + crc = sum(nums) + crc = ((~crc) + 1) & 0xFF + nums.append(crc) + line = ':' + ''.join(['{:02X}'.format(b) for b in nums]) + return line + +def chunks(data, csize=16): + idx = 0 + while idx < len(data): + s = min(len(data) - idx, csize) + yield data[idx:idx+s] + idx += s class HexFile: """ Represents an intel hexfile """ @@ -65,27 +85,48 @@ self.regions.append(HexFileRegion(startAddress, bytes(curData))) def __repr__(self): - i = [] - i.append(super().__repr__()) - i.append('Start address {0}'.format(hex(self.startAddress))) + return 'Hexfile with {} regions'.format(len(self.regions)) + + def dump(self): + print(self) for r in self.regions: - i.append(str(r)) - return os.linesep.join(i) + print(r) + + def __eq__(self, other): + regions = self.regions + oregions = other.regions + if len(regions) != len(oregions): + return False + return all(rs == ro for rs, ro in zip(regions, oregions)) + + def addRegion(self, address, data): + r = HexFileRegion(address, data) + # TODO: check touches + self.regions.append(r) + self.regions.sort(key=lambda r: r.address) def save(self, f): for r in self.regions: offset = 0 - while offset < len(r.data): - f.write('a') - offset += 16 - + for chunk in chunks(r.data): + print(makeHexLine(r.address + offset, 0x0, bytes(r.data[offset:offset+16])), file=f) + offset += len(chunk) + print(makeHexLine(0, 0x1, bytes()), file=f) class HexFileRegion: - def __init__(self, address, data = bytes()): - self.address = address - self.data = data - def __repr__(self): - return 'Region at 0x{0:X} of {1} bytes'.format(self.address, len(self.data)) + def __init__(self, address, data = bytes()): + self.address = address + self.data = data + + def __repr__(self): + return 'Region at 0x{0:X} of {1} bytes'.format(self.address, len(self.data)) + + def __eq__(self, other): + return (self.address, self.data) == (other.address, other.data) + + @property + def EndAddress(self): + return self.address + len(self.data) if __name__ == '__main__':
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/hexutil.py Wed Jul 24 19:47:13 2013 +0200 @@ -0,0 +1,53 @@ +#!/usr/bin/python + +import sys +import argparse +from hexfile import HexFile + +def hex2int(s): + if s.startswith('0x'): + s = s[2:] + return int(s, 16) + raise ValueError('Hexadecimal value must begin with 0x') + +parser = argparse.ArgumentParser( + description='hexfile manipulation tool by Windel Bouwman') +subparsers = parser.add_subparsers(title='commands', + description='possible commands', dest='command') + +p = subparsers.add_parser('info', help='dump info about hexfile') +p.add_argument('hexfile', type=argparse.FileType('r')) + +p = subparsers.add_parser('new', help='create empty hexfile') +p.add_argument('hexfile', type=argparse.FileType('x')) + +p = subparsers.add_parser('add', help='add binary data from file to hexfile') +p.add_argument('hexfile', type=argparse.FileType('r+'), help="the hexfile to add the data to") +p.add_argument('address', type=hex2int, help="hex address") +p.add_argument('datafile', type=argparse.FileType('rb'), help='binary file to add') + +def main(args): + if args.command == 'info': + hf = HexFile() + hf.load(args.hexfile) + print(hf) + for region in hf.regions: + print(region) + elif args.command == 'new': + hf = HexFile() + hf.save(args.hexfile) + elif args.command == 'add': + hf = HexFile() + hf.load(args.hexfile) + data = args.datafile.read() + hf.addRegion(args.address, data) + else: + raise NotImplementedError() + +if __name__ == '__main__': + args = parser.parse_args() + if not args.command: + parser.print_usage() + sys.exit(1) + main(args) +
--- a/python/st-flash.py Tue Jul 23 16:50:02 2013 +0200 +++ b/python/st-flash.py Wed Jul 24 19:47:13 2013 +0200 @@ -23,6 +23,9 @@ writeparser.add_argument('filename', type=argparse.FileType('rb')) writeparser.add_argument('address', type=hex2int) +hexwriteparser = subparsers.add_parser('hexwrite', help='write hexfile to flash') +hexwriteparser.add_argument('filename', type=argparse.FileType('r')) + verifyparser = subparsers.add_parser('verify', help='verify flash contents') verifyparser.add_argument('filename', type=argparse.FileType('rb')) verifyparser.add_argument('address', type=hex2int)
--- a/python/testhexfile.py Tue Jul 23 16:50:02 2013 +0200 +++ b/python/testhexfile.py Wed Jul 24 19:47:13 2013 +0200 @@ -1,39 +1,66 @@ import unittest import io -import hexfile +from hexfile import HexFile, HexFileException class testHexFile(unittest.TestCase): - def setUp(self): - pass - + def saveload(self, hf): + f = io.StringIO() + hf.save(f) + hf2 = HexFile() + hf2.load(io.StringIO(f.getvalue())) + self.assertEqual(hf, hf2) + def testSave(self): - hf = hexfile.HexFile() - f = io.StringIO() - region = hexfile.HexFileRegion(0x8000, bytes.fromhex('aabbcc')) - hf.regions.append(region) - hf.save(f) + hf = HexFile() + hf.addRegion(0x8000, bytes.fromhex('aabbcc')) + self.saveload(hf) + + def testEqual(self): + hf1 = HexFile() + hf2 = HexFile() + hf1.addRegion(10, bytes.fromhex('aabbcc')) + hf2.addRegion(10, bytes.fromhex('aabbcc')) + self.assertEqual(hf1, hf2) + + def testNotEqual(self): + hf1 = HexFile() + hf2 = HexFile() + hf1.addRegion(10, bytes.fromhex('aabbcc')) + hf2.addRegion(10, bytes.fromhex('aabbdc')) + self.assertNotEqual(hf1, hf2) + + def testNotEqual2(self): + hf1 = HexFile() + hf2 = HexFile() + hf1.addRegion(10, bytes.fromhex('aabbcc')) + hf2.addRegion(10, bytes.fromhex('aabbcc')) + hf2.addRegion(22, bytes.fromhex('aabbcc')) + self.assertNotEqual(hf1, hf2) def testLoad(self): - hf = hexfile.HexFile() + hf = HexFile() dummyhex = """ :01400000aa15 """ f = io.StringIO(dummyhex) hf.load(f) + self.assertEqual(1, len(hf.regions)) + self.assertEqual(0x4000, hf.regions[0].address) + self.assertSequenceEqual(bytes.fromhex('aa'), hf.regions[0].data) def testIncorrectCrc(self): - hf = hexfile.HexFile() + hf = HexFile() txt = ":01400000aabb" f = io.StringIO(txt) - with self.assertRaises(hexfile.HexFileException): + with self.assertRaisesRegex(HexFileException, 'crc'): hf.load(f) def testIncorrectLength(self): - hf = hexfile.HexFile() + hf = HexFile() txt = ":0140002200aabb" f = io.StringIO(txt) - with self.assertRaises(hexfile.HexFileException): + with self.assertRaisesRegex(HexFileException, 'count'): hf.load(f) if __name__ == '__main__':