Example code for reading from a serial GPS unit & parsing an RMC GPS string to a struct.

Dependencies:   mbed

Fork of mbed_blinky by Mbed

GPRMCSentence.h

Committer:
HackerLabATTKit01
Date:
2017-03-14
Revision:
20:a728f1075fb1
Parent:
19:cbacec32ae4b

File content as of revision 20:a728f1075fb1:

#define TIMEMAX     6
#define LATMAX      20
#define LONGMAX     20
#define SPEEDMAX    6
#define TRACKMAX    6
#define DATEMAX     6
#define MAGVARMAX   6
#define CHECKSUMMAX 10
#define DEVNULMAX   20

#define CRLF2 "\n\r"

/** Tfile provides a means for parsing serially received GPRMC sentences into a location struct **/

typedef struct {
    char time[TIMEMAX+1];
    char status;
    char latitude[LATMAX+1];
    double dlatitude;
    char latdir;
    char longitude[LONGMAX+1];
    double dlongitude;
    char longdir;
    char speed[SPEEDMAX+1];
    char trackangle[TRACKMAX+1];
    char date[DATEMAX+1];
    char magvar[MAGVARMAX+1];
    char magvardir;
    //char checksum[CHECKSUMMAX+1];
} GPRMCSentence;

double charStrToDouble(char* str) {
    uint16_t decpos = 0;
    double num = 0.0;
    while((str[decpos]!='.')&&(str[decpos]!='\0')) decpos++;
    double multiplier = 1.0;
    for(uint16_t i = 1;(decpos-i)>=0;i++) {
        num += (multiplier*(str[decpos-i]-48));
        multiplier *= 10.0;
    }
    multiplier = (1.0/10.0);
    for(uint16_t i = 1;str[decpos+i]!='\0';i++) {
        num += (multiplier*(str[decpos+i]-48));
        multiplier /= 10.0;
    }
    return num;
}

uint16_t parseStringToGPRMCStructEntry(char* gprmcstr, char* gprmcentry, uint16_t start, uint16_t length) {
    int16_t i=0;
    while((gprmcstr[start] != ',')  &&
          (gprmcstr[start] != '\0') &&
          (gprmcstr[start] != '\n') &&
          (i < length)) {
        gprmcentry[i] = gprmcstr[start];
        start++;i++;
    }
    while(i<=length) {
        gprmcentry[i] = '\0';
        i++;
    }
    return start + 1;
}

void moveDecimalLeft(char* num, uint16_t places) {
    if (places == 0) return;
    else places--;
    uint16_t i = 0;
    while(num[i] != '\0') {
        if ((i >= places) && (num[i] == '.')) {
            uint16_t j;
            for(j=i;j>(i-places);j--) num[j] = num[j-1];
            num[j] = num[j-1];
            num[j-1] = '.';
            break;
        }
        else i++;
    }
}

void negateCharStrNumber(char* num, uint16_t len) {
    for(uint16_t i=(len-1); i>0;i--) num[i] = num[i-1];
    num[0] = '-';
}

/************************
parseGPRMCStrToStruct:

In: gprmcstr: raw char array string of gprmc sentence
In: GPRMCSentece: struct object representing gprmc sentence to parse to

Out: integer:    < 0 : not a gprmc sentence
                 = 0 : not valid
                 > 0 : valid

*/
int8_t parseGPRMCStrToStruct(char* gprmcstr, GPRMCSentence* gprmstruct) {
    uint16_t pos = 7;
    char devnull[DEVNULMAX+1];
    if ((gprmcstr[0] == '$') &&
        (gprmcstr[1] == 'G') &&
        (gprmcstr[2] == 'P') &&
        (gprmcstr[3] == 'R') &&
        (gprmcstr[4] == 'M') &&
        (gprmcstr[5] == 'C') &&
        (gprmcstr[6] == ',')) {
        pos = parseStringToGPRMCStructEntry(gprmcstr,gprmstruct->time,pos,TIMEMAX);
        if (gprmcstr[pos] != ',') pos = parseStringToGPRMCStructEntry(gprmcstr,devnull,pos,DEVNULMAX); // to get rid of time decimal, needed for some gps modules
        if (gprmcstr[pos] != ',') {gprmstruct->status = gprmcstr[pos];pos++;}
        else gprmstruct->status = '\0';
        pos++;

        pos = parseStringToGPRMCStructEntry(gprmcstr,gprmstruct->latitude,pos,LATMAX);
        moveDecimalLeft(gprmstruct->latitude,2);
        gprmstruct->dlatitude = charStrToDouble(gprmstruct->latitude);
        if (gprmcstr[pos] != ',') {gprmstruct->latdir = gprmcstr[pos];pos++;}
        else gprmstruct->latdir = '\0';
        if(gprmstruct->latdir == 'S') {
            negateCharStrNumber(gprmstruct->latitude, LATMAX);
            gprmstruct->dlatitude *= -1;
        }
        pos++;

        pos = parseStringToGPRMCStructEntry(gprmcstr,gprmstruct->longitude,pos,LONGMAX);
        moveDecimalLeft(gprmstruct->longitude,2);
        gprmstruct->dlongitude = charStrToDouble(gprmstruct->longitude);
        if (gprmcstr[pos] != ',') {gprmstruct->longdir = gprmcstr[pos];pos++;}
        else gprmstruct->longdir = '\0';
        if(gprmstruct->longdir == 'W') {
            negateCharStrNumber(gprmstruct->longitude, LONGMAX);
            gprmstruct->dlongitude *= -1;
        }
        pos++;

        pos = parseStringToGPRMCStructEntry(gprmcstr,gprmstruct->speed,pos,SPEEDMAX);
        pos = parseStringToGPRMCStructEntry(gprmcstr,gprmstruct->trackangle,pos,TRACKMAX);
        pos = parseStringToGPRMCStructEntry(gprmcstr,gprmstruct->date,pos,DATEMAX);
        pos = parseStringToGPRMCStructEntry(gprmcstr,gprmstruct->magvar,pos,MAGVARMAX);
        if (gprmcstr[pos] != ',') {gprmstruct->magvardir = gprmcstr[pos];pos++;}
        else gprmstruct->magvardir = '\0';
        pos++;
        //pos = parseStringToGPRMCStructEntry(gprmcstr,gprmstruct->checksum,pos,CHECKSUMMAX);
        if (gprmstruct->status == 'A') return 1;
        else return 0;
    }
    else return -1;
}

void printGPRMCSentence(GPRMCSentence* gprmcstruct, Serial *serial) {
    serial->printf("Time:    %s" CRLF2,gprmcstruct->time);
    serial->printf("Status:  %c" CRLF2,gprmcstruct->status);
    serial->printf("Lat:     %s" CRLF2,gprmcstruct->latitude);
    serial->printf("LatDir:  %c" CRLF2,gprmcstruct->latdir);
    serial->printf("Long:    %s" CRLF2,gprmcstruct->longitude);
    serial->printf("LongDir: %c" CRLF2,gprmcstruct->longdir);
    serial->printf("Speed:   %s" CRLF2,gprmcstruct->speed);
    serial->printf("Angle:   %s" CRLF2,gprmcstruct->trackangle);
    serial->printf("Date:    %s" CRLF2,gprmcstruct->date);
    serial->printf("MagVar:  %s" CRLF2,gprmcstruct->magvar);
    serial->printf("MagDir:  %c" CRLF2,gprmcstruct->magvardir);
}