From a2bd520a3baa6b5d1ad63aa3e578d8808e5cbcdc Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sun, 15 Jul 2012 20:05:10 +0200 Subject: [PATCH] ATISMgr clean-up / improvements Adds serviceable/operable properties to comm radio. Obey comm radio power source (no power => no radio => no ATIS). Also further clean-up to stuff belonging to former ATCmgr module. --- src/ATCDCL/ATC.cxx | 4 +- src/ATCDCL/ATC.hxx | 14 ++-- src/ATCDCL/ATISmgr.cxx | 121 ++++++------------------------ src/ATCDCL/ATISmgr.hxx | 53 +++----------- src/ATCDCL/atis.cxx | 163 +++++++++++++++++++++++++++++++++++------ src/ATCDCL/atis.hxx | 120 ++++++++++++++++-------------- 6 files changed, 245 insertions(+), 230 deletions(-) diff --git a/src/ATCDCL/ATC.cxx b/src/ATCDCL/ATC.cxx index 0f0e0f9e4..5e03ca383 100644 --- a/src/ATCDCL/ATC.cxx +++ b/src/ATCDCL/ATC.cxx @@ -77,7 +77,7 @@ FGATC::~FGATC() { #ifndef OLD_ATC_MGR // Derived classes wishing to use the response counter should // call this from their own Update(...). -void FGATC::Update(double dt) { +void FGATC::update(double dt) { #ifdef ENABLE_AUDIO_SUPPORT bool active = _atc_external->getBoolValue() || @@ -117,7 +117,7 @@ void FGATC::SetStation(flightgear::CommStation* sta) { freq = 0; SetNoDisplay(); - Update(0); // one last update + update(0); // one last update } else { diff --git a/src/ATCDCL/ATC.hxx b/src/ATCDCL/ATC.hxx index f709c1dcc..e57ebabd7 100644 --- a/src/ATCDCL/ATC.hxx +++ b/src/ATCDCL/ATC.hxx @@ -90,17 +90,17 @@ std::ostream& operator << (std::ostream& os, atc_type atc); class FGATC { friend class FGATISMgr; public: - + FGATC(); virtual ~FGATC(); - - virtual void Init()=0; - + + virtual void init()=0; + // Run the internal calculations // Derived classes should call this method from their own Update methods if they // wish to use the response timer functionality. - virtual void Update(double dt); - + virtual void update(double dt); + // Indicate that this instance should output to the display if appropriate inline void SetDisplay() { _display = true; } @@ -141,7 +141,7 @@ public: inline atc_type GetType() { return _type; } // Set the core ATC data - void SetStation(flightgear::CommStation* sta); + void SetStation(flightgear::CommStation* sta); inline const std::string& get_ident() { return ident; } inline void set_ident(const std::string& id) { ident = id; } diff --git a/src/ATCDCL/ATISmgr.cxx b/src/ATCDCL/ATISmgr.cxx index 0df65051e..1c5dc8ca7 100644 --- a/src/ATCDCL/ATISmgr.cxx +++ b/src/ATCDCL/ATISmgr.cxx @@ -27,24 +27,17 @@ #include #include -#include -#include #include
#include "ATISmgr.hxx" -#include "ATCutils.hxx" #include "atis.hxx" -using flightgear::CommStation; - FGATISMgr::FGATISMgr() : _currentUnit(0), - _maxCommRadios(4), + _maxCommRadios(4) #ifdef ENABLE_AUDIO_SUPPORT - voice(true), - voice1(0) -#else - voice(false) + ,useVoice(true), + voice(0) #endif { globals->set_ATIS_mgr(this); @@ -56,58 +49,36 @@ FGATISMgr::~FGATISMgr() for (unsigned int unit = 0;unit < _maxCommRadios; ++unit) { - delete radios[unit].station; - radios[unit].station = NULL; + delete radios[unit]; + radios[unit] = NULL; } #ifdef ENABLE_AUDIO_SUPPORT - delete voice1; + delete voice; #endif } -void FGATISMgr::bind() -{ -} - -void FGATISMgr::unbind() -{ -} - void FGATISMgr::init() { - lon_node = fgGetNode("/position/longitude-deg", true); - lat_node = fgGetNode("/position/latitude-deg", true); - elev_node = fgGetNode("/position/altitude-ft", true); - for (unsigned int unit = 0;unit < _maxCommRadios; ++unit) { - CommRadioData data; - string ncunit; if (unit < _maxCommRadios/2) - ncunit = "comm[" + decimalNumeral(unit) + "]"; + radios.push_back(new FGATIS("comm", unit)); else - ncunit = "nav[" + decimalNumeral(unit - _maxCommRadios/2) + "]"; - string commbase = "/instrumentation/" + ncunit; - string commfreq = commbase + "/frequencies/selected-mhz"; - - data.freq = fgGetNode(commfreq.c_str(), true); - data.station = new FGATIS(commbase); - radios.push_back(data); + radios.push_back(new FGATIS("nav", unit - _maxCommRadios/2)); } } + void FGATISMgr::update(double dt) { // update only runs every now and then (1-2 per second) if (++_currentUnit >= _maxCommRadios) _currentUnit = 0; - FGATC* pStation = radios[_currentUnit].station; - if (pStation) - pStation->Update(dt * _maxCommRadios); - - // Search the tuned frequencies - FreqSearch(_currentUnit); + FGATC* commRadio = radios[_currentUnit]; + if (commRadio) + commRadio->update(dt * _maxCommRadios); } // Return a pointer to an appropriate voice for a given type of ATC @@ -119,13 +90,13 @@ void FGATISMgr::update(double dt) // at different airports in quick succession if a large enough selection are available. FGATCVoice* FGATISMgr::GetVoicePointer(const atc_type& type) { +#ifdef ENABLE_AUDIO_SUPPORT // TODO - implement me better - maintain a list of loaded voices and other voices!! - if(voice) + if(useVoice) { switch(type) { case ATIS: case AWOS: -#ifdef ENABLE_AUDIO_SUPPORT // Delayed loading for all available voices, needed because the // sound manager might not be initialized (at all) at this point. // For now we'll do one hard-wired one @@ -135,22 +106,19 @@ FGATCVoice* FGATISMgr::GetVoicePointer(const atc_type& type) * subsequently switches /sim/sound/audible to true. * (which is the right thing to do -- CLO) :-) */ - if (!voice1 && fgGetBool("/sim/sound/working")) { - voice1 = new FGATCVoice; + if (!voice && fgGetBool("/sim/sound/working")) { + voice = new FGATCVoice; try { - voice = voice1->LoadVoice("default"); + useVoice = voice->LoadVoice("default"); } catch ( sg_io_exception & e) { SG_LOG(SG_ATC, SG_ALERT, "Unable to load default voice : " << e.getFormattedMessage().c_str()); - voice = false; - delete voice1; - voice1 = 0; + useVoice = false; + delete voice; + voice = 0; } } - if (voice) - return voice1; -#endif - return NULL; + return voice; case TOWER: return NULL; case APPROACH: @@ -161,52 +129,7 @@ FGATCVoice* FGATISMgr::GetVoicePointer(const atc_type& type) return NULL; } } +#endif return NULL; } - -class RangeFilter : public CommStation::Filter -{ -public: - RangeFilter( const SGGeod & pos ) : - CommStation::Filter(), - _cart(SGVec3d::fromGeod(pos)), - _pos(pos) - { - } - - virtual bool pass(FGPositioned* aPos) const - { - flightgear::CommStation * stn = dynamic_cast(aPos); - if( NULL == stn ) - return false; - - // do the range check in cartesian space, since the distances are potentially - // large enough that the geodetic functions become unstable - // (eg, station on opposite side of the planet) - double rangeM = SGMiscd::max( stn->rangeNm(), 10.0 ) * SG_NM_TO_METER; - double d2 = distSqr( aPos->cart(), _cart); - - return d2 <= (rangeM * rangeM); - } -private: - SGVec3d _cart; - SGGeod _pos; -}; - -// Search for ATC stations by frequency -void FGATISMgr::FreqSearch(const unsigned int unit) -{ - double frequency = radios[unit].freq->getDoubleValue(); - - // Note: 122.375 must be rounded DOWN to 12237 - // in order to be consistent with apt.dat et cetera. - int freqKhz = static_cast(frequency * 100.0 + 0.25); - - _aircraftPos = SGGeod::fromDegFt(lon_node->getDoubleValue(), - lat_node->getDoubleValue(), elev_node->getDoubleValue()); - - RangeFilter rangeFilter(_aircraftPos ); - CommStation* sta = CommStation::findByFreq(freqKhz, _aircraftPos, &rangeFilter ); - radios[unit].station->SetStation(sta); -} diff --git a/src/ATCDCL/ATISmgr.hxx b/src/ATCDCL/ATISmgr.hxx index 75ef3a30f..716044f83 100644 --- a/src/ATCDCL/ATISmgr.hxx +++ b/src/ATCDCL/ATISmgr.hxx @@ -19,55 +19,27 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -#ifndef _FG_ATCMGR_HXX -#define _FG_ATCMGR_HXX +#ifndef _FG_ATISMGR_HXX +#define _FG_ATISMGR_HXX -#include +#include -#include -#include -#include +#include #include "ATC.hxx" -namespace flightgear -{ - class CommStation; -} - -typedef struct -{ - SGPropertyNode_ptr freq; - FGATC* station; -} CommRadioData; - class FGATISMgr : public SGSubsystem { - private: // A vector containing all comm radios - typedef std::vector radio_list_type; - radio_list_type radios; - - // Any member function of FGATISMgr is permitted to leave this iterator pointing - // at any point in or at the end of the list. - // Hence any new access must explicitly first check for atc_list.end() before dereferencing. - - // Position of the Users Aircraft - SGGeod _aircraftPos; - - // Pointers to current users position - SGPropertyNode_ptr lon_node; - SGPropertyNode_ptr lat_node; - SGPropertyNode_ptr elev_node; + std::vector radios; unsigned int _currentUnit; unsigned int _maxCommRadios; - - // Voice related stuff - bool voice; // Flag - true if we are using voice + #ifdef ENABLE_AUDIO_SUPPORT - FGATCVoice* voice1; + bool useVoice; // Flag - true if we are using voice + FGATCVoice* voice; #endif public: @@ -75,11 +47,6 @@ public: ~FGATISMgr(); void init(); - - void bind(); - - void unbind(); - void update(double dt); // Return a pointer to an appropriate voice for a given type of ATC @@ -92,8 +59,6 @@ public: FGATCVoice* GetVoicePointer(const atc_type& type); private: - // Search the specified radio for stations on the same frequency and in range. - void FreqSearch(const unsigned int unit); }; -#endif // _FG_ATCMGR_HXX +#endif // _FG_ATISMGR_HXX diff --git a/src/ATCDCL/atis.cxx b/src/ATCDCL/atis.cxx index 95acc757b..36f2f66f0 100644 --- a/src/ATCDCL/atis.cxx +++ b/src/ATCDCL/atis.cxx @@ -55,6 +55,7 @@ #include #include +#include #include "ATCutils.hxx" #include "ATISmgr.hxx" @@ -65,8 +66,11 @@ using std::cout; using std::cout; using boost::ref; using boost::tie; +using flightgear::CommStation; -FGATIS::FGATIS(const string& commbase) : +FGATIS::FGATIS(const std::string& name, int num) : + _name(name), + _num(num), transmission(""), trans_ident(""), old_volume(0), @@ -74,10 +78,37 @@ FGATIS::FGATIS(const string& commbase) : msg_OK(0), attention(0), _prev_display(0), - _commbase(commbase) + _time_before_search_sec(0), + _last_frequency(0) { fgTie("/environment/attention", this, (int_getter)0, &FGATIS::attend); + _root = fgGetNode("/instrumentation", true)->getNode(_name, num, true); + _volume = _root->getNode("volume",true); + _serviceable = _root->getNode("serviceable",true); + + if (name != "nav") + { + // only drive "operable" for non-nav instruments (nav radio drives this separately) + _operable = _root->getNode("operable",true); + _operable->setBoolValue(false); + } + + _electrical = fgGetNode("/systems/electrical/outputs",true)->getNode(_name,num, true); + _atis = _root->getNode("atis",true); + _freq = _root->getNode("frequencies/selected-mhz",true); + + // current position + _lon_node = fgGetNode("/position/longitude-deg", true); + _lat_node = fgGetNode("/position/latitude-deg", true); + _elev_node = fgGetNode("/position/altitude-ft", true); + + // backward compatibility: some properties may not exist (but default to "ON") + if (!_serviceable->hasValue()) + _serviceable->setBoolValue(true); + if (!_electrical->hasValue()) + _electrical->setDoubleValue(24.0); + /////////////// // FIXME: This would be more flexible and more extensible // if the mappings were taken from an XML file, not hard-coded ... @@ -115,7 +146,7 @@ FGATCVoice* FGATIS::GetVoicePointer() return pAtisMgr->GetVoicePointer(ATIS); } -void FGATIS::Init() { +void FGATIS::init() { // Nothing to see here. Move along. } @@ -134,7 +165,7 @@ FGATIS::attend (int attn) // Main update function - checks whether we are displaying or not the correct message. -void FGATIS::Update(double dt) { +void FGATIS::update(double dt) { cur_time = globals->get_time_params()->get_cur_time(); msg_OK = (msg_time < cur_time); @@ -148,28 +179,52 @@ void FGATIS::Update(double dt) { } #endif - if(_display) + double volume = 0; + if ((_electrical->getDoubleValue()>8) && _serviceable->getBoolValue()) + { + _time_before_search_sec -= dt; + // radio is switched on and OK + if (_operable.valid()) + _operable->setBoolValue(true); + + // Search the tuned frequencies + search(); + + if (_display) + { + volume = _volume->getDoubleValue(); + } + } + else { - string prop = _commbase + "/volume"; - double volume = globals->get_props()->getDoubleValue(prop.c_str()); + // radio is OFF + if (_operable.valid()) + _operable->setBoolValue(false); + _time_before_search_sec = 0; + } -// Check if we need to update the message -// - basically every hour and if the weather changes significantly at the station -// If !_prev_display, the radio had been detuned for a while and our -// "transmission" variable was lost when we were de-instantiated. + if (volume > 0.05) + { + // Check if we need to update the message + // - basically every hour and if the weather changes significantly at the station + // If !_prev_display, the radio had been detuned for a while and our + // "transmission" variable was lost when we were de-instantiated. int changed = GenTransmission(!_prev_display, attention); + + // update output property TreeOut(msg_OK); + if (changed || volume != old_volume) { - //cout << "ATIS calling ATC::render volume: " << volume << endl; - Render(transmission, volume, _commbase, true); + // audio output enabled + Render(transmission, volume, _name, true); old_volume = volume; } + _prev_display = _display; } else { -// We shouldn't be displaying - //cout << "ATIS.CXX - calling NoRender()..." << endl; - NoRender(_commbase); + // silence + NoRender(_name); + _prev_display = false; } - _prev_display = _display; attention = 0; } @@ -522,10 +577,74 @@ int FGATIS::GenTransmission(const int regen, const int special) { // http://localhost:5400/instrumentation/comm[1] // // (Also, if in debug mode, dump it to the console.) -void FGATIS::TreeOut(int msg_OK){ - string prop = _commbase + "/atis"; - globals->get_props()->setStringValue(prop.c_str(), - ("
\n" + transmission_readable + "
\n").c_str()); - SG_LOG(SG_ATC, SG_DEBUG, "**** ATIS active on: " << prop << +void FGATIS::TreeOut(int msg_OK) +{ + _atis->setStringValue("
\n" + transmission_readable + "
\n"); + SG_LOG(SG_ATC, SG_DEBUG, "**** ATIS active on: " << _name << "transmission: " << transmission_readable); } + + + +class RangeFilter : public CommStation::Filter +{ +public: + RangeFilter( const SGGeod & pos ) : + CommStation::Filter(), + _cart(SGVec3d::fromGeod(pos)), + _pos(pos) + { + } + + virtual bool pass(FGPositioned* aPos) const + { + flightgear::CommStation * stn = dynamic_cast(aPos); + if( NULL == stn ) + return false; + + // do the range check in cartesian space, since the distances are potentially + // large enough that the geodetic functions become unstable + // (eg, station on opposite side of the planet) + double rangeM = SGMiscd::max( stn->rangeNm(), 10.0 ) * SG_NM_TO_METER; + double d2 = distSqr( aPos->cart(), _cart); + + return d2 <= (rangeM * rangeM); + } +private: + SGVec3d _cart; + SGGeod _pos; +}; + +// Search for ATC stations by frequency +void FGATIS::search(void) +{ + double frequency = _freq->getDoubleValue(); + + // Note: 122.375 must be rounded DOWN to 12237 + // in order to be consistent with apt.dat et cetera. + int freqKhz = static_cast(frequency * 100.0 + 0.25); + + // throttle frequency searches + if ((freqKhz == _last_frequency)&&(_time_before_search_sec > 0)) + return; + + _last_frequency = freqKhz; + _time_before_search_sec = 4.0; + + // Position of the Users Aircraft + SGGeod aircraftPos = SGGeod::fromDegFt(_lon_node->getDoubleValue(), + _lat_node->getDoubleValue(), + _elev_node->getDoubleValue()); + + RangeFilter rangeFilter(aircraftPos ); + CommStation* sta = CommStation::findByFreq(freqKhz, aircraftPos, &rangeFilter ); + SetStation(sta); + if (sta && sta->airport()) + { + SG_LOG(SG_ATC, SG_DEBUG, "FGATIS " << _name << ": " << sta->airport()->name()); + } + else + { + SG_LOG(SG_ATC, SG_DEBUG, "FGATIS " << _name << ": no station."); + } +} diff --git a/src/ATCDCL/atis.hxx b/src/ATCDCL/atis.hxx index 8a79e9fb2..bd67d8ec8 100644 --- a/src/ATCDCL/atis.hxx +++ b/src/ATCDCL/atis.hxx @@ -28,75 +28,83 @@ #include #include +#include #include "ATC.hxx" -//DCL - a complete guess for now. -#define FG_ATIS_DEFAULT_RANGE 30 - typedef std::map MSS; class FGATIS : public FGATC { - - //atc_type type; - - // The actual ATIS transmission - // This is generated from the prevailing conditions when required. - // This is the version with markup, suitable for voice synthesis: - std::string transmission; - - // Same as above, but in a form more readable as text. - std::string transmission_readable; - - // for failure modeling - std::string trans_ident; // transmitted ident - double old_volume; - bool atis_failed; // atis failed? - time_t msg_time; // for moderating error messages - time_t cur_time; - int msg_OK; - int attention; - - bool _prev_display; // Previous value of _display flag - MSS _remap; // abbreviations to be expanded - - std::string _commbase; - - // Aircraft position - // ATIS is actually a special case in that unlike other ATC eg.tower it doesn't actually know about - // or the whereabouts of the aircraft it is transmitting to. However, to ensure consistancy of - // operation with the other ATC classes the ATIS class must calculate range to the aircraft in order - // to decide whether to render the transmission - hence the users plane details must be stored. - //SGPropertyNode_ptr airplane_lon_node; - //SGPropertyNode_ptr airplane_lat_node; - //SGPropertyNode_ptr airplane_elev_node; - + + std::string _name; + int _num; + + SGPropertyNode_ptr _root; + SGPropertyNode_ptr _volume; + SGPropertyNode_ptr _serviceable; + SGPropertyNode_ptr _operable; + SGPropertyNode_ptr _electrical; + SGPropertyNode_ptr _freq; + SGPropertyNode_ptr _atis; + + // Pointers to current users position + SGPropertyNode_ptr _lon_node; + SGPropertyNode_ptr _lat_node; + SGPropertyNode_ptr _elev_node; + + // The actual ATIS transmission + // This is generated from the prevailing conditions when required. + // This is the version with markup, suitable for voice synthesis: + std::string transmission; + + // Same as above, but in a form more readable as text. + std::string transmission_readable; + + // for failure modeling + std::string trans_ident; // transmitted ident + double old_volume; + bool atis_failed; // atis failed? + time_t msg_time; // for moderating error messages + time_t cur_time; + int msg_OK; + int attention; + + bool _prev_display; // Previous value of _display flag + MSS _remap; // abbreviations to be expanded + + // internal periodic station search timer + double _time_before_search_sec; + int _last_frequency; + public: - - FGATIS(const std::string& commbase); - ~FGATIS(void); - virtual void Init(); - void attend (int); - - //run the ATIS instance - void Update(double dt); - - //inline void set_type(const atc_type tp) {type = tp;} - inline const std::string& get_trans_ident() { return trans_ident; } - + + FGATIS(const std::string& name, int num); + ~FGATIS(void); + virtual void init(); + void attend (int); + + //run the ATIS instance + void update(double dt); + + //inline void set_type(const atc_type tp) {type = tp;} + inline const std::string& get_trans_ident() { return trans_ident; } + protected: virtual FGATCVoice* GetVoicePointer(); private: - // Generate the ATIS transmission text: - int GenTransmission(const int regen, const int special); - - // Put the text into the property tree - // (and in debug mode, print it on the console): - void TreeOut(int msgOK); + // Generate the ATIS transmission text: + int GenTransmission(const int regen, const int special); + + // Put the text into the property tree + // (and in debug mode, print it on the console): + void TreeOut(int msgOK); + + // Search the specified radio for stations on the same frequency and in range. + void search(void); - friend std::istream& operator>> ( std::istream&, FGATIS& ); + friend std::istream& operator>> ( std::istream&, FGATIS& ); }; -- 2.39.5