1 #!/usr/bin/env python |
|
2 """ |
|
3 Freeslot project |
|
4 Command line interface |
|
5 """ |
|
6 |
|
7 from freeslot import Blackbox, LOGLEVEL |
|
8 from optparse import OptionParser |
|
9 from operator import itemgetter |
|
10 from subprocess import Popen, PIPE |
|
11 import sys, os |
|
12 from copy import copy |
|
13 import curses |
|
14 from time import sleep |
|
15 |
|
16 import SimpleXMLRPCServer |
|
17 import xmlrpclib |
|
18 import threading |
|
19 |
|
20 |
|
21 VERSION = "1.7" |
|
22 MAXSLOTS = 6 |
|
23 TERM = { |
|
24 "caption": "\033[1;37m\033[1;44m", |
|
25 "text": "\033[1;30m", |
|
26 } |
|
27 |
|
28 # disable debug log output |
|
29 LOGLEVEL = 10 |
|
30 |
|
31 SOUNDPREFIX = "quake-" |
|
32 EVENTPREFIX = "event/" |
|
33 SOUNDS = { |
|
34 "countdown_start": os.path.abspath(SOUNDPREFIX + "sound/countdown.mp3"), |
|
35 "race_start": os.path.abspath(SOUNDPREFIX + "sound/racestart.mp3"), |
|
36 "race_prepare": os.path.abspath(SOUNDPREFIX + "sound/prepare.mp3"), |
|
37 "lap_record": os.path.abspath(SOUNDPREFIX + "sound/laprecord.mp3"), |
|
38 "fuel_warning1": os.path.abspath(SOUNDPREFIX + "sound/fuel1.mp3"), |
|
39 "fuel_warning2": os.path.abspath(SOUNDPREFIX + "sound/fuel2.mp3"), |
|
40 "fuel_full": os.path.abspath(SOUNDPREFIX + "sound/fuel_full.mp3"), |
|
41 "pitlane_enter": os.path.abspath(SOUNDPREFIX + "sound/pitlane_enter.mp3"), |
|
42 "pitlane_exit": os.path.abspath(SOUNDPREFIX + "sound/pitlane_exit.mp3"), |
|
43 "data_error": os.path.abspath(SOUNDPREFIX + "sound/data_error.mp3"), |
|
44 "panic": os.path.abspath(SOUNDPREFIX + "sound/panic.mp3"), |
|
45 "panic_shortcut": os.path.abspath(SOUNDPREFIX + "sound/panic_shortcut.mp3"), |
|
46 "resume": os.path.abspath(SOUNDPREFIX + "sound/resume.mp3"), |
|
47 "win": os.path.abspath(SOUNDPREFIX + "sound/win.mp3"), |
|
48 |
|
49 } |
|
50 |
|
51 def trigger_sound(what): |
|
52 if what in SOUNDS: |
|
53 Popen(["/usr/bin/mpg123", "-q", SOUNDS[what]]) |
|
54 #os.spawnlp(os.P_NOWAIT, "/usr/bin/mpg123", "mpg123", SOUNDS[what]) |
|
55 #Popen(["/usr/bin/mpg123", SOUNDS[what]]).pid |
|
56 |
|
57 def trigger_event(what, slot = 0): |
|
58 trigger_sound(what) |
|
59 Popen(["/bin/sh", os.path.abspath(EVENTPREFIX + what), str(slot)]) |
|
60 |
|
61 class SlotServer(threading.Thread): |
|
62 def __init__(self, blackbox): |
|
63 threading.Thread.__init__(self) |
|
64 self.server = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 8000)) |
|
65 self.server.register_instance(blackbox) |
|
66 #self.server.register_function(lambda astr: '_' + astr, '_string') |
|
67 self.daemon = True |
|
68 |
|
69 def run(self): |
|
70 self.server.serve_forever() |
|
71 |
|
72 class SlotClient(): |
|
73 def __init__(self, url): |
|
74 self.box = xmlrpclib.Server(url) |
|
75 |
|
76 class SlotCli(): |
|
77 def __init__(self, test = None, dev=""): |
|
78 self.box = Blackbox() |
|
79 if (not test): |
|
80 self.box.connect(dev) |
|
81 self.rpcserver = SlotServer(self.box) |
|
82 self.rpcserver.start() |
|
83 self.slot_dummy = { |
|
84 "name": "Unnamed", |
|
85 "laps": 0, |
|
86 "laps_last": 0, |
|
87 "last": 0.00, |
|
88 "best": 0.00, |
|
89 "fuel": 0, |
|
90 "fuel_last": 0, |
|
91 "position": 0, |
|
92 "drive": 0, |
|
93 "status": "Idle", |
|
94 "clk": 0, |
|
95 "car": 0, |
|
96 "limit": 15, |
|
97 } |
|
98 |
|
99 self.slot = [ |
|
100 copy(self.slot_dummy), copy(self.slot_dummy), |
|
101 copy(self.slot_dummy), copy(self.slot_dummy), |
|
102 copy(self.slot_dummy), copy(self.slot_dummy), |
|
103 ] |
|
104 self.reset_slots() |
|
105 self.sysclk = 0.00 |
|
106 self.sysclk_last = 0.00 |
|
107 self.bestlap = 9999999.00 |
|
108 self.test = test |
|
109 self.laplimit = 999; |
|
110 self.timelimit = 0; |
|
111 |
|
112 def reset_slots(self): |
|
113 idx = 0 |
|
114 for slt in self.slot: |
|
115 slt["laps"] = 0 |
|
116 slt["laps_last"] = 0 |
|
117 slt["last"] = 0.00 |
|
118 slt["best"] = 0.00 |
|
119 slt["fuel"] = 100 |
|
120 slt["fuel_last"] = 0 |
|
121 slt["position"] = idx |
|
122 slt["car"] = idx # used for sort order calculation |
|
123 slt["status"] = self.slot_dummy["status"] |
|
124 slt["clk"] = 0 |
|
125 slt["limit"] = 15 |
|
126 idx += 1 |
|
127 self.bestlap = 99999.00 |
|
128 self.raceactive = False |
|
129 |
|
130 def update_positions(self): |
|
131 order1 = sorted(self.slot, key=itemgetter( |
|
132 "clk")) |
|
133 order2 = sorted(self.slot, key=itemgetter( |
|
134 "laps"), reverse=True) |
|
135 idx = 1 |
|
136 for tst in order2: |
|
137 self.slot[tst["car"]]["position"] = idx |
|
138 idx += 1 |
|
139 |
|
140 def render_slots(self): |
|
141 self.update_positions() |
|
142 self.scr.addstr(3,0, |
|
143 #"Pos | #/Name | Laps | Best | Last | Fuel | Status ", |
|
144 "Pos | #/Name ", |
|
145 curses.color_pair(2)) |
|
146 self.scr.addstr(4,4, |
|
147 " Laps | Best | Last | Fuel | Status ", |
|
148 curses.color_pair(2)) |
|
149 for idx in range(MAXSLOTS): |
|
150 """ |
|
151 self.scr.addstr((3 + (self.slot[idx]["position"] * 2)), 0, |
|
152 "%3i | %i %15s | %4i | %7.2fs | %7.2fs | %3i%% | %10s" % ( |
|
153 self.slot[idx]["position"], |
|
154 self.slot[idx]["car"] + 1, self.slot[idx]["name"], |
|
155 self.slot[idx]["laps"], |
|
156 self.slot[idx]["best"], |
|
157 self.slot[idx]["last"], |
|
158 self.slot[idx]["fuel"], |
|
159 self.slot[idx]["status"], |
|
160 ), |
|
161 curses.color_pair(11 + idx) ) |
|
162 """ |
|
163 if idx > 3: |
|
164 namesuffix = " (%i)" % self.slot[idx]["drive"] |
|
165 else: |
|
166 namesuffix = "" |
|
167 |
|
168 self.scr.addstr((3 + (self.slot[idx]["position"] * 2)), 0, |
|
169 "%3i | %i %15s %48s" % ( |
|
170 self.slot[idx]["position"], |
|
171 self.slot[idx]["car"] + 1, (self.slot[idx]["name"] + namesuffix), |
|
172 "", |
|
173 ), |
|
174 curses.color_pair(11 + idx) ) |
|
175 self.scr.addstr((4 + (self.slot[idx]["position"] * 2)), 4, |
|
176 " %4i | %7.2fs | %7.2fs | %3i%% | %10s | %2i% 15s" % ( |
|
177 self.slot[idx]["laps"], |
|
178 self.slot[idx]["best"], |
|
179 self.slot[idx]["last"], |
|
180 self.slot[idx]["fuel"], |
|
181 self.slot[idx]["status"], |
|
182 self.slot[idx]["limit"], |
|
183 "" |
|
184 ), |
|
185 curses.color_pair(11 + idx) ) |
|
186 |
|
187 def cleartop(self): |
|
188 self.scr.addstr(0,0, "%60s" % "Race Limits: %i Laps / %i Minutes" % (self.laplimit, self.timelimit)) |
|
189 self.scr.addstr(1,0, "%80s" % " ") |
|
190 |
|
191 def readName(self, slot): |
|
192 self.scr.nodelay(0) # enable delay on readkey |
|
193 curses.echo() |
|
194 self.scr.addstr(0,0, "Enter Name for Controller %i [%s]:" % ( |
|
195 slot + 1, |
|
196 self.slot[slot]["name"]), |
|
197 curses.color_pair(1)) |
|
198 self.scr.refresh() |
|
199 name = self.scr.getstr(1,0, 15) |
|
200 if name != "": |
|
201 self.slot[slot]["name"] = name |
|
202 self.cleartop() |
|
203 self.scr.refresh() |
|
204 curses.noecho() |
|
205 self.scr.nodelay(1) # disable delay on readkey |
|
206 |
|
207 def readLimit(self, slot): |
|
208 limit = self.readInt("SPEEDLIMIT for %s (%i)" % ( |
|
209 self.slot[slot]["name"], |
|
210 slot + 1), |
|
211 self.slot[slot]["limit"], 15) |
|
212 if limit: |
|
213 self.slot[slot]["limit"] = limit |
|
214 self.cleartop() |
|
215 self.box.speedlimit(slot, limit) |
|
216 |
|
217 |
|
218 def readInt(self, msg, default, maximum = 999999): |
|
219 self.scr.nodelay(0) # enable delay on readkey |
|
220 curses.echo() |
|
221 self.scr.addstr(0,0, "%s [%i]:" % ( |
|
222 msg, |
|
223 default), |
|
224 curses.color_pair(1)) |
|
225 self.scr.refresh() |
|
226 inp = self.scr.getstr(1,0, 4) |
|
227 if inp != "": |
|
228 try: |
|
229 inp = int(inp) |
|
230 if inp > maximum: inp = maximum |
|
231 except Exception: |
|
232 inp = None |
|
233 else: |
|
234 inp = None |
|
235 self.cleartop() |
|
236 self.scr.refresh() |
|
237 curses.noecho() |
|
238 self.scr.nodelay(1) # disable delay on readkey |
|
239 return inp |
|
240 |
|
241 |
|
242 def monitor_init(self, live = 1): |
|
243 """ |
|
244 Send initializing commands for live monitoring |
|
245 """ |
|
246 self.box.query("F1\n") # set fuel logic enabled |
|
247 self.box.query("*%i\n" % live) # set live fuel info |
|
248 |
|
249 def monitor_learn(self, slot): |
|
250 # clear garbage in UART rx buffer |
|
251 self.box.query("*0\n") # set live fuel info |
|
252 self.box.query("*0\n") # set live fuel info |
|
253 while self.box.readline() != "": pass |
|
254 |
|
255 trk = False |
|
256 spd = 0 |
|
257 trk_old = False |
|
258 spd_old = 0 |
|
259 clock = -1 |
|
260 |
|
261 self.monitor_init(slot + 2) |
|
262 while 1: |
|
263 #key = self.scr.getch() |
|
264 #if key == ord('c'): break |
|
265 |
|
266 # is there something in the rx buffer? |
|
267 rx = self.box.readline() |
|
268 if (rx != ""): |
|
269 try: |
|
270 data = rx.split(":") |
|
271 if rx[:3] == "LN:": |
|
272 if clock >= 0: |
|
273 clock += 1 |
|
274 spd = int(data[1], 16) |
|
275 trk = (data[2] != 'X') |
|
276 if (spd != spd_old) or (trk != trk_old): |
|
277 if clock < 0: |
|
278 clock = 0 |
|
279 print "%i,%i,%s" % (clock, spd, trk) |
|
280 trk_old = trk |
|
281 spd_old = spd * 1 |
|
282 if rx[:2] == "L:": |
|
283 # update lap time info |
|
284 l = int(data[2], 16) |
|
285 s = int(data[3]) - 1 |
|
286 t = int(data[4], 16) / 2000.00 |
|
287 if (slot == s): |
|
288 print "# lap %i complete: %3.2f seconds" % (l, t) |
|
289 clock = 0 |
|
290 print "%i,%i,%s" % (clock, spd, trk) |
|
291 except: |
|
292 print "RX ERROR: " % rx |
|
293 |
|
294 def monitor_playback(self, slot, filename): |
|
295 # clear garbage in UART rx buffer |
|
296 self.box.query("*0\n") # set live fuel info |
|
297 self.box.query("*0\n") # set live fuel info |
|
298 sleep(1) |
|
299 cli.box.speedminimum(slot, 0 ) |
|
300 while self.box.readline() != "": pass |
|
301 |
|
302 clock = -5 |
|
303 trkfile = open(filename, "r").readlines() |
|
304 print "Loading %s..." % filename |
|
305 |
|
306 while 1: |
|
307 try: |
|
308 for l in trkfile: |
|
309 l = l.strip() |
|
310 if (l != "") and (l[:1] != "#"): |
|
311 print "Line: %s" % repr(l) |
|
312 data = l.split(",") |
|
313 speed = int(data[1]) |
|
314 while (clock < int(data[0]) and (int(data[0]) > 0)): |
|
315 clock += 1 |
|
316 sleep(0.07) |
|
317 print "CLK %i/%i -> set: %i" % (clock, int(data[0]), speed) |
|
318 cli.box.speedminimum(slot, speed ) |
|
319 # now wait for lap sync :) |
|
320 while self.box.readline() != "": pass |
|
321 rx = "" |
|
322 while rx[:2] != "L:": |
|
323 rx = self.box.readline() |
|
324 data = rx.split(":") |
|
325 l = int(data[2], 16) |
|
326 s = int(data[3]) - 1 |
|
327 t = int(data[4], 16) / 2000.00 |
|
328 print "# lap %i complete: %3.2f seconds" % (l, t) |
|
329 clock = -3 |
|
330 except Exception, e: |
|
331 print repr(e) |
|
332 sys.exit(1) |
|
333 except KeyboardInterrupt: |
|
334 print "resetting" |
|
335 cli.box.speedminimum(slot, 0 ) |
|
336 cli.box.speedminimum(slot, 0 ) |
|
337 sys.exit(0) |
|
338 |
|
339 |
|
340 |
|
341 def monitor(self): |
|
342 """ |
|
343 Live Monitor on the console |
|
344 Keyboard loop to control it??? |
|
345 """ |
|
346 # clear garbage in UART rx buffer |
|
347 while self.box.readline() != "": pass |
|
348 |
|
349 self.monitor_init() |
|
350 self.scr = curses.initscr() |
|
351 curses.start_color() |
|
352 curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK) # standard text |
|
353 curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE) # label |
|
354 curses.init_pair(11, curses.COLOR_BLACK, curses.COLOR_YELLOW) # player 1 slot |
|
355 curses.init_pair(12, curses.COLOR_BLACK, curses.COLOR_GREEN) # player 2 slot |
|
356 curses.init_pair(13, curses.COLOR_BLACK, curses.COLOR_RED) # player 3 slot |
|
357 curses.init_pair(14, curses.COLOR_BLACK, curses.COLOR_MAGENTA) # player 4 slot |
|
358 curses.init_pair(15, curses.COLOR_WHITE, curses.COLOR_BLACK) # player 5 slot |
|
359 curses.init_pair(16, curses.COLOR_WHITE, curses.COLOR_BLACK) # player 6 slot |
|
360 curses.noecho() # disable key echo |
|
361 curses.cbreak() # do not buffer keypresses |
|
362 self.scr.keypad(1) # enable special keys |
|
363 self.scr.nodelay(1) # disable delay on readkey |
|
364 |
|
365 self.cleartop() |
|
366 self.render_slots() |
|
367 self.scr.refresh() |
|
368 |
|
369 |
|
370 while 1: |
|
371 key = self.scr.getch() |
|
372 if key == ord('c'): break |
|
373 elif key == ord(' '): self.box.query("+") # panic / resume |
|
374 elif key == 10: self.box.query("#") # remote start button press |
|
375 elif key == ord('1'): self.readName(0) |
|
376 elif key == ord('2'): self.readName(1) |
|
377 elif key == ord('3'): self.readName(2) |
|
378 elif key == ord('4'): self.readName(3) |
|
379 elif key == ord('5'): self.readName(4) |
|
380 elif key == ord('6'): self.readName(5) |
|
381 elif key == ord('q'): self.readLimit(0) |
|
382 elif key == ord('w'): self.readLimit(1) |
|
383 elif key == ord('e'): self.readLimit(2) |
|
384 elif key == ord('r'): self.readLimit(3) |
|
385 elif key == ord('t'): self.readLimit(4) |
|
386 elif key == ord('z'): self.readLimit(5) |
|
387 elif key == ord('a'): |
|
388 if self.slot[4]["drive"] > 0: self.slot[4]["drive"] -= 1 |
|
389 cli.box.speedminimum(4, self.slot[4]["drive"]) |
|
390 elif key == ord('s'): |
|
391 if self.slot[4]["drive"] < 16: self.slot[4]["drive"] += 1 |
|
392 cli.box.speedminimum(4, self.slot[4]["drive"]) |
|
393 elif key == ord('y'): |
|
394 if self.slot[5]["drive"] > 0: self.slot[5]["drive"] -= 1 |
|
395 cli.box.speedminimum(5, self.slot[5]["drive"]) |
|
396 elif key == ord('x'): |
|
397 if self.slot[5]["drive"] < 16: self.slot[5]["drive"] += 1 |
|
398 cli.box.speedminimum(5, self.slot[5]["drive"]) |
|
399 elif key == ord('t'): |
|
400 tmp = self.readInt("Set new Race TIME limit", self.timelimit) |
|
401 if tmp: self.timelimit = tmp |
|
402 elif key == ord('l'): |
|
403 tmp = self.readInt("Set new Race LAP limit", self.laplimit) |
|
404 if tmp: self.laplimit = tmp |
|
405 |
|
406 |
|
407 # is there something in the rx buffer? |
|
408 rx = self.box.readline() |
|
409 if (rx != "") or self.test: |
|
410 self.scr.addstr(17,0, |
|
411 "Last RX: %19s" % rx, curses.color_pair(2)) |
|
412 self.scr.redrawwin() |
|
413 self.scr.refresh() |
|
414 # we have received something |
|
415 try: |
|
416 data = rx.split(":") |
|
417 if rx[:2] == "L:": |
|
418 # update lap time info |
|
419 l = int(data[2], 16) |
|
420 slot = int(data[3]) - 1 |
|
421 t = int(data[4], 16) / 2000.00 |
|
422 self.sysclk = int(data[5], 16) / 2000.00 |
|
423 self.slot[slot]["laps_last"] = self.slot[slot]["laps"] |
|
424 self.slot[slot]["laps"] = l |
|
425 self.slot[slot]["last"] = t |
|
426 self.slot[slot]["clk"] = self.sysclk |
|
427 if (self.slot[slot]["best"] > t) or (self.slot[slot]["best"] == 0): |
|
428 self.slot[slot]["best"] = t |
|
429 if self.bestlap > t: |
|
430 trigger_event("lap_record", slot + 1) |
|
431 self.bestlap = t |
|
432 |
|
433 self.slot[slot]["status"] = "IN-RACE" |
|
434 if (self.slot[slot]["laps_last"] != l) and (l == self.laplimit): |
|
435 # we have lap limit reached! |
|
436 trigger_event("win", slot + 1) |
|
437 self.raceactive = False |
|
438 self.slot[slot]["status"] = "WINNER!" |
|
439 self.box.query("+") # stop race |
|
440 |
|
441 self.render_slots() |
|
442 |
|
443 if rx[:2] == "F:": |
|
444 # update fuel level |
|
445 slot = int(data[1]) |
|
446 f = int(data[2], 16) |
|
447 f = f / 100 # fuel in percent |
|
448 self.sysclk = int(data[3], 16) / 2000.00 |
|
449 self.slot[slot]["fuel_last"] = self.slot[slot]["fuel"] |
|
450 self.slot[slot]["fuel"] = f |
|
451 if self.slot[slot]["fuel_last"] != f: |
|
452 if (self.slot[slot]["fuel_last"] == 16) and (f == 15): |
|
453 # 15 percent fuel, set speed limit for car to 8 |
|
454 # warning sound |
|
455 trigger_event("fuel_warning1", slot + 1) |
|
456 cli.box.speedlimit(slot, 8) |
|
457 if (self.slot[slot]["fuel_last"] == 6) and (f == 5): |
|
458 # 5 percent, set speed limit for car to 6 |
|
459 # warning sound |
|
460 trigger_event("fuel_warning2", slot + 1) |
|
461 cli.box.speedlimit(slot, 6) |
|
462 if (self.slot[slot]["fuel_last"] == 1) and (f == 0): |
|
463 # fuel empty |
|
464 # set speedlimit to 4 |
|
465 cli.box.speedlimit(slot, 4) |
|
466 if (self.slot[slot]["fuel_last"] < f) and (f >= 11) and (f < 20): |
|
467 cli.box.speedlimit(slot, 15) |
|
468 if (self.slot[slot]["fuel_last"] < f) and (f == 100): |
|
469 trigger_event("fuel_full", slot + 1) |
|
470 self.render_slots() |
|
471 |
|
472 if rx[:1] == "~": |
|
473 # jumpstart occured |
|
474 slot = int(rx[1:2]) |
|
475 t = int(data[1], 16) / 2000.00 |
|
476 self.slot[slot]["jumpstart"] = t |
|
477 self.slot[slot]["status"] = "Jumpstart!" |
|
478 |
|
479 if rx[:3] == "RW:": |
|
480 # ResponseWire packet, do nothing at the moment, just decode |
|
481 slot = int(data[1]) |
|
482 devtype = int(data[2]) |
|
483 sender = int(data[3], 16) |
|
484 status = int(data[4], 16) |
|
485 self.sysclk = int(data[5], 16) |
|
486 if (devtype == 4): |
|
487 # pitlane sent something |
|
488 if (status == 5): |
|
489 self.slot[slot]["status"] = "PITLANE" |
|
490 trigger_event("pitlane_enter", slot + 1) |
|
491 if (status == 7): |
|
492 self.slot[slot]["status"] = "IN-RACE" |
|
493 trigger_event("pitlane_exit", slot + 1) |
|
494 |
|
495 self.render_slots() |
|
496 |
|
497 if rx == "!RACE PREPARE": |
|
498 # reset current race status |
|
499 # and display PREPARE PHASE |
|
500 self.reset_slots() |
|
501 for slot in range(MAXSLOTS): |
|
502 self.slot[slot]["status"] = "Prepare" |
|
503 trigger_event("race_prepare") |
|
504 |
|
505 if rx == "!RACE START": |
|
506 for slot in range(MAXSLOTS): |
|
507 if self.slot[slot]["status"] == "~~~~~~~~~~": |
|
508 self.slot[slot]["status"] = "Idle" |
|
509 trigger_event("race_start") |
|
510 self.raceactive = True |
|
511 |
|
512 if rx == "!COUNTDOWN": |
|
513 # countdown initiated |
|
514 for slot in range(MAXSLOTS): |
|
515 self.slot[slot]["status"] = "~~~~~~~~~~" |
|
516 trigger_event("countdown_start") |
|
517 |
|
518 if rx == "!PANIC": |
|
519 # panic mode |
|
520 trigger_event("panic") |
|
521 |
|
522 if rx == "!SHORTCUT": |
|
523 # panic mode |
|
524 trigger_event("panic_shortcut") |
|
525 |
|
526 if rx == "!RESUME": |
|
527 # panic mode |
|
528 trigger_event("resume") |
|
529 |
|
530 |
|
531 if ((self.timelimit > 0) and (self.raceactive) and |
|
532 (self.sysclk_last != self.sysclk) and |
|
533 ((self.sysclk / 60) >= self.timelimit)): |
|
534 self.sysclk_last = self.sysclk |
|
535 self.raceactive = False |
|
536 # we have time limit reached! |
|
537 self.box.query("+") # stop race |
|
538 trigger_event("win") |
|
539 # get the one with position 1 |
|
540 for slot in self.slots: |
|
541 if slot["position"] == 1: |
|
542 slot["status"] = "WINNER!" |
|
543 self.render_slots() |
|
544 self.sysclk_last = self.sysclk |
|
545 |
|
546 |
|
547 |
|
548 self.scr.addstr(17,31, |
|
549 "Race Timer: %7.3f min" % (self.sysclk / 60), |
|
550 curses.color_pair(2)) |
|
551 |
|
552 self.scr.refresh() |
|
553 |
|
554 except Exception: |
|
555 trigger_event("data_error") |
|
556 pass |
|
557 |
|
558 # terminate |
|
559 curses.nocbreak() |
|
560 self.scr.keypad(0) |
|
561 curses.echo() |
|
562 curses.endwin() |
|
563 return None |
|
564 |
|
565 def cyclemode(self): |
|
566 pass |
|
567 |
|
568 if __name__ == "__main__": |
|
569 parser = OptionParser(version="%prog " + VERSION) |
|
570 parser.add_option("--live", dest="live", action="store_true", default=False, |
|
571 help="Run Live monitor on console", metavar="[0-5]") |
|
572 parser.add_option("--learn", dest="learn", action="store_true", default=False, |
|
573 help="Run Learning mode for [slot]", metavar="[0-5]") |
|
574 parser.add_option("--teach", dest="playback", |
|
575 help="Playback teach file", metavar="[filename]") |
|
576 |
|
577 parser.add_option("--slot", dest="carid", |
|
578 help="Required for programming a car directly", metavar="[1-6]") |
|
579 parser.add_option("--fuel", dest="fuel", |
|
580 help="Set maximum CAR fuel level", metavar="[0-15]") |
|
581 parser.add_option("--brake", dest="brake", |
|
582 help="Set CAR brake strength", metavar="[0-15]") |
|
583 parser.add_option("--accel", dest="accel", |
|
584 help="Set CAR acceleration ", metavar="[6-15]") |
|
585 parser.add_option("--blink", dest="blink", |
|
586 help="Set car lights blinking state", metavar="[on|off]") |
|
587 parser.add_option("--limit", dest="limit", |
|
588 help="Controlled SPEED LIMIT (15 = no limit)", metavar="[0-15]") |
|
589 parser.add_option("--drive", dest="drive", |
|
590 help="Controlled SPEED MINIMUM (0 = disabled)", metavar="[0-15]") |
|
591 parser.add_option("--test", dest="test", action="store_true", default=False, |
|
592 help="", metavar="") |
|
593 parser.add_option("--dev", dest="dev", default="/dev/ttyUSB0", |
|
594 help="Communication port", metavar="[/dev/ttyUSB0]") |
|
595 |
|
596 (options, args) = parser.parse_args() |
|
597 #if not options.dev: |
|
598 # options.dev = "/dev/ttyUSB0" |
|
599 |
|
600 if options.live or options.learn or options.playback: |
|
601 cli = SlotCli(options.test, options.dev) |
|
602 else: |
|
603 cli = SlotClient('http://localhost:8000') |
|
604 # should a CLI function be started? |
|
605 |
|
606 if options.live: |
|
607 # start the live monitor |
|
608 cli.monitor() |
|
609 sys.exit(0) |
|
610 |
|
611 # check commandline if we have to program something |
|
612 if not options.carid: |
|
613 print "Option --slot is required for all car programming commands!\nUse --help to get a list of available commands" |
|
614 sys.exit(1) |
|
615 else: |
|
616 options.carid = int(options.carid) - 1 |
|
617 if (options.carid < 0) or (options.carid > 6): |
|
618 print "Error: Invalid slot selected" |
|
619 sys.exit(1) |
|
620 |
|
621 if options.learn: |
|
622 # start the learn monitor |
|
623 cli.monitor_learn(options.carid) |
|
624 sys.exit(0) |
|
625 |
|
626 if options.playback: |
|
627 # start the playback monitor |
|
628 cli.monitor_playback(options.carid, options.playback) |
|
629 sys.exit(0) |
|
630 |
|
631 if options.fuel: |
|
632 print "setFuel: " + cli.box.progcar(int(options.carid), "fuel", int(options.fuel)) |
|
633 |
|
634 if options.accel: |
|
635 print "setAccel: " + cli.box.progcar(int(options.carid), "accel", int(options.accel)) |
|
636 |
|
637 if options.brake: |
|
638 print "setBrake: " + cli.box.progcar(int(options.carid), "brake", int(options.brake)) |
|
639 |
|
640 if options.blink: |
|
641 state = False |
|
642 if options.blink == "on": |
|
643 state = True |
|
644 print "setBlink: " + cli.box.blinkcar(int(options.carid), state) |
|
645 |
|
646 if options.limit: |
|
647 print "Change Speed Limit: " + cli.box.speedlimit(int(options.carid), int(options.limit)) |
|
648 |
|
649 if options.drive: |
|
650 print "Change minimum Speed drive: " + cli.box.speedminimum(int(options.carid), int(options.drive)) |
|
651 |
|