]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/dme.cxx
Code cleanups, code updates and fix at least on (possible) devide-by-zero
[flightgear.git] / src / Instrumentation / dme.cxx
1 // dme.cxx - distance-measuring equipment.
2 // Written by David Megginson, started 2003.
3 //
4 // This file is in the Public Domain and comes with no warranty.
5
6 #ifdef HAVE_CONFIG_H
7 #  include <config.h>
8 #endif
9
10 #include <simgear/compiler.h>
11 #include <simgear/sg_inlines.h>
12 #include <simgear/math/sg_geodesy.hxx>
13 #include <simgear/math/sg_random.h>
14 #include <simgear/sound/sample_group.hxx>
15
16 #include <Main/fg_props.hxx>
17 #include <Navaids/navlist.hxx>
18 #include <Sound/audioident.hxx>
19
20 #include "dme.hxx"
21
22 #include <cstdio>
23
24
25 /**
26  * Adjust the range.
27  *
28  * Start by calculating the radar horizon based on the elevation
29  * difference, then clamp to the maximum, then add a fudge for
30  * borderline reception.
31  */
32 static double
33 adjust_range (double transmitter_elevation_ft, double aircraft_altitude_ft,
34               double max_range_nm)
35 {
36     double delta_elevation_ft =
37         fabs(aircraft_altitude_ft - transmitter_elevation_ft);
38     double range_nm = 1.23 * sqrt(delta_elevation_ft);
39     if (range_nm > max_range_nm)
40         range_nm = max_range_nm;
41     else if (range_nm < 20.0)
42         range_nm = 20.0;
43     double rand = sg_random();
44     return range_nm + (range_nm * rand * rand);
45 }
46
47 namespace {
48   
49   class DMEFilter : public FGNavList::TypeFilter
50   {
51   public:
52     DMEFilter() :
53       TypeFilter(FGPositioned::DME),
54       _locEnabled(fgGetBool("/sim/realism/dme-fallback-to-loc", true))
55     {
56       if (_locEnabled) {
57         _mintype = FGPositioned::ILS;
58       }
59     }
60     
61     virtual bool pass(FGPositioned* pos) const
62     {
63       switch (pos->type()) {
64       case FGPositioned::DME: return true;
65       case FGPositioned::ILS:
66       case FGPositioned::LOC: return _locEnabled;
67       default: return false;
68       }
69     }
70     
71   private:
72     const bool _locEnabled;
73   };
74   
75 } // of anonymous namespace
76
77
78 DME::DME ( SGPropertyNode *node )
79     : _last_distance_nm(0),
80       _last_frequency_mhz(-1),
81       _time_before_search_sec(0),
82       _navrecord(NULL),
83       _name(node->getStringValue("name", "dme")),
84       _num(node->getIntValue("number", 0)),
85       _audioIdent(NULL)
86 {
87 }
88
89 DME::~DME ()
90 {
91     delete _audioIdent;
92 }
93
94 void
95 DME::init ()
96 {
97     std::string branch;
98     branch = "/instrumentation/" + _name;
99
100     SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true );
101
102     _serviceable_node = node->getChild("serviceable", 0, true);
103     _electrical_node = fgGetNode("/systems/electrical/outputs/dme", true);
104     SGPropertyNode *fnode = node->getChild("frequencies", 0, true);
105     _source_node = fnode->getChild("source", 0, true);
106     _frequency_node = fnode->getChild("selected-mhz", 0, true);
107     _in_range_node = node->getChild("in-range", 0, true);
108     _distance_node = node->getChild("indicated-distance-nm", 0, true);
109     _speed_node = node->getChild("indicated-ground-speed-kt", 0, true);
110     _time_node = node->getChild("indicated-time-min", 0, true);
111
112     double d = node->getDoubleValue( "volume", 1.0 );
113     _volume_node = node->getChild("volume", 0, true);
114     _volume_node->setDoubleValue( d );
115
116     bool b = node->getBoolValue( "ident", false );
117     _ident_btn_node = node->getChild("ident", 0, true);
118     _ident_btn_node->setBoolValue( b );
119
120     SGPropertyNode *subnode = node->getChild("KDI572-574", 0, true);
121
122     _distance_string = subnode->getChild("nm",0, true);
123     _distance_string->setStringValue("---");
124     _speed_string = subnode->getChild("kt", 0, true);
125     _speed_string->setStringValue("---");
126     _time_string = subnode->getChild("min",0, true);
127     _time_string->setStringValue("--");
128
129     std::ostringstream temp;
130     temp << _name << "-ident-" << _num;
131     if( NULL == _audioIdent ) 
132         _audioIdent = new DMEAudioIdent( temp.str() );
133     _audioIdent->init();
134
135     reinit();
136 }
137
138 void
139 DME::reinit ()
140 {
141     _time_before_search_sec = 0;
142 }
143
144 void
145 DME::update (double delta_time_sec)
146 {
147     if( delta_time_sec < SGLimitsd::min() )
148         return;  //paused
149     char tmp[16];
150                                 // Figure out the source
151     const char * source = _source_node->getStringValue();
152     if (source[0] == '\0') {
153         std::string branch;
154         branch = "/instrumentation/" + _name + "/frequencies/selected-mhz";
155         _source_node->setStringValue(branch.c_str());
156         source = _source_node->getStringValue();
157     }
158                                 // Get the frequency
159
160     double frequency_mhz = fgGetDouble(source, 108.0);
161     if (frequency_mhz != _last_frequency_mhz) {
162         _time_before_search_sec = 0;
163         _last_frequency_mhz = frequency_mhz;
164     }
165     _frequency_node->setDoubleValue(frequency_mhz);
166
167                                 // Get the aircraft position
168     // On timeout, scan again
169     _time_before_search_sec -= delta_time_sec;
170     if (_time_before_search_sec < 0) {
171         _time_before_search_sec = 1.0;
172
173       SGGeod pos(globals->get_aircraft_position());
174       DMEFilter filter;
175       _navrecord = FGNavList::findByFreq(frequency_mhz, pos, &filter);
176     }
177
178
179     // If it's off, don't bother.
180     if (!_serviceable_node->getBoolValue() ||
181         !_electrical_node->getBoolValue()){
182         _last_distance_nm = 0;
183         _in_range_node->setBoolValue(false);
184         _distance_node->setDoubleValue(0);
185         _speed_node->setDoubleValue(0);
186         _time_node->setDoubleValue(0);
187         _audioIdent->setIdent("", 0.0 );
188         _distance_string->setStringValue("");
189         _speed_string->setStringValue("");
190         _time_string->setStringValue("");
191         return;
192     }
193     // If it's on, but invalid source,don't bother.
194 if (NULL == _navrecord ){
195         _distance_string->setStringValue("---");
196         _speed_string->setStringValue("---");
197         _time_string->setStringValue("--");
198         return;
199     }
200     // Calculate the distance to the transmitter
201     double distance_nm = dist(_navrecord->cart(),
202                   globals->get_aircraft_position_cart()) * SG_METER_TO_NM;
203
204     double range_nm = adjust_range(_navrecord->get_elev_ft(),
205                                    globals->get_aircraft_position().getElevationFt(),
206                                    _navrecord->get_range());
207
208     if (distance_nm <= range_nm) {
209         double volume = _volume_node->getDoubleValue();
210         if( false == _ident_btn_node->getBoolValue() )
211             volume = 0.0;
212
213         _audioIdent->setIdent(_navrecord->ident(), volume );
214
215         double speed_kt = (fabs(distance_nm - _last_distance_nm) *
216                            ((1 / delta_time_sec) * 3600.0));
217         _last_distance_nm = distance_nm;
218
219         _in_range_node->setBoolValue(true);
220         double tmp_dist = distance_nm - _navrecord->get_multiuse();
221         if ( tmp_dist < 0.0 ) {
222             tmp_dist = 0.0;
223         }
224         _distance_node->setDoubleValue( tmp_dist );
225         if ( tmp_dist >389 ) tmp_dist = 389;
226         if ( tmp_dist >= 100.0) {
227             snprintf ( tmp,16,"%3.0f",tmp_dist);
228         } else {
229             snprintf ( tmp,16,"%2.1f",tmp_dist);
230         }
231         _distance_string->setStringValue(tmp);
232
233         _speed_node->setDoubleValue(speed_kt);
234         double spd = speed_kt;
235         if(spd>999) spd=999;
236         snprintf ( tmp,16,"%3.0f",spd);
237         _speed_string->setStringValue(tmp);
238
239
240         if (SGLimitsd::min() < fabs(speed_kt)){
241             double tm = distance_nm/speed_kt*60.0;
242             _time_node->setDoubleValue(tm);
243             if (tm >99) tm= 99;
244             snprintf ( tmp,16,"%2.0f",tm);
245             _time_string->setStringValue(tmp);
246         }
247         
248     } else {
249         _last_distance_nm = 0;
250         _in_range_node->setBoolValue(false);
251         _distance_node->setDoubleValue(0);
252         _distance_string->setStringValue("---");
253         _speed_node->setDoubleValue(0);
254         _speed_string->setStringValue("---");
255         _time_node->setDoubleValue(0);
256         _time_string->setStringValue("--");
257         _audioIdent->setIdent("", 0.0 );
258     }
259     _audioIdent->update( delta_time_sec );
260 }
261
262 // end of dme.cxx