clinuxttypty

How to use a socat pty to send and receive data with two C programs?


I'm trying to use a pseudo tty to send and receive data, in order to later use a real tty linked to a serial RS232 USB adapter.

I first create the pseudo tty using socat:

sudo socat -d -d pty,link=./ttyUSB0,echo=0,perm=0666 pty,link=./ttyUSB1,echo=0,perm=0666

The transmiter seems to manage to send data, but the receiver doesn't receive it. I first run the receiver that block on the first call to read() function. Then I run the transmiter to send data to it.

Here is the transmiter program:

#define _GNU_SOURCE
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

#include <termios.h>

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

float data[100000];

int main() {
  int fdm = -1;
  fdm = open("./ttyUSB0",O_RDWR);
  if(fdm < 0) { perror("Error"); exit(EXIT_FAILURE); }
  grantpt(fdm);
  unlockpt(fdm);
  
  int i;
  for(i=0; i<100000; i++) {
    if(i%100 == 0) { printf("\rTransmit %d / %d",i,100000); fflush(stdout); }
    write(fdm,&data[i],sizeof(float));
  }
}

And the receiver program:

#define _GNU_SOURCE
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

#include <termios.h>

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

float data[100000];

int main() {
  int fds = open("./ttyUSB1",O_RDWR);
  if(fds < 0) { perror("Error"); exit(EXIT_FAILURE); }
  grantpt(fds);
  unlockpt(fds);
  
  int i;
  for(i=0; i<100000; i++) {
    if(i%100 == 0) { printf("\rReceive %d / %d",i,100000); fflush(stdout); }
    read(fds,&data[i],sizeof(float));
  }
}

When I run cat ./ttyUSB1 and echo abcd >> ./ttyUSB0, the cat command print the message sent with echo.

So the problem seems to come from my program.


Solution

  • I followed the tutorial of mbedded ninja about serial port programming, to configure the pseudo tty like a real tty. Now it seems to work without problems.

    Here is the code of the transmitter, having done the same tty settings for the receiver:

    #define _GNU_SOURCE
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/ioctl.h>
    #include <sys/stat.h>
    
    #include <termios.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    
    float data[100000];
    
    int main() {
      int fdm = -1;
      fdm = open("./ttyUSB0",O_RDWR);
      if(fdm < 0) { perror("Error"); exit(EXIT_FAILURE); }
      grantpt(fdm);
      unlockpt(fdm);
      
      struct termios tty;
      if(tcgetattr(fdm, &tty) != 0) {
          printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
      }
      tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
      tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
      
      tty.c_cflag &= ~CSIZE; // Clear all the size bits, then use one of the statements below
      tty.c_cflag |= CS8; // 8 bits per byte (most common)
      
      tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
      tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)
      tty.c_lflag &= ~ICANON; // disable input cannonical mode
      tty.c_lflag &= ~ECHO; // Disable echo
      tty.c_lflag &= ~ECHOE; // Disable erasure
      tty.c_lflag &= ~ECHONL; // Disable new-line echo
      
      tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
      
      tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
      tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes
      
      tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
      tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
      
      tty.c_cc[VTIME] = 10;    // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
      tty.c_cc[VMIN] = 0;
      
      cfsetispeed(&tty, B115200);
      cfsetospeed(&tty, B115200);
      cfsetspeed(&tty, B115200); // set both input and output speed
      
      if (tcsetattr(fdm, TCSANOW, &tty) != 0) {
        printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
      }
      
      int i;
      for(i=0; i<100000; i++) {
        if(i%100 == 0) { printf("\rTransmit %d / %d",i,100000); fflush(stdout); }
        write(fdm,&data[i],sizeof(float));
      }
    }