2

I am trying to write some data to a serial port, that I will read from forexample screen in the same computer. I have tried looking at this answer how-to-send-data-to-a-serial-port-and-see-any-answer
I have added my user to group dialout and ran chmod o+rw /dev/ttyS1
Then in python I do like this, and get following error:

>>> 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')

So the question is, what do I do wrong here?

Or should I look for a different approach.

The issue is, that I got some udp messages that I can receive in for example python, that I need to send to a software, that only sees serial ports.
Maybe there is a different approach?
In that case, what is a good way to do that?

  • If it's a "virtual" serial port and not real hardware, how did you create it? – dirkt Jan 7 '17 at 21:50
  • @dirkt I did not create it. I did ls -l /dev/ttyS* and get a list of /dev/ttyS0, 1 and to... I tought I could use these? – el3ien Jan 7 '17 at 21:57
  • If you did not create it, it's not a "virtual" tty, and it's backed by real hardware (and there's possibly a login shell running on it, which you may need to disable). That means the "software that only sees serial ports" is running on another computer, which is connected to this computer by a serial cable. Is that correct? Or is the software running on the same computer, and just expects to use a tty? What software is it in the first place? – dirkt Jan 8 '17 at 6:33
  • @dirkt The software is on the same computer. And possibly I need 4 or more virtual ports. The software is olex, a marine plotter. The data is nmea, strings from gps, compass, ais, echo sounder and so on. It used to be a bunch of serial cables, now I want everything tru ethernet – el3ien Jan 8 '17 at 21:16
  • @dirkt askubuntu.com/questions/588800/… this looks promising. am on mobile now, so have not tested it yet – el3ien Jan 9 '17 at 2:51
1

If you need to connect two programs, one of which insisting that it uses a tty-device (of which a serial port is an example), you can instead connect them using a pseudoterminal pair.

You can either do it from Python with the standard pty module, or you use a small C program that just creates the pair, and then access it from the shell, a Python program or whatever just like a normal file.

Your suggestion from the comment uses a kernel module, which is overkill and not as portable.

Here's an example C program I have used in a similar situation, it's not very polished and needs some way to communicate the names used.

/* 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; 
}
  • Couldnt get this to compile. But when using python pty pair, it creates a /dev/pts4 and /dev/ptmx, but I dont see the messages in screen. Found this tho http://stackoverflow.com/questions/2174071/how-to-use-dev-ptmx-for-create-a-virtual-serial-port The edit from the author works. socat PTY,link=COM8 PTY,link=COM9 .. Alltho it would be nicer to get your example to work, so I dont need to install socat – el3ien Jan 10 '17 at 3:16
  • As it says in the source, you need to link with libutil, so try cc ptycat.c -o ptycat -lutil etc. to compile. – dirkt Jan 10 '17 at 12:46
  • Nice, thank you very much. That worked :) . Hopefully my c knowledge will become better at some point. – el3ien Jan 10 '17 at 21:56
  • I just saw that I still have the "logdata" calls in the code which I used so I could what goes over the tty's. Just remove the two calls to make it silent. – dirkt Jan 11 '17 at 5:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.