1 // radiostack.cxx -- class to manage an instance of the radio stack
3 // Written by Curtis Olson, started April 2000.
5 // Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
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.
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.
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.
28 #include <stdio.h> // snprintf
30 #include <simgear/compiler.h>
31 #include <simgear/math/sg_random.h>
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>
39 #include "radiostack.hxx"
45 FGRadioStack *current_radiostack;
49 * Boy, this is ugly! Make the VOR range vary by altitude difference.
51 static double kludgeRange ( double stationElev, double aircraftElev,
54 // Assume that the nominal range (usually
55 // 50nm) applies at a 5,000 ft difference.
57 double factor = ((aircraftElev*SG_METER_TO_FEET) - stationElev) / 5000.0;
58 double range = fabs(nominalRange * factor);
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;
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)),
83 SGPath path( globals->get_fg_root() );
85 term.append( "Navaids/range.term" );
87 low.append( "Navaids/range.low" );
89 high.append( "Navaids/range.high" );
91 term_tbl = new SGInterpTable( term.str() );
92 low_tbl = new SGInterpTable( low.str() );
93 high_tbl = new SGInterpTable( high.str() );
98 FGRadioStack::~FGRadioStack()
104 unbind(); // FIXME: should be called externally
113 FGRadioStack::init ()
115 navcom1.set_bind_index( 0 );
118 navcom2.set_bind_index( 1 );
134 update(0); // FIXME: use dt
140 // Search radio database once per second
141 global_events.Register( "fgRadioSearch()",
142 current_radiostack, &FGRadioStack::search,
148 FGRadioStack::bind ()
151 fgTie("/radios/marker-beacon/inner", this,
152 &FGRadioStack::get_inner_blink);
154 fgTie("/radios/marker-beacon/middle", this,
155 &FGRadioStack::get_middle_blink);
157 fgTie("/radios/marker-beacon/outer", this,
158 &FGRadioStack::get_outer_blink);
162 navcom1.set_bind_index( 0 );
164 navcom2.set_bind_index( 1 );
171 FGRadioStack::unbind ()
173 fgUntie("/radios/marker-beacon/inner");
174 fgUntie("/radios/marker-beacon/middle");
175 fgUntie("/radios/marker-beacon/outer");
185 // Update the various nav values based on position and valid tuned in navs
187 FGRadioStack::update(double dt)
192 navcom1.update( dt );
193 navcom2.update( dt );
194 dme.update( dt ); // dme is updated after the navcom's
195 xponder.update( dt );
197 // marker beacon blinking
198 bool light_on = ( outer_blink || middle_blink || inner_blink );
202 if ( light_on && (current - blink > 400000) ) {
205 } else if ( !light_on && (current - blink > 100000) ) {
210 if ( outer_marker ) {
211 outer_blink = light_on;
216 if ( middle_marker ) {
217 middle_blink = light_on;
219 middle_blink = false;
222 if ( inner_marker ) {
223 inner_blink = light_on;
228 // cout << outer_blink << " " << middle_blink << " " << inner_blink << endl;
232 // Update current nav/adf radio stations based on current postition
233 void FGRadioStack::search()
235 static FGMkrBeacon::fgMkrBeacType last_beacon = FGMkrBeacon::NOBEACON;
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;
247 ////////////////////////////////////////////////////////////////////////
249 ////////////////////////////////////////////////////////////////////////
251 FGMkrBeacon::fgMkrBeacType beacon_type
252 = current_beacons->query( lon * SGD_RADIANS_TO_DEGREES,
253 lat * SGD_RADIANS_TO_DEGREES, elev );
255 outer_marker = middle_marker = inner_marker = false;
257 if ( beacon_type == FGMkrBeacon::OUTER ) {
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" );
267 if ( !globals->get_soundmgr()->is_playing("outer-marker") ) {
268 globals->get_soundmgr()->play_looped( "outer-marker" );
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" );
282 if ( !globals->get_soundmgr()->is_playing("middle-marker") ) {
283 globals->get_soundmgr()->play_looped( "middle-marker" );
287 } else if ( beacon_type == FGMkrBeacon::INNER ) {
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" );
297 if ( !globals->get_soundmgr()->is_playing("inner-marker") ) {
298 globals->get_soundmgr()->play_looped( "inner-marker" );
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" );
310 last_beacon = beacon_type;