altos: SPI radio - use 1->0 for 'done' and 0->1 for 'ready'
authorKeith Packard <keithp@keithp.com>
Wed, 29 Aug 2012 18:23:13 +0000 (11:23 -0700)
committerKeith Packard <keithp@keithp.com>
Wed, 29 Aug 2012 18:23:13 +0000 (11:23 -0700)
This changes how the SPI radio protocol uses the interrupt
line. Instead of a pulse indicating operation done, this now uses a 0
value for done and a 1 value for ready. The key distinction is that
the master can tell when the slave is waiting for the next command
instead of hoping that it got done 'soon enough'.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/drivers/ao_radio_master.c
src/drivers/ao_radio_slave.c

index bfbcb1f8d757e7336806f1b0fdb60a805a801624..73ac3c03803e06425f3f711d59ff29fa6d022e28 100644 (file)
 
 static __xdata struct ao_radio_spi_reply       ao_radio_spi_reply;
 static __xdata struct ao_radio_spi_request     ao_radio_spi_request;
-static volatile __xdata uint8_t                        ao_radio_done = 1;
+static volatile __xdata uint8_t                        ao_radio_wait_mode;
+static volatile __xdata uint8_t                        ao_radio_done = 0;
+static volatile __xdata uint8_t                        ao_radio_ready = 1;
 static __xdata uint8_t                         ao_radio_mutex;
+static __xdata uint8_t                         ao_radio_aes_seq;
 
 __xdata int8_t                                 ao_radio_cmac_rssi;
 
 #if 0
-#define PRINTD(...) do { printf ("\r%s: ", __func__); printf(__VA_ARGS__); flush(); } while(0)
+#define PRINTD(...) do { printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0)
 #else
 #define PRINTD(...) 
 #endif
@@ -36,24 +39,18 @@ __xdata int8_t                                      ao_radio_cmac_rssi;
 static void
 ao_radio_isr(void)
 {
-       ao_exti_disable(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN);
-       ao_radio_done = 1;
-       ao_wakeup((void *) &ao_radio_done);
-}
-
-static void
-ao_radio_master_delay(void)
-{
-//     uint16_t        i;
-//     for (i = 0; i < 1000; i++)
-//             ao_arch_nop();
-       ao_delay(1);
+       if (ao_gpio_get(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN, AO_RADIO_INT)) {
+               ao_radio_ready = 1;
+               ao_wakeup((void *) &ao_radio_ready);
+       } else {
+               ao_radio_done = 1;
+               ao_wakeup((void *) &ao_radio_done);
+       }
 }
 
 static void
 ao_radio_master_start(void)
 {
-       ao_radio_master_delay();
        ao_spi_get_bit(AO_RADIO_CS_PORT, AO_RADIO_CS_PIN, AO_RADIO_CS,
                       AO_RADIO_SPI_BUS,
                       AO_SPI_SPEED_200kHz);
@@ -64,32 +61,50 @@ ao_radio_master_stop(void)
 {
        ao_spi_put_bit(AO_RADIO_CS_PORT, AO_RADIO_CS_PIN, AO_RADIO_CS,
                       AO_RADIO_SPI_BUS);
-//     ao_delay(1);
 }
 
 static uint8_t
 ao_radio_master_send(void)
 {
-       if (!ao_radio_done)
-               printf ("radio not done in ao_radio_master_send\n");
+       uint8_t ret;
+
        PRINTD("send %d\n", ao_radio_spi_request.len);
        ao_radio_done = 0;
-       ao_exti_enable(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN);
+
+       /* Wait for radio chip to be ready for a command
+        */
+
+       PRINTD("Waiting radio ready\n");
+       cli();
+       ao_radio_ready = ao_gpio_get(AO_RADIO_INT_PORT,
+                                    AO_RADIO_INT_PIN, AO_RADIO_INT);
+       ret = 0;
+       while (!ao_radio_ready) {
+               ret = ao_sleep((void *) &ao_radio_ready);
+               if (ret)
+                       break;
+       }
+       sei();
+       if (ret)
+               return 0;
+
+       PRINTD("radio_ready %d radio_done %d\n", ao_radio_ready, ao_radio_done);
+
+       /* Send the command
+        */
+       ao_radio_wait_mode = 0;
        ao_radio_master_start();
        ao_spi_send(&ao_radio_spi_request,
                    ao_radio_spi_request.len,
                    AO_RADIO_SPI_BUS);
        ao_radio_master_stop();
+       PRINTD("waiting for send done %d\n", ao_radio_done);
        cli();
        while (!ao_radio_done)
-               if (ao_sleep((void *) &ao_radio_done)) {
-                       printf ("ao_radio_master awoken\n");
+               if (ao_sleep((void *) &ao_radio_done))
                        break;
-               }
        sei();
-       PRINTD ("sent, radio done %d\n", ao_radio_done);
-       if (!ao_radio_done)
-               printf ("radio didn't finish after ao_radio_master_send\n");
+       PRINTD ("sent, radio done %d isr_0 %d isr_1 %d\n", ao_radio_done, isr_0_count, isr_1_count);
        return ao_radio_done;
 }
 
@@ -112,15 +127,6 @@ ao_radio_put(void)
 static void
 ao_radio_get_data(__xdata void *d, uint8_t size)
 {
-       uint8_t ret;
-
-       PRINTD ("send fetch req\n");
-       ao_radio_spi_request.len = AO_RADIO_SPI_REQUEST_HEADER_LEN;
-       ao_radio_spi_request.request = AO_RADIO_SPI_RECV_FETCH;
-       ao_radio_spi_request.recv_len = size;
-       ret = ao_radio_master_send();
-       PRINTD ("fetch req sent %d\n", ret);
-
        PRINTD ("fetch\n");
        ao_radio_master_start();
        ao_spi_recv(&ao_radio_spi_reply,
@@ -167,21 +173,17 @@ ao_radio_recv(__xdata void *d, uint8_t size)
                return 0;
        }
        ao_radio_get_data(d, size);
-
        recv = ao_radio_spi_reply.status;
-
        ao_radio_put();
 
        return recv;
 }
 
-int8_t
-ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant
+static void
+ao_radio_cmac_set_key(void)
 {
-       if (len > AO_CMAC_MAX_LEN)
-               return AO_RADIO_CMAC_LEN_ERROR;
-
-       PRINTD ("cmac_send: send %d\n", len);
+       if (ao_radio_aes_seq == ao_config_aes_seq)
+               return;
        /* Set the key.
         */
        PRINTD ("set key\n");
@@ -190,6 +192,18 @@ ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant
        ao_radio_master_send();
        ao_radio_put();
        PRINTD ("key set\n");
+       ao_radio_aes_seq = ao_config_aes_seq;
+}
+
+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_radio_cmac_set_key();
+
+       PRINTD ("cmac_send: send %d\n", len);
 
        /* Send the data
         */
@@ -212,21 +226,14 @@ ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentr
        if (len > AO_CMAC_MAX_LEN)
                return AO_RADIO_CMAC_LEN_ERROR;
 
-       /* Set the key.
-        */
-       PRINTD ("setting key\n");
-       ao_radio_get(AO_RADIO_SPI_CMAC_KEY, AO_AES_LEN);
-       ao_radio_spi_request.timeout = timeout;
-       ao_xmemcpy(&ao_radio_spi_request.payload, &ao_config.aes_key, AO_AES_LEN);
-       recv = ao_radio_master_send();
-       ao_radio_put();
-       PRINTD ("key set: %d\n", recv);
+       ao_radio_cmac_set_key();
 
        /* Recv the data
         */
        PRINTD ("queuing recv\n");
        ao_radio_get(AO_RADIO_SPI_CMAC_RECV, 0);
        ao_radio_spi_request.recv_len = len;
+       ao_radio_spi_request.timeout = timeout;
        recv = ao_radio_master_send();
        PRINTD ("recv queued: %d\n", recv);
        if (!recv) {
@@ -300,7 +307,8 @@ ao_radio_init(void)
        ao_enable_port(AO_RADIO_INT_PORT);
        ao_exti_setup(AO_RADIO_INT_PORT,
                      AO_RADIO_INT_PIN,
-                     AO_EXTI_MODE_FALLING,
+                     AO_EXTI_MODE_RISING|AO_EXTI_MODE_FALLING,
                      ao_radio_isr);
+       ao_exti_enable(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN);
        ao_cmd_register(&ao_radio_cmds[0]);
 }
index ab23894fd31b8e3bbf7452128bbc753c9e862ad2..9a01bbfaa00cc5648ee1431466a19323b7e5f0a5 100644 (file)
@@ -23,54 +23,69 @@ static __xdata struct ao_radio_spi_reply ao_radio_spi_reply;
 
 static __xdata struct ao_radio_spi_request ao_radio_spi_request;
 
-static __xdata uint8_t ao_radio_spi_recv_request;
-static __xdata uint8_t ao_radio_spi_recv_len;
-static __xdata uint16_t        ao_radio_spi_recv_timeout;
+static __xdata uint8_t slave_state;
 
 static void
-ao_radio_slave_signal(void)
+ao_radio_slave_low(void)
 {
+       uint16_t        i;
+
+       if (slave_state != 1)
+               ao_panic(1);
+       ao_led_toggle(AO_LED_GREEN);
        ao_gpio_set(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 0);
-       ao_arch_nop();
-       ao_arch_nop();
-       ao_arch_nop();
+       for (i = 0; i < 1000; i++)
+               ao_arch_nop();
+       slave_state = 0;
+}
+
+static void
+ao_radio_slave_high(void)
+{
+       if (slave_state != 0)
+               ao_panic(2);
+       ao_led_toggle(AO_LED_RED);
        ao_gpio_set(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 1);
+       slave_state = 1;
 }
 
 static void
 ao_radio_slave_spi(void)
 {
-       uint8_t need_signal = 0;
-
        ao_spi_get_slave(AO_RADIO_SLAVE_BUS);
        for (;;) {
                ao_spi_recv(&ao_radio_spi_request,
                            (2 << 13) | sizeof (ao_radio_spi_request),
                            AO_RADIO_SLAVE_BUS);
-               if (need_signal) {
-                       ao_radio_slave_signal();
-                       need_signal = 0;
-               }
+               ao_radio_slave_high();
                ao_spi_recv_wait();
                switch (ao_radio_spi_request.request) {
                case AO_RADIO_SPI_RECV:
-               case AO_RADIO_SPI_CMAC_RECV:
+
+                       /* XXX monitor CS to interrupt the receive */
+
                        ao_config.radio_setting = ao_radio_spi_request.setting;
-                       ao_radio_spi_recv_request = ao_radio_spi_request.request;
-                       ao_radio_spi_recv_len = ao_radio_spi_request.recv_len;
-                       ao_radio_spi_recv_timeout = ao_radio_spi_request.timeout;
-                       ao_wakeup(&ao_radio_spi_recv_len);
+                       ao_radio_spi_reply.status = ao_radio_recv(&ao_radio_spi_reply.payload,
+                                                                 ao_radio_spi_request.recv_len);
+                       ao_radio_spi_reply.rssi = 0;
+                       ao_spi_send(&ao_radio_spi_reply,
+                                   AO_RADIO_SPI_REPLY_HEADER_LEN + ao_radio_spi_request.recv_len,
+                                   AO_RADIO_SLAVE_BUS);
+                       ao_radio_slave_low();
+                       ao_spi_send_wait();
                        continue;
-               case AO_RADIO_SPI_RECV_FETCH:
+               case AO_RADIO_SPI_CMAC_RECV:
+                       ao_config.radio_setting = ao_radio_spi_request.setting;
+                       ao_radio_spi_reply.status = ao_radio_cmac_recv(&ao_radio_spi_reply.payload,
+                                                                      ao_radio_spi_request.recv_len,
+                                                                      ao_radio_spi_request.timeout);
+                       ao_radio_spi_reply.rssi = ao_radio_cmac_rssi;
                        ao_spi_send(&ao_radio_spi_reply,
-                                   ao_radio_spi_request.recv_len,
+                                   AO_RADIO_SPI_REPLY_HEADER_LEN + ao_radio_spi_request.recv_len,
                                    AO_RADIO_SLAVE_BUS);
-                       ao_radio_slave_signal();
+                       ao_radio_slave_low();
                        ao_spi_send_wait();
                        continue;
-               case AO_RADIO_SPI_RECV_ABORT:
-                       ao_radio_recv_abort();
-                       break;
                case AO_RADIO_SPI_SEND:
                        ao_config.radio_setting = ao_radio_spi_request.setting;
                        ao_radio_send(&ao_radio_spi_request.payload,
@@ -96,38 +111,15 @@ ao_radio_slave_spi(void)
                        ao_radio_test(0);
                        break;
                }
-               need_signal = 1;
-       }
-}
-
-static void
-ao_radio_slave_recv(void)
-{
-       uint8_t len;
-       for (;;) {
-               while (!ao_radio_spi_recv_len)
-                       ao_sleep(&ao_radio_spi_recv_len);
-               len = ao_radio_spi_recv_len;
-               ao_radio_spi_recv_len = 0;
-               if (ao_radio_spi_recv_request == AO_RADIO_SPI_RECV) {
-                       ao_radio_spi_reply.status = ao_radio_recv(&ao_radio_spi_reply.payload, len);
-                       ao_radio_spi_reply.rssi = 0;
-               } else {
-                       ao_radio_spi_reply.status = ao_radio_cmac_recv(&ao_radio_spi_reply.payload, len,
-                                                                      ao_radio_spi_recv_timeout);
-                       ao_radio_spi_reply.rssi = ao_radio_cmac_rssi;
-               }
-               ao_radio_slave_signal();
+               ao_radio_slave_low();
        }
 }
 
 static __xdata struct ao_task ao_radio_slave_spi_task;
-static __xdata struct ao_task ao_radio_slave_recv_task;
 
 void
 ao_radio_slave_init(void)
 {
        ao_add_task(&ao_radio_slave_spi_task, ao_radio_slave_spi, "radio_spi");
-       ao_add_task(&ao_radio_slave_recv_task, ao_radio_slave_recv, "radio_recv");
-       ao_enable_output(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 1);
+       ao_enable_output(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 0);
 }