2019-09-13 01:00 PM
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 ?
2019-09-13 02:50 PM
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)
2019-09-13 04:05 PM
The strtok function is your friend.
-- pa
2019-09-14 06:04 AM
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.
2019-09-14 07:47 AM
But not a thread-safe one, don't let him drive drunk..
2019-09-14 01:41 PM
Maybe there? https://github.com/MaJerle?tab=repositories
2019-10-26 02:36 AM
#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...
2019-10-27 11:11 AM
Tested, you say? Oh.
uint16_t ok = 0;
while(1)
{
if(RxDATA[ok]=='K')
{
break;
}
ok++;
}
a=0;
while(RxDATA[a]!=',')
{
a++;
}
2019-10-28 12:06 AM
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 :)
2019-10-28 02:18 AM
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++;
}