altos: Split out LCO functions from ao_radio_cmac.c to ao_lco.c
[fw/altos] / src / drivers / 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
21 static __xdata struct ao_launch_command command;
22 static __xdata struct ao_launch_query   query;
23 static __pdata uint16_t launch_serial;
24 static __pdata uint8_t  launch_channel;
25 static __pdata uint16_t tick_offset;
26
27 static void
28 launch_args(void) __reentrant
29 {
30         ao_cmd_decimal();
31         launch_serial = ao_cmd_lex_i;
32         ao_cmd_decimal();
33         launch_channel = ao_cmd_lex_i;
34 }
35
36 static int8_t
37 launch_query(void)
38 {
39         uint8_t i;
40         int8_t  r = AO_RADIO_CMAC_OK;
41
42         tick_offset = ao_time();
43         for (i = 0; i < 10; i++) {
44                 printf ("."); flush();
45                 command.tick = ao_time();
46                 command.serial = launch_serial;
47                 command.cmd = AO_LAUNCH_QUERY;
48                 command.channel = launch_channel;
49                 ao_radio_cmac_send(&command, sizeof (command));
50                 r = ao_radio_cmac_recv(&query, sizeof (query), AO_MS_TO_TICKS(500));
51                 if (r == AO_RADIO_CMAC_OK)
52                         break;
53         }
54         tick_offset -= query.tick;
55         printf("\n"); flush();
56         return r;
57 }
58
59 static void
60 launch_report_cmd(void) __reentrant
61 {
62         int8_t          r;
63
64         launch_args();
65         if (ao_cmd_status != ao_cmd_success)
66                 return;
67         r = launch_query();
68         switch (r) {
69         case AO_RADIO_CMAC_OK:
70                 if (query.valid) {
71                         switch (query.arm_status) {
72                         case ao_igniter_ready:
73                         case ao_igniter_active:
74                                 printf ("Armed: ");
75                                 break;
76                         default:
77                                 printf("Disarmed: ");
78                         }
79                         switch (query.igniter_status) {
80                         default:
81                                 printf("unknown\n");
82                                 break;
83                         case ao_igniter_ready:
84                                 printf("igniter good\n");
85                                 break;
86                         case ao_igniter_open:
87                                 printf("igniter bad\n");
88                                 break;
89                         }
90                 } else {
91                         printf("Invalid channel %d\n", launch_channel);
92                 }
93                 printf("Rssi: %d\n", ao_radio_cmac_rssi);
94                 break;
95         default:
96                 printf("Error %d\n", r);
97                 break;
98         }
99 }
100
101 static void
102 launch_arm(void) __reentrant
103 {
104         command.tick = ao_time() - tick_offset;
105         command.serial = launch_serial;
106         command.cmd = AO_LAUNCH_ARM;
107         command.channel = launch_channel;
108         ao_radio_cmac_send(&command, sizeof (command));
109 }
110
111 static void
112 launch_ignite(void) __reentrant
113 {
114         command.tick = ao_time() - tick_offset;
115         command.serial = launch_serial;
116         command.cmd = AO_LAUNCH_FIRE;
117         command.channel = 0;
118         ao_radio_cmac_send(&command, sizeof (command));
119 }
120
121 static void
122 launch_fire_cmd(void) __reentrant
123 {
124         static __xdata struct ao_launch_command command;
125         uint8_t         secs;
126         uint8_t         i;
127         int8_t          r;
128
129         launch_args();
130         ao_cmd_decimal();
131         secs = ao_cmd_lex_i;
132         if (ao_cmd_status != ao_cmd_success)
133                 return;
134         r = launch_query();
135         if (r != AO_RADIO_CMAC_OK) {
136                 printf("query failed %d\n", r);
137                 return;
138         }
139
140         for (i = 0; i < 4; i++) {
141                 printf("arm %d\n", i); flush();
142                 launch_arm();
143         }
144
145         secs = secs * 10 - 5;
146         if (secs > 100)
147                 secs = 100;
148         for (i = 0; i < secs; i++) {
149                 printf("fire %d\n", i); flush();
150                 launch_ignite();
151                 ao_delay(AO_MS_TO_TICKS(100));
152         }
153 }
154
155 static void
156 launch_arm_cmd(void) __reentrant
157 {
158         uint8_t i;
159         int8_t  r;
160         launch_args();
161         r = launch_query();
162         if (r != AO_RADIO_CMAC_OK) {
163                 printf("query failed %d\n", r);
164                 return;
165         }
166         for (i = 0; i < 4; i++)
167                 launch_arm();
168 }
169
170 static void
171 launch_ignite_cmd(void) __reentrant
172 {
173         uint8_t i;
174         launch_args();
175         for (i = 0; i < 4; i++)
176                 launch_ignite();
177 }
178
179 static __code struct ao_cmds ao_lco_cmds[] = {
180         { radio_cmac_send_cmd,  "s <length>\0Send AES-CMAC packet. Bytes to send follow on next line" },
181         { radio_cmac_recv_cmd,  "S <length> <timeout>\0Receive AES-CMAC packet. Timeout in ms" },
182         { launch_report_cmd,    "l <serial> <channel>\0Get remote launch status" },
183         { launch_fire_cmd,      "f <serial> <channel> <secs>\0Fire remote igniter" },
184         { launch_arm_cmd,       "a <serial> <channel>\0Arm remote igniter" },
185         { launch_ignite_cmd,    "i <serial> <channel>\0Pulse remote igniter" },
186         { 0, NULL },
187 };
188
189 void
190 ao_lco_init(void)
191 {
192         ao_cmd_register(&ao_lco_cmds[0]);
193 }