/** * Calculates location, altitude, average climb speed and * looks up the callsign of each target */ void DeviceBlackboard::ProcessFLARM() { const NMEA_INFO &basic = Basic(); FLARM_STATE &flarm = SetBasic().flarm; const FLARM_STATE &last_flarm = LastBasic().flarm; // if (FLARM data is available) if (!flarm.available || flarm.traffic.empty()) return; fixed FLARM_NorthingToLatitude(0); fixed FLARM_EastingToLongitude(0); if (basic.LocationAvailable) { // Precalculate relative east and north projection to lat/lon // for Location calculations of each target Angle delta_lat = Angle::degrees(fixed(0.01)); Angle delta_lon = Angle::degrees(fixed(0.01)); GeoPoint plat = basic.Location; plat.Latitude += delta_lat; GeoPoint plon = basic.Location; plon.Longitude += delta_lon; fixed dlat = Distance(basic.Location, plat); fixed dlon = Distance(basic.Location, plon); if (positive(fabs(dlat)) && positive(fabs(dlon))) { FLARM_NorthingToLatitude = delta_lat.value_degrees() / dlat; FLARM_EastingToLongitude = delta_lon.value_degrees() / dlon; } } // for each item in traffic for (unsigned i = 0; i < flarm.traffic.size(); i++) { FLARM_TRAFFIC &traffic = flarm.traffic[i]; // if we don't know the target's name yet if (!traffic.HasName()) { // lookup the name of this target's id const TCHAR *fname = FlarmDetails::LookupCallsign(traffic.id); if (fname != NULL) traffic.name = fname; } // Calculate distance traffic.distance = hypot(traffic.relative_north, traffic.relative_east); // Calculate Location traffic.location_available = basic.LocationAvailable; if (traffic.location_available) { traffic.location.Latitude = Angle::degrees(traffic.relative_north * FLARM_NorthingToLatitude) + basic.Location.Latitude; traffic.location.Longitude = Angle::degrees(traffic.relative_east * FLARM_EastingToLongitude) + basic.Location.Longitude; } // Calculate absolute altitude traffic.altitude_available = basic.GPSAltitudeAvailable; if (traffic.altitude_available) traffic.altitude = traffic.relative_altitude + basic.GPSAltitude; // Calculate average climb rate traffic.climb_rate_avg30s_available = traffic.altitude_available; if (traffic.climb_rate_avg30s_available) traffic.climb_rate_avg30s = flarmCalculations.Average30s(traffic.id, basic.Time, traffic.altitude); // The following calculations are only relevant for targets // where information is missing if (traffic.track_received || traffic.turn_rate_received || traffic.speed_received || traffic.climb_rate_received) continue; // Check if the target has been seen before in the last seconds const FLARM_TRAFFIC *last_traffic = last_flarm.FindTraffic(traffic.id); if (last_traffic == NULL || !last_traffic->valid) continue; // Calculate the time difference between now and the last contact fixed dt = traffic.valid.GetTimeDifference(last_traffic->valid); if (positive(dt)) { // Calculate the immediate climb rate if (!traffic.climb_rate_received) traffic.climb_rate = (traffic.relative_altitude - last_traffic->relative_altitude) / dt; } else { // Since the time difference is zero (or negative) // we can just copy the old values if (!traffic.climb_rate_received) traffic.climb_rate = last_traffic->climb_rate; } if (positive(dt) && traffic.location_available && last_traffic->location_available) { // Calculate the GeoVector between now and the last contact GeoVector vec = last_traffic->location.distance_bearing(traffic.location); if (!traffic.track_received) traffic.track = vec.Bearing; // Calculate the turn rate if (!traffic.turn_rate_received) traffic.turn_rate = (traffic.track - last_traffic->track).as_delta().value_degrees() / dt; // Calculate the speed [m/s] if (!traffic.speed_received) traffic.speed = vec.Distance / dt; } else { // Since the time difference is zero (or negative) // we can just copy the old values if (!traffic.track_received) traffic.track = last_traffic->track; if (!traffic.turn_rate_received) traffic.turn_rate = last_traffic->turn_rate; if (!traffic.speed_received) traffic.speed = last_traffic->speed; } } }
/** * Parses a PFLAA sentence * (Data on other moving objects around) * @param String Input string * @param params Parameter array * @param nparams Number of parameters * @param GPS_INFO GPS_INFO struct to parse into * @return Parsing success * @see http://flarm.com/support/manual/FLARM_DataportManual_v4.06E.pdf */ bool NMEAParser::PFLAA(NMEAInputLine &line, NMEA_INFO *GPS_INFO) { FLARM_STATE &flarm = GPS_INFO->flarm; isFlarm = true; // calculate relative east and north projection to lat/lon Angle delta_lat = Angle::degrees(fixed(0.01)); Angle delta_lon = Angle::degrees(fixed(0.01)); GeoPoint plat = GPS_INFO->Location; plat.Latitude += delta_lat; GeoPoint plon = GPS_INFO->Location; plon.Longitude += delta_lon; fixed dlat = Distance(GPS_INFO->Location, plat); fixed dlon = Distance(GPS_INFO->Location, plon); fixed FLARM_NorthingToLatitude(0); fixed FLARM_EastingToLongitude(0); if (positive(fabs(dlat)) && positive(fabs(dlon))) { FLARM_NorthingToLatitude = delta_lat.value_degrees() / dlat; FLARM_EastingToLongitude = delta_lon.value_degrees() / dlon; } // PFLAA,<AlarmLevel>,<RelativeNorth>,<RelativeEast>,<RelativeVertical>, // <IDType>,<ID>,<Track>,<TurnRate>,<GroundSpeed>,<ClimbRate>,<AcftType> FLARM_TRAFFIC traffic; traffic.AlarmLevel = line.read(0); traffic.RelativeNorth = line.read(fixed_zero); traffic.RelativeEast = line.read(fixed_zero); traffic.RelativeAltitude = line.read(fixed_zero); traffic.IDType = line.read(0); // 5 id, 6 digit hex char id_string[16]; line.read(id_string, 16); traffic.ID.parse(id_string, NULL); traffic.TrackBearing = Angle::degrees(line.read(fixed_zero)); traffic.TurnRate = line.read(fixed_zero); traffic.Speed = line.read(fixed_zero); traffic.ClimbRate = line.read(fixed_zero); traffic.Type = (FLARM_TRAFFIC::AircraftType)line.read(0); FLARM_TRAFFIC *flarm_slot = flarm.FindTraffic(traffic.ID); if (flarm_slot == NULL) { flarm_slot = flarm.AllocateTraffic(); if (flarm_slot == NULL) // no more slots available return false; flarm_slot->ID = traffic.ID; flarm.NewTraffic = true; InputEvents::processGlideComputer(GCE_FLARM_NEWTRAFFIC); } // set time of fix to current time flarm_slot->Time_Fix = GPS_INFO->Time; // PFLAA,<AlarmLevel>,<RelativeNorth>,<RelativeEast>,<RelativeVertical>, // <IDType>,<ID>,<Track>,<TurnRate>,<GroundSpeed>,<ClimbRate>,<AcftType> flarm_slot->AlarmLevel = traffic.AlarmLevel; flarm_slot->RelativeNorth = traffic.RelativeNorth; flarm_slot->RelativeEast = traffic.RelativeEast; flarm_slot->RelativeAltitude = traffic.RelativeAltitude; flarm_slot->IDType = traffic.IDType; flarm_slot->TrackBearing = traffic.TrackBearing; flarm_slot->TurnRate = traffic.TurnRate; flarm_slot->Speed = traffic.Speed; flarm_slot->ClimbRate = traffic.ClimbRate; flarm_slot->Type = traffic.Type; // 1 relativenorth, meters flarm_slot->Location.Latitude = Angle::degrees(flarm_slot->RelativeNorth * FLARM_NorthingToLatitude) + GPS_INFO->Location.Latitude; // 2 relativeeast, meters flarm_slot->Location.Longitude = Angle::degrees(flarm_slot->RelativeEast * FLARM_EastingToLongitude) + GPS_INFO->Location.Longitude; // alt flarm_slot->Altitude = flarm_slot->RelativeAltitude + GPS_INFO->GPSAltitude; flarm_slot->Average30s = flarmCalculations.Average30s(flarm_slot->ID, GPS_INFO->Time, flarm_slot->Altitude); // QUESTION TB: never returns true?! return false; }
BOOL NMEAParser::PFLAA(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *pGPS) { int flarm_slot = 0; isFlarm = true; // 5 id, 6 digit hex long ID; swscanf(params[5],TEXT("%lx"), &ID); // unsigned long uID = ID; flarm_slot = FLARM_FindSlot(pGPS, ID); if (flarm_slot<0) { // no more slots available, #ifdef DEBUG_LKT StartupStore(_T("... NO SLOTS for Flarm traffic, too many ids!%s"),NEWLINE); #endif return FALSE; } // before changing timefix, see if it was an old target back locked in! CheckBackTarget(pGPS, flarm_slot); // and then set time of fix to current time pGPS->FLARM_Traffic[flarm_slot].Time_Fix = pGPS->Time; TCHAR nString[MAX_NMEA_LEN+1]; unsigned int i, j; for (i=0, j=0; i<_tcslen(String); i++) { // if not a comma, copy and proceed if (String[i] != _T(',')) { nString[j++]=String[i]; continue; } // there was a comma, but the next one is not a comma, so ok.. if (String[i+1] != _T(',') ) { nString[j++]=String[i]; continue; } // We have a bad ,, case that scanf cannot bear with, so we add a 0 nString[j++] = String[i]; nString[j++] = _T('0'); } nString[j]=_T('\0'); //#ifdef DEBUG_LKT //StartupStore(_T("PFLAA: %s%s"),nString,NEWLINE); //#endif _stscanf(nString, TEXT("%hu,%lf,%lf,%lf,%hu,%lx,%lf,%lf,%lf,%lf,%hu"), &pGPS->FLARM_Traffic[flarm_slot].AlarmLevel, // unsigned short 0 &pGPS->FLARM_Traffic[flarm_slot].RelativeNorth, // 1 &pGPS->FLARM_Traffic[flarm_slot].RelativeEast, // 2 &pGPS->FLARM_Traffic[flarm_slot].RelativeAltitude, // 3 &pGPS->FLARM_Traffic[flarm_slot].IDType, // unsigned short 4 &pGPS->FLARM_Traffic[flarm_slot].ID, // 6 char hex &pGPS->FLARM_Traffic[flarm_slot].TrackBearing, // double 6 &pGPS->FLARM_Traffic[flarm_slot].TurnRate, // double 7 &pGPS->FLARM_Traffic[flarm_slot].Speed, // double 8 m/s &pGPS->FLARM_Traffic[flarm_slot].ClimbRate, // double 9 m/s &pGPS->FLARM_Traffic[flarm_slot].Type); // unsigned short 10 // 1 relativenorth, meters pGPS->FLARM_Traffic[flarm_slot].Latitude = pGPS->FLARM_Traffic[flarm_slot].RelativeNorth *FLARM_NorthingToLatitude + pGPS->Latitude; // 2 relativeeast, meters pGPS->FLARM_Traffic[flarm_slot].Longitude = pGPS->FLARM_Traffic[flarm_slot].RelativeEast *FLARM_EastingToLongitude + pGPS->Longitude; // we need to compare with BARO altitude FLARM relative Alt difference! if (pGPS->BaroAltitude>0) // just to be sure pGPS->FLARM_Traffic[flarm_slot].Altitude = pGPS->FLARM_Traffic[flarm_slot].RelativeAltitude + pGPS->BaroAltitude; else pGPS->FLARM_Traffic[flarm_slot].Altitude = pGPS->FLARM_Traffic[flarm_slot].RelativeAltitude + pGPS->Altitude; pGPS->FLARM_Traffic[flarm_slot].Average30s = flarmCalculations.Average30s( pGPS->FLARM_Traffic[flarm_slot].ID, pGPS->Time, pGPS->FLARM_Traffic[flarm_slot].Altitude); TCHAR *name = pGPS->FLARM_Traffic[flarm_slot].Name; //TCHAR *cn = pGPS->FLARM_Traffic[flarm_slot].Cn; // If there is no name yet, or if we have a pending update event.. if (!_tcslen(name) || pGPS->FLARM_Traffic[flarm_slot].UpdateNameFlag ) { #ifdef DEBUG_LKT if (pGPS->FLARM_Traffic[flarm_slot].UpdateNameFlag ) { StartupStore(_T("... UpdateNameFlag for slot %d\n"),flarm_slot); } else { StartupStore(_T("... First lookup name for slot %d\n"),flarm_slot); } #endif pGPS->FLARM_Traffic[flarm_slot].UpdateNameFlag=false; // clear flag first TCHAR *fname = LookupFLARMDetails(pGPS->FLARM_Traffic[flarm_slot].ID); if (fname) { LK_tcsncpy(name,fname,MAXFLARMNAME); // Now we have the name, so lookup also for the Cn // This will return either real Cn or Name, again TCHAR *cname = LookupFLARMCn(pGPS->FLARM_Traffic[flarm_slot].ID); if (cname) { int cnamelen=_tcslen(cname); if (cnamelen<=MAXFLARMCN) { _tcscpy( pGPS->FLARM_Traffic[flarm_slot].Cn, cname); } else { // else probably it is the Name again, and we create a fake Cn pGPS->FLARM_Traffic[flarm_slot].Cn[0]=cname[0]; pGPS->FLARM_Traffic[flarm_slot].Cn[1]=cname[cnamelen-2]; pGPS->FLARM_Traffic[flarm_slot].Cn[2]=cname[cnamelen-1]; pGPS->FLARM_Traffic[flarm_slot].Cn[3]=_T('\0'); } } else { _tcscpy( pGPS->FLARM_Traffic[flarm_slot].Cn, _T("Err")); } #ifdef DEBUG_LKT StartupStore(_T("... PFLAA Name to FlarmSlot=%d ID=%lx Name=<%s> Cn=<%s>\n"), flarm_slot, pGPS->FLARM_Traffic[flarm_slot].ID, pGPS->FLARM_Traffic[flarm_slot].Name, pGPS->FLARM_Traffic[flarm_slot].Cn); #endif } else { // Else we NEED to set a name, otherwise it will constantly search for it over and over.. name[0]=_T('?'); name[1]=_T('\0'); pGPS->FLARM_Traffic[flarm_slot].Cn[0]=_T('?'); pGPS->FLARM_Traffic[flarm_slot].Cn[1]=_T('\0'); #ifdef DEBUG_LKT StartupStore(_T("... New FlarmSlot=%d ID=%lx with no name, assigned a \"?\"\n"), flarm_slot, pGPS->FLARM_Traffic[flarm_slot].ID); #endif } } #ifdef DEBUG_LKT StartupStore(_T("... PFLAA pGPS slot=%d ID=%lx name=<%s> cn=<%s> rAlt=%.0f Track=%.0f Speed=%.0f Climb=%.1f Baro=%f FlAlt=%f\n"), flarm_slot, pGPS->FLARM_Traffic[flarm_slot].ID, pGPS->FLARM_Traffic[flarm_slot].Name, pGPS->FLARM_Traffic[flarm_slot].Cn, pGPS->FLARM_Traffic[flarm_slot].RelativeAltitude, pGPS->FLARM_Traffic[flarm_slot].TrackBearing, pGPS->FLARM_Traffic[flarm_slot].Speed, pGPS->FLARM_Traffic[flarm_slot].ClimbRate, pGPS->BaroAltitude, pGPS->FLARM_Traffic[flarm_slot].Altitude); #endif // update Virtual Waypoint for target FLARM if (flarm_slot == LKTargetIndex) { WayPointList[RESWP_FLARMTARGET].Latitude = pGPS->FLARM_Traffic[LKTargetIndex].Latitude; WayPointList[RESWP_FLARMTARGET].Longitude = pGPS->FLARM_Traffic[LKTargetIndex].Longitude; WayPointList[RESWP_FLARMTARGET].Altitude = pGPS->FLARM_Traffic[LKTargetIndex].Altitude; } return FALSE; }
// // The purpose of simulating flarm traffic is NOT to play a videogame against flarm objects: // we only need some traffic to display for testing on ground during simulations. // // >>>>> This is accessing directly the GPS_INFO main struct, writing inside it. <<<<< // Called by LKSimulator, already locking FlightData . No worry. // void SimFlarmTraffic(long ID, double offset) { int flarm_slot = 0; bool newtraffic=false; GPS_INFO.FLARM_Available=true; LastFlarmCommandTime=GPS_INFO.Time; // useless really, we dont call UpdateMonitor from SIM flarm_slot = FLARM_FindSlot(&GPS_INFO, ID); if (flarm_slot<0) return; if ( GPS_INFO.FLARM_Traffic[flarm_slot].Status == LKT_EMPTY) { newtraffic=true; } // before changing timefix, see if it was an old target back locked in! CheckBackTarget(&GPS_INFO, flarm_slot); // and then set time of fix to current time GPS_INFO.FLARM_Traffic[flarm_slot].Time_Fix = GPS_INFO.Time; /* TEXT("%hu,%lf,%lf,%lf,%hu,%lx,%lf,%lf,%lf,%lf,%hu"), &GPS_INFO.FLARM_Traffic[flarm_slot].AlarmLevel, // unsigned short 0 &GPS_INFO.FLARM_Traffic[flarm_slot].RelativeNorth, // 1 &GPS_INFO.FLARM_Traffic[flarm_slot].RelativeEast, // 2 &GPS_INFO.FLARM_Traffic[flarm_slot].RelativeAltitude, // 3 &GPS_INFO.FLARM_Traffic[flarm_slot].IDType, // unsigned short 4 &GPS_INFO.FLARM_Traffic[flarm_slot].ID, // 6 char hex &GPS_INFO.FLARM_Traffic[flarm_slot].TrackBearing, // double 6 &GPS_INFO.FLARM_Traffic[flarm_slot].TurnRate, // double 7 &GPS_INFO.FLARM_Traffic[flarm_slot].Speed, // double 8 m/s &GPS_INFO.FLARM_Traffic[flarm_slot].ClimbRate, // double 9 m/s &GPS_INFO.FLARM_Traffic[flarm_slot].Type); // unsigned short 10 */ // If first time seen this traffic, place it nearby if ( newtraffic ) { GPS_INFO.FLARM_Traffic[flarm_slot].RelativeNorth=2; GPS_INFO.FLARM_Traffic[flarm_slot].RelativeEast=2; GPS_INFO.FLARM_Traffic[flarm_slot].Latitude = SimNewCoordinate(GPS_INFO.Latitude, offset); GPS_INFO.FLARM_Traffic[flarm_slot].Longitude = SimNewCoordinate(GPS_INFO.Longitude,offset); GPS_INFO.FLARM_Traffic[flarm_slot].Altitude = SimNewAltitude(GPS_INFO.Altitude); GPS_INFO.FLARM_Traffic[flarm_slot].TrackBearing= (double) rand()/91.276; GPS_INFO.FLARM_Traffic[flarm_slot].AlarmLevel=0; GPS_INFO.FLARM_Traffic[flarm_slot].ID=ID; GPS_INFO.FLARM_Traffic[flarm_slot].TurnRate=0; GPS_INFO.FLARM_Traffic[flarm_slot].Speed= SimNewSpeed(GPS_INFO.Speed); GPS_INFO.FLARM_Traffic[flarm_slot].Status = LKT_REAL; } else { GPS_INFO.FLARM_Traffic[flarm_slot].Latitude += (double)(rand()/20000000.0)*(rand()>15000?1:-1); GPS_INFO.FLARM_Traffic[flarm_slot].Longitude += (double)(rand()/20000000.0)*(rand()>15000?1:-1); GPS_INFO.FLARM_Traffic[flarm_slot].Altitude += (double)(rand()/2200.0)*(rand()>15000?1:-1); } GPS_INFO.FLARM_Traffic[flarm_slot].RelativeAltitude = GPS_INFO.FLARM_Traffic[flarm_slot].Altitude - GPS_INFO.Altitude; // GPS_INFO.FLARM_Traffic[flarm_slot].Average30s = flarmCalculations.Average30s( GPS_INFO.FLARM_Traffic[flarm_slot].ID, GPS_INFO.Time, GPS_INFO.FLARM_Traffic[flarm_slot].Altitude); TCHAR *name = GPS_INFO.FLARM_Traffic[flarm_slot].Name; //TCHAR *cn = GPS_INFO.FLARM_Traffic[flarm_slot].Cn; // If there is no name yet, or if we have a pending update event.. if (!_tcslen(name) || GPS_INFO.FLARM_Traffic[flarm_slot].UpdateNameFlag ) { #ifdef DEBUG_SIMLKT if (GPS_INFO.FLARM_Traffic[flarm_slot].UpdateNameFlag ) { StartupStore(_T("... UpdateNameFlag for slot %d\n"),flarm_slot); } else { StartupStore(_T("... First lookup name for slot %d\n"),flarm_slot); } #endif GPS_INFO.FLARM_Traffic[flarm_slot].UpdateNameFlag=false; // clear flag first TCHAR *fname = LookupFLARMDetails(GPS_INFO.FLARM_Traffic[flarm_slot].ID); if (fname) { LK_tcsncpy(name,fname,MAXFLARMNAME); // Now we have the name, so lookup also for the Cn // This will return either real Cn or Name, again TCHAR *cname = LookupFLARMCn(GPS_INFO.FLARM_Traffic[flarm_slot].ID); if (cname) { int cnamelen=_tcslen(cname); if (cnamelen<=MAXFLARMCN) { _tcscpy( GPS_INFO.FLARM_Traffic[flarm_slot].Cn, cname); } else { // else probably it is the Name again, and we create a fake Cn GPS_INFO.FLARM_Traffic[flarm_slot].Cn[0]=cname[0]; GPS_INFO.FLARM_Traffic[flarm_slot].Cn[1]=cname[cnamelen-2]; GPS_INFO.FLARM_Traffic[flarm_slot].Cn[2]=cname[cnamelen-1]; GPS_INFO.FLARM_Traffic[flarm_slot].Cn[3]=_T('\0'); } } else { _tcscpy( GPS_INFO.FLARM_Traffic[flarm_slot].Cn, _T("Err")); } #ifdef DEBUG_SIMLKT StartupStore(_T("... PFLAA Name to FlarmSlot=%d ID=%lx Name=<%s> Cn=<%s>\n"), flarm_slot, GPS_INFO.FLARM_Traffic[flarm_slot].ID, GPS_INFO.FLARM_Traffic[flarm_slot].Name, GPS_INFO.FLARM_Traffic[flarm_slot].Cn); #endif } else { // Else we NEED to set a name, otherwise it will constantly search for it over and over.. name[0]=_T('?'); name[1]=_T('\0'); GPS_INFO.FLARM_Traffic[flarm_slot].Cn[0]=_T('?'); GPS_INFO.FLARM_Traffic[flarm_slot].Cn[1]=_T('\0'); #ifdef DEBUG_SIMLKT StartupStore(_T("... New FlarmSlot=%d ID=%lx with no name, assigned a \"?\"\n"), flarm_slot, GPS_INFO.FLARM_Traffic[flarm_slot].ID); #endif } } // update Virtual Waypoint for target FLARM if (flarm_slot == LKTargetIndex) { WayPointList[RESWP_FLARMTARGET].Latitude = GPS_INFO.FLARM_Traffic[LKTargetIndex].Latitude; WayPointList[RESWP_FLARMTARGET].Longitude = GPS_INFO.FLARM_Traffic[LKTargetIndex].Longitude; WayPointList[RESWP_FLARMTARGET].Altitude = GPS_INFO.FLARM_Traffic[LKTargetIndex].Altitude; } }
/** * Parses a PFLAA sentence * @param String Input string * @param params Parameter array * @param nparams Number of parameters * @param GPS_INFO GPS_INFO struct to parse into * @return Parsing success * @see http://flarm.com/support/manual/FLARM_DataportManual_v4.06E.pdf */ bool NMEAParser::PFLAA(const TCHAR *String, const TCHAR **params, size_t nparams, NMEA_INFO *GPS_INFO) { int flarm_slot = 0; isFlarm = true; // 5 id, 6 digit hex long ID; _stscanf(params[5],TEXT("%lx"), &ID); // unsigned long uID = ID; flarm_slot = FLARM_FindSlot(GPS_INFO, ID); if (flarm_slot<0) { // no more slots available, return false; } // set time of fix to current time GPS_INFO->FLARM_Traffic[flarm_slot].Time_Fix = GPS_INFO->Time; _stscanf(String, TEXT("%hu,%lf,%lf,%lf,%hu,%lx,%lf,%lf,%lf,%lf,%hu"), &GPS_INFO->FLARM_Traffic[flarm_slot].AlarmLevel, // unsigned short 0 &GPS_INFO->FLARM_Traffic[flarm_slot].RelativeNorth, // double? 1 &GPS_INFO->FLARM_Traffic[flarm_slot].RelativeEast, // double? 2 &GPS_INFO->FLARM_Traffic[flarm_slot].RelativeAltitude, // double 3 &GPS_INFO->FLARM_Traffic[flarm_slot].IDType, // unsigned short 4 &GPS_INFO->FLARM_Traffic[flarm_slot].ID, // 6 char hex &GPS_INFO->FLARM_Traffic[flarm_slot].TrackBearing, // double 6 &GPS_INFO->FLARM_Traffic[flarm_slot].TurnRate, // double 7 &GPS_INFO->FLARM_Traffic[flarm_slot].Speed, // double 8 &GPS_INFO->FLARM_Traffic[flarm_slot].ClimbRate, // double 9 &GPS_INFO->FLARM_Traffic[flarm_slot].Type); // unsigned short 10 // 1 relativenorth, meters GPS_INFO->FLARM_Traffic[flarm_slot].Location.Latitude = GPS_INFO->FLARM_Traffic[flarm_slot].RelativeNorth *FLARM_NorthingToLatitude + GPS_INFO->Location.Latitude; // 2 relativeeast, meters GPS_INFO->FLARM_Traffic[flarm_slot].Location.Longitude = GPS_INFO->FLARM_Traffic[flarm_slot].RelativeEast *FLARM_EastingToLongitude + GPS_INFO->Location.Longitude; // alt GPS_INFO->FLARM_Traffic[flarm_slot].Altitude = GPS_INFO->FLARM_Traffic[flarm_slot].RelativeAltitude + GPS_INFO->Altitude; #ifdef FLARM_AVERAGE GPS_INFO->FLARM_Traffic[flarm_slot].Average30s = flarmCalculations.Average30s( GPS_INFO->FLARM_Traffic[flarm_slot].ID, GPS_INFO->Time, GPS_INFO->FLARM_Traffic[flarm_slot].Altitude); #endif // QUESTION TB: never returns true?! return false; }