Example #1
0
 def set_elapsed(self):
     """Update elapsed time in race ui and announcer."""
     self.curelap = None
     if self.start is not None and self.finish is not None:
         et = self.finish - self.start
         self.time_lbl.set_text(et.timestr(2))
         self.curelap = et
         msg = unt4.unt4(header=unichr(unt4.DC3) + u'N F$',
                         xx=0,
                         yy=0,
                         text=et.timestr(2)[0:12])
         self.meet.udptimer.sendto(msg.pack(), (self.meet.udpaddr, 6789))
     elif self.start is not None:  # Note: uses 'local start' for RT
         runtm = (tod.tod('now') - self.lstart).timestr(1)
         ## UDP hack
         msg = unt4.unt4(header=unichr(unt4.DC3) + u'R F$',
                         xx=0,
                         yy=0,
                         text=runtm[0:12])
         self.meet.udptimer.sendto(msg.pack(), (self.meet.udpaddr, 6789))
         self.time_lbl.set_text(runtm)
     elif self.timerstat == 'armstart':
         self.time_lbl.set_text(tod.tod(0).timestr(1))
     else:
         self.time_lbl.set_text('')
Example #2
0
    def timeout(self, data=None):
        """Handle timeout."""

        # 1: Terminate?
        if not self.running:
            return False

        # 2: Process?
        try:
            ntime = tod.tod(u'now')
            ntod = ntime.truncate(0)
            if ntime >= self.nc.truncate(1):
                self.tod = ntod
                self.nc += tod.ONE
                self.process_timeout()
            else:
                self.log.debug(u'Timeout called early: ' + ntime.rawtime())
                # no need to advance, desired timeout not yet reached
        except Exception as e:
            self.log.error(u'Timeout: ' + unicode(e))

        # 3: Re-Schedule
        tt = tod.tod(u'now')+tod.tod(u'0.01')
        while self.nc < tt:	# ensure interval is positive
            if tod.MAX - tt < tod.ONE:
                self.log.debug(u'Midnight rollover.')
                break
            self.log.debug(u'May have missed an interval, catching up.')
            self.nc += tod.ONE	# 0.01 allows for processing delay
        ival = int(1000.0 * float((self.nc - tod.tod(u'now')).timeval))
        glib.timeout_add(ival, self.timeout)

        # 4: Return False
        return False	# must return False
Example #3
0
    def __init__(self):
        # logger and handler
        self.log = logging.getLogger()
        self.log.setLevel(logging.DEBUG)
        self.loghandler = logging.FileHandler(LOGFILE)
        self.loghandler.setLevel(logging.DEBUG)
        self.loghandler.setFormatter(logging.Formatter(
                       '%(asctime)s %(levelname)s:%(name)s: %(message)s'))
        self.log.addHandler(self.loghandler)
        self.log.info(u'IRTT Starter - Init.')

        # require one timy and one uscbsrv
        self.timer = timy.timy()
        self.scb = telegraph.telegraph()

        self.started = False
        self.running = True

        # Audio output
        self.player = gst.element_factory_make("playbin2", "player")
        self.player.set_property("audio-sink",
                         gst.element_factory_make("alsasink", "sink"))
        self.player.set_property("video-sink",
                         gst.element_factory_make("fakesink", "fakesink"))
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.connect("message", self.gst_message)
        self.player.set_property('uri', u'file://'
                             + os.path.join(metarace.DB_PATH, u'start.wav'))

        # variables
        self.armed = False
        self.width = 0
        self.height = 0
        self.backlight = 0.0
        self.backlightmax = 20
        self.backlightdev = None
        self.backlightlow = 0.25
        self.backlighthigh = 1.0
        self.syncthresh = 100000000
        self.tod = tod.tod(u'now').truncate(0)
        self.nc = self.tod + tod.tod(u'1.22') # set interval a little off mark
        self.countdown = None
        self.riderstr = None
        self.bulb = None
        self.currider = None
        self.ridermap = {}
        self.window = gtk.Window()
        self.window.set_title(u'Start Clock')
        self.window.connect('destroy', self.window_destroy_cb)
        self.area_src = None
        self.area = gtk.DrawingArea()
        self.area.connect('configure_event', self.area_configure_event_cb)
        self.area.connect('expose_event', self.area_expose_event_cb)
        self.area.set_size_request(400,220)
        self.area.show()
        self.window.add(self.area)
        self.log.info(u'Starting clock intervals at: ' + self.nc.rawtime(3))
        glib.timeout_add(2000, self.timeout)
        glib.timeout_add_seconds(5, self.delayed_cursor)
Example #4
0
    def __init__(self, configpath=None):
        """App constructor."""
        # logger and log handler
        self.log = logging.getLogger()
        self.log.setLevel(logging.DEBUG)
        self.loghandler = None  # set in loadconfig to meet dir

        # meet configuration path and options
        if configpath is None:
            configpath = u'.'  # None assumes 'current dir'
        self.configpath = configpath
        self.loglevel = logging.INFO  # UI log window

        # hardware connections
        self.remote = telegraph.telegraph()
        self.remoteuser = u''  # match against remote nick
        self.remoteport = u''  # only connect if requested
        self.remotechan = u'#announce'
        self.remote.set_pub_cb(self.remote_cb)
        self.port = u''  # re-set in loadconfig
        self.scb = None
        self.remote_enable = True
        self.obuf = []  # current output buffer
        for j in range(0, 2):
            self.obuf.append(u''.ljust(10))

        self.set_remote_enable()

        # run state
        self.running = True
        self.started = False
        self.tod = tod.tod(u'now').truncate(0)
        self.nc = self.tod + tod.tod(u'1.22')  # set interval a little off mark
        self.maxlaptime = tod.tod('2:00')  # default maximum lap time

        # animation variables
        self.ttrank = None
        self.ttno = None
        self.ttname = None
        self.ttcat = None
        self.tttime = None
        self.elapstart = None
        self.elapfin = None
        self.timerstat = u'running'  # default assume run state
        self.timelimit = None
        self.distance = None
        self.lapfin = None
        self.timeofday = True  # show timeofday on bottom line?
        self.failcount = 0
        self.failthresh = 30  # connect timeout ~30sec

        # start timer
        self.log.debug(u'Starting clock intervals at: ' + self.nc.rawtime(3))
        glib.timeout_add(2000, self.timeout)
Example #5
0
    def __init__(self, port=None, name='rru'):
        """Construct thread object.

        Named parameters:

          port -- serial port
          name -- text identifier for use in log messages

        """
        threading.Thread.__init__(self)
        self.name = name
        self.port = None
        self.looppower = 20
        self.loopid = 1
        self.unitno = u'rru'
        self.loopchannel = 2
        self.lastsync = tod.tod(u'now')
        self.lastts = 0
        self.error = False
        self.errstr = ''
        self.cqueue = Queue.Queue()  # command queue
        self.log = logging.getLogger(self.name)
        self.log.setLevel(logging.DEBUG)
        self.__rdbuf = ''
        self.setcb()
        if port is not None:
            self.setport(port)
Example #6
0
 def starttrig(self, e):
     """React to start trigger."""
     if self.timerstat == 'armstart':
         self.start = e
         self.lstart = tod.tod('now')
         self.setrunning()
         glib.timeout_add_seconds(4, self.armfinish)
Example #7
0
 def clearplaces(self):
     """Zero internal model for recalculate."""
     for r in self.riders:
         r[COL_PLACE] = ''
         r[COL_TOTAL] = 0
         r[COL_TIME] = tod.tod(0)
         r[COL_POINTS] = []
Example #8
0
 def __command(self, m):
     """Process a command out of the command queue."""
     if type(m) is tuple and type(m[0]) is str:
         if m[0] == 'WRITE':
             if len(m) == 3:
                 self.__write(m[1], m[2])
         elif m[0] == 'PASSING':
             if len(m) == 3:
                 if self.__cb is not None:
                     self.__cb(m[2], m[1], self.__cbdata)
                 else:
                     self.log.info(u'PASS: '******' :: '
                                    + m[2])
         elif m[0] == 'STATUSACK':
             if len(m) == 3:
                 if self.__statuscb is not None:
                     self.__statuscb(m[2], m[1], self.__cbdata)
                 else:
                     self.log.debug(u'STATUS: ' + unicode(m[1]) + u' :: '
                                    + m[2])
         elif m[0] == 'SYNC':
             # broadcast or direct a rough sync command
             dst = self.broadcast
             if m[1] is not None:
                 dst = m[1]
             t = tod.tod('now')
             while t-t.truncate(0) > tod.tod('0.02'):
                 t = tod.tod('now')
             self.__write(self.__set_time_cmd(t), dst)
         elif m[0] == 'ALLSTAT':
             self.__write(STATCMD, self.broadcast)
         elif m[0] == 'IPCONFIG':
             if len(m) == 3:
                 self.__ipconfigset(m[1], m[2])
         elif m[0] == 'CONFIG':
             if len(m) == 3:
                 self.__configset(m[1], m[2])
         elif m[0] == 'ADD':
             if len(m) == 3:
                 self.__add(m[1], m[2])
         elif m[0] == 'REMOVE':
             if len(m) == 2:
                 self.__remove(m[1])
         else:
             pass
     else:
         self.log.warn(u'Unknown command: ' + repr(m))
Example #9
0
    def append_rider(self, msg):
        sr = msg.split(chr(unt4.US))
        if len(sr) == 5:
            rftime = tod.str2tod(sr[4])
            if rftime is not None:
                if len(self.riders) == 0:
                    # Case 1: Starting a new lap
                    if self.lapfin is not None:
                        self.cur_split = self.lapfin
                    else:
                        self.cur_split = rftime
                    if self.lapstart is not None:
                        self.cur_lap = (self.cur_split -
                                        self.lapstart).truncate(0)
                    elif self.elapstart:  # no lap start?
                        self.cur_lap = (self.cur_split -
                                        self.elapstart).truncate(0)
                    else:
                        self.cur_lap = self.cur_split.truncate(0)
                    if self.final:
                        # overwrite cur split for down times
                        self.cur_split = rftime  # check if down from here?
                        self.cur_lap = rftime
                    self.cur_bunchid = 0
                    self.cur_bunchcnt = 1
                    self.last_time = rftime
                    nr = [
                        sr[0], sr[1], sr[2], sr[3],
                        self.cur_lap.rawtime(0), self.cur_bunchcnt,
                        COLOURMAP[self.cur_bunchid][0], rftime
                    ]
                elif rftime < self.last_time or rftime - self.last_time < tod.tod(
                        '5.0'):
                    # Case 2: Same bunch
                    self.last_time = rftime
                    self.cur_bunchcnt += 1
                    nr = [
                        sr[0], sr[1], sr[2], sr[3], '', self.cur_bunchcnt,
                        COLOURMAP[self.cur_bunchid][0], rftime
                    ]
                else:
                    # Case 3: New bunch
                    self.riders.append(
                        ['', '', '', '', '', '', '#fefefe', None])
                    self.cur_bunchid = (self.cur_bunchid + 1) % COLOURMAPLEN
                    self.cur_bunchcnt = 1
                    self.last_time = rftime
                    nr = [
                        sr[0], sr[1], sr[2], sr[3],
                        '+' + (rftime - self.cur_split).rawtime(0),
                        self.cur_bunchcnt, COLOURMAP[self.cur_bunchid][0],
                        rftime
                    ]
            else:
                # Informative non-timeline record
                nr = [sr[0], sr[1], sr[2], sr[3], '', '', '#fefefe', None]

            self.riders.append(nr)
            self.redraw_flag = True
Example #10
0
    def process_timeout(self):
        """Perform required timeout activities."""
        estr = u''
        dstr = u''
        if self.elapstart is not None:
            if self.elapfin is not None:
                # Race over - show elap and down if poss
                estr = (self.elapfin - self.elapstart).rawtime(0)
                if self.timerstat != u'finished':
                    if self.tod > self.elapfin:
                        dstr = u'+' + (self.tod - self.elapfin).rawtime(0)
            else:
                # race in progress, show run time and distance or lap
                elap = self.tod - (self.elapstart + tod.tod('0.2'))
                if elap > tod.MAXELAP:
                    elap = tod.ZERO
                estr = elap.rawtime(0)
                if self.distance is not None and self.distance > 0.5:
                    dstr = u'~{0:1.1f}km'.format(self.distance)
                if self.lapfin is not None:
                    # lap down time overwrites dist, but only if valid
                    laptm = self.tod - self.lapfin
                    if laptm < self.maxlaptime:
                        dstr = u'+' + laptm.rawtime(0)
        self.elap_lbl.set_text(estr)
        self.gap_lbl.set_text(dstr)

        #if self.timerstat == 'running' and self.laplbl:
        #tmsg = u''
        #if self.finstr:
        #tmsg = self.finstr + u' '
        ## add lap and sprint info
        #tmsg += self.laplbl
        #if self.laptype:
        #tmsg += u' - ' + self.laptype
        #self.lbl_header.set_text(tmsg)
        #else:
        if True:  # always show the title_str, it now has better info
            if self.title_str:
                self.lbl_header.set_text(self.title_str)

        if self.redraw_flag:
            self.redraw_flag = False
            self.map_redraw()  # update src map
            self.track_redraw()  # update src map
            self.map_area.queue_draw()  # queue copy to screen
            self.track_area.queue_draw()  # queue copy to screen

        # check connection status
        if not self.io.connected():
            self.failcount += 1
            if self.failcount > self.failthresh:
                self.io.set_portstr(force=True)
                self.failcount = 0
            self.log.debug(u'Telegraph connection failed, count = ' +
                           repr(self.failcount))
        else:
            self.failcount = 0
Example #11
0
    def draw_ridermap(self, cr):
        width = self.map_winsz
        height = 80
        cr.identity_matrix()

        # bg filled
        cr.set_source_rgb(0.85, 0.85, 0.9)
        cr.paint()

        # scale: | . . . . i . . . . | . . .
        cr.set_line_width(1.0)
        cr.set_font_size(15.0)
        xof = 0
        dw = width - (2 * MAPHMARGIN)
        dh = height - (2 * MAPVMARGIN)
        cnt = 0
        while xof < dw:
            lh = 4
            if cnt % 10 == 0:
                lh = 12
                cr.set_source_rgb(0.05, 0.05, 0.05)
                cr.move_to(xof + MAPHMARGIN + 1, MAPVMARGIN + dh - lh - 2)
                cr.show_text(tod.tod(int(cnt)).rawtime(0))
            elif cnt % 5 == 0:
                lh = 8
            cr.set_source_rgb(0.05, 0.05, 0.05)
            cr.move_to(xof + MAPHMARGIN, MAPVMARGIN + dh - lh)
            cr.line_to(xof + MAPHMARGIN, MAPVMARGIN + dh)
            cr.stroke()
            if cnt % 5 == 0:
                cr.set_source_rgb(0.96, 0.96, 0.96)
                cr.move_to(xof + MAPHMARGIN, MAPVMARGIN)
                cr.line_to(xof + MAPHMARGIN, MAPVMARGIN + dh - lh - 2)
                cr.stroke()
            cnt += 1
            xof += self.timetick

        cr.set_line_width(2.0)
        inbox = False
        cnt = 0
        st = None
        x1 = None
        x2 = None
        for r in self.riders:
            if r[7] is not None:  # have a row
                if st is None:
                    st = r[7].truncate(0)  # save lap split
                if not inbox:
                    x1 = r[7].truncate(0) - st
                    inbox = True
                x2 = r[7] - st
            else:  # have a break
                if inbox:
                    self.do_bubble(cr, cnt, x1, x2)
                    cnt += 1
                inbox = False
        if inbox:
            self.do_bubble(cr, cnt, x1, x2)
Example #12
0
 def procmsg(self, msg):
     """Read IPX wheeltime event and insert as tod into command queue."""
     s = msg.strip()
     if (len(s) == 36 or len(s) == 38) and s[1] == 'a':
         sum = ipico_lrc(s)
         lrc = int(s[34:36], 16)
         if sum == lrc:
             #tagid=s[4:16]	## NOTE: Using 'shortform' tag ids
             if s[4:10] == TAGPREFIX:	# match id prefix
                 tagid=(s[10:16]).lower()
                 timestr = '{0}:{1}:{2}.{3:02}'.format(s[26:28], s[28:30],
                                s[30:32], int(s[32:34], 16))
                 istr = '00:0'	# emulate THbC info, but zero for WT
                 chanstr = 'BOX'
                 t = tod.tod(timestr, index=istr, chan=chanstr,
                                      refid=tagid, source=self.srcid)
                 if self.cb is not None:
                     glib.idle_add(self.cb, t)
                 self.cqueue.put_nowait(('RFID', t))	# notify only now
             else:
                 self.log.warn('Spurious tag id: ' + s[4:10] + ' :: ' 
                                 + s[10:16])
         else:
             self.log.warn('Incorrect char sum message skipped: ' 
                            + hex(sum) + ' != ' + hex(lrc))
     elif len(s) == 30 and s[0:8] == 'ab010a2c':
         # Process a trigger event
         sum = ipico_lrc(s, 28)
         lrc = int(s[28:30], 16)
         if sum == lrc:
             timestr = '{0}:{1}:{2}.{3:02}'.format(s[16:18], s[18:20],
                            s[20:22], int(s[22:24], 16))
             istr = '00:0'
             chanstr = 'MAN'
             tagid = ''	# emulate THbC manual trigger (lstripped)
             t = tod.tod(timestr, index=istr, chan=chanstr,
                                  refid=tagid, source=self.srcid)
             if self.cb is not None:
                 glib.idle_add(self.cb, t)
             self.cqueue.put_nowait(('RFID', t))	# notify only now
         else:
             self.log.warn('Incorrect char sum message skipped: ' 
                            + hex(sum) + ' != ' + hex(lrc))
     else:
         self.log.debug('Non RFID message: ' + repr(msg))
Example #13
0
 def addrider(self, bib='', info=None):
     """Add specified rider to race model."""
     nr = [bib, '', '', '', '', 0, tod.tod(0), '', []]
     if bib == '' or self.getrider(bib) is None:
         dbr = self.meet.rdb.getrider(bib, self.series)
         if dbr is not None:
             for i in range(1, 5):
                 nr[i] = self.meet.rdb.getvalue(dbr, i)
         return self.riders.append(nr)
     else:
         return None
Example #14
0
def get_dateline(width=32):
    dpart = time.strftime(DATE_FMT)
    tpart = tod.tod('now').meridian()
    ret = tpart
    totlen = len(tpart) + len(dpart)
    if totlen >= width:  # with a space
        ret = tpart.center(width)  # fall back to time
    else:
        ret = dpart + u' ' * (width - totlen) + tpart

    return ret
Example #15
0
    def toload(self, bib=None):
        """Load timer."""
        self.status = 'load'
        self.starttod = None
        self.recovtod = tod.tod(0)
        self.finishtod = None
        self.set_time()
	self.lap = 0
        self.set_lap()
        self.splits = []
        if bib is not None:
            self.setrider(bib)
        uiutil.buttonchg(self.b, uiutil.bg_none, 'Ready')
Example #16
0
    def timeout(self):
        """Update status."""
        # 1: Terminate?
        if not self.running:
            return False
        # 2: Process?
        try:
            ntime = tod.tod(u'now')
            ntod = ntime.truncate(0)
            if ntime >= self.nc.truncate(1):
                self.tod = ntod
                self.process_timeout()
                # and advance one second
                self.nc += tod.ONE
            else:
                self.log.debug(u'Timeout called early: ' + ntime.rawtime())
                # no need to advance, desired timeout not yet reached
        except Exception as e:
            self.log.error(u'Timeout: ' + repr(e))

        # 3: Re-Schedule
        tt = tod.tod(u'now') + tod.tod(u'0.01')
        count = 0
        while self.nc < tt:  # ensure interval is positive
            if tod.MAX - tt < tod.ONE:
                self.log.debug(u'Midnight rollover.')
                break
            self.log.debug(u'May have missed an interval, catching up.')
            self.nc += tod.ONE  # 0.01 allows for processing delay
            count += 1
            if count > 10:
                break
        ival = int(1000.0 * float((self.nc - tod.tod(u'now')).timeval))
        if ival < 0 or ival > 10000:
            ival = 1000  # assume host time change
        glib.timeout_add(ival, self.timeout)

        # 4: Return False
        return False  # must return False
Example #17
0
    def spfin_info_time_edit_activate_cb(self, button):
        """Display contest timing edit dialog."""
        ostx = ''
        oftx = ''
        if self.start is not None:
            ostx = self.start.rawtime(4)
        else:
            ostx = '0.0'
        if self.finish is not None:
            oftx = self.finish.rawtime(4)
        ret = uiutil.edit_times_dlg(self.meet.window, ostx, oftx)
        if ret[0] == 1:
            try:
                stod = None
                if ret[1]:
                    stod = tod.tod(ret[1], 'MANU', 'C0i')
                    self.meet.timer.printline(' ' + str(stod))
                ftod = None
                if ret[2]:
                    ftod = tod.tod(ret[2], 'MANU', 'C1i')
                    self.meet.timer.printline(' ' + str(ftod))
                self.set_start(stod)
                self.set_finish(ftod)
                self.set_elapsed()
                cid = ''
                i = self.current_contest_combo.get_active_iter()
                if i is not None:  # contest selected ok
                    cid = self.contests.get_value(i, COL_CONTEST)
                    self.contests.set_value(i, COL_200M, self.curelap)
                if self.start is not None and self.finish is not None:
                    self.log_elapsed(cid)
                self.log.info('Updated race times.')
            except Exception as v:
                self.log.error('Error updating times: ' + str(v))

            glib.idle_add(self.delayed_announce)
        else:
            self.log.info('Edit race times cancelled.')
Example #18
0
    def trig(self, timeval='now', index='FAKE', chan='MAN',
                   refid='0', sourceid=None):
        """Create a fake timing event.

           Generate a new tod object to mimic a message as requested
           and pipe it to the command thread. Default tod is the
           'now' time in the calling thread.

        """
        src=self.name
        if sourceid is not None:
           src=sourceid
        t = tod.tod(timeval, index, chan, refid.lstrip('0'), source=src)
        self.cqueue.put_nowait(('TRIG', t))
Example #19
0
 def current_contest_combo_changed_cb(self, combo, data=None):
     """Copy elapsed time into timer (dodgey)."""
     self.resettimer()
     i = self.current_contest_combo.get_active_iter()
     if i is not None:  # contest selected ok
         ft = self.contests.get_value(i, COL_200M)
         if ft is not None:
             self.start = tod.tod(0)
             self.finish = ft
             self.set_elapsed()
         else:
             self.start = None
             self.finish = None
             self.set_elapsed()
         winner = self.contests.get_value(i, COL_WINNER)
         self.ctrl_winner.set_text(winner)
Example #20
0
    def toidle(self):
        """Set timer state to idle."""
        self.status = 'idle'
        self.bib = None
        self.bibent.set_text('')
        self.bibent.set_sensitive(True)
        self.serent.set_sensitive(True)
        self.biblbl.set_text('')
        self.starttod = None
        self.recovtod = tod.tod(0)
        self.finishtod = None
	self.lap = 0
        self.set_lap()
        self.splits = []
        self.set_time()
        uiutil.buttonchg(self.b, uiutil.bg_none, 'Idle')
Example #21
0
    def tstotod(self, ts):
        """Convert a race result timestamp to time of day."""
        ret = None
        try:
            # get offset from last sync beacon in device units
            ti = int(ts) - self.lastts

            # convert offset to seconds
            tsec = decimal.Decimal(ti // 256) + decimal.Decimal(ti % 256) / 256

            # create a new time of day object, truncated to thous
            ntv = self.lastsync.timeval + tsec
            ret = tod.tod(ntv).truncate(3)
        except Exception as e:
            self.log.debug(u'Error converting Ts: ' + repr(e))
        return ret
Example #22
0
 def starttrig(self, e):
     """Process a trigger."""
     chan = timy.chan2id(e.chan)
     if (chan == timy.CHAN_START and self.armed
         and self.currider is not None and self.currider in self.ridermap):
         ls = tod.tod(u'now')# log the 'now' time and the rider's wall start
         # emit rider vec
         cr = self.ridermap[self.currider]
         self.scb.add_rider([cr[1], cr[2], e.rawtime(),
                             cr[0].rawtime(), ls.rawtime()], u'starter')
         self.log.info(u'Starter: ' + u','.join([cr[1], e.rawtime()]))
         self.armed = False
     else:
         # emit an anon tod
         self.log.info(u'Impulse: ' + e.rawtime())
         self.scb.add_rider([u'Impulse: ' + unicode(e)], u'message')
     return False
Example #23
0
    def run(self):
        """Called via threading.Thread.start()."""
        running = True
        self.log.debug('Starting')
        while running:
            try:
                # Read phase
                if self.port is not None:
                    try:
                        self.__read()
                    except socket.timeout:
                        pass
                    m = self.cqueue.get_nowait()
                else:
                    # when no read port avail, block on read of command queue
                    m = self.cqueue.get()
                self.cqueue.task_done()

                # Write phase
                if type(m) is tuple and type(m[0]) is str and m[0] in TCMDS:
                    if m[0] == 'MSG' and self.port and not self.error:
                        cmd = m[1]  ##+ '\r\n'
                        self.log.debug('Sending rawmsg ' + repr(cmd))
                        self.port.write(cmd)
                    elif m[0] == 'TRIG':
                        if type(m[1]) is tod.tod:
                            self.log.log(RFID_LOG_LEVEL, str(m[1]))
                            glib.idle_add(self.__cb,
                                          m[1],
                                          priority=THBC_PRIORITY)
                    elif m[0] == 'SANE':
                        self.log.debug('Checking config.')
                        self.__sane()
                    elif m[0] == 'IPCFG':
                        self.log.debug('Updating Decoder IP.')
                        self.__ipcfg()
                    elif m[0] == 'SYNC':
                        t = tod.tod('now')
                        # DANGER: Busy wait may interfere with caller
                        while t - t.truncate(0) > tod.tod('0.02'):
                            t = tod.tod('now')
                        self.port.write(self.__set_time_cmd(t))
                        self.log.debug('Set time on decoder: ' + t.meridian())
                    elif m[0] == 'REPL':
                        self.log.info('Replay passings from: ' + repr(m[1]))
                        with open(m[1], 'rb') as f:
                            for l in f:
                                self.__readline(l)
                        self.log.info('Replay complete.')
                    elif m[0] == 'EXIT':
                        self.log.debug('Request to close : ' + str(m[1]))
                        running = False  # This may already be set
                    elif m[0] == 'PORT':
                        if self.port is not None:
                            self.port.close()
                            self.port = None
                        if m[1] is not None and m[1] != '' and m[1] != 'NULL':
                            self.log.debug('Re-Connect port : ' + str(m[1]))
                            self.port = self.__mkport(m[1])
                            self.error = False
                            self.unitno = u''
                            self.port.write(QUECMD)  # re-identify decoder
                        else:
                            self.log.debug('Not connected.')
                            self.error = True
                    else:
                        pass
                else:
                    self.log.warn(u'Unknown message: ' + repr(m))
            except Queue.Empty:
                pass
            except serial.SerialException as e:
                if self.port is not None:
                    self.port.close()
                    self.port = None
                self.errstr = 'Serial Port error.'
                self.error = True
                self.log.error('Closed port: ' + str(type(e)) + str(e))
            except socket.error as e:
                self.log.error('Network error: ' + str(type(e)) + str(e))
            except Exception as e:
                self.log.error('Exception: ' + str(type(e)) + str(e))
                raise
                #self.errstr = str(e)
                #self.error = True
        if self.port is not None:
            self.port.close()
            self.port = None
        self.setcb()  # make sure callback is unrefed
        self.log.info('Exiting')
Example #24
0
    def __init__(self, configpath=None):
        # logger and log handler
        self.log = logging.getLogger()
        self.log.setLevel(logging.DEBUG)
        self.loghandler = None  # set in loadconfig to meet dir

        # meet configuration path and options
        if configpath is None:
            configpath = u'.'   # None assumes 'current dir'
        self.configpath = configpath
        self.loglevel = logging.INFO    # UI log window

        self.io = telegraph.telegraph()
        self.io.set_pub_cb(self.msg_cb)
        self.started = False
        self.running = True

        self.fontsize = FONTSIZE
        fnszstr = str(self.fontsize)+'px'
        self.font = pango.FontDescription(FONTFACE + ' ' + fnszstr)

        b = gtk.Builder()
        b.add_from_file(os.path.join(metarace.UI_PATH, 'irtt_announce.ui'))
        self.window = b.get_object('window')

        self.lbl_header = b.get_object('lbl_header')
        self.lbl_header.modify_font(self.font)
        self.lbl_header.set_text('metarace irtt announce ' + metarace.VERSION)
        self.elap_lbl = b.get_object('elap_lbl')
        self.elap_lbl.set_text('--:--')
        self.elap_lbl.modify_font(self.font)

        b.get_object('fin_pfx_lbl').modify_font(self.font)
        self.fin_label = b.get_object('fin_pfx_lbl')
        self.fin_label.modify_font(self.font)
        self.fin_rank = b.get_object('fin_rank_lbl')
        self.fin_rank.modify_font(self.font)
        self.fin_rider = b.get_object('fin_rider_lbl')
        self.fin_rider.modify_font(self.font)
        self.fin_time = b.get_object('fin_time_lbl')
        self.fin_time.modify_font(self.font)

        b.get_object('int_pfx_lbl').modify_font(self.font)
        self.int_label = b.get_object('int_pfx_lbl')
        self.int_label.modify_font(self.font)
        self.int_rank = b.get_object('int_rank_lbl')
        self.int_rank.modify_font(self.font)
        self.int_rider = b.get_object('int_rider_lbl')
        self.int_rider.modify_font(self.font)
        self.int_time = b.get_object('int_time_lbl')
        self.int_time.modify_font(self.font)

        self.fin_box = b.get_object('fin_box')	# seems to work?
        self.fin_box.hide()

        #self.map_winsz = 0
        #self.map_xoft = 0
        #self.map_w = 0
        #self.map_area = b.get_object('map_area')
        #self.map_src = None
        #self.map_area.set_size_request(-1, 80)
        #self.map_area.show()

        # lap & bunch status values
        self.cur_lap = tod.tod(0)
        self.cur_split = tod.tod(0)
        self.cur_bunchid = 0
        self.cur_bunchcnt = 0

        self.riders = gtk.ListStore(gobject.TYPE_STRING,  # rank
                                    gobject.TYPE_STRING,  # no.
                                    gobject.TYPE_STRING,  # namestr
                                    gobject.TYPE_STRING,  # cat/com
                                    gobject.TYPE_STRING,  # timestr
                                    gobject.TYPE_STRING,  # downtime
                                    gobject.TYPE_PYOBJECT) # rftod

        self.inters = gtk.ListStore(gobject.TYPE_STRING,  # rank
                                    gobject.TYPE_STRING,  # no.
                                    gobject.TYPE_STRING,  # namestr
                                    gobject.TYPE_STRING,  # turn
                                    gobject.TYPE_STRING,  # eta
                                    gobject.TYPE_STRING,  # speed
                                    gobject.TYPE_PYOBJECT) # rftod
        t = gtk.TreeView(self.riders)
        self.view = t
        t.set_reorderable(False)
        t.set_rules_hint(True)
        t.set_headers_visible(False)
        self.search_lbl = b.get_object('search_lbl')
        self.search_lbl.modify_font(self.font)
        self.search_entry = b.get_object('search_entry')
        self.search_entry.modify_font(self.font)
        t.set_search_entry(b.get_object('search_entry'))
        t.set_search_column(1)
        t.modify_font(self.font)
        uiutil.mkviewcoltxt(t, 'Rank', 0,width=40)
        uiutil.mkviewcoltxt(t, 'No.', 1,calign=1.0,width=40)
        uiutil.mkviewcoltxt(t, 'Rider', 2,expand=True,fixed=True)
        uiutil.mkviewcoltxt(t, 'Cat', 3,calign=0.0)
        uiutil.mkviewcoltxt(t, 'Time', 4,calign=1.0,width=100)
        uiutil.mkviewcoltxt(t, 'Gap', 5,calign=1.0,width=90)
        # "down" time?
        #uiutil.mkviewcoltxt(t, 'Bunch', 5,width=50,bgcol=6,calign=0.5)
        b.get_object('text_scroll').add(t)
        t.show()
        t.grab_focus()

        ## let's suppress the arrivals for now
        ##b.get_object('arrival_xpnd').hide()
        t = gtk.TreeView(self.inters)
        self.iview = t
        t.set_reorderable(False)
        t.set_rules_hint(True)
        t.set_headers_visible(False)
        t.modify_font(self.font)
        uiutil.mkviewcoltxt(t, '', 0,width=40)
        uiutil.mkviewcoltxt(t, 'No.', 1,calign=1.0,width=40)
        uiutil.mkviewcoltxt(t, 'Rider', 2,expand=True,fixed=True)
        uiutil.mkviewcoltxt(t, 'Turn', 3,calign=0.0)
        uiutil.mkviewcoltxt(t, 'Time', 4,calign=1.0,width=100)
        uiutil.mkviewcoltxt(t, 'Avg', 5,calign=1.0,width=90)
        t.show()
        b.get_object('arrival_scroll').add(t)
        b.connect_signals(self)
Example #25
0
from metarace import tod
from metarace import telegraph
from metarace import unt4  ## todo remove
from metarace import strops

LOGHANDLER_LEVEL = logging.DEBUG
CONFIGFILE = u'voladisp.json'
LOGFILE = u'voladisp.log'
APP_ID = u'voladisp_1.0'  # configuration versioning
ENCODING = 'iso8859-15'
VOLA_BAUD = 9600

STX = 0x02
LF = 0x0a
BRIGHTVALS = [0x31, 0x32, 0x33]
ELAPOFT = tod.tod('0.05')


class voladisp:
    """VOLA Display control console application."""
    def quit_cb(self, menuitem, data=None):
        """Quit the application."""
        self.running = False

    def uscb_activate_cb(self, menuitem, data=None):
        """Request a re-connect to the uSCBsrv IRC connection."""
        if self.uscbport:
            self.log.info(u'Requesting re-connect to announcer: ' +
                          repr(self.uscbport) + repr(self.uscbchan))
        else:
            self.log.info(u'Announcer not configured.')
Example #26
0
    def run(self):
        """Called via threading.Thread.start()."""
        running = True
        self.log.debug('Starting')
        while running:
            try:
                # Read phase
                if self.port is not None:
                    try:
                        self.__read()
                    except Exception as e:
                        self.log.debug(u'EXCEPT timeout: ' + repr(e))
                    m = self.cqueue.get_nowait()
                else:
                    # when no read port avail, block on read of command queue
                    m = self.cqueue.get()
                self.cqueue.task_done()

                # Write phase
                if type(m) is tuple and type(m[0]) is str and m[0] in TCMDS:
                    if m[0] == 'MSG' and self.port and not self.error:
                        cmd = m[1] + '\n'
                        self.log.debug('Sending rawmsg ' + repr(cmd))
                        self.port.write(cmd)
                    elif m[0] == 'TRIG':
                        if type(m[1]) is tod.tod:
                            self.log.log(RFID_LOG_LEVEL, str(m[1]))
                            glib.idle_add(self.__cb,
                                          m[1],
                                          priority=RRU_PRIORITY)
                    elif m[0] == 'SANE':
                        self.log.debug('Checking config.')
                        self.__sane()
                    elif m[0] == 'SYNC':
                        # not the assumption is that 'now' is close to the
                        # time that the Unit processses the message. It
                        # should not then matter how long it takes to get
                        # the reply, we capture the reference time here.
                        self.port.write('GETTIMESTAMP\n')
                        self.lastsync = tod.tod('now')
                        self.lastts = 0  # error passings in transition
                    elif m[0] == 'REPL':
                        self.log.info('Replay passings from: ' + repr(m[1]))
                        with open(m[1], 'rb') as f:
                            for l in f:
                                self.__readline(l)
                        self.log.info('Replay complete.')
                    elif m[0] == 'EXIT':
                        self.log.debug('Request to close : ' + str(m[1]))
                        running = False  # This may already be set
                    elif m[0] == 'PORT':
                        if self.port is not None:
                            self.port.close()
                            self.port = None
                        if m[1] is not None and m[1] != '' and m[1] != 'NULL':
                            self.log.debug('Re-Connect port : ' + str(m[1]))
                            self.port = self.__mkport(m[1])
                            self.error = False
                        else:
                            self.log.debug('Not connected.')
                            self.error = True
                    else:
                        pass
                else:
                    self.log.warn(u'Unknown message: ' + repr(m))
            except Queue.Empty:
                pass
            except serial.SerialException as e:
                if self.port is not None:
                    self.port.close()
                    self.port = None
                self.errstr = 'Serial Port error.'
                self.error = True
                self.log.error('Closed port: ' + str(type(e)) + str(e))
            except Exception as e:
                self.log.error('Exception: ' + str(type(e)) + str(e))
                raise
                #self.errstr = str(e)
                #self.error = True
        if self.port is not None:
            self.port.close()
            self.port = None
        self.setcb()  # make sure callback is unrefed
        self.log.info('Exiting')
Example #27
0
import glib
import time  # for ipcompletion, this is a problem!

import metarace
from metarace import tod

# Serial baudrate
RRU_BAUD = 19200

# GTK Priority for timing message callbacks sent to main loop
RRU_PRIORITY = glib.PRIORITY_HIGH

# Photofinish threshold - ~20cm based on tests at DISC,
# Activator period is ~20ms... with a single active
# loop, all reads within 20ms must be considered same time.
PHOTOTHRESH = tod.tod('0.03')

# thread queue commands -> private to thread
TCMDS = ('EXIT', 'PORT', 'MSG', 'TRIG', 'SYNC', 'SANE', 'REPL')

RFID_LOG_LEVEL = 16  # lower so not in status and on-screen logger.
logging.addLevelName(RFID_LOG_LEVEL, 'RFID')


class rru(threading.Thread):
    """Race Result USB Active thread object class."""
    def __init__(self, port=None, name='rru'):
        """Construct thread object.

        Named parameters:
Example #28
0
    def process_timeout(self):
        """Perform required timeout activities."""
        # Check run state variables iff remote on:
        if self.remote_enable:
            if self.elapstart is not None:
                estr = u''
                dstr = u''
                if self.elapfin is not None:
                    # Race over - show elap and down if poss
                    elap = (self.elapfin - self.elapstart).truncate(0)
                    estr = elap.rawtime(0)
                    if self.timerstat != u'finished':
                        if self.tod > self.elapfin:
                            downtod = self.tod - self.elapfin
                            target = self.maxlaptime
                            if self.timelimit is not None:
                                target = (self.timelimit -
                                          elap) + tod.tod(u'30')
                            if downtod > tod.ZERO:
                                if downtod < target:
                                    #if downtod < target:
                                    dstr = u'+' + downtod.rawtime(0)
                            else:
                                dstr = u'+0'  # prepare for arrival
                        else:
                            dstr = u'+0'  # prepare for arrival
                else:
                    # race in progress, show run time and distance or lap
                    elap = self.tod - (self.elapstart + ELAPOFT)
                    if elap > tod.MAXELAP:
                        elap = tod.ZERO
                    estr = elap.rawtime(0)
                    if self.distance is not None and self.distance > 1.9:
                        dstr = u'{0:1.1f}km'.format(self.distance)
                    if self.lapfin is not None:
                        # lap down time overwrites dist, but only if valid
                        laptm = self.tod - self.lapfin
                        if laptm > tod.ZERO and laptm < self.maxlaptime:
                            dstr = u'+' + laptm.rawtime(0)
                    elif self.timerstat == u'armfinish':
                        dstr = u'+0'
                self.set_left(estr)
                self.set_right(dstr)
            elif self.ttno:
                nostr = u''
                if self.ttno:
                    nostr = self.ttno
                nostr = nostr.rjust(4)
                #nmstr = u''
                #if self.ttname:
                #nmstr = self.ttname
                #nmstr = nmstr.ljust(12)
                #topline = nostr + u' ' + nmstr
                rstr = u''
                if self.ttrank:
                    rstr = u'(' + self.ttrank + u')' + ' '
                rstr = rstr.ljust(6)
                tstr = u''
                if self.tttime:
                    tstr = self.tttime
                    if u'.' not in tstr:
                        tstr += '   '
                tstr = tstr.rjust(10)
                self.set_right(tstr)  # HhMM:SS.DC
                self.set_left(rstr + nostr)  # (rr)  nnn
            elif self.timeofday:
                self.set_left(u'')
                dstr = u''
                if self.distance is not None and self.distance > 1.9:
                    dstr = u'{0:1.1f}km'.format(self.distance)
                else:
                    dstr = self.tod.meridian(secs=False)
                self.set_right(dstr)

        # check connection status
        if not self.remote.connected():
            self.failcount += 1
            if self.failcount > self.failthresh:
                self.remote.set_portstr(force=True)
                self.failcount = 0
            self.log.debug(u'Telegraph connection failed, count = ' +
                           repr(self.failcount))
        else:
            self.failcount = 0
Example #29
0
 def __parse_message(self, msg, ack=True):
     """Return tod object from timing msg or None."""
     ret = None
     if len(msg) > 4:
         if msg[0] == PASSSTART:  # RFID message
             idx = msg.find('>')
             if idx == 37:  # Valid length
                 data = msg[1:33]
                 msum = msg[33:37]
                 tsum = thbc_sum(data)
                 if tsum == msum:  # Valid 'sum'
                     pvec = data.split()
                     istr = pvec[3] + ':' + pvec[5]
                     rstr = pvec[1].lstrip('0')
                     if pvec[5] == '3':  # LOW BATTERY ALERT
                         self.log.warn('Low battery on id: ' + repr(rstr))
                     ret = tod.tod(pvec[2],
                                   index=istr,
                                   chan=pvec[0],
                                   refid=rstr,
                                   source=self.name)
                     self.log.log(RFID_LOG_LEVEL, msg.strip())
                     if ack:
                         self.port.write(ACKCMD)  # Acknowledge if ok
                     self.__cksumerr = 0
                 else:
                     self.log.info('Invalid checksum: ' + repr(tsum) +
                                   ' != ' + repr(msum) + ' :: ' + repr(msg))
                     self.__cksumerr += 1
                     if self.__cksumerr > 3:
                         # assume error on decoder, so acknowledge and
                         # continue with log
                         # NOTE: This path is triggered when serial comms
                         # fail and a tag read happens before a manual trig
                         self.log.error('Erroneous message from decoder.')
                         if ack:
                             self.port.write(ACKCMD)  # Acknowledge if ok
             else:
                 self.log.info('Invalid message: ' + repr(msg))
         elif msg[0] == STATSTART:  # Status message
             data = msg[1:22]
             pvec = data.split()
             if len(pvec) == 5:
                 # Note: this path is not immune to error in stream
                 # but in the case of exception from tod construct
                 # it will be collected by the thread 'main loop'
                 rstr = ':'.join(pvec[1:])
                 ret = tod.tod(pvec[0].rstrip('"'),
                               index='',
                               chan='STS',
                               refid=rstr,
                               source=self.name)
                 self.log.log(RFID_LOG_LEVEL, msg.strip())
             else:
                 self.log.info('Invalid status: ' + repr(msg))
         elif '+++' == msg[0:3] and len(msg) > 53:
             self.__parse_config(msg[3:])
         else:
             self.log.log(RFID_LOG_LEVEL, repr(msg))
     else:
         self.log.info('Short message: ' + repr(msg))
     return ret
Example #30
0
import threading
import Queue
import logging
import socket
import time
import glib

from metarace import tod

# System defaults
TAGPREFIX = '058001'		# Wheeltime rfid prefix
DEFPORT = '192.168.95.32'	# CV wheeltime IP
WHEELRAWPORT = 10000		# TCP Port for raw tag stream
WHEELFSPORT = 10200		# TCP Port for FS/LS filtered stream (normal)
WHEELCMDPORT = 8999		# TCP Wheeltime command port (defunct?)
WHEELPHOTOTHRESH = tod.tod('0.1')	# Wheeltime confidence ~0.1s

# thread queue commands -> private to timy thread
TCMDS = ('RFID', 'EXIT', 'PORT', 'TRIG', 'REPL', 'MSG')

# Logging defaults
RFID_LOG_LEVEL = 16	# lower so not in status and on-screen logger.
logging.addLevelName(RFID_LOG_LEVEL, 'RFID')

adder = lambda sum, ch: sum + ord(ch)

def ipico_lrc(ipxstr='', el=34):
    """Return the so-called 'LRC' character sum from IPX module."""
    return reduce(adder, ipxstr[2:el], 0) & 0xff

def sendall(s, buf):