altos: Implement remote launch protocol
authorKeith Packard <keithp@keithp.com>
Fri, 22 Jul 2011 03:04:05 +0000 (20:04 -0700)
committerKeith Packard <keithp@keithp.com>
Sat, 27 Aug 2011 19:45:33 +0000 (12:45 -0700)
Uses the radio_cmac module to provide secure communication.
Keeps igniter closed for 500ms.
Provides remote status for arming and ignition.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/ao_launch.c
src/ao_radio_cmac.c
src/ao_telelaunch.c
src/cc1111/ao_ignite.c
src/cc1111/ao_packet_master.c
src/cc1111/ao_timer.c
src/core/ao.h
src/core/ao_cmd.c
src/core/ao_config.c
src/core/ao_task.c

index 4870869e8d248fb147a256830e93da671a4a4900..6c15471928e3fc7c85227c8f0f566b856c662115 100644 (file)
 
 #include "ao.h"
 
+__xdata uint16_t ao_launch_ignite;
+
+static void
+ao_launch_run(void)
+{
+       for (;;) {
+               while (!ao_launch_ignite)
+                       ao_sleep(&ao_launch_ignite);
+               while (ao_launch_ignite) {
+                       ao_launch_ignite = 0;
+
+                       ao_ignition[ao_igniter_drogue].firing = 1;
+                       ao_ignition[ao_igniter_main].firing = 1;
+                       AO_IGNITER_DROGUE = 1;
+                       ao_delay(AO_MS_TO_TICKS(500));
+                       AO_IGNITER_DROGUE = 0;
+                       ao_ignition[ao_igniter_drogue].firing = 0;
+                       ao_ignition[ao_igniter_main].firing = 0;
+               }
+       }
+}
+
+static void
+ao_launch_status(void)
+{
+       uint8_t i;
+       for (;;) {
+               ao_delay(AO_SEC_TO_TICKS(1));
+               if (ao_igniter_status(ao_igniter_drogue) == ao_igniter_ready) {
+                       if (ao_igniter_status(ao_igniter_main) == ao_igniter_ready) {
+                               for (i = 0; i < 5; i++) {
+                                       ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(50));
+                                       ao_delay(AO_MS_TO_TICKS(100));
+                               }
+                       } else {
+                               ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
+                       }
+               }
+       }
+}
+
+static __pdata uint8_t ao_launch_armed;
+static __pdata uint16_t        ao_launch_arm_time;
+
 static void
 ao_launch(void)
 {
-       enum    ao_igniter_status       arm_status, ignite_status;
+       static __xdata struct ao_launch_command command;
+       static __xdata struct ao_launch_query   query;
+       int16_t time_difference;
 
        ao_led_off(AO_LED_RED);
        ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
        for (;;) {
-               arm_status = ao_igniter_status(ao_igniter_drogue);
+               if (ao_radio_cmac_recv(&command, sizeof (command), 0) != AO_RADIO_CMAC_OK)
+                       continue;
+               
+               printf ("tick %d serial %d cmd %d channel %d\n",
+                       command.tick, command.serial, command.cmd, command.channel);
+
+               if (command.serial != ao_serial_number) {
+                       printf ("serial number mismatch\n");
+                       continue;
+               }
 
-               switch (arm_status) {
-               case ao_igniter_unknown:
+               switch (command.cmd) {
+               case AO_LAUNCH_QUERY:
+                       if (command.channel == 0) {
+                               query.valid = 1;
+                               query.arm_status = ao_igniter_status(ao_igniter_drogue);
+                               query.igniter_status = ao_igniter_status(ao_igniter_main);
+                       } else {
+                               query.valid = 0;
+                       }
+                       query.tick = ao_time();
+                       query.serial = ao_serial_number;
+                       query.channel = command.channel;
+                       printf ("query tick %d serial %d channel %d valid %d arm %d igniter %d\n",
+                               query.tick, query.serial, query.channel, query.valid, query.arm_status,
+                               query.igniter_status);
+                       ao_radio_cmac_send(&query, sizeof (query));
                        break;
-               case ao_igniter_active:
-               case ao_igniter_open:
+               case AO_LAUNCH_ARM:
+                       if (command.channel != 0)
+                               break;
+                       time_difference = command.tick - ao_time();
+                       printf ("arm tick %d local tick %d\n", command.tick, ao_time());
+                       if (time_difference < 0)
+                               time_difference = -time_difference;
+                       if (time_difference > 10) {
+                               printf ("time difference too large %d\n", time_difference);
+                               break;
+                       }
+                       printf ("armed\n");
+                       ao_launch_armed = 1;
+                       ao_launch_arm_time = ao_time();
                        break;
-               case ao_igniter_ready:
-                       ignite_status = ao_igniter_status(ao_igniter_main);
-                       switch (ignite_status) {
-                       case ao_igniter_unknown:
-                               /* some kind of failure signal here */
+               case AO_LAUNCH_FIRE:
+                       if (command.channel != 0)
                                break;
-                       case ao_igniter_active:
+                       if (!ao_launch_armed) {
+                               printf ("not armed\n");
                                break;
-                       case ao_igniter_open:
+                       }
+                       if ((uint16_t) (ao_launch_arm_time - ao_time()) > AO_SEC_TO_TICKS(20)) {
+                               printf ("late launch arm_time %d time %d\n",
+                                       ao_launch_arm_time, ao_time());
+                               break;
+                       }
+                       time_difference = command.tick - ao_time();
+                       if (time_difference < 0)
+                               time_difference = -time_difference;
+                       if (time_difference > 10) {
+                               printf ("time different too large %d\n", time_difference);
                                break;
                        }
+                       printf ("ignite\n");
+                       ao_launch_ignite = 1;
+                       ao_wakeup(&ao_launch_ignite);
                        break;
                }
-               ao_delay(AO_SEC_TO_TICKS(1));
        }
 }
 
+void
+ao_launch_test(void)
+{
+       switch (ao_igniter_status(ao_igniter_drogue)) {
+       case ao_igniter_ready:
+       case ao_igniter_active:
+               printf ("Armed: ");
+               switch (ao_igniter_status(ao_igniter_main)) {
+               default:
+                       printf("unknown status\n");
+                       break;
+               case ao_igniter_ready:
+                       printf("igniter good\n");
+                       break;
+               case ao_igniter_open:
+                       printf("igniter bad\n");
+                       break;
+               }
+               break;
+       default:
+               printf("Disarmed\n");
+       }
+}
+
+void
+ao_launch_manual(void)
+{
+       ao_cmd_white();
+       if (!ao_match_word("DoIt"))
+               return;
+       ao_cmd_white();
+       ao_launch_ignite = 1;
+       ao_wakeup(&ao_launch_ignite);
+}
+
 static __xdata struct ao_task ao_launch_task;
+static __xdata struct ao_task ao_launch_ignite_task;
+static __xdata struct ao_task ao_launch_status_task;
+
+__code struct ao_cmds ao_launch_cmds[] = {
+       { ao_launch_test,       "t\0Test launch continuity" },
+       { ao_launch_manual,     "i <key>\0Fire igniter. <key> is doit with D&I" },
+       { 0, NULL }
+};
 
 void
 ao_launch_init(void)
 {
-       ao_add_task(&ao_launch_task, ao_launch, "launch status");
+       AO_IGNITER_DROGUE = 0;
+       AO_IGNITER_MAIN = 0;
+       AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;
+       ao_cmd_register(&ao_launch_cmds[0]);
+       ao_add_task(&ao_launch_task, ao_launch, "launch listener");
+       ao_add_task(&ao_launch_ignite_task, ao_launch_run, "launch igniter");
+       ao_add_task(&ao_launch_status_task, ao_launch_status, "launch status");
 }
index 7648a2f599b46cc08f67022b95a3bafb214ea2bf..9694b5b3ef7d20cb989d1954d362b16d668bf78c 100644 (file)
 
 #include "ao.h"
 
-#define AO_CMAC_KEY_LEN                16
+#define AO_CMAC_KEY_LEN                AO_AES_LEN
 #define AO_CMAC_MAX_LEN                (128 - AO_CMAC_KEY_LEN)
 
-static __xdata uint8_t cmac_key[AO_CMAC_KEY_LEN];
+static __xdata uint8_t ao_radio_cmac_mutex;
 static __xdata uint8_t cmac_data[AO_CMAC_MAX_LEN + AO_CMAC_KEY_LEN + 2 + AO_CMAC_KEY_LEN];
 static __pdata uint8_t ao_radio_cmac_len;
 
 static uint8_t
 getnibble(void)
 {
-       __pdata char    c;
-
-       c = getchar();
-       if ('0' <= c && c <= '9')
-               return c - '0';
-       if ('a' <= c && c <= 'f')
-               return c - ('a' - 10);
-       if ('A' <= c && c <= 'F')
-               return c - ('A' - 10);
-       ao_cmd_status = ao_cmd_lex_error;
-       return 0;
+       int8_t  b;
+
+       b = ao_cmd_hexchar(getchar());
+       if (b < 0) {
+               ao_cmd_status = ao_cmd_lex_error;
+               return 0;
+       }
+       return (uint8_t) b;
 }
 
 static uint8_t
@@ -49,20 +46,137 @@ getbyte(void)
        return b;
 }
        
+static uint8_t
+round_len(uint8_t len)
+{
+       uint8_t rem;
+
+       /* Make sure we transfer at least one packet, and
+        * then make sure every packet is full. Note that
+        * there is no length encoded, and that the receiver
+        * must deal with any extra bytes in the packet
+        */
+       if (len < AO_CMAC_KEY_LEN)
+               len = AO_CMAC_KEY_LEN;
+       rem = len % AO_CMAC_KEY_LEN;
+       if (rem != 0)
+               len += (AO_CMAC_KEY_LEN - rem);
+       return len;
+}
+
+/*
+ * Sign and deliver the data sitting in the cmac buffer
+ */
 static void
-ao_radio_cmac_key(void) __reentrant
+radio_cmac_send(uint8_t len) __reentrant
 {
        uint8_t i;
 
-       for (i = 0; i < AO_CMAC_KEY_LEN; i++) {
-               cmac_key[i] = getbyte();
-               if (ao_cmd_status != ao_cmd_success)
-                       return;
+       len = round_len(len);
+       /* Make sure the AES key is loaded */
+       ao_config_get();
+
+#if HAS_MONITOR
+       ao_set_monitor(0);
+#endif
+
+       ao_mutex_get(&ao_aes_mutex);
+       ao_aes_set_mode(ao_aes_mode_cbc_mac);
+       ao_aes_set_key(ao_config.aes_key);
+       ao_aes_zero_iv();
+       for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
+               if (i + AO_CMAC_KEY_LEN < len)
+                       ao_aes_run(&cmac_data[i], NULL);
+               else
+                       ao_aes_run(&cmac_data[i], &cmac_data[len]);
        }
+       ao_mutex_put(&ao_aes_mutex);
+
+       ao_radio_send(cmac_data, len + AO_CMAC_KEY_LEN);
+}
+
+/*
+ * Receive and validate an incoming packet
+ */
+
+static int8_t
+radio_cmac_recv(uint8_t len, uint16_t timeout) __reentrant
+{
+       uint8_t i;
+
+       len = round_len(len);
+#if HAS_MONITOR
+       ao_set_monitor(0);
+#endif
+       if (timeout)
+               ao_alarm(timeout);
+
+       i = ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2);
+       ao_clear_alarm();
+
+       if (!i)
+               return AO_RADIO_CMAC_TIMEOUT;
+
+       if (!(cmac_data[len + AO_CMAC_KEY_LEN +1] & PKT_APPEND_STATUS_1_CRC_OK))
+               return AO_RADIO_CMAC_CRC_ERROR;
+
+       ao_config_get();
+
+       /* Compute the packet signature
+        */
+       ao_mutex_get(&ao_aes_mutex);
+       ao_aes_set_mode(ao_aes_mode_cbc_mac);
+       ao_aes_set_key(ao_config.aes_key);
+       ao_aes_zero_iv();
+       for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
+               if (i + AO_CMAC_KEY_LEN < len)
+                       ao_aes_run(&cmac_data[i], NULL);
+               else
+                       ao_aes_run(&cmac_data[i], &cmac_data[len + AO_CMAC_KEY_LEN + 2]);
+       }
+       ao_mutex_put(&ao_aes_mutex);
+
+       /* Check the packet signature against the signature provided
+        * over the link
+        */
+        
+       if (memcmp(&cmac_data[len],
+                  &cmac_data[len + AO_CMAC_KEY_LEN + 2],
+                  AO_CMAC_KEY_LEN) != 0) {
+               return AO_RADIO_CMAC_MAC_ERROR;
+       }
+
+       return AO_RADIO_CMAC_OK;
+}
+
+int8_t
+ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant
+{
+       if (len > AO_CMAC_MAX_LEN)
+               return AO_RADIO_CMAC_LEN_ERROR;
+       ao_mutex_get(&ao_radio_cmac_mutex);
+       memcpy(cmac_data, packet, len);
+       radio_cmac_send(len);
+       ao_mutex_put(&ao_radio_cmac_mutex);
+       return AO_RADIO_CMAC_OK;
+}
+
+int8_t
+ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant
+{
+       uint8_t i;
+       if (len > AO_CMAC_MAX_LEN)
+               return AO_RADIO_CMAC_LEN_ERROR;
+       ao_mutex_get(&ao_radio_cmac_mutex);
+       i = radio_cmac_recv(len, timeout);
+       if (i == AO_RADIO_CMAC_OK)
+               memcpy(packet, cmac_data, len);
+       ao_mutex_put(&ao_radio_cmac_mutex);
+       return i;
 }
 
 static void
-ao_radio_cmac_send(void) __reentrant
+radio_cmac_send_cmd(void) __reentrant
 {
        uint8_t i;
        uint8_t len;
@@ -70,43 +184,25 @@ ao_radio_cmac_send(void) __reentrant
        ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
                return;
-       if (ao_cmd_lex_i < AO_CMAC_KEY_LEN ||
-           ao_cmd_lex_i > AO_CMAC_MAX_LEN ||
-           ao_cmd_lex_i % AO_CMAC_KEY_LEN != 0)
-       {
+       len = ao_cmd_lex_i;
+       if (len > AO_CMAC_MAX_LEN) {
                ao_cmd_status = ao_cmd_syntax_error;
                return;
        }
        flush();
+       ao_mutex_get(&ao_radio_cmac_mutex);
        len = ao_cmd_lex_i;
        for (i = 0; i < len; i++) {
                cmac_data[i] = getbyte();
                if (ao_cmd_status != ao_cmd_success)
                        return;
        }
-       ao_mutex_get(&ao_aes_mutex);
-       ao_aes_set_mode(ao_aes_mode_cbc_mac);
-       ao_aes_set_key(cmac_key);
-       ao_aes_zero_iv();
-       for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
-               if (i + AO_CMAC_KEY_LEN < len)
-                       ao_aes_run(&cmac_data[i], NULL);
-               else
-                       ao_aes_run(&cmac_data[i], &cmac_data[len]);
-       }
-       ao_mutex_put(&ao_aes_mutex);
-#if HAS_MONITOR
-       ao_set_monitor(0);
-#endif
-       printf("send:");
-       for (i = 0; i < len + AO_CMAC_KEY_LEN; i++)
-               printf(" %02x", cmac_data[i]);
-       printf("\n"); flush();
-       ao_radio_send(cmac_data, len + AO_CMAC_KEY_LEN);
+       radio_cmac_send(len);
+       ao_mutex_put(&ao_radio_cmac_mutex);
 }
 
 static void
-ao_radio_cmac_recv(void) __reentrant
+radio_cmac_recv_cmd(void) __reentrant
 {
        uint8_t         len, i;
        uint16_t        timeout;
@@ -114,47 +210,79 @@ ao_radio_cmac_recv(void) __reentrant
        ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
                return;
-       if (ao_cmd_lex_i < AO_CMAC_KEY_LEN ||
-           ao_cmd_lex_i > AO_CMAC_MAX_LEN ||
-           ao_cmd_lex_i % AO_CMAC_KEY_LEN != 0)
-       {
-               ao_cmd_status = ao_cmd_syntax_error;
-               return;
-       }
        len = ao_cmd_lex_i;
        ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
                return;
-       timeout = ao_cmd_lex_i;
-#if HAS_MONITOR
-       ao_set_monitor(0);
-#endif
-       if (timeout)
-               ao_alarm(timeout);
-       if (!ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2)) {
-               printf("timeout\n");
+       timeout = AO_MS_TO_TICKS(ao_cmd_lex_i);
+       ao_mutex_get(&ao_radio_cmac_mutex);
+       i = radio_cmac_recv(len, timeout);
+       if (i == AO_RADIO_CMAC_OK) {
+               printf ("PACKET ");
+               for (i = 0; i < len; i++)
+                       printf("%02x", cmac_data[i]);
+               printf ("\n");
+       } else
+               printf ("ERROR %d\n", i);
+       ao_mutex_put(&ao_radio_cmac_mutex);
+}
+
+static void
+launch_report_cmd(void) __reentrant
+{
+       static __xdata struct ao_launch_command command;
+       static __xdata struct ao_launch_query   query;
+       uint8_t         channel;
+       uint16_t        serial;
+       uint8_t         i;
+
+       ao_cmd_decimal();
+       serial = ao_cmd_lex_i;
+       ao_cmd_decimal();
+       channel = ao_cmd_lex_i;
+       if (ao_cmd_status != ao_cmd_success)
                return;
+       flush();
+       for (i = 0; i < 10; i++) {
+               printf ("."); flush();
+               command.tick = 0;
+               command.serial = serial;
+               command.cmd = AO_LAUNCH_QUERY;
+               command.channel = channel;
+               ao_radio_cmac_send(&command, sizeof (command));
+               switch (ao_radio_cmac_recv(&query, sizeof (query), AO_MS_TO_TICKS(500))) {
+               case AO_RADIO_CMAC_OK:
+                       printf("\n");
+                       switch (query.arm_status) {
+                       case ao_igniter_ready:
+                       case ao_igniter_active:
+                               printf ("Armed: ");
+                               switch (query.igniter_status) {
+                               default:
+                                       printf("unknown status\n");
+                                       break;
+                               case ao_igniter_ready:
+                                       printf("igniter good\n");
+                                       break;
+                               case ao_igniter_open:
+                                       printf("igniter bad\n");
+                                       break;
+                               }
+                       default:
+                               printf("Disarmed\n");
+                       }
+                       return;
+               default:
+                       continue;
+               }
        }
-       ao_mutex_get(&ao_aes_mutex);
-       ao_aes_set_mode(ao_aes_mode_cbc_mac);
-       ao_aes_set_key(cmac_key);
-       ao_aes_zero_iv();
-       for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
-               if (i + AO_CMAC_KEY_LEN < len)
-                       ao_aes_run(&cmac_data[i], NULL);
-               else
-                       ao_aes_run(&cmac_data[i], &cmac_data[len + AO_CMAC_KEY_LEN + 2]);
-       }
-       printf ("PACKET ");
-       for (i = 0; i < len + AO_CMAC_KEY_LEN + 2 + AO_CMAC_KEY_LEN; i++)
-               printf("%02x", cmac_data[i]);
-       printf ("\n");
+       printf ("Timeout\n");
 }
 
 static __code struct ao_cmds ao_radio_cmac_cmds[] = {
-       { ao_radio_cmac_key,    "k\0Set AES-CMAC key. 16 key bytes follow on next line" },
-       { ao_radio_cmac_send,   "s <length>\0Send AES-CMAC packet. Bytes to send follow on next line" },
-       { ao_radio_cmac_recv,   "S <length> <timeout>\0Receive AES-CMAC packet. Timeout in ms" },
+       { radio_cmac_send_cmd,  "s <length>\0Send AES-CMAC packet. Bytes to send follow on next line" },
+       { radio_cmac_recv_cmd,  "S <length> <timeout>\0Receive AES-CMAC packet. Timeout in ms" },
+       { launch_report_cmd,    "l <serial> <channel>\0Get remote launch status" },
        { 0, NULL },
 };
 
index b5404710d6d8f758f5e48f38af31955c4ec3b888..506431ded9245778734002f99c4b99ebc71ad820 100644 (file)
@@ -35,7 +35,6 @@ main(void)
        ao_storage_init();
        ao_usb_init();
        ao_radio_init();
-       ao_igniter_init();
 #if HAS_DBG
        ao_dbg_init();
 #endif
index 5238beb4315663950e717f98629168b05bc4a419..0fd2b4bff389396a6cae1318512da2b23f729e6b 100644 (file)
 #define AO_IGNITER_FIRE_TIME   AO_MS_TO_TICKS(50)
 #define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000)
 
-struct ao_ignition {
-       uint8_t request;
-       uint8_t fired;
-       uint8_t firing;
-};
-
 __xdata struct ao_ignition ao_ignition[2];
 
 void
index b0fdf5a8804288386651c070ba6f5be8f7f703fc..0d0be30ea2faa5f02e2e320a99cf7224f9ff9068 100644 (file)
@@ -80,13 +80,16 @@ ao_packet_master(void)
        ao_packet_master_time = ao_time();
        ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT;
        while (ao_packet_enable) {
+               uint8_t r;
                memcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN);
                ao_packet_send();
                if (ao_tx_packet.len)
                        ao_packet_master_busy();
                ao_packet_master_check_busy();
                ao_alarm(ao_packet_master_delay);
-               if (ao_packet_recv()) {
+               r = ao_packet_recv();
+               ao_clear_alarm();
+               if (r) {
                        /* if we can transmit data, do so */
                        if (ao_packet_tx_used && ao_tx_packet.len == 0)
                                continue;
@@ -95,6 +98,7 @@ ao_packet_master(void)
                        ao_packet_master_sleeping = 1;
                        ao_alarm(ao_packet_master_delay);
                        ao_sleep(&ao_packet_master_sleeping);
+                       ao_clear_alarm();
                        ao_packet_master_sleeping = 0;
                }
        }
index c977fbc8b85a2f997c38e48df05f857306bac658..aadee71e239e324a8b7644fe70872148e615f5d9 100644 (file)
@@ -31,6 +31,7 @@ ao_delay(uint16_t ticks)
 {
        ao_alarm(ticks);
        ao_sleep(&ao_forever);
+       ao_clear_alarm();
 }
 
 #define T1_CLOCK_DIVISOR       8       /* 24e6/8 = 3e6 */
index 2898852b974f9f14dd570a7c21d7e04913848cfa..a5bbb6f1fce51433ffb985a651a2670fca43cadf 100644 (file)
@@ -68,6 +68,10 @@ ao_wakeup(__xdata void *wchan);
 void
 ao_alarm(uint16_t delay);
 
+/* Clear any pending alarm */
+void
+ao_clear_alarm(void);
+
 /* Yield the processor to another task */
 void
 ao_yield(void) ao_arch_naked_declare;
@@ -342,6 +346,12 @@ ao_cmd_put16(uint16_t v);
 void
 ao_cmd_white(void);
 
+int8_t
+ao_cmd_hexchar(char c);
+
+void
+ao_cmd_hexbyte(void);
+
 void
 ao_cmd_hex(void);
 
@@ -1417,6 +1427,14 @@ enum ao_igniter_status {
        ao_igniter_open,        /* open circuit detected */
 };
 
+struct ao_ignition {
+       uint8_t request;
+       uint8_t fired;
+       uint8_t firing;
+};
+
+extern __xdata struct ao_ignition ao_ignition[2];
+
 enum ao_igniter_status
 ao_igniter_status(enum ao_igniter igniter);
 
@@ -1431,7 +1449,8 @@ ao_igniter_init(void);
  */
 
 #define AO_CONFIG_MAJOR        1
-#define AO_CONFIG_MINOR        8
+#define AO_CONFIG_MINOR        9
+#define AO_AES_LEN 16
 
 struct ao_config {
        uint8_t         major;
@@ -1448,6 +1467,7 @@ struct ao_config {
        uint8_t         pad_orientation;        /* minor version 6 */
        uint32_t        radio_setting;          /* minor version 7 */
        uint8_t         radio_enable;           /* minor version 8 */
+       uint8_t         aes_key[AO_AES_LEN];    /* minor version 9 */
 };
 
 #define AO_IGNITE_MODE_DUAL            0
@@ -1635,8 +1655,6 @@ __xdata uint8_t ao_aes_mutex;
 
 /* AES keys and blocks are 128 bits */
 
-#define AO_AES_LEN     16
-
 enum ao_aes_mode {
        ao_aes_mode_cbc_mac
 };
@@ -1664,10 +1682,45 @@ ao_aes_init(void);
 
 /* ao_radio_cmac.c */
 
+int8_t
+ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant;
+
+#define AO_RADIO_CMAC_OK       0
+#define AO_RADIO_CMAC_LEN_ERROR        -1
+#define AO_RADIO_CMAC_CRC_ERROR        -2
+#define AO_RADIO_CMAC_MAC_ERROR        -3
+#define AO_RADIO_CMAC_TIMEOUT  -4
+
+int8_t
+ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant;
+
 void
 ao_radio_cmac_init(void);
 
 /* ao_launch.c */
+
+struct ao_launch_command {
+       uint16_t        tick;
+       uint16_t        serial;
+       uint8_t         cmd;
+       uint8_t         channel;
+       uint16_t        unused;
+};
+
+#define AO_LAUNCH_QUERY                1
+
+struct ao_launch_query {
+       uint16_t        tick;
+       uint16_t        serial;
+       uint8_t         channel;
+       uint8_t         valid;
+       uint8_t         arm_status;
+       uint8_t         igniter_status;
+};
+
+#define AO_LAUNCH_ARM          2
+#define AO_LAUNCH_FIRE         3
+
 void
 ao_launch_init(void);
 
index 7663d87533a5771e205f121c388e84e3ce3cc1d0..9e14c221441096f77b2bcf943ed8c1fda5ee0c14 100644 (file)
@@ -22,7 +22,7 @@ __pdata uint32_t ao_cmd_lex_u32;
 __pdata char   ao_cmd_lex_c;
 __pdata enum ao_cmd_status ao_cmd_status;
 
-#define CMD_LEN        32
+#define CMD_LEN        48
 
 static __xdata char    cmd_line[CMD_LEN];
 static __pdata uint8_t cmd_len;
@@ -128,22 +128,48 @@ ao_cmd_white(void)
                ao_cmd_lex();
 }
 
+int8_t
+ao_cmd_hexchar(char c)
+{
+       if ('0' <= c && c <= '9')
+               return (c - '0');
+       if ('a' <= c && c <= 'f')
+               return (c - 'a' + 10);
+       if ('A' <= c && c <= 'F')
+               return (c - 'A' + 10);
+       return -1;
+}
+
+void
+ao_cmd_hexbyte(void)
+{
+       uint8_t i;
+       int8_t  n;
+
+       ao_cmd_lex_i = 0;
+       ao_cmd_white();
+       for (i = 0; i < 2; i++) {
+               n = ao_cmd_hexchar(ao_cmd_lex_c);
+               if (n < 0) {
+                       ao_cmd_status = ao_cmd_syntax_error;
+                       break;
+               }
+               ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
+               ao_cmd_lex();
+       }
+}
+
 void
 ao_cmd_hex(void)
 {
        __pdata uint8_t r = ao_cmd_lex_error;
-       uint8_t n;
+       int8_t  n;
 
        ao_cmd_lex_i = 0;
        ao_cmd_white();
        for(;;) {
-               if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
-                       n = (ao_cmd_lex_c - '0');
-               else if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f')
-                       n = (ao_cmd_lex_c - 'a' + 10);
-               else if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F')
-                       n = (ao_cmd_lex_c - 'A' + 10);
-               else
+               n = ao_cmd_hexchar(ao_cmd_lex_c);
+               if (n < 0)
                        break;
                ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
                r = ao_cmd_success;
index ec2b61f6b7c1367549a0601c766e9d5380607c85..7f999feb10ea2612f1fcfd87953c3654481f22bd 100644 (file)
@@ -74,11 +74,14 @@ _ao_config_get(void)
        if (ao_config.major != AO_CONFIG_MAJOR) {
                ao_config.major = AO_CONFIG_MAJOR;
                ao_config.minor = 0;
+
+               /* Version 0 stuff */
                ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY;
                ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL;
                memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign));
                memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN,
                       sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
+               ao_config_dirty = 1;
        }
        if (ao_config.minor < AO_CONFIG_MINOR) {
                /* Fixups for minor version 1 */
@@ -104,6 +107,8 @@ _ao_config_get(void)
                        ao_config.radio_setting = ao_config.radio_cal;
                if (ao_config.minor < 8)
                        ao_config.radio_enable = TRUE;
+               if (ao_config.minor < 9)
+                       memset(&ao_config.aes_key, '\0', AO_AES_LEN);
                ao_config.minor = AO_CONFIG_MINOR;
                ao_config_dirty = 1;
        }
@@ -414,6 +419,33 @@ ao_config_radio_enable_set(void) __reentrant
        _ao_config_edit_finish();
 }
        
+#if HAS_AES
+void
+ao_config_key_show(void) __reentrant
+{
+       uint8_t i;
+       printf("AES key: ");
+       for (i = 0; i < AO_AES_LEN; i++)
+               printf ("%02x", ao_config.aes_key[i]);
+       printf("\n");
+}
+
+void
+ao_config_key_set(void) __reentrant
+{
+       uint8_t i;
+
+       _ao_config_edit_start();
+       for (i = 0; i < AO_AES_LEN; i++) {
+               ao_cmd_hexbyte();
+               if (ao_cmd_status != ao_cmd_success)
+                       break;
+               ao_config.aes_key[i] = ao_cmd_lex_i;
+       }
+       _ao_config_edit_finish();
+}
+#endif
+
 struct ao_config_var {
        __code char     *str;
        void            (*set)(void) __reentrant;
@@ -461,6 +493,10 @@ __code struct ao_config_var ao_config_vars[] = {
 #if HAS_ACCEL
        { "o <0 antenna up, 1 antenna down>\0Set pad orientation",
          ao_config_pad_orientation_set,ao_config_pad_orientation_show },
+#endif
+#if HAS_AES
+       { "k <32 hex digits>\0Set AES encryption key",
+         ao_config_key_set, ao_config_key_show },
 #endif
        { "s\0Show",
          ao_config_show,               0 },
index 32826114c4e5e855fa6e1159378c57321cb2c9ae..a19a6a6f5e62f1f484ea09991c89d30cae9c7b79 100644 (file)
@@ -107,7 +107,6 @@ ao_sleep(__xdata void *wchan)
                ao_cur_task->wchan = wchan;
                );
        ao_yield();
-       ao_cur_task->alarm = 0;
        if (ao_cur_task->wchan) {
                ao_cur_task->wchan = NULL;
                return 1;
@@ -135,6 +134,12 @@ ao_alarm(uint16_t delay)
                ao_cur_task->alarm = 1;
 }
 
+void
+ao_clear_alarm(void)
+{
+       ao_cur_task->alarm = 0;
+}
+
 void
 ao_exit(void)
 {