3

I am trying to write a simple program that sends bytes over a serial connection. I created a data transfer loop using socat as follows:

$ socat -d -d pty pty

This creates a data transfer loop between /dev/pts/2 and /dev/pts/0. When I try to use termios in my C program to write some bytes, I successfully am able to open the serial connection using open(). I then write some bytes using write() and I receive the number of bytes written. Yet, when I listen to the opposite ends I don't see any output. I used these to try and listen in another terminal:

$ cat /dev/pts/0 | xxd
$ read -r line < /dev/pts/0
$ echo $line

I know my socat connection works because when I echo bytes and listen on the other end, I receive them normally.

#define BAUD_RATE B9600
#define PORT_NAME "/dev/pts/2"

/* Serial Connection Manager */
struct termios tty;
int fd;

int main(){
  /*
  O_RDWR: read/write access to serial port
  O_NOCTTY: No terminal will control the process
  O_NDELAY: Non-blocking, returns immediately
  */
  fd = open(PORT_NAME, O_RDWR | O_NOCTTY | O_NDELAY);
  printf("%s\n", PORT_NAME);
  if (fd == -1) {
    printf("Error in opening serial port\n");
    return -1;
  }
  else
    printf("Port opened successfully\n");

  tcgetattr(fd, &tty); // get current attrs of serial port
  // raw mode of terminal driver
  //cfsetispeed(&tty, BAUD_RATE);
  //cfsetospeed(&tty, BAUD_RATE);
  cfmakeraw(&tty);

  // set additional control modes
  cfsetspeed(&tty, (speed_t) BAUD_RATE);
  tty.c_cflag &= ~CSTOPB; //1 stop bit
  tty.c_cflag &= ~CRTSCTS; //disable hardware flow control
  tty.c_cflag |= CLOCAL; //ignore modem control lines
  tty.c_cflag |= CREAD; //enable receiver

  if((tcsetattr(fd, TCSANOW, &tty)) != 0){
    printf("Error in setting attributes\n");
    close(fd);
    return -1;
  }
  else
    printf("BaudRate = %d\nStopBits = 1\nParity = Odd\n", BAUD_RATE);

  sleep(1); // wait for configuration
  tcflush(fd, TCIOFLUSH);

  char buf[3] = "abc";
  int bytes_written = write(fd, buf, 3);
  printf("Bytes written: %d", bytes_written);
  close(fd);
  return 0;
}

I expected to be able to listen to the bytes using $ read -r output < /dev/pts/0 and that when echoing output would give "abc".

Running my program gives the following output:

/dev/pts/2
Port opened successfully
BaudRate = 13
StopBits = 1
Parity = Odd
Bytes written: 3

So I know the bytes are going somewhere since write() doesn't return -1.

1 Answers1

0

Your code works fine with real and virtual serial ports for me.

You need to pay attention to the socat output:

$ socat -d -d pty pty
2019/07/18 07:55:45 socat[8144] N PTY is /dev/pts/2
2019/07/18 07:55:45 socat[8144] N PTY is /dev/pts/3
2019/07/18 07:55:45 socat[8144] N starting data transfer loop with FDs [5,5] and [7,7]

Then listen on the first port of the pair:

$ cat /dev/pts/2

And run your code (compiled with PORT_NAME "/dev/pts/2") and you'll see the abc con the terminal where you run cat.

You can also try connecting to /dev/pts/2 or /dev/pts/3 with minicom or any other terminal you like and you'll see the output:

$ minicom -D /dev/pts/2 -b 9600
Marcos G.
  • 3,371
  • 2
  • 8
  • 16
  • If I am writing bytes to /dev/pts/2 shouldn't I be able to listen to /dev/pts/3 to observe output (since this is a data transfer connection between them)? When I echo to /dev/pts/2 I can cat /dev/pts/3 to see what I echo'd. – BreakfastCalzone Jul 18 '19 at 15:23
  • Also, this tried exactly this with listening to BOTH /dev/pts/2 and /dev/pts/3 but it still didn't work. – BreakfastCalzone Jul 18 '19 at 15:44
  • With minicom I see data on both ports. If I use `cat` I can only see data on `/dev/pts/2`. – Marcos G. Jul 18 '19 at 15:47
  • Oh ok it works with minicom and I can only see it on the port that is not being written to (which is the expected behavior). Thanks! Not sure why cat and read don't work. – BreakfastCalzone Jul 18 '19 at 16:09
  • Yeah, that's consistent with what I see. I'm not sure why `cat` works like that either. I have never been fond of it. – Marcos G. Jul 18 '19 at 16:14