struct site LoadQTH(char *filename) { /* This function reads SPLAT! .qth (site location) files. The latitude and longitude may be expressed either in decimal degrees, or in degree, minute, second format. Antenna height is assumed to be expressed in feet above ground level (AGL), unless followed by the letter 'M', or 'm', or by the word "meters" or "Meters", in which case meters is assumed, and is handled accordingly. */ int x; char string[50], qthfile[255]; struct site tempsite; FILE *fd=NULL; for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++) qthfile[x]=filename[x]; qthfile[x]='.'; qthfile[x+1]='q'; qthfile[x+2]='t'; qthfile[x+3]='h'; qthfile[x+4]=0; tempsite.lat=91.0; tempsite.lon=361.0; tempsite.name[0]=0; tempsite.azimuth=0.0; fd=fopen(qthfile,"r"); if (fd!=NULL) { /* Site Name */ fgets(string,49,fd); /* Strip <CR> and/or <LF> from end of site name */ for (x=0; string[x]!=13 && string[x]!=10 && string[x]!=0; tempsite.name[x]=string[x], x++); tempsite.name[x]=0; /* Site Latitude */ fgets(string,49,fd); tempsite.lat=ReadBearing(string); /* Site Longitude */ fgets(string,49,fd); tempsite.lon=ReadBearing(string); fclose(fd); } return tempsite; }
/** * Parse HDM NMEA sentence. */ bool NMEAParser::HDM(NMEAInputLine &line, NMEAInfo &info) { /* * $HCHDM,238.5,M*hh/CR/LF * * Field Number: * 1) Magnetic Heading to one decimal place * 2) M (Magnetic) * 3) Checksum */ Angle heading; bool heading_available = ReadBearing(line, heading); if (!heading_available) info.heading_available.Clear(); else if (heading_available) { info.heading = heading; info.heading_available.Update(info.clock); } return true; }
bool NMEAParser::RMC(NMEAInputLine &line, NMEAInfo &info) { /* * $--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a,m,*hh * * Field Number: * 1) UTC Time * 2) Status, V=Navigation receiver warning A=Valid * 3) Latitude * 4) N or S * 5) Longitude * 6) E or W * 7) Speed over ground, knots * 8) Track made good, degrees true * 9) Date, ddmmyy * 10) Magnetic Variation, degrees * 11) E or W * 12) FAA mode indicator (NMEA 2.3 and later) * 13) Checksum */ fixed this_time; if (!ReadTime(line, info.date_time_utc, this_time)) return true; bool gps_valid = !NAVWarn(line.ReadFirstChar()); GeoPoint location; bool valid_location = ReadGeoPoint(line, location); fixed speed; bool ground_speed_available = line.ReadChecked(speed); Angle track; bool track_available = ReadBearing(line, track); // JMW get date info first so TimeModify is accurate ReadDate(line, info.date_time_utc); Angle variation; bool variation_available = ReadVariation(line, variation); if (!TimeHasAdvanced(this_time, info)) return true; if (!gps_valid) info.location_available.Clear(); else if (valid_location) info.location_available.Update(info.clock); if (valid_location) info.location = location; if (ground_speed_available) { info.ground_speed = Units::ToSysUnit(speed, Unit::KNOTS); info.ground_speed_available.Update(info.clock); } if (track_available && info.MovementDetected()) { // JMW don't update bearing unless we're moving info.track = track; info.track_available.Update(info.clock); } if (!variation_available) info.variation_available.Clear(); else if (variation_available) { info.variation = variation; info.variation_available.Update(info.clock); } info.gps.real = real; #if defined(ANDROID) || defined(__APPLE__) info.gps.nonexpiring_internal_gps = false; #endif return true; }
void ParsePFLAA(NMEAInputLine &line, TrafficList &flarm, double clock) { flarm.modified.Update(clock); // PFLAA,<AlarmLevel>,<RelativeNorth>,<RelativeEast>,<RelativeVertical>, // <IDType>,<ID>,<Track>,<TurnRate>,<GroundSpeed>,<ClimbRate>,<AcftType> FlarmTraffic traffic; traffic.alarm_level = (FlarmTraffic::AlarmType) line.Read((int)FlarmTraffic::AlarmType::NONE); double value; bool stealth = false; if (!line.ReadChecked(value)) // Relative North is required ! return; traffic.relative_north = value; if (!line.ReadChecked(value)) // Relative East is required ! return; traffic.relative_east = value; if (!line.ReadChecked(value)) // Relative Altitude is required ! return; traffic.relative_altitude = value; line.Skip(); /* id type */ // 5 id, 6 digit hex char id_string[16]; line.Read(id_string, 16); traffic.id = FlarmId::Parse(id_string, nullptr); Angle track; traffic.track_received = ReadBearing(line, track); if (!traffic.track_received) { // Field is empty in stealth mode stealth = true; traffic.track = Angle::Zero(); } else traffic.track = track; traffic.turn_rate_received = line.ReadChecked(value); if (!traffic.turn_rate_received) { // Field is empty in stealth mode traffic.turn_rate = 0; } else traffic.turn_rate = value; traffic.speed_received = line.ReadChecked(value); if (!traffic.speed_received) { // Field is empty in stealth mode stealth = true; traffic.speed = 0; } else traffic.speed = value; traffic.climb_rate_received = line.ReadChecked(value); if (!traffic.climb_rate_received) { // Field is empty in stealth mode stealth = true; traffic.climb_rate = 0; } else traffic.climb_rate = value; traffic.stealth = stealth; unsigned type = line.Read(0); if (type > 15 || type == 14) traffic.type = FlarmTraffic::AircraftType::UNKNOWN; else traffic.type = (FlarmTraffic::AircraftType)type; FlarmTraffic *flarm_slot = flarm.FindTraffic(traffic.id); if (flarm_slot == nullptr) { flarm_slot = flarm.AllocateTraffic(); if (flarm_slot == nullptr) // no more slots available return; flarm_slot->Clear(); flarm_slot->id = traffic.id; flarm.new_traffic.Update(clock); } // set time of fix to current time flarm_slot->valid.Update(clock); flarm_slot->Update(traffic); }