2

I'm receiving periodically some data via Serial Port, in order to plot it and do some more stuff. In order to achive this purpose, I send the data from my microcontroller to my computer with a header, which specifies the length of each packet.

I have the program running and working perfectly except a one last detail. When the header specifies a lenght, my program will not stop until it reachs that amount of bytes. So if, for some reason, some data from one packet is missed, the program wait and take the beginning of the next packet...and then start the real problems. Since that moment, every fails.

I thought about rising a Timer every 0.9 seconds ( the packages come every second) who will give a command in order to comeback to wait and reset variables. But I don't know how to do it, I tried but I obtain errors while running. Since IndCom ( see next code) resets in the midle of some function and errors as "Index out of bounds" arises.

I attach my code ( without timer)

private void routineRx(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        try
        {
            int BytesWaiting;


            do
            {
                BytesWaiting = this.serialPort.BytesToRead;
                //Copy it to the BuffCom
                while (BytesWaiting > 0)
                {
                    BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
                    IndCom = IndCom + 1;
                    BytesWaiting = BytesWaiting - 1;
                }

            } while (IndCom < HeaderLength);
            //I have to read until I got the whole Header which gives the info about the current packet

            PacketLength = getIntInfo(BuffCom,4);

            while (IndCom < PacketLength)
            {
                BytesWaiting = this.serialPort.BytesToRead;
                //Copy it to the BuffCom
                while (BytesWaiting > 0)
                {
                    BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
                    IndCom = IndCom + 1;
                    BytesWaiting = BytesWaiting - 1;
                }
             }

            //If we have a packet--> check if it is valid and, if so, what kind of packet is
            this.Invoke(new EventHandler(checkPacket));
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

    }

I'm new in object-oriented programming and c#, so be clement, please! And thank you very much

Ger
  • 37
  • 1
  • 8
  • ** So if, for some reason, some data from one packet is missed** : You might want to SOLVE the problem, before you start to circumvent it? WHY is the data missing? The µC doesn't send it, or your apps drops it for some reason? – igrimpe Nov 26 '12 at 12:05
  • If I'm true, it's because I'm forcing that situation, sending wrong packets ( more length specified than real). I've never missed one packet or single byte. But this is the first step to implement a GPRS application, and the probability to lose data will increase. I'm testing the program first via Serial Port, but I need a strong program, abled to face this kind of issues – Ger Nov 26 '12 at 12:19

1 Answers1

1

What you might do is use a Stopwatch.

const long COM_TIMEOUT = 500;

Stopwatch spw = new Stopwatch();
spw.Restart();
while (IndCom < PacketLength)
{
    //read byte, do stuff
    if (spw.ElapsedMilliseconds > COM_TIMEOUT) break;  //etc
}

Restart the stopwatch at the beginning and check the time in each while loop, then break out(and clean up) if the timeout hits. 900ms is probably too much, even, if you're only expecting a few bytes. Com traffic is quite fast - if you don't get the whole thing immediately it's probably not coming.

I like to use termination characters in communication protocols (like [CR], etc). This allows you to read until you find the termination character, then stop. This prevents reading into the next command. Even if you don't want to use termination characters, changing your code to something like this :

 while (IndCom < PacketLength)
 {
     if (serialPort.BytesToRead > 0) 
     {
         BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
         IndCom++;             
     }
  }

it allows you to stop when you reach your packet size, leaving any remaining characters in the buffer for the next round through (ie: the next command). You can add the stopwatch timeout in the above also.

The other nice thing about termination characters is that you don't have to know in advance how long the packet should be - you just read until you reach the termination character and then process/parse the whole thing once you've got it. It makes your two-step port read into a one-step port read.

J...
  • 30,968
  • 6
  • 66
  • 143
  • I've tried with the stopwatch and it works ( I had to add that not only a break when the timeelapsed was necessary, also reseting IndCom and other variables), but it works nicely :) Thank you very much J... – Ger Nov 26 '12 at 15:28
  • I am also trying to do the same, have posted a question [here](https://stackoverflow.com/q/55026042/7124761) – Prashant Pimpale Mar 07 '19 at 12:58