How to transmit structure over com port

hi

I have one problem, how to recognise structure sended from arduino decimila board to pc. At the moment i have program, that loges information and these informations are gathered into structure datarecord - temperature, rpm, I, V,status, gps. But how to transmit, recognise these structure in pc software? I would like to get informations in pc software like datarecord.temperature, datarecord.rpm etc.

For pc software i use c++ for decimila i use ordinary Arduino language... The connection between board and pc is with xbee pro.

Thanks in advance

Friendly regards

Denis

Hi Denis and welcome to Arduino forum.

You could develop a function that receives a pointer to the structure and the length of it and use serial.print for each byte at a time.

Something like this:

void SendStructure( char *StructurePointer, int StructureLength)
{
int i;

for (i = 0 ; i < StructureLength ; i++)
serial.print(StructurePointer*, HEX);*
}
Something you should consider is integer and longs bytes swapping (if needed). I don't really know if AVG-GCC in ATmega168/8 uses little indian or big indian format.
Juan C.

Part of the fun is knowing where the structure begins too.

This is probably easiest if you have the arduino listen on the com port for a "getdata" string then spit out the data in response. Then whenever the PC is ready to process another set of values it sends "getdata" to the arduino.

But there are plenty of other schemes as well, like a special set of bytes inserted between sets of data.

I have used Juan's technique successfully, but, as he indicated, there are some things to watch out for:

  1. byte order - make sure the bytes within an int/long are transmitted in the same order the host expects
  2. integer size - make sure the integer sizes match. sizeof(int) on Arduino is 2, but in most PCs it's 4.
  3. padding - some compilers insert dead areas into structures to improve member access
  4. handshaking/synchronization - what happens when your PC receiver doesn't start listening until the middle of your transmission stream?
  5. flow control - (dcb mentioned this) what happens if your PC cannot keep up with the data being transmitted by the Arduino?

Call Juan's function like this:

SendStructure((char *)&MyStruct, sizeof(MyStruct));

Mikal

Oh, and the Arduino processor is little endian, meaning the lowest order addresses contain the least significant data. This means that you should be able receive binary data without byte swapping on most PC architectures, the most notable exception being the PowerPC chip, which is big endian.

Thank you for your time and hepl.

I think it would be looking something like this on transsmition part ?
So i have to let know pc SW (software) how long is the structure, where to begin and end of recieving data? For the redy status of
"getdata" is just another if case needed for arduino to listen from pc.

if (serial.read()="getdata")
{
SendStructure((char *)&MyStruct, sizeof(MyStruct));
};

I am sitting behind a c++ books and studing how to solve that problem. i have not program for ages, so i have to renew my knowledge. Extra comments are welcome.

Ok and here is a program.

void setup();

struct MyStruct // structure of gathered data
{
int rpm[4];
int voltage[4];
int current[4];
int temp1[4];
int temp2[4];
char longitudeGps[8];
char altitudeGps[8];
char latitudeGps[8]
};

void loop()
{
SendStructure((char *)&MyStruct, sizeof(MyStruct)); // calling function SendStructure
};

void SendStructure( char *StructurePointer, int StructureLength) //Function SendStructure
{
int i;

for (i = 0 ; i < StructureLength ; i++) // counting value i and sending data to serial, till it is lower than StructureLength
serial.print(StructurePointer*, HEX);*
}
Question. So if i am not wrong, by calling "SendStructure((char *)&MyStruct, sizeof(MyStruct));" values mirrors into values of function "SendStructure( char *StructurePointer, int StructureLength)" ? As i know (char *)&MyStruct points to the char *StructurePointer and sizeof(MyStruct) points to the int StructureLength?
That is only one part of preparing to send data, what about pc SW to recieve? again writte another structure and mirroring recieved data intoo struct arduinoData = serial.read(), so that i can work with like arduino.temp1 , arduino.voltage,.....
Thank you in advance and success in programing and developing;)

My C isn't the best either, but "if (serial.read()="getdata")" will need some work, you will have to put the read characters into a string then do a strcmp or something on it.

Also you need to wait for that string before each sendstructure, not just in setup.
void loop()
{
WaitForDataRequest(); //
SendStructure(...);
};

And if you dont want to worry about endian, or even possibly difference in the size of an int or all that, just send them as text numbers and atoi them on the pc if you need to do anything other than log them. You have character data in there already from the GPS, and you will be mixing in binary data in non human readable form

//this will make it real easy to troubleshoot using any terminal program and pc platform independent
SendStructure(){
Serial.println(rpm);
Serial.println(voltage);
Serial.println(current);
Serial.println(temp1);
Serial.println(temp2);
Serial.println(longitudeGps); //assuming zero terminated string
Serial.println(altitudeGps);
Serial.println(latitudeGps);
}
}

Putting all the data in a structure and serializing it is a neat trick, but not always the best idea when crossing hardware platforms.

I agree that dcb's solution will be much easier to debug and implement, even though you'll have to do a little parsing on the PC side.

Here's a suggestion: instead of sending the string "getdata" to signal that the PC is ready for data, how about just sending a single byte, like 'd'? Then you could easily write WaitforDataRequest() like this:

void WaitForDataRequest()
{
  while (true)
    if (Serial.available() && Serial.read() == 'd')
      return;
}

Mikal

Here is a program, have to test it and to correct mistakes...

/*
//Name: LogBox 0.1
//Date: 21.09.08 17:19
//Description:
*/

#include <nmea.h>
#include <avr/interrupt.h>
#include <SoftwareSerial.h>
#include <ctype.h>
#include <OneWire.h>

#define GPS_RX 7
#define GPS_TX 8

SoftwareSerial mySerial = SoftwareSerial(GPS_RX, GPS_TX); //configuring software serial ports
NMEA gps(GPRMC);

float GpsLatitude; // definition of strings for GPS data
float GpsLongitude;
float GpsSpeed;

volatile byte rpmcount; // definition of strings for Rpm data
unsigned int rpm;
unsigned long timeold;

OneWire ds(4); // definition of 1wire port for temperatur sensor, pin4

void OneWireData(){

//1Wire temperature
//***********************************************

byte i;
byte present = 0;
byte data[12];
byte addr[8];

ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end

delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.

present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad

Serial.print("P=");
Serial.print(present,HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data = ds.read();
_ Serial.print(data*, HEX);_
_
Serial.print(" ");_
_
}_
_
Serial.print(" CRC=");_
_
Serial.print( OneWire::crc8( data, 8), HEX);_
_
Serial.println();_
_
};_
void WaitForDataRequest()
_
{_
_
while (true)_
_
if (Serial.available() && Serial.read() == 'd')_
_
return;_
_
}_
void rpm_funct()
_
{_
rpm_count++;
_
//Each rotation, this interrupt function is run twice*_
};
void setup()
{
* Serial.begin(34800); //opens serial port, sets data rate*
* mySerial.begin(34800); //opens software serial port, sets data rate*
* pinMode(GPS_RX, INPUT); //definition of pins*
* pinMode(GPS_TX,OUTPUT);
attachInterrupt(0, rpm_funct, RISING);
rpm_count = 0; //values ou rpm part*

* old_time = 0;
_
rpm = 0;_
_
};_
void loop()
_
{_
_
//rpm*_
_ //
* if (rpm_count >= 20)
_
{*

* //Update RPM every 20 counts, increase this for better RPM resolution,*
* //decrease for faster update*
rpm = 301000/(millis() - old_time)rpm_count;
old_time = millis();

* rpm_count = 0;
_
}_
_
//GPS communication*_
_ //

* if (mySerial.available() > 0 )*
* {*
* // read incoming character from GPS*
* char c = mySerial.read();*
* // check if the character completes a valid GPS sentence*
* if (gps.decode(c))*
* {*
* // check if GPS positioning was active*
* if (gps.gprmc_status() == 'A')
_
{*

* GpsLatitude = gps.gprmc_latitude();
GpsLongitude = gps.gprmc_longitude();
GpsSpeed = gps.gprmc_speed(KMPH);
_
}_
_
}_
_
}_
_
//Transmition//_
_ //***********************************************_
_
WaitForDataRequest(); //waiting for answer*_
SendStructure() //Sending data to pc
* {*
* Serial.println(rpm,DEC);*
* Serial.println(GpsLatitude);*
* Serial.println(GpsLongitude);*
* Serial.println(GpsSpeed);*
* OneWireData();*
* }*
}
};
[/quote]

Since you need to repeatedly do stuff, you won't want to wait for the PC to get ready. I'd change WaitForDataRequest() to CheckForDataRequest():

bool CheckForDataRequest()
{
  return Serial.available() && Serial.read() == 'd';
}

Then in your loop do

if (CheckForDataRequest())
  SendStructure();

Savvy?

Mikal