93d9dd9d341313d54fa927ca496ff8544374b894
[fw/altos] / src / drivers / ao_btm.c
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19 #ifdef AO_BTM_INT_PORT
20 #include <ao_exti.h>
21 #endif
22
23 #ifndef ao_serial_btm_getchar
24 #define ao_serial_btm_putchar   ao_serial1_putchar
25 #define _ao_serial_btm_pollchar _ao_serial1_pollchar
26 #define _ao_serial_btm_sleep_for(timeout)       ao_sleep_for((void *) &ao_serial1_rx_fifo, timeout)
27 #define ao_serial_btm_set_speed ao_serial1_set_speed
28 #define ao_serial_btm_drain     ao_serial1_drain
29 #endif
30
31 int8_t                  ao_btm_stdio;
32 __xdata uint8_t         ao_btm_connected;
33
34 #define BT_DEBUG 0
35
36 #if BT_DEBUG
37 __xdata char            ao_btm_buffer[256];
38 uint16_t                ao_btm_ptr;
39 char                    ao_btm_dir;
40
41 static void
42 ao_btm_add_char(char c)
43 {
44         if (ao_btm_ptr < sizeof (ao_btm_buffer))
45                 ao_btm_buffer[ao_btm_ptr++] = c;
46 }
47
48 static void
49 ao_btm_log_char(char c, char dir)
50 {
51         if (dir != ao_btm_dir) {
52                 ao_btm_add_char(dir);
53                 ao_btm_dir = dir;
54         }
55         ao_btm_add_char(c);
56 }
57
58 static void
59 ao_btm_log_out_char(char c)
60 {
61         ao_btm_log_char(c, '>');
62 }
63
64 static void
65 ao_btm_log_in_char(char c)
66 {
67         ao_btm_log_char(c, '<');
68 }
69
70 /*
71  * Dump everything received from the bluetooth device during startup
72  */
73 static void
74 ao_btm_dump(void)
75 {
76         int i;
77         char c;
78
79         for (i = 0; i < ao_btm_ptr; i++) {
80                 c = ao_btm_buffer[i];
81                 if (c < ' ' && c != '\n')
82                         printf("\\%03o", ((int) c) & 0xff);
83                 else
84                         putchar(ao_btm_buffer[i]);
85         }
86         putchar('\n');
87         ao_cmd_decimal();
88         if (ao_cmd_status == ao_cmd_success && ao_cmd_lex_i)
89                 ao_btm_ptr = 0;
90         ao_cmd_status = ao_cmd_success;
91 }
92
93 static void
94 ao_btm_speed(void)
95 {
96         ao_cmd_decimal();
97         if (ao_cmd_lex_u32 == 57600)
98                 ao_serial_btm_set_speed(AO_SERIAL_SPEED_57600);
99         else if (ao_cmd_lex_u32 == 19200)
100                 ao_serial_btm_set_speed(AO_SERIAL_SPEED_19200);
101         else
102                 ao_cmd_status = ao_cmd_syntax_error;
103 }
104
105 static uint8_t  ao_btm_enable;
106
107 static void
108 ao_btm_do_echo(void)
109 {
110         int     c;
111         while (ao_btm_enable) {
112                 ao_arch_block_interrupts();
113                 while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN && ao_btm_enable)
114                         _ao_serial_btm_sleep_for(0);
115                 ao_arch_release_interrupts();
116                 if (c != AO_READ_AGAIN) {
117                         putchar(c);
118                         flush();
119                 }
120         }
121         ao_exit();
122 }
123
124 static struct ao_task ao_btm_echo_task;
125
126 static void
127 ao_btm_send(void)
128 {
129         int c;
130         ao_btm_enable = 1;
131         ao_add_task(&ao_btm_echo_task, ao_btm_do_echo, "btm-echo");
132         while ((c = getchar()) != '~') {
133                 ao_serial_btm_putchar(c);
134         }
135         ao_btm_enable = 0;
136         ao_wakeup((void *) &ao_serial_btm_rx_fifo);
137 }
138
139 __code struct ao_cmds ao_btm_cmds[] = {
140         { ao_btm_dump,          "d\0Dump btm buffer." },
141         { ao_btm_speed,         "s <19200,57600>\0Set btm serial speed." },
142         { ao_btm_send,          "S\0BTM interactive mode. ~ to exit." },
143         { 0, NULL },
144 };
145
146 #define ao_btm_log_init()       ao_cmd_register(&ao_btm_cmds[0])
147
148 #else
149 #define ao_btm_log_in_char(c)
150 #define ao_btm_log_out_char(c)
151 #define ao_btm_log_init()
152 #endif
153
154 #define AO_BTM_MAX_REPLY        16
155 __xdata char            ao_btm_reply[AO_BTM_MAX_REPLY];
156
157 /*
158  * Read one bluetooth character.
159  * Returns AO_READ_AGAIN if no character arrives within 10ms
160  */
161
162 static int
163 ao_btm_getchar(void)
164 {
165         int     c;
166
167         ao_arch_block_interrupts();
168         while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN) {
169                 c = _ao_serial_btm_sleep_for(AO_MS_TO_TICKS(10));
170                 if (c) {
171                         c = AO_READ_AGAIN;
172                         break;
173                 }
174         }
175         ao_arch_release_interrupts();
176         return c;
177 }
178
179 /*
180  * Read a line of data from the serial port, truncating
181  * it after a few characters.
182  */
183
184 uint8_t
185 ao_btm_get_line(void)
186 {
187         uint8_t ao_btm_reply_len = 0;
188         int c;
189         uint8_t l;
190
191         while ((c = ao_btm_getchar()) != AO_READ_AGAIN) {
192                 ao_btm_log_in_char(c);
193                 if (ao_btm_reply_len < sizeof (ao_btm_reply))
194                         ao_btm_reply[ao_btm_reply_len++] = c;
195                 if (c == '\r' || c == '\n')
196                         break;
197         }
198         for (l = ao_btm_reply_len; l < sizeof (ao_btm_reply);)
199                 ao_btm_reply[l++] = '\0';
200         return ao_btm_reply_len;
201 }
202
203 /*
204  * Drain the serial port completely
205  */
206 void
207 ao_btm_drain()
208 {
209         while (ao_btm_get_line())
210                 ;
211 }
212
213 /*
214  * Set the stdio echo for the bluetooth link
215  */
216 void
217 ao_btm_echo(uint8_t echo)
218 {
219         ao_stdios[ao_btm_stdio].echo = echo;
220 }
221
222 /*
223  * Delay between command charaters; the BT module
224  * can't keep up with 57600 baud
225  */
226
227 void
228 ao_btm_putchar(char c)
229 {
230         ao_btm_log_out_char(c);
231         ao_serial_btm_putchar(c);
232         ao_delay(1);
233 }
234
235 /*
236  * Wait for the bluetooth device to return
237  * status from the previously executed command
238  */
239 uint8_t
240 ao_btm_wait_reply(void)
241 {
242         for (;;) {
243                 ao_btm_get_line();
244                 if (!strncmp(ao_btm_reply, "OK", 2))
245                         return 1;
246                 if (!strncmp(ao_btm_reply, "ERROR", 5))
247                         return -1;
248                 if (ao_btm_reply[0] == '\0')
249                         return 0;
250         }
251 }
252
253 void
254 ao_btm_string(__code char *cmd)
255 {
256         char    c;
257
258         while ((c = *cmd++) != '\0')
259                 ao_btm_putchar(c);
260 }
261
262 uint8_t
263 ao_btm_cmd(__code char *cmd)
264 {
265         ao_btm_drain();
266         ao_btm_string(cmd);
267         return ao_btm_wait_reply();
268 }
269
270 uint8_t
271 ao_btm_set_name(void)
272 {
273         char    sn[8];
274         char    *s = sn + 8;
275         char    c;
276         int     n;
277         ao_btm_string("ATN=TeleBT-");
278         *--s = '\0';
279         *--s = '\r';
280         n = ao_serial_number;
281         do {
282                 *--s = '0' + n % 10;
283         } while (n /= 10);
284         while ((c = *s++))
285                 ao_btm_putchar(c);
286         return ao_btm_wait_reply();
287 }
288
289 uint8_t
290 ao_btm_try_speed(uint8_t speed)
291 {
292         ao_serial_btm_set_speed(speed);
293         ao_serial_btm_drain();
294         (void) ao_btm_cmd("\rATE0\rATQ0\r");
295         if (ao_btm_cmd("AT\r") == 1)
296                 return 1;
297         return 0;
298 }
299
300 #if BT_LINK_ON_P2
301 #define BT_PICTL_ICON   PICTL_P2ICON
302 #define BT_PIFG         P2IFG
303 #define BT_PDIR         P2DIR
304 #define BT_PINP         P2INP
305 #define BT_IEN2_PIE     IEN2_P2IE
306 #define BT_CC1111       1
307 #endif
308 #if BT_LINK_ON_P1
309 #define BT_PICTL_ICON   PICTL_P1ICON
310 #define BT_PIFG         P1IFG
311 #define BT_PDIR         P1DIR
312 #define BT_PINP         P1INP
313 #define BT_IEN2_PIE     IEN2_P1IE
314 #define BT_CC1111       1
315 #endif
316
317 void
318 ao_btm_check_link()
319 {
320 #if BT_CC1111
321         ao_arch_critical(
322                 /* Check the pin and configure the interrupt detector to wait for the
323                  * pin to flip the other way
324                  */
325                 if (BT_LINK_PIN) {
326                         ao_btm_connected = 0;
327                         PICTL |= BT_PICTL_ICON;
328                 } else {
329                         ao_btm_connected = 1;
330                         PICTL &= ~BT_PICTL_ICON;
331                 }
332                 );
333 #else
334         ao_arch_block_interrupts();
335         if (ao_gpio_get(AO_BTM_INT_PORT, AO_BTM_INT_PIN, AO_BTM_INT) == 0) {
336                 ao_btm_connected = 1;
337         } else {
338                 ao_btm_connected = 0;
339         }
340         ao_arch_release_interrupts();
341 #endif
342 }
343
344 __xdata struct ao_task ao_btm_task;
345
346 /*
347  * A thread to initialize the bluetooth device and
348  * hang around to blink the LED when connected
349  */
350 void
351 ao_btm(void)
352 {
353         /*
354          * Wait for the bluetooth device to boot
355          */
356         ao_delay(AO_SEC_TO_TICKS(3));
357
358         /*
359          * The first time we connect, the BTM-180 comes up at 19200 baud.
360          * After that, it will remember and come up at 57600 baud. So, see
361          * if it is already running at 57600 baud, and if that doesn't work
362          * then tell it to switch to 57600 from 19200 baud.
363          */
364         while (!ao_btm_try_speed(AO_SERIAL_SPEED_57600)) {
365                 ao_delay(AO_SEC_TO_TICKS(1));
366                 if (ao_btm_try_speed(AO_SERIAL_SPEED_19200))
367                         ao_btm_cmd("ATL4\r");
368                 ao_delay(AO_SEC_TO_TICKS(1));
369         }
370
371         /* Disable echo */
372         ao_btm_cmd("ATE0\r");
373
374         /* Enable flow control */
375         ao_btm_cmd("ATC1\r");
376
377         /* Set the reported name to something we can find on the host */
378         ao_btm_set_name();
379
380         /* Turn off status reporting */
381         ao_btm_cmd("ATQ1\r");
382
383         ao_btm_stdio = ao_add_stdio(_ao_serial_btm_pollchar,
384                                     ao_serial_btm_putchar,
385                                     NULL);
386         ao_btm_echo(0);
387
388         /* Check current pin state */
389         ao_btm_check_link();
390
391 #ifdef AO_BTM_INT_PORT
392         ao_exti_enable(AO_BTM_INT_PORT, AO_BTM_INT_PIN);
393 #endif
394
395         for (;;) {
396                 while (!ao_btm_connected)
397                         ao_sleep(&ao_btm_connected);
398                 while (ao_btm_connected) {
399                         ao_led_for(AO_BT_LED, AO_MS_TO_TICKS(20));
400                         ao_delay(AO_SEC_TO_TICKS(3));
401                 }
402         }
403 }
404
405
406 #if BT_CC1111
407 void
408 ao_btm_isr(void)
409 #if BT_LINK_ON_P1
410         __interrupt 15
411 #endif
412 {
413 #if BT_LINK_ON_P1
414         P1IF = 0;
415 #endif
416         if (BT_PIFG & (1 << BT_LINK_PIN_INDEX)) {
417                 ao_btm_check_link();
418                 ao_wakeup(&ao_btm_connected);
419         }
420         BT_PIFG = 0;
421 }
422 #endif
423
424 #ifdef AO_BTM_INT_PORT
425 void
426 ao_btm_isr(void)
427 {
428         ao_btm_check_link();
429         ao_wakeup(&ao_btm_connected);
430 }
431 #endif
432
433 void
434 ao_btm_init (void)
435 {
436         ao_serial_init();
437
438         ao_serial_btm_set_speed(AO_SERIAL_SPEED_19200);
439
440 #ifdef AO_BTM_RESET_PORT
441         ao_enable_output(AO_BTM_RESET_PORT,AO_BTM_RESET_PIN,AO_BTM_RESET,0);
442 #endif
443
444 #ifdef AO_BTM_INT_PORT
445         ao_enable_port(AO_BTM_INT_PORT);
446         ao_exti_setup(AO_BTM_INT_PORT, AO_BTM_INT_PIN,
447                       AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_LOW,
448                       ao_btm_isr);
449 #endif
450
451 #if BT_CC1111
452 #if BT_LINK_ON_P1
453         /*
454          * Configure ser reset line
455          */
456
457         P1_6 = 0;
458         P1DIR |= (1 << 6);
459 #endif
460
461         /*
462          * Configure link status line
463          */
464
465         /* Set pin to input */
466         BT_PDIR &= ~(1 << BT_LINK_PIN_INDEX);
467
468         /* Set pin to tri-state */
469         BT_PINP |= (1 << BT_LINK_PIN_INDEX);
470
471         /* Enable interrupts */
472         IEN2 |= BT_IEN2_PIE;
473 #endif
474
475 #if BT_LINK_ON_P2
476         /* Eable the pin interrupt */
477         PICTL |= PICTL_P2IEN;
478 #endif
479 #if BT_LINK_ON_P1
480         /* Enable pin interrupt */
481         P1IEN |= (1 << BT_LINK_PIN_INDEX);
482 #endif
483
484         ao_add_task(&ao_btm_task, ao_btm, "bt");
485         ao_btm_log_init();
486 }