6f2b618aec51c39e223fb17ca151f637e151ced0
[fw/altos] / src / telelco-v2.0 / ao_lco_v2.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20 #include <ao_lco.h>
21 #include <ao_event.h>
22 #include <ao_seven_segment.h>
23 #include <ao_quadrature.h>
24 #include <ao_lco_func.h>
25 #include <ao_radio_cmac.h>
26
27 #define DEBUG   1
28
29 #if DEBUG
30 static uint8_t  ao_lco_debug;
31 #define PRINTD(...) do { if (!ao_lco_debug) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0)
32 #else
33 #define PRINTD(...) 
34 #endif
35
36 #define AO_LCO_PAD_DIGIT        0
37 #define AO_LCO_BOX_DIGIT_1      1
38 #define AO_LCO_BOX_DIGIT_10     2
39
40 #define AO_LCO_DRAG_RACE_START_TIME     AO_SEC_TO_TICKS(5)
41 #define AO_LCO_DRAG_RACE_STOP_TIME      AO_SEC_TO_TICKS(2)
42
43 #define AO_LCO_VALID_LAST       1
44 #define AO_LCO_VALID_EVER       2
45
46 static uint8_t  ao_lco_min_box, ao_lco_max_box;
47 static uint8_t  ao_lco_selected[AO_PAD_MAX_BOXES];
48 static uint8_t  ao_lco_valid[AO_PAD_MAX_BOXES];
49 static uint8_t  ao_lco_channels[AO_PAD_MAX_BOXES];
50 static uint16_t ao_lco_tick_offset[AO_PAD_MAX_BOXES];
51
52 /* UI values */
53 static uint8_t  ao_lco_armed;
54 static uint8_t  ao_lco_firing;
55 static uint16_t ao_lco_fire_tick;
56 static uint8_t  ao_lco_fire_down;
57 static uint8_t  ao_lco_drag_race;
58 static uint8_t  ao_lco_pad;
59 static int16_t  ao_lco_box;
60 static uint8_t  ao_lco_select_mode;
61 #define AO_LCO_SELECT_PAD       0
62 #define AO_LCO_SELECT_BOX       1
63 #define AO_LCO_SELECT_NONE      2
64
65 static struct ao_pad_query      ao_pad_query;
66
67 static uint8_t  ao_lco_display_mutex;
68
69 static void
70 ao_lco_set_pad(uint8_t pad)
71 {
72         ao_mutex_get(&ao_lco_display_mutex);
73         ao_seven_segment_set(AO_LCO_PAD_DIGIT, pad | (ao_lco_drag_race << 4));
74         ao_mutex_put(&ao_lco_display_mutex);
75 }
76
77 #define SEVEN_SEGMENT_d         ((0 << 0) |     \
78                                  (0 << 1) |     \
79                                  (1 << 2) |     \
80                                  (1 << 3) |     \
81                                  (1 << 4) |     \
82                                  (1 << 5) |     \
83                                  (1 << 6))
84
85
86 #define SEVEN_SEGMENT_r         ((0 << 0) |     \
87                                  (0 << 1) |     \
88                                  (0 << 2) |     \
89                                  (1 << 3) |     \
90                                  (1 << 4) |     \
91                                  (0 << 5) |     \
92                                  (0 << 6))
93
94 static void
95 ao_lco_set_box(uint16_t box)
96 {
97         ao_mutex_get(&ao_lco_display_mutex);
98         ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, box % 10 | (ao_lco_drag_race << 4));
99         ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, box / 10 | (ao_lco_drag_race << 4));
100         ao_mutex_put(&ao_lco_display_mutex);
101 }
102
103 static void
104 ao_lco_set_voltage(uint16_t decivolts)
105 {
106         uint8_t tens, ones, tenths;
107
108         tenths = decivolts % 10;
109         ones = (decivolts / 10) % 10;
110         tens = (decivolts / 100) % 10;
111         ao_mutex_get(&ao_lco_display_mutex);
112         ao_seven_segment_set(AO_LCO_PAD_DIGIT, tenths);
113         ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, ones | 0x10);
114         ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, tens);
115         ao_mutex_put(&ao_lco_display_mutex);
116 }
117
118 static void
119 ao_lco_set_display(void)
120 {
121         if (ao_lco_pad == 0) {
122                 ao_lco_set_voltage(ao_pad_query.battery);
123         } else {
124                 ao_lco_set_pad(ao_lco_pad);
125                 ao_lco_set_box(ao_lco_box);
126         }
127 }
128
129 #define MASK_SIZE(n)    (((n) + 7) >> 3)
130 #define MASK_ID(n)      ((n) >> 3)
131 #define MASK_SHIFT(n)   ((n) & 7)
132
133 static uint8_t  ao_lco_box_mask[MASK_SIZE(AO_PAD_MAX_BOXES)];
134
135 static uint8_t
136 ao_lco_box_present(uint16_t box)
137 {
138         if (box >= AO_PAD_MAX_BOXES)
139                 return 0;
140         return (ao_lco_box_mask[MASK_ID(box)] >> MASK_SHIFT(box)) & 1;
141 }
142
143 static uint8_t
144 ao_lco_pad_present(uint8_t box, uint8_t pad)
145 {
146         /* voltage measurement is always valid */
147         if (pad == 0)
148                 return 1;
149         if (!ao_lco_channels[box])
150                 return 0;
151         if (pad > AO_PAD_MAX_CHANNELS)
152                 return 0;
153         return (ao_lco_channels[box] >> (pad - 1)) & 1;
154 }
155
156 static uint8_t
157 ao_lco_pad_first(uint8_t box)
158 {
159         uint8_t pad;
160
161         for (pad = 1; pad <= AO_PAD_MAX_CHANNELS; pad++)
162                 if (ao_lco_pad_present(box, pad))
163                         return pad;
164         return 0;
165 }
166
167 static void
168 ao_lco_set_select(void)
169 {
170         switch (ao_lco_select_mode) {
171         case AO_LCO_SELECT_PAD:
172                 ao_led_off(AO_LED_BOX);
173                 ao_led_on(AO_LED_PAD);
174                 break;
175         case AO_LCO_SELECT_BOX:
176                 ao_led_off(AO_LED_PAD);
177                 ao_led_on(AO_LED_BOX);
178                 break;
179         default:
180                 ao_led_off(AO_LED_PAD);
181                 ao_led_off(AO_LED_BOX);
182                 break;
183         }
184 }
185
186 static struct ao_task   ao_lco_drag_task;
187 static uint8_t          ao_lco_drag_active;
188 static uint8_t          ao_lco_drag_beep_count;
189 static uint8_t          ao_lco_drag_beep_on;
190 static uint16_t         ao_lco_drag_beep_time;
191 static uint16_t         ao_lco_drag_warn_time;
192
193 #define AO_LCO_DRAG_BEEP_TIME   AO_MS_TO_TICKS(50)
194 #define AO_LCO_DRAG_WARN_TIME   AO_SEC_TO_TICKS(5)
195
196 static void
197 ao_lco_drag_beep_start(void)
198 {
199         ao_beep(AO_BEEP_HIGH);
200         PRINTD("beep start\n");
201         ao_lco_drag_beep_on = 1;
202         ao_lco_drag_beep_time = ao_time() + AO_LCO_DRAG_BEEP_TIME;
203 }
204
205 static void
206 ao_lco_drag_beep_stop(void)
207 {
208         ao_beep(0);
209         PRINTD("beep stop\n");
210         ao_lco_drag_beep_on = 0;
211         if (ao_lco_drag_beep_count) {
212                 --ao_lco_drag_beep_count;
213                 if (ao_lco_drag_beep_count)
214                         ao_lco_drag_beep_time = ao_time() + AO_LCO_DRAG_BEEP_TIME;
215         }
216 }
217
218 static void
219 ao_lco_drag_beep(uint8_t beeps)
220 {
221         PRINTD("beep %d\n", beeps);
222         if (!ao_lco_drag_beep_count)
223                 ao_lco_drag_beep_start();
224         ao_lco_drag_beep_count += beeps;
225 }
226
227 static uint16_t
228 ao_lco_drag_beep_check(uint16_t now, uint16_t delay)
229 {
230         PRINTD("beep check count %d delta %d\n",
231                ao_lco_drag_beep_count,
232                (int16_t) (now - ao_lco_drag_beep_time));
233         if (ao_lco_drag_beep_count) {
234                 if ((int16_t) (now - ao_lco_drag_beep_time) >= 0) {
235                         if (ao_lco_drag_beep_on)
236                                 ao_lco_drag_beep_stop();
237                         else
238                                 ao_lco_drag_beep_start();
239                 }
240         }
241
242         if (ao_lco_drag_beep_count) {
243                 if (delay > AO_LCO_DRAG_BEEP_TIME)
244                         delay = AO_LCO_DRAG_BEEP_TIME;
245         }
246         return delay;
247 }
248
249 static void
250 ao_lco_drag_enable(void)
251 {
252         PRINTD("Drag enable\n");
253         ao_lco_drag_race = 1;
254         memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
255         ao_lco_drag_beep(5);
256         ao_lco_set_display();
257         ao_lco_fire_down = 0;
258 }
259
260 static void
261 ao_lco_drag_disable(void)
262 {
263         PRINTD("Drag disable\n");
264         ao_lco_drag_race = 0;
265         memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
266         ao_lco_drag_beep(2);
267         ao_lco_set_display();
268         ao_lco_fire_down = 0;
269 }
270
271 static uint16_t
272 ao_lco_drag_button_check(uint16_t now, uint16_t delay)
273 {
274         uint16_t        button_delay = ~0;
275
276         /*
277          * Check to see if the button has been held down long enough
278          * to switch in/out of drag race mode
279          */
280         if (ao_lco_fire_down) {
281                 if (ao_lco_drag_race) {
282                         if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_STOP_TIME)
283                                 ao_lco_drag_disable();
284                         else
285                                 button_delay = ao_lco_fire_tick + AO_LCO_DRAG_RACE_STOP_TIME - now;
286                 } else {
287                         if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_START_TIME)
288                                 ao_lco_drag_enable();
289                         else
290                                 button_delay = ao_lco_fire_tick + AO_LCO_DRAG_RACE_START_TIME - now;
291                 }
292                 if (delay > button_delay)
293                         delay = button_delay;
294         }
295         return delay;
296 }
297
298 static uint16_t
299 ao_lco_drag_warn_check(uint16_t now, uint16_t delay)
300 {
301         uint16_t        warn_delay = ~0;
302
303         if (ao_lco_drag_race) {
304                 if ((int16_t) (now - ao_lco_drag_warn_time) >= 0) {
305                         ao_lco_drag_beep(1);
306                         ao_lco_drag_warn_time = now + AO_LCO_DRAG_WARN_TIME;
307                 }
308                 warn_delay = ao_lco_drag_warn_time - now;
309         }
310         if (delay > warn_delay)
311                 delay = warn_delay;
312         return delay;
313 }
314
315 static void
316 ao_lco_drag_monitor(void)
317 {
318         uint16_t        delay = ~0;
319         uint16_t        now;
320
321         for (;;) {
322                 PRINTD("Drag monitor active %d delay %d\n", ao_lco_drag_active, delay);
323                 if (delay == (uint16_t) ~0)
324                         ao_sleep(&ao_lco_drag_active);
325                 else
326                         ao_sleep_for(&ao_lco_drag_active, delay);
327
328                 delay = ~0;
329                 if (!ao_lco_drag_active)
330                         continue;
331
332                 now = ao_time();
333                 delay = ao_lco_drag_button_check(now, delay);
334                 delay = ao_lco_drag_warn_check(now, delay);
335                 delay = ao_lco_drag_beep_check(now, delay);
336
337                 /* check to see if there's anything left to do here */
338                 if (!ao_lco_fire_down && !ao_lco_drag_race && !ao_lco_drag_beep_count) {
339                         delay = ~0;
340                         ao_lco_drag_active = 0;
341                 }
342         }
343 }
344
345 static void
346 ao_lco_input(void)
347 {
348         static struct ao_event  event;
349         int8_t          dir, new_pad;
350         int16_t         new_box;
351
352         ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
353         for (;;) {
354                 ao_event_get(&event);
355                 PRINTD("event type %d unit %d value %d\n",
356                        event.type, event.unit, event.value);
357                 switch (event.type) {
358                 case AO_EVENT_QUADRATURE:
359                         switch (event.unit) {
360                         case AO_QUADRATURE_SELECT:
361                                 if (!ao_lco_armed) {
362                                         switch (ao_lco_select_mode) {
363                                         case AO_LCO_SELECT_PAD:
364                                                 dir = (int8_t) event.value;
365                                                 new_pad = ao_lco_pad;
366                                                 do {
367                                                         new_pad += dir;
368                                                         if (new_pad > AO_PAD_MAX_CHANNELS)
369                                                                 new_pad = 0;
370                                                         if (new_pad < 0)
371                                                                 new_pad = AO_PAD_MAX_CHANNELS;
372                                                         if (new_pad == ao_lco_pad)
373                                                                 break;
374                                                 } while (!ao_lco_pad_present(ao_lco_box, new_pad));
375                                                 if (new_pad != ao_lco_pad) {
376                                                         ao_lco_pad = new_pad;
377                                                         ao_lco_set_display();
378                                                 }
379                                                 break;
380                                         case AO_LCO_SELECT_BOX:
381                                                 dir = (int8_t) event.value;
382                                                 new_box = ao_lco_box;
383                                                 do {
384                                                         new_box += dir;
385                                                         if (new_box > ao_lco_max_box)
386                                                                 new_box = ao_lco_min_box;
387                                                         else if (new_box < ao_lco_min_box)
388                                                                 new_box = ao_lco_max_box;
389                                                         if (new_box == ao_lco_box)
390                                                                 break;
391                                                 } while (!ao_lco_box_present(new_box));
392                                                 if (ao_lco_box != new_box) {
393                                                         ao_lco_box = new_box;
394                                                         ao_lco_pad = 1;
395                                                         ao_lco_channels[ao_lco_box] = 0;
396                                                         ao_lco_set_display();
397                                                 }
398                                                 break;
399                                         default:
400                                                 break;
401                                         }
402                                 }
403                                 break;
404                         }
405                         break;
406                 case AO_EVENT_BUTTON:
407                         switch (event.unit) {
408                         case AO_BUTTON_ARM:
409                                 ao_lco_armed = event.value;
410                                 PRINTD("Armed %d\n", ao_lco_armed);
411                                 if (ao_lco_armed) {
412                                         if (ao_lco_drag_race) {
413                                                 uint8_t box;
414
415                                                 for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) {
416                                                         if (ao_lco_selected[box]) {
417                                                                 ao_wakeup(&ao_lco_armed);
418                                                                 break;
419                                                         }
420                                                 }
421                                         } else {
422                                                 memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
423                                                 if (ao_lco_pad != 0)
424                                                         ao_lco_selected[ao_lco_box] = (1 << (ao_lco_pad - 1));
425                                                 else
426                                                         ao_lco_armed = 0;
427                                         }
428                                 }
429                                 ao_wakeup(&ao_lco_armed);
430                                 break;
431                         case AO_BUTTON_FIRE:
432                                 if (ao_lco_armed) {
433                                         ao_lco_fire_down = 0;
434                                         ao_lco_firing = event.value;
435                                         PRINTD("Firing %d\n", ao_lco_firing);
436                                         ao_wakeup(&ao_lco_armed);
437                                 }
438                                 break;
439                         case AO_BUTTON_DRAG_SELECT:
440                                 if (ao_lco_drag_race) {
441                                         if (ao_lco_pad != 0) {
442                                                 ao_lco_selected[ao_lco_box] ^= (1 << (ao_lco_pad - 1));
443                                                 PRINTD("Toggle box %d pad %d (pads now %x) to drag race\n",
444                                                        ao_lco_pad, ao_lco_box, ao_lco_selected[ao_lco_box]);
445                                                 ao_lco_drag_beep(ao_lco_pad);
446                                         }
447                                 }
448                                 break;
449                         case AO_BUTTON_MODE_SELECT:
450                                 if (event.value)
451                                         ao_lco_drag_enable();
452                                 else
453                                         ao_lco_drag_disable();
454                                 break;
455                         case AO_BUTTON_SELECT:
456                                 ao_lco_select_mode++;
457                                 if (ao_lco_select_mode > AO_LCO_SELECT_NONE)
458                                         ao_lco_select_mode = AO_LCO_SELECT_PAD;
459                                 ao_lco_set_select();
460                                 break;
461                         }
462                         break;
463                 }
464         }
465 }
466
467 static AO_LED_TYPE      continuity_led[AO_LED_CONTINUITY_NUM] = {
468 #ifdef AO_LED_CONTINUITY_0
469         AO_LED_CONTINUITY_0,
470 #endif
471 #ifdef AO_LED_CONTINUITY_1
472         AO_LED_CONTINUITY_1,
473 #endif
474 #ifdef AO_LED_CONTINUITY_2
475         AO_LED_CONTINUITY_2,
476 #endif
477 #ifdef AO_LED_CONTINUITY_3
478         AO_LED_CONTINUITY_3,
479 #endif
480 #ifdef AO_LED_CONTINUITY_4
481         AO_LED_CONTINUITY_4,
482 #endif
483 #ifdef AO_LED_CONTINUITY_5
484         AO_LED_CONTINUITY_5,
485 #endif
486 #ifdef AO_LED_CONTINUITY_6
487         AO_LED_CONTINUITY_6,
488 #endif
489 #ifdef AO_LED_CONTINUITY_7
490         AO_LED_CONTINUITY_7,
491 #endif
492 };
493
494 static uint8_t
495 ao_lco_get_channels(uint8_t box, struct ao_pad_query *query)
496 {
497         int8_t                  r;
498
499         r = ao_lco_query(box, query, &ao_lco_tick_offset[box]);
500         if (r == AO_RADIO_CMAC_OK) {
501                 ao_lco_channels[box] = query->channels;
502                 ao_lco_valid[box] = AO_LCO_VALID_LAST | AO_LCO_VALID_EVER;
503         } else
504                 ao_lco_valid[box] &= ~AO_LCO_VALID_LAST;
505         PRINTD("ao_lco_get_channels(%d) rssi %d valid %d ret %d offset %d\n", box, ao_radio_cmac_rssi, ao_lco_valid[box], r, ao_lco_tick_offset[box]);
506         ao_wakeup(&ao_pad_query);
507         return ao_lco_valid[box];
508 }
509
510 static void
511 ao_lco_update(void)
512 {
513         uint8_t previous_valid = ao_lco_valid[ao_lco_box];
514
515         if (ao_lco_get_channels(ao_lco_box, &ao_pad_query) & AO_LCO_VALID_LAST) {
516                 if (!(previous_valid & AO_LCO_VALID_EVER)) {
517                         if (ao_lco_pad != 0)
518                                 ao_lco_pad = ao_lco_pad_first(ao_lco_box);
519                         ao_lco_set_display();
520                 }
521                 if (ao_lco_pad == 0)
522                         ao_lco_set_display();
523         }
524 }
525
526 static void
527 ao_lco_box_reset_present(void)
528 {
529         ao_lco_min_box = 0xff;
530         ao_lco_max_box = 0x00;
531         memset(ao_lco_box_mask, 0, sizeof (ao_lco_box_mask));
532 }
533
534 static void
535 ao_lco_box_set_present(uint8_t box)
536 {
537         if (box < ao_lco_min_box)
538                 ao_lco_min_box = box;
539         if (box > ao_lco_max_box)
540                 ao_lco_max_box = box;
541         if (box >= AO_PAD_MAX_BOXES)
542                 return;
543         ao_lco_box_mask[MASK_ID(box)] |= 1 << MASK_SHIFT(box);
544 }
545
546 static void
547 ao_lco_search(void)
548 {
549         int8_t          r;
550         int8_t          try;
551         uint8_t         box;
552         uint8_t         boxes = 0;
553
554         ao_lco_box_reset_present();
555         ao_lco_set_pad(0);
556         for (box = 0; box < AO_PAD_MAX_BOXES; box++) {
557                 if ((box % 10) == 0)
558                         ao_lco_set_box(box);
559                 for (try = 0; try < 3; try++) {
560                         ao_lco_tick_offset[box] = 0;
561                         r = ao_lco_query(box, &ao_pad_query, &ao_lco_tick_offset[box]);
562                         PRINTD("box %d result %d offset %d\n", box, r, ao_lco_tick_offset[box]);
563                         if (r == AO_RADIO_CMAC_OK) {
564                                 ++boxes;
565                                 ao_lco_box_set_present(box);
566                                 ao_lco_set_pad(boxes % 10);
567                                 ao_delay(AO_MS_TO_TICKS(30));
568                                 break;
569                         }
570                 }
571         }
572         if (ao_lco_min_box <= ao_lco_max_box)
573                 ao_lco_box = ao_lco_min_box;
574         else
575                 ao_lco_min_box = ao_lco_max_box = ao_lco_box = 0;
576         memset(ao_lco_valid, 0, sizeof (ao_lco_valid));
577         memset(ao_lco_channels, 0, sizeof (ao_lco_channels));
578         ao_lco_pad = 1;
579         ao_lco_set_display();
580 }
581
582 static void
583 ao_lco_igniter_status(void)
584 {
585         uint8_t         c;
586         uint8_t         t = 0;
587
588         for (;;) {
589                 ao_sleep(&ao_pad_query);
590                 PRINTD("RSSI %d VALID %d\n", ao_radio_cmac_rssi, ao_lco_valid[ao_lco_box]);
591                 if (!(ao_lco_valid[ao_lco_box] & AO_LCO_VALID_LAST)) {
592                         ao_led_on(AO_LED_RED);
593                         ao_led_off(AO_LED_GREEN|AO_LED_AMBER);
594                         continue;
595                 }
596                 if (ao_radio_cmac_rssi < -90) {
597                         ao_led_on(AO_LED_AMBER);
598                         ao_led_off(AO_LED_RED|AO_LED_GREEN);
599                 } else {
600                         ao_led_on(AO_LED_GREEN);
601                         ao_led_off(AO_LED_RED|AO_LED_AMBER);
602                 }
603                 if (ao_pad_query.arm_status)
604                         ao_led_on(AO_LED_REMOTE_ARM);
605                 else
606                         ao_led_off(AO_LED_REMOTE_ARM);
607
608                 for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) {
609                         uint8_t status;
610
611                         if (ao_lco_drag_race) {
612                                 if (ao_lco_selected[ao_lco_box] & (1 << c) && t)
613                                         ao_led_on(continuity_led[c]);
614                                 else
615                                         ao_led_off(continuity_led[c]);
616                         } else {
617                                 if (ao_pad_query.channels & (1 << c))
618                                         status = ao_pad_query.igniter_status[c];
619                                 else
620                                         status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN;
621                                 if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN)
622                                         ao_led_on(continuity_led[c]);
623                                 else
624                                         ao_led_off(continuity_led[c]);
625                         }
626                 }
627                 t = 1-t;
628         }
629 }
630
631 static void
632 ao_lco_arm_warn(void)
633 {
634         for (;;) {
635                 while (!ao_lco_armed) {
636                         ao_led_off(AO_LED_FIRE);
637                         ao_sleep(&ao_lco_armed);
638                 }
639                 ao_led_on(AO_LED_FIRE);
640                 ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
641                 ao_delay(AO_MS_TO_TICKS(200));
642         }
643 }
644
645 static struct ao_task ao_lco_input_task;
646 static struct ao_task ao_lco_monitor_task;
647 static struct ao_task ao_lco_arm_warn_task;
648 static struct ao_task ao_lco_igniter_status_task;
649
650 static void
651 ao_lco_monitor(void)
652 {
653         uint16_t                delay;
654         uint8_t                 box;
655
656         ao_lco_search();
657         ao_add_task(&ao_lco_input_task, ao_lco_input, "lco input");
658         ao_add_task(&ao_lco_arm_warn_task, ao_lco_arm_warn, "lco arm warn");
659         ao_add_task(&ao_lco_igniter_status_task, ao_lco_igniter_status, "lco igniter status");
660         ao_add_task(&ao_lco_drag_task, ao_lco_drag_monitor, "drag race");
661         for (;;) {
662                 PRINTD("monitor armed %d firing %d\n",
663                        ao_lco_armed, ao_lco_firing);
664
665                 if (ao_lco_armed && ao_lco_firing) {
666                         ao_lco_ignite(AO_PAD_FIRE);
667                 } else {
668                         ao_lco_update();
669                         if (ao_lco_armed) {
670                                 for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) {
671                                         if (ao_lco_selected[box]) {
672                                                 PRINTD("Arming box %d pads %x\n",
673                                                        box, ao_lco_selected[box]);
674                                                 if (ao_lco_valid[box] & AO_LCO_VALID_EVER) {
675                                                         ao_lco_arm(box, ao_lco_selected[box], ao_lco_tick_offset[box]);
676                                                         ao_delay(AO_MS_TO_TICKS(10));
677                                                 }
678                                         }
679                                 }
680                         }
681                 }
682                 if (ao_lco_armed && ao_lco_firing)
683                         delay = AO_MS_TO_TICKS(100);
684                 else
685                         delay = AO_SEC_TO_TICKS(1);
686                 ao_sleep_for(&ao_lco_armed, delay);
687         }
688 }
689
690 #if DEBUG
691 void
692 ao_lco_set_debug(void)
693 {
694         ao_cmd_decimal();
695         if (ao_cmd_status == ao_cmd_success)
696                 ao_lco_debug = ao_cmd_lex_i != 0;
697 }
698
699 __code struct ao_cmds ao_lco_cmds[] = {
700         { ao_lco_set_debug,     "D <0 off, 1 on>\0Debug" },
701         { ao_lco_search,        "s\0Search for pad boxes" },
702         { 0, NULL }
703 };
704 #endif
705
706 void
707 ao_lco_init(void)
708 {
709         ao_add_task(&ao_lco_monitor_task, ao_lco_monitor, "lco monitor");
710 #if DEBUG
711         ao_cmd_register(&ao_lco_cmds[0]);
712 #endif
713 }