From a2922e2e23837683e41480680174015e7035ec02 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sat, 12 May 2012 23:27:57 +0200 Subject: [PATCH] ATCDCL cleanup, part II. Remove/comment out obsolete code. Refactor ATCmgr(-old) into ATISmgr(-new), only keeping the COM radio / ATIS support. --- src/ATCDCL/ATC.cxx | 156 +++++++++---- src/ATCDCL/ATC.hxx | 63 +++-- src/ATCDCL/ATCmgr.cxx | 308 ------------------------- src/ATCDCL/ATISmgr.cxx | 208 +++++++++++++++++ src/ATCDCL/{ATCmgr.hxx => ATISmgr.hxx} | 63 ++--- src/ATCDCL/CMakeLists.txt | 4 +- src/ATCDCL/atis.cxx | 69 +++--- src/ATCDCL/atis.hxx | 16 +- src/Main/fg_init.cxx | 15 +- src/Main/globals.cxx | 6 +- src/Main/globals.hxx | 8 +- src/Main/main.cxx | 20 +- 12 files changed, 424 insertions(+), 512 deletions(-) delete mode 100644 src/ATCDCL/ATCmgr.cxx create mode 100644 src/ATCDCL/ATISmgr.cxx rename src/ATCDCL/{ATCmgr.hxx => ATISmgr.hxx} (55%) diff --git a/src/ATCDCL/ATC.cxx b/src/ATCDCL/ATC.cxx index 2653d442f..59825d25e 100644 --- a/src/ATCDCL/ATC.cxx +++ b/src/ATCDCL/ATC.cxx @@ -35,9 +35,13 @@ #include FGATC::FGATC() : + freq(0), + _currentStation(NULL), + range(0), + _voice(true), _playing(false), - _voiceOK(false), _sgr(NULL), +#ifdef OLD_ATC_MGR freqClear(true), receiving(false), respond(false), @@ -45,22 +49,25 @@ FGATC::FGATC() : runResponseCounter(false), _runReleaseCounter(false), responseReqd(false), - _type(INVALID), - _display(false), // Transmission timing stuff pending_transmission(""), - _timeout(0), +#endif + _type(INVALID), + _display(false) +#ifdef OLD_ATC_MGR + ,_timeout(0), _pending(false), _transmit(false), _transmitting(false), _counter(0.0), _max_count(5.0) +#endif { SGSoundMgr *smgr = globals->get_soundmgr(); _sgr = smgr->find("atc", true); - _sgr->tie_to_listener(); + _sgr->tie_to_listener(); - _volume = fgGetNode("/sim/sound/atc/volume", true); + _masterVolume = fgGetNode("/sim/sound/atc/volume", true); _enabled = fgGetNode("/sim/sound/atc/enabled", true); _atc_external = fgGetNode("/sim/sound/atc/external-view", true); _internal = fgGetNode("/sim/current-view/internal", true); @@ -72,6 +79,20 @@ FGATC::~FGATC() { // Derived classes wishing to use the response counter should // call this from their own Update(...). void FGATC::Update(double dt) { + +#ifdef ENABLE_AUDIO_SUPPORT + bool active = _atc_external->getBoolValue() || + _internal->getBoolValue(); + + if ( active && _enabled->getBoolValue() ) { + _sgr->set_volume( _masterVolume->getFloatValue() ); + _sgr->resume(); // no-op if already in resumed state + } else { + _sgr->suspend(); + } +#endif + +#ifdef OLD_ATC_MGR if(runResponseCounter) { //cout << responseCounter << '\t' << responseTime << '\n'; if(responseCounter >= responseTime) { @@ -112,18 +133,6 @@ void FGATC::Update(double dt) { } } -#ifdef ENABLE_AUDIO_SUPPORT - bool active = _atc_external->getBoolValue() || - _internal->getBoolValue(); - - if ( active && _enabled->getBoolValue() ) { - _sgr->set_volume( _volume->getFloatValue() ); - _sgr->resume(); // no-op if already in resumed state - } else { - _sgr->suspend(); - } -#endif - if(_transmit) { _counter = 0.0; _max_count = 5.0; // FIXME - hardwired length of message - need to calculate it! @@ -149,8 +158,10 @@ void FGATC::Update(double dt) { } _counter += dt; } +#endif } +#ifdef OLD_ATC_MGR void FGATC::ReceiveUserCallback(int code) { SG_LOG(SG_ATC, SG_WARN, "WARNING - whichever ATC class was intended to receive callback code " << code << " didn't get it!!!"); } @@ -180,21 +191,45 @@ void FGATC::NotifyTransmissionFinished(const string& rid) { freqClear = true; } } +#endif void FGATC::SetStation(flightgear::CommStation* sta) { - switch (sta->type()) { - case FGPositioned::FREQ_ATIS: _type = ATIS; break; - case FGPositioned::FREQ_AWOS: _type = AWOS; break; - default: - throw sg_exception("unsupported comm station type"); + if (_currentStation == sta) + return; + _currentStation = sta; + + if (sta) + { + switch (sta->type()) { + case FGPositioned::FREQ_ATIS: _type = ATIS; break; + case FGPositioned::FREQ_AWOS: _type = AWOS; break; + default: + sta = NULL; + break; + } + } + + if (sta == NULL) + { + range = 0; + ident = ""; + name = ""; + freq = 0; + + SetNoDisplay(); + Update(0); // one last update + } + else + { + _geod = sta->geod(); + _cart = sta->cart(); + + range = sta->rangeNm(); + ident = sta->airport()->ident(); + name = sta->airport()->name(); + freq = sta->freqKHz(); + SetDisplay(); } - - _geod = sta->geod(); - _cart = sta->cart(); - range = sta->rangeNm(); - ident = sta->airport()->ident(); - name = sta->airport()->name(); - freq = sta->freqKHz(); } // Render a transmission @@ -203,7 +238,7 @@ void FGATC::SetStation(flightgear::CommStation* sta) { // The repeating flag indicates whether the message should be repeated continuously or played once. void FGATC::Render(string& msg, const float volume, const string& refname, const bool repeating) { - if (volume < 0.05) + if ((!_display) ||(volume < 0.05)) { NoRender(refname); return; @@ -215,35 +250,55 @@ void FGATC::Render(string& msg, const float volume, fgSetString("/sim/messages/atc", msg.c_str()); #ifdef ENABLE_AUDIO_SUPPORT - _voice = (_voiceOK && fgGetBool("/sim/sound/voice")); - if(_voice) { - size_t len; - void* buf = _vPtr->WriteMessage((char*)msg.c_str(), &len); - NoRender(refname); - if(buf) { - try { + bool useVoice = _voice && fgGetBool("/sim/sound/voice") && fgGetBool("/sim/sound/atc/enabled"); + SGSoundSample *simple = _sgr->find(refname); + if(useVoice) { + if (simple && (_currentMsg == msg)) + { + simple->set_volume(volume); + } + else + { + _currentMsg = msg; + size_t len; + void* buf = NULL; + if (!_vPtr) + _vPtr = GetVoicePointer(); + if (_vPtr) + buf = _vPtr->WriteMessage((char*)msg.c_str(), &len); + NoRender(refname); + if(buf) { + try { // >>> Beware: must pass a (new) object to the (add) method, // >>> because the (remove) method is going to do a (delete) // >>> whether that's what you want or not. - SGSoundSample *simple = new SGSoundSample(&buf, len, 8000); - simple->set_volume(volume); - _sgr->add(simple, refname); - _sgr->play(refname, repeating); - } catch ( sg_io_exception &e ) { - SG_LOG(SG_ATC, SG_ALERT, e.getFormattedMessage()); - } + simple = new SGSoundSample(&buf, len, 8000); + simple->set_volume(volume); + _sgr->add(simple, refname); + _sgr->play(refname, repeating); + } catch ( sg_io_exception &e ) { + SG_LOG(SG_ATC, SG_ALERT, e.getFormattedMessage()); + } + } } } + else + if (simple) + { + NoRender(refname); + } #endif // ENABLE_AUDIO_SUPPORT - if(!_voice) { - // first rip the underscores and the pause hints out of the string - these are for the convienience of the voice parser + + if (!useVoice) + { + // first rip the underscores and the pause hints out of the string - these are for the convenience of the voice parser for(unsigned int i = 0; i < msg.length(); ++i) { if((msg.substr(i,1) == "_") || (msg.substr(i,1) == "/")) { msg[i] = ' '; } } } - _playing = true; + _playing = true; } @@ -251,7 +306,7 @@ void FGATC::Render(string& msg, const float volume, void FGATC::NoRender(const string& refname) { if(_playing) { if(_voice) { -#ifdef ENABLE_AUDIO_SUPPORT +#ifdef ENABLE_AUDIO_SUPPORT _sgr->stop(refname); _sgr->remove(refname); #endif @@ -260,6 +315,7 @@ void FGATC::NoRender(const string& refname) { } } +#ifdef OLD_ATC_MGR // Generate the text of a message from its parameters and the current context. string FGATC::GenText(const string& m, int c) { return(""); @@ -336,4 +392,4 @@ std::istream& operator >> ( std::istream& fin, ATCData& a ) a.cart = SGVec3d::fromGeod(a.geod); return fin >> skipeol; } - +#endif diff --git a/src/ATCDCL/ATC.hxx b/src/ATCDCL/ATC.hxx index 17f743cd7..f709c1dcc 100644 --- a/src/ATCDCL/ATC.hxx +++ b/src/ATCDCL/ATC.hxx @@ -42,20 +42,6 @@ namespace flightgear class CommStation; } -// Convert a frequency in MHz to tens of kHz -// so we can use it e.g. as an index into commlist_freq -// -// If freq > 1000 assume it's already in tens of KHz; -// otherwise assume MHz. -// -// Note: 122.375 must be rounded DOWN to 12237 -// in order to be consistent with apt.dat et cetera. -inline int kHz10(double freq) -{ - if (freq > 1000.) return int(freq); - return int(freq*100.0 + 0.25); -} - // Possible types of ATC type that the radios may be tuned to. // INVALID implies not tuned in to anything. enum atc_type { @@ -69,6 +55,7 @@ enum atc_type { INVALID /* must be last element; see ATC_NUM_TYPES */ }; +#ifdef OLD_ATC_MGR const int ATC_NUM_TYPES = 1 + INVALID; // DCL - new experimental ATC data store @@ -98,9 +85,10 @@ struct RunwayDetails { }; std::ostream& operator << (std::ostream& os, atc_type atc); +#endif class FGATC { - friend class FGATCMgr; + friend class FGATISMgr; public: FGATC(); @@ -113,15 +101,16 @@ public: // wish to use the response timer functionality. virtual void Update(double dt); - // Recieve a coded callback from the ATC menu system based on the user's selection - virtual void ReceiveUserCallback(int code); - // Indicate that this instance should output to the display if appropriate inline void SetDisplay() { _display = true; } // Indicate that this instance should not output to the display inline void SetNoDisplay() { _display = false; } +#ifdef OLD_ATC_MGR + // Receive a coded callback from the ATC menu system based on the user's selection + virtual void ReceiveUserCallback(int code); + // Generate the text of a message from its parameters and the current context. virtual std::string GenText(const std::string& m, int c); @@ -141,21 +130,24 @@ public: // AI traffic should check FreqClear() is true prior to transmitting. // The user will just have to wait for a gap in dialog as in real life. - // Return the type of ATC station that the class represents - inline atc_type GetType() { return _type; } - // Set the core ATC data - void SetStation(flightgear::CommStation* sta); inline int get_freq() const { return freq; } inline void set_freq(const int fq) {freq = fq;} inline int get_range() const { return range; } inline void set_range(const int rg) {range = rg;} +#endif + // Return the type of ATC station that the class represents + inline atc_type GetType() { return _type; } + + // Set the core ATC data + void SetStation(flightgear::CommStation* sta); + inline const std::string& get_ident() { return ident; } inline void set_ident(const std::string& id) { ident = id; } inline const std::string& get_name() { return name; } inline void set_name(const std::string& nm) { name = nm; } - + protected: // Render a transmission @@ -169,25 +161,26 @@ protected: // Requires the sound manager refname if audio, else "". void NoRender(const std::string& refname); + virtual FGATCVoice* GetVoicePointer() = 0; + SGGeod _geod; SGVec3d _cart; int freq; - std::map active_on; - + flightgear::CommStation* _currentStation; + int range; std::string ident; // Code of the airport its at. std::string name; // Name transmitted in the broadcast. + std::string _currentMsg; // Current message being transmitted - // Rendering related stuff bool _voice; // Flag - true if we are using voice - bool _playing; // Indicates a message in progress - bool _voiceOK; // Flag - true if at least one voice has loaded OK + bool _playing; // Indicates a message in progress FGATCVoice* _vPtr; SGSharedPtr _sgr; // default sample group; - +#ifdef OLD_ATC_MGR bool freqClear; // Flag to indicate if the frequency is clear of ongoing dialog bool receiving; // Flag to indicate we are receiving a transmission @@ -204,11 +197,14 @@ protected: bool responseReqd; // Flag to indicate we should be responding to a request/report double _releaseTime; double _releaseCounter; + std::string pending_transmission; // derived classes set this string before calling Transmit(...) +#endif atc_type _type; bool _display; // Flag to indicate whether we should be outputting to the ATC display. - std::string pending_transmission; // derived classes set this string before calling Transmit(...) - + private: + +#ifdef OLD_ATC_MGR // Transmission timing stuff. double _timeout; bool _pending; @@ -216,13 +212,16 @@ private: bool _transmitting; // we are transmitting double _counter; double _max_count; +#endif - SGPropertyNode_ptr _volume; + SGPropertyNode_ptr _masterVolume; SGPropertyNode_ptr _enabled; SGPropertyNode_ptr _atc_external; SGPropertyNode_ptr _internal; }; +#ifdef OLD_ATC_MGR std::istream& operator>> ( std::istream& fin, ATCData& a ); +#endif #endif // _FG_ATC_HXX diff --git a/src/ATCDCL/ATCmgr.cxx b/src/ATCDCL/ATCmgr.cxx deleted file mode 100644 index 110fecc0f..000000000 --- a/src/ATCDCL/ATCmgr.cxx +++ /dev/null @@ -1,308 +0,0 @@ -// ATCmgr.cxx - Implementation of FGATCMgr - a global Flightgear ATC manager. -// -// Written by David Luff, started February 2002. -// -// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk -// -// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include - -#include -#include -#include
- -#include "ATCmgr.hxx" -#include "ATCutils.hxx" -#include "atis.hxx" - -using flightgear::CommStation; - -FGATCMgr::FGATCMgr() : - initDone(false), - atc_list(new atc_list_type), -#ifdef ENABLE_AUDIO_SUPPORT - voice(true), - voiceOK(false), - v1(0) -#else - voice(false), -#endif -{ - globals->set_ATC_mgr(this); -} - -FGATCMgr::~FGATCMgr() { - globals->set_ATC_mgr(NULL); - delete v1; -} - -void FGATCMgr::bind() { -} - -void FGATCMgr::unbind() { -} - -void FGATCMgr::init() { - //cout << "ATCMgr::init called..." << endl; - - lon_node = fgGetNode("/position/longitude-deg", true); - lat_node = fgGetNode("/position/latitude-deg", true); - elev_node = fgGetNode("/position/altitude-ft", true); - atc_list_itr = atc_list->begin(); - - // Search for connected ATC stations once per 0.8 seconds or so - // globals->get_event_mgr()->add( "fgATCSearch()", fgATCSearch, - // FGEvent::FG_EVENT_READY, 800); - // - // For some reason the above doesn't compile - including Time/event.hxx stops compilation. - // Is this still true after the reorganization of the event managar?? - // -EMH- - - initDone = true; - //cout << "ATCmgr::init done!" << endl; -} - -void FGATCMgr::update(double dt) { - if(!initDone) { - init(); - SG_LOG(SG_ATC, SG_WARN, "Warning - ATCMgr::update(...) called before ATCMgr::init()"); - } - - //cout << "Entering update..." << endl; - //Traverse the list of active stations. - //Only update one class per update step to avoid the whole ATC system having to calculate between frames. - //Eventually we should only update every so many steps. - //cout << "In FGATCMgr::update - atc_list.size = " << atc_list->size() << endl; - if(atc_list->size()) { - if(atc_list_itr == atc_list->end()) { - atc_list_itr = atc_list->begin(); - } - //cout << "Updating " << (*atc_list_itr)->get_ident() << ' ' << (*atc_list_itr)->GetType() << '\n'; - //cout << "Freq = " << (*atc_list_itr)->get_freq() << '\n'; - //cout << "Updating...\n"; - (*atc_list_itr).second->Update(dt * atc_list->size()); - //cout << "Done ATC update..." << endl; - ++atc_list_itr; - } - -#ifdef ATC_TEST - //cout << "ATC_LIST: " << atc_list->size() << ' '; - for(atc_list_iterator it = atc_list->begin(); it != atc_list->end(); it++) { - cout << (*it)->get_ident() << ' '; - } - //cout << '\n'; -#endif - - // Search the tuned frequencies every now and then - this should be done with the event scheduler - static int i = 0; // Very ugly - but there should only ever be one instance of FGATCMgr. - if(i == 15) { - //cout << "About to search navcomm1" << endl; - FreqSearch("comm", 0); - FreqSearch("nav", 0); - } - if(i == 30) { - //cout << "About to search navcomm2" << endl; - FreqSearch("comm", 1); - FreqSearch("nav", 1); - i = 0; - } - ++i; - - //cout << "comm1 type = " << comm_type[0] << '\n'; - //cout << "Leaving update..." << endl; -} - -typedef map MSI; - -void FGATCMgr::ZapOtherService(const string ncunit, const string svc_name){ - for (atc_list_iterator svc = atc_list->begin(); svc != atc_list->end(); svc++) { - - if (svc->first != svc_name) { - MSI &actv = svc->second->active_on; - // OK, we have found some OTHER service; - // see if it is (was) active on our unit: - if (!actv.count(ncunit)) continue; - //cout << "Eradicating '" << svc->first << "' from: " << ncunit << endl; - actv.erase(ncunit); - if (!actv.size()) { - //cout << "Eradicating service: '" << svc->first << "'" << endl; - svc->second->SetNoDisplay(); - svc->second->Update(0); // one last update - SG_LOG(SG_ATC, SG_INFO, "would have erased ATC service:" << svc->second->get_name()<< "/" - << svc->second->get_ident()); - // delete svc->second; - atc_list->erase(svc); - // ALL pointers into the ATC list are now invalid, - // so let's reset them: - atc_list_itr = atc_list->begin(); - } - break; // cannot be duplicates in the active list - } - } -} - -// Find in list - return a currently active ATC pointer given ICAO code and type -// Return NULL if the given service is not in the list -// - *** THE CALLING FUNCTION MUST CHECK FOR THIS *** -FGATC* FGATCMgr::FindInList(const string& id, const atc_type& tp) { - string ndx = id + decimalNumeral(tp); - if (!atc_list->count(ndx)) return 0; - return (*atc_list)[ndx]; -} - -// Return a pointer to an appropriate voice for a given type of ATC -// creating the voice if necessary - ie. make sure exactly one copy -// of every voice in use exists in memory. -// -// TODO - in the future this will get more complex and dole out country/airport -// specific voices, and possible make sure that the same voice doesn't get used -// at different airports in quick succession if a large enough selection are available. -FGATCVoice* FGATCMgr::GetVoicePointer(const atc_type& type) { - // TODO - implement me better - maintain a list of loaded voices and other voices!! - if(voice) { - switch(type) { - case ATIS: case AWOS: -#ifdef ENABLE_AUDIO_SUPPORT - // Delayed loading fo all available voices, needed because the - // soundmanager might not be initialized (at all) at this point. - // For now we'll do one hardwired one - - /* I've loaded the voice even if /sim/sound/pause is true - * since I know no way of forcing load of the voice if the user - * subsequently switches /sim/sound/audible to true. - * (which is the right thing to do -- CLO) :-) - */ - if (!voiceOK && fgGetBool("/sim/sound/working")) { - v1 = new FGATCVoice; - try { - voiceOK = v1->LoadVoice("default"); - voice = voiceOK; - } catch ( sg_io_exception & e) { - voiceOK = false; - SG_LOG(SG_ATC, SG_ALERT, "Unable to load default voice : " - << e.getFormattedMessage().c_str()); - voice = false; - delete v1; - v1 = 0; - } - } -#endif - if(voiceOK) { - return(v1); - } - case TOWER: - return(NULL); - case APPROACH: - return(NULL); - case GROUND: - return(NULL); - default: - return(NULL); - } - return(NULL); - } else { - return(NULL); - } -} - -// Search for ATC stations by frequency -void FGATCMgr::FreqSearch(const string navcomm, const int unit) { - - - string ncunit = navcomm + "[" + decimalNumeral(unit) + "]"; - string commbase = "/instrumentation/" + ncunit; - string commfreq = commbase + "/frequencies/selected-mhz"; - SGPropertyNode_ptr comm_node = fgGetNode(commfreq.c_str(), false); - - //cout << "FreqSearch: " << ncunit - // << " node: " << comm_node << endl; - if (!comm_node) return; // no such radio unit - - ATCData data; - // Note: 122.375 must be rounded DOWN to 12237 - // in order to be consistent with apt.dat et cetera. - int freqKhz = static_cast(comm_node->getDoubleValue() * 100.0 + 0.25); - - _aircraftPos = SGGeod::fromDegFt(lon_node->getDoubleValue(), - lat_node->getDoubleValue(), elev_node->getDoubleValue()); - - 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; - }; - - RangeFilter rangeFilter(_aircraftPos ); - - CommStation* sta = CommStation::findByFreq(freqKhz, _aircraftPos, &rangeFilter ); - if (!sta) { - ZapOtherService(ncunit, "x x x"); - return; - } - - // Get rid of any *other* service that was on this radio unit: - FGPositioned::Type ty = sta->type(); - string svc_name = sta->ident() + FGPositioned::nameForType(ty); - ZapOtherService(ncunit, svc_name); - // See if the service already exists, possibly connected to - // some other radio unit: - if (atc_list->count(svc_name)) { - // make sure the service knows it's tuned on this radio: - FGATC* svc = (*atc_list)[svc_name]; - svc->active_on[ncunit] = 1; - svc->SetDisplay(); - return; - } - - // This was a switch-case statement but the compiler didn't like - // the new variable creation with it. - if(ty == FGPositioned::FREQ_ATIS || ty == FGPositioned::FREQ_AWOS) { - (*atc_list)[svc_name] = new FGATIS; - FGATC* svc = (*atc_list)[svc_name]; - if(svc != NULL) { - svc->SetStation(sta); - svc->active_on[ncunit] = 1; - svc->SetDisplay(); - svc->Init(); - } - } - -} diff --git a/src/ATCDCL/ATISmgr.cxx b/src/ATCDCL/ATISmgr.cxx new file mode 100644 index 000000000..bfe1e6314 --- /dev/null +++ b/src/ATCDCL/ATISmgr.cxx @@ -0,0 +1,208 @@ +// ATISmgr.cxx - Implementation of FGATISMgr - a global Flightgear ATIS manager. +// +// Written by David Luff, started February 2002. +// +// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk +// Copyright (C) 2012 Thorsten Brehm +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include +#include +#include
+ +#include "ATISmgr.hxx" +#include "ATCutils.hxx" +#include "atis.hxx" + +using flightgear::CommStation; + +FGATISMgr::FGATISMgr() : + _currentUnit(0), + _maxCommRadios(2), +#ifdef ENABLE_AUDIO_SUPPORT + voice(true), + voice1(0) +#else + voice(false) +#endif +{ + globals->set_ATIS_mgr(this); +} + +FGATISMgr::~FGATISMgr() +{ + globals->set_ATIS_mgr(NULL); + + for (unsigned int unit = 0;unit < _maxCommRadios; ++unit) + { + delete radios[unit].station; + radios[unit].station = NULL; + } + +#ifdef ENABLE_AUDIO_SUPPORT + delete voice1; +#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 = "comm[" + decimalNumeral(unit) + "]"; + 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); + } +} + +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); +} + +// Return a pointer to an appropriate voice for a given type of ATC +// creating the voice if necessary - i.e. make sure exactly one copy +// of every voice in use exists in memory. +// +// TODO - in the future this will get more complex and dole out country/airport +// specific voices, and possible make sure that the same voice doesn't get used +// at different airports in quick succession if a large enough selection are available. +FGATCVoice* FGATISMgr::GetVoicePointer(const atc_type& type) +{ + // TODO - implement me better - maintain a list of loaded voices and other voices!! + if(voice) + { + 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 + + /* I've loaded the voice even if /sim/sound/pause is true + * since I know no way of forcing load of the voice if the user + * subsequently switches /sim/sound/audible to true. + * (which is the right thing to do -- CLO) :-) + */ + if (!voice1 && fgGetBool("/sim/sound/working")) { + voice1 = new FGATCVoice; + try { + voice = voice1->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; + } + } + if (voice) + return voice1; +#endif + return NULL; + case TOWER: + return NULL; + case APPROACH: + return NULL; + case GROUND: + return NULL; + default: + return NULL; + } + } + + 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/ATCmgr.hxx b/src/ATCDCL/ATISmgr.hxx similarity index 55% rename from src/ATCDCL/ATCmgr.hxx rename to src/ATCDCL/ATISmgr.hxx index 179f65fc3..75ef3a30f 100644 --- a/src/ATCDCL/ATCmgr.hxx +++ b/src/ATCDCL/ATISmgr.hxx @@ -1,5 +1,5 @@ -// ATCMgr.hxx - definition of FGATCMgr -// - a global management class for FlightGear generated ATC +// ATISmgr.hxx - definition of FGATISMgr +// - a global management class for FlightGear generated ATIS // // Written by David Luff, started February 2002. // @@ -30,23 +30,26 @@ #include "ATC.hxx" -class FGATCMgr : public SGSubsystem +namespace flightgear { + class CommStation; +} -private: +typedef struct +{ + SGPropertyNode_ptr freq; + FGATC* station; +} CommRadioData; - bool initDone; // Hack - guard against update getting called before init +class FGATISMgr : public SGSubsystem +{ - // A list of pointers to all currently active ATC classes - typedef std::map atc_list_type; - typedef atc_list_type::iterator atc_list_iterator; - typedef atc_list_type::const_iterator atc_list_const_iterator; +private: + // A vector containing all comm radios + typedef std::vector radio_list_type; + radio_list_type radios; - // Everything put in this list should be created dynamically - // on the heap and ***DELETED WHEN REMOVED!!!!!*** - atc_list_type* atc_list; - atc_list_iterator atc_list_itr; - // Any member function of FGATCMgr is permitted to leave this iterator pointing + // 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. @@ -58,19 +61,18 @@ private: SGPropertyNode_ptr lat_node; SGPropertyNode_ptr elev_node; - //FGATIS atis; + unsigned int _currentUnit; + unsigned int _maxCommRadios; // Voice related stuff bool voice; // Flag - true if we are using voice #ifdef ENABLE_AUDIO_SUPPORT - bool voiceOK; // Flag - true if at least one voice has loaded OK - FGATCVoice* v1; + FGATCVoice* voice1; #endif public: - - FGATCMgr(); - ~FGATCMgr(); + FGATISMgr(); + ~FGATISMgr(); void init(); @@ -80,35 +82,18 @@ public: void update(double dt); - // Return a pointer to an appropriate voice for a given type of ATC - // creating the voice if necessary - ie. make sure exactly one copy + // creating the voice if necessary - i.e. make sure exactly one copy // of every voice in use exists in memory. // // TODO - in the future this will get more complex and dole out country/airport // specific voices, and possible make sure that the same voice doesn't get used // at different airports in quick succession if a large enough selection are available. FGATCVoice* GetVoicePointer(const atc_type& type); - - atc_type GetComm1ATCType() { return(INVALID/* kludge */); } - FGATC* GetComm1ATCPointer() { return(0/* kludge */); } - atc_type GetComm2ATCType() { return(INVALID); } - FGATC* GetComm2ATCPointer() { return(0/* kludge */); } - private: - - // Remove a class from the atc_list and delete it from memory - // *if* no other comm channel or AI plane is using it. - void ZapOtherService(const std::string ncunit, const std::string svc_name); - - // Return a pointer to a class in the list given ICAO code and type - // Return NULL if the given service is not in the list - // - *** THE CALLING FUNCTION MUST CHECK FOR THIS *** - FGATC* FindInList(const std::string& id, const atc_type& tp); - // Search the specified radio for stations on the same frequency and in range. - void FreqSearch(const std::string navcomm, const int unit); + void FreqSearch(const unsigned int unit); }; #endif // _FG_ATCMGR_HXX diff --git a/src/ATCDCL/CMakeLists.txt b/src/ATCDCL/CMakeLists.txt index caeebbe33..fd1a3736b 100644 --- a/src/ATCDCL/CMakeLists.txt +++ b/src/ATCDCL/CMakeLists.txt @@ -4,7 +4,7 @@ set(SOURCES ATC.cxx atis.cxx ATCVoice.cxx - ATCmgr.cxx + ATISmgr.cxx ATCutils.cxx ATCProjection.cxx ) @@ -13,7 +13,7 @@ set(HEADERS ATC.hxx atis.hxx ATCVoice.hxx - ATCmgr.hxx + ATISmgr.hxx ATCutils.hxx ATCProjection.hxx atis_lexicon.hxx diff --git a/src/ATCDCL/atis.cxx b/src/ATCDCL/atis.cxx index b87369e1a..95acc757b 100644 --- a/src/ATCDCL/atis.cxx +++ b/src/ATCDCL/atis.cxx @@ -57,7 +57,7 @@ #include "ATCutils.hxx" -#include "ATCmgr.hxx" +#include "ATISmgr.hxx" using std::string; using std::map; @@ -66,7 +66,7 @@ using std::cout; using boost::ref; using boost::tie; -FGATIS::FGATIS() : +FGATIS::FGATIS(const string& commbase) : transmission(""), trans_ident(""), old_volume(0), @@ -74,20 +74,8 @@ FGATIS::FGATIS() : msg_OK(0), attention(0), _prev_display(0), - refname("atis") + _commbase(commbase) { - FGATCMgr* pAtcMgr = globals->get_ATC_mgr(); - if (!pAtcMgr) - { - SG_LOG(SG_ATC, SG_ALERT, "ERROR! No ATC manager! Oops..."); - _vPtr = NULL; - } - else - _vPtr = pAtcMgr->GetVoicePointer(ATIS); - _voiceOK = (_vPtr == NULL ? false : true); - if (!(_type != ATIS || _type == AWOS)) { - SG_LOG(SG_ATC, SG_ALERT, "ERROR - _type not ATIS or AWOS in atis.cxx"); - } fgTie("/environment/attention", this, (int_getter)0, &FGATIS::attend); /////////////// @@ -115,6 +103,18 @@ FGATIS::~FGATIS() { fgUntie("/environment/attention"); } +FGATCVoice* FGATIS::GetVoicePointer() +{ + FGATISMgr* pAtisMgr = globals->get_ATIS_mgr(); + if (!pAtisMgr) + { + SG_LOG(SG_ATC, SG_ALERT, "ERROR! No ATIS manager! Oops..."); + return NULL; + } + + return pAtisMgr->GetVoicePointer(ATIS); +} + void FGATIS::Init() { // Nothing to see here. Move along. } @@ -137,6 +137,7 @@ FGATIS::attend (int attn) void FGATIS::Update(double dt) { cur_time = globals->get_time_params()->get_cur_time(); msg_OK = (msg_time < cur_time); + #ifdef ATIS_TEST if (msg_OK || _display != _prev_display) { cout << "ATIS Update: " << _display << " " << _prev_display @@ -146,29 +147,27 @@ void FGATIS::Update(double dt) { msg_time = cur_time; } #endif - if(_display) { - double volume(0); - for (map::iterator act = active_on.begin(); - act != active_on.end(); act++) { - string prop = "/instrumentation/" + act->first + "/volume"; - volume += globals->get_props()->getDoubleValue(prop.c_str()); - } + + if(_display) + { + string prop = _commbase + "/volume"; + double volume = globals->get_props()->getDoubleValue(prop.c_str()); // 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 rslt = GenTransmission(!_prev_display, attention); + int changed = GenTransmission(!_prev_display, attention); TreeOut(msg_OK); - if (rslt || volume != old_volume) { + if (changed || volume != old_volume) { //cout << "ATIS calling ATC::render volume: " << volume << endl; - Render(transmission, volume, refname, true); + Render(transmission, volume, _commbase, true); old_volume = volume; } } else { // We shouldn't be displaying //cout << "ATIS.CXX - calling NoRender()..." << endl; - NoRender(refname); + NoRender(_commbase); } _prev_display = _display; attention = 0; @@ -517,26 +516,16 @@ int FGATIS::GenTransmission(const int regen, const int special) { return 1; } -// Put the transmission into the property tree, -// possibly in multiple places if multiple radios -// are tuned to the same ATIS. +// Put the transmission into the property tree. // You can see it by pointing a web browser // at the property tree. The second comm radio is: // http://localhost:5400/instrumentation/comm[1] // // (Also, if in debug mode, dump it to the console.) void FGATIS::TreeOut(int msg_OK){ - for (map::iterator act = active_on.begin(); - act != active_on.end(); - act++){ - string prop = "/instrumentation/" + act->first + "/atis"; + string prop = _commbase + "/atis"; globals->get_props()->setStringValue(prop.c_str(), ("
\n" + transmission_readable + "
\n").c_str()); -#ifdef ATIS_TEST - if (msg_OK) cout << "**** ATIS active on: " << prop << endl; -#endif - } -#ifdef ATIS_TEST - if (msg_OK) cout << transmission_readable << endl; -#endif + SG_LOG(SG_ATC, SG_DEBUG, "**** ATIS active on: " << prop << + "transmission: " << transmission_readable); } diff --git a/src/ATCDCL/atis.hxx b/src/ATCDCL/atis.hxx index 0c6124b8d..8a79e9fb2 100644 --- a/src/ATCDCL/atis.hxx +++ b/src/ATCDCL/atis.hxx @@ -60,6 +60,8 @@ class FGATIS : public FGATC { 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 @@ -69,9 +71,9 @@ class FGATIS : public FGATC { //SGPropertyNode_ptr airplane_lat_node; //SGPropertyNode_ptr airplane_elev_node; - public: +public: - FGATIS(void); + FGATIS(const std::string& commbase); ~FGATIS(void); virtual void Init(); void attend (int); @@ -81,12 +83,12 @@ class FGATIS : public FGATC { //inline void set_type(const atc_type tp) {type = tp;} inline const std::string& get_trans_ident() { return trans_ident; } - inline void set_refname(const std::string& r) { refname = r; } - - private: - - std::string refname; // Holds the refname of a transmission in progress +protected: + virtual FGATCVoice* GetVoicePointer(); + +private: + // Generate the ATIS transmission text: int GenTransmission(const int regen, const int special); diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index ea323425c..b6b8c02cb 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -77,7 +77,7 @@ #include -#include +#include #include #include @@ -1158,27 +1158,20 @@ bool fgInitSubsystems() { //////////////////////////////////////////////////////////////////// fgGetBool("/sim/rendering/bump-mapping", false); - - //////////////////////////////////////////////////////////////////// - // Initialise the ATC Manager - // Note that this is old stuff, but might be necessesary for the + // Initialise the ATIS Manager + // Note that this is old stuff, but is necessary for the // current ATIS implementation. Therefore, leave it in here // until the ATIS system is ported over to make use of the ATIS // sub system infrastructure. //////////////////////////////////////////////////////////////////// - globals->add_subsystem("ATC-old", new FGATCMgr, SGSubsystemMgr::INIT); + globals->add_subsystem("ATIS", new FGATISMgr, SGSubsystemMgr::INIT, 0.4); //////////////////////////////////////////////////////////////////// // Initialize the ATC subsystem //////////////////////////////////////////////////////////////////// globals->add_subsystem("ATC", new FGATCManager, SGSubsystemMgr::POST_FDM); - //////////////////////////////////////////////////////////////////// - // Initialise the ATIS Subsystem - //////////////////////////////////////////////////////////////////// - //globals->add_subsystem("atis", new FGAtisManager, SGSubsystemMgr::POST_FDM); - //////////////////////////////////////////////////////////////////// // Initialize multiplayer subsystem diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx index 2dd696ba9..a2e702c89 100644 --- a/src/Main/globals.cxx +++ b/src/Main/globals.cxx @@ -44,7 +44,7 @@ #include #include -#include +#include #include #include #include @@ -135,7 +135,7 @@ FGGlobals::FGGlobals() : matlib( NULL ), route_mgr( NULL ), current_panel( NULL ), - ATC_mgr( NULL ), + ATIS_mgr( NULL ), controls( NULL ), viewmgr( NULL ), commands( SGCommandMgr::instance() ), @@ -191,7 +191,7 @@ FGGlobals::~FGGlobals() delete route_mgr; current_panel = NULL; - delete ATC_mgr; + delete ATIS_mgr; if (controls) { diff --git a/src/Main/globals.hxx b/src/Main/globals.hxx index 2788455e2..85292b58f 100644 --- a/src/Main/globals.hxx +++ b/src/Main/globals.hxx @@ -55,7 +55,7 @@ class SGSubsystemMgr; class SGSubsystem; class SGSoundMgr; -class FGATCMgr; +class FGATISMgr; class FGAircraftModel; class FGControls; class FGFlightPlanDispatcher; @@ -123,7 +123,7 @@ private: SGSharedPtr current_panel; // ATC manager - FGATCMgr *ATC_mgr; + FGATISMgr *ATIS_mgr; // control input state FGControls *controls; @@ -240,8 +240,8 @@ public: inline SGMaterialLib *get_matlib() const { return matlib; } inline void set_matlib( SGMaterialLib *m ) { matlib = m; } - inline FGATCMgr *get_ATC_mgr() const { return ATC_mgr; } - inline void set_ATC_mgr( FGATCMgr *a ) {ATC_mgr = a; } + inline FGATISMgr *get_ATIS_mgr() const { return ATIS_mgr; } + inline void set_ATIS_mgr( FGATISMgr *a ) {ATIS_mgr = a; } inline FGPanel *get_current_panel() const { return current_panel; } void set_current_panel( FGPanel *cp ); diff --git a/src/Main/main.cxx b/src/Main/main.cxx index ac3880f29..21cc87396 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -41,37 +41,24 @@ // Class references #include #include -#include -#include -#include #include #include #include -#include #include -#include #include #include +#include +#include +#include -#include