LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Bug in ComRdTerm?

I'm wondering if there is a bug in this function (CVI 8.1) or if it might be something else.  I'm probably not going to do a good job of explaining this so bare with me, but here is the problem I'm having....

I have a device that sends data (4800/n/8/1 no flowcontrol) in the form of "$1234\r\n".  It does not send the NULL terminator, or the quotes and sends around 425 of these lines at a time.

To setup the callback function I'm actually looking for the '\r' termination character or any character sent:

    InstallComCallback (portNo, (LWRS_RECEIVE | LWRS_RXCHAR), 1, '\r', CheckDeviceSerial, 0);

So basically the callback will be invoked on any character sent


In the actual callback function it disables itself and then loops while there is data in the serial buffer, does the read, then re-enables itself when the buffer is empty.  A simplified code snippet of the main loop is below:

    cnt = GetInQLen(portNo);  
    while(cnt)
    {  

          //buffer is overkill so read upto the term char
        numBytesRead = ComRdTerm(portNo, buffer, 254, '\r');

             //just put this in to catch the error
        if( (buffer[0] == '\n') || (buffer[0] == '\r') )
        {
            cnt = 1;
        }
       
        <usefull processing stuff>

        cnt = GetInQLen(portNo);  
    }

Putting a break on the "cnt = 1" line, it will be hit at random times.  To me, it seems that the comRdTerm isn't always removing the following LF from the previous read.  Examining the buffer, the first character is a LF, which must be from the previous read (should have been removed according to the docs).

If I change the termination character to LF, everything works ok (which I can do just as well).  I will just have to manually remove the CR before the LF.
          

 



 

0 Kudos
Message 1 of 4
(3,304 Views)
Hello,

I think what you're seeing is not a bug, but rather a logical quirk of the transfer behavior.  Consider that the data may arrive in arbitrary chunks like the following:

$1234\r\n$12
34\r\n$1234\r
\n$1234\r\n$
...

The first call to ComRdTerm will immediately parse the first term, removing both the \r and \n.  The second call will read the remaining characters ($12) without finding a \r (the termination character), so it will wait for more characters to arrive.  When the second chunk comes, the ComRdTerm call finds the \r, as well as the \n, so both are removed, and the function returns.  The third call to ComRdTerm then reads the remaining characters ($1234\r) and finds the termination character (though no \n), so it removes the \r and returns.  This is where the quirk comes from.  The next call to ComRdTerm will encounter an "orphaned" \n character.

As you said, if you make \n the termination character, then ComRdTerm will never return until both the \r and \n characters have been read, since the \r always preceeds the \n.

ComRdTerm shouldn't wait for a \n that might come when the termination character is \r, so there really isn't a bug to fix.  I think the best workarounds are the ones you've already noted: check for leading \n characters (when using \r as the term char) or manually remove the trailing \r (when using \n as the term char).

Sorry for the weirdness.  Hope this clears things up.

Mert A.
National Instruments

0 Kudos
Message 2 of 4
(3,303 Views)
Maybe I'm confused about the term "chunk".  The device is a simple microcontroller that does a sprintf to a buffer, writes the first character to the serial register, loops on a done bit until the hardware shifts it out, writes the register with the next character and so on.  It breaks the loop when it sees a LF (after writing the LF to the register).  So by chunks I am saying that it sends the full "$xxxxx\r\n" as fast as 4800bps can take it, then pause to read & format the next "chunk" and send it and so forth.

It should happen like this:
<write a character at a time>: $0001\r\n   <relativly longer pause for read/format of next data>
<write>: $0002\r\n   <pause>
<write>: $0003\r\n   <pause>
etc.

I never get a timeout error, so it must be terminating on the CR when the function returns.

If ComRdTerm is not waiting at least one character transfer time after the termination character to determine if the next character received is a LF (or CR if LF is first), then it seems that the 2 lines in the documentation regarding removing both if it sees one seems invalid?  Maybe it should say preceeding instead of following (it doesn't do that either though)?

let me know if i'm nuts 🙂

For what's it's worth, the computer I develop on is a lot faster than the targets, and the problem was first noticed on a slower machine.  Perhaps the speed of the executing lower level code in comrdterm makes a difference as it behaves differently depending on this?
0 Kudos
Message 3 of 4
(3,295 Views)
When I say that the data may come in arbitrary chunks, I am considering that the driver probably has to wait for a hardware buffer to fill before transferring that data to the software buffer.  That said, I confirmed that ComRdTerm does in fact wait 2x the character transmission time monitoring for the complement to the terminating \r or \n character, and at 4800 baud, 8 data bits, no parity bits, and one stop bit, this time is about 4 ms.  I would not expect delays this long between transfers from the serial hardware buffer to the driver's software buffer.  Another possible explanation for the newline orphaning is a context switch taking up the monitoring period.  That is, if a context switch occurs after the initial, unsuccessful check for a trailing \n character, we will probably never loop again looking for the \n, as the 4 ms will already be up.

Unfortunately I can't reproduce this behavior, so I can't nail down the exact cause.  If I can get it to happen, I'll look into it further.

Mert A.
National Instruments
0 Kudos
Message 4 of 4
(3,283 Views)