27 "last": 0.00, |
31 "last": 0.00, |
28 "best": 0.00, |
32 "best": 0.00, |
29 "fuel": 0, |
33 "fuel": 0, |
30 "position": 0, |
34 "position": 0, |
31 "drive": 0, |
35 "drive": 0, |
|
36 "status": "Idle", |
|
37 "clk": 0, |
|
38 "car": 0, |
32 } |
39 } |
33 |
40 |
34 self.slot = [ |
41 self.slot = [ |
35 copy(self.slot_dummy), copy(self.slot_dummy), |
42 copy(self.slot_dummy), copy(self.slot_dummy), |
36 copy(self.slot_dummy), copy(self.slot_dummy), |
43 copy(self.slot_dummy), copy(self.slot_dummy), |
37 copy(self.slot_dummy), copy(self.slot_dummy), |
44 copy(self.slot_dummy), copy(self.slot_dummy), |
38 ] |
45 ] |
|
46 self.reset_slots() |
|
47 self.sysclk = 0.00 |
|
48 |
|
49 def reset_slots(self): |
|
50 idx = 0 |
|
51 for slt in self.slot: |
|
52 slt["laps"] = 0 |
|
53 slt["last"] = 0.00 |
|
54 slt["best"] = 0.00 |
|
55 slt["fuel"] = 0 |
|
56 slt["position"] = idx |
|
57 slt["car"] = idx # used for sort order calculation |
|
58 slt["status"] = self.slot_dummy["status"] |
|
59 slt["clk"] = 0 |
|
60 idx += 1 |
39 |
61 |
40 def update_positions(self): |
62 def update_positions(self): |
41 for idx in range(MAXSLOTS): |
63 order1 = sorted(self.slot, key=itemgetter( |
42 self.slot[idx]["position"] = idx + 1 |
64 "clk")) |
43 # TODO |
65 order2 = sorted(self.slot, key=itemgetter( |
|
66 "laps"), reverse=True) |
|
67 idx = 1 |
|
68 for tst in order2: |
|
69 self.slot[tst["car"]]["position"] = idx |
|
70 idx += 1 |
44 |
71 |
45 def render_slots(self): |
72 def render_slots(self): |
46 self.update_positions() |
73 self.update_positions() |
47 self.scr.addstr(3,0, |
74 self.scr.addstr(3,0, |
48 "Pos | #/Name | Laps | Best | Last | Fuel |", |
75 "Pos | #/Name | Laps | Best | Last | Fuel | Status ", |
49 curses.color_pair(2)) |
76 curses.color_pair(2)) |
50 for idx in range(MAXSLOTS): |
77 for idx in range(MAXSLOTS): |
51 self.scr.addstr((3 + self.slot[idx]["position"]), 0, |
78 self.scr.addstr((3 + self.slot[idx]["position"]), 0, |
52 "%3i | %15s | %4i | %5.2fs | %5.2fs | %3i%% |" % ( |
79 "%3i | %i %15s | %4i | %7.2fs | %7.2fs | %3i%% | %10s" % ( |
53 self.slot[idx]["position"], |
80 self.slot[idx]["position"], |
54 self.slot[idx]["name"], |
81 self.slot[idx]["car"] + 1, self.slot[idx]["name"], |
55 self.slot[idx]["laps"], |
82 self.slot[idx]["laps"], |
56 self.slot[idx]["best"], |
83 self.slot[idx]["best"], |
57 self.slot[idx]["last"], |
84 self.slot[idx]["last"], |
58 self.slot[idx]["fuel"], |
85 self.slot[idx]["fuel"], |
|
86 self.slot[idx]["status"], |
59 ) ) |
87 ) ) |
60 |
88 |
61 def cleartop(self): |
89 def cleartop(self): |
62 self.scr.addstr(0,0, "%80s" % "Live monitor running, press keys to control or (q)uit") |
90 self.scr.addstr(0,0, "%80s" % "Live monitor running, press keys to control or (q)uit") |
63 self.scr.addstr(1,0, "%80s" % " ") |
91 self.scr.addstr(1,0, "%80s" % " ") |
88 def monitor(self): |
116 def monitor(self): |
89 """ |
117 """ |
90 Live Monitor on the console |
118 Live Monitor on the console |
91 Keyboard loop to control it??? |
119 Keyboard loop to control it??? |
92 """ |
120 """ |
|
121 # clear garbage in UART rx buffer |
|
122 while self.box.com.readline() != "": pass |
|
123 |
93 self.monitor_init() |
124 self.monitor_init() |
94 self.scr = curses.initscr() |
125 self.scr = curses.initscr() |
95 curses.start_color() |
126 curses.start_color() |
96 curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK) # standard text |
127 curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK) # standard text |
97 curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE) # label |
128 curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE) # label |
130 |
161 |
131 |
162 |
132 # is there something in the rx buffer? |
163 # is there something in the rx buffer? |
133 rx = self.box.com.readline() |
164 rx = self.box.com.readline() |
134 if rx != "": |
165 if rx != "": |
|
166 self.scr.addstr(10,0, |
|
167 "Last RX: %19s" % rx, curses.color_pair(2)) |
|
168 self.scr.refresh() |
135 # we have received something |
169 # we have received something |
136 data = rx.split(":") |
170 data = rx.split(":") |
137 if rx[:2] == "L:": |
171 if rx[:2] == "L:": |
138 # update lap time info |
172 # update lap time info |
|
173 l = int(data[2], 16) |
139 slot = int(data[3]) - 1 |
174 slot = int(data[3]) - 1 |
140 t = int(data[4], 16) |
175 t = int(data[4], 16) / 2000.00 |
141 l = int(data[2], 16) |
176 self.sysclk = int(data[5], 16) / 2000.00 |
142 t /= 2000.00 |
|
143 self.slot[slot]["laps"] = l |
177 self.slot[slot]["laps"] = l |
144 self.slot[slot]["last"] = t |
178 self.slot[slot]["last"] = t |
|
179 self.slot[slot]["clk"] = self.sysclk |
145 if (self.slot[slot]["best"] > t) or (self.slot[slot]["best"] == 0): self.slot[slot]["best"] = t |
180 if (self.slot[slot]["best"] > t) or (self.slot[slot]["best"] == 0): self.slot[slot]["best"] = t |
|
181 self.slot[slot]["status"] = "IN-RACE" |
146 self.render_slots() |
182 self.render_slots() |
147 |
183 |
148 if rx[:2] == "F:": |
184 if rx[:2] == "F:": |
149 # update fuel level |
185 # update fuel level |
150 slot = int(data[1]) |
186 slot = int(data[1]) |
151 f = int(data[2], 16) |
187 f = int(data[2], 16) |
152 f = f / 100 # fuel in percent |
188 f = f / 100 # fuel in percent |
|
189 self.sysclk = int(data[3], 16) / 2000.00 |
153 self.slot[slot]["fuel"] = f |
190 self.slot[slot]["fuel"] = f |
154 self.render_slots() |
191 self.render_slots() |
|
192 |
|
193 if rx[:1] == "~": |
|
194 # jumpstart occured |
|
195 slot = int(rx[1:2]) |
|
196 t = int(data[1], 16) / 2000.00 |
|
197 self.slot[slot]["jumpstart"] = t |
|
198 self.slot[slot]["status"] = "Jumpstart!" |
|
199 |
|
200 if rx[:3] == "RW:": |
|
201 # ResponseWire packet, do nothing at the moment, just decode |
|
202 slot = int(data[1]) |
|
203 devtype = int(data[2]) |
|
204 sender = int(data[3], 16) |
|
205 status = int(data[4], 16) |
|
206 self.sysclk = int(data[5], 16) |
|
207 if (devtype == 4): |
|
208 # pitlane sent something |
|
209 if (status == 5): self.slot[slot]["status"] = "PITLANE" |
|
210 if (status == 6): self.slot[slot]["status"] = "IN-RACE" |
|
211 |
|
212 self.render_slots() |
|
213 |
|
214 if rx == "!RACE PREPARE": |
|
215 # reset current race status |
|
216 # and display PREPARE PHASE |
|
217 for slot in range(MAXSLOTS): |
|
218 self.slot[slot]["status"] = "Prepare" |
|
219 |
|
220 if rx == "!RACE START": |
|
221 for slot in range(MAXSLOTS): |
|
222 if self.slot[slot]["status"] == "~~~~~~~~~~": |
|
223 self.slot[slot]["status"] = "Idle" |
|
224 |
|
225 if rx == "!COUNTDOWN": |
|
226 # countdown initiated |
|
227 for slot in range(MAXSLOTS): |
|
228 self.slot[slot]["status"] = "~~~~~~~~~~" |
|
229 |
|
230 self.scr.addstr(10,31, |
|
231 "Race Timer: %7.3f min" % (self.sysclk / 60), |
|
232 curses.color_pair(2)) |
155 |
233 |
156 self.scr.refresh() |
234 self.scr.refresh() |
157 |
235 |
158 # terminate |
236 # terminate |
159 curses.nocbreak() |
237 curses.nocbreak() |