Main Site Documentation

[Urgent Help] Serial data splitting


#1

Hi, really appreciate a quick answer for this one

I am receiving data to send to FEZ mini motors, and I am splitting the incoming data on ‘,’ however occasionally I get 2 & 1/2 values which out grows the array throwing an exception.

much appreciate ideas you have
Dan


#2

Hi Dan:

Without a code sample we can only guess what is happening…

I would guess that you are assuming that each time you do a read you get one value. This would be a wrong assumption with streaming data. You could read one value, a half a value, two values etc. You have to parse the data stream separating the read data into values.


#3

Sorry was supposed to paste in the bottom
(also apologies I have been hacking and slashing since)

the data I am sending is formatted : (double’,‘double’,’)


public static void respond(object sender, SerialDataReceivedEventArgs e)
        {

            String temp = "";
            temp += ReadMessage().ToString();
            string subtemp = "";
            
            if ((temp != null || temp != "0,0,") && temp.Length >= 6)
            {
                subtemp = temp.Substring(0, 6);
                string[] instructionArray = new string[2];

                instructionArray = subtemp.Split(',');


                try
                {

                    Debug.Print("Recieved :" + instructionArray[0] + " " + instructionArray[1]);
                    if (instructionArray[0] == null)
                    {
                        instructionArray[0] = "0";

                    }
                    if (instructionArray[1] == null)
                    {
                        instructionArray[1] = "0";

                    }

                    ActOnInstruction((sbyte)int.Parse(instructionArray[0])(sbyte)int.Parse(instructionArray[1]));
                }
                catch (InvalidOperationException j)
                {
                    Debug.Print(j.ToString());
                    OutputPort led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, true);
                }
            }
        } 

#4

The code that actually does the serial port reading is not included in your code.

As I said, if your data is continually streaming, if is possible that you will receive more than one value in a single read. Add a Debug.Print to your ReadMessage method and see how the data is actually arriving.


#5

you showed parenthesis around your value pairs. Are they actually included in the data? If not, then you will need some way of terminating each value pair. For example,

1,2;22,4;

For pair 1,2 and pair 22,5.


#6

no the parenthesis are not part of the data just to separate them from the text one set is

10,10,

or

10,12,

Ok, so for some reason charBuffer.ToString(); didn’t like being printed out, but after the exception had been thrown I could see the buffer
the output is :

	[0]	44 ','	char
	[1]	49 '1'	char
	[2]	48 '0'	char
	[3]	44 ','	char
	[4]	49 '1'	char
	[5]	48 '0'	char
	[6]	44 ','	char
	[7]	49 '1'	char
	[8]	48 '0'	char
	[9]	44 ','	char
	[10]	0 '\0'	char
	[11]	44 ','	char
	[12]	48 '0'	char
	[13]	44 ','	char
	[14]	48 '0'	char
	[15]	44 ','	char
	[16]	0 '\0'	char
	[17]	0 '\0'	char
	[18]	0 '\0'	char
	[19]	0 '\0'	char
	[20]	0 '\0'	char

and the ‘\0’ continues to [99]

and incase it would help this is my ReadMessage method:


static string ReadMessage()
        {
            if (serialPort.BytesToRead > 0)
            {
                int noAvailable = serialPort.BytesToRead;
                byte[] byteBuffer = new byte[noAvailable];
                

                serialPort.Read(
                    byteBuffer,  // buffer to store the data
                    0,           // start location for data
                    noAvailable);  // number of bytes to read

                decoder.Convert(byteBuffer, 0, noAvailable,
                    charBuffer, 0, BUFFER_SIZE,
                    false, out bytesUsed, out charsUsed, out complete);

                Debug.Print("recieved");

                return new string(charBuffer);
            }
            return "";
        }


#7

you’re relying on getting all the data at once - you can’t make that assumption.

You need to de-queue data that you process and leave the remnants for subsequent processing. So in your scenario you need a higher-level object that contains the string that has been read but is yet un-processed, and use that as the first part of your “temp” string.

Let me also say however, string processing is going to be slower than you expect (and cause GC runs), perhaps you’re better off parsing the byte array? Grab a character from your last processed point, if a number “add” in the new value (you’ll need to handle before a decimal point and after a decimal point scenarios); if a comma or delimiter, move on to next value or next line.


#8

do you mean something like this or am I missing the point ?


        static sbyte[] ReadMessage()
        {
            sbyte[] retrievedMessage = new sbyte[2]{0,0};
            
            if (serialPort.BytesToRead > 0)
            {
                int noAvailable = serialPort.BytesToRead;
                byte[] byteBuffer = new byte[noAvailable];
                

                serialPort.Read(
                    byteBuffer,  // buffer to store the data
                    0,           // start location for data
                    noAvailable);  // number of bytes to read
                
                for (int i = 0; i < noAvailable; i++)
                {
                    if ((int)byteBuffer[i] < 39 && (int)byteBuffer[i] >= 30)
                    {
                        //store digits until ','
                        //add leftover bytes to storage for use on next recurrsion
                    }
                }
            }
            return retrievedMessage;
        }


#9

Well, I guess it’d be worth seeing how you’re expecting to call the methods in question.

But I consider this a consumer/producer problem, and in need of a circular buffer. That’s how I would approach it…

Your producer is just a loop that, when there’s room on the CBuf, it just reads the number of available slots on the buffer, or the available bytes on the serial port, and adds them to the buffer.

You then have a consumer that looks if there’s a full sequence of data on the queue, and if so de-spool it and parse it, and then act on it.


#10

First you are going to have to add a separator between value pairs. You can not make any assumptions that there will be a time delay between value pairs.

And then implement a mechanism as described by Brett.


#11

Sorry for the late reply, could you possibly explain this in the simplest way as if you were speaking to a newbie.

I am trying to send two values to the FEZ mini which will then send them to the motors

as for the separator who knows where that went it was in my actual code.


#12

you need two different seperators; one for separating each pair off values, and one for.separating each set of two values.

1,2;44,54;…

you code then reads bytes until you receive a semi colon. you can then separate the bytes into the two values using the comma.

use a while loop to read one byte at a tme. for now, don’t use an event.

questions?


#13

nope, thank you very much

Super helpful :slight_smile: