Search code examples
c++wxwidgets

c++ serial connection


My arduino (this is not an Arduino issue but a general C++ one) is connected to the PC and sends every 2 seconds a counting 3 digit number:

for (long i=100; i <= 999; i++){
  Serial.println(i);
  delay(2000);
}

Connecting via a terminal program to the com port shows that the code does what is intended.

In my C++ application (lets call it client) I am using following code - which runs in an own thread - to pickup the data from the serial connection:

void *MyThread::Entry() {
SerialPort arduino(port_name); // Init serial port
if (arduino.isConnected()){
    wxLogMessage("Message: %s", "Connection Established");
}
else {
        wxLogMessage("Message: %s", "ERROR, check port name");
}
while (arduino.isConnected()){
    int read_result = arduino.readSerialPort(incomingData, MAX_DATA_LENGTH); // Read data
    if (read_result > 2){ // Length of read data
        wxLogMessage("incomingData: %s", incomingData);
    }
}
}

However, this produces an output like the following:

09:02:14: Message: Connection Established
09:02:14: incomingData: 100
09:02:15: incomingData: 
1
09:02:17: incomingData: 01
09:02:18: incomingData: 
10
09:02:20: incomingData: 2

09:02:21: incomingData: 103
09:02:23: incomingData: 
1
09:02:24: incomingData: 04
09:02:26: incomingData: 
10
09:02:27: incomingData: 5

09:02:29: incomingData: 106
09:02:30: incomingData: 
1
09:02:32: incomingData: 07
09:02:33: incomingData: 
10
09:02:35: incomingData: 8

09:02:36: incomingData: 109
09:02:38: incomingData: 
1

So I have always 4 lines with wrong values between two correct lines. I think it's a racing issue. The C++ code is polling the serial connection ways higher than the arduino sends data (every 2 seconds).

As incomingData is

char incomingData[255];

I can't just empty incomingData and test for 3 digits.

So how can I achieve that the client is just getting every full 3 digit value send by the arduino in a correct way? Do I need to implement an own messaging system like enclosing the value send by the arduino with a start and stop sign? Or is there another cheap way I don't see?


Solution

  • As a general rule, you can't "read exactly the length you want" (including newlines and whatever) when using serial commms. There is a possibility that characters go missing, or "noise" gets added.

    It is a much better way to validate the data from the serial input, and using a larger buffer to read into a separate buffer, and return lines (or whatever "packets" you want to return), when they are complete, to the calling code. This will of course get a little more complicated, as you need a second buffer to track what you "haven't yet given to the caller".

    Although, as my comment implies, I think the problem here is that you are reading exactly 3 bytes, and you receive 5 bytes. Your actual messages look like this:

    100<CR><LF>
    101<CR><LF>
    102<CR><LF>
    103<CR><LF>
    

    So the first time, you read 100, then second read gets <CR><LF>1, and then 01<CR>, next gets <LF>10, then 2<CR><LF>, and we're back in sync with 103 again.

    Where <CR> is character 13 (Control-M) and <LF> is character 10 (Control-J)