diff --git a/src/Cockpit/Makefile.am b/src/Cockpit/Makefile.am index 14463061d..6e0a54c9f 100644 --- a/src/Cockpit/Makefile.am +++ b/src/Cockpit/Makefile.am @@ -10,6 +10,7 @@ libCockpit_a_SOURCES = \ hud_scal.cxx hud_tbi.cxx \ kr_87.cxx kr_87.hxx \ kt_70.cxx kt_70.hxx \ + marker_beacon.cxx marker_beacon.hxx \ navcom.cxx navcom.hxx \ panel.cxx panel.hxx \ panel_io.cxx panel_io.hxx \ diff --git a/src/Cockpit/marker_beacon.cxx b/src/Cockpit/marker_beacon.cxx new file mode 100644 index 000000000..941d1e2b4 --- /dev/null +++ b/src/Cockpit/marker_beacon.cxx @@ -0,0 +1,251 @@ +// marker_beacon.cxx -- class to manage the marker beacons +// +// Written by Curtis Olson, started April 2000. +// +// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> // snprintf + +#include <simgear/compiler.h> +#include <simgear/math/sg_random.h> + +#include <Aircraft/aircraft.hxx> +#include <Navaids/mkrbeacons.hxx> +#include <Time/FGEventMgr.hxx> + +#include "marker_beacon.hxx" + +#include <string> +SG_USING_STD(string); + + +/** + * Boy, this is ugly! Make the VOR range vary by altitude difference. + */ +static double kludgeRange ( double stationElev, double aircraftElev, + double nominalRange) +{ + // Assume that the nominal range (usually + // 50nm) applies at a 5,000 ft difference. + // Just a wild guess! + double factor = ((aircraftElev*SG_METER_TO_FEET) - stationElev) / 5000.0; + double range = fabs(nominalRange * factor); + + // Clamp the range to keep it sane; for + // now, never less than 25% or more than + // 500% of nominal range. + if (range < nominalRange/4.0) { + range = nominalRange/4.0; + } else if (range > nominalRange*5.0) { + range = nominalRange*5.0; + } + + return range; +} + + +// Constructor +FGMarkerBeacon::FGMarkerBeacon() : + lon_node(fgGetNode("/position/longitude-deg", true)), + lat_node(fgGetNode("/position/latitude-deg", true)), + alt_node(fgGetNode("/position/altitude-ft", true)), + need_update(true), + outer_blink(false), + middle_blink(false), + inner_blink(false) +{ + SGPath path( globals->get_fg_root() ); + SGPath term = path; + term.append( "Navaids/range.term" ); + SGPath low = path; + low.append( "Navaids/range.low" ); + SGPath high = path; + high.append( "Navaids/range.high" ); + + term_tbl = new SGInterpTable( term.str() ); + low_tbl = new SGInterpTable( low.str() ); + high_tbl = new SGInterpTable( high.str() ); +} + + +// Destructor +FGMarkerBeacon::~FGMarkerBeacon() +{ + delete term_tbl; + delete low_tbl; + delete high_tbl; +} + + +void +FGMarkerBeacon::init () +{ + morse.init(); + beacon.init(); + blink.stamp(); + + search(); + update(0); // FIXME: use dt +} + + +void +FGMarkerBeacon::bind () +{ + + fgTie("/radios/marker-beacon/inner", this, + &FGMarkerBeacon::get_inner_blink); + + fgTie("/radios/marker-beacon/middle", this, + &FGMarkerBeacon::get_middle_blink); + + fgTie("/radios/marker-beacon/outer", this, + &FGMarkerBeacon::get_outer_blink); +} + + +void +FGMarkerBeacon::unbind () +{ + fgUntie("/radios/marker-beacon/inner"); + fgUntie("/radios/marker-beacon/middle"); + fgUntie("/radios/marker-beacon/outer"); +} + + +// Update the various nav values based on position and valid tuned in navs +void +FGMarkerBeacon::update(double dt) +{ + need_update = false; + + // marker beacon blinking + bool light_on = ( outer_blink || middle_blink || inner_blink ); + SGTimeStamp current; + current.stamp(); + + if ( light_on && (current - blink > 400000) ) { + light_on = false; + blink.stamp(); + } else if ( !light_on && (current - blink > 100000) ) { + light_on = true; + blink.stamp(); + } + + if ( outer_marker ) { + outer_blink = light_on; + } else { + outer_blink = false; + } + + if ( middle_marker ) { + middle_blink = light_on; + } else { + middle_blink = false; + } + + if ( inner_marker ) { + inner_blink = light_on; + } else { + inner_blink = false; + } + + // cout << outer_blink << " " << middle_blink << " " << inner_blink << endl; +} + + +// Update current nav/adf radio stations based on current postition +void FGMarkerBeacon::search() +{ + static FGMkrBeacon::fgMkrBeacType last_beacon = FGMkrBeacon::NOBEACON; + + double lon = lon_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS; + double lat = lat_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS; + double elev = alt_node->getDoubleValue() * SG_FEET_TO_METER; + + //////////////////////////////////////////////////////////////////////// + // Beacons. + //////////////////////////////////////////////////////////////////////// + + FGMkrBeacon::fgMkrBeacType beacon_type + = current_beacons->query( lon * SGD_RADIANS_TO_DEGREES, + lat * SGD_RADIANS_TO_DEGREES, elev ); + + outer_marker = middle_marker = inner_marker = false; + + if ( beacon_type == FGMkrBeacon::OUTER ) { + outer_marker = true; + // cout << "OUTER MARKER" << endl; +#ifdef ENABLE_AUDIO_SUPPORT + if ( last_beacon != FGMkrBeacon::OUTER ) { + if ( ! globals->get_soundmgr()->exists( "outer-marker" ) ) { + FGSimpleSound *sound = beacon.get_outer(); + sound->set_volume( 0.3 ); + globals->get_soundmgr()->add( sound, "outer-marker" ); + } + if ( !globals->get_soundmgr()->is_playing("outer-marker") ) { + globals->get_soundmgr()->play_looped( "outer-marker" ); + } + } +#endif + } else if ( beacon_type == FGMkrBeacon::MIDDLE ) { + middle_marker = true; + // cout << "MIDDLE MARKER" << endl; +#ifdef ENABLE_AUDIO_SUPPORT + if ( last_beacon != FGMkrBeacon::MIDDLE ) { + if ( ! globals->get_soundmgr()->exists( "middle-marker" ) ) { + FGSimpleSound *sound = beacon.get_middle(); + sound->set_volume( 0.3 ); + globals->get_soundmgr()->add( sound, "middle-marker" ); + } + if ( !globals->get_soundmgr()->is_playing("middle-marker") ) { + globals->get_soundmgr()->play_looped( "middle-marker" ); + } + } +#endif + } else if ( beacon_type == FGMkrBeacon::INNER ) { + inner_marker = true; + // cout << "INNER MARKER" << endl; +#ifdef ENABLE_AUDIO_SUPPORT + if ( last_beacon != FGMkrBeacon::INNER ) { + if ( ! globals->get_soundmgr()->exists( "inner-marker" ) ) { + FGSimpleSound *sound = beacon.get_inner(); + sound->set_volume( 0.3 ); + globals->get_soundmgr()->add( sound, "inner-marker" ); + } + if ( !globals->get_soundmgr()->is_playing("inner-marker") ) { + globals->get_soundmgr()->play_looped( "inner-marker" ); + } + } +#endif + } else { + // cout << "no marker" << endl; +#ifdef ENABLE_AUDIO_SUPPORT + globals->get_soundmgr()->stop( "outer-marker" ); + globals->get_soundmgr()->stop( "middle-marker" ); + globals->get_soundmgr()->stop( "inner-marker" ); +#endif + } + last_beacon = beacon_type; +} diff --git a/src/Cockpit/marker_beacon.hxx b/src/Cockpit/marker_beacon.hxx new file mode 100644 index 000000000..1a49844dd --- /dev/null +++ b/src/Cockpit/marker_beacon.hxx @@ -0,0 +1,84 @@ +// marker_beacon.hxx -- class to manage the marker beacons +// +// Written by Curtis Olson, started April 2000. +// +// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#ifndef _FG_MARKER_BEACON_HXX +#define _FG_MARKER_BEACON_HXX + + +#include <Main/fgfs.hxx> +#include <Main/fg_props.hxx> + +#include <simgear/compiler.h> + +#include <simgear/math/interpolater.hxx> +#include <simgear/timing/timestamp.hxx> + +#include <Sound/beacon.hxx> +#include <Sound/morse.hxx> + + +class FGMarkerBeacon : public FGSubsystem +{ + FGBeacon beacon; + FGMorse morse; + + SGInterpTable *term_tbl; + SGInterpTable *low_tbl; + SGInterpTable *high_tbl; + + SGPropertyNode *lon_node; + SGPropertyNode *lat_node; + SGPropertyNode *alt_node; + + bool need_update; + + bool outer_marker; + bool middle_marker; + bool inner_marker; + + SGTimeStamp blink; + bool outer_blink; + bool middle_blink; + bool inner_blink; + +public: + + FGMarkerBeacon(); + ~FGMarkerBeacon(); + + void init (); + void bind (); + void unbind (); + void update (double dt); + + // Update nav/adf radios based on current postition + void search (); + + // Marker Beacon Accessors + inline bool get_inner_blink () const { return inner_blink; } + inline bool get_middle_blink () const { return middle_blink; } + inline bool get_outer_blink () const { return outer_blink; } +}; + + +#endif // _FG_MARKER_BEACON_HXX diff --git a/src/Cockpit/radiostack.cxx b/src/Cockpit/radiostack.cxx index 134a6cb76..6566daf7e 100644 --- a/src/Cockpit/radiostack.cxx +++ b/src/Cockpit/radiostack.cxx @@ -45,67 +45,19 @@ SG_USING_STD(string); FGRadioStack *current_radiostack; -/** - * Boy, this is ugly! Make the VOR range vary by altitude difference. - */ -static double kludgeRange ( double stationElev, double aircraftElev, - double nominalRange) -{ - // Assume that the nominal range (usually - // 50nm) applies at a 5,000 ft difference. - // Just a wild guess! - double factor = ((aircraftElev*SG_METER_TO_FEET) - stationElev) / 5000.0; - double range = fabs(nominalRange * factor); - - // Clamp the range to keep it sane; for - // now, never less than 25% or more than - // 500% of nominal range. - if (range < nominalRange/4.0) { - range = nominalRange/4.0; - } else if (range > nominalRange*5.0) { - range = nominalRange*5.0; - } - - return range; -} - - // Constructor -FGRadioStack::FGRadioStack() : - lon_node(fgGetNode("/position/longitude-deg", true)), - lat_node(fgGetNode("/position/latitude-deg", true)), - alt_node(fgGetNode("/position/altitude-ft", true)), - need_update(true), - outer_blink(false), - middle_blink(false), - inner_blink(false) -{ - SGPath path( globals->get_fg_root() ); - SGPath term = path; - term.append( "Navaids/range.term" ); - SGPath low = path; - low.append( "Navaids/range.low" ); - SGPath high = path; - high.append( "Navaids/range.high" ); - - term_tbl = new SGInterpTable( term.str() ); - low_tbl = new SGInterpTable( low.str() ); - high_tbl = new SGInterpTable( high.str() ); +FGRadioStack::FGRadioStack() { } // Destructor FGRadioStack::~FGRadioStack() { + adf.unbind(); + beacon.unbind(); navcom1.unbind(); navcom2.unbind(); - adf.unbind(); xponder.unbind(); - unbind(); // FIXME: should be called externally - - delete term_tbl; - delete low_tbl; - delete high_tbl; } @@ -119,23 +71,11 @@ FGRadioStack::init () navcom2.init(); adf.init(); + beacon.init(); xponder.init(); - morse.init(); - beacon.init(); - blink.stamp(); - search(); - navcom1.search(); - navcom2.search(); - adf.search(); - xponder.search(); - update(0); // FIXME: use dt - navcom1.update(0); - navcom2.update(0); - adf.update(0); - xponder.update(0); // Search radio database once per second global_events.Register( "fgRadioSearch()", @@ -147,17 +87,8 @@ FGRadioStack::init () void FGRadioStack::bind () { - - fgTie("/radios/marker-beacon/inner", this, - &FGRadioStack::get_inner_blink); - - fgTie("/radios/marker-beacon/middle", this, - &FGRadioStack::get_middle_blink); - - fgTie("/radios/marker-beacon/outer", this, - &FGRadioStack::get_outer_blink); - adf.bind(); + beacon.bind(); dme.bind(); navcom1.set_bind_index( 0 ); navcom1.bind(); @@ -170,11 +101,8 @@ FGRadioStack::bind () void FGRadioStack::unbind () { - fgUntie("/radios/marker-beacon/inner"); - fgUntie("/radios/marker-beacon/middle"); - fgUntie("/radios/marker-beacon/outer"); - adf.unbind(); + beacon.unbind(); dme.unbind(); navcom1.unbind(); navcom2.unbind(); @@ -186,126 +114,22 @@ FGRadioStack::unbind () void FGRadioStack::update(double dt) { - need_update = false; - adf.update( dt ); + beacon.update( dt ); navcom1.update( dt ); navcom2.update( dt ); dme.update( dt ); // dme is updated after the navcom's xponder.update( dt ); - - // marker beacon blinking - bool light_on = ( outer_blink || middle_blink || inner_blink ); - SGTimeStamp current; - current.stamp(); - - if ( light_on && (current - blink > 400000) ) { - light_on = false; - blink.stamp(); - } else if ( !light_on && (current - blink > 100000) ) { - light_on = true; - blink.stamp(); - } - - if ( outer_marker ) { - outer_blink = light_on; - } else { - outer_blink = false; - } - - if ( middle_marker ) { - middle_blink = light_on; - } else { - middle_blink = false; - } - - if ( inner_marker ) { - inner_blink = light_on; - } else { - inner_blink = false; - } - - // cout << outer_blink << " " << middle_blink << " " << inner_blink << endl; } // Update current nav/adf radio stations based on current postition void FGRadioStack::search() { - static FGMkrBeacon::fgMkrBeacType last_beacon = FGMkrBeacon::NOBEACON; - - double lon = lon_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS; - double lat = lat_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS; - double elev = alt_node->getDoubleValue() * SG_FEET_TO_METER; - adf.search(); + beacon.search(); navcom1.search(); navcom2.search(); dme.search(); xponder.search(); - - //////////////////////////////////////////////////////////////////////// - // Beacons. - //////////////////////////////////////////////////////////////////////// - - FGMkrBeacon::fgMkrBeacType beacon_type - = current_beacons->query( lon * SGD_RADIANS_TO_DEGREES, - lat * SGD_RADIANS_TO_DEGREES, elev ); - - outer_marker = middle_marker = inner_marker = false; - - if ( beacon_type == FGMkrBeacon::OUTER ) { - outer_marker = true; - // cout << "OUTER MARKER" << endl; -#ifdef ENABLE_AUDIO_SUPPORT - if ( last_beacon != FGMkrBeacon::OUTER ) { - if ( ! globals->get_soundmgr()->exists( "outer-marker" ) ) { - FGSimpleSound *sound = beacon.get_outer(); - sound->set_volume( 0.3 ); - globals->get_soundmgr()->add( sound, "outer-marker" ); - } - if ( !globals->get_soundmgr()->is_playing("outer-marker") ) { - globals->get_soundmgr()->play_looped( "outer-marker" ); - } - } -#endif - } else if ( beacon_type == FGMkrBeacon::MIDDLE ) { - middle_marker = true; - // cout << "MIDDLE MARKER" << endl; -#ifdef ENABLE_AUDIO_SUPPORT - if ( last_beacon != FGMkrBeacon::MIDDLE ) { - if ( ! globals->get_soundmgr()->exists( "middle-marker" ) ) { - FGSimpleSound *sound = beacon.get_middle(); - sound->set_volume( 0.3 ); - globals->get_soundmgr()->add( sound, "middle-marker" ); - } - if ( !globals->get_soundmgr()->is_playing("middle-marker") ) { - globals->get_soundmgr()->play_looped( "middle-marker" ); - } - } -#endif - } else if ( beacon_type == FGMkrBeacon::INNER ) { - inner_marker = true; - // cout << "INNER MARKER" << endl; -#ifdef ENABLE_AUDIO_SUPPORT - if ( last_beacon != FGMkrBeacon::INNER ) { - if ( ! globals->get_soundmgr()->exists( "inner-marker" ) ) { - FGSimpleSound *sound = beacon.get_inner(); - sound->set_volume( 0.3 ); - globals->get_soundmgr()->add( sound, "inner-marker" ); - } - if ( !globals->get_soundmgr()->is_playing("inner-marker") ) { - globals->get_soundmgr()->play_looped( "inner-marker" ); - } - } -#endif - } else { - // cout << "no marker" << endl; -#ifdef ENABLE_AUDIO_SUPPORT - globals->get_soundmgr()->stop( "outer-marker" ); - globals->get_soundmgr()->stop( "middle-marker" ); - globals->get_soundmgr()->stop( "inner-marker" ); -#endif - } - last_beacon = beacon_type; } diff --git a/src/Cockpit/radiostack.hxx b/src/Cockpit/radiostack.hxx index 17f5e6013..10d59cf09 100644 --- a/src/Cockpit/radiostack.hxx +++ b/src/Cockpit/radiostack.hxx @@ -41,37 +41,16 @@ #include "dme.hxx" #include "kr_87.hxx" // ADF #include "kt_70.hxx" // Transponder +#include "marker_beacon.hxx" #include "navcom.hxx" class FGRadioStack : public FGSubsystem { - FGBeacon beacon; - FGMorse morse; - - SGInterpTable *term_tbl; - SGInterpTable *low_tbl; - SGInterpTable *high_tbl; - - SGPropertyNode *lon_node; - SGPropertyNode *lat_node; - SGPropertyNode *alt_node; - SGPropertyNode *dme_bus_power; - - bool need_update; - - bool outer_marker; - bool middle_marker; - bool inner_marker; - - SGTimeStamp blink; - bool outer_blink; - bool middle_blink; - bool inner_blink; - FGDME dme; FGKR_87 adf; // King KR 87 Digital ADF model FGKT_70 xponder; // Bendix/King KT 70 Panel-Mounted Transponder + FGMarkerBeacon beacon; FGNavCom navcom1; FGNavCom navcom2; @@ -90,11 +69,6 @@ public: inline FGNavCom *get_navcom1() { return &navcom1; } inline FGNavCom *get_navcom2() { return &navcom2; } - - // Marker Beacon Accessors - inline bool get_inner_blink () const { return inner_blink; } - inline bool get_middle_blink () const { return middle_blink; } - inline bool get_outer_blink () const { return outer_blink; } };