1
0
Fork 0

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:
Torsten Dreyer 2011-09-15 21:28:30 +02:00
parent 2de3872d66
commit 43109feb0c
14 changed files with 323 additions and 262 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -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" );

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 */

View file

@ -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();