Problem with understanding STRUCT

Hi,
I am trying to add a STRUCT from a data sheet which is showing the FIX Situation on a GPS.

The Data sheet was too big to attach :wink:

I will attach the code and the data sheet part I am trying to code.
The code I have so far is from two programs I have found on the Internet.
My programming knowledge is minimal but I really need this function in the program.

My Problem is that I do not understand the unsigned, unsigned Long, Long etc.

To see the STRUCT NAV_POSLLH which is K see page 173 in the data sheet.
The STRUCT I am trying to do is page 176. STRUCT NAV_STATUS. This is for seeing if the GPS has a FIX which is the only part I need before I start saving data to the SD Card.
It may be over my head but I think I am very near to my target.

I do realise that I should start with something simple but perhaps someone has the Patience to help. :slight_smile:

Please Help :slight_smile: Best wishes Paul OE8PCK. OAP:

UBLOX_ARDUINO_TEST_FOR_PAUL2.ino (2.93 KB)

Just post the code - don’t make people download it.

#include <SoftwareSerial.h>
 #include <SD.h>
 #include <SPI.h>
 
//  * SD card attached to SPI bus as follows:
// ** MOSI - pin 11
// ** MISO - pin 12
// ** CLK - pin 13
// ** CS - pin 4
// Connect the GPS RX/TX to arduino pins 3 and 5

SoftwareSerial serial = SoftwareSerial(3,5);

const unsigned char UBX_HEADER[] = { 0xB5, 0x62 };
struct NAV_STATUS {
unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  unsigned long gpsFix;
    
};

struct NAV_POSLLH {
  unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  long lon;
  long lat;
  long height;
  long hMSL;
  unsigned long hAcc;
  unsigned long vAcc;
};

NAV_POSLLH posllh;

void calcChecksum(unsigned char* CK) {
  memset(CK, 0, 2);
  for (int i = 0; i < (int)sizeof(NAV_POSLLH); i++) {
    CK[0] += ((unsigned char*)(&posllh))[i];
    CK[1] += CK[0];
  }
}

bool processGPS() {
  static int fpos = 0;
  static unsigned char checksum[2];
  const int payloadSize = sizeof(NAV_POSLLH);

  while ( serial.available() ) {
    byte c = serial.read();
    if ( fpos < 2 ) {
      if ( c == UBX_HEADER[fpos] )
        fpos++;
      else
        fpos = 0;
  
   
    
    }
    else {
      if ( (fpos-2) < payloadSize )
        ((unsigned char*)(&posllh))[fpos-2] = c;

      fpos++;

      if ( fpos == (payloadSize+2) ) {
        calcChecksum(checksum);
      }
      else if ( fpos == (payloadSize+3) ) {
        if ( c != checksum[0] )
          fpos = 0;
      }
      else if ( fpos == (payloadSize+4) ) {
        fpos = 0;
        if ( c == checksum[1] ) {
          return true;
        }
      }
      else if ( fpos > (payloadSize+4) ) {
        fpos = 0;
      }
    }
  }
  return false;
}
int chipSelect = 10;
File mySensorData;


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

  pinMode(10, OUTPUT);
  SD.begin(chipSelect);

  
  
  if (SD.exists("GPSData.txt")){
  SD.remove("GPSData.txt");
  
  }
  
  
  }
  


void loop() {




  
  if ( processGPS() ) {

  mySensorData=SD.open("GPS.txt", FILE_WRITE);
 mySensorData.print(posllh.iTOW);mySensorData.print(",");mySensorData.print(posllh.lat/10000000.0f);mySensorData.print(",");mySensorData.print(posllh.lon/10000000.0f);mySensorData.print(",");mySensorData.print(posllh.height/1000.0f);mySensorData.print(",");mySensorData.print("possllh.hMSL/1000.0f");
 mySensorData.print(",");mySensorData.print("posllh.hAcc/1000.0f");mySensorData.print(",");mySensorData.print("vA/1000.0f");
 
 mySensorData.close();
   
   

    
    Serial.print("iTOW:");      Serial.print(posllh.iTOW);
    Serial.print(" lat/lon: "); Serial.print(posllh.lat/10000000.0f); Serial.print(","); Serial.print(posllh.lon/10000000.0f);
    Serial.print(" height: ");  Serial.print(posllh.height/1000.0f);
    Serial.print(" hMSL: ");    Serial.print(posllh.hMSL/1000.0f);
    Serial.print(" hAcc: ");    Serial.print(posllh.hAcc/1000.0f);
    Serial.print(" vAcc: ");    Serial.print(posllh.vAcc/1000.0f);
    Serial.println();
  }
}

A long is an integer value in the range -2,147,483,648 to 2,147,483,647, and an unsigned long is an integer value in the range 0 to 4,294,967,295

I assume you don't understand the X1 in Nav-Status; as far as I can see they are just bytes.

struct NAV_STATUS {
unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  unsigned long gpsFix;
  
  byte flags;
  byte fixStat;
  byte flags2;
  
  unsigned long ttff;
  unsigned long msss; 
};

You can use them like that and use some logical operations to check if a bit in the byte is set.

NAV_STATUS navstat;

if((navstat & 0x01) == 0x01)
{
}
else
{
   
}

The alternative is to make use of bitfields

struct NAV_STATUS {
unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  unsigned long gpsFix;
  
  byte gpsfixOk: 1;
  byte diffSoln: 1;
  byte wknSet: 1;
  byte towSet: 1;
  byte dummy1: 4;
  
  byte dgpsIStat: 1;
  byte dummy2: 5;
  byte mapMatching: 2;
  
  byte psmState: 2;
  byte dummy3: 6;
  
  unsigned long ttff;
  unsigned long msss; 
};

And you can access the bits directly

NAV_STATUS navstat;

if(navstat.gpsfixOk)
{
}
else
{
}

Read up on C bitfields if you want to use the latter approach.

You should be using the types defined in <stdint.h> (see avr-libc: <stdint.h>: Standard Integer Types ) rather than those defined for the Arduino. Types such as uint8_t, uint16_t, uint32_t etc can be mapped directly to the fields in NAV-STATUS by just using a type that matches in length of those fields in NAV-STATUS.

Hi Sterretje and Stowite, thank you very much for your help. I just don’t have the knowlege yet to try your idea Stowite but I can just about follow your second solution Sterretje. I would like to ask if you think it is necessary to calculate the check sum for NAV_STATUS because I just don’t know how to go about that. What I really want is to check if the gpsFixOk good is like you example 2. I have now added your code and the compile is ok. Could you be so Kind as to look at where I open the SD Card and tell me the best way to only open the Card for writing when the FIX is ok. I am really very grateful for your Kind help.

#include <SoftwareSerial.h>
 #include <SD.h>
 #include <SPI.h>
 
//  * SD card attached to SPI bus as follows:
// ** MOSI - pin 11
// ** MISO - pin 12
// ** CLK - pin 13
// ** CS - pin 4
// Connect the GPS RX/TX to arduino pins 3 and 5

SoftwareSerial serial = SoftwareSerial(3,5);

const unsigned char UBX_HEADER[] = { 0xB5, 0x62 };

struct NAV_STATUS {
unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  unsigned long gpsFix;
  
  byte gpsfixOk: 1;
  byte diffSoln: 1;
  byte wknSet: 1;
  byte towSet: 1;
  byte dummy1: 4;
  
  byte dgpsIStat: 1;
  byte dummy2: 5;
  byte mapMatching: 2;
  
  byte psmState: 2;
  byte dummy3: 6;
  
  unsigned long ttff;
  unsigned long msss; 
};









struct NAV_POSLLH {
  unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  long lon;
  long lat;
  long height;
  long hMSL;
  unsigned long hAcc;
  unsigned long vAcc;
};

NAV_POSLLH posllh;

void calcChecksum(unsigned char* CK) {
  memset(CK, 0, 2);
  for (int i = 0; i < (int)sizeof(NAV_POSLLH); i++) {
    CK[0] += ((unsigned char*)(&posllh))[i];
    CK[1] += CK[0];
  }
}

bool processGPS() {
  static int fpos = 0;
  static unsigned char checksum[2];
  const int payloadSize = sizeof(NAV_POSLLH);

  while ( serial.available() ) {
    byte c = serial.read();
    if ( fpos < 2 ) {
      if ( c == UBX_HEADER[fpos] )
        fpos++;
      else
        fpos = 0;
  
   
    
    }
    else {
      if ( (fpos-2) < payloadSize )
        ((unsigned char*)(&posllh))[fpos-2] = c;

      fpos++;

      if ( fpos == (payloadSize+2) ) {
        calcChecksum(checksum);
      }
      else if ( fpos == (payloadSize+3) ) {
        if ( c != checksum[0] )
          fpos = 0;
      }
      else if ( fpos == (payloadSize+4) ) {
        fpos = 0;
        if ( c == checksum[1] ) {
          return true;
        }
      }
      else if ( fpos > (payloadSize+4) ) {
        fpos = 0;
      }
    }
  }
  return false;
}
int chipSelect = 10;
File mySensorData;


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

  pinMode(10, OUTPUT);
  SD.begin(chipSelect);

  
  
  if (SD.exists("GPSData.txt")){
  SD.remove("GPSData.txt");
  
  }
  
  
  }
  


void loop() {




  
  if ( processGPS() ) {

  mySensorData=SD.open("GPS.txt", FILE_WRITE);
 mySensorData.print(posllh.iTOW);mySensorData.print(",");mySensorData.print(posllh.lat/10000000.0f);mySensorData.print(",");mySensorData.print(posllh.lon/10000000.0f);mySensorData.print(",");mySensorData.print(posllh.height/1000.0f);mySensorData.print(",");mySensorData.print("possllh.hMSL/1000.0f");
 mySensorData.print(",");mySensorData.print("posllh.hAcc/1000.0f");mySensorData.print(",");mySensorData.print("vA/1000.0f");
 
 mySensorData.close();
   
   

    
    Serial.print("iTOW:");      Serial.print(posllh.iTOW);
    Serial.print(" lat/lon: "); Serial.print(posllh.lat/10000000.0f); Serial.print(","); Serial.print(posllh.lon/10000000.0f);
    Serial.print(" height: ");  Serial.print(posllh.height/1000.0f);
    Serial.print(" hMSL: ");    Serial.print(posllh.hMSL/1000.0f);
    Serial.print(" hAcc: ");    Serial.print(posllh.hAcc/1000.0f);
    Serial.print(" vAcc: ");    Serial.print(posllh.vAcc/1000.0f);
    Serial.println();
  }
}

oe8pck: I would like to ask if you think it is necessary to calculate the check sum for NAV_STATUS because I just don't know how to go about that.

It's better to check it as it 'guarantees' that the data is not corrupted. Except for the fact that the data comes from a GPS device, I don't know where that data actually comes from. If it's generated by the device and your communication lines are short it's quite safe to leave it out. If it in some way comes from satellites, I would definitely check it.

oe8pck: Could you be so Kind as to look at where I open the SD Card and tell me the best way to only open the Card for writing when the FIX is ok. I am really very grateful for your Kind help.

I probably will only have time after the weekend; will try to follow up then.

It comes from a GPS RX. As you can see on the dta sheet- The Data strings are of a constant length. NAV-STATUS is 16 Bytes according to the data sheet- Page 176. The link is in my first message. I have tried just copying the previous STRUCT but I get into conflict with the existing Struc in the check sum calculation.

sterretje: If it's generated by the device and your communication lines are short it's quite safe to leave it out.

With Arduinos, a little paranoia is not a bad idea. What I mean is: leave it in.

#include <SoftwareSerial.h>
 #include <SD.h>
 #include <SPI.h>
 
//  * SD card attached to SPI bus as follows:
// ** MOSI - pin 11
// ** MISO - pin 12
// ** CLK - pin 13
// ** CS - pin 4
// Connect the GPS RX/TX to arduino pins 3 and 5

SoftwareSerial serial = SoftwareSerial(3,5);

const unsigned char UBX_HEADER[] = { 0xB5, 0x62 };

struct NAV_STATUS {
unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  unsigned long gpsFix;
  
  byte gpsfixOk: 1;
  byte diffSoln: 1;
  byte wknSet: 1;
  byte towSet: 1;
  byte dummy1: 4;
  
  byte dgpsIStat: 1;
  byte dummy2: 5;
  byte mapMatching: 2;
  
  byte psmState: 2;
  byte dummy3: 6;
  
  unsigned long ttff;
  unsigned long msss; 
};

NAV_STATUS navstat;

void calcChecksum(unsigned char* CK) {
  memset(CK, 0, 2);
  for (int i = 0; i < (int)sizeof(NAV_STATUS); i++) {
    CK[0] += ((unsigned char*)(&navstat))[i];
    CK[1] += CK[0];
  }

}

bool processGPS() {
  static int fpos = 0;
  static unsigned char checksum[2];
  const int payloadSize = sizeof(NAV_STATUS);

  while ( serial.available() ) {
    byte c = serial.read();
    if ( fpos < 2 ) {
      if ( c == UBX_HEADER[fpos] )
        fpos++;
      else
        fpos = 0;
  
   
    
    }
    else {
      if ( (fpos-2) < payloadSize )
        ((unsigned char*)(&posllh))[fpos-2] = c;

      fpos++;

      if ( fpos == (payloadSize+2) ) {
        calcChecksum(checksum);
      }
      else if ( fpos == (payloadSize+3) ) {
        if ( c != checksum[0] )
          fpos = 0;
      }
      else if ( fpos == (payloadSize+4) ) {
        fpos = 0;
        if ( c == checksum[1] ) {
          return true;
        }
      }
      else if ( fpos > (payloadSize+4) ) {
        fpos = 0;
      }
    }
  }
  return false;
}





struct NAV_POSLLH {
  unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  long lon;
  long lat;
  long height;
  long hMSL;
  unsigned long hAcc;
  unsigned long vAcc;
};

NAV_POSLLH posllh;

void calcChecksum(unsigned char* CK) {
  memset(CK, 0, 2);
  for (int i = 0; i < (int)sizeof(NAV_POSLLH); i++) {
    CK[0] += ((unsigned char*)(&posllh))[i];
    CK[1] += CK[0];
  }
}

bool processGPS() {
  static int fpos = 0;
  static unsigned char checksum[2];
  const int payloadSize = sizeof(NAV_POSLLH);

  while ( serial.available() ) {
    byte c = serial.read();
    if ( fpos < 2 ) {
      if ( c == UBX_HEADER[fpos] )
        fpos++;
      else
        fpos = 0;
  
   
    
    }
    else {
      if ( (fpos-2) < payloadSize )
        ((unsigned char*)(&posllh))[fpos-2] = c;

      fpos++;

      if ( fpos == (payloadSize+2) ) {
        calcChecksum(checksum);
      }
      else if ( fpos == (payloadSize+3) ) {
        if ( c != checksum[0] )
          fpos = 0;
      }
      else if ( fpos == (payloadSize+4) ) {
        fpos = 0;
        if ( c == checksum[1] ) {
          return true;
        }
      }
      else if ( fpos > (payloadSize+4) ) {
        fpos = 0;
      }
    }
  }
  return false;
}
int chipSelect = 10;
File mySensorData;


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

  pinMode(10, OUTPUT);
  SD.begin(chipSelect);

  
  
  if (SD.exists("GPSData.txt")){
  SD.remove("GPSData.txt");
  
  }
  
  
  }
  


void loop() {
 

NAV_STATUS navstat;

if((navstat & 0x01) == 0x01)
{
}
else
{
   
}








  
  if ( processGPS() ) {
     

 

  mySensorData=SD.open("GPS.txt", FILE_WRITE);
 mySensorData.print(posllh.iTOW);mySensorData.print(",");mySensorData.print(posllh.lat/10000000.0f);mySensorData.print(",");mySensorData.print(posllh.lon/10000000.0f);mySensorData.print(",");mySensorData.print(posllh.height/1000.0f);mySensorData.print(",");mySensorData.print("possllh.hMSL/1000.0f");
 mySensorData.print(",");mySensorData.print("posllh.hAcc/1000.0f");mySensorData.print(",");mySensorData.print("vA/1000.0f");
 
 mySensorData.close();}
   
 

    
    Serial.print("iTOW:");      Serial.print(posllh.iTOW);
    Serial.print(" lat/lon: "); Serial.print(posllh.lat/10000000.0f); Serial.print(","); Serial.print(posllh.lon/10000000.0f);
    Serial.print(" height: ");  Serial.print(posllh.height/1000.0f);
    Serial.print(" hMSL: ");    Serial.print(posllh.hMSL/1000.0f);
    Serial.print(" hAcc: ");    Serial.print(posllh.hAcc/1000.0f);
    Serial.print(" vAcc: ");    Serial.print(posllh.vAcc/1000.0f);
    Serial.println();
  
}

This is my newest attempt. Getting really frustrated now but not giving up. I just cannot get my head around this STRUCT Business.

A struct is simply a way of organizing data. For example, you could use:

char name[20];
char address[20];
char city[15];
char state[3];
byte age;
byte sex;

and access everything as discrete variables. However, since the data is used to describe a person, you could organize it as a struct:

struct Demographics {
char name[20];
char address[20];
char city[15];
char state[3];
byte age;
byte sex;
};
struct DEMOGRAPHICS myMembers[100];

You assign (or fetch) a member's data using the dot operator (i.e., structure name DOT member name):

   myMembers[0].age = 25;

One advantage of a struct is that you can have an array of *struct*s which allows you to group dissimilar data together, but work with the structure content as individual pieces of data. Because you can group dissimilar data, I refer to structures as "arrays for adults". Finally, structures are like C++ classes, but without the ability to place methods within the structure definition.

econjack: Finally, structures are like C++ classes, but without the ability to place methods within the structure definition.

Really, have you tried/verified this?

A struct is a type of class... with everything being implicitly public. That's it, this is literally the only difference.

I doubt very much that your code compiles :wink: Several functions exist twice and the below does not do what you want it to do

if((navstat & 0x01) == 0x01)
{
}
else
{
   
}

This compares a structure with a number and that does not work. From what I understood from your earlier post, you want to check the gpsfixOk flag in navstat.

if(navstat.gpsfixOk == true)
{
 // it's valid, do whatever
}
else
{
}

Note: don‚Äôt use the name ‚Äėserial‚Äô for your softwareserial. It only differs in the case of one character with ‚ÄėSerial‚Äô; mistakes are made easily so it might be better to use something like ‚Äėswserial‚Äô.

I did work out a solution; the reading of the data works completely different from your way of doing it (I forgot about the casting to byte option). You can have a look at it. It consists of three (five) files (the SWSerialSim files can be deleted, they are used to simulate reading from the GPS). You might have to change the calculation of the checksum.

Extract the zip and double click the ino to open the project in the IDE.

You can ask questions via PM.

gps_ublox.zip (4.78 KB)

@pYro_65: I was just trying to provide him with a hook to understand a structure, since my guess is that the OP is relatively new to C. I added the last statement to provide a little understanding of C++, which helps when using most libraries.

econjack: @pYro_65: I was just trying to provide him with a hook to understand a structure, since my guess is that the OP is relatively new to C.

Yeah, it was a good explanation of how to use a structure, I do not fault that.

I added the last statement to provide a little understanding of C++.

However, that statement does not provide anything towards understanding C++ at all. It is completely wrong, and quite misleading.

@pYro_65:

Finally, structures are like C++ classes...

I was simply providing a way for a beginner to think about a class, and I disagree that it is "completely wrong and quite misleading". How can anything that uses the word "like" be completely wrong in this context? How would you explain to a beginner that what I said was completely wrong?

econjack:
@pYro_65:

I was simply providing a way for a beginner to think about a class, and I disagree that it is ‚Äúcompletely wrong and quite misleading‚ÄĚ. How can anything that uses the word ‚Äúlike‚ÄĚ be completely wrong in this context? How would you explain to a beginner that what I said was completely wrong?

econjack:
Finally, structures are like C++ classes, but without the ability to place methods within the structure definition.

I would say:

Structs are a type of class where all elements are public.

The word ‚Äúlike‚ÄĚ is stating commonality, but implying dissimilarities, which you then stated‚Ķ And is completely wrong.

People, can we keep it on track? Else we end up with N pages of yes / no, this / that etc ;) That will not help OP and each time I see a new reply I end up reading something that I'm not interested in. You can disagree with each other forever using PM :D

sterretje: People, can we keep it on track? Else we end up with N pages of yes / no, this / that etc ;) That will not help OP and each time I see a new reply I end up reading something that I'm not interested in. You can disagree with each other forever using PM :D

Having correct information relevant to what the OP is asking is always beneficial. This is a discussion forum. If you want simple Q 'n A, you might find Stackoverflow more appealing to your expectations...

This the first ti,e I have really used the Forum... I would like to use the personal message but I have looked and cannot work out how to send one... I feel so stupid :-( Can you send me one then I think I know how to answer..... I hope.