# $Id$
"""

"""

import Tkinter
import random
import string
import time

import wibohost

class COMDialog(Tkinter.Frame):
	def __init__(self, master, whost, **kwargs):
		Tkinter.Frame.__init__(self, master, **kwargs)
		self.whost=whost
		self.comport = Tkinter.StringVar()
		self.comport.set('COM10')
		Tkinter.Label(self, text='COM Port').pack()
		Tkinter.Entry(self, textvariable=self.comport).pack()
		self.connbut=Tkinter.Button(self, text='Connect', command=self.connect)
		self.connbut.pack()
	def connect(self):
		print "Opening", self.comport.get()
		self.whost.port = self.comport.get()
		self.whost.setBaudrate(38400)
		self.whost.setTimeout(1.0)
		self.whost.open()
		time.sleep(0.1) # for the bootup string if device was reset on COM port open
		st = "Thequickbrownfox"
		if self.whost.echo(st)['data'] != st:
			print "Cant connect to HOST", self.whost.getSettingsDict()
		else:
			self.connbut.config(text = 'Disconnect', command=self.disconnect)

	def disconnect(self):
		self.whost.close()
		self.connbut.config(text = 'Connect', command=self.connect)

class NodePool(Tkinter.Canvas):
	map_status = {None:'grey', 'OK':'green', 'FAIL':'red'}
	map_memtarget = {'X':'none', 'F':'Flash', 'E':'EEPROM'}
	def __init__(self, master, whost, **kwargs):
		Tkinter.Canvas.__init__(self, master, **kwargs)
		self.whost = whost
		
	def redraw(self):
		[self.delete(t) for t in self.find_all()]
		rad = 20
		for n in self.whost.nodes:
			x, y = (random.randrange(rad+1,self.winfo_width()-rad-1), random.randrange(rad+1,self.winfo_height()-rad-1))
			rect = (x-rad,y-rad,x+rad,y+rad)
			while len(self.find_overlapping(*rect)) > 0:
				x, y = (random.randrange(rad+1,self.winfo_width()-rad-1), random.randrange(rad+1,self.winfo_height()-rad-1))
				rect = (x-rad,y-rad,x+rad,y+rad)
			tag = hex(n['short_addr'])
			self.create_oval(*rect,fill=self.map_status[n['status']], outline='grey', tags=tag)
			self.create_text(x,y-rad/2,text=hex(n['short_addr']))
			self.create_text(x,y+rad/3,text=self.map_memtarget[n['target']])

class App(object):
	def __init__(self, master, whost):
		self.frame = Tkinter.Frame(master)
		self.frame.pack()

		self.whost=whost

		self.comdialog = COMDialog(self.frame, self.whost, border=1, relief=Tkinter.RAISED)
		self.comdialog.pack()

		self.hexfile=Tkinter.StringVar(value='-filename-') # hex-file to flash

		self.scanmin = Tkinter.StringVar()
		self.scanmin.set('0x0000')
		self.scanmax = Tkinter.StringVar()
		self.scanmax.set('0x000F')
		Tkinter.Label(self.frame, text='Scan Range').pack()
		Tkinter.Entry(self.frame, textvariable=self.scanmin).pack()
		Tkinter.Entry(self.frame, textvariable=self.scanmax).pack()

		self.pool=NodePool(self.frame, self.whost, bg='white')
		self.pool.pack()
		Tkinter.Button(self.frame, text='Scan', command=self.scan).pack()
		
		Tkinter.Button(self.frame, text='Jump Bootloader', command=self.jbootl).pack()
		Tkinter.Entry(self.frame, textvariable=self.hexfile).pack()
		Tkinter.Button(self.frame, text='Flash', command=self.flash).pack()
		Tkinter.Button(self.frame, text='Quit', command=self.frame.quit).pack()

	def jbootl(self):
		self.whost.jbootl(0xFFFF)
		
	def scan(self):
		self.whost.scan(range(int(self.scanmin.get(), 16), int(self.scanmax.get(), 16)+1))
		print self.whost.nodes
		# DEBUG
		[n.update({'status':random.choice([None, 'OK', 'FAIL'])}) for n in self.whost.nodes]
		#######
		self.pool.redraw()

	def flash(self):
		self.whost.flashhex(nodeid=0xFFFF,  fname=self.hexfile) # as broadcast
		print [self.whost.checkcrc(n['short_addr']) for n in self.pool.nodes]

class EmuDevice(object):
	def __init__(self, nwksize=10):
		self.nodes = {}
		self.checksum = 0
		for i in range(1,nwksize+1):
			self.nodes.update({i:{'pagesize': 256, 'appname': 'wibo', 'short_addr': i, 'chan': 11, 'crc': 0, 'version': 1, 'boardname': 'ibdt232'}})

	def ping(self, nodeid):
		if nodeid in self.nodes:
			return self.nodes[nodeid]
		else:
			return None

	def finish(self, nodeid):
		return None

	def feedhex(self, nodeid, ln):
		self.checksum += 1
		if random.randint(1,1000) != 5: # emulate some failed transmission
			if nodeid == 0xFFFF: # broadcast
				nodes = self.nodes
			else:
				nodes = [nodeid]
			for n in nodes: self.nodes[n]['crc'] += 1

	def reset(self):
		self.checksum = 0
		for n in self.nodes: self.nodes[n]['crc']=0

	def exit(self, nodeid):
		self.nodes.remove(nodeid)

	def crc(self):
		return self.checksum

	def echo(self, dstr):
		return None


class EmuHost(EmuDevice):
	def __init__(self, *args, **kwargs):
		EmuDevice.__init__(self)
		self.devicelist = []
		self.verbose = 1

	def scan(self, scanrange=[]):
		ret = []
		if self.verbose:
			print "scan nodes", scanrange,
		for a in scanrange:
			tmp = self.ping(a)
			if tmp != None:
				ret.append(tmp)
				if self.verbose:
					print "0x%04x" % tmp['short_addr'],
					if (len(ret) % 4) == 0:
						print "\n        ",
		if self.verbose:
			print "\nFound %d devices\n" % len(ret)
		return ret

	def flashhex(self, nodeid=0xFFFF, fname=None, delay=0.05):
		f=[string.join(map(hex,[random.randrange(256) for j in range(20)])) for i in range(100)]
		self.reset()
		for i, ln in enumerate(f):
			self.feedhex(nodeid, ln.strip())
			# time.sleep(delay)
			if self.verbose == 1:
				print "line %-4d crc: 0x%04x\r" % (i, self.crc()),
			elif self.verbose > 1:
				print i, ln.strip(), hex(self.crc())

		print "                      \r"\
			  "file: %s, node: 0x%04x, records: %d, crc: 0x%04x" % \
			  (fname, nodeid, i, self.crc())
		time.sleep(delay)
		self.finish(nodeid)
		return

	def checkcrc(self, nodeid):
		hostcrc = self.crc()
		p = self.ping(nodeid)
		if p:
			ret = (hostcrc == p['crc'])
			if ret:
				print "node 0x%04x crc OK" % nodeid
			else:
				print "node 0x%04x crc fail" % nodeid
				print "hostcrc: 0x%04x nodecrc: 0x%04x" % (hostcrc, p.get('crc'))
		else:
			print "no response from node 0x%04x" % nodeid
			ret = False
		return ret


if __name__ == "__main__":

	root = Tkinter.Tk()
	app=App(root, wibohost.WIBONetwork())
	# app=App(root, EmuHost())
	root.mainloop()


# EOF
