LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Linux serial port jammed (https://www.linuxquestions.org/questions/programming-9/linux-serial-port-jammed-727207/)

craftybones 05-20-2009 02:13 AM

Linux serial port jammed
 
Hello,

I have a specific problem concerning serial ports, termios and linux. I have some custom hardware that I communicate with over two serial ports. One of the serial ports is one way traffic and constantly provides certain updates as a set of 8 byte strings.

I am using termios to connect and talk to this and have been able to do so. However, on the channel that provides continuous updates, things go dead after a few seconds. Just completely dead. I have to disconnect and reconnect the serial port through termios for me to receive messages again.

A similar implementation of this works in windows, so we can ascertain that its not a hardware problem. The problem is either with termios or with my code.

I can post the code, but before I condense it and put it up, do people have any general suggestions I should look at?

Thank you,

Jay

pcardout 05-20-2009 02:17 AM

Minicom is a perfectly good serial communications tool for linux that lets you rapidly configure everything that might be
important (parity, software vs. hardware stop bits, baud rate, port used ... etc.). It would let you probe the
relevant parameters in linux. Perhaps the problem is all termios.

Without meaning to be too rude to the folks in Redmond, last time I used Hyperterm I found it a real bitch to figure out what
parameters it was setting exactly. Minicom is much more transparent. It could easily just be a software configuration problem.
Windows "works" but do you know why? Maybe minicom can help you figure it out so you can put proper parameters in your own code.

craftybones 05-20-2009 02:53 AM

Hello,

Thank you for the quick reply. I have used minicom, setserial, stty and the usual host of tools, but it doesn't seem to be a setting problem. Here's another thing, when I use a plain old cat /dev/ttyS4 > dummy...it doesn't stop. It seems to be specific to termios and specific to this port. The other channel works great.

Jay

Sergei Steshenko 05-20-2009 03:47 AM

The old trick is to set two stop bits at the transmitting side and one stop bit at the receiving side, and this trick has good physical explanation.

I think that some HW allows even 1.5 bits, which would also be OK (instead of the 2 bits).

craftybones 05-20-2009 04:43 AM

Hello,

I am not sure about setting two bits but here is the code:

int connect(char *port) {
int connector;
struct termios options;

connector = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (connector == -1) {
/* blah */
} else {
fcntl(connector, F_SETFL, FNDELAY); //FNDELAY is for non blocking read calls
}

tcgetattr(connector, &options);
cfsetispeed(&options, baud);
cfsetospeed(&options, baud);
options.c_iflag &= ~IGNBRK;
options.c_oflag &= ~OPOST;
options.c_lflag = 0;
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~CRTSCTS;

int status = tcsetattr(connector, TCSANOW, &options);
if ( status != 0 ) { /* blah */ }

return status;
}

To write to the port:

tcflush(maio_connector, TCOFLUSH);
nbytes = write(maio_connector, command, length)
if ( nbytes != length) { /* blah */ }

To read from the port:
if ((nbytes = read(maio_connector, buffer, sizeof(buffer) )) > 0)

While I am still clueless about what's wrong, I appreciate all your efforts in helping me out.

Thank you,

Jay

Sergei Steshenko 05-20-2009 12:15 PM

Quote:

Originally Posted by craftybones (Post 3546755)
Hello,

I am not sure about setting two bits but here is the code:

int connect(char *port) {
int connector;
struct termios options;

connector = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (connector == -1) {
/* blah */
} else {
fcntl(connector, F_SETFL, FNDELAY); //FNDELAY is for non blocking read calls
}

tcgetattr(connector, &options);
cfsetispeed(&options, baud);
cfsetospeed(&options, baud);
options.c_iflag &= ~IGNBRK;
options.c_oflag &= ~OPOST;
options.c_lflag = 0;
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~CRTSCTS;

int status = tcsetattr(connector, TCSANOW, &options);
if ( status != 0 ) { /* blah */ }

return status;
}

To write to the port:

tcflush(maio_connector, TCOFLUSH);
nbytes = write(maio_connector, command, length)
if ( nbytes != length) { /* blah */ }

To read from the port:
if ((nbytes = read(maio_connector, buffer, sizeof(buffer) )) > 0)

While I am still clueless about what's wrong, I appreciate all your efforts in helping me out.

Thank you,

Jay

I have entered into yahoo.com search field

termios stop bits
.

The very first match is:

http://www.kernel.org/doc/Documentation/serial/driver
.

Using 'stop' as search item in the above I come to:

Code:

  set_termios(port,termios,oldtermios)
        Change the port parameters, including word length, parity, stop
        bits.  Update read_status_mask and ignore_status_mask to indicate
        the types of events we are interested in receiving.  Relevant
        termios->c_cflag bits are:
                CSIZE        - word size
                CSTOPB        - 2 stop bits

.

theNbomr 05-20-2009 03:25 PM

Quote:

Originally Posted by Sergei Steshenko (Post 3546700)
The old trick is to set two stop bits at the transmitting side and one stop bit at the receiving side, and this trick has good physical explanation.

I think that some HW allows even 1.5 bits, which would also be OK (instead of the 2 bits).

Not saying you are wrong, but what about craftybones' problem is suggestive that the number of stop bits is the cause of the problem? To me, it seems just as likely that something about the data stream is affecting the behavior of the connection. Perhaps embedded escape sequences that are being trapped, or XOFFs being sent and freezing the connection.
In applications such as craftybones is crafting, it always seems to make the most sense to me, to invoke RAW mode ( c_lflag &= ~ICANON ), to remove the line-oriented treatment of incoming data. If this is done, it may also be prudent to specifically set VMIN & VTIME in the c_cc[] array. If the receiver is in canonical mode, it is possible that the receiver is simply waiting for an End-Of-Line character, and blocking until such a character is received.
craftybones has cleared CRTSCTS, so that should take care of hardware flow control getting in the way.

Some decent sources of information, in case you haven't found them already:
Serial Programming Howto
Serial Howto
Serial Programming Guide for POSIX Operating Systems
Terminal Concepts in GNU/Linux

--- rod.

Sergei Steshenko 05-20-2009 03:53 PM

Quote:

Originally Posted by theNbomr (Post 3547356)
Not saying you are wrong, but what about craftybones' problem is suggestive that the number of stop bits is the cause of the problem? To me, it seems just as likely that something about the data stream is affecting the behavior of the connection. Perhaps embedded escape sequences that are being trapped, or XOFFs being sent and freezing the connection.
In applications such as craftybones is crafting, it always seems to make the most sense to me, to invoke RAW mode ( c_lflag &= ~ICANON ), to remove the line-oriented treatment of incoming data. If this is done, it may also be prudent to specifically set VMIN & VTIME in the c_cc[] array. If the receiver is in canonical mode, it is possible that the receiver is simply waiting for an End-Of-Line character, and blocking until such a character is received.
craftybones has cleared CRTSCTS, so that should take care of hardware flow control getting in the way.

Some decent sources of information, in case you haven't found them already:
Serial Programming Howto
Serial Howto
Serial Programming Guide for POSIX Operating Systems
Terminal Concepts in GNU/Linux

--- rod.

I am not saying I am definitely right, but I had a similar problem 20 years ago - the communications just stopped after some time (minutes or seconds - I already do not remember).

Regarding the stop bits on both sides - receiver and transmitter are not synchronized WRT their clock frequency. And the stop bit at receiving side should be no shorter than full length, but the receiver can easily deal with linger than necessary stop bits - it's the same as no start bit yet and thus OK.

There is even a special term in communications - I think it's called "bit shaving", i.e. a part of bit duration is "shaved off" - that's regarding 1.5 bits.

craftybones 05-20-2009 06:59 PM

Hello all,

I have tried setting the stop bits to two but the behavior doesn't change. When I said I didn't know about the stop bits, I meant that I didn't know if changing it was going to help.

The suggestion to remove canonical is interesting. I think its worth a shot. I'll do that when I get to work and give you guys a shout. Thanks a ton.

Jayanth

theNbomr 05-20-2009 07:04 PM

Yes, the number of stop bits sent can be arbitrarily large, since the state of a stop bit (mark) is the same as the state of the idle period between frames, and there is no specific delimiter between the end of the last stop bit and the beginning of the idle state. I suppose that if the receiver is expecting two stop bits while the sender is transmitting only one, there is a possibility of a framing error by seeing the subsequent start bit unexpectedly. Since craftybones has not set 'CSTOPB', his receiver should be expecting only one stop bit, however. If I recall correctly, on a 8250 family UART (I know this was not specified, but they are fairly ubiquitous), a 1.5 stop-bit width is only possible on a 5-bit data word, which I have yet to see used in practice.
One question that remains unanswered is what exact failure mode is exhibited? There are at least two possibilities that come immediately to mind. First, the read() call can return zero in perpetuity, or second, the read() call can block perpetually. This assumes that there are no other errors in the program that would have the reported result. From a cursory inspection of the supplied code, I see no errors in logic, although there is evidently much code removed from the sample.
--- rod.

Sergei Steshenko 05-20-2009 07:25 PM

Quote:

Originally Posted by craftybones (Post 3547536)
Hello all,

I have tried setting the stop bits to two but the behavior doesn't change. When I said I didn't know about the stop bits, I meant that I didn't know if changing it was going to help.

The suggestion to remove canonical is interesting. I think its worth a shot. I'll do that when I get to work and give you guys a shout. Thanks a ton.

Jayanth


Did you do this only on the transmitting side. Rather, if it's bidirectional link, both sides transmitters have to have 2 stop bits while both sides receivers have to to have one stop bit.

craftybones 05-21-2009 01:46 AM

Hello,

It seems like the read call is blocking!!! So perhaps setting the VMIN and VTIME is perhaps appropriate. Let me check and get back.

Thank you,

Jayanth

craftybones 05-21-2009 02:07 AM

Ok, so I set VMIN and VTIME to zero values, positive values...but now, instead of blocking, read just returns 0. I have flushed the buffers, and I still get a read of 0 bytes. Now I am totally clueless.

Jayanth

craftybones 05-21-2009 04:14 AM

Hello,

Turns out that closing and opening the connection again fixes the problem, but this is still a hack as I need to keep opening and closing connections and there is no guarantee that this will always work either.

Any ideas?

Jay

wje_lq 05-21-2009 04:33 AM

  1. By now you're removing the canonical bit, yes? This is very important.
  2. VMIN must be 1 and VTIME must be 0. You'll get one byte per read().
  3. I wrote a program which uses the modem. You're not interested in modem complications, but the advantages to you of this program are these:
    1. It's rather short, so it's not too difficult to understand the source.
    2. It's very, very thoroughly documented.
    Download the source from here, rip out what you don't need, play with it, and come back here with questions. (My time will be very limited until next Tuesday, but I'll do what I can even before then.)

    I intend to leave the program at that URL for at least two weeks.


All times are GMT -5. The time now is 03:44 AM.