Odd Problem with RS232 Port read: Changing 0x0D (CR) to 0x0A (LF) - Linux

This is a discussion on Odd Problem with RS232 Port read: Changing 0x0D (CR) to 0x0A (LF) - Linux ; Greetings all - I have a strange problem, and I hope someone can give me some ideas. I'm writing a program with a serial interface (RS232 for now, maybe RS485 later). My serial port setup code is pretty much straight ...

+ Reply to Thread
Results 1 to 6 of 6

Thread: Odd Problem with RS232 Port read: Changing 0x0D (CR) to 0x0A (LF)

  1. Odd Problem with RS232 Port read: Changing 0x0D (CR) to 0x0A (LF)

    Greetings all -

    I have a strange problem, and I hope someone can give me some ideas.

    I'm writing a program with a serial interface (RS232 for now, maybe
    RS485 later). My serial port setup code is pretty much straight out of
    Sweet's Serial Programming Guide for POSIX.

    The serial read generally works fine, with one exception: Whenever the
    value 13 (0x0D) shows up anywhere in the data, it turns into 10 (0x0A).
    These values correspond to CR and LF, which is probably not a
    coincidence.

    Here is what I'm doing to set up the port:

    -----

    *** Using open() to open the port

    FileDescriptor = open(qPrintable(DeviceName),
    O_RDWR|O_NOCTTY|O_NDELAY);
    //FileDescriptor = open("/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);

    if(FileDescriptor != -1)
    {
    status = fcntl(FileDescriptor, F_SETFL, O_NONBLOCK);
    }

    *** Setting up the port:

    bool UARTInterface::SetupPort(void)
    {
    int status = -1;
    struct termios term_ios;
    bool setup_status = false;

    if(IsOpen() == true)
    {
    // get the current terminal attributes
    status = tcgetattr(FileDescriptor, &term_ios);

    // baud rate
    cfsetospeed(&term_ios, B19200);
    cfsetispeed(&term_ios, B19200);

    // set remainder of terminal flags
    term_ios.c_cflag |= (CLOCAL | CREAD);

    // set the terminal attributes
    status = tcsetattr(FileDescriptor, TCSANOW, &term_ios);

    /// more stuff
    // get the current terminal attributes
    status = tcgetattr(FileDescriptor, &term_ios);

    term_ios.c_cflag &= ~PARENB;
    term_ios.c_cflag &= ~CSTOPB;
    term_ios.c_cflag &= ~CSIZE;
    term_ios.c_cflag |= CS8;

    term_ios.c_iflag &= ~(IXON | IXOFF | IXANY);

    term_ios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    term_ios.c_oflag &= ~OPOST;

    // set the terminal attributes
    status = tcsetattr(FileDescriptor, TCSANOW,
    &term_ios);

    if(status != -1)
    {
    setup_status = true;
    }
    else
    {
    printf("UART: SetupPort error\n");
    }

    }

    return setup_status;
    }

    *** Reading the port:

    num_chars_read = read(FileDescriptor, buf, num_bytes);
    printf("--- %02x\n",buf[0]);


    ------------------

    The line right above is what shows the problem. I always have
    num_bytes = 1, so buf always contains 1 character. This works fine,
    except that when the incoming data byte = 13, it gets read as a 10.

    So, any thoughts? Any idea where I'm going wrong?

    Thanks,

    Dave


  2. Re: Odd Problem with RS232 Port read: Changing 0x0D (CR) to 0x0A (LF)

    On a sunny day (15 Jan 2007 11:09:39 -0800) it happened dave.zieger@gmail.com
    wrote in <1168888179.580714.179560@m58g2000cwm.googlegroups. com>:

    >Greetings all -
    >
    >I have a strange problem, and I hope someone can give me some ideas.
    >
    >I'm writing a program with a serial interface (RS232 for now, maybe
    >RS485 later). My serial port setup code is pretty much straight out of
    >Sweet's Serial Programming Guide for POSIX.
    >
    >The serial read generally works fine, with one exception: Whenever the
    >value 13 (0x0D) shows up anywhere in the data, it turns into 10 (0x0A).
    > These values correspond to CR and LF, which is probably not a
    >coincidence.
    >
    >Here is what I'm doing to set up the port:


    man termios
    says:
    INLCR Translate NL to CR on input.

    ICRNL Translate carriage return to newline on input (unless IGNCR is set).

    Maybe some of this is set, and you need to reset it?

  3. Re: Odd Problem with RS232 Port read: Changing 0x0D (CR) to 0x0A (LF)

    dave.zieger@gmail.com wrote:
    > I'm writing a program with a serial interface (RS232 for now, maybe
    > RS485 later). My serial port setup code is pretty much straight out of
    > Sweet's Serial Programming Guide for POSIX.


    > The serial read generally works fine, with one exception: Whenever the
    > value 13 (0x0D) shows up anywhere in the data, it turns into 10 (0x0A).
    > These values correspond to CR and LF, which is probably not a
    > coincidence.


    > term_ios.c_iflag &= ~(IXON | IXOFF | IXANY);


    I guess you also need to clear the ICRNL bit - perhaps it would be
    prudent to zero out all the flags first and then only set those bits
    you really need in order to avoid ending up with some bits acciden-
    tally remaining set.
    Regards, Jens
    --
    \ Jens Thoms Toerring ___ jt@toerring.de
    \__________________________ http://toerring.de

  4. Re: Odd Problem with RS232 Port read: Changing 0x0D (CR) to 0x0A (LF)


    Jens Thoms Toerring wrote:
    > dave.zieger@gmail.com wrote:
    > > I'm writing a program with a serial interface (RS232 for now, maybe
    > > RS485 later). My serial port setup code is pretty much straight out of
    > > Sweet's Serial Programming Guide for POSIX.

    >
    > > The serial read generally works fine, with one exception: Whenever the
    > > value 13 (0x0D) shows up anywhere in the data, it turns into 10 (0x0A).
    > > These values correspond to CR and LF, which is probably not a
    > > coincidence.

    >
    > > term_ios.c_iflag &= ~(IXON | IXOFF | IXANY);

    >
    > I guess you also need to clear the ICRNL bit - perhaps it would be
    > prudent to zero out all the flags first and then only set those bits
    > you really need in order to avoid ending up with some bits acciden-
    > tally remaining set.
    > Regards, Jens
    > --
    > \ Jens Thoms Toerring ___ jt@toerring.de
    > \__________________________ http://toerring.de




    --

    Yep - thanks for the 2 replies. I needed to add the ICRNL flag into
    the line above.

    All is well now.

    Thanks,
    Dave


  5. Re: Odd Problem with RS232 Port read: Changing 0x0D (CR) to 0x0A (LF)


    Jens Thoms Toerring wrote:
    > dave.zieger@gmail.com wrote:
    > > I'm writing a program with a serial interface (RS232 for now, maybe
    > > RS485 later). My serial port setup code is pretty much straight out of
    > > Sweet's Serial Programming Guide for POSIX.

    >
    > > The serial read generally works fine, with one exception: Whenever the
    > > value 13 (0x0D) shows up anywhere in the data, it turns into 10 (0x0A).
    > > These values correspond to CR and LF, which is probably not a
    > > coincidence.

    >
    > > term_ios.c_iflag &= ~(IXON | IXOFF | IXANY);

    >
    > I guess you also need to clear the ICRNL bit - perhaps it would be
    > prudent to zero out all the flags first and then only set those bits
    > you really need in order to avoid ending up with some bits acciden-
    > tally remaining set.
    > Regards, Jens
    > --
    > \ Jens Thoms Toerring ___ jt@toerring.de
    > \__________________________ http://toerring.de



  6. Re: Odd Problem with RS232 Port read: Changing 0x0D (CR) to 0x0A(LF)

    "DZieger" wrote:
    >Jens Thoms Toerring wrote:
    >> dave.zieger@gmail.com wrote:
    >> > I'm writing a program with a serial interface (RS232 for now, maybe
    >> > RS485 later). My serial port setup code is pretty much straight out of
    >> > Sweet's Serial Programming Guide for POSIX.

    >>
    >> > The serial read generally works fine, with one exception: Whenever the
    >> > value 13 (0x0D) shows up anywhere in the data, it turns into 10 (0x0A).
    >> > These values correspond to CR and LF, which is probably not a
    >> > coincidence.

    >>
    >> > term_ios.c_iflag &= ~(IXON | IXOFF | IXANY);

    >>
    >> I guess you also need to clear the ICRNL bit - perhaps it would be
    >> prudent to zero out all the flags first and then only set those bits
    >> you really need in order to avoid ending up with some bits acciden-
    >> tally remaining set.


    >Yep - thanks for the 2 replies. I needed to add the ICRNL flag into
    >the line above.
    >
    >All is well now.


    Nope, all is not well, yet. You just haven't discovered the
    next problem... :-)

    For example, with your code the Linux specific termios struct
    element "c_line" has not been set to a specific value, and will
    remain whatever it was when the last program to use the serial
    port exited (or crashed, as the case may be). If it just
    happens that pppd was running on that port, and crashed or was
    killed with SIGKILL, your program will refuse to run.

    The effect is that your program could run fine for months or
    even years, and then suddenly and mysteriously refuse to work.

    Clear the entire struct termios, and then specifically set each
    and every flag that you need. That is the only way to guarantee
    no artifacts from a previous program configuration. As you can
    see from the code below, there are other problems that would some
    day have come to light.


    bool UARTInterface::SetupPort(void)
    {
    int status = -1;
    struct termios term_ios;
    bool setup_status = false;

    if(IsOpen() == true)
    {
    // clear all struct termios elements
    memset(&term_ios, 0, sizeof term_ios)

    // Ignore break, framing errors, and parity errors
    term_ios.c_iflag = (IGNBRK | IGNPAR);

    // set terminal flags as needed
    term_ios.c_cflag = (CLOCAL | CREAD | CS8);

    #if 0
    // enable this to have hardware flow control
    term_ios.c_cflag |= CRTSCTS;
    #endif

    // Configure to block and read 1 character at a time
    term_ios.c_cc[VMIN] = 1; // return with 1 byte
    term_ios.c_cc[VTIME] = 0; // no timer

    // set baud rate last
    cfsetospeed(&term_ios, B19200);
    cfsetispeed(&term_ios, B19200);

    // set the terminal attributes
    status = tcsetattr(FileDescriptor, TCSANOW, &term_ios);

    if(status == -1)
    {
    printf("UART: SetupPort error\n");
    }
    }
    return setup_status == -1;
    }


    The above configures the port for raw i/o that will block on
    read requests until a character is received. That may or may
    not be what you want.

    If you want to wait only so long for a byte to be received, set
    the VTIME array member to a number between 1 and 255
    (representing delay in tenths of a second), and set the VMIN member
    to 0.

    If you set both to 0, a read() call will return immediately
    either with or without a byte.

    Just to be clear, you could set the VMIN member to something
    other than 0 or 1, but trying to use it that way is certain to
    come to grief.

    Note also that just because a call to read() can return with only
    a single character, that doesn't mean it can't also return with
    more, hence your

    num_chars_read = read(FileDescriptor, buf, num_bytes);
    printf("--- %02x\n",buf[0]);

    Would be valid when buf is a ten element char array and
    num_bytes is 10. If data is being sent but no read() is called
    for a few seconds, there might be hundreds of bytes available,
    and read() would return whatever the value of num_bytes happens
    to be. Hence if you want single byte reads, make sure num_bytes
    is never larger than 1.

    --
    Floyd L. Davidson
    Ukpeagvik (Barrow, Alaska) floyd@apaflo.com

+ Reply to Thread