#!/usr/bin/python import sys, os, serial, time, re DEV = '/dev' PORTS = [os.path.join(DEV, port) for port in os.listdir(DEV) if port.startswith('ttyUSB')] TIMEOUT = 0.2 # for serial communications PAUSE = 0.1 # for hardware signaling EOL = '\r\n' TOGGLE_LINES = True CLOCK_RATE = '20000' # clock rate of SBC in KHz (CCLK) (as string) CMD_SUCCESS = '0' # expected from PCB after successful command entry def dump(*args): if len(args) != 2: print >>sys.stderr, 'Must specify start address and number of bytes' sys.exit(1) start, bytecount = map(safeint, args) print >>sys.stderr, 'Dumping %d bytes starting at 0x%x' % (bytecount, start) port = init() sync(port) dumped = '' send(port, 'R %d %d' % (start, bytecount)) response = filter(None, expect(port, True).group().split('\r\n')) debug('response: %s' % response) check_equal('0', response.pop(0), 'Error code from R command') dumped += uudecode(response) while True: send(port, 'OK') response = filter(None, expect(port, True).group().split('\r\n')) debug('response: %s' % response) if not response: return xxd(dumped, address = start) else: dumped += uudecode(response) def xxd(data, address = 0, chunksize = 16, wordsize = 2): 'dump data in xxd format' address_format = '%07x:' if address + len(data) < 0x10000000 else '%08x:' padding = [' ' * wordsize * 2] * (chunksize / wordsize) chunked = [data[n:n + chunksize] for n in range(0, len(data), chunksize)] for chunk in chunked: print address_format % address, words = [chunk[n:n + wordsize].encode('hex') for n in range(0, chunksize, wordsize)] for word in (words + padding)[:chunksize / wordsize]: print (word + padding[0])[:len(padding[0])], print ' ' + re.compile('[^ -~]').sub('.', chunk) address += chunksize def init(): port = serial.Serial(PORTS[0], baudrate = 19200, timeout = TIMEOUT) if TOGGLE_LINES: port.setDTR(1) # DTR high forces reset port.setRTS(1) # RTS high forces ISP mode (pin 14) time.sleep(PAUSE) port.setDTR(0) # drop reset line first, holding P0.14 high time.sleep(PAUSE) port.setRTS(0) else: port.setRTS(0) port.setDTR(0) time.sleep(PAUSE) # give SBC a chance to initialize return port def safeint(number): if number.startswith(('0X', '0x')): return int(number, 16) else: return int(number) def comm(): port = init() sync(port) print >>sys.stderr, 'Communications established. Enter commands:' while True: try: command = raw_input('> ').rstrip() if command == 'QUIT': raise EOFError, 'User exited' send(port, command) print expect(port, True).group() except EOFError: print >>sys.stderr, '\r\n' break port.close() def sync(port): expect(port, '', eol = None) send(port, '?', eol = None) expect(port, 'Synchronized') send(port, 'Synchronized') expect(port, ['Synchronized', 'OK']) # because echo is still on send(port, CLOCK_RATE) expect(port, [CLOCK_RATE, 'OK']) send(port, 'A 0') # turn off echo expect(port, ['A 0', CMD_SUCCESS]) # last echo we should get def uudecode(lines): 'uudecode requires begin and end; treats \r as illegal character' checksum = lines.pop(-1) message = 'begin\n' + '\n'.join(lines) + '\n \nend\n' debug('decoding %s' % repr(message)) decoded = message.decode('uu') check_equal(int(checksum), sum(map(ord, decoded)), 'Checksum for uudecode') return decoded def check_equal(expected, got, message): if got != expected: print >>sys.stderr, '%s: got %s, expected %s' % (message, got, expected) sys.exit(1) def send(port, message, eol = EOL): debug('Sending: %s' % message) port.write(message + (eol or '')) def expect(port, what, eol = EOL): if type(what) == str: debug('Expecting: %s' % repr(what)) elif hasattr(what, 'pattern'): debug('Expecting match for pattern %s' % repr(what.pattern)) elif what is True: debug('Expecting a response') what = re.compile('(?s).*') else: # assume iterable what = eol.join(what) debug('Expecting: %s' % repr(what)) message = read(port) match, pattern, found = check_match(message, what, eol) if not match: print >>sys.stderr, 'Expected %s, got %s' % (repr(pattern), repr(found)) sys.exit(1) else: return match def check_match(text, pattern, eol): if type(pattern) == str and pattern + (eol or '') == text: return True, pattern, text elif hasattr(pattern, 'pattern'): match = pattern.match(text) return match, pattern.pattern, text else: return False, pattern, text def read(port, chunksize = 64): text = '' while True: partial = port.read(chunksize) # must have timeout or will block forever if len(partial): text += partial else: return text def debug(message): if os.getenv('DEBUGGING'): print >>sys.stderr, message if __name__ == '__main__': command = os.path.splitext(os.path.split(sys.argv[0])[1])[0] print >>sys.stderr, eval(command)(*sys.argv[1:]) or ''