#!/usr/bin/env python # Copyright (c) 2007 Johns Hopkins University. # All rights reserved. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose, without fee, and without written # agreement is hereby granted, provided that the above copyright # notice, the (updated) modification history and the author appear in # all copies of this source code. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, # OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. # @author Chieh-Jan Mike Liang # @author Razvan Musaloiu-E. import sys, struct, operator from xml.dom.minidom import parse DELUGE_PKTS_PER_PAGE = 48 DELUGE_PKT_PAYLOAD_SIZE = 23 DELUGE_BYTES_PER_PAGE = DELUGE_PKTS_PER_PAGE * DELUGE_PKT_PAYLOAD_SIZE DELUGE_MAX_PAGES = 128 DELUGE_IDENT_SIZE = 128 def sencode(s, dim): s = [ord(c) for c in s] if len(s) > dim: return s[:dim] return s + [0] * (dim - len(s)) # Encode to big endian def encode(val, dim): output = [] for i in range(dim): output.append(val & 0xFF) val = val >> 8 output.reverse() return output def int2byte(v): return "".join([struct.pack("B", i) for i in v]) def crc16(data): crc = 0 for b in data: crc = crc ^ (b << 8) for i in range(0, 8): if crc & 0x8000 == 0x8000: crc = (crc << 1) ^ 0x1021 else: crc = crc << 1 crc = crc & 0xffff return crc def pages(data): l = len(data) - 2*DELUGE_MAX_PAGES if l % DELUGE_BYTES_PER_PAGE != 0: sys.stderr.write("ERROR: Bug in padding!") sys.exit() return l / DELUGE_BYTES_PER_PAGE def align(data): mod = len(data) % DELUGE_BYTES_PER_PAGE if mod == 0: return data return data + [0] * (DELUGE_BYTES_PER_PAGE - mod) def deluge_ident(data): tmp = encode(ident['uidhash'], 4) + \ encode(ident['size'], 4) + \ [pages(data), 0] crc = crc16(tmp) tmp += encode(crc, 2) + \ sencode(ident['appname'], 16) + \ sencode(ident['username'], 16) + \ sencode(ident['hostname'], 16) + \ sencode(ident['platform'], 16) + \ encode(ident['timestamp'], 4) + \ encode(ident['userhash'], 4) return tmp + [0] * (DELUGE_IDENT_SIZE - len(tmp)) def deluge_crc(data): crc = [0] * DELUGE_MAX_PAGES j = 0 sys.stderr.write("CRCs:\n ") for i in range(0, len(data)-1, DELUGE_BYTES_PER_PAGE): crc[j] = crc16(data[i:i+DELUGE_BYTES_PER_PAGE]) sys.stderr.write("0x%04X " % (crc[j])) if (j + 1) % 7 == 0: sys.stderr.write("\n ") j += 1 sys.stderr.write("\n") return reduce(operator.add, [encode(i, 2) for i in crc]) + data for i in range(len(sys.argv)): if sys.argv[i] == '-i': img_num = int(sys.argv[i+1]) dom = parse(sys.argv[-1]) ident = {} ident_list = [(n.localName, n.firstChild.nodeValue) for n in dom.getElementsByTagName('ident')[0].childNodes if n.localName != None] for (k, v) in ident_list: ident[k] = v for p in ['timestamp', 'userhash', 'uidhash']: ident[p] = int(ident[p][:-1], 16) error = "ERROR: getting the image from the XML file failed." try: image_element = dom.getElementsByTagName('image')[0] if image_element.getAttribute('format') != 'ihex': error = "ERROR: image format is %s instead of ihex" % image_element.getAttribute('format') sys.exit() image = image_element.firstChild.nodeValue except: sys.stderr.write(error + '\n') sys.exit() all = [] section = [] end_addr = None for line in image.split(): #print "DEBUG:", line length = int(line[1:3], 16) addr = int(line[3:7], 16) rectype = int(line[7:9], 16) data = [] if len(line) > 11: data = [int(line[i:i+2], 16) for i in range(9, len(line)-2, 2)] crc = int(line[-2:], 16) if rectype in [0x00, 0x03]: if not end_addr: end_addr = addr start_addr = addr if end_addr != addr: all.append((start_addr, section)) if rectype == 0x03: # This last record updates the first 4 bytes which # holds some some low level configuration. They are # the same all the time so I guess that's why they are # skipped. break section = [] start_addr = addr section += data end_addr = addr + length elif rectype == 0x01: all.append((start_addr, section)) section = [] start_addr = addr sys.stderr.write('Ihex read complete:\n') sys.stderr.write(' ' + '\n '.join(["%5d bytes starting at 0x%X" % (len(l), a) for (a, l) in all])) sys.stderr.write('\n') sys.stderr.write(' %d bytes in %d sections\n' % (reduce(operator.add, [len(l) for (_, l) in all]), len(all))) # Usually, there are two sections: one for the code and one for the # interrupt vector. all_data = [] for (addr, data) in all: all_data += encode(addr, 4) + \ encode(len(data), 4) + \ data padding = [0] * (DELUGE_BYTES_PER_PAGE - len(all_data) % DELUGE_BYTES_PER_PAGE) if len(padding) < DELUGE_BYTES_PER_PAGE: all_data += padding all_data = deluge_crc(all_data) ident['size'] = DELUGE_IDENT_SIZE + len(all_data) sys.stdout.write(int2byte(deluge_ident(all_data)) + int2byte(all_data))