views:

392

answers:

2

I've got a little application written in C# that listens on a SerialPort for information to come in. The information comes in as: STX + data + ETX + BCC. We then calculate the BCC of the transmission packet and compare. The function is:

private bool ConsistencyCheck(byte[] buffer)
{
    byte expected = buffer[buffer.Length - 1];
    byte actual = 0x00;

    for (int i = 1; i < buffer.Length - 1; i++)
    {
     actual ^= buffer[i];
    }

    if ((expected & 0xFF) != (actual & 0xFF))
    {
     if (AppTools.Logger.IsDebugEnabled)
     {
      AppTools.Logger.Warn(String.Format("ConsistencyCheck failed: Expected: #{0} Got: #{1}", expected, actual));
     }
    }

    return (expected & 0xFF) == (actual & 0xFF);
}

And it seems to work more or less. It is accurately not including the STX or the BCC and accurately including the ETX in it's calculations. It seems to work a very large percentage of the time, however we have at least two machines we are running this on, both of which are Windows 2008 64-bit in which the BCC calculation NEVER adds up. Pulling from a recent log I had in one byte 20 was sent and I calculated 16 and one where 11 was sent and I calculated 27.

I'm absolutely stumped as to what is going on here. Is there perhaps a 64 bit or Windows 2008 "gotcha" I'm missing here? Any help or even wild ideas would be appreciated.

EDIT:

Here's the code that reads the data in:

private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    // Retrieve number of bytes in the buffer
    int bytes = serialPort.BytesToRead;

    // Create a byte array to hold the awaiting data
    byte[] received = new byte[bytes];

    //read the data and store it
    serialPort.Read(received, 0, bytes);

    DataReceived(received);
}

And the DataReceived() function takes that string and appends it to global StringBuilder object. It then stays as a string builder until it's passed to these various functions at which point the .ToString() is called on it.

EDIT2: Changed the code to reflect my altered routines that operate on bytes/byte arrays rather than strings.

EDIT3: I still haven't figured this out yet, and I've gotten more test data that has completely inconsistent results (the amount I'm off of the send checksum varies each time with no pattern). It feels like I'm just calculating the checksum wrong, but I don't know how.

+2  A: 

The buffer is defined as a String. While I suspect the data you are transmitting are bytes. I would recommend using byte arrays (even if you are sending ascii/utf/whatever encoding). Then after the checksum is valid, convert the data to a string

Toad
While I agree that that is probably a good idea, how exactly would that win me anything? I don't really feel like refactoring the entire app to use a byte array for no reason.
Morinar
I would not knwo if you feed the bytes 0 - 255 into a string, if the string characters would also read 0-255... since some conversion takes place to it's internal format, it could very well be they are translated and hence your checksum will be wrong
Toad
+1 for Morinar's answer. strings aren't suited to representing arrays of bytes. It should be trivial to refactor from string to byte[]. I would put money on your problem being down to the use of a string instead of byte[].
Bryan
Trivial to rewrite that single function, not necessarily the entire app. Still, seems like a decent idea (how I would have done it if I'd written the initial implementation for sure) so I'll probably change it. Any other ideas?
Morinar
Well, this doesn't seem to be the issue. I'm definitely going to leave the code this way as it's definitely "better", but there is still something here I am definitely missing.
Morinar
Did checking for the EventType not help at all? Don't be fooled by the EventType.Chars. This does not mean 'Chars' in the normal sense of the word, it means data of some sort has arrived at the port.
Andy
I don't think that's the issue... it seems more likely to me that I'm not receiving bytes that the device thinks it's sending rather than that I'm receiving too much. I'm pulling out the byte strings that are coming over (and that I see in the log) and recalculating the checksums and they match the original (wrong) checksums I'm calculating. I really just think I'm calculating them wrong, but I just don't know how.
Morinar
A: 

Make sure you have the port set to accept null bytes somewhere in your port setup code. (This maybe the default value, I'm not sure.)

port.DiscardNull = false;

Also, check for the type of byte arriving at he serial port, and accept only data:

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    if (e.EventType == SerialData.Chars)
    {
        // Your existing code
    }
}
Andy