From: Michel Pollet Date: Sat, 2 Jun 2012 14:34:21 +0000 (+0100) Subject: uart_pty: Introduced the notion of 'tap' port X-Git-Tag: v1.0~105 X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=8c5185f9db51a5eea9a0e0a794f95131cacd391c;p=sx%2Fsimavr.git uart_pty: Introduced the notion of 'tap' port The previous way to debug was 'stealing' the port by using an xterm on it.. the new way leaves the proper pty available to the application you want to use but still allow you to have a 'tap' port that sees both the sides of the communication om the other pty. You can also type stuff obviously, and it does some cr/lf conversions. /tmp/simavr-uart0 : will be the normal fake serial port /tmp/simavr-uarttap0 : is the one to launch an xterm on This allow you to really see the serial traffic as it happends with both requests and replies. Signed-off-by: Michel Pollet --- diff --git a/examples/parts/uart_pty.c b/examples/parts/uart_pty.c index 6fc3287..eb3ba7f 100644 --- a/examples/parts/uart_pty.c +++ b/examples/parts/uart_pty.c @@ -55,7 +55,13 @@ uart_pty_in_hook( { uart_pty_t * p = (uart_pty_t*)param; TRACE(printf("uart_pty_in_hook %02x\n", value);) - uart_pty_fifo_write(&p->in, value); + uart_pty_fifo_write(&p->pty.in, value); + + if (p->tap.s) { + if (p->tap.crlf && value == '\n') + uart_pty_fifo_write(&p->tap.in, '\r'); + uart_pty_fifo_write(&p->tap.in, value); + } } // try to empty our fifo, the uart_pty_xoff_hook() will be called when @@ -64,10 +70,22 @@ static void uart_pty_flush_incoming( uart_pty_t * p) { - while (p->xon && !uart_pty_fifo_isempty(&p->out)) { - uint8_t byte = uart_pty_fifo_read(&p->out); + while (p->xon && !uart_pty_fifo_isempty(&p->pty.out)) { + uint8_t byte = uart_pty_fifo_read(&p->pty.out); TRACE(printf("uart_pty_flush_incoming send %02x\n", byte);) avr_raise_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, byte); + + if (p->tap.s) { + if (p->tap.crlf && byte == '\n') + uart_pty_fifo_write(&p->tap.in, '\r'); + uart_pty_fifo_write(&p->tap.in, byte); + } + } + if (p->tap.s) { + while (p->xon && !uart_pty_fifo_isempty(&p->tap.out)) { + uint8_t byte = uart_pty_fifo_read(&p->tap.out); + avr_raise_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, byte); + } } } @@ -109,44 +127,55 @@ uart_pty_thread( while (1) { fd_set read_set, write_set; - int max = p->s + 1; + int max = 0; FD_ZERO(&read_set); FD_ZERO(&write_set); - // read more only if buffer was flushed - if (p->buffer_len == p->buffer_done) - FD_SET(p->s, &read_set); - if (!uart_pty_fifo_isempty(&p->in)) - FD_SET(p->s, &write_set); + for (int ti = 0; ti < 2; ti++) if (p->port[ti].s) { + // read more only if buffer was flushed + if (p->port[ti].buffer_len == p->port[ti].buffer_done) { + FD_SET(p->port[ti].s, &read_set); + max = p->port[ti].s > max ? p->port[ti].s : max; + } + if (!uart_pty_fifo_isempty(&p->port[ti].in)) { + FD_SET(p->port[ti].s, &write_set); + max = p->port[ti].s > max ? p->port[ti].s : max; + } + } struct timeval timo = { 0, 500 }; // short, but not too short interval - int ret = select(max, &read_set, &write_set, NULL, &timo); + int ret = select(max+1, &read_set, &write_set, NULL, &timo); if (!ret) continue; if (ret < 0) break; - if (FD_ISSET(p->s, &read_set)) { - ssize_t r = read(p->s, p->buffer, sizeof(p->buffer)-1); - p->buffer_len = r; - p->buffer_done = 0; - TRACE(hdump("pty recv", p->buffer, r);) - } - if (p->buffer_done < p->buffer_len) { - // write them in fifo - while (p->buffer_done < p->buffer_len && !uart_pty_fifo_isfull(&p->out)) - uart_pty_fifo_write(&p->out, p->buffer[p->buffer_done++]); - } - if (FD_ISSET(p->s, &write_set)) { - uint8_t buffer[512]; - // write them in fifo - uint8_t * dst = buffer; - while (!uart_pty_fifo_isempty(&p->in) && dst < (buffer+sizeof(buffer))) - *dst++ = uart_pty_fifo_read(&p->in); - size_t len = dst - buffer; - TRACE(size_t r =) write(p->s, buffer, len); - TRACE(hdump("pty send", buffer, r);) + for (int ti = 0; ti < 2; ti++) if (p->port[ti].s) { + if (FD_ISSET(p->port[ti].s, &read_set)) { + ssize_t r = read(p->port[ti].s, p->port[ti].buffer, sizeof(p->port[ti].buffer)-1); + p->port[ti].buffer_len = r; + p->port[ti].buffer_done = 0; + TRACE(hdump("pty recv", p->port[ti].buffer, r);) + } + if (p->port[ti].buffer_done < p->port[ti].buffer_len) { + // write them in fifo + while (p->port[ti].buffer_done < p->port[ti].buffer_len && + !uart_pty_fifo_isfull(&p->port[ti].out)) + uart_pty_fifo_write(&p->port[ti].out, + p->port[ti].buffer[p->port[ti].buffer_done++]); + } + if (FD_ISSET(p->port[ti].s, &write_set)) { + uint8_t buffer[512]; + // write them in fifo + uint8_t * dst = buffer; + while (!uart_pty_fifo_isempty(&p->port[ti].in) && + dst < (buffer + sizeof(buffer))) + *dst++ = uart_pty_fifo_read(&p->port[ti].in); + size_t len = dst - buffer; + TRACE(size_t r =) write(p->port[ti].s, buffer, len); + TRACE(hdump("pty send", buffer, r);) + } } uart_pty_flush_incoming(p); } @@ -163,19 +192,32 @@ uart_pty_init( struct avr_t * avr, uart_pty_t * p) { + memset(p, 0, sizeof(*p)); + p->avr = avr; p->irq = avr_alloc_irq(&avr->irq_pool, 0, IRQ_UART_PTY_COUNT, irq_names); avr_irq_register_notify(p->irq + IRQ_UART_PTY_BYTE_IN, uart_pty_in_hook, p); - int m, s; + int hastap = (getenv("SIMAVR_UART_TAP") && atoi(getenv("SIMAVR_UART_TAP"))) || + (getenv("SIMAVR_UART_XTERM") && atoi(getenv("SIMAVR_UART_XTERM"))) ; - if (openpty(&m, &s, p->slavename, NULL, NULL) < 0) { - fprintf(stderr, "%s: Can't create pty: %s", __FUNCTION__, strerror(errno)); - return ; - } - p->s = m; + for (int ti = 0; ti < 1 + hastap; ti++) { + int m, s; - printf("uart_pty_init bridge on port *** %s ***\n", p->slavename); + if (openpty(&m, &s, p->port[ti].slavename, NULL, NULL) < 0) { + fprintf(stderr, "%s: Can't create pty: %s", __FUNCTION__, strerror(errno)); + return ; + } + struct termios tio; + tcgetattr(m, &tio); + cfmakeraw(&tio); + tcsetattr(m, TCSANOW, &tio); + p->port[ti].s = m; + p->port[ti].tap = ti != 0; + p->port[ti].crlf = ti != 0; + printf("uart_pty_init %s on port *** %s ***\n", + ti == 0 ? "bridge" : "tap", p->port[ti].slavename); + } pthread_create(&p->thread, NULL, uart_pty_thread, p); @@ -187,7 +229,9 @@ uart_pty_stop( { puts(__func__); pthread_kill(p->thread, SIGINT); - close(p->s); + for (int ti = 0; ti < 2; ti++) + if (p->port[ti].s) + close(p->port[ti].s); void * ret; pthread_join(p->thread, &ret); } @@ -216,17 +260,20 @@ uart_pty_connect( if (xoff) avr_irq_register_notify(xoff, uart_pty_xoff_hook, p); - char link[128]; - sprintf(link, "/tmp/simavr-uart%c", uart); - unlink(link); - if (symlink(p->slavename, link) != 0) { - fprintf(stderr, "WARN %s: Can't create %s: %s", __func__, link, strerror(errno)); - } else { - printf("%s: %s now points to %s\n", __func__, link, p->slavename); + for (int ti = 0; ti < 1; ti++) if (p->port[ti].s) { + char link[128]; + sprintf(link, "/tmp/simavr-uart%s%c", ti == 1 ? "tap" : "", uart); + unlink(link); + if (symlink(p->port[ti].slavename, link) != 0) { + fprintf(stderr, "WARN %s: Can't create %s: %s", __func__, link, strerror(errno)); + } else { + printf("%s: %s now points to %s\n", __func__, link, p->port[ti].slavename); + } } if (getenv("SIMAVR_UART_XTERM") && atoi(getenv("SIMAVR_UART_XTERM"))) { char cmd[256]; - sprintf(cmd, "nohup xterm -e picocom -b 115200 %s >/dev/null 2>&1 &", p->slavename); + sprintf(cmd, "xterm -e picocom -b 115200 %s >/dev/null 2>&1 &", + p->tap.slavename); system(cmd); } else printf("note: export SIMAVR_UART_XTERM=1 and install picocom to get a terminal\n"); diff --git a/examples/parts/uart_pty.h b/examples/parts/uart_pty.h index f797e58..c6e0603 100644 --- a/examples/parts/uart_pty.h +++ b/examples/parts/uart_pty.h @@ -35,19 +35,30 @@ enum { DECLARE_FIFO(uint8_t,uart_pty_fifo, 512); +typedef struct uart_pty_port_t { + int tap : 1, crlf : 1; + int s; // socket we chat on + char slavename[64]; + uart_pty_fifo_t in; + uart_pty_fifo_t out; + uint8_t buffer[512]; + size_t buffer_len, buffer_done; +} uart_pty_port_t, *uart_pty_port_p; + typedef struct uart_pty_t { avr_irq_t * irq; // irq list struct avr_t *avr; // keep it around so we can pause it pthread_t thread; - int s; // socket we chat on - char slavename[64]; int xon; - uart_pty_fifo_t in; - uart_pty_fifo_t out; - uint8_t buffer[512]; - size_t buffer_len, buffer_done; + union { + struct { + uart_pty_port_t pty; + uart_pty_port_t tap; + }; + uart_pty_port_t port[2]; + }; } uart_pty_t; void