]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/radiostack.cxx
Shuffling/reorganizing code.
[flightgear.git] / src / Cockpit / radiostack.cxx
1 // radiostack.cxx -- class to manage an instance of the radio stack
2 //
3 // Written by Curtis Olson, started April 2000.
4 //
5 // Copyright (C) 2000  Curtis L. Olson - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <stdio.h>      // snprintf
29
30 #include <simgear/compiler.h>
31 #include <simgear/math/sg_random.h>
32
33 #include <Aircraft/aircraft.hxx>
34 #include <Navaids/ilslist.hxx>
35 #include <Navaids/mkrbeacons.hxx>
36 #include <Navaids/navlist.hxx>
37 #include <Time/FGEventMgr.hxx>
38
39 #include "radiostack.hxx"
40
41 #include <string>
42 SG_USING_STD(string);
43
44
45 FGRadioStack *current_radiostack;
46
47
48 /**
49  * Boy, this is ugly!  Make the VOR range vary by altitude difference.
50  */
51 static double kludgeRange ( double stationElev, double aircraftElev,
52                             double nominalRange)
53 {
54                                 // Assume that the nominal range (usually
55                                 // 50nm) applies at a 5,000 ft difference.
56                                 // Just a wild guess!
57   double factor = ((aircraftElev*SG_METER_TO_FEET) - stationElev) / 5000.0;
58   double range = fabs(nominalRange * factor);
59
60                                 // Clamp the range to keep it sane; for
61                                 // now, never less than 25% or more than
62                                 // 500% of nominal range.
63   if (range < nominalRange/4.0) {
64     range = nominalRange/4.0;
65   } else if (range > nominalRange*5.0) {
66     range = nominalRange*5.0;
67   }
68
69   return range;
70 }
71
72
73 // Constructor
74 FGRadioStack::FGRadioStack() :
75     lon_node(fgGetNode("/position/longitude-deg", true)),
76     lat_node(fgGetNode("/position/latitude-deg", true)),
77     alt_node(fgGetNode("/position/altitude-ft", true)),
78     need_update(true),
79     outer_blink(false),
80     middle_blink(false),
81     inner_blink(false)
82 {
83     SGPath path( globals->get_fg_root() );
84     SGPath term = path;
85     term.append( "Navaids/range.term" );
86     SGPath low = path;
87     low.append( "Navaids/range.low" );
88     SGPath high = path;
89     high.append( "Navaids/range.high" );
90
91     term_tbl = new SGInterpTable( term.str() );
92     low_tbl = new SGInterpTable( low.str() );
93     high_tbl = new SGInterpTable( high.str() );
94 }
95
96
97 // Destructor
98 FGRadioStack::~FGRadioStack() 
99 {
100     navcom1.unbind();
101     navcom2.unbind();
102     adf.unbind();
103     xponder.unbind();
104     unbind();                   // FIXME: should be called externally
105
106     delete term_tbl;
107     delete low_tbl;
108     delete high_tbl;
109 }
110
111
112 void
113 FGRadioStack::init ()
114 {
115     navcom1.set_bind_index( 0 );
116     navcom1.init();
117
118     navcom2.set_bind_index( 1 );
119     navcom2.init();
120
121     adf.init();
122     xponder.init();
123
124     morse.init();
125     beacon.init();
126     blink.stamp();
127
128     search();
129     navcom1.search();
130     navcom2.search();
131     adf.search();
132     xponder.search();
133
134     update(0);                  // FIXME: use dt
135     navcom1.update(0);
136     navcom2.update(0);
137     adf.update(0);
138     xponder.update(0);
139
140     // Search radio database once per second
141     global_events.Register( "fgRadioSearch()",
142                             current_radiostack, &FGRadioStack::search,
143                             1000 );
144 }
145
146
147 void
148 FGRadioStack::bind ()
149 {
150
151     fgTie("/radios/marker-beacon/inner", this,
152           &FGRadioStack::get_inner_blink);
153
154     fgTie("/radios/marker-beacon/middle", this,
155           &FGRadioStack::get_middle_blink);
156
157     fgTie("/radios/marker-beacon/outer", this,
158           &FGRadioStack::get_outer_blink);
159
160     adf.bind();
161     dme.bind();
162     navcom1.set_bind_index( 0 );
163     navcom1.bind();
164     navcom2.set_bind_index( 1 );
165     navcom2.bind();
166     xponder.bind();
167 }
168
169
170 void
171 FGRadioStack::unbind ()
172 {
173     fgUntie("/radios/marker-beacon/inner");
174     fgUntie("/radios/marker-beacon/middle");
175     fgUntie("/radios/marker-beacon/outer");
176
177     adf.unbind();
178     dme.unbind();
179     navcom1.unbind();
180     navcom2.unbind();
181     xponder.unbind();
182 }
183
184
185 // Update the various nav values based on position and valid tuned in navs
186 void 
187 FGRadioStack::update(double dt) 
188 {
189     need_update = false;
190
191     adf.update( dt );
192     navcom1.update( dt );
193     navcom2.update( dt );
194     dme.update( dt );           // dme is updated after the navcom's
195     xponder.update( dt );
196
197     // marker beacon blinking
198     bool light_on = ( outer_blink || middle_blink || inner_blink );
199     SGTimeStamp current;
200     current.stamp();
201
202     if ( light_on && (current - blink > 400000) ) {
203         light_on = false;
204         blink.stamp();
205     } else if ( !light_on && (current - blink > 100000) ) {
206         light_on = true;
207         blink.stamp();
208     }
209
210     if ( outer_marker ) {
211         outer_blink = light_on;
212     } else {
213         outer_blink = false;
214     }
215
216     if ( middle_marker ) {
217         middle_blink = light_on;
218     } else {
219         middle_blink = false;
220     }
221
222     if ( inner_marker ) {
223         inner_blink = light_on;
224     } else {
225         inner_blink = false;
226     }
227
228     // cout << outer_blink << " " << middle_blink << " " << inner_blink << endl;
229 }
230
231
232 // Update current nav/adf radio stations based on current postition
233 void FGRadioStack::search() 
234 {
235     static FGMkrBeacon::fgMkrBeacType last_beacon = FGMkrBeacon::NOBEACON;
236
237     double lon = lon_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
238     double lat = lat_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
239     double elev = alt_node->getDoubleValue() * SG_FEET_TO_METER;
240
241     adf.search();
242     navcom1.search();
243     navcom2.search();
244     dme.search();
245     xponder.search();
246
247     ////////////////////////////////////////////////////////////////////////
248     // Beacons.
249     ////////////////////////////////////////////////////////////////////////
250
251     FGMkrBeacon::fgMkrBeacType beacon_type
252         = current_beacons->query( lon * SGD_RADIANS_TO_DEGREES,
253                                   lat * SGD_RADIANS_TO_DEGREES, elev );
254
255     outer_marker = middle_marker = inner_marker = false;
256
257     if ( beacon_type == FGMkrBeacon::OUTER ) {
258         outer_marker = true;
259         // cout << "OUTER MARKER" << endl;
260 #ifdef ENABLE_AUDIO_SUPPORT
261         if ( last_beacon != FGMkrBeacon::OUTER ) {
262             if ( ! globals->get_soundmgr()->exists( "outer-marker" ) ) {
263                 FGSimpleSound *sound = beacon.get_outer();
264                 sound->set_volume( 0.3 );
265                 globals->get_soundmgr()->add( sound, "outer-marker" );
266             }
267             if ( !globals->get_soundmgr()->is_playing("outer-marker") ) {
268                 globals->get_soundmgr()->play_looped( "outer-marker" );
269             }
270         }
271 #endif
272     } else if ( beacon_type == FGMkrBeacon::MIDDLE ) {
273         middle_marker = true;
274         // cout << "MIDDLE MARKER" << endl;
275 #ifdef ENABLE_AUDIO_SUPPORT
276         if ( last_beacon != FGMkrBeacon::MIDDLE ) {
277             if ( ! globals->get_soundmgr()->exists( "middle-marker" ) ) {
278                 FGSimpleSound *sound = beacon.get_middle();
279                 sound->set_volume( 0.3 );
280                 globals->get_soundmgr()->add( sound, "middle-marker" );
281             }
282             if ( !globals->get_soundmgr()->is_playing("middle-marker") ) {
283                 globals->get_soundmgr()->play_looped( "middle-marker" );
284             }
285         }
286 #endif
287     } else if ( beacon_type == FGMkrBeacon::INNER ) {
288         inner_marker = true;
289         // cout << "INNER MARKER" << endl;
290 #ifdef ENABLE_AUDIO_SUPPORT
291         if ( last_beacon != FGMkrBeacon::INNER ) {
292             if ( ! globals->get_soundmgr()->exists( "inner-marker" ) ) {
293                 FGSimpleSound *sound = beacon.get_inner();
294                 sound->set_volume( 0.3 );
295                 globals->get_soundmgr()->add( sound, "inner-marker" );
296             }
297             if ( !globals->get_soundmgr()->is_playing("inner-marker") ) {
298                 globals->get_soundmgr()->play_looped( "inner-marker" );
299             }
300         }
301 #endif
302     } else {
303         // cout << "no marker" << endl;
304 #ifdef ENABLE_AUDIO_SUPPORT
305         globals->get_soundmgr()->stop( "outer-marker" );
306         globals->get_soundmgr()->stop( "middle-marker" );
307         globals->get_soundmgr()->stop( "inner-marker" );
308 #endif
309     }
310     last_beacon = beacon_type;
311 }