c3b51d123ef1407702200798feaf17c6711c3e02
[fw/altos] / src / kernel / ao_stdio.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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao.h"
20
21 /*
22  * Basic I/O functions to support SDCC stdio package
23  */
24
25 #ifndef USE_SERIAL_0_STDIN
26 #define USE_SERIAL_0_STDIN      0
27 #endif
28 #ifndef USE_SERIAL_1_STDIN
29 #define USE_SERIAL_1_STDIN      0
30 #endif
31 #ifndef USE_SERIAL_2_STDIN
32 #define USE_SERIAL_2_STDIN      0
33 #endif
34 #ifndef USE_SERIAL_3_STDIN
35 #define USE_SERIAL_3_STDIN      0
36 #endif
37 #ifndef USE_SERIAL_4_STDIN
38 #define USE_SERIAL_4_STDIN      0
39 #endif
40 #ifndef USE_SERIAL_5_STDIN
41 #define USE_SERIAL_5_STDIN      0
42 #endif
43 #ifndef USE_SERIAL_6_STDIN
44 #define USE_SERIAL_6_STDIN      0
45 #endif
46 #ifndef USE_SERIAL_7_STDIN
47 #define USE_SERIAL_7_STDIN      0
48 #endif
49 #ifndef USE_SERIAL_8_STDIN
50 #define USE_SERIAL_8_STDIN      0
51 #endif
52 #ifndef USE_SERIAL_9_STDIN
53 #define USE_SERIAL_9_STDIN      0
54 #endif
55 #ifndef PACKET_HAS_SLAVE
56 #define PACKET_HAS_SLAVE        0
57 #endif
58 #ifndef CONSOLE_STDIN
59 #define CONSOLE_STDIN           0
60 #endif
61
62 #define USE_SERIAL_STDIN (USE_SERIAL_0_STDIN +  \
63                           USE_SERIAL_1_STDIN +  \
64                           USE_SERIAL_2_STDIN +  \
65                           USE_SERIAL_3_STDIN +  \
66                           USE_SERIAL_4_STDIN +  \
67                           USE_SERIAL_5_STDIN +  \
68                           USE_SERIAL_6_STDIN +  \
69                           USE_SERIAL_7_STDIN +  \
70                           USE_SERIAL_8_STDIN +  \
71                           USE_SERIAL_9_STDIN)
72
73 #define AO_NUM_STDIOS   (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN + CONSOLE_STDIN)
74
75 struct ao_stdio ao_stdios[AO_NUM_STDIOS];
76
77 #if AO_NUM_STDIOS > 1
78 int8_t ao_cur_stdio;
79 int8_t ao_num_stdios;
80 #else
81 int8_t ao_cur_stdio;
82 #define ao_cur_stdio    0
83 #define ao_num_stdios   0
84 #endif
85
86 int
87 ao_putchar(char c)
88 {
89 #if LOW_LEVEL_DEBUG
90         if (!ao_cur_task) {
91                 extern void ao_debug_out(char c);
92                 if (c == '\n')
93                         ao_debug_out('\r');
94                 ao_debug_out(c);
95                 return 0;
96         }
97 #endif
98         if (c == '\n')
99                 (*ao_stdios[ao_cur_stdio].putchar)('\r');
100         (*ao_stdios[ao_cur_stdio].putchar)(c);
101         return 0;
102 }
103
104 void
105 flush(void)
106 {
107         if (ao_stdios[ao_cur_stdio].flush)
108                 ao_stdios[ao_cur_stdio].flush();
109 }
110
111 uint8_t ao_stdin_ready;
112
113 char
114 ao_getchar(void) 
115 {
116         int c;
117         int8_t stdio;
118
119         ao_arch_block_interrupts();
120         stdio = ao_cur_stdio;
121         for (;;) {
122                 c = ao_stdios[stdio]._pollchar();
123                 if (c != AO_READ_AGAIN)
124                         break;
125 #if AO_NUM_STDIOS > 1
126                 if (++stdio == ao_num_stdios)
127                         stdio = 0;
128                 if (stdio == ao_cur_stdio)
129 #endif
130                         ao_sleep(&ao_stdin_ready);
131         }
132 #if AO_NUM_STDIOS > 1
133         ao_cur_stdio = stdio;
134 #endif
135         ao_arch_release_interrupts();
136         return c;
137 }
138
139 uint8_t
140 ao_echo(void)
141 {
142         return ao_stdios[ao_cur_stdio].echo;
143 }
144
145 int8_t
146 ao_add_stdio(int (*_pollchar)(void),
147              void (*putchar)(char),
148              void (*flush)(void)) 
149 {
150         if (ao_num_stdios == AO_NUM_STDIOS)
151                 ao_panic(AO_PANIC_STDIO);
152         ao_stdios[ao_num_stdios]._pollchar = _pollchar;
153         ao_stdios[ao_num_stdios].putchar = putchar;
154         ao_stdios[ao_num_stdios].flush = flush;
155         ao_stdios[ao_num_stdios].echo = 1;
156 #if AO_NUM_STDIOS > 1
157         return ao_num_stdios++;
158 #else
159         return 0;
160 #endif
161 }
162
163 /*
164  * Basic I/O functions to support newlib tinystdio package
165  */
166
167 static int
168 ao_putc(char c, FILE *ignore)
169 {
170         (void) ignore;
171         return ao_putchar(c);
172 }
173
174 static int
175 ao_getc(FILE *ignore)
176 {
177         (void) ignore;
178         return ao_getchar();
179 }
180
181 static int
182 ao_flushc(FILE *ignore)
183 {
184         (void) ignore;
185         flush();
186         return 0;
187 }
188
189 static FILE __stdio = FDEV_SETUP_STREAM(ao_putc, ao_getc, ao_flushc, _FDEV_SETUP_RW);
190
191 FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio };