]> git.karo-electronics.de Git - oswald.git/blob - metawatch/mw_bt.c
Some minor improvements.
[oswald.git] / metawatch / mw_bt.c
1 #include <msp430.h>
2 #include <msp430xgeneric.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <string.h>
6
7 #include "mw_main.h"
8
9 #include "mw_uart.h"
10 #include "mw_bt.h"
11 #include "bt_hci.h"
12 #include "bt_l2cap.h"
13
14 #include "bluetooth_init_cc256x.h"
15
16
17 static char bt_rx_buf[BT_RX_MAX_SIZE];
18 static unsigned char bt_rx_buf_wpos = 0;
19 static unsigned char bt_rx_buf_rpos = 0;
20 static uint8_t mw_bt_enabled = 0;
21
22 int mw_bt_get_rxbuf_len(void)
23 {
24         if (bt_rx_buf_rpos > bt_rx_buf_wpos)
25                 return (BT_RX_MAX_SIZE - bt_rx_buf_rpos) + bt_rx_buf_wpos;
26         else
27                 return bt_rx_buf_wpos - bt_rx_buf_rpos;
28 }
29
30 const unsigned char *mw_bt_get_rx_buf(unsigned char **rpos, unsigned char *len)
31 {
32         *rpos = &bt_rx_buf_rpos;
33
34         if (bt_rx_buf_rpos > bt_rx_buf_wpos)
35                 *len = (BT_RX_MAX_SIZE - bt_rx_buf_rpos) + bt_rx_buf_wpos;
36         else
37                 *len = bt_rx_buf_wpos - bt_rx_buf_rpos;
38
39         // if we reach high water mark raise RTS to stop more data
40         if (*len > (BT_RX_MAX_SIZE-(BT_RX_MAX_SIZE/10))) {
41                 debug_uart_tx("BT UART RTS\n");
42                 BT_IO_POUT |= BT_IO_RTS; // low == ready, high == !ready
43         } else {
44                 BT_IO_POUT &= ~BT_IO_RTS; // low == ready, high == !ready
45         }
46
47         return (unsigned char *)bt_rx_buf;
48 }
49
50 #pragma vector=USCI_A1_VECTOR
51 __interrupt void UCA1_ISR (void)
52 {
53         switch (UCA1IV) {
54                 case 2: // RXIFG
55                         /* clear IRQ flag */
56                         //UCA1IFG  &= ~UCRXIFG;
57                         /* wake up to handle the received char */
58                         if (UCA1STAT & UCRXERR) {
59                                 debug_uart_tx("BT UART RXERR: ");
60                                 if (UCA1STAT & UCOE)
61                                         debug_uart_tx("overrun ");
62                                 if (UCA1STAT & UCPE)
63                                         debug_uart_tx("parity err ");
64                                 if (UCA1STAT & UCFE)
65                                         debug_uart_tx("frm-err ");
66                                 debug_uart_tx("\n");
67                         }
68                         bt_rx_buf[bt_rx_buf_wpos++] = UCA1RXBUF;
69                         bt_rx_buf_wpos %= BT_RX_MAX_SIZE;
70                         // LPM3_EXIT;
71                         LPM3_EXIT_ISR();
72                         _event_src |= BT_UART_RCV_EVENT;
73                         break;
74                 case 4: // TXIFG
75                         debug_uart_tx("BT UART TX IRQ - huh?\n");
76                         break;
77                 default:
78                         break;
79         };
80 }
81
82 void mw_init_bt_uart(const bt_uart_baud_t baud)
83 {
84         UCA1CTL1 = UCSWRST;
85
86         UCA1CTL1 |= UCSSEL__SMCLK;
87
88         switch (baud) {
89                 case BT_UART_BD115200:
90                 default:
91                         UCA1BR0 = 138;
92                         UCA1MCTL = UCBRS_7 + UCBRF_0;
93                 break;
94         };
95         UCA1STAT = 0;
96         // UCA1CTL0 = UCMODE_0; // UART mode
97         // UCA1CTL0 &= ~UC7BIT; // 8bit char
98         //UCA1CTL0 |= UCRXEIE;
99
100         UCA1CTL1 &= ~UCSWRST;
101
102         /* clear interrup flags */
103         UCA1IFG = 0;
104         UCA1IE = UCRXIE;
105 }
106
107 #if 0 // Does never finish, presumably trigger does not trigger, unknown :(
108 void mw_bt_uart_tx(const void *buf, const unsigned int len)
109 {
110         UCA1IE &= UCTXIE;
111
112         DMACTL0 = DMA0TSEL_21;
113
114         DMA0DA  = (unsigned int) &UCA1TXBUF;
115         DMA0SA  = (uint32_t) buf;
116         DMA0SZ  = len;
117
118         //DMA0CTL = 0x03F0;
119         DMA0CTL = DMADT_1 | DMASRCINCR_3 | DMASBDB | DMALEVEL | DMAIE;
120         UCA1IFG &= ~UCTXIFG;
121         DMA0CTL |= DMAEN;
122
123         while ((DMA0CTL & DMAIFG) == 0 && (DMA0CTL & DMAABORT) == 0)
124                 nop();
125 }
126 #else
127 int mw_bt_uart_tx(const void *buf, const unsigned int len)
128 {
129         unsigned int pos, i;
130         // char txstr[8];
131
132         pos = 0;
133         // debug_uart_tx("BT tx: ");
134         while (pos < len) {
135                 // watch for CTS to be low
136                 i = 0;
137                 while ((BT_IO_PIN & BT_IO_CTS) && (i < 1000)) {
138                         __delay_cycles(16000);
139                         i++;
140                         if (i >= 1000)
141                                 return -1;
142                         // nop();
143                 }
144
145                 // do not start a transfer if UART is busy, e.g. rx-ing
146                 while (UCA1STAT & UCBUSY)
147                         nop();
148
149                 UCA1TXBUF = *(unsigned char *) (buf+pos);
150                 // debug_uart_tx_char(*(unsigned char *) (buf+pos));
151                 // snprintf(txstr, 8, "0x%02x ", *(unsigned char *) (buf+pos));
152                 // debug_uart_tx(txstr);
153                 pos++;
154                 while ((UCA1IFG & UCTXIFG) == 0)
155                         nop();
156         }
157         while (UCA1STAT & UCBUSY)
158                 nop();
159
160         return len;
161 }
162 #endif
163
164 static int load_cc256x_init_script(void)
165 {
166         uint32_t pos;
167         unsigned char *tptr;
168         int tlen;
169
170         pos = 0;
171         while (pos < cc256x_init_script_size) {
172                 if (_event_src != 0)
173                         handle_event();
174                 tptr = (unsigned char *)(cc256x_init_script + pos);
175                 tlen = mw_bt_uart_tx(tptr, 4 + tptr[3]);
176                 if (tlen < 0)
177                         return -1;
178                 pos += tlen /*4 + tptr[3]*/;
179                 // each init script part is one HCI command so wait for reply
180                 if (_event_src != 0)
181                         handle_event();
182         }
183         return 0;
184 }
185
186 void mw_enable_bt(void)
187 {
188         int i;
189
190         /* make sure it resets */
191         BT_SHUTDOWN();
192         __delay_cycles(16000);
193
194         /* enable 32kHz ACLK output to BT module */
195         P11DIR |= BIT0;
196         P11SEL |= BIT0;
197
198         // wait for clock to stabilize
199         __delay_cycles(16000);
200
201         // disable the IRQ on CTS, later used to get a wakeup IRQ from eHCILL
202         // will be enabled when going to sleep
203         P1IE &= ~BT_IO_CTS;
204         P1IES &= ~BT_IO_CTS;
205
206         BT_IO_PDIR &= ~(BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
207         BT_IO_PDIR |= BT_IO_RTS;
208
209         BT_IO_POUT &= ~(BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
210         BT_IO_POUT &= ~BT_IO_RTS; // low == ready, high == !ready
211
212         BT_IO_REN |= BT_IO_CTS; // enable pull-down on CTS, POUT-CTS is 0 already
213
214         /* setup UART pins */
215         BT_UART_PSEL |= BT_UART_TX_PIN | BT_UART_RX_PIN;
216         // P5OUT |= BT_UART_TX_PIN | BT_UART_RX_PIN;
217         // P5REN |= BT_UART_TX_PIN | BT_UART_RX_PIN;
218
219         mw_init_bt_uart(BT_UART_BD115200);
220
221         bt_rx_buf_wpos = 0;
222         bt_rx_buf_rpos = 0;
223
224         /* release BT reset pin */
225         BT_ENABLE();
226
227         for (i=0; i<1000; i++) {
228                 __delay_cycles(16000);
229                 if ((BT_IO_PIN & BT_IO_CTS) == 0) // when CTS goes low module is ready
230                         break;
231         }
232         if (i>=1000) {
233                 debug_uart_tx("Timeout waiting for CC256x to lower CTS\n");
234                 mw_bt_enabled = 0;
235         } else {
236                 debug_uart_tx("CC256x CTS low - uploading init\n");
237
238                 // the init script consists of HCI cmds so HCI must be setup before
239                 bt_hci_init();
240
241                 // give it some more time before anyone sends data
242                 for (i=0; i<10; i++) {
243                         __delay_cycles(16000);
244                 }
245                 if (load_cc256x_init_script() < 0) {
246                         debug_uart_tx("init upload failed!\n");
247                         return;
248                 }
249
250                 __delay_cycles(32000);
251
252                 debug_uart_tx("init uploaded\n");
253
254                 init_l2cap();
255
256                 if (_event_src != 0)
257                         handle_event();
258
259                 mw_bt_enabled = 1;
260         }
261 }
262
263 void mw_disable_bt(void)
264 {
265         mw_bt_enabled = 0;
266
267         // disable the IRQ on CTS
268         P1IE &= ~BT_IO_CTS;
269         P1IES &= ~BT_IO_CTS;
270         // BT_IO_REN &= ~BT_IO_CTS; // disable pull-down on CTS
271         P1IFG &= ~BT_IO_CTS;
272
273         /* disable UART RX interrupt */
274         UCA1IE &= ~UCRXIE;
275
276         /* disable UART pins */
277         BT_UART_PSEL &= ~(BT_UART_TX_PIN | BT_UART_RX_PIN);
278
279         /* set BT reset pin */
280         BT_SHUTDOWN();
281
282         /* disable 32kHz ACLK output to BT module */
283         P11DIR &= ~BIT0;
284         P11SEL &= ~BIT0;
285
286         /* make all I/O Pins inputs so we do not drive against a "deaf" module */
287         BT_IO_PDIR &= ~(BT_IO_RTS | BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
288         BT_IO_POUT &= ~(BT_IO_RTS | BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ);
289 }
290
291 uint8_t mw_bt_is_enabled(void)
292 {
293         return mw_bt_enabled;
294 }
295