2

I wrote common functions in order to manage serial ports, based on the following structure:

  typedef struct
  {
     int  PHandle;
     unsigned int  Port;
     unsigned int  BaudRate;
     unsigned char Parity;
     unsigned char FlowControl;
     char Device[MAX_SIZE];
  } Tst_SPort;

I am calling these functions (see below) in another file in order to test an RS232 serial port. The flow control needs to be enabled.

  int iInit(Tst_SPort *port, const char *device, int baudRate, unsigned char parity, unsigned char flowControl)
  {
     strncpy(port->Device, device, MAX_SIZE);
     port->PHandle     = iOpen(port);
     port->Port        = -1;
     port->BaudRate    = baudRate;
     port->Parity      = parity;
     port->FlowControl = flowControl;
     if(port->PHandle > 0)
     {
        setuart(port, port->BaudRate);
     }
     return port->PHandle;
  }

  int iOpen(Tst_SPort *port)
  {
     port->PHandle = open(port->Device, O_RDWR | O_NOCTTY);
     if(port->PHandle < 0)
     {
        perror("open:");
        return (-1);
     }
     return (port->PHandle);
  }

  void setuart(Tst_SPort *port, int baudRate)
  {
     struct termios opt, optCmp;           
     struct serial_struct info;

     if(port->PHandle > 0)
     {
        bzero(&opt,    sizeof(opt));
        bzero(&optCmp, sizeof(optCmp));

        if(ioctl(port->PHandle, TIOCGSERIAL, &info) == 0) 
           port->Port = info.port;

        fcntl(port->PHandle, F_SETFL, O_NONBLOCK);

        if (tcgetattr(port->PHandle, &opt) < 0) 
           perror("tcgetattr Get:");

        if(baudRate > 0)
        {
           cfsetospeed (&opt, baudRate);
           cfsetispeed (&opt, baudRate);   
        }

        opt.c_iflag = IGNPAR;               
        opt.c_oflag &= ~OPOST
        opt.c_oflag &= ~ONLCR;
        opt.c_lflag = 0;                   
        opt.c_cflag |= (CLOCAL | CREAD); 
        opt.c_cflag &= ~(PARENB | PARODD); 
        opt.c_cflag |= port->Parity;
        opt.c_cflag &= ~CSTOPB;         
        opt.c_cflag &= ~CSIZE;
        opt.c_cflag |=  CS8;        
        if(!port->FlowControl)
           opt.c_cflag &= ~CRTSCTS;         
        else
           opt.c_cflag |= CRTSCTS;         

        opt.c_cc[VMIN] = 0;               
        opt.c_cc[VTIME] = 50; 

        if(tcsetattr(opt->PHandle, TCSANOW, &opt) < 0)
           perror("tcgetattr Update :");

        if (tcgetattr(opt->PHandle, &optCmp) < 0) 
           perror("tcgetattr Read:");

        /* Compare */
        if (memcmp((void *)&opt, (void *)&optCmp, sizeof(opt)) != 0)
           printf("Conf failed");         

        tcflush(port->PHandle, TCIFLUSH);
     }
  }

  int iRead(Tst_SPort *port, char *buffer, unsigned long buffLength)
  {
     struct  timeval tv;   
     fd_set  recv;
     int     s32Read = 0;
     int     s32Offset = 0;
     int     s32SRes = 0;

     tv.tv_sec = 0;
     tv.tv_usec = 100000; /* 100ms */

     if ((port) && (port->PHandle > 0)) 
     {
        while (s32Offset < buffLength)
        {
           FD_ZERO(&recv);
           FD_SET(port->PHandle, &recv);

           s32SRes = select(port->PHandle + 1, &recv, NULL, NULL, &tv);
           if ((s32SRes == -1) && (errno == EINTR)) 
           {
              continue; 
           }
           else if(s32SRes > 0)
           {
              if (FD_ISSET(port->PHandle, &recv))
              {
                 s32Read = read(port->PHandle, buffer + s32Offset, buffLength - s32Offset);
                 if(s32Read  > 0)
                 {
                    tv.tv_sec = 0;
                    tv.tv_usec = 5000;
                    s32Offset += s32Read;
                    continue;
                 }
              }
           }
           break;
        }
     }  
     return s32Offset;
  }

  int iClose(Tst_SPort *port)
  {
     return (close(port->Phandle));
  }

In order to validate the implementation, the pinouts Tx and Rx have been connected together, idem for CTS and RTS. Everything works fine, the message sent can be read correctly. In addition, when Tx is disconnected from the Rx nothing is reading as expected.

But when the CTS is unplugged from the RTS the test blocks after the port closing step (~20 seconds).

However, if the function setuart() is called with flowControl == 0, the test does not block and returns the exepected error code without delay.

I probably understood something wrongly especially in port configuration. Is it the good way to do ?

ogs
  • 1,139
  • 8
  • 19
  • 42

1 Answers1

1

The problem you are facing is a correct behaviour.

Leaving CTS unconnected with flow control enabled, means DTE (AKA PC) cannot send data to DCE (slave device).

When you try to write to the UART output buffer it, probably, is full and application temporarily stops running and waits until some buffer space becomes available.

LPs
  • 16,045
  • 8
  • 30
  • 61
  • Is there a way to integrate a workaround or is it directly link to the uart driver ? – ogs May 20 '16 at 14:04
  • If you enable flow control CTS and RTS signals have to be consistent. BTW try to find use a non blocking (O_NONBLOCK) handle and read the CTS state from application using something like `ioctl(fd, TIOCMGET, &serial)` – LPs May 20 '16 at 14:17
  • Take also not that some behavior are HW related and implementation (driver) defined. – LPs May 20 '16 at 14:18