Como enviar para a porta serial virtual e ler de outro programa?

2

Eu estou tentando gravar alguns dados em uma porta serial, que vou ler de forexample screen no mesmo computador. Eu tentei olhar para esta resposta como-enviar-dados-para-uma-porta-serial-e-ver-qualquer-resposta
Eu adicionei meu usuário ao grupo dialout e executei chmod o+rw /dev/ttyS1
Então, em python eu gosto disso e recebo o seguinte erro:

>>> import serial
>>> ser = serial.Serial("/dev/ttyS1",4800)  

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/el3/Envs/serial/lib/python2.7/site-packages/serial/serialutil.py", line 236, in __init__
    self.open()
  File "/home/el3/Envs/serial/lib/python2.7/site-packages/serial/serialposix.py", line 272, in open
    self._reconfigure_port(force_update=True)
  File "/home/el3/Envs/serial/lib/python2.7/site-packages/serial/serialposix.py", line 315, in _reconfigure_port
    raise SerialException("Could not configure port: {}".format(msg))
serial.serialutil.SerialException: Could not configure port: (5, 'Input/output error')

Então a questão é: o que eu faço de errado aqui?

Ou eu deveria procurar uma abordagem diferente.

O problema é que recebi algumas mensagens do udp que eu posso receber, por exemplo, em python, que preciso enviar para um software, que só vê portas seriais.
Talvez haja uma abordagem diferente?
Nesse caso, o que é uma boa maneira de fazer isso?

    
por el3ien 07.01.2017 / 19:02

1 resposta

1

Se você precisar conectar dois programas, um dos quais insistindo que ele usa um tty-device (do qual uma porta serial é um exemplo), você pode conectá-los usando um par pseudoterminal .

Você pode fazer isso do Python com o módulo pty padrão ou usar um pequeno C programa que apenas cria o par e acessa-o a partir do shell, um programa Python ou qualquer outro que seja como um arquivo normal.

O seu sugestão do comentário usa um módulo do kernel, que é um exagero e não é tão portátil.

Aqui está um exemplo de programa C que eu usei em uma situação similar, não é muito polido e precisa de alguma forma para comunicar os nomes usados.

/* ptycat (ptypipe? ptypair?)
 *
 * create a pair of pseudo-terminal slaves connected to each other
 *
 * Link with -lutil
 */

#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 never reached */
  return 0; 
}
    
por 09.01.2017 / 08:41