Merge remote-tracking branch 'mjb/master'
[fw/altos] / src / telelco-v0.1 / ao_lco.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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19 #include <ao_lco.h>
20 #include <ao_event.h>
21 #include <ao_seven_segment.h>
22 #include <ao_quadrature.h>
23 #include <ao_lco_func.h>
24 #include <ao_radio_cmac.h>
25
26 #if 1
27 #define PRINTD(...) do { printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0)
28 #else
29 #define PRINTD(...) 
30 #endif
31
32 #define AO_LCO_PAD_DIGIT        0
33 #define AO_LCO_BOX_DIGIT_1      1
34 #define AO_LCO_BOX_DIGIT_10     2
35
36 #define AO_NUM_BOX              10
37
38 static uint8_t  ao_lco_mutex;
39 static uint8_t  ao_lco_pad;
40 static uint8_t  ao_lco_box;
41 static uint8_t  ao_lco_armed;
42 static uint8_t  ao_lco_firing;
43 static uint8_t  ao_lco_valid;
44
45 static void
46 ao_lco_set_pad(void)
47 {
48         ao_seven_segment_set(AO_LCO_PAD_DIGIT, ao_lco_pad);
49 }
50
51 static void
52 ao_lco_set_box(void)
53 {
54         ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, ao_lco_box % 10);
55         ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, ao_lco_box / 10);
56 }
57
58 static void
59 ao_lco_input(void)
60 {
61         static struct ao_event  event;
62
63         ao_lco_set_pad();
64         ao_lco_set_box();
65         for (;;) {
66                 ao_event_get(&event);
67                 PRINTD("event type %d unit %d value %d\n",
68                        event.type, event.unit, event.value);
69                 switch (event.type) {
70                 case AO_EVENT_QUADRATURE:
71                         switch (event.unit) {
72                         case AO_QUADRATURE_PAD:
73                                 if (!ao_lco_armed) {
74                                         ao_lco_pad = event.value & 3;
75                                         ao_lco_valid = 0;
76                                         ao_quadrature_count[AO_QUADRATURE_PAD] = ao_lco_pad;
77                                         ao_lco_set_pad();
78                                 }
79                                 break;
80                         case AO_QUADRATURE_BOX:
81                                 if (!ao_lco_armed) {
82                                         ao_lco_box = event.value;
83                                         ao_lco_valid = 0;
84                                         while (ao_lco_box >= AO_NUM_BOX)
85                                                 ao_lco_box -= AO_NUM_BOX;
86                                         while (ao_lco_box < 0)
87                                                 ao_lco_box += AO_NUM_BOX;
88                                         ao_quadrature_count[AO_QUADRATURE_PAD] = ao_lco_box;
89                                         ao_lco_set_box();
90                                 }
91                                 break;
92                         }
93                         break;
94                 case AO_EVENT_BUTTON:
95                         switch (event.unit) {
96                         case AO_BUTTON_ARM:
97                                 ao_lco_armed = event.value;
98                                 PRINTD("Armed %d\n", ao_lco_armed);
99                                 ao_wakeup(&ao_lco_armed);
100                                 break;
101                         case AO_BUTTON_FIRE:
102                                 if (ao_lco_armed) {
103                                         ao_lco_firing = event.value;
104                                         PRINTD("Firing %d\n", ao_lco_firing);
105                                         ao_wakeup(&ao_lco_armed);
106                                 }
107                                 break;
108                         }
109                         break;
110                 }
111         }
112 }
113
114 static AO_LED_TYPE      continuity_led[AO_LED_CONTINUITY_NUM] = {
115 #ifdef AO_LED_CONTINUITY_0
116         AO_LED_CONTINUITY_0,
117 #endif
118 #ifdef AO_LED_CONTINUITY_1
119         AO_LED_CONTINUITY_1,
120 #endif
121 #ifdef AO_LED_CONTINUITY_2
122         AO_LED_CONTINUITY_2,
123 #endif
124 #ifdef AO_LED_CONTINUITY_3
125         AO_LED_CONTINUITY_3,
126 #endif
127 #ifdef AO_LED_CONTINUITY_4
128         AO_LED_CONTINUITY_4,
129 #endif
130 #ifdef AO_LED_CONTINUITY_5
131         AO_LED_CONTINUITY_5,
132 #endif
133 #ifdef AO_LED_CONTINUITY_6
134         AO_LED_CONTINUITY_6,
135 #endif
136 #ifdef AO_LED_CONTINUITY_7
137         AO_LED_CONTINUITY_7,
138 #endif
139 };
140
141 static uint16_t ao_lco_tick_offset;
142
143 static void
144 ao_lco_update(void)
145 {
146         int8_t                  r;
147         uint8_t                 c;
148         struct ao_pad_query     query;
149
150         r = ao_lco_query(ao_lco_box, &query, &ao_lco_tick_offset);
151         if (r != AO_RADIO_CMAC_OK) {
152                 PRINTD("lco_query return %d\n", r);
153                 return;
154         }
155
156 #if 0
157         PRINTD("lco_query success arm_status %d i0 %d i1 %d i2 %d i3 %d\n",
158                query.arm_status,
159                query.igniter_status[0],
160                query.igniter_status[1],
161                query.igniter_status[2],
162                query.igniter_status[3]);
163 #endif
164
165         ao_lco_valid = 1;
166         if (query.arm_status)
167                 ao_led_on(AO_LED_REMOTE_ARM);
168         else
169                 ao_led_off(AO_LED_REMOTE_ARM);
170         for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) {
171                 uint8_t status;
172
173                 if (query.channels & (1 << c))
174                         status = query.igniter_status[c];
175                 else
176                         status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN;
177                 if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN)
178                         ao_led_on(continuity_led[c]);
179                 else
180                         ao_led_off(continuity_led[c]);
181         }
182 }
183
184 static void
185 ao_lco_monitor(void)
186 {
187         uint16_t                delay;
188
189         for (;;) {
190                 if (ao_lco_armed && ao_lco_firing) {
191                         PRINTD("Firing box %d pad %d: valid %d\n",
192                                ao_lco_box, ao_lco_pad, ao_lco_valid);
193                         if (!ao_lco_valid)
194                                 ao_lco_update();
195                         if (ao_lco_valid)
196                                 ao_lco_ignite(ao_lco_box, ao_lco_pad, ao_lco_tick_offset);
197                 } else {
198                         ao_lco_update();
199                 }
200                 if (ao_lco_armed && ao_lco_firing)
201                         delay = AO_MS_TO_TICKS(100);
202                 else
203                         delay = AO_SEC_TO_TICKS(1);
204                 ao_alarm(delay);
205                 ao_sleep(&ao_lco_armed);
206                 ao_clear_alarm();
207         }
208 }
209
210 static void
211 ao_lco_arm_warn(void)
212 {
213         for (;;) {
214                 while (!ao_lco_armed)
215                         ao_sleep(&ao_lco_armed);
216                 ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
217                 ao_delay(AO_MS_TO_TICKS(200));
218         }
219 }
220
221 static struct ao_task ao_lco_input_task;
222 static struct ao_task ao_lco_monitor_task;
223 static struct ao_task ao_lco_arm_warn_task;
224
225 void
226 ao_lco_init(void)
227 {
228         ao_add_task(&ao_lco_input_task, ao_lco_input, "lco input");
229         ao_add_task(&ao_lco_monitor_task, ao_lco_monitor, "lco monitor");
230         ao_add_task(&ao_lco_arm_warn_task, ao_lco_arm_warn, "lco arm warn");
231 }