swap names so v3.0 is the default TeleDongle version to turn on
[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()  ao_sleep((void *) &ao_serial1_rx_fifo)
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();
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                 ao_alarm(AO_MS_TO_TICKS(10));
170                 c = _ao_serial_btm_sleep();
171                 ao_clear_alarm();
172                 if (c) {
173                         c = AO_READ_AGAIN;
174                         break;
175                 }
176         }
177         ao_arch_release_interrupts();
178         return c;
179 }
180
181 /*
182  * Read a line of data from the serial port, truncating
183  * it after a few characters.
184  */
185
186 uint8_t
187 ao_btm_get_line(void)
188 {
189         uint8_t ao_btm_reply_len = 0;
190         int c;
191         uint8_t l;
192
193         while ((c = ao_btm_getchar()) != AO_READ_AGAIN) {
194                 ao_btm_log_in_char(c);
195                 if (ao_btm_reply_len < sizeof (ao_btm_reply))
196                         ao_btm_reply[ao_btm_reply_len++] = c;
197                 if (c == '\r' || c == '\n')
198                         break;
199         }
200         for (l = ao_btm_reply_len; l < sizeof (ao_btm_reply);)
201                 ao_btm_reply[l++] = '\0';
202         return ao_btm_reply_len;
203 }
204
205 /*
206  * Drain the serial port completely
207  */
208 void
209 ao_btm_drain()
210 {
211         while (ao_btm_get_line())
212                 ;
213 }
214
215 /*
216  * Set the stdio echo for the bluetooth link
217  */
218 void
219 ao_btm_echo(uint8_t echo)
220 {
221         ao_stdios[ao_btm_stdio].echo = echo;
222 }
223
224 /*
225  * Delay between command charaters; the BT module
226  * can't keep up with 57600 baud
227  */
228
229 void
230 ao_btm_putchar(char c)
231 {
232         ao_btm_log_out_char(c);
233         ao_serial_btm_putchar(c);
234         ao_delay(1);
235 }
236
237 /*
238  * Wait for the bluetooth device to return
239  * status from the previously executed command
240  */
241 uint8_t
242 ao_btm_wait_reply(void)
243 {
244         for (;;) {
245                 ao_btm_get_line();
246                 if (!strncmp(ao_btm_reply, "OK", 2))
247                         return 1;
248                 if (!strncmp(ao_btm_reply, "ERROR", 5))
249                         return -1;
250                 if (ao_btm_reply[0] == '\0')
251                         return 0;
252         }
253 }
254
255 void
256 ao_btm_string(__code char *cmd)
257 {
258         char    c;
259
260         while ((c = *cmd++) != '\0')
261                 ao_btm_putchar(c);
262 }
263
264 uint8_t
265 ao_btm_cmd(__code char *cmd)
266 {
267         ao_btm_drain();
268         ao_btm_string(cmd);
269         return ao_btm_wait_reply();
270 }
271
272 uint8_t
273 ao_btm_set_name(void)
274 {
275         char    sn[8];
276         char    *s = sn + 8;
277         char    c;
278         int     n;
279         ao_btm_string("ATN=TeleBT-");
280         *--s = '\0';
281         *--s = '\r';
282         n = ao_serial_number;
283         do {
284                 *--s = '0' + n % 10;
285         } while (n /= 10);
286         while ((c = *s++))
287                 ao_btm_putchar(c);
288         return ao_btm_wait_reply();
289 }
290
291 uint8_t
292 ao_btm_try_speed(uint8_t speed)
293 {
294         ao_serial_btm_set_speed(speed);
295         ao_serial_btm_drain();
296         (void) ao_btm_cmd("\rATE0\rATQ0\r");
297         if (ao_btm_cmd("AT\r") == 1)
298                 return 1;
299         return 0;
300 }
301
302 #if BT_LINK_ON_P2
303 #define BT_PICTL_ICON   PICTL_P2ICON
304 #define BT_PIFG         P2IFG
305 #define BT_PDIR         P2DIR
306 #define BT_PINP         P2INP
307 #define BT_IEN2_PIE     IEN2_P2IE
308 #define BT_CC1111       1
309 #endif
310 #if BT_LINK_ON_P1
311 #define BT_PICTL_ICON   PICTL_P1ICON
312 #define BT_PIFG         P1IFG
313 #define BT_PDIR         P1DIR
314 #define BT_PINP         P1INP
315 #define BT_IEN2_PIE     IEN2_P1IE
316 #define BT_CC1111       1
317 #endif
318
319 void
320 ao_btm_check_link()
321 {
322 #if BT_CC1111
323         ao_arch_critical(
324                 /* Check the pin and configure the interrupt detector to wait for the
325                  * pin to flip the other way
326                  */
327                 if (BT_LINK_PIN) {
328                         ao_btm_connected = 0;
329                         PICTL |= BT_PICTL_ICON;
330                 } else {
331                         ao_btm_connected = 1;
332                         PICTL &= ~BT_PICTL_ICON;
333                 }
334                 );
335 #else
336         ao_arch_block_interrupts();
337         if (ao_gpio_get(AO_BTM_INT_PORT, AO_BTM_INT_PIN, AO_BTM_INT) == 0) {
338                 ao_btm_connected = 1;
339         } else {
340                 ao_btm_connected = 0;
341         }
342         ao_arch_release_interrupts();
343 #endif
344 }
345
346 __xdata struct ao_task ao_btm_task;
347
348 /*
349  * A thread to initialize the bluetooth device and
350  * hang around to blink the LED when connected
351  */
352 void
353 ao_btm(void)
354 {
355         /*
356          * Wait for the bluetooth device to boot
357          */
358         ao_delay(AO_SEC_TO_TICKS(3));
359
360         /*
361          * The first time we connect, the BTM-180 comes up at 19200 baud.
362          * After that, it will remember and come up at 57600 baud. So, see
363          * if it is already running at 57600 baud, and if that doesn't work
364          * then tell it to switch to 57600 from 19200 baud.
365          */
366         while (!ao_btm_try_speed(AO_SERIAL_SPEED_57600)) {
367                 ao_delay(AO_SEC_TO_TICKS(1));
368                 if (ao_btm_try_speed(AO_SERIAL_SPEED_19200))
369                         ao_btm_cmd("ATL4\r");
370                 ao_delay(AO_SEC_TO_TICKS(1));
371         }
372
373         /* Disable echo */
374         ao_btm_cmd("ATE0\r");
375
376         /* Enable flow control */
377         ao_btm_cmd("ATC1\r");
378
379         /* Set the reported name to something we can find on the host */
380         ao_btm_set_name();
381
382         /* Turn off status reporting */
383         ao_btm_cmd("ATQ1\r");
384
385         ao_btm_stdio = ao_add_stdio(_ao_serial_btm_pollchar,
386                                     ao_serial_btm_putchar,
387                                     NULL);
388         ao_btm_echo(0);
389
390         /* Check current pin state */
391         ao_btm_check_link();
392
393 #ifdef AO_BTM_INT_PORT
394         ao_exti_enable(AO_BTM_INT_PORT, AO_BTM_INT_PIN);
395 #endif
396
397         for (;;) {
398                 while (!ao_btm_connected)
399                         ao_sleep(&ao_btm_connected);
400                 while (ao_btm_connected) {
401                         ao_led_for(AO_BT_LED, AO_MS_TO_TICKS(20));
402                         ao_delay(AO_SEC_TO_TICKS(3));
403                 }
404         }
405 }
406
407
408 #if BT_CC1111
409 void
410 ao_btm_isr(void)
411 #if BT_LINK_ON_P1
412         __interrupt 15
413 #endif
414 {
415 #if BT_LINK_ON_P1
416         P1IF = 0;
417 #endif
418         if (BT_PIFG & (1 << BT_LINK_PIN_INDEX)) {
419                 ao_btm_check_link();
420                 ao_wakeup(&ao_btm_connected);
421         }
422         BT_PIFG = 0;
423 }
424 #endif
425
426 #ifdef AO_BTM_INT_PORT
427 void
428 ao_btm_isr(void)
429 {
430         ao_btm_check_link();
431         ao_wakeup(&ao_btm_connected);
432 }
433 #endif
434
435 void
436 ao_btm_init (void)
437 {
438         ao_serial_init();
439
440         ao_serial_btm_set_speed(AO_SERIAL_SPEED_19200);
441
442 #ifdef AO_BTM_RESET_PORT
443         ao_enable_output(AO_BTM_RESET_PORT,AO_BTM_RESET_PIN,AO_BTM_RESET,0);
444 #endif
445
446 #ifdef AO_BTM_INT_PORT
447         ao_enable_port(AO_BTM_INT_PORT);
448         ao_exti_setup(AO_BTM_INT_PORT, AO_BTM_INT_PIN,
449                       AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_LOW,
450                       ao_btm_isr);
451 #endif
452
453 #if BT_CC1111
454 #if BT_LINK_ON_P1
455         /*
456          * Configure ser reset line
457          */
458
459         P1_6 = 0;
460         P1DIR |= (1 << 6);
461 #endif
462
463         /*
464          * Configure link status line
465          */
466
467         /* Set pin to input */
468         BT_PDIR &= ~(1 << BT_LINK_PIN_INDEX);
469
470         /* Set pin to tri-state */
471         BT_PINP |= (1 << BT_LINK_PIN_INDEX);
472
473         /* Enable interrupts */
474         IEN2 |= BT_IEN2_PIE;
475 #endif
476
477 #if BT_LINK_ON_P2
478         /* Eable the pin interrupt */
479         PICTL |= PICTL_P2IEN;
480 #endif
481 #if BT_LINK_ON_P1
482         /* Enable pin interrupt */
483         P1IEN |= (1 << BT_LINK_PIN_INDEX);
484 #endif
485
486         ao_add_task(&ao_btm_task, ao_btm, "bt");
487         ao_btm_log_init();
488 }