Destination array is not long enough

2

I'm trying to make a serial communication from Arduino to C# in Visual Studio. Here is my code. I use timer to request and receive the data.

private void timer1_Tick(object sender, EventArgs e)
    {
        isConnected = true;
        port.Write("A");

        int bytes = port.BytesToRead;
        byte[] buffer = new byte[bytes];
        port.Read(buffer, 0, bytes);

        for (int i = 0; i < bytes; i++)
        {
            int potensio = BitConverter.ToInt32(buffer, 0);
            string potString = Convert.ToString(potensio);
            label1.Text = potString;
        }
    }

Error in this line int potensio = BitConverter.ToInt32(buffer, 0);

    System.ArgumentException
      HResult = 0x80070057
      Message=Destination array is not long enough to copy all the items in the collection.Check array index and length.
      Source= mscorlib
      StackTrace:
       at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
       at System.BitConverter.ToInt32(Byte[] value, Int32 startIndex)
       at SerialTest.Form1.timer1_Tick(Object sender, EventArgs e) in C:\Users\ThinkPad\source\repos\SerialTest\SerialTest\Form1.cs:line 73
       at System.Windows.Forms.Timer.OnTick(EventArgs e)
       at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at SerialTest.Program.Main() in C:\Users\ThinkPad\source\repos\SerialTest\SerialTest\Program.cs:line 19
c#
serial-port
asked on Stack Overflow Feb 15, 2019 by Yusuf Praditya • edited Feb 15, 2019 by gre_gor

1 Answer

1

k; let's try and fix this; the problem here is that data doesn't always arrive in nice neat chunks of what you want. In your case, you want to process 4 bytes at a time, so: let's try that:

byte[] buffer = new byte[4];
int bytesBuffered = 0;
bool inProgress = false;
private void timer1_Tick(object sender, EventArgs e)
{
    if (!inProgress) {
        // presumably this means "send me the current data?"
        inProgress = true;
        port.Write("A");            
    }

    // read whatever we still need to make 4, if available
    int bytes = Math.Min(port.BytesToRead, 4 - bytesBuffered);
    if (bytes <= 0) return; // nothing to do right now

    // read the next few bytes, noting the offset
    bytes = port.Read(buffer, bytesBuffered, bytes);
    // TODO: check if bytes is <= 0 - if so, the port may have disconnected
    bytesBuffered += bytes;

    // check whether we have enough to update the UI
    if (bytesBuffered == 4)
    {
        // we now have 4 bytes; update the UI, and reset
        int potensio = BitConverter.ToInt32(buffer, 0);
        string potString = Convert.ToString(potensio);
        label1.Text = potString;

        // and issue a new A next time
        bytesBuffered = 0;
        inProgress = false;
    }
}

Note: if you get odd results, it is possible that you haven't accounted for "endianness" - a 4-byte integer can be encoded as "big endian" or "little endian", and your CPU can be "big endian" or "little endian" - the two need to match. If the results look insanely big (or insanely negative), try adding Array.Reverse(buffer) before the ToInt32 call, preferably after a BitConverter.IsLittleEndian check; i.e.

// we now have 4 bytes; update the UI, and reset
if (BitConverter.IsLittleEndian) Array.Reverse(buffer); // fix endianness
int potensio = BitConverter.ToInt32(buffer, 0);

and if that gives the wrong result: reverse it!

// we now have 4 bytes; update the UI, and reset
if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); // fix endianness
int potensio = BitConverter.ToInt32(buffer, 0);
answered on Stack Overflow Feb 15, 2019 by Marc Gravell • edited Feb 15, 2019 by Marc Gravell

User contributions licensed under CC BY-SA 3.0