altos: Make stdio 8-bit clean by making pollchar return int
[fw/altos] / src / cc1111 / 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 const __code struct ao_serial_speed ao_serial_speeds[] = {
21         /* [AO_SERIAL_SPEED_4800] = */ {
22                 /* .baud = */ 163,
23                 /* .gcr  = */ (7 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
24         },
25         /* [AO_SERIAL_SPEED_9600] = */ {
26                 /* .baud = */ 163,
27                 /* .gcr  = */ (8 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
28         },
29         /* [AO_SERIAL_SPEED_19200] = */ {
30                 /* .baud = */ 163,
31                 /* .gcr  = */ (9 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
32         },
33         /* [AO_SERIAL_SPEED_57600] = */ {
34                 /* .baud = */ 59,
35                 /* .gcr =  */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
36         },
37 };
38
39 #if HAS_SERIAL_0
40
41 volatile __xdata struct ao_fifo ao_serial0_rx_fifo;
42 volatile __xdata struct ao_fifo ao_serial0_tx_fifo;
43
44 void
45 ao_serial0_rx_isr(void) __interrupt 2
46 {
47         if (!ao_fifo_full(ao_serial0_rx_fifo))
48                 ao_fifo_insert(ao_serial0_rx_fifo, U0DBUF);
49         ao_wakeup(&ao_serial0_rx_fifo);
50 #if USE_SERIAL_0_STDIN
51         ao_wakeup(&ao_stdin_ready);
52 #endif
53 }
54
55 static __xdata uint8_t ao_serial0_tx_started;
56
57 static void
58 ao_serial0_tx_start(void)
59 {
60         if (!ao_fifo_empty(ao_serial0_tx_fifo) &&
61             !ao_serial0_tx_started)
62         {
63                 ao_serial0_tx_started = 1;
64                 ao_fifo_remove(ao_serial0_tx_fifo, U0DBUF);
65         }
66 }
67
68 void
69 ao_serial0_tx_isr(void) __interrupt 7
70 {
71         UTX0IF = 0;
72         ao_serial0_tx_started = 0;
73         ao_serial0_tx_start();
74         ao_wakeup(&ao_serial0_tx_fifo);
75 }
76
77 char
78 ao_serial0_getchar(void) __critical
79 {
80         char    c;
81         while (ao_fifo_empty(ao_serial0_rx_fifo))
82                 ao_sleep(&ao_serial0_rx_fifo);
83         ao_fifo_remove(ao_serial0_rx_fifo, c);
84         return c;
85 }
86
87 #if USE_SERIAL_0_STDIN
88 int
89 ao_serial0_pollchar(void) __critical
90 {
91         uint8_t c;
92         if (ao_fifo_empty(ao_serial0_rx_fifo))
93                 return AO_READ_AGAIN;
94         ao_fifo_remove(ao_serial0_rx_fifo,c);
95         return c;
96 }
97 #endif
98
99 void
100 ao_serial0_putchar(char c) __critical
101 {
102         while (ao_fifo_full(ao_serial0_tx_fifo))
103                 ao_sleep(&ao_serial0_tx_fifo);
104         ao_fifo_insert(ao_serial0_tx_fifo, c);
105         ao_serial0_tx_start();
106 }
107
108 void
109 ao_serial0_drain(void) __critical
110 {
111         while (!ao_fifo_empty(ao_serial0_tx_fifo))
112                 ao_sleep(&ao_serial0_tx_fifo);
113 }
114
115 void
116 ao_serial0_set_speed(uint8_t speed)
117 {
118         ao_serial0_drain();
119         if (speed > AO_SERIAL_SPEED_57600)
120                 return;
121         U0UCR |= UxUCR_FLUSH;
122         U0BAUD = ao_serial_speeds[speed].baud;
123         U0GCR = ao_serial_speeds[speed].gcr;
124 }
125 #endif /* HAS_SERIAL_0 */
126
127 #if HAS_SERIAL_1
128
129 volatile __xdata struct ao_fifo ao_serial1_rx_fifo;
130 volatile __xdata struct ao_fifo ao_serial1_tx_fifo;
131
132 void
133 ao_serial1_rx_isr(void) __interrupt 3
134 {
135         if (!ao_fifo_full(ao_serial1_rx_fifo))
136                 ao_fifo_insert(ao_serial1_rx_fifo, U1DBUF);
137         ao_wakeup(&ao_serial1_rx_fifo);
138 #if USE_SERIAL_1_STDIN
139         ao_wakeup(&ao_stdin_ready);
140 #endif
141 }
142
143 static __xdata uint8_t ao_serial1_tx_started;
144
145 static void
146 ao_serial1_tx_start(void)
147 {
148         if (!ao_fifo_empty(ao_serial1_tx_fifo) &&
149             !ao_serial1_tx_started)
150         {
151                 ao_serial1_tx_started = 1;
152                 ao_fifo_remove(ao_serial1_tx_fifo, U1DBUF);
153         }
154 }
155
156 void
157 ao_serial1_tx_isr(void) __interrupt 14
158 {
159         UTX1IF = 0;
160         ao_serial1_tx_started = 0;
161         ao_serial1_tx_start();
162         ao_wakeup(&ao_serial1_tx_fifo);
163 }
164
165 char
166 ao_serial1_getchar(void) __critical
167 {
168         char    c;
169         while (ao_fifo_empty(ao_serial1_rx_fifo))
170                 ao_sleep(&ao_serial1_rx_fifo);
171         ao_fifo_remove(ao_serial1_rx_fifo, c);
172         return c;
173 }
174
175 #if USE_SERIAL_1_STDIN
176 int
177 ao_serial1_pollchar(void) __critical
178 {
179         uint8_t c;
180         if (ao_fifo_empty(ao_serial1_rx_fifo))
181                 return AO_READ_AGAIN;
182         ao_fifo_remove(ao_serial1_rx_fifo,c);
183         return c;
184 }
185 #endif
186
187 void
188 ao_serial1_putchar(char c) __critical
189 {
190         while (ao_fifo_full(ao_serial1_tx_fifo))
191                 ao_sleep(&ao_serial1_tx_fifo);
192         ao_fifo_insert(ao_serial1_tx_fifo, c);
193         ao_serial1_tx_start();
194 }
195
196 void
197 ao_serial1_drain(void) __critical
198 {
199         while (!ao_fifo_empty(ao_serial1_tx_fifo))
200                 ao_sleep(&ao_serial1_tx_fifo);
201 }
202
203 void
204 ao_serial1_set_speed(uint8_t speed)
205 {
206         ao_serial1_drain();
207         if (speed > AO_SERIAL_SPEED_57600)
208                 return;
209         U1UCR |= UxUCR_FLUSH;
210         U1BAUD = ao_serial_speeds[speed].baud;
211         U1GCR = ao_serial_speeds[speed].gcr;
212 }
213
214 #endif /* HAS_SERIAL_1 */
215
216 void
217 ao_serial_init(void)
218 {
219 #if HAS_SERIAL_0
220 #if HAS_SERIAL_0_ALT_1
221         /* Set up the USART pin assignment */
222         PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_1;
223
224         P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART0_USART1;
225
226         /* Make the USART pins be controlled by the USART */
227         P0SEL |= (1 << 2) | (1 << 3);
228 #if HAS_SERIAL_0_HW_FLOW
229         P0SEL |= (1 << 4) | (1 << 5);
230 #endif
231 #else
232         /* Set up the USART pin assignment */
233         PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2;
234
235         P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI0P1_MASK)) |
236                 (P2SEL_PRI3P1_USART0 | P2SEL_PRI0P1_USART0);
237
238         /* Make the USART pins be controlled by the USART */
239         P1SEL |= (1 << 5) | (1 << 4);
240 #if HAS_SERIAL_0_HW_FLOW
241         P1SEL |= (1 << 3) | (1 << 2);
242 #endif
243 #endif
244
245         /* UART mode with receiver enabled */
246         U0CSR = (UxCSR_MODE_UART | UxCSR_RE);
247
248         /* Pick a 9600 baud rate */
249         ao_serial0_set_speed(AO_SERIAL_SPEED_9600);
250
251         /* Reasonable serial parameters */
252         U0UCR = (UxUCR_FLUSH |
253 #if HAS_SERIAL_0_HW_FLOW
254                  UxUCR_FLOW_ENABLE |
255 #else
256                  UxUCR_FLOW_DISABLE |
257 #endif
258                  UxUCR_D9_EVEN_PARITY |
259                  UxUCR_BIT9_8_BITS |
260                  UxUCR_PARITY_DISABLE |
261                  UxUCR_SPB_1_STOP_BIT |
262                  UxUCR_STOP_HIGH |
263                  UxUCR_START_LOW);
264
265         IEN0 |= IEN0_URX0IE;
266         IEN2 |= IEN2_UTX0IE;
267 #if USE_SERIAL_0_STDIN && !DELAY_SERIAL_0_STDIN
268         ao_add_stdio(ao_serial0_pollchar,
269                      ao_serial0_putchar,
270                      NULL);
271 #endif
272 #endif /* HAS_SERIAL_0 */
273
274 #if HAS_SERIAL_1
275 #if HAS_SERIAL_1_ALT_1
276         /* Set up the USART pin assignment */
277         PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1;
278
279         P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART1_USART0;
280
281         /* Make the USART pins be controlled by the USART */
282         P0SEL |= (1 << 5) | (1 << 4);
283 #if HAS_SERIAL_1_HW_FLOW
284         P0SEL |= (1 << 3) | (1 << 2);
285 #endif
286 #else
287         /* Set up the USART pin assignment */
288         PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2;
289
290         P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI2P1_MASK)) |
291                 (P2SEL_PRI3P1_USART1 | P2SEL_PRI2P1_USART1);
292
293         /* Make the USART pins be controlled by the USART */
294         P1SEL |= (1 << 6) | (1 << 7);
295 #if HAS_SERIAL_1_HW_FLOW
296         P1SEL |= (1 << 5) | (1 << 4);
297 #endif
298 #endif
299
300         /* UART mode with receiver enabled */
301         U1CSR = (UxCSR_MODE_UART | UxCSR_RE);
302
303         /* Pick a 4800 baud rate */
304         ao_serial1_set_speed(AO_SERIAL_SPEED_4800);
305
306         /* Reasonable serial parameters */
307         U1UCR = (UxUCR_FLUSH |
308 #if HAS_SERIAL_1_HW_FLOW
309                  UxUCR_FLOW_ENABLE |
310 #else
311                  UxUCR_FLOW_DISABLE |
312 #endif
313                  UxUCR_D9_EVEN_PARITY |
314                  UxUCR_BIT9_8_BITS |
315                  UxUCR_PARITY_DISABLE |
316                  UxUCR_SPB_1_STOP_BIT |
317                  UxUCR_STOP_HIGH |
318                  UxUCR_START_LOW);
319
320         IEN0 |= IEN0_URX1IE;
321         IEN2 |= IEN2_UTX1IE;
322
323 #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
324         ao_add_stdio(ao_serial1_pollchar,
325                      ao_serial1_putchar,
326                      NULL);
327 #endif
328 #endif /* HAS_SERIAL_1 */
329 }