1
0
Fork 0

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.
This commit is contained in:
ThorstenB 2012-07-15 20:05:10 +02:00
parent ec739a17c2
commit a2bd520a3b
6 changed files with 240 additions and 225 deletions

View file

@ -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
{

View file

@ -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; }

View file

@ -27,24 +27,17 @@
#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);
@ -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<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);
}

View file

@ -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 <vector>
#include <simgear/structure/subsystem_mgr.hxx>
#include <string>
#include <list>
#include <map>
#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:
@ -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

View file

@ -55,6 +55,7 @@
#include <Airports/runways.hxx>
#include <Airports/dynamics.hxx>
#include <ATC/CommStation.hxx>
#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())
{
string prop = _commbase + "/volume";
double volume = globals->get_props()->getDoubleValue(prop.c_str());
_time_before_search_sec -= dt;
// radio is switched on and OK
if (_operable.valid())
_operable->setBoolValue(true);
// 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.
// Search the tuned frequencies
search();
if (_display)
{
volume = _volume->getDoubleValue();
}
}
else
{
// radio is OFF
if (_operable.valid())
_operable->setBoolValue(false);
_time_before_search_sec = 0;
}
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(),
("<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.");
}
}

View file

@ -28,75 +28,83 @@
#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;
std::string _name;
int _num;
// 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
SGPropertyNode_ptr _root;
SGPropertyNode_ptr _volume;
SGPropertyNode_ptr _serviceable;
SGPropertyNode_ptr _operable;
SGPropertyNode_ptr _electrical;
SGPropertyNode_ptr _freq;
SGPropertyNode_ptr _atis;
std::string _commbase;
// 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;
// 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;
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);
friend std::istream& operator>> ( std::istream&, FGATIS& );
// 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& );
};