1
0
Fork 0

Merge branch 'next' of gitorious.org:fg/flightgear into next

This commit is contained in:
Curtis L. Olson 2011-02-28 08:10:15 -06:00
commit 12f694f06d
22 changed files with 2521 additions and 407 deletions

View file

@ -1819,6 +1819,10 @@
<File
RelativePath="..\..\src\instrumentation\wxradar.hxx"
>
</File>
<File
RelativePath="..\..\src\instrumentation\tcas.hxx"
>
</File>
<File
RelativePath="..\..\src\autopilot\xmlauto.hxx"
@ -3566,6 +3570,10 @@
RelativePath="..\..\src\instrumentation\wxradar.cxx"
>
</File>
<File
RelativePath="..\..\src\instrumentation\tcas.cxx"
>
</File>
<File
RelativePath="..\..\src\autopilot\xmlauto.cxx"
>

View file

@ -3784,6 +3784,14 @@
<File
RelativePath="..\..\..\src\Instrumentation\wxradar.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\tcas.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\tcas.hxx"
>
</File>
<Filter
Name="Lib_HUD"

View file

@ -332,6 +332,7 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
use_perf_vs = false;
tgt_vs = (curr->crossat - altitude_ft) / (fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr)
/ 6076.0 / speed*60.0);
checkTcas();
tgt_altitude_ft = curr->crossat;
} else {
use_perf_vs = true;
@ -343,6 +344,32 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
}
}
void FGAIAircraft::checkTcas(void)
{
if (props->getIntValue("tcas/threat-level",0)==3)
{
int RASense = props->getIntValue("tcas/ra-sense",0);
if ((RASense>0)&&(tgt_vs<4000))
// upward RA: climb!
tgt_vs = 4000;
else
if (RASense<0)
{
// downward RA: descend!
if (altitude_ft < 1000)
{
// too low: level off
if (tgt_vs>0)
tgt_vs = 0;
}
else
{
if (tgt_vs >- 4000)
tgt_vs = -4000;
}
}
}
}
void FGAIAircraft::initializeFlightPlan() {
}
@ -603,6 +630,7 @@ void FGAIAircraft::handleFirstWaypoint() {
tgt_vs = (curr->crossat - prev->altitude)
/ (fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr)
/ 6076.0 / prev->speed*60.0);
checkTcas();
tgt_altitude_ft = curr->crossat;
} else {
use_perf_vs = true;
@ -1025,6 +1053,7 @@ void FGAIAircraft::updateVerticalSpeedTarget() {
}
} //else
// tgt_vs = 0.0;
checkTcas();
}
void FGAIAircraft::updatePitchAngleTarget() {
@ -1183,4 +1212,4 @@ time_t FGAIAircraft::checkForArrivalTime(string wptName) {
cerr << "Checking arrival time: ete " << ete << ". Time to go : " << secondsToGo << ". Track length = " << tracklength << endl;
}
return (ete - secondsToGo); // Positive when we're too slow...
}
}

View file

@ -94,6 +94,7 @@ public:
inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
std::string atGate();
void checkTcas();
protected:
void Run(double dt);

View file

@ -39,11 +39,11 @@ FGAIMultiplayer::FGAIMultiplayer() : FGAIBase(otMultiplayer) {
mTimeOffsetSet = false;
mAllowExtrapolation = true;
mLagAdjustSystemSpeed = 10;
mLastTimestamp = 0;
aip.getSceneGraph()->setNodeMask(~SG_NODEMASK_TERRAIN_BIT);
lastUpdateTime = 0;
}
}
FGAIMultiplayer::~FGAIMultiplayer() {
}
@ -417,8 +417,21 @@ void FGAIMultiplayer::update(double dt)
// extract the position
pos = SGGeod::fromCart(ecPos);
double recent_alt_ft = altitude_ft;
altitude_ft = pos.getElevationFt();
// expose a valid vertical speed
if (lastUpdateTime != 0)
{
double dT = curtime - lastUpdateTime;
double Weighting=1;
if (dt < 1.0)
Weighting = dt;
// simple smoothing over 1 second
vs = (1.0-Weighting)*vs + Weighting * (altitude_ft - recent_alt_ft) / dT * 60;
}
lastUpdateTime = curtime;
// The quaternion rotating from the earth centered frame to the
// horizontal local frame
SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)pos.getLongitudeRad(),

View file

@ -78,6 +78,8 @@ private:
double mTimeOffset;
bool mTimeOffsetSet;
double lastUpdateTime;
/// Properties which are for now exposed for testing
bool mAllowExtrapolation;
double mLagAdjustSystemSpeed;

View file

@ -24,7 +24,7 @@
#define _REALWX_CTRL_HXX
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
namespace Environment {
class RealWxController : public SGSubsystem
{

View file

@ -31,6 +31,7 @@ set(SOURCES
rnav_waypt_controller.cxx
slip_skid_ball.cxx
tacan.cxx
tcas.cxx
transponder.cxx
turn_indicator.cxx
vertical_speed_indicator.cxx

View file

@ -33,6 +33,7 @@ libInstrumentation_a_SOURCES = \
render_area_2d.cxx render_area_2d.hxx \
groundradar.cxx groundradar.hxx \
agradar.cxx agradar.hxx rad_alt.cxx rad_alt.hxx \
rnav_waypt_controller.cxx rnav_waypt_controller.hxx
rnav_waypt_controller.cxx rnav_waypt_controller.hxx \
tcas.cxx tcas.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_builddir)/src

View file

@ -33,6 +33,7 @@
#include <map>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#include <Navaids/positioned.hxx>
class SGTime;

View file

@ -50,6 +50,7 @@
#include "groundradar.hxx"
#include "agradar.hxx"
#include "rad_alt.hxx"
#include "tcas.hxx"
FGInstrumentMgr::FGInstrumentMgr () :
_explicitGps(false)
@ -223,6 +224,9 @@ bool FGInstrumentMgr::build (SGPropertyNode* config_props)
} else if ( name == "radar-altimeter" ) {
set_subsystem( id, new radAlt( node ),1);
} else if ( name == "tcas" ) {
set_subsystem( id, new TCAS( node ) );
} else {
SG_LOG( SG_ALL, SG_ALERT, "Unknown top level section: "
<< name );

View file

@ -210,17 +210,6 @@ MK_VIII::PropertiesHandler::init ()
mk_node(vs) = fgGetNode("/velocities/vertical-speed-fps", true);
}
void
MK_VIII::PropertiesHandler::unbind ()
{
vector<SGPropertyNode_ptr>::iterator iter;
for (iter = tied_properties.begin(); iter != tied_properties.end(); iter++)
(*iter)->untie();
tied_properties.clear();
}
///////////////////////////////////////////////////////////////////////////////
// PowerHandler ///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@ -1858,7 +1847,8 @@ MK_VIII::IOHandler::tie_input (SGPropertyNode *node,
bool *input,
bool *feed)
{
mk->properties_handler.tie(node, (string("inputs/discretes/") + name).c_str(), RawValueMethodsData<MK_VIII::IOHandler, bool, bool *>(*this, input, &MK_VIII::IOHandler::get_discrete_input, &MK_VIII::IOHandler::set_discrete_input));
mk->properties_handler.tie(node, (string("inputs/discretes/") + name).c_str(),
FGVoicePlayer::RawValueMethodsData<MK_VIII::IOHandler, bool, bool *>(*this, input, &MK_VIII::IOHandler::get_discrete_input, &MK_VIII::IOHandler::set_discrete_input));
if (feed)
mk->properties_handler.tie(node, (string("input-feeders/discretes/") + name).c_str(), SGRawValuePointer<bool>(feed));
}
@ -2144,11 +2134,22 @@ MK_VIII::IOHandler::set_present_status (bool value)
///////////////////////////////////////////////////////////////////////////////
// VoicePlayer ////////////////////////////////////////////////////////////////
// FGVoicePlayer //////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void
MK_VIII::VoicePlayer::Speaker::bind (SGPropertyNode *node)
FGVoicePlayer::PropertiesHandler::unbind ()
{
vector<SGPropertyNode_ptr>::iterator iter;
for (iter = tied_properties.begin(); iter != tied_properties.end(); iter++)
(*iter)->untie();
tied_properties.clear();
}
void
FGVoicePlayer::Speaker::bind (SGPropertyNode *node)
{
// uses xmlsound property names
tie(node, "volume", &volume);
@ -2156,7 +2157,7 @@ MK_VIII::VoicePlayer::Speaker::bind (SGPropertyNode *node)
}
void
MK_VIII::VoicePlayer::Speaker::update_configuration ()
FGVoicePlayer::Speaker::update_configuration ()
{
map< string, SGSharedPtr<SGSoundSample> >::iterator iter;
for (iter = player->samples.begin(); iter != player->samples.end(); iter++)
@ -2170,7 +2171,7 @@ MK_VIII::VoicePlayer::Speaker::update_configuration ()
player->voice->volume_changed();
}
MK_VIII::VoicePlayer::Voice::~Voice ()
FGVoicePlayer::Voice::~Voice ()
{
for (iter = elements.begin(); iter != elements.end(); iter++)
delete *iter; // we owned the element
@ -2178,7 +2179,7 @@ MK_VIII::VoicePlayer::Voice::~Voice ()
}
void
MK_VIII::VoicePlayer::Voice::play ()
FGVoicePlayer::Voice::play ()
{
iter = elements.begin();
element = *iter;
@ -2187,7 +2188,7 @@ MK_VIII::VoicePlayer::Voice::play ()
}
void
MK_VIII::VoicePlayer::Voice::stop (bool now)
FGVoicePlayer::Voice::stop (bool now)
{
if (element)
{
@ -2202,21 +2203,21 @@ MK_VIII::VoicePlayer::Voice::stop (bool now)
}
void
MK_VIII::VoicePlayer::Voice::set_volume (float _volume)
FGVoicePlayer::Voice::set_volume (float _volume)
{
volume = _volume;
volume_changed();
}
void
MK_VIII::VoicePlayer::Voice::volume_changed ()
FGVoicePlayer::Voice::volume_changed ()
{
if (element)
element->set_volume(get_volume());
}
void
MK_VIII::VoicePlayer::Voice::update ()
FGVoicePlayer::Voice::update ()
{
if (element)
{
@ -2233,7 +2234,7 @@ MK_VIII::VoicePlayer::Voice::update ()
}
}
MK_VIII::VoicePlayer::~VoicePlayer ()
FGVoicePlayer::~FGVoicePlayer ()
{
vector<Voice *>::iterator iter1;
for (iter1 = _voices.begin(); iter1 != _voices.end(); iter1++)
@ -2243,85 +2244,80 @@ MK_VIII::VoicePlayer::~VoicePlayer ()
}
void
MK_VIII::VoicePlayer::init ()
FGVoicePlayer::bind (SGPropertyNode *node, const char* default_dir_prefix)
{
#define STDPAUSE 0.75 // [SPEC] 6.4.4: "the standard 0.75 second delay"
dir_prefix = node->getStringValue("voice/file-prefix", default_dir_prefix);
speaker.bind(node);
}
void
FGVoicePlayer::init ()
{
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("avionics", true);
_sgr->tie_to_listener();
make_voice(&voices.application_data_base_failed, "application-data-base-failed");
make_voice(&voices.bank_angle, "bank-angle");
make_voice(&voices.bank_angle_bank_angle, "bank-angle", "bank-angle");
make_voice(&voices.bank_angle_bank_angle_3, "bank-angle", "bank-angle", 3.0);
make_voice(&voices.bank_angle_inop, "bank-angle-inop");
make_voice(&voices.bank_angle_pause_bank_angle, "bank-angle", STDPAUSE, "bank-angle");
make_voice(&voices.bank_angle_pause_bank_angle_3, "bank-angle", STDPAUSE, "bank-angle", 3.0);
make_voice(&voices.callouts_inop, "callouts-inop");
make_voice(&voices.configuration_type_invalid, "configuration-type-invalid");
make_voice(&voices.dont_sink, "dont-sink");
make_voice(&voices.dont_sink_pause_dont_sink, "dont-sink", STDPAUSE, "dont-sink");
make_voice(&voices.five_hundred_above, "500-above");
make_voice(&voices.glideslope, "glideslope");
make_voice(&voices.glideslope_inop, "glideslope-inop");
make_voice(&voices.gpws_inop, "gpws-inop");
make_voice(&voices.hard_glideslope, "glideslope", "glideslope", 3.0);
make_voice(&voices.minimums, "minimums");
make_voice(&voices.minimums_minimums, "minimums", "minimums");
make_voice(&voices.pull_up, "pull-up");
make_voice(&voices.sink_rate, "sink-rate");
make_voice(&voices.sink_rate_pause_sink_rate, "sink-rate", STDPAUSE, "sink-rate");
make_voice(&voices.soft_glideslope, new Voice::SampleElement(get_sample("glideslope"), modify_amplitude(1.0, -6)));
make_voice(&voices.terrain, "terrain");
make_voice(&voices.terrain_pause_terrain, "terrain", STDPAUSE, "terrain");
make_voice(&voices.too_low_flaps, "too-low-flaps");
make_voice(&voices.too_low_gear, "too-low-gear");
make_voice(&voices.too_low_terrain, "too-low-terrain");
for (unsigned i = 0; i < n_altitude_callouts; i++)
{
std::ostringstream name;
name << "altitude-" << mk->mode6_handler.altitude_callout_definitions[i];
make_voice(&voices.altitude_callouts[i], name.str().c_str());
}
speaker.update_configuration();
}
SGSoundSample *
MK_VIII::VoicePlayer::get_sample (const char *name)
void
FGVoicePlayer::pause()
{
std::ostringstream refname;
refname << mk->name << "[" << mk->num << "]" << "/" << name;
if (paused)
return;
SGSoundSample *sample = _sgr->find(refname.str());
paused = true;
if (voice)
{
voice->stop(true);
}
}
void
FGVoicePlayer::resume()
{
if (!paused)
return;
paused = false;
if (voice)
{
voice->play();
}
}
SGSoundSample *
FGVoicePlayer::get_sample (const char *name)
{
string refname;
refname = dev_name + "/" + dir_prefix + name;
SGSoundSample *sample = _sgr->find(refname);
if (! sample)
{
string filename = "Sounds/mk-viii/" + string(name) + ".wav";
string filename = dir_prefix + string(name) + ".wav";
try
{
sample = new SGSoundSample(filename.c_str(), SGPath());
}
catch (const sg_exception &e)
{
SG_LOG(SG_INSTR, SG_ALERT, "Error loading MK VIII sound sample \"" + filename + "\": " + e.getFormattedMessage());
SG_LOG(SG_INSTR, SG_ALERT, "Error loading sound sample \"" + filename + "\": " + e.getFormattedMessage());
exit(1);
}
_sgr->add(sample, refname.str());
samples[refname.str()] = sample;
_sgr->add(sample, refname);
samples[refname] = sample;
}
return sample;
}
void
MK_VIII::VoicePlayer::play (Voice *_voice, unsigned int flags)
FGVoicePlayer::play (Voice *_voice, unsigned int flags)
{
if (!_voice)
return;
if (test_bits(flags, PLAY_NOW) || ! voice || voice->element->silence)
if (test_bits(flags, PLAY_NOW) || ! voice ||
(voice->element && voice->element->silence))
{
if (voice)
voice->stop(true);
@ -2332,7 +2328,8 @@ MK_VIII::VoicePlayer::play (Voice *_voice, unsigned int flags)
next_voice = NULL;
next_looped = false;
voice->play();
if (!paused)
voice->play();
}
else
{
@ -2342,7 +2339,7 @@ MK_VIII::VoicePlayer::play (Voice *_voice, unsigned int flags)
}
void
MK_VIII::VoicePlayer::stop (unsigned int flags)
FGVoicePlayer::stop (unsigned int flags)
{
if (voice)
{
@ -2356,7 +2353,7 @@ MK_VIII::VoicePlayer::stop (unsigned int flags)
}
void
MK_VIII::VoicePlayer::set_volume (float _volume)
FGVoicePlayer::set_volume (float _volume)
{
volume = _volume;
if (voice)
@ -2364,7 +2361,7 @@ MK_VIII::VoicePlayer::set_volume (float _volume)
}
void
MK_VIII::VoicePlayer::update ()
FGVoicePlayer::update ()
{
if (voice)
{
@ -2396,6 +2393,53 @@ MK_VIII::VoicePlayer::update ()
}
}
///////////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer ///////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void
MK_VIII::VoicePlayer::init ()
{
FGVoicePlayer::init();
#define STDPAUSE 0.75 // [SPEC] 6.4.4: "the standard 0.75 second delay"
make_voice(&voices.application_data_base_failed, "application-data-base-failed");
make_voice(&voices.bank_angle, "bank-angle");
make_voice(&voices.bank_angle_bank_angle, "bank-angle", "bank-angle");
make_voice(&voices.bank_angle_bank_angle_3, "bank-angle", "bank-angle", 3.0);
make_voice(&voices.bank_angle_inop, "bank-angle-inop");
make_voice(&voices.bank_angle_pause_bank_angle, "bank-angle", STDPAUSE, "bank-angle");
make_voice(&voices.bank_angle_pause_bank_angle_3, "bank-angle", STDPAUSE, "bank-angle", 3.0);
make_voice(&voices.callouts_inop, "callouts-inop");
make_voice(&voices.configuration_type_invalid, "configuration-type-invalid");
make_voice(&voices.dont_sink, "dont-sink");
make_voice(&voices.dont_sink_pause_dont_sink, "dont-sink", STDPAUSE, "dont-sink");
make_voice(&voices.five_hundred_above, "500-above");
make_voice(&voices.glideslope, "glideslope");
make_voice(&voices.glideslope_inop, "glideslope-inop");
make_voice(&voices.gpws_inop, "gpws-inop");
make_voice(&voices.hard_glideslope, "glideslope", "glideslope", 3.0);
make_voice(&voices.minimums, "minimums");
make_voice(&voices.minimums_minimums, "minimums", "minimums");
make_voice(&voices.pull_up, "pull-up");
make_voice(&voices.sink_rate, "sink-rate");
make_voice(&voices.sink_rate_pause_sink_rate, "sink-rate", STDPAUSE, "sink-rate");
make_voice(&voices.soft_glideslope, new Voice::SampleElement(get_sample("glideslope"), modify_amplitude(1.0, -6)));
make_voice(&voices.terrain, "terrain");
make_voice(&voices.terrain_pause_terrain, "terrain", STDPAUSE, "terrain");
make_voice(&voices.too_low_flaps, "too-low-flaps");
make_voice(&voices.too_low_gear, "too-low-gear");
make_voice(&voices.too_low_terrain, "too-low-terrain");
for (unsigned i = 0; i < n_altitude_callouts; i++)
{
std::ostringstream name;
name << "altitude-" << MK_VIII::Mode6Handler::altitude_callout_definitions[i];
make_voice(&voices.altitude_callouts[i], name.str().c_str());
}
speaker.update_configuration();
}
///////////////////////////////////////////////////////////////////////////////
// SelfTestHandler ////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@ -4949,7 +4993,7 @@ MK_VIII::bind ()
configuration_module.bind(node);
power_handler.bind(node);
io_handler.bind(node);
voice_player.bind(node);
voice_player.bind(node, "Sounds/mk-viii/");
}
void

View file

@ -47,6 +47,295 @@ class SGSampleGroup;
# pragma warning( disable: 4355 )
#endif
/////////////////////////////////////////////////////////////////////////////
// FGVoicePlayer /////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class FGVoicePlayer
{
public:
/////////////////////////////////////////////////////////////////////////////
// MK::RawValueMethodsData /////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
template <class C, class VT, class DT>
class RawValueMethodsData : public SGRawValue<VT>
{
public:
typedef VT (C::*getter_t) (DT) const;
typedef void (C::*setter_t) (DT, VT);
RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
: _obj(obj), _data(data), _getter(getter), _setter(setter) {}
virtual VT getValue () const
{
if (_getter)
return (_obj.*_getter)(_data);
else
return SGRawValue<VT>::DefaultValue();
}
virtual bool setValue (VT value)
{
if (_setter)
{
(_obj.*_setter)(_data, value);
return true;
}
else
return false;
}
virtual SGRawValue<VT> *clone () const
{
return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
}
private:
C &_obj;
DT _data;
getter_t _getter;
setter_t _setter;
};
class PropertiesHandler
{
public:
vector<SGPropertyNode_ptr> tied_properties;
template <class T>
inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
{
node->tie(raw_value);
tied_properties.push_back(node);
}
template <class T>
inline void tie (SGPropertyNode *node,
const char *relative_path,
const SGRawValue<T> &raw_value)
{
tie(node->getNode(relative_path, true), raw_value);
}
PropertiesHandler() {};
void unbind ();
};
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
class Voice
{
public:
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice::Element ////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
class Element
{
public:
bool silence;
virtual inline void play (float volume) {}
virtual inline void stop () {}
virtual bool is_playing () = 0;
virtual inline void set_volume (float volume) {}
};
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice::SampleElement ///////////////////////////
/////////////////////////////////////////////////////////////////////////
class SampleElement : public Element
{
SGSharedPtr<SGSoundSample> _sample;
float _volume;
public:
inline SampleElement (SGSharedPtr<SGSoundSample> sample, float volume = 1.0)
: _sample(sample), _volume(volume) { silence = false; }
virtual inline void play (float volume) { if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); } }
virtual inline void stop () { if (_sample) _sample->stop(); }
virtual inline bool is_playing () { return _sample ? _sample->is_playing() : false; }
virtual inline void set_volume (float volume) { if (_sample) _sample->set_volume(volume * _volume); }
};
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice::SilenceElement //////////////////////////
/////////////////////////////////////////////////////////////////////////
class SilenceElement : public Element
{
double _duration;
double start_time;
public:
inline SilenceElement (double duration)
: _duration(duration) { silence = true; }
virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
};
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice (continued) //////////////////////////////
/////////////////////////////////////////////////////////////////////////
Element *element;
inline Voice (FGVoicePlayer *_player)
: element(NULL), player(_player), volume(1.0) {}
~Voice ();
inline void append (Element *_element) { elements.push_back(_element); }
void play ();
void stop (bool now);
void set_volume (float _volume);
void volume_changed ();
void update ();
private:
FGVoicePlayer *player;
float volume;
vector<Element *> elements;
vector<Element *>::iterator iter;
inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
};
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer (continued) ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
struct
{
float volume;
} conf;
float volume;
Voice *voice;
Voice *next_voice;
bool paused;
string dev_name;
string dir_prefix;
inline FGVoicePlayer (PropertiesHandler* properties_handler, string _dev_name)
: volume(1.0), voice(NULL), next_voice(NULL), paused(false),
dev_name(_dev_name), dir_prefix(""),
speaker(this,properties_handler) {}
~FGVoicePlayer ();
void init ();
void pause();
void resume();
bool is_playing() { return (voice!=NULL);}
enum
{
PLAY_NOW = 1 << 0,
PLAY_LOOPED = 1 << 1
};
void play (Voice *_voice, unsigned int flags = 0);
enum
{
STOP_NOW = 1 << 0
};
void stop (unsigned int flags = 0);
void set_volume (float _volume);
void update ();
void bind (SGPropertyNode *node, const char* default_dir_prefix);
public:
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Speaker //////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
class Speaker
{
FGVoicePlayer *player;
PropertiesHandler* properties_handler;
double pitch;
template <class T>
inline void tie (SGPropertyNode *node, const char *name, T *ptr)
{
properties_handler->tie
(node, (string("speaker/") + name).c_str(),
RawValueMethodsData<FGVoicePlayer::Speaker,T,T*>
(*this, ptr,
&FGVoicePlayer::Speaker::get_property,
&FGVoicePlayer::Speaker::set_property));
}
public:
template <class T>
inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
template <class T>
inline T get_property (T *ptr) const { return *ptr; }
float volume;
inline Speaker (FGVoicePlayer *_player,PropertiesHandler* _properties_handler)
: player(_player),
properties_handler(_properties_handler),
pitch(1),
volume(1)
{
}
void bind (SGPropertyNode *node);
void update_configuration ();
};
protected:
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer (continued) ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
SGSharedPtr<SGSampleGroup> _sgr;
Speaker speaker;
map< string, SGSharedPtr<SGSoundSample> > samples;
vector<Voice *> _voices;
bool looped;
bool next_looped;
SGSoundSample *get_sample (const char *name);
inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
inline void append (Voice *voice, const char *sample_name) { voice->append(new Voice::SampleElement(get_sample(sample_name))); }
inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
template <class T1>
inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
template <class T1, class T2>
inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
template <class T1, class T2, class T3>
inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
template <class T1, class T2, class T3, class T4>
inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
};
///////////////////////////////////////////////////////////////////////////////
// MK_VIII ////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@ -56,49 +345,6 @@ class MK_VIII : public SGSubsystem
// keep in sync with Mode6Handler::altitude_callout_definitions[]
static const unsigned n_altitude_callouts = 11;
/////////////////////////////////////////////////////////////////////////////
// MK_VIII::RawValueMethodsData /////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
template <class C, class VT, class DT>
class RawValueMethodsData : public SGRawValue<VT>
{
public:
typedef VT (C::*getter_t) (DT) const;
typedef void (C::*setter_t) (DT, VT);
RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
: _obj(obj), _data(data), _getter(getter), _setter(setter) {}
virtual VT getValue () const
{
if (_getter)
return (_obj.*_getter)(_data);
else
return SGRawValue<VT>::DefaultValue();
}
virtual bool setValue (VT value)
{
if (_setter)
{
(_obj.*_setter)(_data, value);
return true;
}
else
return false;
}
virtual SGRawValue<VT> *clone () const
{
return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
}
private:
C &_obj;
DT _data;
getter_t _getter;
setter_t _setter;
};
/////////////////////////////////////////////////////////////////////////////
// MK_VIII::Parameter ///////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
@ -184,12 +430,10 @@ class MK_VIII : public SGSubsystem
// MK_VIII::PropertiesHandler ///////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class PropertiesHandler
class PropertiesHandler : public FGVoicePlayer::PropertiesHandler
{
MK_VIII *mk;
vector<SGPropertyNode_ptr> tied_properties;
public:
struct
{
@ -225,27 +469,11 @@ class MK_VIII : public SGSubsystem
} external_properties;
inline PropertiesHandler (MK_VIII *device)
: mk(device) {}
: FGVoicePlayer::PropertiesHandler(), mk(device) {}
template <class T>
inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
{
node->tie(raw_value);
tied_properties.push_back(node);
}
template <class T>
inline void tie (SGPropertyNode *node,
const char *relative_path,
const SGRawValue<T> &raw_value)
{
tie(node->getNode(relative_path, true), raw_value);
}
PropertiesHandler() {};
PropertiesHandler() : FGVoicePlayer::PropertiesHandler() {}
void init ();
void unbind ();
};
public:
@ -716,250 +944,49 @@ public:
bool *get_lamp_output (Lamp lamp);
};
/////////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer /////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class VoicePlayer
class VoicePlayer : public FGVoicePlayer
{
public:
VoicePlayer (MK_VIII *device) :
FGVoicePlayer(&device->properties_handler, "mk-viii")
{}
///////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer::Voice ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
~VoicePlayer() {}
void init ();
class Voice
{
public:
/////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer::Voice::Element ////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
class Element
struct
{
public:
bool silence;
virtual inline void play (float volume) {}
virtual inline void stop () {}
virtual bool is_playing () = 0;
virtual inline void set_volume (float volume) {}
};
/////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer::Voice::SampleElement ///////////////////////////
/////////////////////////////////////////////////////////////////////////
class SampleElement : public Element
{
SGSharedPtr<SGSoundSample> _sample;
float _volume;
public:
inline SampleElement (SGSharedPtr<SGSoundSample> sample, float volume = 1.0)
: _sample(sample), _volume(volume) { silence = false; }
virtual inline void play (float volume) { if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); } }
virtual inline void stop () { if (_sample) _sample->stop(); }
virtual inline bool is_playing () { return _sample ? _sample->is_playing() : false; }
virtual inline void set_volume (float volume) { if (_sample) _sample->set_volume(volume * _volume); }
};
/////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer::Voice::SilenceElement //////////////////////////
/////////////////////////////////////////////////////////////////////////
class SilenceElement : public Element
{
double _duration;
double start_time;
public:
inline SilenceElement (double duration)
: _duration(duration) { silence = true; }
virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
};
/////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer::Voice (continued) //////////////////////////////
/////////////////////////////////////////////////////////////////////////
Element *element;
inline Voice (VoicePlayer *_player)
: element(NULL), player(_player), volume(1.0) {}
~Voice ();
inline void append (Element *_element) { elements.push_back(_element); }
void play ();
void stop (bool now);
void set_volume (float _volume);
void volume_changed ();
void update ();
private:
VoicePlayer *player;
float volume;
vector<Element *> elements;
vector<Element *>::iterator iter;
inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
};
///////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer (continued) ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
struct
{
float volume;
} conf;
float volume;
Voice *voice;
Voice *next_voice;
struct
{
Voice *application_data_base_failed;
Voice *bank_angle;
Voice *bank_angle_bank_angle;
Voice *bank_angle_bank_angle_3;
Voice *bank_angle_inop;
Voice *bank_angle_pause_bank_angle;
Voice *bank_angle_pause_bank_angle_3;
Voice *callouts_inop;
Voice *configuration_type_invalid;
Voice *dont_sink;
Voice *dont_sink_pause_dont_sink;
Voice *five_hundred_above;
Voice *glideslope;
Voice *glideslope_inop;
Voice *gpws_inop;
Voice *hard_glideslope;
Voice *minimums;
Voice *minimums_minimums;
Voice *pull_up;
Voice *sink_rate;
Voice *sink_rate_pause_sink_rate;
Voice *soft_glideslope;
Voice *terrain;
Voice *terrain_pause_terrain;
Voice *too_low_flaps;
Voice *too_low_gear;
Voice *too_low_terrain;
Voice *altitude_callouts[n_altitude_callouts];
} voices;
inline VoicePlayer (MK_VIII *device)
: voice(NULL), next_voice(NULL), mk(device), speaker(this) {}
~VoicePlayer ();
void init ();
enum
{
PLAY_NOW = 1 << 0,
PLAY_LOOPED = 1 << 1
};
void play (Voice *_voice, unsigned int flags = 0);
enum
{
STOP_NOW = 1 << 0
};
void stop (unsigned int flags = 0);
void set_volume (float _volume);
void update ();
inline void bind (SGPropertyNode *node) { speaker.bind(node); }
public:
///////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer::Speaker //////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
class Speaker
{
VoicePlayer *player;
double pitch;
template <class T>
inline void tie (SGPropertyNode *node, const char *name, T *ptr)
{
player->mk->properties_handler.tie
(node, (string("speaker/") + name).c_str(),
RawValueMethodsData<MK_VIII::VoicePlayer::Speaker,T,T*>
(*this, ptr,
&MK_VIII::VoicePlayer::Speaker::get_property,
&MK_VIII::VoicePlayer::Speaker::set_property));
}
public:
template <class T>
inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
template <class T>
inline T get_property (T *ptr) const { return *ptr; }
float volume;
inline Speaker (VoicePlayer *_player)
: player(_player),
pitch(1),
volume(1)
{
}
void bind (SGPropertyNode *node);
void update_configuration ();
};
private:
///////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer (continued) ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
MK_VIII *mk;
SGSharedPtr<SGSampleGroup> _sgr;
Speaker speaker;
map< string, SGSharedPtr<SGSoundSample> > samples;
vector<Voice *> _voices;
bool looped;
bool next_looped;
SGSoundSample *get_sample (const char *name);
inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
inline void append (Voice *voice, const char *sample_name) { voice->append(new Voice::SampleElement(get_sample(sample_name))); }
inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
template <class T1>
inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
template <class T1, class T2>
inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
template <class T1, class T2, class T3>
inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
template <class T1, class T2, class T3, class T4>
inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
Voice *application_data_base_failed;
Voice *bank_angle;
Voice *bank_angle_bank_angle;
Voice *bank_angle_bank_angle_3;
Voice *bank_angle_inop;
Voice *bank_angle_pause_bank_angle;
Voice *bank_angle_pause_bank_angle_3;
Voice *callouts_inop;
Voice *configuration_type_invalid;
Voice *dont_sink;
Voice *dont_sink_pause_dont_sink;
Voice *five_hundred_above;
Voice *glideslope;
Voice *glideslope_inop;
Voice *gpws_inop;
Voice *hard_glideslope;
Voice *minimums;
Voice *minimums_minimums;
Voice *pull_up;
Voice *sink_rate;
Voice *sink_rate_pause_sink_rate;
Voice *soft_glideslope;
Voice *terrain;
Voice *terrain_pause_terrain;
Voice *too_low_flaps;
Voice *too_low_gear;
Voice *too_low_terrain;
Voice *altitude_callouts[n_altitude_callouts];
} voices;
};
private:

1464
src/Instrumentation/tcas.cxx Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,390 @@
// tcas.hxx -- Traffic Alert and Collision Avoidance System (TCAS)
//
// Written by Thorsten Brehm, started December 2010.
//
// Copyright (C) 2010 Thorsten Brehm - brehmt (at) gmail com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#ifndef __INSTRUMENTS_TCAS_HXX
#define __INSTRUMENTS_TCAS_HXX
#include <assert.h>
#include <vector>
#include <deque>
#include <map>
#include <simgear/props/props.hxx>
#include <simgear/sound/sample_openal.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include "mk_viii.hxx" // FGVoicePlayer only
using std::vector;
using std::deque;
using std::map;
class SGSampleGroup;
#include <Main/globals.hxx>
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning( disable: 4355 )
#endif
///////////////////////////////////////////////////////////////////////////////
// TCAS //////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
class TCAS : public SGSubsystem
{
typedef enum
{
AdvisoryClear = 0, /*< Clear of traffic */
AdvisoryIntrusion = 1, /*< Intrusion flag */
AdvisoryClimb = AdvisoryIntrusion|(1 << 1), /*< RA climb */
AdvisoryDescend = AdvisoryIntrusion|(1 << 2), /*< RA descend */
AdvisoryAdjustVSpeed = AdvisoryIntrusion|(1 << 3), /*< RA adjust vertical speed (TCAS II 7.0 only) */
AdvisoryMaintVSpeed = AdvisoryIntrusion|(1 << 4), /*< RA maintain vertical speed */
AdvisoryMonitorVSpeed = AdvisoryIntrusion|(1 << 5), /*< RA monitor vertical speed */
AdvisoryLevelOff = AdvisoryIntrusion|(1 << 6) /*< RA level off (TCAS II 7.1 only) */
} EnumAdvisory;
typedef enum
{
OptionNone = 0, /*< no option modifier */
OptionIncreaseClimb = (1 << 0), /*< increase climb */
OptionIncreaseDescend = (1 << 1), /*< increase descend */
OptionCrossingClimb = (1 << 2), /*< crossing climb */
OptionCrossingDescent = (1 << 3) /*< crossing descent */
} EnumAdvisoryOption;
typedef enum
{
SwitchOff = 0, /*< TCAS switched off */
SwitchStandby = 1, /*< TCAS standby (no TA/RA) */
SwitchTaOnly = 2, /*< TCAS in TA-only mode (no RA) */
SwitchAuto = 3 /*< TCAS in TA/RA mode */
} EnumModeSwitch;
typedef enum
{
ThreatInvisible = -1,/*< Traffic is invisible to TCAS (i.e. no transponder) */
ThreatNone = 0, /*< Traffic is visible but no threat. */
ThreatProximity = 1, /*< Proximity intruder traffic (no threat). */
ThreatTA = 2, /*< TA-level threat traffic. */
ThreatRA = 3 /*< RA-level threat traffic. */
} EnumThreatLevel;
typedef struct
{
int threatLevel; /*< intruder threat level: 0=clear, 1=proximity,
2=intruder, 3=proximity intruder */
int RA; /*< resolution advisory */
int RAOption; /*< option flags for advisory */
} ResolutionAdvisory;
typedef struct
{
float Tau; /*< vertical/horizontal protection range in seconds */
float DMOD; /*< horizontal protection range in nm */
float ALIM; /*< vertical protection range in ft */
} Thresholds;
typedef struct
{
double maxAltitude; /*< max altitude for this sensitivity level */
int sl; /*< sensitivity level */
Thresholds TA; /*< thresholds for TA-level threats */
Thresholds RA; /*< thresholds for RA-level threats */
} SensitivityLevel;
typedef struct
{
string callsign;
bool verticalTA;
bool verticalRA;
bool horizontalTA;
bool horizontalRA;
bool isTracked;
float horizontalTau;
float verticalTau;
float relativeAltitudeFt;
float verticalFps;
int RASense;
} ThreatInfo;
typedef struct
{
int threatLevel;
double TAtimestamp;
double RAtimestamp;
} TrackerTarget;
typedef map<string,TrackerTarget*> TrackerTargets;
typedef struct
{
double lat;
double lon;
float altFt;
float heading;
float velocityKt;
float verticalFps;
} LocalInfo; /*< info structure for local aircraft */
/////////////////////////////////////////////////////////////////////////////
// TCAS::PropertiesHandler ///////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class PropertiesHandler : public FGVoicePlayer::PropertiesHandler
{
TCAS *tcas;
public:
PropertiesHandler (TCAS *device) :
FGVoicePlayer::PropertiesHandler(), tcas(device) {}
PropertiesHandler (void) : FGVoicePlayer::PropertiesHandler() {}
};
/////////////////////////////////////////////////////////////////////////////
// TCAS::VoicePlayer ////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class VoicePlayer :
public FGVoicePlayer
{
public:
VoicePlayer (TCAS* tcas) :
FGVoicePlayer(&tcas->properties_handler, "tcas") {}
~VoicePlayer (void) {}
void init (void);
struct
{
Voice* pTrafficTraffic;
Voice* pClimb;
Voice* pClimbNow;
Voice* pClimbCrossing;
Voice* pClimbIncrease;
Voice* pDescend;
Voice* pDescendNow;
Voice* pDescendCrossing;
Voice* pDescendIncrease;
Voice* pClear;
Voice* pAdjustVSpeed;
Voice* pMaintVSpeed;
Voice* pMonitorVSpeed;
Voice* pLevelOff;
Voice* pTestOk;
Voice* pTestFail;
} Voices;
private:
SGPropertyNode_ptr nodeSoundFilePrefix;
};
/////////////////////////////////////////////////////////////////////////////
// TCAS::Annunciator ////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class Annunciator
{
public:
Annunciator (TCAS* tcas);
~Annunciator (void) {}
void bind (SGPropertyNode* node);
void init (void);
void update (void);
void trigger (const ResolutionAdvisory& newAdvisory, bool revertedRA);
void test (bool testOk);
void clear (void);
bool isPlaying (void) { return voicePlayer.is_playing();}
private:
TCAS* tcas;
ResolutionAdvisory previous;
FGVoicePlayer::Voice* pLastVoice;
VoicePlayer voicePlayer;
SGPropertyNode_ptr nodeGpwsAlertOn;
};
/////////////////////////////////////////////////////////////////////////////
// TCAS::AdvisoryCoordinator ////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class AdvisoryCoordinator
{
public:
AdvisoryCoordinator (TCAS* _tcas);
~AdvisoryCoordinator (void) {}
void bind (SGPropertyNode* node);
void init (void);
void update (int mode);
void clear (void);
void add (const ResolutionAdvisory& newAdvisory);
private:
TCAS* tcas;
double lastTATime;
ResolutionAdvisory current;
ResolutionAdvisory previous;
SGPropertyNode_ptr nodeTAWarning;
};
/////////////////////////////////////////////////////////////////////////////
// TCAS::Tracker ////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class Tracker
{
public:
Tracker (TCAS* _tcas);
~Tracker (void) {}
void update (void);
void add (const string callsign, int detectedLevel);
bool active (void) { return haveTargets;}
bool newTraffic (void) { return newTargets;}
bool isTracked (string callsign) { if (!haveTargets) return false;else return _isTracked(callsign);}
bool _isTracked (string callsign);
int getThreatLevel (string callsign);
private:
TCAS* tcas;
double currentTime;
bool haveTargets;
bool newTargets;
TrackerTargets targets;
};
/////////////////////////////////////////////////////////////////////////////
// TCAS::AdvisoryGenerator //////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class AdvisoryGenerator
{
public:
AdvisoryGenerator (TCAS* _tcas);
~AdvisoryGenerator (void) {}
void init (const LocalInfo* _pSelf, ThreatInfo* _pCurrentThreat);
void setAlarmThresholds (const SensitivityLevel* _pAlarmThresholds);
int resolution (int mode, int threatLevel, float distanceNm,
float altFt, float heading, float velocityKt);
private:
float verticalSeparation (float newVerticalFps);
void determineRAsense (int& RASense, bool& isCrossing);
private:
TCAS* tcas;
const LocalInfo* pSelf; /*< info structure for local aircraft */
ThreatInfo* pCurrentThreat; /*< info structure on current intruder/threat */
const SensitivityLevel* pAlarmThresholds;
};
/////////////////////////////////////////////////////////////////////////////
// TCAS::ThreatDetector /////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class ThreatDetector
{
public:
ThreatDetector (TCAS* _tcas);
~ThreatDetector (void) {}
void init (void);
void update (void);
bool checkTransponder (const SGPropertyNode* pModel, float velocityKt);
int checkThreat (int mode, const SGPropertyNode* pModel);
void checkVerticalThreat (void);
void horizontalThreat (float bearing, float distanceNm, float heading,
float velocityKt);
void setAlt (float altFt) { self.altFt = altFt;}
float getAlt (void) { return self.altFt;}
float getVelocityKt (void) { return self.velocityKt;}
int getRASense (void) { return currentThreat.RASense;}
private:
void unitTest (void);
private:
static const SensitivityLevel sensitivityLevels[];
TCAS* tcas;
int checkCount;
SGPropertyNode_ptr nodeLat;
SGPropertyNode_ptr nodeLon;
SGPropertyNode_ptr nodeAlt;
SGPropertyNode_ptr nodeHeading;
SGPropertyNode_ptr nodeVelocity;
SGPropertyNode_ptr nodeVerticalFps;
LocalInfo self; /*< info structure for local aircraft */
ThreatInfo currentThreat; /*< info structure on current intruder/threat */
const SensitivityLevel* pAlarmThresholds;
};
private:
string name;
int num;
double nextUpdateTime;
int selfTestStep;
SGPropertyNode_ptr nodeModeSwitch;
SGPropertyNode_ptr nodeServiceable;
SGPropertyNode_ptr nodeSelfTest;
SGPropertyNode_ptr nodeDebugTrigger;
SGPropertyNode_ptr nodeDebugRA;
SGPropertyNode_ptr nodeDebugThreat;
PropertiesHandler properties_handler;
ThreatDetector threatDetector;
Tracker tracker;
AdvisoryCoordinator advisoryCoordinator;
AdvisoryGenerator advisoryGenerator;
Annunciator annunciator;
private:
void selfTest (void);
public:
TCAS (SGPropertyNode* node);
virtual void bind (void);
virtual void unbind (void);
virtual void init (void);
virtual void update (double dt);
};
#ifdef _MSC_VER
# pragma warning( pop )
#endif
#endif // __INSTRUMENTS_TCAS_HXX

View file

@ -69,18 +69,29 @@ using std::endl;
static const float UNIT = 1.0f / 8.0f; // 8 symbols in a row/column in the texture
static const char *DEFAULT_FONT = "typewriter.txf";
wxRadarBg::wxRadarBg(SGPropertyNode *node) :
_name(node->getStringValue("name", "radar")),
_num(node->getIntValue("number", 0)),
_time(0.0),
_interval(node->getDoubleValue("update-interval-sec", 1.0)),
_elapsed_time(0),
_persistance(0),
_sim_init_done(false),
_odg(0),
_last_switchKnob("off"),
_range_nm(0),
_scale(0),
_angle_offset(0),
_view_heading(0),
_x_offset(0),
_y_offset(0),
_radar_ref_rng(0),
_lat(0),
_lon(0),
_antenna_ht(node->getDoubleValue("antenna-ht-ft", 0.0)),
_resultTexture(0),
_wxEcho(0)
_wxEcho(0),
_font_size(0),
_font_spacing(0)
{
string branch;
branch = "/instrumentation/" + _name;
@ -174,6 +185,8 @@ wxRadarBg::init ()
_radar_symbol_node = n->getNode("symbol", true);
_radar_centre_node = n->getNode("centre", true);
_radar_rotate_node = n->getNode("rotate", true);
_radar_tcas_node = n->getNode("tcas", true);
_radar_absalt_node = n->getNode("abs-altitude", true);
_radar_centre_node->setBoolValue(false);
if (!_radar_coverage_node->hasValue())
@ -231,6 +244,8 @@ wxRadarBg::init ()
osg::Camera *camera = _odg->getCamera();
camera->addChild(_radarGeode.get());
camera->addChild(_textGeode.get());
updateFont();
}
@ -305,16 +320,6 @@ wxRadarBg::update (double delta_time_sec)
}
string switchKnob = _Instrument->getStringValue("switch", "on");
if (_last_switchKnob != switchKnob) {
// since 3D models don't share textures with the rest of the world
// we must locate them and replace their handle by hand
// only do that when the instrument is turned on
//if (_last_switchKnob == "off")
//_odg->set_texture(_texture_path.c_str(), _resultTexture->getHandle());
_last_switchKnob = switchKnob;
}
if (switchKnob == "off") {
_Instrument->setStringValue("status", "");
} else if (switchKnob == "stby") {
@ -666,9 +671,11 @@ wxRadarBg::update_aircraft()
if (!_ai_enabled_node->getBoolValue())
return;
bool draw_echoes = _radar_position_node->getBoolValue();
bool draw_symbols = _radar_symbol_node->getBoolValue();
bool draw_data = _radar_data_node->getBoolValue();
bool draw_tcas = _radar_tcas_node->getBoolValue();
bool draw_absolute = _radar_absalt_node->getBoolValue();
bool draw_echoes = _radar_position_node->getBoolValue();
bool draw_symbols = _radar_symbol_node->getBoolValue();
bool draw_data = _radar_data_node->getBoolValue();
if (!draw_echoes && !draw_symbols && !draw_data)
return;
@ -697,7 +704,8 @@ wxRadarBg::update_aircraft()
model = ai->getChild(i);
if (!model->nChildren())
continue;
if (model->getIntValue("id") == selected_id) {
if ((model->getIntValue("id") == selected_id)&&
(!draw_tcas)) {
selected_ac = model; // save selected model for last iteration
continue;
}
@ -752,8 +760,14 @@ wxRadarBg::update_aircraft()
bearing += _angle_offset;
heading += _angle_offset;
bool is_tcas_contact = false;
if (draw_tcas)
{
is_tcas_contact = update_tcas(model,range,user_alt,alt,bearing,radius,draw_absolute);
}
// pos mode
if (draw_echoes) {
if (draw_echoes && (!is_tcas_contact)) {
float size = echo_radius * 120 * UNIT;
const osg::Vec2f texBase(3 * UNIT, 3 * UNIT);
@ -764,7 +778,7 @@ wxRadarBg::update_aircraft()
}
// data mode
if (draw_symbols) {
if (draw_symbols && (!draw_tcas)) {
const osg::Vec2f texBase(0, 3 * UNIT);
float size = 600 * UNIT;
osg::Matrixf m(osg::Matrixf::scale(size, size, 1.0f)
@ -774,11 +788,98 @@ wxRadarBg::update_aircraft()
addQuad(_vertices, _texCoords, m, texBase);
}
if (draw_data || i < 0) // selected one (i == -1) is always drawn
if ((draw_data || i < 0)&& // selected one (i == -1) is always drawn
((!draw_tcas)||(is_tcas_contact)||(draw_echoes)))
update_data(model, alt, heading, radius, bearing, i < 0);
}
}
/** Update TCAS display.
* Return true when processed as TCAS contact, false otherwise. */
bool
wxRadarBg::update_tcas(const SGPropertyNode *model,double range,double user_alt,double alt,
double bearing,double radius,bool absMode)
{
int threatLevel=0;
{
// update TCAS symbol
osg::Vec2f texBase;
threatLevel = model->getIntValue("tcas/threat-level",-1);
if (threatLevel == -1)
{
// no TCAS information (i.e. no transponder) => not visible to TCAS
return false;
}
int row = 7 - threatLevel;
int col = 4;
double vspeed = model->getDoubleValue("velocities/vertical-speed-fps");
if (vspeed < -3.0) // descending
col+=1;
else
if (vspeed > 3.0) // climbing
col+=2;
texBase = osg::Vec2f(col*UNIT,row * UNIT);
float size = 200 * UNIT;
osg::Matrixf m(osg::Matrixf::scale(size, size, 1.0f)
* wxRotate(-bearing)
* osg::Matrixf::translate(0.0f, radius, 0.0f)
* wxRotate(bearing) * _centerTrans);
addQuad(_vertices, _texCoords, m, texBase);
}
{
// update TCAS data
osgText::Text *altStr = new osgText::Text;
altStr->setFont(_font.get());
altStr->setFontResolution(12, 12);
altStr->setCharacterSize(_font_size);
altStr->setColor(_tcas_colors[threatLevel]);
osg::Matrixf m(wxRotate(-bearing)
* osg::Matrixf::translate(0.0f, radius, 0.0f)
* wxRotate(bearing) * _centerTrans);
osg::Vec3 pos = m.preMult(osg::Vec3(16, 16, 0));
// cast to int's, otherwise text comes out ugly
altStr->setLineSpacing(_font_spacing);
stringstream text;
altStr->setAlignment(osgText::Text::LEFT_CENTER);
int altDif = (alt-user_alt+50)/100;
char sign = 0;
int dy=0;
if (altDif>=0)
{
sign='+';
dy=2;
}
else
if (altDif<0)
{
sign='-';
altDif = -altDif;
dy=-30;
}
altStr->setPosition(osg::Vec3((int)pos.x()-30, (int)pos.y()+dy, 0));
if (absMode)
{
// absolute altitude display
text << setprecision(0) << fixed
<< setw(3) << setfill('0') << alt/100 << endl;
}
else // relative altitude display
if (sign)
{
text << sign
<< setprecision(0) << fixed
<< setw(2) << setfill('0') << altDif << endl;
}
altStr->setText(text.str());
_textGeode->addDrawable(altStr);
}
return true;
}
void
wxRadarBg::update_tacan()
@ -983,11 +1084,23 @@ wxRadarBg::updateFont()
_font->setGlyphImageMargin(0);
_font->setGlyphImageMarginRatio(0);
}
for (int i=0;i<4;i++)
{
const float defaultColors[4][3] = {{0,1,1},{0,1,1},{1,0.5,0},{1,0,0}};
SGPropertyNode_ptr color_node = _font_node->getNode("tcas/color",i,true);
float red = color_node->getFloatValue("red",defaultColors[i][0]);
float green = color_node->getFloatValue("green",defaultColors[i][1]);
float blue = color_node->getFloatValue("blue",defaultColors[i][2]);
float alpha = color_node->getFloatValue("alpha",1);
_tcas_colors[i]=osg::Vec4(red, green, blue, alpha);
}
}
void
wxRadarBg::valueChanged(SGPropertyNode*)
{
updateFont();
_time = _interval;
}

View file

@ -96,8 +96,6 @@ private:
typedef enum { ARC, MAP, PLAN, ROSE, BSCAN} DisplayMode;
DisplayMode _display_mode;
string _last_switchKnob;
float _range_nm;
float _scale; // factor to convert nm to display units
float _angle_offset;
@ -130,6 +128,8 @@ private:
SGPropertyNode_ptr _radar_ref_rng_node;
SGPropertyNode_ptr _radar_hdg_marker_node;
SGPropertyNode_ptr _radar_rotate_node;
SGPropertyNode_ptr _radar_tcas_node;
SGPropertyNode_ptr _radar_absalt_node;
SGPropertyNode_ptr _font_node;
SGPropertyNode_ptr _ai_enabled_node;
@ -144,6 +144,7 @@ private:
osg::Matrixf _centerTrans;
osg::ref_ptr<osgText::Font> _font;
osg::Vec4 _font_color;
osg::Vec4 _tcas_colors[4];
float _font_size;
float _font_spacing;
@ -155,6 +156,8 @@ private:
void update_heading_marker();
void update_data(const SGPropertyNode *ac, double alt, double heading,
double radius, double bearing, bool selected);
bool update_tcas(const SGPropertyNode *model,double range,double user_alt,double alt,
double bearing,double radius, bool absMode);
void center_map();
void apply_map_offset();
void updateFont();

View file

@ -11,6 +11,7 @@
#include <simgear/compiler.h>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
/**
* Log any property values to any number of CSV files.

View file

@ -29,6 +29,7 @@
#include <simgear/compiler.h>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#include <simgear/math/SGMath.hxx>
// forward decls

View file

@ -29,6 +29,7 @@
#include <vector>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#include <simgear/sound/sample_group.hxx>
class SGXmlSound;

View file

@ -29,6 +29,7 @@
#include <queue>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#include <simgear/sound/sample_group.hxx>
class SGSoundSample;

View file

@ -22,6 +22,7 @@
#define FG_TIME_TIMEMANAGER_HXX
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
// forward decls
class SGTime;