Problem detecting and reacting to serial break

Paul Thornton prt at prt.org
Sat Aug 14 17:30:59 UTC 2010


Hi,

I'm working on a small piece of code that reads a data stream from the
serial port, putting it into a buffer for processing later - for those
interested, it is receiving DMX512 lighting control data - but I'm
having trouble with the detection of a break condition on the serial
line.  I'd appreciate any suggestions from anyone.

I'm using 8.0-RELEASE with uftdi and ucom driving the serial port.

The format of this data is very simple - a break is sent, followed by
513 bytes of useful information; then after some arbitrary delay another
break, and the next 513 bytes.  So, I think, easy to do this - just wait
for a break and read away.

My problem is that despite setting the port up (as I think) correctly,
the break seems to be ignored at a driver level and it appears as data
byte of 0x00 (what I'd expect to see if IGNBRK was set).  This is no
good as I have no way to know where I am in the chunk of 513 bytes of
data, so can't synchronize at all.

I have the following code setting up my serial port:

        tcgetattr(fd, &options);
        printf("before: c_iflag=%x c_oflag=%x c_cflag=%x c_lflag=%x\n",
	 options.c_iflag, options.c_oflag,
	 options.c_cflag, options.c_lflag);

        options.c_iflag         = (BRKINT | IGNPAR);
        options.c_oflag         = 0;
        options.c_cflag         = (CLOCAL | CREAD | CS8 | CSTOPB);
        options.c_lflag         = 0;
        options.c_cc[VMIN]      = 513;
        options.c_cc[VTIME]     = 0;

        if (cfsetispeed(&options, BAUDRATE) < 0) {
                perror("cfsetispeed");
                exit(1);
        }

        if (cfsetospeed(&options, BAUDRATE) < 0) {
                perror("cfsetospeed");
                exit(1);
        }

        if (tcsetattr(fd, TCSANOW, &options) < 0) {
                perror("tcsetattr");
                exit(1);
        }

        /* debug test - did anything change? */
        tcgetattr(fd, &options);
        printf("after: c_iflag=%x c_oflag=%x c_cflag=%x c_lflag=%x\n",
	 options.c_iflag, options.c_oflag,
	 options.c_cflag, options.c_lflag);

The debug output shows my set is doing what I expect it to:
before: c_iflag=2005 c_oflag=3 c_cflag=cf00 c_lflag=443
after: c_iflag=6 c_oflag=0 c_cflag=8f00 c_lflag=0

So according to the documentation, the effect of the break should be to
flush the input and output buffers, and send a SIGINT to my process. The
buffer doesn't seem to get flushed, and I don't get sent the SIGINT.

The data I'm getting in my buffer is valid, apart from the fact that I
can't tell where byte 1 is - and every time I run the test program the
location of byte 1 changes arbitrarily depending on what was in the
receive buffer.

Have I missed something here, or is there any other way that I can
detect the presence of the break out-of-band?  I cannot make any
assumptions about the 513 bytes that I'm receiving and any combination
of data may be present in there.

Many thanks,

Paul.





More information about the freebsd-hackers mailing list