4 Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
6 This file is part of simavr.
8 simavr is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 simavr is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with simavr. If not, see <http://www.gnu.org/licenses/>.
22 #include "sim_network.h"
40 DEFINE_FIFO(uint8_t,uart_pty_fifo);
42 //#define TRACE(_w) _w
47 #define LOCK_MUTEX { TRACE(printf("%s lock: %p\n", __FUNCTION__ , (void*)pthread_self())); pthread_mutex_lock(&p->lock); }
48 #define UNLOCK_MUTEX { pthread_mutex_unlock(&p->lock); TRACE(printf("%s unlock: %p\n", __FUNCTION__ , (void*)pthread_self())); }
51 * called when a byte is send via the uart on the AVR
55 struct avr_irq_t * irq,
59 uart_pty_t * p = (uart_pty_t*)param;
61 TRACE(printf("uart_pty_in_hook %02x\n", value);)
62 uart_pty_fifo_write(&p->pty.in, value);
65 if (p->tap.crlf && value == '\n')
66 uart_pty_fifo_write(&p->tap.in, '\r');
67 uart_pty_fifo_write(&p->tap.in, value);
72 // try to empty our fifo, the uart_pty_xoff_hook() will be called when
75 uart_pty_flush_incoming(
79 while (p->xon && !uart_pty_fifo_isempty(&p->pty.out)) {
80 uint8_t byte = uart_pty_fifo_read(&p->pty.out);
81 TRACE(printf("uart_pty_flush_incoming send %02x\n", byte);)
82 avr_raise_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, byte);
85 if (p->tap.crlf && byte == '\n')
86 uart_pty_fifo_write(&p->tap.in, '\r');
87 uart_pty_fifo_write(&p->tap.in, byte);
91 while (p->xon && !uart_pty_fifo_isempty(&p->tap.out)) {
92 uint8_t byte = uart_pty_fifo_read(&p->tap.out);
93 if (p->tap.crlf && byte == '\r') {
94 uart_pty_fifo_write(&p->tap.in, '\n');
98 uart_pty_fifo_write(&p->tap.in, byte);
99 avr_raise_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, byte);
106 * Called when the uart has room in it's input buffer. This is called repeateadly
107 * if necessary, while the xoff is called only when the uart fifo is FULL
111 struct avr_irq_t * irq,
115 uart_pty_t * p = (uart_pty_t*)param;
116 TRACE(if (!p->xon) printf("uart_pty_xon_hook\n");)
118 uart_pty_flush_incoming(p);
122 * Called when the uart ran out of room in it's input buffer
126 struct avr_irq_t * irq,
130 uart_pty_t * p = (uart_pty_t*)param;
131 TRACE(if (p->xon) printf("uart_pty_xoff_hook\n");)
139 uart_pty_t * p = (uart_pty_t*)param;
142 fd_set read_set, write_set;
147 for (int ti = 0; ti < 2; ti++) if (p->port[ti].s) {
148 // read more only if buffer was flushed
149 if (p->port[ti].buffer_len == p->port[ti].buffer_done) {
150 FD_SET(p->port[ti].s, &read_set);
151 max = p->port[ti].s > max ? p->port[ti].s : max;
153 if (!uart_pty_fifo_isempty(&p->port[ti].in)) {
154 FD_SET(p->port[ti].s, &write_set);
155 max = p->port[ti].s > max ? p->port[ti].s : max;
159 struct timeval timo = { 0, 500 }; // short, but not too short interval
160 int ret = select(max+1, &read_set, &write_set, NULL, &timo);
167 for (int ti = 0; ti < 2; ti++) if (p->port[ti].s) {
168 if (FD_ISSET(p->port[ti].s, &read_set)) {
170 ssize_t r = read(p->port[ti].s, p->port[ti].buffer, sizeof(p->port[ti].buffer)-1);
171 p->port[ti].buffer_len = r;
172 p->port[ti].buffer_done = 0;
173 TRACE(hdump("pty recv", p->port[ti].buffer, r);)
176 if (p->port[ti].buffer_done < p->port[ti].buffer_len) {
178 // write them in fifo
179 while (p->port[ti].buffer_done < p->port[ti].buffer_len &&
180 !uart_pty_fifo_isfull(&p->port[ti].out))
181 uart_pty_fifo_write(&p->port[ti].out,
182 p->port[ti].buffer[p->port[ti].buffer_done++]);
185 if (FD_ISSET(p->port[ti].s, &write_set)) {
188 // write them in fifo
189 uint8_t * dst = buffer;
190 while (!uart_pty_fifo_isempty(&p->port[ti].in) &&
191 dst < (buffer + sizeof(buffer)))
192 *dst++ = uart_pty_fifo_read(&p->port[ti].in);
193 size_t len = dst - buffer;
194 TRACE(size_t r =) write(p->port[ti].s, buffer, len);
195 TRACE(hdump("pty send", buffer, r);)
199 uart_pty_flush_incoming(p);
204 static const char * irq_names[IRQ_UART_PTY_COUNT] = {
205 [IRQ_UART_PTY_BYTE_IN] = "8<uart_pty.in",
206 [IRQ_UART_PTY_BYTE_OUT] = "8>uart_pty.out",
214 memset(p, 0, sizeof(*p));
217 p->irq = avr_alloc_irq(&avr->irq_pool, 0, IRQ_UART_PTY_COUNT, irq_names);
218 avr_irq_register_notify(p->irq + IRQ_UART_PTY_BYTE_IN, uart_pty_in_hook, p);
220 int hastap = (getenv("SIMAVR_UART_TAP") && atoi(getenv("SIMAVR_UART_TAP"))) ||
221 (getenv("SIMAVR_UART_XTERM") && atoi(getenv("SIMAVR_UART_XTERM"))) ;
223 for (int ti = 0; ti < 1 + hastap; ti++) {
226 if (openpty(&m, &s, p->port[ti].slavename, NULL, NULL) < 0) {
227 fprintf(stderr, "%s: Can't create pty: %s", __FUNCTION__, strerror(errno));
233 tcsetattr(m, TCSANOW, &tio);
235 p->port[ti].tap = ti != 0;
236 p->port[ti].crlf = ti != 0;
237 printf("uart_pty_init %s on port *** %s ***\n",
238 ti == 0 ? "bridge" : "tap", p->port[ti].slavename);
241 pthread_mutex_init(&p->lock, NULL);
242 pthread_create(&p->thread, NULL, uart_pty_thread, p);
251 pthread_kill(p->thread, SIGINT);
252 for (int ti = 0; ti < 2; ti++)
254 close(p->port[ti].s);
256 pthread_join(p->thread, &ret);
264 // disable the stdio dump, as we are sending binary there
266 avr_ioctl(p->avr, AVR_IOCTL_UART_GET_FLAGS(uart), &f);
267 f &= ~AVR_UART_FLAG_STDIO;
268 avr_ioctl(p->avr, AVR_IOCTL_UART_SET_FLAGS(uart), &f);
270 avr_irq_t * src = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUTPUT);
271 avr_irq_t * dst = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_INPUT);
272 avr_irq_t * xon = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XON);
273 avr_irq_t * xoff = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XOFF);
275 avr_connect_irq(src, p->irq + IRQ_UART_PTY_BYTE_IN);
276 avr_connect_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, dst);
279 avr_irq_register_notify(xon, uart_pty_xon_hook, p);
281 avr_irq_register_notify(xoff, uart_pty_xoff_hook, p);
283 for (int ti = 0; ti < 1; ti++) if (p->port[ti].s) {
285 sprintf(link, "/tmp/simavr-uart%s%c", ti == 1 ? "tap" : "", uart);
287 if (symlink(p->port[ti].slavename, link) != 0) {
288 fprintf(stderr, "WARN %s: Can't create %s: %s", __func__, link, strerror(errno));
290 printf("%s: %s now points to %s\n", __func__, link, p->port[ti].slavename);
293 if (getenv("SIMAVR_UART_XTERM") && atoi(getenv("SIMAVR_UART_XTERM"))) {
295 sprintf(cmd, "xterm -e picocom -b 115200 %s >/dev/null 2>&1 &",
299 printf("note: export SIMAVR_UART_XTERM=1 and install picocom to get a terminal\n");