/* Instead of just merging input from a secondary device, which is * part of the design of NMEA and which would make life easy, Trimble * wraps messages in a proprietary message PTNLAG001. This handler * just re-serializes the contents of that message and bounces * it back to ArGPS for further parsing. */ void ArTrimbleGPS::handlePTNLAG001(ArNMEAParser::Message m) { ArNMEAParser::MessageVector *message = m.message; if(message->size() < 2) return; std::string text; size_t len = 0; // Undo split by commas, skip msg[0] which is "PTNLAG001" for(ArNMEAParser::MessageVector::const_iterator i = message->begin() + 1; i != message->end(); ++i) { if(i != message->begin()) text += ","; text += *i; len += (*i).length() + 1; } #ifdef DEBUG_ARTRIMBLEGPS printf("XXXXXXXXX Got PTNLAG001 contents from Trimble, %d bytes: %s\n", len, text.c_str()); #endif // Reparse contents. Note, this will clobber NMEA parser state, including // *message, so after calling this we can't do anything else with it. (So // exit the function) text += "\r\n"; len += 2; myNMEAParser.parse(text.c_str(), len); }
void ArNovatelGPS::handleNovatelGPGGA(ArNMEAParser::Message msg) { // call base handler ArGPS::handleGPGGA(msg); // Some of Novatel's values are different from the standard: // (see // http://na1.salesforce.com/_ui/selfservice/pkb/PublicKnowledgeSolution/d?orgId=00D300000000T86&id=501300000008RAN&retURL=%2Fsol%2Fpublic%2Fsolutionbrowser.jsp%3Fsearch%3DGPGGA%26cid%3D000000000000000%26orgId%3D00D300000000T86%26t%3D4&ps=1 or search Novatel's Knowlege Base for "GPGGA") ArNMEAParser::MessageVector *message = msg.message; if(message->size() < 7) return; switch((*message)[6].c_str()[0]) { case '2': myData.fixType = OmnistarConverging; break; case '5': myData.fixType = OmnistarConverged; break; case '9': myData.fixType = DGPSFix; break; } }
int TestArGPS::tests() { puts(""); double degmin = 4248.32544; double deg = gpsDegminToDegrees(degmin); printf("Degrees/minutes combination %f converts to decimal degrees %f.\nChecking against correct value 42.805424...\n", degmin, deg); assert(floatsCloseEnough(deg, 42.805424)); puts("OK"); puts(""); degmin = -4248.32544; deg = gpsDegminToDegrees(degmin); printf("Degrees/minutes combination %f converts to decimal degrees %f.\nChecking against correct value -42.805424... \n", degmin, deg); assert(floatsCloseEnough(deg, -42.805424)); puts("OK"); puts(""); ArNMEAParser::MessageVector msgParts; msgParts.push_back("GPRMC"); msgParts.push_back("1.1"); // timestamp msgParts.push_back("A"); // warning flag msgParts.push_back("4248.32544"); // latitude msgParts.push_back("N"); // lat n/s msgParts.push_back("7234.293016"); // longitude msgParts.push_back("E"); // lon e/w msgParts.push_back("0"); // speed ArNMEAParser::Message msg; msg.message = &msgParts; handleGPRMC(msg); printf("Extracted and converted data from preconstructed GPRMC message with north latitude, east latitude: lat=%f, lon=%f, time.sec=%lu, time.msec=%lu, speed=%f.\nChecking against correct values lat=42.805424 lon=72.571550, time.sec=1, time.mseg=100, speed=0.0...\n", myData.latitude, myData.longitude, myData.GPSPositionTimestamp.getSec(), myData.GPSPositionTimestamp.getMSec(), myData.speed); assert(myData.havePosition); assert(floatsCloseEnough(myData.latitude, 42.805424)); assert(floatsCloseEnough(myData.longitude, 72.571550)); assert(myData.GPSPositionTimestamp.getSec() == 1); assert(myData.GPSPositionTimestamp.getMSec() == 100); assert(floatsCloseEnough(myData.speed, 0.0)); puts("OK"); puts(""); msgParts[4] = "S"; msgParts[6] = "W"; handleGPRMC(msg); printf("Extracted and converted data from preconstructed GPRMC message with south latitude, west longitude: lat=%f, lon=%f, time.sec=%lu, time.msec=%ld, speed=%f.\nChecking against correct values lat=-42.805424 lon=-72.57155...\n", myData.latitude, myData.longitude, myData.GPSPositionTimestamp.getSec(), myData.GPSPositionTimestamp.getMSec(), myData.speed); assert(myData.havePosition); assert(floatsCloseEnough(myData.latitude, -42.805424)); assert(floatsCloseEnough(myData.longitude, -72.57155)); puts("OK"); puts(""); msgParts[6] = "xxx"; msgParts[1] = "2"; handleGPRMC(msg); printf("Extracted and converted data from preconstructed GPRMC message with south latitude, invalid (\"xxx\") longitude, message should have been ignored (timestamp should still show 1/100, not 2.): lat=%f, lon=%f, time.sec=%lu, time.msec=%ld, speed=%f.\nChecking against correct values lat=-42.805424 lon=-72.57155, time.sec!=2...\n", myData.latitude, myData.longitude, myData.GPSPositionTimestamp.getSec(), myData.GPSPositionTimestamp.getMSec(), myData.speed); assert(floatsCloseEnough(myData.latitude, -42.805424)); assert(floatsCloseEnough(myData.longitude, -72.57155)); assert(myData.GPSPositionTimestamp.getSec() != 2); puts("OK"); puts(""); puts("Now testing messages with invalid NMEA format (checksums should be seen as wrong, or messages ignored)."); char *malformedMessage1 = "$GPRMC,11\r\n99,22$33,44*5*6\n" ; // broken halfway through char *malformedMessage2 = "xxx\r\nxxxx\r\n"; // not an nmea message char *malformedMessage3 = "$*01\r\n"; // missing key contents. maybe acepted by ignored? char *malformedMessage4 = "$GPRMC,11,22,33\r\n"; // missing checksum char *malformedMessage5 = "$GPRMC,11,22$GPRMC,99,$GPR33MC88,77*01\r**0\n203\r\n"; // overlapping messages puts("\nMessage 1 of 5..."); myNMEAParser.parse(malformedMessage1, strlen(malformedMessage1)); myNMEAParser.parse("\r\n\r\n", 4); puts("\nMessage 2 of 5..."); myNMEAParser.parse(malformedMessage2, strlen(malformedMessage2)); myNMEAParser.parse("\r\n\r\n", 4); puts("\nMessage 3 of 5..."); myNMEAParser.parse(malformedMessage3, strlen(malformedMessage3)); myNMEAParser.parse("\r\n\r\n", 4); puts("\nMessage 4 of 5..."); myNMEAParser.parse(malformedMessage4, strlen(malformedMessage4)); myNMEAParser.parse("\r\n\r\n", 4); puts("\nMessage 5 of 5..."); myNMEAParser.parse(malformedMessage5, strlen(malformedMessage5)); myNMEAParser.parse("\r\n\r\n", 4); puts(""); char *text = "HCHDM,123.4,M"; char chk = 0; for(unsigned int i = 0; i < strlen(text); ++i) { chk ^= text[i]; } printf("Checking checksum algorithm: Checksum for example message contents \"%s\" is 0x%X (%d). (ought to be 0x2D). Checking...\n", text, chk&0xFF, chk&0xFF); assert(chk == 0x2D); puts("OK"); puts(""); puts("Testing a message with a correct checksum. Should be no checksum warnings."); char *messageWithGoodChecksum = "$HCHDM,123.4,M*2D\r\n"; myNMEAParser.parse(messageWithGoodChecksum, strlen(messageWithGoodChecksum)); puts(""); puts("Testing messages with incorrect checksums. Should see checksum warnings."); char *messageWithBadChecksum = "$HCHDM,123.4,M*23\r\n"; myNMEAParser.parse(messageWithBadChecksum, strlen(messageWithBadChecksum)); myNMEAParser.parse("\r\n\r\n", 4); messageWithBadChecksum = "$HCHDM,123.4,z*2D\r\n"; myNMEAParser.parse(messageWithBadChecksum, strlen(messageWithBadChecksum)); myNMEAParser.parse("\r\n\r\n", 4); puts(""); puts("Done."); return 0; }