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 <sys/select.h>
36 DEFINE_FIFO(uint8_t,uart_pty_fifo);
38 //#define TRACE(_w) _w
44 * called when a byte is send via the uart on the AVR
46 static void uart_pty_in_hook(struct avr_irq_t * irq, uint32_t value, void * param)
48 uart_pty_t * p = (uart_pty_t*)param;
49 TRACE(printf("uart_pty_in_hook %02x\n", value);)
50 uart_pty_fifo_write(&p->in, value);
53 // try to empty our fifo, the uart_pty_xoff_hook() will be called when
55 static void uart_pty_flush_incoming(uart_pty_t * p)
57 while (p->xon && !uart_pty_fifo_isempty(&p->out)) {
58 uint8_t byte = uart_pty_fifo_read(&p->out);
59 TRACE(printf("uart_pty_flush_incoming send %02x\n", byte);)
60 avr_raise_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, byte);
65 * Called when the uart has room in it's input buffer. This is called repeateadly
66 * if necessary, while the xoff is called only when the uart fifo is FULL
68 static void uart_pty_xon_hook(struct avr_irq_t * irq, uint32_t value, void * param)
70 uart_pty_t * p = (uart_pty_t*)param;
71 TRACE(if (!p->xon) printf("uart_pty_xon_hook\n");)
73 uart_pty_flush_incoming(p);
77 * Called when the uart ran out of room in it's input buffer
79 static void uart_pty_xoff_hook(struct avr_irq_t * irq, uint32_t value, void * param)
81 uart_pty_t * p = (uart_pty_t*)param;
82 TRACE(if (p->xon) printf("uart_pty_xoff_hook\n");)
86 static void * uart_pty_thread(void * param)
88 uart_pty_t * p = (uart_pty_t*)param;
91 fd_set read_set, write_set;
96 // read more only if buffer was flushed
97 if (p->buffer_len == p->buffer_done)
98 FD_SET(p->s, &read_set);
99 if (!uart_pty_fifo_isempty(&p->in))
100 FD_SET(p->s, &write_set);
102 struct timeval timo = { 0, 500 }; // short, but not too short interval
103 int ret = select(max, &read_set, &write_set, NULL, &timo);
110 if (FD_ISSET(p->s, &read_set)) {
111 ssize_t r = read(p->s, p->buffer, sizeof(p->buffer)-1);
114 TRACE(hdump("pty recv", p->buffer, r);)
116 if (p->buffer_done < p->buffer_len) {
117 // write them in fifo
118 while (p->buffer_done < p->buffer_len && !uart_pty_fifo_isfull(&p->out))
119 uart_pty_fifo_write(&p->out, p->buffer[p->buffer_done++]);
121 if (FD_ISSET(p->s, &write_set)) {
123 // write them in fifo
124 uint8_t * dst = buffer;
125 while (!uart_pty_fifo_isempty(&p->in) && dst < (buffer+sizeof(buffer)))
126 *dst++ = uart_pty_fifo_read(&p->in);
127 size_t len = dst - buffer;
128 TRACE(size_t r =) write(p->s, buffer, len);
129 TRACE(hdump("pty send", buffer, r);)
131 uart_pty_flush_incoming(p);
136 static const char * irq_names[IRQ_UART_PTY_COUNT] = {
137 [IRQ_UART_PTY_BYTE_IN] = "8<uart_pty.in",
138 [IRQ_UART_PTY_BYTE_OUT] = "8>uart_pty.out",
141 void uart_pty_init(struct avr_t * avr, uart_pty_t * p)
144 p->irq = avr_alloc_irq(&avr->irq_pool, 0, IRQ_UART_PTY_COUNT, irq_names);
145 avr_irq_register_notify(p->irq + IRQ_UART_PTY_BYTE_IN, uart_pty_in_hook, p);
149 if (openpty(&m, &s, p->slavename, NULL, NULL) < 0) {
150 fprintf(stderr, "%s: Can't create pty: %s", __FUNCTION__, strerror(errno));
155 printf("uart_pty_init bridge on port *** %s ***\n", p->slavename);
157 pthread_create(&p->thread, NULL, uart_pty_thread, p);
161 void uart_pty_stop(uart_pty_t * p)
164 pthread_kill(p->thread, SIGINT);
167 pthread_join(p->thread, &ret);
170 void uart_pty_connect(uart_pty_t * p, char uart)
172 // disable the stdio dump, as we are sending binary there
174 avr_ioctl(p->avr, AVR_IOCTL_UART_GET_FLAGS(uart), &f);
175 f &= ~AVR_UART_FLAG_STDIO;
176 avr_ioctl(p->avr, AVR_IOCTL_UART_SET_FLAGS(uart), &f);
178 avr_irq_t * src = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUTPUT);
179 avr_irq_t * dst = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_INPUT);
180 avr_irq_t * xon = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XON);
181 avr_irq_t * xoff = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XOFF);
183 avr_connect_irq(src, p->irq + IRQ_UART_PTY_BYTE_IN);
184 avr_connect_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, dst);
187 avr_irq_register_notify(xon, uart_pty_xon_hook, p);
189 avr_irq_register_notify(xoff, uart_pty_xoff_hook, p);
192 sprintf(link, "/tmp/simavr-uart%c", uart);
194 if (symlink(p->slavename, link) != 0) {
195 fprintf(stderr, "WARN %s: Can't create %s: %s", __func__, link, strerror(errno));
197 printf("%s: %s now points to %s\n", __func__, link, p->slavename);
199 if (getenv("SIMAVR_UART_XTERM")) {
201 sprintf(cmd, "nohup xterm -e picocom -b 115200 %s >/dev/null 2>&1 &", p->slavename);