4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "FLARM/FlarmComputer.hpp"
25 #include "FLARM/FlarmDetails.hpp"
26 #include "NMEA/Info.hpp"
27 #include "Geo/GeoVector.hpp"
30 FlarmComputer::Process(FlarmData
&flarm
, const FlarmData
&last_flarm
,
31 const NMEAInfo
&basic
)
33 // Cleanup old calculation instances
34 if (basic
.time_available
)
35 flarm_calculations
.CleanUp(basic
.time
);
37 // if (FLARM data is available)
38 if (!flarm
.IsDetected())
41 fixed
north_to_latitude(0);
42 fixed
east_to_longitude(0);
44 if (basic
.location_available
) {
45 // Precalculate relative east and north projection to lat/lon
46 // for Location calculations of each target
47 constexpr Angle delta_lat
= Angle::Degrees(0.01);
48 constexpr Angle delta_lon
= Angle::Degrees(0.01);
50 GeoPoint plat
= basic
.location
;
51 plat
.latitude
+= delta_lat
;
52 GeoPoint plon
= basic
.location
;
53 plon
.longitude
+= delta_lon
;
55 fixed dlat
= basic
.location
.Distance(plat
);
56 fixed dlon
= basic
.location
.Distance(plon
);
58 if (positive(fabs(dlat
)) && positive(fabs(dlon
))) {
59 north_to_latitude
= delta_lat
.Degrees() / dlat
;
60 east_to_longitude
= delta_lon
.Degrees() / dlon
;
64 // for each item in traffic
65 for (auto &traffic
: flarm
.traffic
.list
) {
66 // if we don't know the target's name yet
67 if (!traffic
.HasName()) {
68 // lookup the name of this target's id
69 const TCHAR
*fname
= FlarmDetails::LookupCallsign(traffic
.id
);
75 traffic
.distance
= SmallHypot(traffic
.relative_north
,
76 traffic
.relative_east
);
79 traffic
.location_available
= basic
.location_available
;
80 if (traffic
.location_available
) {
81 traffic
.location
.latitude
=
82 Angle::Degrees(traffic
.relative_north
* north_to_latitude
) +
83 basic
.location
.latitude
;
85 traffic
.location
.longitude
=
86 Angle::Degrees(traffic
.relative_east
* east_to_longitude
) +
87 basic
.location
.longitude
;
90 // Calculate absolute altitude
91 traffic
.altitude_available
= basic
.gps_altitude_available
;
92 if (traffic
.altitude_available
)
93 traffic
.altitude
= traffic
.relative_altitude
+ RoughAltitude(basic
.gps_altitude
);
95 // Calculate average climb rate
96 traffic
.climb_rate_avg30s_available
= traffic
.altitude_available
;
97 if (traffic
.climb_rate_avg30s_available
)
98 traffic
.climb_rate_avg30s
=
99 flarm_calculations
.Average30s(traffic
.id
, basic
.time
, traffic
.altitude
);
101 // The following calculations are only relevant for targets
102 // where information is missing
103 if (traffic
.track_received
&& traffic
.turn_rate_received
&&
104 traffic
.speed_received
&& traffic
.climb_rate_received
)
107 // Check if the target has been seen before in the last seconds
108 const FlarmTraffic
*last_traffic
=
109 last_flarm
.traffic
.FindTraffic(traffic
.id
);
110 if (last_traffic
== NULL
|| !last_traffic
->valid
)
113 // Calculate the time difference between now and the last contact
114 fixed dt
= traffic
.valid
.GetTimeDifference(last_traffic
->valid
);
116 // Calculate the immediate climb rate
117 if (!traffic
.climb_rate_received
)
119 (traffic
.relative_altitude
- last_traffic
->relative_altitude
) / dt
;
121 // Since the time difference is zero (or negative)
122 // we can just copy the old values
123 if (!traffic
.climb_rate_received
)
124 traffic
.climb_rate
= last_traffic
->climb_rate
;
128 traffic
.location_available
&&
129 last_traffic
->location_available
) {
130 // Calculate the GeoVector between now and the last contact
131 GeoVector vec
= last_traffic
->location
.DistanceBearing(traffic
.location
);
133 if (!traffic
.track_received
)
134 traffic
.track
= vec
.bearing
;
136 // Calculate the turn rate
137 if (!traffic
.turn_rate_received
) {
138 Angle turn_rate
= traffic
.track
- last_traffic
->track
;
140 turn_rate
.AsDelta().Degrees() / dt
;
143 // Calculate the speed [m/s]
144 if (!traffic
.speed_received
)
145 traffic
.speed
= vec
.distance
/ dt
;
147 // Since the time difference is zero (or negative)
148 // we can just copy the old values
149 if (!traffic
.track_received
)
150 traffic
.track
= last_traffic
->track
;
152 if (!traffic
.turn_rate_received
)
153 traffic
.turn_rate
= last_traffic
->turn_rate
;
155 if (!traffic
.speed_received
)
156 traffic
.speed
= last_traffic
->speed
;