d
Dependencies: BME280 DOGS102 DS1820 MMA845x_timmeh MTS-Serial libmDot_Australia915Mhz mbed-rtos mbed
Fork of mDot_TTN_OTAA_Node by
GPS/GPSPARSER.cpp
- Committer:
- 1994timmeh
- Date:
- 2017-01-11
- Revision:
- 17:55ea4f38710b
File content as of revision 17:55ea4f38710b:
/** * @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); }