# $Id: wibohost.py,v 1.16 2010/08/13 19:55:02 awachtler Exp $
"""
wibo host utility

Usage:
    python -i wibo_host.py [OPTIONS]

    Options:
      -P PORT : Port string ("port" or "port:baudrate"), e.g. /dev/ttyS0, COM1:38400
                [default COM2:38400]
      -h      : show help and exit
      -V      : show version and exit
"""
import serial, string, re, time, sys, getopt
HISTORY = "wibohost.hist"
VERSION = 0.01
PORT = "COM2"
BAUDRATE = 38400



class WIBORxDevice(serial.Serial):
	""" Basic class to interface an WIBO Host on serial line """

	def __init__(self, *args, **kwargs):
		serial.Serial.__init__(self, *args, **kwargs)
		self.flt = re.compile("(?P<code>[A-Z]+)(?P<data>.*)")
		self.VERBOSE = 0

	def _flush(self):
		self.read(self.inWaiting())

	def _sendcommand(self, cmd, *args):
		self._flush()
		self.write(string.join(map(str,[cmd]+list(args)+['\n'])))
		# TODO evaluate returning line and parse for parameters
		s = self.readline().strip()
		if self.VERBOSE: print s
		m = self.flt.match(s)
		if m == None:
			return None
		else:
			return m.groupdict()

class WIBOHostDevice(WIBORxDevice):
	""" Class to implement commands for WIBO Host """

	def __init__(self, *args, **kwargs):
		WIBORxDevice.__init__(self, *args, **kwargs)

	def ping(self, nodeid):
		ret=self._sendcommand('ping', nodeid)
		if ret['code'] == 'OK':
			return eval(ret['data'])
		else:
			return None

	def finish(self, nodeid):
		self._sendcommand('finish', nodeid)

	def feedhex(self, nodeid, ln):
		self._sendcommand('feedhex', nodeid, ln)

	def reset(self):
		self._sendcommand('reset')

	def exit(self, nodeid):
		self._sendcommand('exit', nodeid)

	def crc(self):
		return int(self._sendcommand('crc')['data'],16)

	def addr(self, nodeid):
		return self._sendcommand('addr', nodeid)

	def echo(self, dstr):
		return self._sendcommand('echo', dstr)

class WIBOHost(WIBOHostDevice):
	""" Class to represent a list of WIBO nodes """

	def __init__(self, *args, **kwargs):
		WIBOHostDevice.__init__(self, *args, **kwargs)
		self.devicelist = []

	def scan(self, scanrange=[]):
		return [i for i in scanrange if self.ping(i) != None]

	def flashhex(self, nodeid='FFFF', fname=None, delay=0.1):
		f=open(fname)
		self.reset()
		for i, ln in enumerate(f):
			self.feedhex(nodeid, ln.strip())
			time.sleep(delay)
			print i, ln.strip(), hex(self.crc())
		time.sleep(delay)
		self.finish(nodeid)
		f.close()
		return

	def checkcrc(self, nodeid):
		hostcrc = self.crc()
		print "Host CRC:", hostcrc
		p = self.ping(nodeid)
		print "Host:", hostcrc, "Node%X: "%nodeid, p['crc']
		return hostcrc == p['crc']


def init_prompt():
    global HISTORY
    try:
        import readline, rlcompleter, atexit, sys, os
        sys.ps1 = "wibo>"
        readline.parse_and_bind("tab:complete")
        save_hist = lambda history : readline.write_history_file(history)
        atexit.register(readline.write_history_file, HISTORY) 
        if os.path.exists(HISTORY):
            readline.read_history_file(HISTORY)
    except:
        print "No libreadline support"
        traceback.print_exc()

def process_command_line():
    global PORT, BAUDRATE
    opts,args = getopt.getopt(sys.argv[1:],"P:hV")
    ret = False
    for o,v in opts:
        if o == "-h":
            print __doc__
            ret = True
        if o == "-V":
            print "wibohost v.", VERSION
            ret = True
        if o == "-P":
            try:
                p,b = v.split(":")
                b = eval(b)
                PORT = p
                BAUDRATE = b
            except ValueError:
                PORT = v
    return ret


if __name__ == "__main__":
    do_exit = process_command_line()
    if do_exit:
        sys.exit(0)
    init_prompt()
    print "open",PORT,"at",BAUDRATE

    wh = WIBOHost(port=PORT, baudrate=BAUDRATE)
