uart_pty: Introduced the notion of 'tap' port
authorMichel Pollet <buserror@gmail.com>
Sat, 2 Jun 2012 14:34:21 +0000 (15:34 +0100)
committerMichel Pollet <buserror@gmail.com>
Sat, 2 Jun 2012 14:34:21 +0000 (15:34 +0100)
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 <buserror@gmail.com>
examples/parts/uart_pty.c
examples/parts/uart_pty.h

index 6fc3287..eb3ba7f 100644 (file)
@@ -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");
index f797e58..c6e0603 100644 (file)
@@ -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