]> git.karo-electronics.de Git - oswald.git/blobdiff - metawatch/mw_bt.c
Add modified LPM3_EXIT_ISR to work around FLL IRQ wake-up problem
[oswald.git] / metawatch / mw_bt.c
index 7cb24e1b0e63fad8978a87bd30243b050eb4c05f..ace18e9a5e0dff740734fe31248e1c68613f0cbb 100644 (file)
@@ -19,16 +19,30 @@ static unsigned char bt_rx_buf_wpos = 0;
 static unsigned char bt_rx_buf_rpos = 0;
 static uint8_t mw_bt_enabled = 0;
 
+int mw_bt_get_rxbuf_len(void)
+{
+       if (bt_rx_buf_rpos > bt_rx_buf_wpos)
+               return (BT_RX_MAX_SIZE - bt_rx_buf_rpos) + bt_rx_buf_wpos;
+       else
+               return bt_rx_buf_wpos - bt_rx_buf_rpos;
+}
+
 const unsigned char *mw_bt_get_rx_buf(unsigned char **rpos, unsigned char *len)
 {
        *rpos = &bt_rx_buf_rpos;
+
        if (bt_rx_buf_rpos > bt_rx_buf_wpos)
                *len = (BT_RX_MAX_SIZE - bt_rx_buf_rpos) + bt_rx_buf_wpos;
        else
                *len = bt_rx_buf_wpos - bt_rx_buf_rpos;
 
-       if (*len > (BT_RX_MAX_SIZE-(BT_RX_MAX_SIZE/10)))
+       // if we reach high water mark raise RTS to stop more data
+       if (*len > (BT_RX_MAX_SIZE-(BT_RX_MAX_SIZE/10))) {
+               debug_uart_tx("BT UART RTS\n");
                BT_IO_POUT |= BT_IO_RTS; // low == ready, high == !ready
+       } else {
+               BT_IO_POUT &= ~BT_IO_RTS; // low == ready, high == !ready
+       }
 
        return (unsigned char *)bt_rx_buf;
 }
@@ -38,15 +52,27 @@ __interrupt void UCA1_ISR (void)
 {
        switch (UCA1IV) {
                case 2: // RXIFG
+                       /* clear IRQ flag */
+                       //UCA1IFG  &= ~UCRXIFG;
                        /* wake up to handle the received char */
-                       LPM3_EXIT;
+                       if (UCA1STAT & UCRXERR) {
+                               debug_uart_tx("BT UART RXERR: ");
+                               if (UCA1STAT & UCOE)
+                                       debug_uart_tx("overrun ");
+                               if (UCA1STAT & UCPE)
+                                       debug_uart_tx("parity err ");
+                               if (UCA1STAT & UCFE)
+                                       debug_uart_tx("frm-err ");
+                               debug_uart_tx("\n");
+                       }
                        bt_rx_buf[bt_rx_buf_wpos++] = UCA1RXBUF;
-                       /* clear IRQ flag */
-                       UCA1IFG  &= ~UCRXIFG;
                        bt_rx_buf_wpos %= BT_RX_MAX_SIZE;
+                       // LPM3_EXIT;
+                       LPM3_EXIT_ISR();
                        _event_src |= BT_UART_RCV_EVENT;
                        break;
                case 4: // TXIFG
+                       debug_uart_tx("BT UART TX IRQ - huh?\n");
                        break;
                default:
                        break;
@@ -56,7 +82,9 @@ __interrupt void UCA1_ISR (void)
 void mw_init_bt_uart(const bt_uart_baud_t baud)
 {
        UCA1CTL1 = UCSWRST;
+
        UCA1CTL1 |= UCSSEL__SMCLK;
+
        switch (baud) {
                case BT_UART_BD115200:
                default:
@@ -65,10 +93,12 @@ void mw_init_bt_uart(const bt_uart_baud_t baud)
                break;
        };
        UCA1STAT = 0;
-       UCA1CTL0 = UCMODE_0;    // UART mode
-       UCA1CTL0 &= ~UC7BIT;    // 8bit char
+       // UCA1CTL0 = UCMODE_0; // UART mode
+       // UCA1CTL0 &= ~UC7BIT; // 8bit char
+       //UCA1CTL0 |= UCRXEIE;
 
        UCA1CTL1 &= ~UCSWRST;
+
        /* clear interrup flags */
        UCA1IFG = 0;
        UCA1IE = UCRXIE;
@@ -94,15 +124,26 @@ void mw_bt_uart_tx(const void *buf, const unsigned int len)
                nop();
 }
 #else
-void mw_bt_uart_tx(const void *buf, const unsigned int len)
+int mw_bt_uart_tx(const void *buf, const unsigned int len)
 {
-       unsigned int pos;
+       unsigned int pos, i;
        // char txstr[8];
 
        pos = 0;
        // debug_uart_tx("BT tx: ");
        while (pos < len) {
-               while ((BT_IO_PIN & BT_IO_CTS)) // wait for CTS to go low
+               // watch for CTS to be low
+               i = 0;
+               while ((BT_IO_PIN & BT_IO_CTS) && (i < 1000)) {
+                       __delay_cycles(16000);
+                       i++;
+                       if (i >= 1000)
+                               return -1;
+                       // nop();
+               }
+
+               // do not start a transfer if UART is busy, e.g. rx-ing
+               while (UCA1STAT & UCBUSY)
                        nop();
 
                UCA1TXBUF = *(unsigned char *) (buf+pos);
@@ -115,26 +156,31 @@ void mw_bt_uart_tx(const void *buf, const unsigned int len)
        }
        while (UCA1STAT & UCBUSY)
                nop();
-       // debug_uart_tx("\n");
+
+       return len;
 }
 #endif
 
-static void load_cc256x_init_script(void)
+static int load_cc256x_init_script(void)
 {
        uint32_t pos;
        unsigned char *tptr;
+       int tlen;
 
        pos = 0;
        while (pos < cc256x_init_script_size) {
                if (_event_src != 0)
                        handle_event();
                tptr = (unsigned char *)(cc256x_init_script + pos);
-               mw_bt_uart_tx(tptr, 4 + tptr[3]);
-               pos += 4 + tptr[3];
+               tlen = mw_bt_uart_tx(tptr, 4 + tptr[3]);
+               if (tlen < 0)
+                       return -1;
+               pos += tlen /*4 + tptr[3]*/;
                // each init script part is one HCI command so wait for reply
                if (_event_src != 0)
                        handle_event();
        }
+       return 0;
 }
 
 void mw_enable_bt(void)
@@ -143,6 +189,7 @@ void mw_enable_bt(void)
 
        /* make sure it resets */
        BT_SHUTDOWN();
+       __delay_cycles(16000);
 
        /* enable 32kHz ACLK output to BT module */
        P11DIR |= BIT0;
@@ -151,11 +198,19 @@ void mw_enable_bt(void)
        // wait for clock to stabilize
        __delay_cycles(16000);
 
+       // disable the IRQ on CTS, later used to get a wakeup IRQ from eHCILL
+       // will be enabled when going to sleep
+       P1IE &= ~BT_IO_CTS;
+       P1IES &= ~BT_IO_CTS;
+
        BT_IO_PDIR &= ~(BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
        BT_IO_PDIR |= BT_IO_RTS;
+
        BT_IO_POUT &= ~(BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
        BT_IO_POUT &= ~BT_IO_RTS; // low == ready, high == !ready
 
+       BT_IO_REN |= BT_IO_CTS; // enable pull-down on CTS, POUT-CTS is 0 already
+
        /* setup UART pins */
        BT_UART_PSEL |= BT_UART_TX_PIN | BT_UART_RX_PIN;
        // P5OUT |= BT_UART_TX_PIN | BT_UART_RX_PIN;
@@ -163,6 +218,9 @@ void mw_enable_bt(void)
 
        mw_init_bt_uart(BT_UART_BD115200);
 
+       bt_rx_buf_wpos = 0;
+       bt_rx_buf_rpos = 0;
+
        /* release BT reset pin */
        BT_ENABLE();
 
@@ -173,36 +231,45 @@ void mw_enable_bt(void)
        }
        if (i>=1000) {
                debug_uart_tx("Timeout waiting for CC256x to lower CTS\n");
+               mw_bt_enabled = 0;
        } else {
                debug_uart_tx("CC256x CTS low - uploading init\n");
-               for (i=0; i<100; i++) {
-                       __delay_cycles(16000); // give it some more before anyone sends data
+
+               // the init script consists of HCI cmds so HCI must be setup before
+               bt_hci_init();
+
+               // give it some more time before anyone sends data
+               for (i=0; i<10; i++) {
+                       __delay_cycles(16000);
+               }
+               if (load_cc256x_init_script() < 0) {
+                       debug_uart_tx("init upload failed!\n");
+                       return;
                }
-               load_cc256x_init_script();
+
+               __delay_cycles(32000);
+
                debug_uart_tx("init uploaded\n");
-       }
-       P1IE &= ~BT_IO_CTS;
-       P1IES &= ~BT_IO_CTS;
-       bt_hci_init();
-       init_l2cap();
-       mw_bt_enabled = 1;
-}
 
-#pragma vector=PORT1_VECTOR
-__interrupt void BT_CTS_ISR (void)
-{
-       P1IFG &= ~BT_IO_CTS;
+               init_l2cap();
 
-       debug_uart_tx("BTS CTS triggered\n");
-       bt_hci_ehcill_wake();
+               if (_event_src != 0)
+                       handle_event();
 
-       LPM3_EXIT;
+               mw_bt_enabled = 1;
+       }
 }
 
 void mw_disable_bt(void)
 {
        mw_bt_enabled = 0;
 
+       // disable the IRQ on CTS
+       P1IE &= ~BT_IO_CTS;
+       P1IES &= ~BT_IO_CTS;
+       // BT_IO_REN &= ~BT_IO_CTS; // disable pull-down on CTS
+       P1IFG &= ~BT_IO_CTS;
+
        /* disable UART RX interrupt */
        UCA1IE &= ~UCRXIE;