d

Dependencies:   BME280 DOGS102 DS1820 MMA845x_timmeh MTS-Serial libmDot_Australia915Mhz mbed-rtos mbed

Fork of mDot_TTN_OTAA_Node by Thing Innovations

Revision:
17:55ea4f38710b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GPS/GPSPARSER.cpp	Wed Jan 11 04:12:39 2017 +0000
@@ -0,0 +1,483 @@
+/**
+ * @file    NemaParser.cpp
+ * @brief   NEMA String to Packet Parser - NEMA strings to compact packet data
+ * @author  Tim Barr
+ * @version 1.01
+ * @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.
+ *
+ * 09/16/15 TAB V1.01 Changed report rate of GGA and GSA NEMA sentences
+ * 09/22/15 TAB V1.02 Fixed status value for no GPS detected. Increased report rate
+ *              of GSV, GGA, and GSA NEMA Sentences
+ *
+ * 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),
+      _led_state(0),
+      _tick_running(false)
+{
+    _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 = 1;
+    _num_satellites =0;
+    _gps_detected = false;
+
+    return;
+}
+
+GPSPARSER::~GPSPARSER(void)
+{
+    if (_gps_detected)
+        _getSentenceThread.terminate();
+}
+
+void GPSPARSER::startSentenceThread(void const *p)
+{
+    GPSPARSER *instance = (GPSPARSER*)p;
+    instance->readNemaSentence();
+}
+
+int GPSPARSER::readNemaSentence (void) {
+//    logInfo("===== READING GPS ======\n\r");
+    // 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,GSV every 10 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,0x0A,0x0A,0x0A,0x00,0x01,0x00,0x00,0x00,0x03,0x0D,0x0A};
+    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);
+//    logInfo("GPS starting\r\n");
+
+    _gps_uart->rxClear();
+    _gps_uart->write(init_gps, sizeof(init_gps));
+    
+    while (! _gps_uart->readable()) {
+//        logInfo("GPS UART NOT READABLE\n\r");
+        osDelay(1000);
+    }
+        
+    do {
+        _gps_uart->read(chk_char);
+    } while ((chk_char != 0xA0) && (!_gps_uart->rxEmpty()));
+    
+    if (chk_char == 0xA0) {
+        _gps_uart->read(chk_char);
+//        logInfo("read char %#X\r\n", chk_char);
+        if (chk_char == 0xA1) {
+            _gps_uart->read(chk_char);
+            //logInfo("read char %#X\r\n", chk_char);
+            _gps_uart->read(chk_char);
+            //logInfo("read char %#X\r\n", chk_char);
+            _gps_uart->read(chk_char);
+            //logInfo("read char %#X\r\n", chk_char);
+            if (chk_char == 0x83) {
+                _gps_detected = true;
+            }
+        }
+    }
+
+//    logInfo("GPS detected %s\r\n", _gps_detected ? "true" : "false");
+
+    if (! _gps_detected) {
+        _fix_status = 0;
+        return;
+    }
+
+        if (_gps_uart->readable() > 80) {
+            do {
+                _gps_uart->read(chk_char);
+//                logInfo("read char %#X\r\n", 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());
+                    
+//                    logInfo("STR %s\n", nema_str);
+
+                    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 {
+//                            logInfo("Unknown NEMA String Type\r\n");
+                        }
+                        
+                        return 1;
+                    } else {
+//                        logInfo("NEMA String checksum error %x != %x\r\n",nema_cksum,calc_cksum);
+                        return 0;
+                    }
+                }
+            } else
+//                logInfo("RX empty before all data read\r\n");
+                return 0;
+        }
+        return 0;
+
+//        if (_led) {
+//            if (_fix_status >= 2) {
+//                if (_tick_running) {
+//                    _tick.detach();
+//                    _tick_running = false;
+//                }
+////                _led->setPWM(NCP5623B::LED_3, 8);
+//            } else {
+//                if (! _tick_running) {
+//                    _tick.attach(this, &GPSPARSER::blinker, 0.5);
+//                    _tick_running = true;
+//                }
+//            }
+//        }
+
+}
+
+uint8_t GPSPARSER::parseGGA(char *nema_buf)
+{
+    char* token_str;
+    uint8_t ret = 0;
+
+    _mutex.lock();
+
+    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);
+
+    _mutex.unlock();
+
+    return ret;
+}
+
+uint8_t GPSPARSER::parseGSA(char *nema_buf)
+{
+    char* token_str;
+    uint8_t ret = 0;
+
+    _mutex.lock();
+
+    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);
+    }
+
+    _mutex.unlock();
+
+    return ret;
+}
+
+uint8_t GPSPARSER::parseGSV(char *nema_buf)
+{
+    char* token_str;
+    uint8_t ret = 0;
+
+    _mutex.lock();
+
+    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
+
+    _mutex.unlock();
+
+    return ret;
+}
+
+uint8_t GPSPARSER::parseRMC(char *nema_buf)
+{
+    char* token_str;
+    char temp_str[6];
+    uint8_t ret = 0;
+
+    _mutex.lock();
+
+    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;
+
+    _mutex.unlock();
+
+    return ret;
+}
+
+uint8_t GPSPARSER::parseVTG(char *nema_buf)
+{
+    uint8_t ret = 0;
+    //logInfo("ParseVTG****\r\n");
+    //logInfo(nema_buf);
+    //logInfo("\r\n");
+    return ret;
+}
+
+uint8_t GPSPARSER::parseGLL(char *nema_buf)
+{
+    uint8_t ret = 0;
+    //logInfo("ParseGLL*****\r\n");
+    //logInfo(nema_buf);
+    //logInfo("\r\n");
+    return ret;
+}
+
+uint8_t GPSPARSER::parseZDA(char *nema_buf)
+{
+    uint8_t ret = 0;
+    //logInfo("ParseZDA******\r\n");
+    //logInfo(nema_buf);
+    //logInfo("\r\n");
+    return ret;
+}
+
+bool GPSPARSER::gpsDetected(void)
+{
+    bool detected;
+
+    _mutex.lock();
+    detected =  _gps_detected;
+    _mutex.unlock();
+
+    return detected;
+}
+
+GPSPARSER::longitude GPSPARSER::getLongitude(void)
+{
+    longitude lon;
+
+    _mutex.lock();
+    lon = _gps_longitude;
+    _mutex.unlock();
+
+    return lon;
+}
+
+GPSPARSER::latitude GPSPARSER::getLatitude(void)
+{
+    latitude lat;
+
+    _mutex.lock();
+    lat = _gps_latitude;
+    _mutex.unlock();
+
+    return lat;
+}
+
+struct tm GPSPARSER::getTimestamp(void) {
+    struct tm time;
+
+    _mutex.lock();
+    time = _timestamp;
+    _mutex.unlock();
+
+    return time;
+}
+
+bool GPSPARSER::getLockStatus(void)
+{
+    bool status;
+
+    _mutex.lock();
+    status = _gps_status;
+    _mutex.unlock();
+
+    return status;
+}
+
+uint8_t GPSPARSER::getFixStatus(void)
+{
+    uint8_t fix;
+
+    _mutex.lock();
+    fix = _fix_status;
+    _mutex.unlock();
+
+    return fix;
+}
+
+uint8_t GPSPARSER::getFixQuality(void)
+{
+    uint8_t fix;
+
+    _mutex.lock();
+    fix = _fix_quality;
+    _mutex.unlock();
+
+    return fix;
+}
+
+uint8_t GPSPARSER::getNumSatellites(void)
+{
+    uint8_t sats;
+
+    _mutex.lock();
+    sats = _num_satellites;
+    _mutex.unlock();
+
+    return sats;
+}
+
+int16_t GPSPARSER::getAltitude(void)
+{
+    int16_t alt;
+
+    _mutex.lock();
+    alt = _msl_altitude;
+    _mutex.unlock();
+
+    return alt;
+}
+
+void GPSPARSER::blinker()
+{
+    _led_state = (_led_state == 0) ? 8 : 0;
+//    _led->setPWM(NCP5623B::LED_3, _led_state);
+}
+