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 ?
Advertisement
Answer
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.