Some more refactoring of the radios
- wrap the ident-generating code into a class - move dme-in-range property into dme.cxx - move dme-ident generation into dme.cxx - support ident-button and volume for dme idents - use globals.get_aircraft_position instead of properties - some minor cleanup
This commit is contained in:
parent
2de3872d66
commit
43109feb0c
14 changed files with 323 additions and 262 deletions
|
@ -3197,6 +3197,14 @@
|
|||
<Filter
|
||||
Name="Lib_Sound"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Sound\audioident.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Sound\audioident.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\Sound\beacon.cxx"
|
||||
>
|
||||
|
|
|
@ -252,7 +252,7 @@ ADF::search (double frequency_khz, double longitude_rad,
|
|||
}
|
||||
|
||||
SGSoundSample *sound;
|
||||
sound = FGMorse::instance()->make_ident( ident, LO_FREQUENCY );
|
||||
sound = FGMorse::instance()->make_ident( ident, FGMorse::LO_FREQUENCY );
|
||||
sound->set_volume(_last_volume = 0);
|
||||
_sgr->add( sound, _adf_ident );
|
||||
|
||||
|
|
|
@ -8,15 +8,16 @@
|
|||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/sg_inlines.h>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Navaids/navlist.hxx>
|
||||
#include <Sound/audioident.hxx>
|
||||
|
||||
#include "dme.hxx"
|
||||
|
||||
|
||||
/**
|
||||
* Adjust the range.
|
||||
*
|
||||
|
@ -44,17 +45,16 @@ DME::DME ( SGPropertyNode *node )
|
|||
: _last_distance_nm(0),
|
||||
_last_frequency_mhz(-1),
|
||||
_time_before_search_sec(0),
|
||||
_transmitter_valid(false),
|
||||
_transmitter_elevation_ft(0),
|
||||
_transmitter_range_nm(0),
|
||||
_transmitter_bias(0.0),
|
||||
_navrecord(NULL),
|
||||
_name(node->getStringValue("name", "dme")),
|
||||
_num(node->getIntValue("number", 0))
|
||||
_num(node->getIntValue("number", 0)),
|
||||
_audioIdent(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
DME::~DME ()
|
||||
{
|
||||
delete _audioIdent;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -65,9 +65,6 @@ DME::init ()
|
|||
|
||||
SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true );
|
||||
|
||||
_longitude_node = fgGetNode("/position/longitude-deg", true);
|
||||
_latitude_node = fgGetNode("/position/latitude-deg", true);
|
||||
_altitude_node = fgGetNode("/position/altitude-ft", true);
|
||||
_serviceable_node = node->getChild("serviceable", 0, true);
|
||||
_electrical_node = fgGetNode("/systems/electrical/outputs/dme", true);
|
||||
SGPropertyNode *fnode = node->getChild("frequencies", 0, true);
|
||||
|
@ -77,11 +74,28 @@ DME::init ()
|
|||
_distance_node = node->getChild("indicated-distance-nm", 0, true);
|
||||
_speed_node = node->getChild("indicated-ground-speed-kt", 0, true);
|
||||
_time_node = node->getChild("indicated-time-min", 0, true);
|
||||
|
||||
double d = node->getDoubleValue( "volume", 1.0 );
|
||||
_volume_node = node->getChild("volume", 0, true);
|
||||
_volume_node->setDoubleValue( d );
|
||||
|
||||
bool b = node->getBoolValue( "ident", false );
|
||||
_ident_btn_node = node->getChild("ident", 0, true);
|
||||
_ident_btn_node->setBoolValue( b );
|
||||
|
||||
std::ostringstream temp;
|
||||
temp << _name << "-ident-" << _num;
|
||||
if( NULL == _audioIdent )
|
||||
_audioIdent = new DMEAudioIdent( temp.str() );
|
||||
_audioIdent->init();
|
||||
}
|
||||
|
||||
void
|
||||
DME::update (double delta_time_sec)
|
||||
{
|
||||
if( delta_time_sec < SGLimitsd::min() )
|
||||
return; //paused
|
||||
|
||||
// Figure out the source
|
||||
const char * source = _source_node->getStringValue();
|
||||
if (source[0] == '\0') {
|
||||
|
@ -100,48 +114,50 @@ DME::update (double delta_time_sec)
|
|||
_frequency_node->setDoubleValue(frequency_mhz);
|
||||
|
||||
// Get the aircraft position
|
||||
double longitude_rad =
|
||||
_longitude_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
|
||||
double latitude_rad =
|
||||
_latitude_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
|
||||
double altitude_m =
|
||||
_altitude_node->getDoubleValue() * SG_FEET_TO_METER;
|
||||
|
||||
// On timeout, scan again
|
||||
_time_before_search_sec -= delta_time_sec;
|
||||
if (_time_before_search_sec < 0)
|
||||
search(frequency_mhz, longitude_rad,
|
||||
latitude_rad, altitude_m);
|
||||
if (_time_before_search_sec < 0) {
|
||||
_time_before_search_sec = 1.0;
|
||||
|
||||
_navrecord = globals->get_dmelist()->findByFreq( frequency_mhz,
|
||||
globals->get_aircraft_position());
|
||||
}
|
||||
|
||||
// If it's off, don't bother.
|
||||
if (!_serviceable_node->getBoolValue() ||
|
||||
!_electrical_node->getBoolValue() ||
|
||||
!_transmitter_valid) {
|
||||
NULL == _navrecord ) {
|
||||
_last_distance_nm = 0;
|
||||
_in_range_node->setBoolValue(false);
|
||||
_distance_node->setDoubleValue(0);
|
||||
_speed_node->setDoubleValue(0);
|
||||
_time_node->setDoubleValue(0);
|
||||
_audioIdent->setIdent("", 0.0 );
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the distance to the transmitter
|
||||
SGGeod geod = SGGeod::fromRadM(longitude_rad, latitude_rad, altitude_m);
|
||||
SGVec3d location = SGVec3d::fromGeod(geod);
|
||||
SGVec3d location = SGVec3d::fromGeod(globals->get_aircraft_position());
|
||||
|
||||
double distance_nm = dist(_transmitter, location) * SG_METER_TO_NM;
|
||||
double distance_nm = dist(_navrecord->cart(), location) * SG_METER_TO_NM;
|
||||
|
||||
double range_nm = adjust_range(_transmitter_elevation_ft,
|
||||
altitude_m * SG_METER_TO_FEET,
|
||||
_transmitter_range_nm);
|
||||
double range_nm = adjust_range(_navrecord->get_elev_ft(),
|
||||
globals->get_aircraft_position().getElevationFt(),
|
||||
_navrecord->get_range());
|
||||
|
||||
if (distance_nm <= range_nm) {
|
||||
double volume = _volume_node->getDoubleValue();
|
||||
if( false == _ident_btn_node->getBoolValue() )
|
||||
volume = 0.0;
|
||||
|
||||
_audioIdent->setIdent(_navrecord->ident(), volume );
|
||||
|
||||
double speed_kt = (fabs(distance_nm - _last_distance_nm) *
|
||||
((1 / delta_time_sec) * 3600.0));
|
||||
_last_distance_nm = distance_nm;
|
||||
|
||||
_in_range_node->setBoolValue(true);
|
||||
double tmp_dist = distance_nm - _transmitter_bias;
|
||||
double tmp_dist = distance_nm - _navrecord->get_multiuse();
|
||||
if ( tmp_dist < 0.0 ) {
|
||||
tmp_dist = 0.0;
|
||||
}
|
||||
|
@ -156,29 +172,10 @@ DME::update (double delta_time_sec)
|
|||
_distance_node->setDoubleValue(0);
|
||||
_speed_node->setDoubleValue(0);
|
||||
_time_node->setDoubleValue(0);
|
||||
_audioIdent->setIdent("", 0.0 );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DME::search (double frequency_mhz, double longitude_rad,
|
||||
double latitude_rad, double altitude_m)
|
||||
{
|
||||
// reset search time
|
||||
_time_before_search_sec = 1.0;
|
||||
|
||||
// try the ILS list first
|
||||
|
||||
FGNavRecord *dme = globals->get_dmelist()->findByFreq( frequency_mhz,
|
||||
SGGeod::fromRadM(longitude_rad, latitude_rad, altitude_m));
|
||||
|
||||
_transmitter_valid = (dme != NULL);
|
||||
|
||||
if ( _transmitter_valid ) {
|
||||
_transmitter = dme->cart();
|
||||
_transmitter_elevation_ft = dme->get_elev_ft();
|
||||
_transmitter_range_nm = dme->get_range();
|
||||
_transmitter_bias = dme->get_multiuse();
|
||||
}
|
||||
_audioIdent->update( delta_time_sec );
|
||||
}
|
||||
|
||||
// end of dme.cxx
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
|
||||
/**
|
||||
* Model a DME radio.
|
||||
*
|
||||
|
@ -44,12 +43,6 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
void search (double frequency, double longitude_rad,
|
||||
double latitude_rad, double altitude_m);
|
||||
|
||||
SGPropertyNode_ptr _longitude_node;
|
||||
SGPropertyNode_ptr _latitude_node;
|
||||
SGPropertyNode_ptr _altitude_node;
|
||||
SGPropertyNode_ptr _serviceable_node;
|
||||
SGPropertyNode_ptr _electrical_node;
|
||||
SGPropertyNode_ptr _source_node;
|
||||
|
@ -59,20 +52,19 @@ private:
|
|||
SGPropertyNode_ptr _distance_node;
|
||||
SGPropertyNode_ptr _speed_node;
|
||||
SGPropertyNode_ptr _time_node;
|
||||
SGPropertyNode_ptr _ident_btn_node;
|
||||
SGPropertyNode_ptr _volume_node;
|
||||
|
||||
double _last_distance_nm;
|
||||
double _last_frequency_mhz;
|
||||
double _time_before_search_sec;
|
||||
|
||||
bool _transmitter_valid;
|
||||
SGVec3d _transmitter;
|
||||
double _transmitter_elevation_ft;
|
||||
double _transmitter_range_nm;
|
||||
double _transmitter_bias;
|
||||
FGNavRecord * _navrecord;
|
||||
|
||||
string _name;
|
||||
int _num;
|
||||
|
||||
class AudioIdent * _audioIdent;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -71,9 +70,6 @@ static double kludgeRange ( double stationElev, double aircraftElev,
|
|||
|
||||
// Constructor
|
||||
FGKR_87::FGKR_87( SGPropertyNode *node ) :
|
||||
lon_node(fgGetNode("/position/longitude-deg", true)),
|
||||
lat_node(fgGetNode("/position/latitude-deg", true)),
|
||||
alt_node(fgGetNode("/position/altitude-ft", true)),
|
||||
bus_power(fgGetNode("/systems/electrical/outputs/adf", true)),
|
||||
serviceable(fgGetNode("/instrumentation/adf/serviceable", true)),
|
||||
need_update(true),
|
||||
|
@ -249,9 +245,7 @@ void FGKR_87::unbind () {
|
|||
|
||||
// Update the various nav values based on position and valid tuned in navs
|
||||
void FGKR_87::update( double dt_sec ) {
|
||||
SGGeod acft = SGGeod::fromDegFt(lon_node->getDoubleValue(),
|
||||
lat_node->getDoubleValue(),
|
||||
alt_node->getDoubleValue());
|
||||
SGGeod acft = globals->get_aircraft_position();
|
||||
|
||||
need_update = false;
|
||||
|
||||
|
@ -497,8 +491,7 @@ void FGKR_87::update( double dt_sec ) {
|
|||
|
||||
// Update current nav/adf radio stations based on current postition
|
||||
void FGKR_87::search() {
|
||||
SGGeod pos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
|
||||
lat_node->getDoubleValue(), alt_node->getDoubleValue());
|
||||
SGGeod pos = globals->get_aircraft_position();
|
||||
|
||||
// FIXME: the panel should handle this
|
||||
static string last_ident = "";
|
||||
|
@ -534,7 +527,7 @@ void FGKR_87::search() {
|
|||
_sgr->remove( "adf-ident" );
|
||||
}
|
||||
SGSoundSample *sound;
|
||||
sound = FGMorse::instance()->make_ident( trans_ident, LO_FREQUENCY );
|
||||
sound = FGMorse::instance()->make_ident( trans_ident, FGMorse::LO_FREQUENCY );
|
||||
sound->set_volume( 0.3 );
|
||||
_sgr->add( sound, "adf-ident" );
|
||||
|
||||
|
|
|
@ -37,9 +37,6 @@ class SGSampleGroup;
|
|||
|
||||
class FGKR_87 : public SGSubsystem
|
||||
{
|
||||
SGPropertyNode_ptr lon_node;
|
||||
SGPropertyNode_ptr lat_node;
|
||||
SGPropertyNode_ptr alt_node;
|
||||
SGPropertyNode_ptr bus_power;
|
||||
SGPropertyNode_ptr serviceable;
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
|
@ -40,12 +38,10 @@
|
|||
#include <simgear/misc/strutils.hxx>
|
||||
|
||||
#include <Navaids/navrecord.hxx>
|
||||
|
||||
#include <Sound/audioident.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
#include <Navaids/navlist.hxx>
|
||||
#include <Main/util.hxx>
|
||||
#include <Sound/morse.hxx>
|
||||
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -105,9 +101,6 @@ FGNavRadio::FGNavRadio(SGPropertyNode *node) :
|
|||
term_tbl(NULL),
|
||||
low_tbl(NULL),
|
||||
high_tbl(NULL),
|
||||
lon_node(fgGetNode("/position/longitude-deg", true)),
|
||||
lat_node(fgGetNode("/position/latitude-deg", true)),
|
||||
alt_node(fgGetNode("/position/altitude-ft", true)),
|
||||
_operable(false),
|
||||
play_count(0),
|
||||
last_time(0),
|
||||
|
@ -126,14 +119,13 @@ FGNavRadio::FGNavRadio(SGPropertyNode *node) :
|
|||
_gsCart(SGVec3d::zeros()),
|
||||
_gsAxis(SGVec3d::zeros()),
|
||||
_gsVertical(SGVec3d::zeros()),
|
||||
_dmeInRange(false),
|
||||
_toFlag(false),
|
||||
_fromFlag(false),
|
||||
_cdiDeflection(0.0),
|
||||
_cdiCrossTrackErrorM(0.0),
|
||||
_gsNeedleDeflection(0.0),
|
||||
_gsNeedleDeflectionNorm(0.0),
|
||||
_sgr(NULL)
|
||||
_audioIdent(NULL)
|
||||
{
|
||||
SGPath path( globals->get_fg_root() );
|
||||
SGPath term = path;
|
||||
|
@ -166,16 +158,14 @@ FGNavRadio::~FGNavRadio()
|
|||
delete term_tbl;
|
||||
delete low_tbl;
|
||||
delete high_tbl;
|
||||
|
||||
delete _audioIdent;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FGNavRadio::init ()
|
||||
{
|
||||
SGSoundMgr *smgr = globals->get_soundmgr();
|
||||
_sgr = smgr->find("avionics", true);
|
||||
_sgr->tie_to_listener();
|
||||
|
||||
SGPropertyNode* node = _radio_node.get();
|
||||
bus_power_node =
|
||||
fgGetNode(("/systems/electrical/outputs/" + _name).c_str(), true);
|
||||
|
@ -196,7 +186,6 @@ FGNavRadio::init ()
|
|||
cdi_serviceable_node = createServiceableProp(node, "cdi");
|
||||
gs_serviceable_node = createServiceableProp(node, "gs");
|
||||
tofrom_serviceable_node = createServiceableProp(node, "to-from");
|
||||
dme_serviceable_node = createServiceableProp(node, "dme");
|
||||
|
||||
falseCoursesEnabledNode =
|
||||
fgGetNode("/sim/realism/false-radio-courses-enabled");
|
||||
|
@ -266,27 +255,28 @@ FGNavRadio::init ()
|
|||
_magvarNode = fgGetNode("/environment/magnetic-variation-deg", true);
|
||||
|
||||
std::ostringstream temp;
|
||||
temp << _name << "nav-ident" << _num;
|
||||
nav_fx_name = temp.str();
|
||||
temp << _name << "dme-ident" << _num;
|
||||
dme_fx_name = temp.str();
|
||||
temp << _name << "-ident-" << _num;
|
||||
if( NULL == _audioIdent )
|
||||
_audioIdent = new VORAudioIdent( temp.str() );
|
||||
_audioIdent->init();
|
||||
|
||||
// dme-in-range is deprecated,
|
||||
// temporarily create dme-in-range alias for instrumentation/dme[0]/in-range
|
||||
// remove after flightgear 2.6.0
|
||||
node->getNode( "dme-in-range", true )->alias( fgGetNode("/instrumentation/dme[0]/in-range", true ) );
|
||||
}
|
||||
|
||||
void
|
||||
FGNavRadio::bind ()
|
||||
{
|
||||
tie("dme-in-range", SGRawValuePointer<bool>(&_dmeInRange));
|
||||
tie("operable", SGRawValueMethods<FGNavRadio, bool>(*this, &FGNavRadio::isOperable, NULL));
|
||||
_radio_node->tie( "operable", SGRawValueMethods<FGNavRadio,bool>( *this, &FGNavRadio::isOperable ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FGNavRadio::unbind ()
|
||||
{
|
||||
for (unsigned int t=0; t<_tiedNodes.size(); ++t) {
|
||||
_tiedNodes[t]->untie();
|
||||
}
|
||||
_tiedNodes.clear();
|
||||
_radio_node->untie("operable");
|
||||
}
|
||||
|
||||
|
||||
|
@ -386,7 +376,7 @@ FGNavRadio::update(double dt)
|
|||
clearOutputs();
|
||||
}
|
||||
|
||||
updateAudio();
|
||||
updateAudio( dt );
|
||||
}
|
||||
|
||||
void FGNavRadio::clearOutputs()
|
||||
|
@ -412,17 +402,13 @@ void FGNavRadio::clearOutputs()
|
|||
is_valid_node->setBoolValue(false);
|
||||
nav_id_node->setStringValue("");
|
||||
|
||||
_dmeInRange = false;
|
||||
_operable = false;
|
||||
_navaid = NULL;
|
||||
}
|
||||
|
||||
void FGNavRadio::updateReceiver(double dt)
|
||||
{
|
||||
SGGeod pos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
|
||||
lat_node->getDoubleValue(),
|
||||
alt_node->getDoubleValue());
|
||||
SGVec3d aircraft = SGVec3d::fromGeod(pos);
|
||||
SGVec3d aircraft = SGVec3d::fromGeod(globals->get_aircraft_position());
|
||||
double loc_dist = 0;
|
||||
|
||||
// Do a nav station search only once a second to reduce
|
||||
|
@ -438,11 +424,10 @@ void FGNavRadio::updateReceiver(double dt)
|
|||
loc_dist = dist(aircraft, _navaid->cart());
|
||||
loc_dist_node->setDoubleValue( loc_dist );
|
||||
}
|
||||
updateDME(aircraft);
|
||||
|
||||
if (nav_slaved_to_gps_node->getBoolValue()) {
|
||||
// when slaved to GPS: only allow stuff above: tune NAV station
|
||||
// upate DME. All other data driven by GPS only.
|
||||
// All other data driven by GPS only.
|
||||
updateGPSSlaved();
|
||||
return;
|
||||
}
|
||||
|
@ -468,7 +453,7 @@ void FGNavRadio::updateReceiver(double dt)
|
|||
// compute forward and reverse wgs84 headings to localizer
|
||||
//////////////////////////////////////////////////////////
|
||||
double hdg;
|
||||
SGGeodesy::inverse(pos, _navaid->geod(), hdg, az2, s);
|
||||
SGGeodesy::inverse(globals->get_aircraft_position(), _navaid->geod(), hdg, az2, s);
|
||||
heading_node->setDoubleValue(hdg);
|
||||
double radial = az2 - twist;
|
||||
double recip = radial + 180.0;
|
||||
|
@ -497,11 +482,11 @@ void FGNavRadio::updateReceiver(double dt)
|
|||
double offset = radial - target_radial;
|
||||
SG_NORMALIZE_RANGE(offset, -180.0, 180.0);
|
||||
effective_range
|
||||
= adjustILSRange( nav_elev, pos.getElevationM(), offset,
|
||||
= adjustILSRange( nav_elev, globals->get_aircraft_position().getElevationM(), offset,
|
||||
loc_dist * SG_METER_TO_NM );
|
||||
} else {
|
||||
effective_range
|
||||
= adjustNavRange( nav_elev, pos.getElevationM(), _navaid->get_range() );
|
||||
= adjustNavRange( nav_elev, globals->get_aircraft_position().getElevationM(), _navaid->get_range() );
|
||||
}
|
||||
|
||||
double effective_range_m = effective_range * SG_NM_TO_METER;
|
||||
|
@ -679,17 +664,6 @@ void FGNavRadio::updateGlideSlope(double dt, const SGVec3d& aircraft, double sig
|
|||
->setDoubleValue( gs_rate_of_climb_node->getDoubleValue() * 60 );
|
||||
}
|
||||
|
||||
void FGNavRadio::updateDME(const SGVec3d& aircraft)
|
||||
{
|
||||
if (!_dme || !dme_serviceable_node->getBoolValue()) {
|
||||
_dmeInRange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
double dme_distance = dist(aircraft, _dme->cart());
|
||||
_dmeInRange = (dme_distance < _dme->get_range() * SG_NM_TO_METER);
|
||||
}
|
||||
|
||||
void FGNavRadio::valueChanged (SGPropertyNode* prop)
|
||||
{
|
||||
if (prop == gps_course_node) {
|
||||
|
@ -849,9 +823,10 @@ void FGNavRadio::updateCDI(double dt)
|
|||
last_xtrack_error = _cdiCrossTrackErrorM;
|
||||
}
|
||||
|
||||
void FGNavRadio::updateAudio()
|
||||
void FGNavRadio::updateAudio( double dt )
|
||||
{
|
||||
if (!_navaid || !inrange_node->getBoolValue() || !nav_serviceable_node->getBoolValue()) {
|
||||
_audioIdent->setIdent("", 0.0 );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -861,57 +836,13 @@ void FGNavRadio::updateAudio()
|
|||
|| !(bus_power_node->getDoubleValue() > 1.0)
|
||||
|| !ident_btn_node->getBoolValue()
|
||||
|| !audio_btn_node->getBoolValue() ) {
|
||||
_sgr->stop( nav_fx_name );
|
||||
_sgr->stop( dme_fx_name );
|
||||
_audioIdent->setIdent("", 0.0 );
|
||||
return;
|
||||
}
|
||||
|
||||
SGSoundSample *sound = _sgr->find( nav_fx_name );
|
||||
double vol = vol_btn_node->getFloatValue();
|
||||
SG_CLAMP_RANGE(vol, 0.0, 1.0);
|
||||
_audioIdent->setIdent( _navaid->get_trans_ident(), vol_btn_node->getFloatValue() );
|
||||
|
||||
if ( sound != NULL ) {
|
||||
sound->set_volume( vol );
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Can't find nav-vor-ident sound" );
|
||||
}
|
||||
|
||||
sound = _sgr->find( dme_fx_name );
|
||||
if ( sound != NULL ) {
|
||||
sound->set_volume( vol );
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Can't find nav-dme-ident sound" );
|
||||
}
|
||||
|
||||
const int NUM_IDENT_SLOTS = 5;
|
||||
const time_t SLOT_LENGTH = 5; // seconds
|
||||
|
||||
// There are N slots numbered 0 through (NUM_IDENT_SLOTS-1) inclusive.
|
||||
// Each slot is 5 seconds long.
|
||||
// Slots 0 is for DME
|
||||
// the rest are for azimuth.
|
||||
time_t now = globals->get_time_params()->get_cur_time();
|
||||
if ((now >= last_time) && (now < last_time + SLOT_LENGTH)) {
|
||||
return; // wait longer
|
||||
}
|
||||
|
||||
last_time = now;
|
||||
play_count++;
|
||||
play_count %= NUM_IDENT_SLOTS;
|
||||
|
||||
// Previous ident is out of time; if still playing, cut it off:
|
||||
_sgr->stop( nav_fx_name );
|
||||
_sgr->stop( dme_fx_name );
|
||||
if (play_count == 0) { // the DME slot
|
||||
if (_dmeInRange && dme_serviceable_node->getBoolValue()) {
|
||||
// play DME ident
|
||||
if (vol > 0.05) _sgr->play_once( dme_fx_name );
|
||||
}
|
||||
} else { // NAV slot
|
||||
if (inrange_node->getBoolValue() && nav_serviceable_node->getBoolValue()) {
|
||||
if (vol > 0.05) _sgr->play_once(nav_fx_name);
|
||||
}
|
||||
}
|
||||
_audioIdent->update( dt );
|
||||
}
|
||||
|
||||
FGNavRecord* FGNavRadio::findPrimaryNavaid(const SGGeod& aPos, double aFreqMHz)
|
||||
|
@ -928,11 +859,9 @@ FGNavRecord* FGNavRadio::findPrimaryNavaid(const SGGeod& aPos, double aFreqMHz)
|
|||
void FGNavRadio::search()
|
||||
{
|
||||
_time_before_search_sec = 1.0;
|
||||
SGGeod pos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
|
||||
lat_node->getDoubleValue(), alt_node->getDoubleValue());
|
||||
double freq = freq_node->getDoubleValue();
|
||||
|
||||
FGNavRecord* nav = findPrimaryNavaid(pos, freq);
|
||||
FGNavRecord* nav = findPrimaryNavaid(globals->get_aircraft_position(), freq);
|
||||
if (nav == _navaid) {
|
||||
return; // found the same as last search, we're done
|
||||
}
|
||||
|
@ -940,16 +869,10 @@ void FGNavRadio::search()
|
|||
_navaid = nav;
|
||||
string identBuffer(4, ' ');
|
||||
if (nav) {
|
||||
// use ILS signals as DME, otherwise search by frequency
|
||||
if (nav->type()==FGPositioned::ILS)
|
||||
_dme = nav;
|
||||
else
|
||||
_dme = globals->get_dmelist()->findByFreq(freq, pos);
|
||||
|
||||
nav_id_node->setStringValue(nav->get_ident());
|
||||
identBuffer = simgear::strutils::rpad( nav->ident(), 4, ' ' );
|
||||
|
||||
effective_range = adjustNavRange(nav->get_elev_ft(), pos.getElevationM(), nav->get_range());
|
||||
effective_range = adjustNavRange(nav->get_elev_ft(), globals->get_aircraft_position().getElevationM(), nav->get_range());
|
||||
loc_node->setBoolValue(nav->type() != FGPositioned::VOR);
|
||||
twist = nav->get_multiuse();
|
||||
|
||||
|
@ -958,7 +881,7 @@ void FGNavRadio::search()
|
|||
_gs = NULL;
|
||||
has_gs_node->setBoolValue(false);
|
||||
} else { // ILS or LOC
|
||||
_gs = globals->get_gslist()->findByFreq(freq, pos);
|
||||
_gs = globals->get_gslist()->findByFreq(freq, globals->get_aircraft_position());
|
||||
has_gs_node->setBoolValue(_gs != NULL);
|
||||
_localizerWidth = nav->localizerWidth();
|
||||
twist = 0.0;
|
||||
|
@ -986,16 +909,12 @@ void FGNavRadio::search()
|
|||
} // of have glideslope
|
||||
} // of found LOC or ILS
|
||||
|
||||
audioNavidChanged();
|
||||
} else { // found nothing
|
||||
_gs = NULL;
|
||||
_dme = NULL;
|
||||
nav_id_node->setStringValue("");
|
||||
loc_node->setBoolValue(false);
|
||||
has_gs_node->setBoolValue(false);
|
||||
|
||||
_sgr->remove( nav_fx_name );
|
||||
_sgr->remove( dme_fx_name );
|
||||
_audioIdent->setIdent("", 0.0 );
|
||||
}
|
||||
|
||||
is_valid_node->setBoolValue(nav != NULL);
|
||||
|
@ -1004,33 +923,3 @@ void FGNavRadio::search()
|
|||
id_c3_node->setIntValue( (int)identBuffer[2] );
|
||||
id_c4_node->setIntValue( (int)identBuffer[3] );
|
||||
}
|
||||
|
||||
void FGNavRadio::audioNavidChanged()
|
||||
{
|
||||
if (_sgr->exists(nav_fx_name)) {
|
||||
_sgr->remove(nav_fx_name);
|
||||
}
|
||||
|
||||
try {
|
||||
string trans_ident(_navaid->get_trans_ident());
|
||||
SGSoundSample* sound = FGMorse::instance()->make_ident(trans_ident, LO_FREQUENCY);
|
||||
sound->set_volume( 0.3 );
|
||||
if (!_sgr->add( sound, nav_fx_name )) {
|
||||
SG_LOG(SG_COCKPIT, SG_WARN, "Failed to add v1-vor-ident sound");
|
||||
}
|
||||
|
||||
if ( _sgr->exists( dme_fx_name ) ) {
|
||||
_sgr->remove( dme_fx_name );
|
||||
}
|
||||
|
||||
sound = FGMorse::instance()->make_ident( trans_ident, HI_FREQUENCY );
|
||||
sound->set_volume( 0.3 );
|
||||
_sgr->add( sound, dme_fx_name );
|
||||
|
||||
int offset = (int)(sg_random() * 30.0);
|
||||
play_count = offset / 4;
|
||||
last_time = globals->get_time_params()->get_cur_time() - offset;
|
||||
} catch (sg_io_exception& e) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, e.getFormattedMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,9 +45,6 @@ class FGNavRadio : public SGSubsystem, public SGPropertyChangeListener
|
|||
SGInterpTable *high_tbl;
|
||||
|
||||
SGPropertyNode_ptr _radio_node;
|
||||
SGPropertyNode_ptr lon_node;
|
||||
SGPropertyNode_ptr lat_node;
|
||||
SGPropertyNode_ptr alt_node;
|
||||
SGPropertyNode_ptr bus_power_node;
|
||||
|
||||
// property inputs
|
||||
|
@ -65,7 +62,6 @@ class FGNavRadio : public SGSubsystem, public SGPropertyChangeListener
|
|||
SGPropertyNode_ptr cdi_serviceable_node;
|
||||
SGPropertyNode_ptr gs_serviceable_node;
|
||||
SGPropertyNode_ptr tofrom_serviceable_node;
|
||||
SGPropertyNode_ptr dme_serviceable_node;
|
||||
|
||||
// property outputs
|
||||
SGPropertyNode_ptr fmt_freq_node; // formated frequency
|
||||
|
@ -131,9 +127,6 @@ class FGNavRadio : public SGSubsystem, public SGPropertyChangeListener
|
|||
FGNavRecordPtr _navaid;
|
||||
FGNavRecordPtr _gs;
|
||||
|
||||
string nav_fx_name;
|
||||
string dme_fx_name;
|
||||
|
||||
double target_radial;
|
||||
double effective_range;
|
||||
double target_gs;
|
||||
|
@ -152,9 +145,6 @@ class FGNavRadio : public SGSubsystem, public SGPropertyChangeListener
|
|||
|
||||
SGVec3d _gsCart, _gsAxis, _gsVertical, _gsBaseline;
|
||||
|
||||
FGNavRecordPtr _dme;
|
||||
bool _dmeInRange;
|
||||
|
||||
// CDI properties
|
||||
bool _toFlag, _fromFlag;
|
||||
double _cdiDeflection;
|
||||
|
@ -163,8 +153,7 @@ class FGNavRadio : public SGSubsystem, public SGPropertyChangeListener
|
|||
double _gsNeedleDeflectionNorm;
|
||||
double _gsDirect;
|
||||
|
||||
SGSharedPtr<SGSampleGroup> _sgr;
|
||||
std::vector<SGPropertyNode_ptr> _tiedNodes;
|
||||
class AudioIdent * _audioIdent;
|
||||
|
||||
bool updateWithPower(double aDt);
|
||||
|
||||
|
@ -176,11 +165,9 @@ class FGNavRadio : public SGSubsystem, public SGPropertyChangeListener
|
|||
double adjustILSRange( double stationElev, double aircraftElev,
|
||||
double offsetDegrees, double distance );
|
||||
|
||||
void updateAudio();
|
||||
void audioNavidChanged();
|
||||
void updateAudio( double dt );
|
||||
|
||||
void updateReceiver(double dt);
|
||||
void updateDME(const SGVec3d& aircraft);
|
||||
void updateGlideSlope(double dt, const SGVec3d& aircraft, double signal_quality_norm);
|
||||
void updateGPSSlaved();
|
||||
void updateCDI(double dt);
|
||||
|
@ -193,17 +180,6 @@ class FGNavRadio : public SGSubsystem, public SGPropertyChangeListener
|
|||
bool isOperable() const
|
||||
{ return _operable; }
|
||||
|
||||
/**
|
||||
* Tied-properties helper, record nodes which are tied for easy un-tie-ing
|
||||
*/
|
||||
template <typename T>
|
||||
void tie(const char* aRelPath, const SGRawValue<T>& aRawValue)
|
||||
{
|
||||
SGPropertyNode_ptr nd = _radio_node->getNode(aRelPath, true);
|
||||
_tiedNodes.push_back(nd);
|
||||
nd->tie(aRawValue);
|
||||
}
|
||||
|
||||
// implement SGPropertyChangeListener
|
||||
virtual void valueChanged (SGPropertyNode * prop);
|
||||
public:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
include(FlightGearComponent)
|
||||
|
||||
set(SOURCES
|
||||
audioident.cxx
|
||||
soundgenerator.cxx
|
||||
beacon.cxx
|
||||
fg_fx.cxx
|
||||
|
@ -11,6 +12,7 @@ set(SOURCES
|
|||
)
|
||||
|
||||
set(HEADERS
|
||||
audioident.hxx
|
||||
soundgenerator.hxx
|
||||
beacon.hxx
|
||||
fg_fx.hxx
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
noinst_LIBRARIES = libSound.a
|
||||
|
||||
libSound_a_SOURCES = \
|
||||
audioident.cxx audioident.hxx \
|
||||
soundgenerator.cxx soundgenerator.hxx \
|
||||
beacon.cxx beacon.hxx \
|
||||
fg_fx.cxx fg_fx.hxx \
|
||||
|
|
141
src/Sound/audioident.cxx
Normal file
141
src/Sound/audioident.cxx
Normal file
|
@ -0,0 +1,141 @@
|
|||
// audioident.cxx -- audible station identifiers
|
||||
//
|
||||
// Written by Torsten Dreyer, September 2011
|
||||
//
|
||||
// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include "audioident.hxx"
|
||||
#include <simgear/sg_inlines.h>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Sound/Morse.hxx>
|
||||
|
||||
AudioIdent::AudioIdent( const std::string & fx_name, const double interval_secs, const int frequency_hz ) :
|
||||
_fx_name(fx_name),
|
||||
_frequency(frequency_hz),
|
||||
_timer(0.0),
|
||||
_interval(interval_secs),
|
||||
_running(false)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioIdent::init()
|
||||
{
|
||||
_timer = 0.0;
|
||||
_ident = "";
|
||||
_running = false;
|
||||
_sgr = globals->get_soundmgr()->find("avionics", true);
|
||||
_sgr->tie_to_listener();
|
||||
}
|
||||
|
||||
void AudioIdent::stop()
|
||||
{
|
||||
if( _sgr->exists( _fx_name ) )
|
||||
_sgr->stop( _fx_name );
|
||||
_running = false;
|
||||
}
|
||||
|
||||
void AudioIdent::start()
|
||||
{
|
||||
_timer = _interval;
|
||||
_sgr->play_once(_fx_name);
|
||||
_running = true;
|
||||
}
|
||||
|
||||
void AudioIdent::setVolumeNorm( double volumeNorm )
|
||||
{
|
||||
SG_CLAMP_RANGE(volumeNorm, 0.0, 1.0);
|
||||
|
||||
SGSoundSample *sound = _sgr->find( _fx_name );
|
||||
|
||||
if ( sound != NULL ) {
|
||||
sound->set_volume( volumeNorm );
|
||||
}
|
||||
}
|
||||
|
||||
void AudioIdent::setIdent( const std::string & ident, double volumeNorm )
|
||||
{
|
||||
if( _ident == ident ) {
|
||||
if( false == _ident.empty() )
|
||||
setVolumeNorm( volumeNorm );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
stop();
|
||||
|
||||
if ( _sgr->exists( _fx_name ) )
|
||||
_sgr->remove( _fx_name );
|
||||
|
||||
if( false == ident.empty() ) {
|
||||
|
||||
SGSoundSample* sound = FGMorse::instance()->make_ident(ident, _frequency );
|
||||
sound->set_volume( volumeNorm );
|
||||
if (!_sgr->add( sound, _fx_name )) {
|
||||
SG_LOG(SG_SOUND, SG_WARN, "Failed to add sound '" << _fx_name << "' for ident '" << ident << "'" );
|
||||
return;
|
||||
}
|
||||
|
||||
start();
|
||||
}
|
||||
_ident = ident;
|
||||
|
||||
} catch (sg_io_exception& e) {
|
||||
SG_LOG(SG_SOUND, SG_ALERT, e.getFormattedMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AudioIdent::update( double dt )
|
||||
{
|
||||
// single-shot
|
||||
if( false == _running || _interval < SGLimitsd::min() )
|
||||
return;
|
||||
|
||||
_timer -= dt;
|
||||
|
||||
if( _timer < SGLimitsd::min() ) {
|
||||
_timer = _interval;
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: shall transmit at least 6 wpm (ICAO Annex 10 - 3.5.3.6.3)
|
||||
DMEAudioIdent::DMEAudioIdent( const std::string & fx_name )
|
||||
: AudioIdent( fx_name, 40, FGMorse::HI_FREQUENCY )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//FIXME: for co-located VOR/DME or ILS/DME, assign four time-slots
|
||||
// 3xVOR/ILS ident, 1xDME ident
|
||||
|
||||
// FIXME: shall transmit at approx. 7 wpm (ICAO Annex 10 - 3.3.6.5.1)
|
||||
VORAudioIdent::VORAudioIdent( const std::string & fx_name )
|
||||
: AudioIdent( fx_name, 10, FGMorse::LO_FREQUENCY )
|
||||
{
|
||||
}
|
||||
|
||||
//FIXME: LOCAudioIdent at approx 7wpm (ICAO Annex 10 - 3.1.3.9.4)
|
||||
// not less than six times per minute at approx equal intervals
|
||||
// frequency 1020+/-50Hz (3.1.3.9.2)
|
||||
|
||||
// FIXME: NDBAudioIdent at approx 7 wpm (ICAO ANNEX 10 - 3.4.5.1)
|
||||
// at least once every 10s (3.4.5.2.1)
|
||||
// frequency 1020+/-50Hz or 400+/-25Hz (3.4.5.4)
|
65
src/Sound/audioident.hxx
Normal file
65
src/Sound/audioident.hxx
Normal file
|
@ -0,0 +1,65 @@
|
|||
// audioident.hxx -- audible station identifiers
|
||||
//
|
||||
// Written by Torsten Dreyer, September 2011
|
||||
//
|
||||
// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
|
||||
#ifndef _FGAUDIOIDENT_HXX
|
||||
#define _FGAUDIOIDENT_HXX
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <simgear/sound/soundmgr_openal.hxx>
|
||||
|
||||
class AudioIdent {
|
||||
public:
|
||||
AudioIdent( const std::string & fx_name, const double interval_secs, const int frequency );
|
||||
void init();
|
||||
void setVolumeNorm( double volumeNorm );
|
||||
void setIdent( const std::string & ident, double volumeNorm );
|
||||
|
||||
void update( double dt );
|
||||
|
||||
private:
|
||||
void stop();
|
||||
void start();
|
||||
|
||||
SGSharedPtr<SGSampleGroup> _sgr;
|
||||
std::string _fx_name;
|
||||
const int _frequency;
|
||||
std::string _ident;
|
||||
double _timer;
|
||||
double _interval;
|
||||
bool _running;
|
||||
};
|
||||
|
||||
class DMEAudioIdent : public AudioIdent {
|
||||
public:
|
||||
DMEAudioIdent( const std::string & fx_name );
|
||||
};
|
||||
|
||||
class VORAudioIdent : public AudioIdent {
|
||||
public:
|
||||
VORAudioIdent( const std::string & fx_name );
|
||||
};
|
||||
|
||||
#endif // _FGAUDIOIDENT_HXX
|
|
@ -26,6 +26,12 @@
|
|||
|
||||
#include <cstring>
|
||||
|
||||
static const char DI = '1';
|
||||
static const char DIT = '1';
|
||||
static const char DA = '2';
|
||||
static const char DAH = '2';
|
||||
static const char END = '0';
|
||||
|
||||
static const char alphabet[26][4] = {
|
||||
{ DI, DAH, END, END }, /* A */
|
||||
{ DA, DI, DI, DIT }, /* B */
|
||||
|
|
|
@ -75,23 +75,6 @@
|
|||
// Hz for the VOR ident.
|
||||
|
||||
|
||||
static const char DI = '1';
|
||||
static const char DIT = '1';
|
||||
static const char DA = '2';
|
||||
static const char DAH = '2';
|
||||
static const char END = '0';
|
||||
|
||||
static const int BYTES_PER_SECOND = 22050;
|
||||
// static const int BEAT_LENGTH = 240; // milleseconds (5 wpm)
|
||||
static const int BEAT_LENGTH = 92; // milleseconds (13 wpm)
|
||||
static const int TRANSITION_BYTES = (int)(0.005 * BYTES_PER_SECOND);
|
||||
static const int COUNT_SIZE = BYTES_PER_SECOND * BEAT_LENGTH / 1000;
|
||||
static const int DIT_SIZE = 2 * COUNT_SIZE; // 2 counts
|
||||
static const int DAH_SIZE = 4 * COUNT_SIZE; // 4 counts
|
||||
static const int SPACE_SIZE = 3 * COUNT_SIZE; // 3 counts
|
||||
static const int LO_FREQUENCY = 1020; // AIM 1-1-7 (f) specified in Hz
|
||||
static const int HI_FREQUENCY = 1350; // AIM 1-1-7 (f) specified in Hz
|
||||
|
||||
// manages everything we need to know for an individual sound sample
|
||||
class FGMorse : public FGSoundGenerator {
|
||||
|
||||
|
@ -113,6 +96,17 @@ private:
|
|||
bool init();
|
||||
|
||||
public:
|
||||
static const int BYTES_PER_SECOND = 22050;
|
||||
// static const int BEAT_LENGTH = 240; // milleseconds (5 wpm)
|
||||
static const int BEAT_LENGTH = 92; // milleseconds (13 wpm)
|
||||
static const int TRANSITION_BYTES = (int)(0.005 * BYTES_PER_SECOND);
|
||||
static const int COUNT_SIZE = BYTES_PER_SECOND * BEAT_LENGTH / 1000;
|
||||
static const int DIT_SIZE = 2 * COUNT_SIZE; // 2 counts
|
||||
static const int DAH_SIZE = 4 * COUNT_SIZE; // 4 counts
|
||||
static const int SPACE_SIZE = 3 * COUNT_SIZE; // 3 counts
|
||||
static const int LO_FREQUENCY = 1020; // AIM 1-1-7 (f) specified in Hz
|
||||
static const int HI_FREQUENCY = 1350; // AIM 1-1-7 (f) specified in Hz
|
||||
|
||||
|
||||
FGMorse();
|
||||
~FGMorse();
|
||||
|
|
Loading…
Reference in a new issue