From 98c0a61db368cbceff182c1b8d54a108ec193580 Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Wed, 27 May 2015 13:23:45 +0200 Subject: [PATCH] Add 8.33 kHz support to the commradio Usage: Add comm 0 true to the instrumentation.xml If eight-point-three is disabled nor not present, previous functionality is unchanged If eight-point-three is enabled, set /instrumentation/comm[x]/frequencies/[selected|standby]-mhz to the desired 8.33 channel (118.000..136.990) or /instrumentation/comm[x]/frequencies/[selected|standby]-channel to the desired channel-number (0..3039). Valid channels are: xxx.000 xxx.005 xxx.010 xxx.015 xxx.025 xxx.030 xxx.035 xxx.040 xxx.050 xxx.055 xxx.060 xxx.065 xxx.075 xxx.080 xxx.085 xxx.090 where 118.0 <= xxx <= 136.990 --- src/Instrumentation/commradio.cxx | 158 +++++++++++++++++++-- src/Instrumentation/frequencyformatter.hxx | 18 ++- 2 files changed, 161 insertions(+), 15 deletions(-) diff --git a/src/Instrumentation/commradio.cxx b/src/Instrumentation/commradio.cxx index 9c8265a6e..3fdd62956 100644 --- a/src/Instrumentation/commradio.cxx +++ b/src/Instrumentation/commradio.cxx @@ -341,6 +341,119 @@ void MetarBridge::valueChanged(SGPropertyNode * node) } } +/* ------------- 8.3kHz Channel implementation ---------------------- */ + +class EightPointThreeFrequencyFormatter : + public FrequencyFormatterBase, + public SGPropertyChangeListener { +public: + EightPointThreeFrequencyFormatter( SGPropertyNode_ptr root, + const char * channel, + const char * fmt, + const char * width, + const char * frq, + const char * cnum ) : + _channel( root, channel ), + _frequency( root, frq ), + _channelSpacing( root, width ), + _formattedChannel( root, fmt ), + _channelNum( root, cnum ) + { + // ensure properties exist. + _channel.node(true); + _frequency.node(true); + _channelSpacing.node(true); + _channelNum.node(true); + _formattedChannel.node(true); + + _channel.node()->addChangeListener( this, true ); + _channelNum.node()->addChangeListener( this, true ); + } + + virtual ~EightPointThreeFrequencyFormatter() + { + _channel.node()->removeChangeListener( this ); + _channelNum.node()->removeChangeListener( this ); + } + +private: + EightPointThreeFrequencyFormatter( const EightPointThreeFrequencyFormatter & ); + EightPointThreeFrequencyFormatter & operator = ( const EightPointThreeFrequencyFormatter & ); + + void valueChanged (SGPropertyNode * prop) { + if( prop == _channel.node() ) + setFrequency(prop->getDoubleValue()); + else if( prop == _channelNum.node() ) + setChannel(prop->getIntValue()); + } + + void setChannel( int channel ) { + channel %= 3040; + if( channel < 0 ) channel += 3040; + double f = 118.000 + 0.025*(channel/4) + 0.005*(channel%4); + if( f != _channel ) _channel = f; + } + + void setFrequency( double channel ) { + // format as fixed decimal "nnn.nnn" + std::ostringstream buf; + buf << std::fixed + << std::setw(6) + << std::setfill('0') + << std::setprecision(3) + << _channel; + _formattedChannel = buf.str(); + + // sanitize range and round to nearest kHz. + unsigned c = static_cast(SGMiscd::round(SGMiscd::clip( channel, 118.0, 136.99 ) * 1000)); + + if ( (c % 25) == 0 ) { + // legacy 25kHz channels continue to be just that. + _channelSpacing = 25.0; + _frequency = c / 1000.0; + + int channelNum = (c-118000)/25*4; + if( channelNum != _channelNum ) _channelNum = channelNum; + + if( _frequency != channel ) { + _channel = _frequency; //triggers recursion + } + } else { + _channelSpacing = 8.33; + + // 25kHz base frequency: xxx.000, xxx.025, xxx.050, xxx.075 + unsigned base25 = (c/25) * 25; + + // add n*8.33 to the 25kHz frequency + unsigned subChannel = SGMisc::clip((c - base25)/5-1, 0, 2 ); + + _frequency = (base25 + 8.33 * subChannel)/1000.0; + + int channelNum = (base25-118000)/25*4 + subChannel+1; + if( channelNum != _channelNum ) _channelNum = channelNum; + + // set to correct channel on bogous input + double sanitizedChannel = (base25 + 5*(subChannel+1))/1000.0; + if( sanitizedChannel != channel ) { + _channel = sanitizedChannel; // triggers recursion + } + } + } + + double getFrequency() const { + return _channel; + } + + + PropertyObject _channel; + PropertyObject _frequency; + PropertyObject _channelSpacing; + PropertyObject _formattedChannel; + PropertyObject _channelNum; + +}; + + /* ------------- The CommRadio implementation ---------------------- */ class CommRadioImpl: public CommRadio, OutputProperties { @@ -365,8 +478,8 @@ private: #if defined(ENABLE_FLITE) AtisSpeaker _atisSpeaker; #endif - FrequencyFormatter _useFrequencyFormatter; - FrequencyFormatter _stbyFrequencyFormatter; + SGSharedPtr _useFrequencyFormatter; + SGSharedPtr _stbyFrequencyFormatter; const SignalQualityComputerRef _signalQualityComputer; double _stationTTL; @@ -383,6 +496,7 @@ private: PropertyObject _atis; PropertyObject _addNoise; PropertyObject _cutoffSignalQuality; + }; CommRadioImpl::CommRadioImpl(SGPropertyNode_ptr node) @@ -390,12 +504,6 @@ CommRadioImpl::CommRadioImpl(SGPropertyNode_ptr node) fgGetNode("/instrumentation", true)->getNode(node->getStringValue("name", "comm"), node->getIntValue("number", 0), true)), _num(node->getIntValue("number", 0)), _metarBridge(new MetarBridge()), - _useFrequencyFormatter(_rootNode->getNode("frequencies/selected-mhz", true), - _rootNode->getNode("frequencies/selected-mhz-fmt", true), 0.025, 118.0, 137.0), - - _stbyFrequencyFormatter(_rootNode->getNode("frequencies/standby-mhz", true), - _rootNode->getNode("frequencies/standby-mhz-fmt", true), 0.025, 118.0, 137.0), - _signalQualityComputer(new SimpleDistanceSquareSignalQualityComputer()), _stationTTL(0.0), @@ -410,6 +518,36 @@ CommRadioImpl::CommRadioImpl(SGPropertyNode_ptr node) _addNoise(_rootNode->getNode("add-noise", true)), _cutoffSignalQuality(_rootNode->getNode("cutoff-signal-quality", true)) { + if( node->getBoolValue("eight-point-three", false ) ) { + _useFrequencyFormatter = new EightPointThreeFrequencyFormatter( + _rootNode->getNode("frequencies", true), + "selected-mhz", + "selected-mhz-fmt", + "selected-channel-width-khz", + "selected-real-frequency-mhz", + "selected-channel" + ); + _stbyFrequencyFormatter = new EightPointThreeFrequencyFormatter( + _rootNode->getNode("frequencies", true), + "standby-mhz", + "standby-mhz-fmt", + "standby-channel-width-khz", + "standby-real-frequency-mhz", + "standby-channel" + ); + } else { + _useFrequencyFormatter = new FrequencyFormatter( + _rootNode->getNode("frequencies/selected-mhz", true), + _rootNode->getNode("frequencies/selected-mhz-fmt", true), + 0.025, 118.0, 137.0); + + _stbyFrequencyFormatter = new FrequencyFormatter( + _rootNode->getNode("frequencies/standby-mhz", true), + _rootNode->getNode("frequencies/standby-mhz-fmt", true), + 0.025, 118.0, 137.0); + + + } } CommRadioImpl::~CommRadioImpl() @@ -520,8 +658,8 @@ void CommRadioImpl::update(double dt) return; } - if (_frequency != _useFrequencyFormatter.getFrequency()) { - _frequency = _useFrequencyFormatter.getFrequency(); + if (_frequency != _useFrequencyFormatter->getFrequency()) { + _frequency = _useFrequencyFormatter->getFrequency(); _stationTTL = 0.0; } diff --git a/src/Instrumentation/frequencyformatter.hxx b/src/Instrumentation/frequencyformatter.hxx index f36c78504..684e413fd 100644 --- a/src/Instrumentation/frequencyformatter.hxx +++ b/src/Instrumentation/frequencyformatter.hxx @@ -2,8 +2,17 @@ #define __FREQUENCY_FORMATTER_HXX /* ------------- A NAV/COMM Frequency formatter ---------------------- */ +class FrequencyFormatterBase : public SGReferenced { +public: + virtual ~FrequencyFormatterBase() + { + } + + virtual double getFrequency() const = 0; + +}; -class FrequencyFormatter : public SGPropertyChangeListener { +class FrequencyFormatter : public FrequencyFormatterBase, public SGPropertyChangeListener { public: FrequencyFormatter( SGPropertyNode_ptr freqNode, SGPropertyNode_ptr fmtFreqNode, double channelSpacing, double min, double max ) : _freqNode( freqNode ), @@ -12,10 +21,9 @@ public: _min(min), _max(max) { - _freqNode->addChangeListener( this ); - valueChanged(_freqNode); + _freqNode->addChangeListener( this, true ); } - ~FrequencyFormatter() + virtual ~FrequencyFormatter() { _freqNode->removeChangeListener( this ); } @@ -32,7 +40,7 @@ public: _fmtFreqNode->setStringValue( buf.str() ); } - double getFrequency() const + virtual double getFrequency() const { double d = SGMiscd::roundToInt(_freqNode->getDoubleValue() / _channelSpacing) * _channelSpacing; // strip last digit, do not round -- 2.39.5