bool PortWriteNMEA(Port &port, const char *line, OperationEnvironment &env) { assert(line != nullptr); /* reasonable hard-coded timeout; do we need to make this a parameter? */ const unsigned timeout_ms = 1000; if (!port.Write('$') || !port.FullWrite(line, strlen(line), env, timeout_ms)) return false; char checksum[16]; sprintf(checksum, "*%02X\r\n", NMEAChecksum(line)); return port.FullWrite(checksum, strlen(checksum), env, timeout_ms); }
int main(int argc, char **argv) { char buffer[1024]; const char *start = buffer; while ((start = fgets(buffer, sizeof(buffer) - 3, stdin)) != NULL) { const char *end = strchr(start, '*'); if (end == NULL) { end = start + strlen(start); while (end > start && (end[-1] == '\n' || end[-1] == '\r')) --end; } printf("%.*s*%02x\n", (int)(end - buffer), buffer, NMEAChecksum(start, end - start)); } return 0; }
char *GetLine() { const auto src = buffer.Read(); char *const end = src.data + src.length; /* a NMEA line starts with a dollar symbol ... */ char *dollar = std::find(src.data, end, '$'); if (dollar == end) { buffer.Clear(); return nullptr; } char *start = dollar + 1; /* ... and ends with an asterisk */ char *asterisk = std::find(start, end, '*'); if (asterisk + 3 > end) /* need more data */ return nullptr; /* verify the checksum following the asterisk (two hex digits) */ const uint8_t calculated_checksum = NMEAChecksum(start, asterisk - start); const char checksum_buffer[3] = { asterisk[1], asterisk[2], 0 }; char *endptr; const uint8_t parsed_checksum = strtoul(checksum_buffer, &endptr, 16); if (endptr != checksum_buffer + 2 || parsed_checksum != calculated_checksum) { buffer.Clear(); return nullptr; } buffer.Consume(asterisk + 3 - src.data); *asterisk = 0; return start; }
bool NMEAParser::ParseLine(const char *string, NMEAInfo &info) { assert(positive(info.clock)); if (string[0] != '$') return false; if (!NMEAChecksum(string)) return false; NMEAInputLine line(string); char type[16]; line.Read(type, 16); if (IsAlphaASCII(type[1]) && IsAlphaASCII(type[2])) { if (StringIsEqual(type + 3, "GSA")) return GSA(line, info); if (StringIsEqual(type + 3, "GLL")) return GLL(line, info); if (StringIsEqual(type + 3, "RMC")) return RMC(line, info); if (StringIsEqual(type + 3, "GGA")) return GGA(line, info); if (StringIsEqual(type + 3, "HDM")) return HDM(line, info); } // if (proprietary sentence) ... if (type[1] == 'P') { // Airspeed and vario sentence if (StringIsEqual(type + 1, "PTAS1")) return PTAS1(line, info); // FLARM sentences if (StringIsEqual(type + 1, "PFLAE")) { ParsePFLAE(line, info.flarm.error, info.clock); return true; } if (StringIsEqual(type + 1, "PFLAV")) { ParsePFLAV(line, info.flarm.version, info.clock); return true; } if (StringIsEqual(type + 1, "PFLAA")) { ParsePFLAA(line, info.flarm.traffic, info.clock); return true; } if (StringIsEqual(type + 1, "PFLAU")) { ParsePFLAU(line, info.flarm.status, info.clock); return true; } // Garmin altitude sentence if (StringIsEqual(type + 1, "PGRMZ")) return RMZ(line, info); return false; } return false; }