cancel
Showing results for 
Search instead for 
Did you mean: 

Simple way to converting large string to multiple float and int32 variables

Linas L
Senior II

Hello. Never had parcing string experience so maybe it is a simple question.

I will get from GPS module message like this:

+CGNSINF: 1,1,20190913183507.000,54.000000,25.000000,139.107,0.00,87.5,2,,0.6,1.1,0.9,,12,16,,,51,,

I need to extract data in correct order to get information about my location, like coordinates to float32 variable.

+CGNSINF: <GNSS run status>,<Fix status>, <UTC date & Time>,<Latitude>,<Longitude>, 
<MSL Altitude>,<Speed Over Ground>, <Course Over Ground>, <Fix Mode>,<Reserved1>,<HDOP>,<PDOP>, <VDOP>,<Reserved2>,<GNSS Satellites in View>, <GNSS Satellites Used>,<GLONASS Satellites Used>,<Reserved3>,<C/N0 max>,<HPA>,<VPA>

I could do it by brute force by counting comas, copying data between comas to arrays, and then by using sprintf converting it to float values. (bin there, done that, it takes a large program to decode it without any glitches)

But clearly it should be a easy way of doing this ? Could any one know how ?

9 REPLIES 9

Use a compound sscanf()

People usually writing parsers or tokenizers.

For NMEA I usually decompose it into fields, and then use sscanf() or atoi() or atod() type functions to pull out the field values

Don't use 32-bit floats for lat/lot, that will lose precision (7 digits)

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Pavel A.
Evangelist III

The strtok function is your friend.

-- pa

S.Ma
Principal

Trackers seems to be common application, There should be plenty of examples available. Probably qualifies as to become a standard application code example from ST.

But not a thread-safe one, don't let him drive drunk..

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
S.Ma
Principal
Linas L
Senior II
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
 
struct GPS_SIM868
{
  uint8_t       Run_Status;
  uint8_t       Fix_Status;
  char          UTC[18];
  double        Latitude;
  double        Longitude;
  float         Altitude;
  float         Speed;
  float         Course;
  uint8_t       Fix_Mode;
  float         HDOP;
  float         PDOP; 
  float         VDOP;
  uint8_t       GPS_Visible;
  uint8_t       GNSS_Used;
  uint8_t       GLONASS_Visible;
  uint8_t       SNR;
};
 
 
 
void GET_GPS(void)
{
  uint32_t a=0,b=0;
  char string[256]={0};
  char temp[32]={0};
  Reset_DMA();
  USART_puts("AT+CGNSINF\r\n");
  uint16_t ok = 0;
  while(1)
  {
    if(RxDATA[ok]=='K')
    {
      break;
    }
    ok++;
  }
  a=0;
  while(RxDATA[a]!=',')
  {
    a++;
  }
  GPS.Run_Status = (RxDATA[a-1]=='1') ? 1:0;
  GPS.Fix_Status = (RxDATA[a+1]=='1') ? 1:0;
  a++;
  while(RxDATA[a]!=',')
  {
    a++;
  }
  b=0;
  a++;
  while(RxDATA[a]!=',')
  {
    GPS.UTC[b]=RxDATA[a];
    a++;
    b++;
    if(b==18)
    {
      break;
    }
  }
  a++; // Latitude copy
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%lf",&GPS.Latitude);
  a++; // Longtitude copy
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%lf",&GPS.Longitude);
  a++; // Altitude  copy
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%f",&GPS.Altitude );
  a++; // Speed  copy
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%f",&GPS.Speed );
  a++; // Course  copy
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%f",&GPS.Course );
  a++; // Fix Mode  copy
  memset(temp,0,32);
  b=0;
  temp[0]=RxDATA[a];
  sscanf(temp,"%2" SCNu8,&GPS.Fix_Mode);
   a++;
  while(RxDATA[a]!=',')
  {
    a++;
  }
  a++;
  while(RxDATA[a]!=',') //reserved
  {
    a++;
  }
  a++;
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%f",&GPS.HDOP);
  a++;
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%f",&GPS.PDOP);
  a++;
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%f",&GPS.VDOP);
  a++;
  a++;
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%2" SCNu8,&GPS.GPS_Visible);
    a++;
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%2" SCNu8,&GPS.GNSS_Used);
  a++;
  memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%2" SCNu8,&GPS.GLONASS_Visible);
  a++;
    while(RxDATA[a]!=',')
  {
    a++;
  }
  a++;
    memset(temp,0,32);
  b=0;
  while(RxDATA[a]!=',')
  {
    temp[b]=RxDATA[a];
    a++;
    b++;
  }
  sscanf(temp,"%2" SCNu8,&GPS.SNR);
}

Here is complete and tested code. A bit tedious , but what could you do...

Pavel A.
Evangelist III

Tested, you say? Oh.

uint16_t ok = 0;
  while(1)
  {
    if(RxDATA[ok]=='K')
    {
      break;
    }
    ok++;
  }
  a=0;
  while(RxDATA[a]!=',')
  {
    a++;
  }

Nice to see some ones read through my code.

Waiting for response place of this code need to add some kind timeout and also count comas , if they are not in single row, since that means unlocked GPS receiver.

But if all is ok with communication and module, this gives correct response to structure, this part is tested and working.

Note i am using DMA to get info from module. I send message, and reset and clear array, that means all i have to do is to check for response

RxDATA[65536] is exactly 16b in size, thats why i use u16 index, it will allow me to wrap correctly if for some reason i get so much text in DMA buffer. I guess you missed this part, since it was not copied 🙂

Jeroen3
Senior

Like this?

    char in[255] = "1,1,20190913183507.000,54.000000,25.000000,139.107,0.00,87.5,2,,0.6,1.1,0.9,,12,16,,,51,,";
    int limit = sizeof(in)-1; // maximum size of line buffer
    char *stringlist[32];
    char *i = in;
    int count = 0;
 
    memset(stringlist,0,sizeof(stringlist));
    stringlist[count++] = in;
 
    while(*i != '\0' && limit--){
        if(*i == ','){
            stringlist[count++] = i+1;
            *i = '\0';
        }
        i++;
    }
 
 
    float arg;
    int test=0;
    while(stringlist[test] != 0){
        if(sscanf(stringlist[test],"%f",&arg) && *stringlist[test] != '\0'){
            printf("%d:%f\n",test,arg);
        }else{
            printf("%d:no data\n",test);
        }
        test++;
    }