extern "C" __declspec(dllexport) int GccReadGps(short &hour, short &min, short &sec, short &msec, // from GPRMC double &latitude, double &longitude, // from GPRMC int &num_sat, double &hdop, double &altitude, // from GPGGA double &geoid_sep, int &max_snr, // from GPGSV double &speed, double &heading, // from GPRMC short &day, short &month, short &year) // from GPRMC { if(__read_lock) { return 0; } const int BUF_SIZE = 4096; DWORD dwBytesRead; char buf[BUF_SIZE+1]; int return_status = 0; FILE *file = NULL; if (logRawNmea) { file = fopen("\\tmp.txt", "a"); fprintf(file, "File handle status: %d\n", (__hGpsPort != INVALID_HANDLE_VALUE ? 1 : 0)); } // reset output vars hour = -1; min = -1; sec = -1; latitude = -32768.0; longitude = -32768.0; num_sat = -1; hdop = -32768.0; altitude = -32768.0; geoid_sep = -32768.0; max_snr = -1; speed = -1.0; heading = -1.0; day = -1; month = -1; year = -1; if(__hGpsPort == INVALID_HANDLE_VALUE) { if (logRawNmea) fclose(file); return return_status; } // read file __read_lock = true; BOOL status = ReadFile(__hGpsPort, // handle of file to read buf, // address of buffer that receives data filemode ? 600 : BUF_SIZE, // number of bytes to read &dwBytesRead, // address of number of bytes read NULL // address of structure for data ); __read_lock = false; if (logRawNmea) fprintf(file, "GPS status: %d, read status: %d, bytes read: %d \n", GccGpsStatus(), (status ? 1 : 0), dwBytesRead); // clear errors if any if(status == false) { DWORD dwErrors; COMSTAT ComStat; ClearCommError(__hGpsPort,&dwErrors,&ComStat); if (logRawNmea) fclose(file); return return_status; } // terminate string buf[dwBytesRead] = '\0'; // nothing read - return if(dwBytesRead == 0) { return_status |= READ_NO_ERRORS; if (logRawNmea) fclose(file); return return_status; } // has some data return_status |= READ_NO_ERRORS; return_status |= READ_HAS_DATA; if(filemode) { char* ptr = strstr(buf+1, "$GPGGA"); if(ptr != NULL) { SetFilePointer(__hGpsPort, (ptr - buf) - dwBytesRead, NULL, FILE_CURRENT); dwBytesRead = ptr - buf; *ptr = '\0'; } } // too much bytes indicate lack of computing power if(dwBytesRead > 600) { //MessageBeep(0); //test if (logRawNmea) fprintf(file, "Warning: Too much Bytes read: %d\n", dwBytesRead); if(dwBytesRead == BUF_SIZE) { PurgeComm(__hGpsPort, PURGE_RXCLEAR); MessageBeep(1); //test } __save_str = std::string(buf); __save_str = __save_str.erase(0, dwBytesRead - 600); //remove old data (would be overwritten anyway) } else { // append to string stored from the last read __save_str += std::string(buf); } // chop into lines std::vector<std::string> lines; std::vector<std::string> words; ChopIntoLines(__save_str, lines); // check what to do with the last segment. If it is not complete - store. if(lines.size() && !filemode) //in filemode would store "----- received 7 lines ----" without CRLF! { std::string &last_line = lines[lines.size()-1]; if(last_line.size() > 3) { if(last_line[last_line.size()-3] != '*') { __save_str = last_line; lines.pop_back(); } } else { __save_str = last_line; lines.pop_back(); } } if (logRawNmea) fprintf(file, "------------ received %d lines ------------ \n", lines.size() ); // parse lines for(unsigned int i = 0; i < lines.size(); i++) { if (logRawNmea) fprintf(file, "%s\n", lines[i].c_str()); // process valid lines only, i.e. the one with correct checksum if(IsLineValid(lines[i])) { ChopIntoCommaSepWords(lines[i], words); if(words.size() == 0) { continue; } if(words[0] == "$GPGSV") { ParseGPGSV(words); gpgsv_trust_count = 10; } else if(words[0] == "$GPGGA") { ParseGPGGA(words); return_status |= READ_HAS_GPGGA; //hour = ___hour; min = ___min; sec = ___sec; //latitude = ___latitude; longitude = ___longitude; hdop = ___hdop; altitude = ___altitude; geoid_sep = ___geoid_sep; } else if(words[0] == "$GPRMC") { ParseGPRMC(words); return_status |= READ_HAS_GPRMC; hour = ___hour; min = ___min; sec = ___sec; msec = ___msec; latitude = ___latitude; longitude = ___longitude; speed = ___speed; heading = ___heading; day = ___day; month = ___month; year = ___year; } } else if (logRawNmea) { fprintf(file, "^invalid line\n"); } } if(gpgsv_trust_count > 0) { max_snr = ___max_snr; num_sat = ___num_sat; //use last values of SNR and NUM to avoid blinking (for 10s) return_status |= READ_HAS_GPGSV; //(some receivers deliver $GPGSV only every 2s or 5s) gpgsv_trust_count--; } if (logRawNmea) fclose(file); /* debug write (if want to dump the read buffer, if line chopping did not work) if(dwBytesRead) { FILE *file = fopen("\\tmp.txt", "a"); fwrite(buf, sizeof(char), dwBytesRead, file); fclose(file); } */ return return_status; }
bool NMEA::Parse(char read) { switch(read) { case '$': //Null the pointers ChecksumIn = false; Checksum = 0; StrChecksum = 0; c = 0; break; default: sentence[c++] = read; if(ChecksumIn) { if(!StrChecksum) StrChecksum = 16 * ((read >= '0' && read <= '9') ? ( read - 48 ) : ( read - 65 + 10 )); else StrChecksum += ((read >= '0' && read <= '9') ? ( read - 48 ) : ( read - 65 + 10 )); } else if(read != ',') Checksum ^= read; break; case '*': sentence[c++] = read; ChecksumIn = true; break; case '\r': sentence[c++] = '\0'; break; case '\n': if(Checksum == StrChecksum) { //Switch on hash value of NMEA sentance name EX GPGGA = 287(P+G+G+A) switch( sentence[1] + sentence[2] + sentence[3] + sentence[4] ) { //TODO: Switch over to ENUMS in future to avoid magic numbers case 287: ParseGPGGA(sentence); break; case 299: ParseGPGSA(sentence); break; case 320: ParseGPGSV(sentence); break; case 306: ParseGPRMC(sentence); break; case 296: //GPRMB Not Implemented; break; default: /*Serial.print("Parse Failed: "); Serial.print(sentence[0]); Serial.print(sentence[1]); Serial.print(sentence[2]); Serial.print(sentence[3]); Serial.print(sentence[4]); Serial.print(sentence[5]); Serial.println( sentence[2] + sentence[3] + sentence[4] + sentence[5] , DEC );*/ break; } } else { //TODO: Report bad checksum here } break; } //VS2008 code - Have to return something in VS2008 return false; }