0

I have an Atmel Atxmega128A1 microcontroller that is sending a message to the PC (c#) application through a serial COM port. Occasionally I start receiving a large string that looks like this (PcIocBus is a class):

"PcIocBus: Invalid message RX: 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00"

in my Visual Studio debug output.

Every time the 0s show up we get an exception

A first chance exception of type System.ArgumentException occurred in system.dll Additional information: Offset and length were out of bounds for the array or count is greater than the nymber of elements from index to the end of the source collection.

which is showing up at the 'Port.Read..." line.

private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
     byte[] rxBuff = new byte[255];
     int bufferSize = Port.BytesToRead;

     try
     {
          Debug.WriteLine("Buffer Size: " + bufferSize);
          Port.Read(rxBuff, 0, Port.BytesToRead);

          foreach (byte newByte in rxBuff)
          {
               InBytes.Enqueue(newByte);
          }
     }
     catch (Exception)
     {
          Debug.WriteLine("PcIocBus: Invalid message RX: " + BitConverter.ToString(rxBuff)):
     }
}

Does anyone might know why this is giving me the errors? I've tried setting the rxBuff array to the same size of the buffer because the buffer (for some reason) does go over 255 sometimes, but I still get the 0s and the exception.

dsolimano
  • 8,870
  • 3
  • 48
  • 63
MB41
  • 552
  • 2
  • 8
  • 24

1 Answers1

3
   byte[] rxBuff = new byte[255];

255 is a completely random number that has nothing to do with reality. It is C code. The BytesToRead certainly can be larger than 255, you already found the kaboom! you get from that. It can also be 0, you are not checking e.EventType in your code.

   Port.Read(rxBuff, 0, Port.BytesToRead);

SerialPort.BytesToRead is not a stable number, it increases while your code is running since the device driver continues to receive data from the serial port. This will crash your code when you fixed the first bug, you'll try to read more bytes into rxBuff then can possibly fit. You actually have a stable number, bufferSize, but you are not using it. Using rxBuff.Length is the correct way after you fixed the 1st bug.

   InBytes.Enqueue(newByte);

This is a very, very nasty bug that is very hard to diagnose. The Queue class is not thread-safe. DataReceived runs on a worker thread, the code you wrote that calls the Dequeue() method runs on another thread. Very Bad Things happen when they run at the same time, this will happen. Your must use the lock keyword to keep the InBytes object access thread-safe.

   Debug.WriteLine("PcIocBus: Invalid message RX: " + BitConverter.ToString(rxBuff)):

Your exception handler is badly broken. It doesn't show the exception message, it doesn't show what was actually received (you ignored the return value of Read()), it offers no hope that the data loss is a recoverable mishap. It won't be. Never write try/catch code that makes your program malfunction in an impossible to diagnose way. And hides programming bugs. Just remove try/catch, it causes nothing but misery. Write an event handler for AppDomain.CurrentDomain.UnhandledException instead.

Programmers that know how to write correct SerialPort code are like the pioneers that made it to Oregon alive. They avoided the arrows in their back.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536