#!/usr/bin/env python # # RS-232 DB9 pin summary: # # pin name color (experimental cable) # 1 DCD # 2 RX red # 3 TX # 4 DTR yellow # 5 GND green # 6 DSR # 7 RTS blue # 8 CTS # 9 RI # # K700 (DCU-11?) USB serial cable (ark3116 driver): # # name color # RTS red clear: +3.2V # RX blue internal pull-up. 15uA pull-down current. # TX white idle: +3.2V # +5V yellow # GND green import sys, os, termios, fcntl, struct, array, select, getopt me = 'read-serial' opt = {} usage = ''' Usage: ''' + me + ''' [options...] [serial device file] Options: -h, -? show this text -C print target C code for feeding this script -d Use a fixed set of variables to dump, mainly eeprom. ''' def out(s): sys.stdout.write(s) def warn(s): sys.stderr.write(me + ': ' + s) def die(s): warn(s) sys.exit(1) def options(): try: opts, args = getopt.getopt(sys.argv[1:], '?hCd') except getopt.GetoptError, err: die(str(err) + '\n') for o, a in opts: if o in ['-h', '-?']: out(usage) sys.exit(0) else: opt[o] = a opt['args'] = args def open_device(name): dtr = struct.pack('I', termios.TIOCM_DTR) rts = struct.pack('I', termios.TIOCM_RTS) d = os.open(name, os.O_RDONLY) #fcntl.ioctl(d, termios.TIOCMBIC, rts) # -11V (default) #fcntl.ioctl(d, termios.TIOCMBIS, dtr) # +11V # Experiments show that the buffer we need is actually something like # # define NCCS 19 /* not necessarily termios.NCCS */ # struct termios { # uint16_t c_iflag; /* input modes */ # uint16_t c_oflag; /* output modes */ # uint16_t c_cflag; /* control modes */ # uint16_t c_lflag; /* local modes */ # uint8_t c_line; /* line discipline */ # char c_cc[NCCS]; /* control chars */ # }; # buf = array.array('H', 14 * [0]) fcntl.ioctl(d, termios.TCGETA, buf, 1) buf[0] = termios.IGNBRK buf[2] = termios.B2400 | termios.CS8 | termios.CREAD | termios.CLOCAL buf[3] = 0 fcntl.ioctl(d, termios.TCSETA, buf) return d def rx(): try: return ord(os.read(fd, 1)) except TypeError: sys.exit(0) class base: all = [] def __init__(self, name, unit, strf=lambda x: '%d' % x): self.name = name self.unit = unit self.strf = strf self.valid = False self.maxlen = 0 base.all += [self] def commit(self): self.val = self.sample self.valid = True self.maxlen = max(self.maxlen, len(self.strf(self.val))) def __str__(self): return '%s: %*s%s' % (self.name, self.maxlen, self.strf(self.val), self.unit) def reset(self): pass class val8(base): def rx(self): self.sample = rx() def C(self): return 'ser_tx(%s);' % self.name class val16(base): def rx(self): self.sample = rx() self.sample = (self.sample << 8) | rx() def C(self): return '{ uint16_t _v; uint8_t _s;saveicli(_s); _v = %s; restorei(_s); ser_tx(_v >> 8); ser_tx(_v); }' % self.name class val32(base): def rx(self): self.sample = rx() self.sample = (self.sample << 8) | rx() self.sample = (self.sample << 8) | rx() self.sample = (self.sample << 8) | rx() def C(self): return '{ uint32_t _v; uint8_t _s;saveicli(_s); _v = %s; restorei(_s); ser_tx(_v >> 24); ser_tx(_v >> 16); ser_tx(_v >> 8); ser_tx(_v); }' % self.name class minmax16(val16): def commit(self): if not self.valid or self.sample < self.min: self.min = self.sample if not self.valid or self.sample > self.max: self.max = self.sample val16.commit(self) def __str__(self): return '%s (%s..%s)' % (val16.__str__(self), self.strf(self.min), self.strf(self.max)) def reset(self): if self.valid: self.min = self.max = self.val def monitor(): sync = 0 while 1: b = rx() if b != ord('Z'): sync = 0 continue sync += 1 for i in base.all: i.rx() if sync > 1: for i in base.all: i.commit() out(' %s' % i) out('\n') if fd != 0 and select.select([0], [], [], 0)[0] > []: while 1: x = os.read(0, 1) if x == '\n': break for i in base.all: i.reset() def generate(): out('/* generated by %s */\n' % me) out('{\n') out('\tser_init();\n') out('\tser_tx(\'Z\');\n') for i in base.all: out('\t%s\n' % i.C()) out('\tser_cleanup();\n') out('}\n') def define_variables(): fA = lambda i: '%.3f' % (i * 1.1 / 1024 / 20 / 0.04) # LED current fV = lambda u: '%.3f' % (u * 1.1 / 1024 * (10+22)/10) # Battery voltage fC = lambda t: '%d' % ((t - 271) / 1.167 + 0.5) # temperature fint16 = lambda x: '%d' % (x - 65536 if x & 0x8000 else x) def hhmmss(ms): hh = ms / (3600 * 1000) ms -= hh * 3600 * 1000 mm = ms / (60 * 1000) ms -= mm * 60 * 1000 ss = ms / 1000 return '%d:%02d:%02d' % (hh, mm, ss) if '-d' in opt: val16('pwm1_max', '') val16('iled_min', 'A', fA) val16('iled_max', 'A', fA) val16('iled_mintime', 'ms') val16('iled_maxtime', 'ms') val16('iled_minerr', '', lambda x: '%d' % (-x)) val16('iled_maxerr', '', lambda x: '%d' % x) val16('iled_maxadj', '') val16('vbat_max', 'V', fV) val16('temp_min', 'C', fC) val16('temp_max', 'C', fC) val32('on_max', '', hhmmss) val16('iled_final', 'A', fA) else: val8('pwm1_read()', '') val16('iled_target', 'A', fA) val16('iled_actual', 'A', fA) val16('iled_max', 'A', fA) val16('iled_err', '', fint16) val16('iled_adjustments', '') val16('iled_stable', '') val16('vbat_val', 'V', fV) val16('temp_val', 'C', fC) options() define_variables() if '-C' in opt: generate() else: fd = 0 # for testing if opt['args']: fd = open_device(opt['args'][-1]) monitor()