Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
[fw/altos] / src / drivers / ao_btm.c
index f381604796dd3d390aae7469fce3df611782e49a..93d9dd9d341313d54fa927ca496ff8544374b894 100644 (file)
  */
 
 #include "ao.h"
+#ifdef AO_BTM_INT_PORT
+#include <ao_exti.h>
+#endif
 
 #ifndef ao_serial_btm_getchar
 #define ao_serial_btm_putchar  ao_serial1_putchar
-#define ao_serial_btm_pollchar ao_serial1_pollchar
+#define _ao_serial_btm_pollchar        _ao_serial1_pollchar
+#define _ao_serial_btm_sleep_for(timeout)      ao_sleep_for((void *) &ao_serial1_rx_fifo, timeout)
 #define ao_serial_btm_set_speed ao_serial1_set_speed
 #define ao_serial_btm_drain    ao_serial1_drain
 #endif
@@ -31,7 +35,7 @@ __xdata uint8_t               ao_btm_connected;
 
 #if BT_DEBUG
 __xdata char           ao_btm_buffer[256];
-int                    ao_btm_ptr;
+uint16_t               ao_btm_ptr;
 char                   ao_btm_dir;
 
 static void
@@ -80,6 +84,10 @@ ao_btm_dump(void)
                        putchar(ao_btm_buffer[i]);
        }
        putchar('\n');
+       ao_cmd_decimal();
+       if (ao_cmd_status == ao_cmd_success && ao_cmd_lex_i)
+               ao_btm_ptr = 0;
+       ao_cmd_status = ao_cmd_success;
 }
 
 static void
@@ -94,9 +102,44 @@ ao_btm_speed(void)
                ao_cmd_status = ao_cmd_syntax_error;
 }
 
+static uint8_t ao_btm_enable;
+
+static void
+ao_btm_do_echo(void)
+{
+       int     c;
+       while (ao_btm_enable) {
+               ao_arch_block_interrupts();
+               while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN && ao_btm_enable)
+                       _ao_serial_btm_sleep_for(0);
+               ao_arch_release_interrupts();
+               if (c != AO_READ_AGAIN) {
+                       putchar(c);
+                       flush();
+               }
+       }
+       ao_exit();
+}
+
+static struct ao_task ao_btm_echo_task;
+
+static void
+ao_btm_send(void)
+{
+       int c;
+       ao_btm_enable = 1;
+       ao_add_task(&ao_btm_echo_task, ao_btm_do_echo, "btm-echo");
+       while ((c = getchar()) != '~') {
+               ao_serial_btm_putchar(c);
+       }
+       ao_btm_enable = 0;
+       ao_wakeup((void *) &ao_serial_btm_rx_fifo);
+}
+
 __code struct ao_cmds ao_btm_cmds[] = {
        { ao_btm_dump,          "d\0Dump btm buffer." },
        { ao_btm_speed,         "s <19200,57600>\0Set btm serial speed." },
+       { ao_btm_send,          "S\0BTM interactive mode. ~ to exit." },
        { 0, NULL },
 };
 
@@ -111,6 +154,28 @@ __code struct ao_cmds ao_btm_cmds[] = {
 #define AO_BTM_MAX_REPLY       16
 __xdata char           ao_btm_reply[AO_BTM_MAX_REPLY];
 
+/*
+ * Read one bluetooth character.
+ * Returns AO_READ_AGAIN if no character arrives within 10ms
+ */
+
+static int
+ao_btm_getchar(void)
+{
+       int     c;
+
+       ao_arch_block_interrupts();
+       while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN) {
+               c = _ao_serial_btm_sleep_for(AO_MS_TO_TICKS(10));
+               if (c) {
+                       c = AO_READ_AGAIN;
+                       break;
+               }
+       }
+       ao_arch_release_interrupts();
+       return c;
+}
+
 /*
  * Read a line of data from the serial port, truncating
  * it after a few characters.
@@ -120,28 +185,18 @@ uint8_t
 ao_btm_get_line(void)
 {
        uint8_t ao_btm_reply_len = 0;
-       char c;
-
-       for (;;) {
-
-               while ((c = ao_serial_btm_pollchar()) != AO_READ_AGAIN) {
-                       ao_btm_log_in_char(c);
-                       if (ao_btm_reply_len < sizeof (ao_btm_reply))
-                               ao_btm_reply[ao_btm_reply_len++] = c;
-                       if (c == '\r' || c == '\n')
-                               goto done;
-               }
-               for (c = 0; c < 10; c++) {
-                       ao_delay(AO_MS_TO_TICKS(10));
-                       if (!ao_fifo_empty(ao_serial1_rx_fifo))
-                               break;
-               }
-               if (c == 10)
-                       goto done;
+       int c;
+       uint8_t l;
+
+       while ((c = ao_btm_getchar()) != AO_READ_AGAIN) {
+               ao_btm_log_in_char(c);
+               if (ao_btm_reply_len < sizeof (ao_btm_reply))
+                       ao_btm_reply[ao_btm_reply_len++] = c;
+               if (c == '\r' || c == '\n')
+                       break;
        }
-done:
-       for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);)
-               ao_btm_reply[c++] = '\0';
+       for (l = ao_btm_reply_len; l < sizeof (ao_btm_reply);)
+               ao_btm_reply[l++] = '\0';
        return ao_btm_reply_len;
 }
 
@@ -200,7 +255,7 @@ ao_btm_string(__code char *cmd)
 {
        char    c;
 
-       while (c = *cmd++)
+       while ((c = *cmd++) != '\0')
                ao_btm_putchar(c);
 }
 
@@ -242,6 +297,52 @@ ao_btm_try_speed(uint8_t speed)
        return 0;
 }
 
+#if BT_LINK_ON_P2
+#define BT_PICTL_ICON  PICTL_P2ICON
+#define BT_PIFG                P2IFG
+#define BT_PDIR                P2DIR
+#define BT_PINP                P2INP
+#define BT_IEN2_PIE    IEN2_P2IE
+#define BT_CC1111      1
+#endif
+#if BT_LINK_ON_P1
+#define BT_PICTL_ICON  PICTL_P1ICON
+#define BT_PIFG                P1IFG
+#define BT_PDIR                P1DIR
+#define BT_PINP                P1INP
+#define BT_IEN2_PIE    IEN2_P1IE
+#define BT_CC1111      1
+#endif
+
+void
+ao_btm_check_link()
+{
+#if BT_CC1111
+       ao_arch_critical(
+               /* Check the pin and configure the interrupt detector to wait for the
+                * pin to flip the other way
+                */
+               if (BT_LINK_PIN) {
+                       ao_btm_connected = 0;
+                       PICTL |= BT_PICTL_ICON;
+               } else {
+                       ao_btm_connected = 1;
+                       PICTL &= ~BT_PICTL_ICON;
+               }
+               );
+#else
+       ao_arch_block_interrupts();
+       if (ao_gpio_get(AO_BTM_INT_PORT, AO_BTM_INT_PIN, AO_BTM_INT) == 0) {
+               ao_btm_connected = 1;
+       } else {
+               ao_btm_connected = 0;
+       }
+       ao_arch_release_interrupts();
+#endif
+}
+
+__xdata struct ao_task ao_btm_task;
+
 /*
  * A thread to initialize the bluetooth device and
  * hang around to blink the LED when connected
@@ -279,55 +380,30 @@ ao_btm(void)
        /* Turn off status reporting */
        ao_btm_cmd("ATQ1\r");
 
-       ao_btm_stdio = ao_add_stdio(ao_serial_btm_pollchar,
+       ao_btm_stdio = ao_add_stdio(_ao_serial_btm_pollchar,
                                    ao_serial_btm_putchar,
                                    NULL);
        ao_btm_echo(0);
 
+       /* Check current pin state */
+       ao_btm_check_link();
+
+#ifdef AO_BTM_INT_PORT
+       ao_exti_enable(AO_BTM_INT_PORT, AO_BTM_INT_PIN);
+#endif
+
        for (;;) {
                while (!ao_btm_connected)
                        ao_sleep(&ao_btm_connected);
                while (ao_btm_connected) {
-                       ao_led_for(AO_LED_GREEN, AO_MS_TO_TICKS(20));
+                       ao_led_for(AO_BT_LED, AO_MS_TO_TICKS(20));
                        ao_delay(AO_SEC_TO_TICKS(3));
                }
        }
 }
 
-__xdata struct ao_task ao_btm_task;
-
-#if BT_LINK_ON_P2
-#define BT_PICTL_ICON  PICTL_P2ICON
-#define BT_PIFG                P2IFG
-#define BT_PDIR                P2DIR
-#define BT_PINP                P2INP
-#define BT_IEN2_PIE    IEN2_P2IE
-#endif
-#if BT_LINK_ON_P1
-#define BT_PICTL_ICON  PICTL_P1ICON
-#define BT_PIFG                P1IFG
-#define BT_PDIR                P1DIR
-#define BT_PINP                P1INP
-#define BT_IEN2_PIE    IEN2_P1IE
-#endif
-
-void
-ao_btm_check_link()
-{
-       ao_arch_critical(
-               /* Check the pin and configure the interrupt detector to wait for the
-                * pin to flip the other way
-                */
-               if (BT_LINK_PIN) {
-                       ao_btm_connected = 0;
-                       PICTL |= BT_PICTL_ICON;
-               } else {
-                       ao_btm_connected = 1;
-                       PICTL &= ~BT_PICTL_ICON;
-               }
-               );
-}
 
+#if BT_CC1111
 void
 ao_btm_isr(void)
 #if BT_LINK_ON_P1
@@ -343,6 +419,16 @@ ao_btm_isr(void)
        }
        BT_PIFG = 0;
 }
+#endif
+
+#ifdef AO_BTM_INT_PORT
+void
+ao_btm_isr(void)
+{
+       ao_btm_check_link();
+       ao_wakeup(&ao_btm_connected);
+}
+#endif
 
 void
 ao_btm_init (void)
@@ -351,6 +437,18 @@ ao_btm_init (void)
 
        ao_serial_btm_set_speed(AO_SERIAL_SPEED_19200);
 
+#ifdef AO_BTM_RESET_PORT
+       ao_enable_output(AO_BTM_RESET_PORT,AO_BTM_RESET_PIN,AO_BTM_RESET,0);
+#endif
+
+#ifdef AO_BTM_INT_PORT
+       ao_enable_port(AO_BTM_INT_PORT);
+       ao_exti_setup(AO_BTM_INT_PORT, AO_BTM_INT_PIN,
+                     AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_LOW,
+                     ao_btm_isr);
+#endif
+
+#if BT_CC1111
 #if BT_LINK_ON_P1
        /*
         * Configure ser reset line
@@ -372,9 +470,7 @@ ao_btm_init (void)
 
        /* Enable interrupts */
        IEN2 |= BT_IEN2_PIE;
-
-       /* Check current pin state */
-       ao_btm_check_link();
+#endif
 
 #if BT_LINK_ON_P2
        /* Eable the pin interrupt */