Burzum619
Burzum619

Reputation: 143

Byte array not being initialized to correct size?

I am writing an application that receives some input from a long range radio via a serial connection. I am currently using the SerialPort C# class to receive and send data, but I am having a few issues. I've noticed that the function I have for receiving data is not correctly setting the buffer byte array size. All data is being sent in bytecode (Hex).

Say the other node sends 103 bytes of data. Stepping through my code and setting a breakpoint at the "Read()" line, I see that "serialPort1.BytesToRead-1" evaluates to 103, BUT the byte[] array is only initialized to 17. I have no explanation for this behavior. As a result, only the first 17 bytes are put into the array. Continuing through the step through, this same event is triggered, this time with "serialPort1.BytesToRead-1" evaluating to 85 (presumably since only the first 17 of the 103 bytes were read.

If I hardcore the data array size at 103, it works flawlessly in one pass. However, at the moment I am unable to store all the data in my byte array in one pass, which is causing a lot of problems. Anyone know why my byte array is being initialized to such an arbitrary size???

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
        byte[] data = new byte[serialPort1.BytesToRead - 1];
        serialPort1.Read(data, 0, data.Length);
        DisplayData(ByteToHex(data) /*+ "\n"*/);
}

Updated: Here's the new method I am attempting. isHeader is a boolean value initially set to true (as the first two bytes being received from the packet are in fact the length of the packet).

    const int NUM_HEADER_BYTES = 2;

    private void serialPort1_DataReceived(object sender,                     System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        byte[] headerdata = new byte[2];
        if (isHeader)
        {
            serialPort1.Read(headerdata, 0, NUM_HEADER_BYTES);
            int totalSize = (headerdata[0] << 8 | headerdata[1]) >> 6;
            serialPort1.ReceivedBytesThreshold = totalSize - NUM_HEADER_BYTES;
            data = new byte[totalSize - NUM_HEADER_BYTES];
            isHeader = false;
        }
        else
        {
            serialPort1.Read(data, 0, data.Length);
            double[][] results = ParseData(data, data.Length);
            serialPort1.ReceivedBytesThreshold = NUM_HEADER_BYTES;
            isHeader = true;
            DisplayData(ByteToHex(data) /*+ "\n"*/);
        }
    }

Upvotes: 1

Views: 1213

Answers (2)

avishayp
avishayp

Reputation: 706

Debuggers won't deliver when it comes to real time data transfer. Use debug traces.

BTW I'd go with polling data myself, not putting my trust on events. With serial ports this is a sound and reliable approach.

Edit per comment: Serial data transfer rate is bounded by your baud-rate. You're worried about losing data, so let's look at the numbers:

Assuming:

baud_rate = 19600 [bytes/sec]  // it's usually *bits*, but we want to err upwards
buffer_size = 4096 [bytes]     // windows allocated default buffer size

So it takes:

4096/19600 [sec] ~ 200 [ms]

To overflow the buffer (upper bound).

So if you sample at 50 Hz, you're running on an order of magnitude safety net, and that's a good spot. On each 'sample' you read the whole buffer. There is no timing issue here.

Of course you should adopt the numbers to your case, but I'll be surprised if your low bandwidth RF channel will result in a transfer rate for which 50 Hz won't be a sufficient overkill.

LAST EDIT: Needless to say, if what you currently have works, then don't touch it.

Upvotes: 2

David Yaw
David Yaw

Reputation: 27864

BytesToRead is equal to the number of bytes waiting in the buffer. It changes from moment to moment as new data arrives, and that's what you're seeing here.

When you step through with the debugger, that takes additional time, and the rest of the serial data comes in while you're stepping in the debugger, and so BytesToRead changes to the full value of 104.

If you know that you need 103 bytes, I believe setting ReceivedBytesThreshold to 104 will trigger the DataRecieved event at the proper time. If you don't know the size of the message you need to receive, you'll need to do something else. I notice you're throwing away one byte (serialPort1.BytesToRead - 1), is that an end-of-message byte that you can search for as you read data?

Upvotes: 3

Related Questions