#!/usr/bin/env python import gtk, cairo from string import split, strip, find, upper, lower from xml.parsers import expat import socket import struct port = 50200 group = '224.2.2.1' units = \ [ \ ["mark5fx01", 0, 0], \ ["mark5fx02", 0, 1], \ ["mark5fx03", 0, 2], \ ["mark5fx06", 1, 0], \ ["mark5fx07", 1, 1], \ ["mark5fx08", 1, 2], \ ["mark5fx09", 2, 0], \ ["mark5fx11", 2, 1], \ ["mark5fx12", 2, 2], \ ["mark5fx13", 3, 0], \ ["mark5fx14", 3, 1], \ ["mark5fx15", 3, 2], \ ["mark5fx16", 4, 0], \ ["mark5fx17", 4, 1], \ ["mark5fx18", 4, 2], \ ["mark5fx19", 5, 0], \ ["mark5fx20", 5, 1], \ ["mark5fx21", 5, 2], \ ["mark5fx22", 6, 0], \ ["mark5fx23", 6, 1], \ ["mark5fx24", 6, 2], \ ] maxX = 7 maxY = 3 class Mk5state: def __init__(self): self.ok = False self.pid = 0 self.id = '' self.mk5 = '' self.seq = 0 self.vsnA = 'none' self.vsnB = 'none' self.bank = ' ' self.state = 'Unknown' self.scan = 0 self.name = '' self.pos = 0L self.rate = 0.0 self.date = 0.0 def getstring(self): if self.ok: b1 = ' ' b2 = ' ' if self.bank == 'A': b1 = '*' elif self.bank == 'B': b2 = '*' str = '%10s %c%8s %c%8s %14s %7.2f %11d %3d %15s %12.6f ' % \ (self.mk5, b1, self.vsnA, b2, self.vsnB, self.state, \ self.rate, self.pos, self.scan, self.name, self.date) else: str = '' return str def getmk5(self): return self.mk5 class Parser: def __init__(self): self._parser = expat.ParserCreate() self._parser.StartElementHandler = self.start self._parser.EndElementHandler = self.end self._parser.CharacterDataHandler = self.data self.info = Mk5state() self.tmp = '' def feed(self, data): try: self._parser.Parse(data, 0) except expat.ExpatError: print '\n\n XXX %s XXX' % data def close(self): self._parser.Parse("", 1) # end of data del self._parser # get rid of circular references def start(self, tag, attrs): pass def end(self, tag): if tag == 'mark5Status': self.info.ok = True if tag == 'bankAVSN': if len(self.tmp) != 8: self.info.vsnA = 'none' else: self.info.vsnA = upper(self.tmp) if tag == 'bankBVSN': if len(self.tmp) != 8: self.info.vsnB = 'none' else: self.info.vsnB = upper(self.tmp) if tag == 'from': self.info.mk5 = lower(self.tmp) if tag == 'state': self.info.state = self.tmp if tag == 'playRate': self.info.rate = float(self.tmp) if tag == 'dataMJD': self.info.date = float(self.tmp) if tag == 'position': self.info.pos = int(self.tmp) if tag == 'scanNumber': self.info.scan = int(self.tmp) if tag == 'scanName': self.info.name = self.tmp if tag == 'activeBank': self.info.bank = self.tmp def data(self, data): self.tmp = data def getinfo(self): return self.info class Unit: def __init__(self): self.X = 0 self.Y = 0 self.name = 'mark5' self.state = Mk5state() def set(self, x, y, name): self.X = x self.Y = y self.color = (1.0*self.X/maxX, 1.0*self.Y/maxY, 0.0) self.name = name print x, y, name def draw(self, cr): cr.set_source_rgb(0,0,0) cr.rectangle(0, 0, 1, 1) cr.fill() cr.set_line_width(0.01) cr.set_font_size(0.08) cr.select_font_face("courier") if self.state.vsnA == 'none': cr.rectangle(0.1, 0.2, 0.35, 0.6) cr.set_source_rgb(0.2,0.25,0.25) cr.fill() else: cr.rectangle(0.08, 0.19, 0.39, 0.62) cr.set_source_rgb(0.9, 0.9, 0.9) cr.stroke() cr.move_to(0.1, 0.5) cr.show_text(self.state.vsnA) if self.state.vsnB == 'none': cr.rectangle(0.55, 0.2, 0.35, 0.6) cr.set_source_rgb(0.2,0.25,0.25) cr.fill() else: cr.rectangle(0.53, 0.19, 0.39, 0.62) cr.set_source_rgb(0.9, 0.9, 0.9) cr.stroke() cr.move_to(0.55, 0.5) cr.show_text(self.state.vsnB) class Mark5s(gtk.DrawingArea): __gsignals__ = { "expose-event": "override" } def init(self): self.Units = [] for u in units: U = Unit() U.set(u[1], u[2], u[0]) self.Units.append(U) self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind(('', port)) mreq = struct.pack("4sl", socket.inet_aton(group), socket.INADDR_ANY) self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) self.socket.settimeout(0.02) def do_expose_event(self, event): print 'expose' cr = self.window.cairo_create() cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) cr.clip() self.draw(cr, *self.window.get_size()) def draw(self, cr, width, height): print 'draw', width, height cr.set_source_rgb(0.7, 0.7, 0.7) cr.rectangle(0, 0, width, height) cr.fill() for U in self.Units: sx = width/maxX-10 sy = height/maxY-10 dx = U.X*width/maxX+5 dy = U.Y*height/maxY+5 cr.translate(dx, dy) cr.scale(sx, sy) U.draw(cr) cr.scale(1.0/sx, 1.0/sy) cr.translate(-dx, -dy) def drawunit(self, U): cr = self.window.cairo_create() width, height = self.window.get_size() sx = width/maxX-10 sy = height/maxY-10 dx = U.X*width/maxX+5 dy = U.Y*height/maxY+5 cr.translate(dx, dy) cr.scale(sx, sy) U.draw(cr) def idle(self): try: message = self.socket.recv(1500) except socket.timeout: return 1 if message[0] != '<': return 1 p = Parser() p.feed(message) info = p.getinfo() p.close() if info.ok: for U in self.Units: if U.name == info.mk5: U.state = info U.color = (0, 1, 0) self.drawunit(U) print info.mk5 return 1 def run(Widget): window = gtk.Window() window.connect("delete-event", gtk.main_quit) window.set_default_size(800, 350) widget = Widget() widget.init() widget.show() window.add(widget) window.present() gtk.idle_add(widget.idle) gtk.main() run(Mark5s)