Como eu duplico um terminal serial?

4

Isso pode ser um problema XY, mas eu gostaria de clonar um terminal serial como / dev / ttyUSB0 em dois terminais. A entrada de qualquer muxed no terminal real e a saída alimentada para ambos. Existe uma ferramenta para conseguir isso? Essa é uma possibilidade?

Costumo trabalhar com hardware embarcado em série usando um pequeno emulador de terminal dterm . Eu gostaria de manter esse terminal interativo aberto em todos os momentos, mas também executar sequências de comando usando esperar sobre ele. Diga, para reiniciar e parar no prompt do U-Boot, por exemplo.

Eu imagino uma ferramenta para ser usada assim:

$ teeterm /dev/ttyUSB0
Clone successful: /dev/pts/3 and /dev/pts/4 available.
$ dterm /dev/pts/3 115200

E em outro shell: $ ./uboot (which spawns and interacts with dterm /dev/pts/4 115200)

    
por kcghost 20.02.2017 / 00:37

2 respostas

2

Usando o código de exemplo postado do dirkt como base, eu coloquei um utilitário real para isso. É disponível no Github .

Acabei usando um: teeterm dterm /dev/ttyUSB0 115200 (in another shell) dterm pty0 (in another shell) dterm pty1

Os dois pseudoterminais têm acesso ao processo de comando I / O. Os aspectos mais importantes do utilitário são uma chamada forkpty para controlar um processo filho através de um pseudoterminal (que não é disponibilizado para o usuário), juntamente com openpty e selecione chamadas para criar os dois pseudoterminais e monitorar todos os três para entradas.

    
por 02.03.2017 / 05:02
2

Conforme solicitado, um pequeno programa C que canaliza bidirecionalmente entre dois pseudo-terminais recém-criados. Não, isso não responde à pergunta, mas pode ser facilmente adaptado para isso. Não é muito longo, então aqui está o código. A licença é "faça o que quiser com isso".

/* ptycat (ptypipe? ptypair?)
 *
 * create a pair of pseudo-terminal slaves connected to each other
 *
 * Link with -lutil
 *
 * Alternative: socat PTY,link=COM8 PTY,link=COM9
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <pty.h>

#undef max
#define max(x,y) ((x) > (y) ? (x) : (y))

/*
  (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);

*/

/* TODO: make symlinks, unlink on atexit */

static uint8_t buf[BUFSIZ]; /* BUFSIZ from stdio.h, at least 256 */
static char *log_dir = NULL;

void logdata (char *dir, uint8_t *data, int n) {
  if (dir != log_dir) fprintf (stdout, "\n%s", dir);
  log_dir = dir;
  for (; n > 0; n--, data++) fprintf (stdout, " %02x", *data);
  fflush (stdout);
}

int main (int argc, char* argv[])
{
  char name[256]; /* max namelen = 255 for most fs. */
  fd_set rfd;

  struct termios tt;
  struct winsize ws;
  int master[2], slave[2];
  int n, nfds, cc;

  if (tcgetattr (STDIN_FILENO, &tt) < 0)
  {
    perror("Cannot get terminal attributes of stdin");
    exit(1);
  }
  cfmakeraw (&tt);
  for (int i = 0; i < 2; i++)
  {
    if (openpty (&master[i], &slave[i], name, &tt, NULL /*ws*/) < 0)
    {
      perror("Cannot open pty");
      exit(1);
    }
    puts(name);
  }

  for (;;) {
    FD_ZERO(&rfd);  
    FD_SET(master[0], &rfd);
    FD_SET(master[1], &rfd);
    nfds = max(master[0], master[1]) + 1;
    n = select(nfds, &rfd, 0, 0, NULL);
    if (n > 0 || errno == EINTR)
    {
      if (FD_ISSET(master[0], &rfd))
      {
        if ((cc = read(master[0], buf, sizeof(buf))) > 0)
        {
          (void) write(master[1], buf, cc);
          logdata (">>>", buf, cc);
        }
      }

      if (FD_ISSET(master[1], &rfd))
      {
        if ((cc = read(master[1], buf, sizeof(buf))) > 0)
        {
          (void) write(master[0], buf, cc);
          logdata ("<<<", buf, cc);
        }
      }
    }
  }
  /* This is never reached */
  return 0; 
}
    
por 20.02.2017 / 16:55

Tags