Linux Serial Port Blocked using termios.h configuration

771 views Asked by At

I'm writing an embedded Linux application that (1) opens a serial connection to another device, (2) sends a known command, (3) checks port for incoming characters (response) until expected response phrase or character is detected, (4) repeats step 2 and 3 until a series of commands are sent and responses received, (5) then closes the port.

My app would go through some cycles of the above sequence and every now and then it would be waiting for a response (reading) when all of a sudden the communication stops and my software faults out because of my built-in timeout logic.

Is there anything in my port configuration that would cause the port to be blocked due to specific byte sent (possibly due to electrical noise)?

Here is how I'm opening my ports (showing configurations via termios.h):

struct termios options;

fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1) {
    debug() << "Port open failed!"
    return FAIL;
}
debug() << "Port Opened Successful"
fcntl(fd, F_SETFL, 0);                                // This setting interacts with VMIN and VTIME below

// Get options
tcgetattr(fd, &options);

// Adjust Com port options

options.c_cflag |= (CLOCAL | CREAD);                  // Program will not "own" port, enable reading on port
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);   // Sets RAW input mode (does not treat input as a line of text with CR/LF ending)
options.c_oflag &= ~ OPOST;                        // Sets RAW ouput mode (avoids newline mapping to CR+LF characters)
options.c_iflag &= ~(IXON | IXOFF | IXANY);           // Turns off SW flow c

options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;

// Set options
tcsetattr(fd, TCSANOW, &options);

//return fd;
return SUCCEED;

I can't figure out why the communication all of a sudden just freezes up and then goes away when I cycle power to my device. Thanks all!

More info - here are my read and write functions:

int Comm::Receive(unsigned char* rBuf)
{
    int bytes;
    ioctl(fd, FIONREAD, &bytes);
    if (bytes >= 1)
    {
        bytes = read(fd, rBuf, 1);
        if (bytes < 0)
            return READ_ERR;
        return SUCCEED;
    }
    else
        return NO_DATA_AVAILABLE;
}


int Comm::Send(int xCt, unsigned char* xBuf)
{
    int bytes;
    if (fd == -1)
        return FAIL;
    bytes = write(fd, xBuf, xCt);
    if (bytes != xCt)
        return FAIL;
    else
        return SUCCEED;
}
2

There are 2 answers

0
Bandrami On

Welcome to the joys of serial ports...

Thought 1: wrap your read calls with a select ()

Thought 2: Unset the ICANON flag in tcsetattr, and set a VTIME attribute for a deliberate timeout (and then, obviously, handle it)

Thought 3: Nothing about serial comms ever works perfectly.

0
Dig The Code On

I also had a similar problem with sending command to devices and reading responses from the device. Please refer to below SOF post and the answer this was working for my problem.

In these cases, We have to care about the protocol which we are going to use for device communication (send and receive). If we can send commands successfully and we didn't receive a response with a noise from device implies there is something wrong in the data packet which was sent to the device. First of all check the protocol specification first and create a byte array for a simple command (like make a beep sound) and send it.

Send data to a barcode scanner over RS232 serial port

I can do something for you If you can post your complete source code with the output.

Enjoy the code. Thanks.