Search code examples
c#stringwinformsuser-interfaceuart

Why do I keep getting this error: "startIndex cannot be larger than length of string" while communicationg with UART


I am making a GUI to communicate with a UART device. For that, I need to show a part of the string received by UART in a rich text box continuously. String Format is like: "$abc,csd,frvt,v,00000,erty,9,gtyu*" (just for reference). Out of this string, I need to show the data in place of the five zeroes in rtb. I am doing the following in code.

Any help is much appreciated.

    private string receiveddata;
    private string substring;
    int startIndex = 17;
    int length = 5;

    private void serialPort1_DataReceived(object sender, 
            System.IO.Ports.SerialDataReceivedEventArgs e)
    {  
        receiveddata = serialPort1.ReadExisting();     
        substring = receiveddata.Substring(startIndex,length);
        this.Invoke(new EventHandler(displayText));
    }


    private void displayText(object o, EventArgs e)
    {
        richTextBox2.AppendText(receiveddata);
        richTextBox3.AppendText(substring);    
    }

It should write the five zeroes every time into the rtb. It does so the first time but after that, gives the error: "startIndex cannot be larger than length of string"


Solution

  • There are a couple details to keep in mind. Like many people have mentioned the serialport data received event won't necessarily be raised with a complete line of your string everytime. It could be a single character, or even multiple complete lines ("$abc,csd,frvt,v,00000,erty,9,gtyu*$abc,csd,frvt,v,00000,erty,9,gtyu*").

    Your update:

    if (receiveddata.length>startIndex)
    {
      substring = receiveddata.Substring(startIndex,length);
    }
    this.Invoke(new EventHandler(displayText));
    

    Gets a little closer to handling the details, but there are still some issues with it. For example: if receiveddata = "$abc,csd,frvt,v,000", it will try to grab the substring but it won't all be there, causing an exception. Or what if receiveddata = "$abc,csd,frvt,v,00000,erty,9,gtyu*$abc,csd,frvt", now you'll be off next time because the leftover string isn't kept.

    The solution I came up with waits for an entire "line" to be received before parsing it. Then it keeps anything extra to add to the next data we receive.

    private string receiveddata = string.Empty;
    private const int startIndex = 17;  // I had to change this from 16 based on the example string you gave.
    private const int length = 5;
    private const int totalLength = 34;  // The total length of the "line" of text we're expecting ("$abc,csd,frvt,v,00000,erty,9,gtyu*").
    
    
    private void serialPort1_DataReceived(object sender,            
      System.IO.Ports.SerialDataReceivedEventArgs e)
    {
      string receivedThisTime = serialPort1.ReadExisting();
    
      // Update the richTextBox that displays everything received.
      Invoke(new Action(() => displayAllReceivedText(receivedThisTime)));
    
      // Add what was just received to the string we're currently working on.
      receiveddata += receivedThisTime;
    
      // If we've received all of the characters in the complete line:
      // "$abc,csd,frvt,v,00000,erty,9,gtyu*", then we're ready to parse the
      // values we need from it.  This is a while in-case receiveddata contains
      // multiple complete lines - we want to parse them all.
      while (receiveddata.Length >= totalLength)
      {
        // Parse what we need from the string.
        string substring = receiveddata.Substring(startIndex, length);
    
        // Update the richtextbox that shows the parsed values.
        Invoke(new Action(() => displaySubText(substring)));
    
        // Now update our string to contain anything that comes after this
        // complete line.  i.e.
        // if receiveddata = "$abc,csd,frvt,v,00000,erty,9,gtyu*$abc,csd,"
        // it should now   = "$abc,csd,"
        receiveddata = receiveddata.Substring(totalLength);
      }
    }
    
    private void displayAllReceivedText(string text)
    {
      richTextBox2.AppendText(text);
    }
    
    private void displaySubText(string text)
    {
      richTextBox3.AppendText(text);
    }