Provide install target
[fw/altos] / ao_serial.c
1 /*
2  * Copyright © 2009 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
20 #define SERIAL_FIFO     32
21
22 struct ao_fifo {
23         uint8_t insert;
24         uint8_t remove;
25         char    fifo[SERIAL_FIFO];
26 };
27
28 volatile __xdata struct ao_fifo ao_usart1_rx_fifo;
29 volatile __xdata struct ao_fifo ao_usart1_tx_fifo;
30
31 #define ao_fifo_insert(f,c) do { \
32         (f).fifo[(f).insert] = (c); \
33         (f).insert = ((f).insert + 1) & (SERIAL_FIFO-1); \
34 } while(0)
35
36 #define ao_fifo_remove(f,c) do {\
37         c = (f).fifo[(f).remove]; \
38         (f).remove = ((f).remove + 1) & (SERIAL_FIFO-1); \
39 } while(0)
40
41 #define ao_fifo_full(f) ((((f).insert + 1) & (SERIAL_FIFO-1)) == (f).remove)
42 #define ao_fifo_empty(f)        ((f).insert == (f).remove)
43
44 void
45 ao_serial_rx1_isr(void) interrupt 3
46 {
47         if (!ao_fifo_full(ao_usart1_rx_fifo))
48                 ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF);
49         ao_wakeup(&ao_usart1_rx_fifo);
50 }
51
52 static __xdata uint8_t ao_serial_tx1_started;
53
54 static void
55 ao_serial_tx1_start(void)
56 {
57         if (!ao_fifo_empty(ao_usart1_tx_fifo) &&
58             !ao_serial_tx1_started)
59         {
60                 ao_serial_tx1_started = 1;
61                 ao_fifo_remove(ao_usart1_tx_fifo, U1DBUF);
62         }
63 }
64
65 void
66 ao_serial_tx1_isr(void) interrupt 14
67 {
68         UTX1IF = 0;
69         ao_serial_tx1_started = 0;
70         ao_serial_tx1_start();
71         ao_wakeup(&ao_usart1_tx_fifo);
72 }
73
74 char
75 ao_serial_getchar(void) __critical
76 {
77         char    c;
78         while (ao_fifo_empty(ao_usart1_rx_fifo))
79                 ao_sleep(&ao_usart1_rx_fifo);
80         ao_fifo_remove(ao_usart1_rx_fifo, c);
81         return c;
82 }
83
84 void
85 ao_serial_putchar(char c) __critical
86 {
87         while (ao_fifo_full(ao_usart1_tx_fifo))
88                 ao_sleep(&ao_usart1_tx_fifo);
89         ao_fifo_insert(ao_usart1_tx_fifo, c);
90         ao_serial_tx1_start();
91 }
92
93 static void
94 send_serial(void)
95 {
96         ao_cmd_white();
97         while (ao_cmd_lex_c != '\n') {
98                 ao_serial_putchar(ao_cmd_lex_c);
99                 ao_cmd_lex();
100         }
101 }
102
103 __code struct ao_cmds ao_serial_cmds[] = {
104         { 'S', send_serial,             "S <data>                           Send data to serial line" },
105         { 0, send_serial, NULL },
106 };
107
108 void
109 ao_serial_init(void)
110 {
111         /* Set up the USART pin assignment */
112         PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2;
113
114         /* ee has already set the P2SEL bits */
115
116         /* Make the USART pins be controlled by the USART */
117         P1SEL |= (1 << 6) | (1 << 7);
118
119         /* UART mode with receiver enabled */
120         U1CSR = (UxCSR_MODE_UART | UxCSR_RE);
121
122         /* Pick a 4800 baud rate */
123         U1BAUD = 163;                           /* 4800 */
124         U1GCR = 7 << UxGCR_BAUD_E_SHIFT;        /* 4800 */
125
126         /* Reasonable serial parameters */
127         U1UCR = (UxUCR_FLUSH |
128                  UxUCR_FLOW_DISABLE |
129                  UxUCR_D9_ODD_PARITY |
130                  UxUCR_BIT9_8_BITS |
131                  UxUCR_PARITY_DISABLE |
132                  UxUCR_SPB_1_STOP_BIT |
133                  UxUCR_STOP_HIGH |
134                  UxUCR_START_LOW);
135
136         IEN0 |= IEN0_URX1IE;
137         IEN2 |= IEN2_UTX1IE;
138
139         ao_cmd_register(&ao_serial_cmds[0]);
140 }