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.
#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() ||
freq = 0;
SetNoDisplay();
- Update(0); // one last update
+ update(0); // one last update
}
else
{
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; }
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; }
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/exception.hxx>
-#include <Airports/simple.hxx>
-#include <ATC/CommStation.hxx>
#include <Main/fg_props.hxx>
#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);
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
// 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
* 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:
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<flightgear::CommStation*>(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<int>(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);
-}
// 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 <simgear/structure/subsystem_mgr.hxx>
+#include <vector>
-#include <string>
-#include <list>
-#include <map>
+#include <simgear/structure/subsystem_mgr.hxx>
#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<CommRadioData> 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<FGATC*> 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:
~FGATISMgr();
void init();
-
- void bind();
-
- void unbind();
-
void update(double dt);
// Return a pointer to an appropriate voice for a given type of ATC
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
#include <Airports/runways.hxx>
#include <Airports/dynamics.hxx>
+#include <ATC/CommStation.hxx>
#include "ATCutils.hxx"
#include "ATISmgr.hxx"
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),
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 ...
return pAtisMgr->GetVoicePointer(ATIS);
}
-void FGATIS::Init() {
+void FGATIS::init() {
// Nothing to see here. Move along.
}
// 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);
}
#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;
}
// 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(),
- ("<pre>\n" + transmission_readable + "</pre>\n").c_str());
- SG_LOG(SG_ATC, SG_DEBUG, "**** ATIS active on: " << prop <<
+void FGATIS::TreeOut(int msg_OK)
+{
+ _atis->setStringValue("<pre>\n" + transmission_readable + "</pre>\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<flightgear::CommStation*>(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<int>(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.");
+ }
+}
#include <simgear/compiler.h>
#include <simgear/timing/sg_time.hxx>
+#include <simgear/props/props.hxx>
#include "ATC.hxx"
-//DCL - a complete guess for now.
-#define FG_ATIS_DEFAULT_RANGE 30
-
typedef std::map<std::string,std::string> 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& );
};