GPS NEMA String parser library. Only supports SkyTraq Venus chip at this time.

Dependents:   MTDOT-EVB-LinkCheck-AL MTDOT-BOX-EVB-Factory-Firmware-LIB-108 TelitSensorToCloud mDot_sensor_to_cloud ... more

Files at this revision

API Documentation at this revision

Comitter:
falingtrea
Date:
Thu Sep 10 20:03:21 2015 +0000
Child:
1:58c50bb3c60c
Commit message:
Initial release. Only supports SkyTraq Venus GPS chip

Changed in this revision

GPSPARSER.cpp Show annotated file Show diff for this revision Revisions of this file
GPSPARSER.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GPSPARSER.cpp	Thu Sep 10 20:03:21 2015 +0000
@@ -0,0 +1,397 @@
+/**
+ * @file    NemaParser.cpp
+ * @brief   NEMA String to Packet Parser - NEMA strings to compact packet data
+ * @author  Tim Barr
+ * @version 1.0
+ * @see     http://www.kh-gps.de/nmea.faq
+ * @see     http://www.catb.org/gpsd/NMEA.html
+ *
+ * Copyright (c) 2015
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * TODO: Add speed, compass direction, error (DOP) data. Make init more generic
+ */
+
+#include "GPSPARSER.h"
+
+using namespace mts;
+
+GPSPARSER::GPSPARSER(MTSSerial *uart)
+    : _getSentenceThread(&GPSPARSER::startSentenceThread,this)
+{
+    _gps_uart = uart;
+    _gps_uart->baud(9600);    //set GPS baud rate here
+    
+    _gps_latitude.degrees = 0;
+    _gps_longitude.degrees = 0;
+    _timestamp.tm_sec = 0;
+    _timestamp.tm_min = 0;
+    _timestamp.tm_hour = 0;
+    _timestamp.tm_mday = 0;
+    _timestamp.tm_mon = 0;
+    _timestamp.tm_year = 0;
+    _timestamp.tm_wday = 0;
+    _timestamp.tm_yday = 0;
+    _timestamp.tm_isdst = -1; // time is UTC so no Daylight savings time
+ 
+    _gps_status = false;
+    _fix_status = 0;
+    _num_satellites =0;
+    _gps_detected = false;
+
+    if (GPSPARSER::initGps() == 0){
+        _gps_detected = true;
+        _getSentenceThread.signal_set(START_THREAD);
+        printf("Started Nema Sentence Thread\r\n");
+    }
+    else
+        printf("No GPS detected");
+        
+    return;
+}
+
+GPSPARSER::~GPSPARSER(void){
+    if (_gps_detected)
+        _getSentenceThread.terminate();
+}
+
+uint8_t GPSPARSER::initGps (void){
+ 
+    // this code is specific to the Skytraq Venus GPS chip. This code could be re-written to detect another type of
+    // GPS device. Maybe read serial port for a specific time and detect $GP from NEMA string
+ 
+    // Sets Skytraq Venus GPS to output GGA,GSA every 240 seconds, GSV every 30 seconds, and RMC every second, no ZDA,GLL,VTG
+    // setup string for GPS                       GGA  GSA  GSV  GLL  RMC  VTG  ZDA       cksum
+    char init_gps[16] = {0xA0,0xA1,0x00,0x09,0x08,0xF0,0xF0,0x1E,0x00,0x01,0x00,0x00,0x00,0x17,0x0D,0x0A};
+    char chk_char;
+    uint8_t ret = 0;
+
+    _gps_uart->rxClear();
+    printf("Starting initGPS \r\n");
+    
+    _gps_uart->write(init_gps,16);
+    printf("wrote control data\r\n");
+    
+    do {
+        osDelay(10);
+    } while (!_gps_uart->txEmpty());
+    
+    osDelay(15);
+    
+    if (_gps_uart->readable()){
+        do{
+            _gps_uart->read(chk_char,20);
+        } while ((chk_char != 0xA0) && (!_gps_uart->rxEmpty()));
+        
+        printf ("found 0xA0 or rx empty\r\n");
+        
+        if (chk_char == 0xA0){
+            _gps_uart->read(chk_char,15);
+            if (chk_char != 0xA1) {
+                printf( "initGPS  failed no message\r\n");
+                ret = 1;
+            }
+            else {
+                printf("message received\r\n");
+                _gps_uart->read(chk_char);
+                _gps_uart->read(chk_char);
+                printf("message size - %x\r\n",chk_char);
+                _gps_uart->read(chk_char);
+                if (chk_char != 0x83){
+                    printf("initGPS failed not ack message\r\n");
+                    ret = 1;
+                }
+                else {
+                    printf("ACK message received\r\n");
+                    _gps_uart->read(chk_char);
+                    printf("config message acknowledged - ID - %x\r\n",chk_char);
+                }
+            }
+        }
+        else {
+            printf("rx empty \r\n");
+            ret = 1;
+        }
+    }
+    else {
+        printf("No readable characters\r\n");
+        ret = 1;
+    }
+
+    printf("initGps done\r\n");
+    return ret;
+}
+
+void GPSPARSER::startSentenceThread(void const *p){
+   GPSPARSER *instance = (GPSPARSER*)p;
+  instance->readNemaSentence(); 
+}
+
+void GPSPARSER::readNemaSentence (void){
+    char chk_char;
+    uint8_t calc_cksum; 
+    uint8_t nema_cksum;
+    char nema_id[2];
+    char nema_str[80];
+    char cksum_str[2];
+ 
+    _getSentenceThread.signal_wait(START_THREAD);
+    printf("Got thread start\r\n");
+    
+    do {
+        if (_gps_uart->readable() > 80){
+            do{
+                _gps_uart->read(chk_char);
+            } while ((chk_char != '$') && (!_gps_uart->rxEmpty()));
+        
+            if (chk_char == '$') {
+                _gps_uart->read(nema_id,2);
+                if (strpbrk(nema_id,"GP") != NULL){
+                    uint8_t i = 0;
+                    calc_cksum = 0x17;          // 8 bit XOR of G and P checksum seed
+                    nema_cksum = 0;             // initialize nema string checksum
+                    memset(nema_str,0x00,80);   // clear nema_str array
+                    do {
+                        _gps_uart->read(chk_char);
+                        if ((chk_char != 0x0D) && (chk_char != '*')){
+                            nema_str[i++] = chk_char;
+                            calc_cksum ^= chk_char;         // 8 bit XOR checksum
+                        }
+                        if (chk_char == '*') {
+                        _gps_uart->read(cksum_str,2);
+                            nema_cksum = (uint8_t)strtoul(cksum_str,NULL,16);
+                        }
+                    } while (( chk_char != 0x0D) && !_gps_uart->rxEmpty());
+                    
+                    if (nema_cksum == calc_cksum)
+                        if (strncmp (nema_str,"GGA",3) == 0)
+                            parseGGA(nema_str);
+                        else if (strncmp (nema_str,"GSA",3) == 0)
+                                parseGSA(nema_str);
+                            else if (strncmp (nema_str,"GSV",3) == 0)
+                                    parseGSV(nema_str);
+                                else if (strncmp (nema_str,"GLL",3) == 0)
+                                        parseGLL(nema_str);
+                                    else if (strncmp (nema_str,"RMC",3) == 0)
+                                            parseRMC(nema_str);
+                                        else if (strncmp (nema_str,"VTG",3) == 0)
+                                                parseVTG(nema_str);
+                                            else if (strncmp (nema_str,"ZDA",3) == 0)
+                                                    parseZDA(nema_str);
+                                                else
+                                                    printf("Unknown NEMA String Type\r\n");
+                    else
+                        printf("NEMA String checksum error %x != %x\r\n",nema_cksum,calc_cksum);
+                }
+            }
+            else
+                printf("RX empty before all data read\r\n");
+        }
+
+        osDelay(100);
+
+    } while(true);
+
+}
+
+uint8_t GPSPARSER::parseGGA(char *nema_buf){
+    char* token_str;
+    uint8_t ret = 0;
+    
+    token_str = strtok(nema_buf, ",");
+// skip timestamp
+    token_str = strtok(NULL, ",");
+// skip latitude degrees minutes
+    token_str = strtok(NULL, ",");
+    token_str = strtok(NULL, ",");
+// skip longitude degree minutes
+    token_str = strtok(NULL, ",");
+    token_str = strtok(NULL, ",");
+// read fix quality        
+    token_str = strtok(NULL, ",");
+    _fix_quality = atoi(token_str);
+// skip number of satellites and horizontal dilution
+    token_str = strtok(NULL, ",");
+    token_str = strtok(NULL, ",");
+// read msl altitude in meters
+    token_str = strtok(NULL, ",");
+    _msl_altitude = atoi(token_str);
+
+    return ret;
+}
+    
+uint8_t GPSPARSER::parseGSA(char *nema_buf){
+    char* token_str;
+    uint8_t ret = 0;
+    
+    token_str = strtok(nema_buf, ",");
+    token_str = strtok(NULL, ",");
+// read fix status
+    token_str = strtok(NULL, ",");
+    _fix_status = atoi(token_str);
+// read satellite PRNs
+    for (uint8_t i=0;i<12;i++){
+        token_str = strtok(NULL, ",");
+        _satellite_prn[i] = atoi(token_str);
+    }
+    return ret;
+}
+
+uint8_t GPSPARSER::parseGSV(char *nema_buf){
+    char* token_str;
+    uint8_t ret = 0;
+    
+    token_str = strtok(nema_buf, ",");
+// skip number of sentences and sentence number for now
+    token_str = strtok(NULL, ",");
+    token_str = strtok(NULL, ",");
+// read Number of satellites
+    token_str = strtok(NULL, ",");
+    _num_satellites = atoi(token_str);
+// add code to read satellite specs if needed
+
+    return ret;
+}
+
+uint8_t GPSPARSER::parseRMC(char *nema_buf){
+    char* token_str;
+    char temp_str[6];
+    uint8_t ret = 0;
+    
+    token_str = strtok(nema_buf, ",");
+// read timestamp
+    token_str = strtok(NULL, ",");
+    strncpy(temp_str,token_str,2);
+    _timestamp.tm_hour = atoi(temp_str);
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str+2,2);
+    _timestamp.tm_min = atoi(temp_str);
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str+4,2);
+    _timestamp.tm_sec = atoi(temp_str);
+// set gps_status  true = active
+    token_str = strtok(NULL, ",");
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str,1);
+    if (temp_str[0] == 'A')
+        _gps_status = true;
+    else
+        _gps_status = false;
+// read latitude degrees minutes
+    token_str = strtok(NULL, ".");
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str,2);
+    _gps_latitude.degrees = atoi(temp_str);
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str+2,2);
+    _gps_latitude.minutes = atoi(temp_str);
+// read fractional minutes
+    token_str = strtok(NULL, ",");
+    _gps_latitude.seconds = atoi(token_str);
+// read latitude hemisphere change sign if 'S'
+    token_str = strtok(NULL, ",");
+    if (token_str[0] == 'S')
+        _gps_latitude.degrees *= -1;
+// read longitude degree minutes
+    token_str = strtok(NULL, ".");
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str,3);
+    _gps_longitude.degrees = atoi(temp_str);
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str+3,2);
+    _gps_longitude.minutes = atoi(temp_str);
+// read fractional minutes
+    token_str = strtok(NULL, ",");
+    _gps_longitude.seconds = atoi(token_str);
+// read longitude hemisphere change sign if 'W'
+    token_str = strtok(NULL, ",");
+    if (token_str[0] == 'W')
+        _gps_longitude.degrees *= -1;
+// skip speed and track angle
+    token_str = strtok(NULL, ",");
+    token_str = strtok(NULL, ",");
+// read date
+    token_str = strtok(NULL, ",");
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str,2);
+    _timestamp.tm_mday = atoi(temp_str);
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str+2,2);
+    _timestamp.tm_mon = atoi(temp_str) - 1;
+    memset(temp_str,0x00,6);
+    strncpy(temp_str,token_str+4,2);
+    _timestamp.tm_year = atoi(temp_str) + 100;
+
+    return ret;
+}
+
+uint8_t GPSPARSER::parseVTG(char *nema_buf){
+    uint8_t ret = 0;
+    printf("ParseVTG****\r\n");
+    printf(nema_buf);
+    printf("\r\n");
+    return ret;
+}
+
+uint8_t GPSPARSER::parseGLL(char *nema_buf){
+    uint8_t ret = 0;
+    printf("ParseGLL*****\r\n");
+    printf(nema_buf);
+    printf("\r\n");
+    return ret;
+}
+
+uint8_t GPSPARSER::parseZDA(char *nema_buf){
+    uint8_t ret = 0;
+    printf("ParseZDA******\r\n");
+    printf(nema_buf);
+    printf("\r\n");
+    return ret;
+}
+
+bool GPSPARSER::gpsDetected(void){
+    return _gps_detected;
+}
+
+GPSPARSER::longitude GPSPARSER::getLongitude(void){
+    return _gps_longitude;
+}
+
+GPSPARSER::latitude GPSPARSER::getLatitude(void){
+    return _gps_latitude;
+}
+
+struct tm GPSPARSER::getTimestamp(void){
+    return _timestamp;
+}
+
+bool GPSPARSER::getLockStatus(void){
+    return _gps_status;
+}
+
+uint8_t GPSPARSER::getFixStatus(void){
+    return _fix_status;
+}
+
+uint8_t GPSPARSER::getFixQuality(void){
+    return _fix_quality;
+}
+
+uint8_t GPSPARSER::getNumSatellites(void){
+    return _num_satellites;
+}
+
+int16_t GPSPARSER::getAltitude(void){
+    return _msl_altitude;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GPSPARSER.h	Thu Sep 10 20:03:21 2015 +0000
@@ -0,0 +1,204 @@
+/**
+ * @file    GpsParser.h
+ * @brief   NEMA String to Packet Parser - NEMA strings to compact packet data
+ * @author  Tim Barr
+ * @version 1.0
+ * @see     http://www.kh-gps.de/nmea.faq
+ * @see     http://www.catb.org/gpsd/NMEA.html
+ * @see     http://www.skytraq.com.tw/products/Venus638LPx_PB_v3.pdf
+ *
+ * Copyright (c) 2015
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GPSPARSER_H
+#define GPSPARSER_H
+
+#include "mbed.h"
+#include "rtos.h"
+#include "MTSSerial.h"
+#include <string>
+#include <vector>
+#include <ctime>
+#define START_THREAD 1
+
+using namespace mts;
+
+class GPSPARSER
+{
+public:
+
+    /**
+     * @typedef struct latitude
+     * @brief latitude degrees, minutes, seconds structure
+     * range of degrees : 0 to 90 signed (negative degrees is South)
+     * range of minutes : 0 to 60 unsigned
+     * Range of seconds : 0-9999 unsigned or 1/10000 of a minute.
+     * Multiply by 6 and divide or modulus by 1000 to get seconds and fractional seconds
+     */
+    typedef struct{int8_t degrees; uint8_t minutes; uint16_t seconds;} latitude;
+    
+    /**
+     * @typedef struct longitude
+     * @brief longitude degrees, minutes, seconds structure negative degrees is West
+     * range of degrees : 0 to 180 signed (negative degrees is West)
+     * range of minutes : 0 to 60 unsigned
+     * Range of seconds : 0-9999 unsigned or 1/10000 of a minute.
+     * Multiply by 6 and divide or modulus by 1000 to get seconds and fractional seconds
+     */
+    typedef struct{int16_t degrees; uint8_t minutes; uint16_t seconds;} longitude;
+    
+    /**
+     * @typdef satellite_prn
+     * @brief satellite prn list, up to 12 valid
+     */
+    typedef uint8_t satellite_prn[12];
+
+    /** Create the GPSPARSER object
+     *  @param uart - an MTSSerial object
+     */ 
+    GPSPARSER(MTSSerial *uart);
+
+    /** destroy the GPSPARSER object
+     */ 
+    ~GPSPARSER(void);
+    
+    /** GPS device detected
+     *  @return boolean whether GPS device detected
+     */
+    bool gpsDetected(void);
+
+    /** get longitude structure
+     *  @return last valid NEMA string longitude data
+     */
+    longitude getLongitude(void);
+
+    /** get latitude structure
+     *  @return last valid NEMA string latitude data
+     */
+    latitude getLatitude(void);
+
+    /** get timestamp structure
+     *  @return last valid NEMA string time and date data
+     *  uses tm struc from ctime standard library
+     */
+    struct tm getTimestamp(void);
+
+    /** get GPS Lock status
+     *  @return boolean of last valid NEMA string lock status data
+     */
+    bool getLockStatus(void);
+
+    /** get GPS Fix status
+     *  @return last valid NEMA Fix status data
+     *  1 = no fix
+     *  2 = 2D fix - latitude, longitude, time only valid
+     *  3 = 3D fix - all data valid
+     */
+    uint8_t getFixStatus(void);
+
+    /** get GPS Fix qualty
+     *  @return last valid NEMA string Fix Quality data
+     *  0 = invalid
+     *  1 = GPS fix (SPS)
+     *  2 = DGPS fix
+     *  3 = PPS fix
+     *  4 = Real Time Kinematic
+     *  5 = Float RTK
+     *  6 = estimated (dead reckoning) (2.3 feature)
+     *  7 = Manual input mode
+     *  8 = Simulation mode
+     */
+    uint8_t getFixQuality(void);
+
+    /** get number of visible satellites
+     *  @return last valid NEMA string number of satellites visible
+     */
+    uint8_t getNumSatellites(void);
+
+    /** get calculated altitude
+     *  @return last valid NEMA string altitude data in meters 
+     */
+    int16_t getAltitude(void);
+
+private:
+
+    std::string _nema_buff;
+    bool _gps_detected;
+    latitude _gps_latitude;
+    longitude _gps_longitude;
+    struct tm _timestamp;
+    bool _gps_status;
+    uint8_t _fix_status;
+    uint8_t _fix_quality;
+    uint8_t _num_satellites;
+    satellite_prn _satellite_prn;
+    int16_t _msl_altitude;
+    
+    MTSSerial::MTSSerial *_gps_uart;
+    Thread _getSentenceThread;
+    
+    /** Detect and initialize GPS device
+     *  @return status of initialization
+     *  @note rewrite this code for specific GPS device. This code supports Skytraq Venus chip
+     */
+    uint8_t initGps (void);
+    
+    /** Start sentence parser thread
+     *  
+     */
+    static void startSentenceThread (void const *p);
+
+    /** Read NEMA sentences from specified serial port and call specific sentence parser
+     */
+    void readNemaSentence (void);
+
+    /** Parse GGA NEMA sentence
+     *  @return status of parser attempt
+     */
+    uint8_t parseGGA(char *nema_buf);
+
+    /** Parse GSA NEMA sentence
+     *  @return status of parser attempt
+     */
+    uint8_t parseGSA(char *nema_buf);
+
+    /** Parse GSV NEMA sentence
+     *  @return status of parser attempt
+     */
+    uint8_t parseGSV(char *nema_buf);
+
+    /** Parse RMC NEMA sentence
+     *  @return status of parser attempt
+     */
+    uint8_t parseRMC(char *nema_buf);
+
+    /** Parse VTG NEMA sentence
+     *  @return status of parser attempt
+     */
+    uint8_t parseVTG(char *nema_buf);
+
+    /** Parse GLL NEMA sentence
+     *  @return status of parser attempt
+     */
+    uint8_t parseGLL(char *nema_buff);
+
+    /** Parse ZDA NEMA sentence
+     *  @return status of parser attempt
+     */
+    uint8_t parseZDA(char *nema_buff);
+
+};
+#endif
\ No newline at end of file