Still stuck with communicating to C++ via serial

I am trying to write an application in C++ that will take values from a potentiometer connected to an Arduino Mega. Unfortunately, I can’t make it work with C++ using the VC++2008 Express compiler, though I can make it work with the VC#2008 compiler. For C++, I’m using the CSerial system described on Codeguru.
Eventually, the Arduino will pass data in the form “address value” so that I can use function pointers in C++ to access functions in constant time rather than having to iterate through sequential ifs or a case statement.
First up, is an example of what the C++ is spitting out:

03
0 [ch9568][ch9568][ch9568][ch9568][ch9568][ch9568][ch9568][ch9568][ch9568][ch9568]T

At the same time, both the Arduino Serial Monitor and the C# program were giving a 0 [space] 503 on each new line in the console window.
Here’s the code for the Arduino:

void setup() 
{
  Serial.begin(9600); 
}

void loop() 
{
  int analog = analogRead(0);
  char packet[6];
  if(digitalRead(51)==1)
  {
    sprintf(packet, "closen");
  }
  else
  {
    sprintf(packet, "0 %d",analog);
  }

  Serial.println(packet);
}

The C++ code as it stands now:

int main(const int &)
{
    CSerial serial;
    if (serial.Open(4, 9600))
    {
     cout<<"Opened!"<<endl;
    }
    else
    {
     cout<<"Didn't open <_<"<<endl;
    }
    while(serial.IsOpened())
    {
        char display[6];
        serial.ReadData(display,6);
        cout<<display<<endl;
        cin>>display;
        if(!_strnicmp(display,"end",3))
        {
            serial.Close();
        }
    }
    return 0;
}

And the C# code:

static void Main(string[] args)
        {
            SerialPort port = new SerialPort("COM4", 9600);
            port.Open();
            String s;
            while (port.IsOpen)
            {
                s = port.ReadLine();
                if (s.Equals("closen"))
                {
                    port.Close();
                }
                else
                {
                    Console.WriteLine(s);
                }
            }
        }

Thanks in advance for any help you can provide with this problem!
Matt

This won’t work:

  char packet[6];
  if(digitalRead(51)==1)
  {
    sprintf(packet, "closen");
  }

sprintf is going to put ‘c’, ‘l’, ‘o’, ‘s’, ‘e’, ‘n’, and NULL (that’s 7 values) in an array that can hold 6 characters. Oops.

    while(serial.IsOpened())
    {
        char display[6];
        serial.ReadData(display,6);
        cout<<display<<endl;
        cin>>display;

Opening a serial port does not make data available to read. You need to see if there is data to read before reading it. The 7 values that you send from the Arduino are not going to fit in a 6 character array.

Thanks for the help, I know I come off as a complete annoying noob, but I just can’t seem to get this, and I apologize for the late reply. I’ve updated the code to have the proper capacity and such. I still get bad data when I outright print it. I also took the extra step to use sscanf(…) in the C++ side of things to see if it was just some random junk the computer was interpreting as weird characters, but I didn’t always get the correct numbers, frequently they were truncated and 450 would appear as 45 for example.

while(serial.IsOpened())
      {
            char display[6];
            if(serial.ReadDataWaiting()>5)
            {
                  
                  serial.ReadData(display,6);
                  //cout<<display<<endl;
            }
            if(!_strnicmp(display,"close",3))
            {
                  serial.Close();
            }
            sscanf(display,"%d%d",&address,&value);
            cout<<address<<" "<<value<<endl;
      }
char display[6];

The sender is sending either "closen" or "0 xxxx". Count the number of characters in each string. Add one for the terminating NULL. What number did YOU come up with?

Six. I forgot to mention that I took the n off “closen” so now it is just close plus the null. Also, 0, space, xxx, null is just six characters (my analog input is currently incapable of exceeding a 3 digit value).

Would it be better to create the array size (at both ends) based on the number of bytes I plan to write to it? For instance, if the analog value is just 0 through 9, I’d only need to write 4 characters: 0, space, 1, null so declare the array after checking the value of analog (<10, 100, 1000). And likewise on the computer end, “peek” with ReadDataWaiting() and declare the array based on that size.

Don't you have sufficient memory on the PC to make the array a little larger? Live a little. Make it 24 bytes.

Post your most recent code on both sides.

The C++ Program:

#include "Serial.h"
#include <iostream>
using namespace std;

int main(const int &)
{
      CSerial serial;
      if (serial.Open(4, 9600))
      {
            cout<<"Opened!"<<endl;
      }
      else
      {
            cout<<"Didn't open <_<"<<endl;
      }
      int address = 0;
      int value = 0;
      int count = 0;
      while(serial.IsOpened())
      {
            char display[24];
            if(serial.ReadDataWaiting()>4)
            {
                  
                  serial.ReadData(display,serial.ReadDataWaiting());
                  count++;
                  //cout<<display<<endl;
            }
            if(!_strnicmp(display,"close",3))
            {
                  serial.Close();
            }
            else
            {
                  sscanf(display,"%d%d",&address,&value);
                  cout<<address<<" "<<value<<endl;
            }
      }
      return 0;
}

The Arduino code:

void setup() 
{
  Serial.begin(9600); 
}

void loop() 
{
  int analog = analogRead(0);
  char packet[6];
  if(digitalRead(51)==1)
  {
    sprintf(packet, "close");
  }
  else
  {
    sprintf(packet, "0 %d",analog);
  }

  Serial.println(packet);
}

Currently, the address and value flip flop with each other on the C++ side. If the Arduino is sending “0 306” I’ll get “0 306” for a while, then get “306 0” for a while, and sometimes I’ll get one right after the other, and still sometimes, it’ll truncate the value some instead of 306, it’ll show just 6.
Also, here’s the link to where I got the Serial class from: http://www.codeguru.com/cpp/i-n/network/serialcommunications/article.php/c2503

If you are getting good data from the Arduino, then the issue is with the serial connection loosing bytes, which happens now and then.

You need to add start-of-packet and end-of-packet markers to the packet, and only process the data on the receiver when a complete packet is received.

The Arduino should send something like “<0 306>”, instead of just “0 306”.

To make it even more robust, you could add the length of the string to the data sent, like this “<5:0 306>”. Then, look for the start of packet marker, <, the end of packet marker, >, and parse the string in between to get 5 and “0 306”. Check that the length of the string matches the actual string length. Only parse the string if the length is correct.

If you want to go all the way, add a checksum value to the end of the string, and make sure that matches, too.

Ok, I’m lost completely and quite a bit pissed off frankly. There’s no way to guarantee that all the data will be there apparently, thus there’s no way to even ensure you’ll get the data with C++. Why does this work with C# and not C++? I’m doing nothing differently on the Arduino end (until now) but I get hugely different results that make ZERO sense.
Here’s the code as of now, but I’m beginning to think the Arduino is useless for communicating to anything written in C++ and running on Windows.

while(serial.IsOpened())
      {
            char display[24];
            int length = 1;
            if(serial.ReadDataWaiting()>4)
            {
                  serial.ReadData(display,length = serial.ReadDataWaiting());
            }
            int i = 0;
            for(; i<sizeof(display)/sizeof(char);i++)
            {
                  if(display[i] == '<')
                  {
                        parse = true;
                  }
            }
            int size = 0;
            if(parse)
            {
                  size = display[i]-'0';
                  i +=2;
                  i += sscanf(display+i,"%d%d>",&address,&value);
                  cout<<address<<" "<<value<<endl;
            }
            if(display[i] = '>')
            {
                  parse = false;
            }
            
            if(!_strnicmp(display,"close",5))
            {
                  serial.Close();
            }
      }
analog = analogRead(0);
  if(analog<10)
  {
    size = 1;
  }
  else if(analog<100)
  {
    size = 2;
  }
  else if(analog<1000)
  {
    size = 3;
  }
  size+=2;
  char packet[6];
  if(digitalRead(51)==1)
  {
    sprintf(packet, "close");
  }
  else
  {
    sprintf(packet, "<%d:0 %d>",size,analog);
  }

  Serial.println(packet);

In the C++ application, try just print each character received.

I don’t understand this statement:

            if(serial.ReadDataWaiting()>4)

You are sending packets that contain between 9 and 11 bytes, using the USPS’s terms of service (the only guarantee they provide is that they will make an attempt to deliver the package if it doesn’t get lost somewhere along the way).

Why is the staging of 5 characters significant?

Before trying to parse the data that has arrived, including extracting the size, you need to wait for the end of packet marker that arrives after a start of packet marker.

You need to make sure that the string contains a : before assuming that the first character in the packet is a number.

At the end of this loop, what value will i have?

for(; i<sizeof(display)/sizeof(char);i++)
            {
                  if(display[i] == '<')
                  {
                        parse = true;
                  }
            }

You don’t break out of the loop when display IS ‘<’, so i will point beyond the end of array.
```

  • size = display[i]-‘0’;*
    * _So, size will contain garbage, since display *refers to the first memory location after the array.*_ _*_
    i += sscanf(display+i,"%d%d>",&address,&value);
    *_ _*And, then, you scan even farther past the end of the array.*_ _*
    cout<<address<<" "<<value<<endl;
    ```
    This is the FIRST time you actually try to print anything. When I am debugging, I have a line of code and a cout statement. Sometimes more than one cout statement per line of code.
    Of course, you can go overboard. I had one application that I was debugging that I was sure was working correctly. I put tons of cout statements in to track the bug. It was occurring very early, so I wasn’t getting a lot of output. When I finally found and fixed the bug, and let the program run, it ended up writing more than 40,000,000 lines in the output file.
    Add cout statements. I’m sure that you can get C++ to receive serial data, and to parse it correctly.

Paul, my tone in my last post was completely unacceptable and I was way out of line. I deeply apologize for venting my frustration on the forum like that.
I’ve taken a step back, and decided to try something else. I’m using the Arduino Playground’s example and Everything works except the data is sometimes incomplete.
First, the new C++ code (just mine, the code from the playground is unchanged):

#include<iostream>
#include "SerialClass.h"

using namespace std;

int main(const int &)
{
      Serial ard("COM4");

      while(ard.IsConnected())
      {
            char buffer[10];
            int size, address, data;
            ard.ReadData(buffer,10);
            sscanf(buffer,"<%d:%d %d>",&size,&address,&data);
            cout<<size<<" "<<address<<" "<<data<<endl;
      }
      ard.~Serial();
      return 0;
}

And the Arduino code:

void setup() 
{
  Serial.begin(9600); 
  
}


void loop() 
{
  int analog = analogRead(0);
  int size = 5;
  char packet[10];
  sprintf(packet, "<%d:0 %d>",size,analog);
  Serial.println(packet);
}

Right now, the input Potentiometer is set to give an analog value of 462. For output however, I’ll get “5 0 462” or “5 0 62” or “5 0 42” but always “5 0 [data]” even if the data isn’t correct so we’re getting there. Also, one peculiarity I’ve found is that when I set the buffer on the Arduino side too large, the C++ program will give me the default int value, but I’m not sure that matters a whole lot.
Thanks again so much for all the help and patience you’ve had with me, and again, I apologize for my inappropriate last post.
-Matt

      ard.~Serial();

First off, one should never invoke the destructor directly. you should be using

delete ard;

This invokes the destructor for you, at the appropriate time.

  int analog = analogRead(0);
  int size = 5;
  char packet[10];
  sprintf(packet, "<%d:0 %d>",size,analog);

Your potentiometer can conceivably cause analog read to return a value of 1000 to 1023. If it did, size would need to be 6. This would cause a total of 11 characters to be written to the array.

I know that you’ve said that it won’t happen, but, please, humor me and make the array bigger. Wasting 2 bytes making the array size 12 really won’t kill the Arduino.

Then, use %4d for the last format specifier. This will cause all values written into the string to have 4 characters. Then, size will always be 6, and the string length will always be 11.

Of course, the C++ code will need to change, too.

Also, one peculiarity I’ve found is that when I set the buffer on the Arduino side too large, the C++ program will give me the default int value, but I’m not sure that matters a whole lot.

I’m not sure what you mean by “the default int value”. Please explain.

YES! THANKS PAUL! It works now. Thanks so much for your help and patience. I again apologize for my tone and my noobishness. My next step is to send multiple inputs from the Arduino, so I can't guarantee I'm done, but at least I've got a base to revert back to if I mess something up. As to your last question, it's what I get if I print a non-initialized variable (which I probably should fix) at least on my computer with VC++2008. Thanks again so much!

No problem. Nice to see you persevere.

Make sure you add adequate space for each new value sent, on both sides.

I’m sorry, but I’m still having problems with this silly thing :stuck_out_tongue: Almost comical how much trouble this simple operation is giving me eh? :stuck_out_tongue:
Well any ways, I’m trying it now with multiple inputs and I’m getting truncation again and sometimes the data is getting crossed. For instance, the “pitch” address will be associated with “roll” data and vice versa. It looks like I’m going to need to verify packet integrity on the computer end actually telling it to go through the received data looking for the < and >. Would this be pretty much what you’ve recommended for sending data TO an Arduino (started && ended) or is there some function that can compare the form of a string to see if it’s in form? I’m thinking the former because looking at the raw data, it seems that sometimes, the received data is incomplete and may be something like “<int 12” then the next received data is “3>.” I’ve also noticed that the buffer seems to read 22 bytes at a time and only 22 bytes. As you’ll see in the code, I do a strlen on the buffer itself, and it’s always 21 (plus a null).
The C++:

int main(const int &)
{
      //Serial *ard = new Serial("COM4");
      Serial ard("COM4");
      while(ard.IsConnected())
      {
            char buffer[11];
            int address, data;
            ard.ReadData(buffer,11);

            if(strlen(buffer)>0)
            {
                  sscanf_s(buffer,"<%d %4d>",&address,&data);
                  int size = strlen(buffer);
                  cout<<address<<" "<<data<<" "<<size<<endl;
            }

            //char temp[5];
            //_itoa_s(data,temp,10);
            //cout<<strlen(temp)<<endl;

            sprintf_s(buffer,"");
            //ard.FlushRead();
      }
      //delete ard;
      return 0;
}

The Arduino:

void loop() 
{
  int analog = analogRead(0);
  //int size = 5;
  char pitch[11];
  sprintf(pitch, "<129 %4d>",analog);
  Serial.println(pitch);
  
  int testinput = 18;
  char roll[11];
  sprintf(roll,"<244 %4d>",testinput);
  Serial.println(roll);
  //delay(100);
}

Thanks as always for any help. I’m slowly getting the hang of this asynchronous communication thing I hope.

The Serial class may have several methods for reading data. See if there is a ReadTo method that allows you to define the terminating character. If there is one, use ReadTo to read to the ‘>’.

Otherwise, use ReadData, and concatenate the data it returns onto another array. When that array contains both ‘<’ (started) and ‘>’ (ended), extract the substring from < to >, process the substring, and then remove the substring from the whole string.

Ok, I think I got it working for real this time. So far, I haven’t had any data swapping errors, or truncation errors, but I’ll still be cautiously optimistic for the time being. Thanks again for all the help!

#include<iostream>
#include<fstream>
#include "SerialClass.h"

using namespace std;

int main(const int &)
{
      //Serial *ard = new Serial("COM4");
      Serial ard("COM4");
      int count = 0;
      while(ard.IsConnected())
      {
            char holder[100];
            strset(holder,NULL);
            char buffer[25];
            strset(buffer,NULL);
            int address = 0; 
            int data = 0; 

            ard.ReadData(buffer,25);
            strcat(holder,buffer);
            for(int i = 0; i<100; i++) 
            { 
                  if(holder[i] == '<' && i+9 < 100) 
                  { 
                        if(i+9 < 100 && holder[i+9] == '>') 
                        { 
                              sscanf(holder+i,"<%d %4d>",&address, &data); //extract packet 
                              memset(holder+i,NULL,10);//set found packet to NULL 
                              cout<<address<<" "<<data<<endl;
                        } 
                  } 
                  else if(holder[i] == '<') //if < found near end 
                  { 
                        memcpy(holder,holder+i,strlen(holder+i)); 
                  } 
            }
            sprintf_s(buffer,"");
      }
      return 0;
}