From 977cfb77b5e7530014b03572a4ffaef3562d6712 Mon Sep 17 00:00:00 2001 From: f-jjth Date: Wed, 8 May 2013 17:34:20 +0200 Subject: [PATCH] Improve transponder instrumentation: new version --- src/Instrumentation/altimeter.cxx | 24 +++- src/Instrumentation/altimeter.hxx | 6 +- src/Instrumentation/transponder.cxx | 199 +++++++++++++++++++++++----- src/Instrumentation/transponder.hxx | 56 ++++++-- src/MultiPlayer/multiplaymgr.cxx | 4 + 5 files changed, 241 insertions(+), 48 deletions(-) diff --git a/src/Instrumentation/altimeter.cxx b/src/Instrumentation/altimeter.cxx index d9e858515..700a48c50 100644 --- a/src/Instrumentation/altimeter.cxx +++ b/src/Instrumentation/altimeter.cxx @@ -41,6 +41,11 @@ Altimeter::Altimeter ( SGPropertyNode *node, double quantum ) _quantum(node->getDoubleValue("quantum", quantum)), _settingInHg(29.921260) { + // FIXME: change default to false once all aircraft which use + // altimiter as an encoder are converted to request this explicitly + _encodeModeC = node->getBoolValue("encode-mode-c", true); + _encodeModeS = node->getBoolValue("encode-mode-s", false); + _tiedProperties.setRoot( _rootNode ); } @@ -78,7 +83,14 @@ Altimeter::init () _pressure_node = fgGetNode(_static_pressure.c_str(), true); _serviceable_node = _rootNode->getChild("serviceable", 0, true); _press_alt_node = _rootNode->getChild("pressure-alt-ft", 0, true); - _mode_c_node = _rootNode->getChild("mode-c-alt-ft", 0, true); + if (_encodeModeC) { + _mode_c_node = _rootNode->getChild("mode-c-alt-ft", 0, true); + } + + if (_encodeModeS) { + _mode_s_node = _rootNode->getChild("mode-s-alt-ft", 0, true); + } + _altitude_node = _rootNode->getChild("indicated-altitude-ft", 0, true); reinit(); @@ -113,7 +125,15 @@ Altimeter::update (double dt) double press_alt = _press_alt_node->getDoubleValue(); // The mechanism settles slowly toward new pressure altitude: _raw_PA = fgGetLowPass(_raw_PA, _altimeter.press_alt_ft(pressure), trat); - _mode_c_node->setDoubleValue(100 * SGMiscd::round(_raw_PA/100)); + + if (_encodeModeC) { + _mode_c_node->setDoubleValue(100 * SGMiscd::round(_raw_PA/100)); + } + + if (_encodeModeS) { + _mode_s_node->setDoubleValue(10 * SGMiscd::round(_raw_PA/10)); + } + _kollsman = fgGetLowPass(_kollsman, _altimeter.kollsman_ft(_settingInHg), trat); if (_quantum) press_alt = _quantum * SGMiscd::round(_raw_PA/_quantum); diff --git a/src/Instrumentation/altimeter.hxx b/src/Instrumentation/altimeter.hxx index 121cafa7c..d45a1249e 100644 --- a/src/Instrumentation/altimeter.hxx +++ b/src/Instrumentation/altimeter.hxx @@ -54,11 +54,15 @@ private: double _kollsman; double _raw_PA; double _settingInHg; - + bool _encodeModeC; + bool _encodeModeS; + SGPropertyNode_ptr _serviceable_node; SGPropertyNode_ptr _pressure_node; SGPropertyNode_ptr _press_alt_node; SGPropertyNode_ptr _mode_c_node; + SGPropertyNode_ptr _mode_s_node; + SGPropertyNode_ptr _transponder_node; SGPropertyNode_ptr _altitude_node; FGAltimeter _altimeter; diff --git a/src/Instrumentation/transponder.cxx b/src/Instrumentation/transponder.cxx index 01b34b662..002b6c0bd 100644 --- a/src/Instrumentation/transponder.cxx +++ b/src/Instrumentation/transponder.cxx @@ -3,6 +3,7 @@ // Written by Roy Vegard Ovesen, started September 2004. // // Copyright (C) 2004 Roy Vegard Ovesen - rvovesen@tiscali.no +// Copyright (C) 2013 Clement de l'Hamaide - clemaez@hotmail.fr // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -17,6 +18,13 @@ // 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. +// +// Example invocation, in the instrumentation.xml file: +// +// encoder +// 0 +// 0 // Mode A = 0, Mode C = 1, Mode S = 2 +// #ifdef HAVE_CONFIG_H # include @@ -24,15 +32,29 @@ #include "transponder.hxx" +#include +#include +#include + +#include
+ +#include + using std::string; +const double IDENT_TIMEOUT = 18.0; // 18 seconds +const int INVALID_ALTITUDE = -9999; +const int INVALID_ID = -9999; + Transponder::Transponder(SGPropertyNode *node) : _name(node->getStringValue("name", "transponder")), _num(node->getIntValue("number", 0)), - _mode_c_altitude(node->getStringValue("mode-c-altitude", - "/instrumentation/encoder/mode-c-alt-ft")) + _mode((Mode) node->getIntValue("mode", 1)), + _listener_active(0) { + _requiredBusVolts = node->getDoubleValue("bus-volts", 8.0); + _altitudeSourcePath = node->getStringValue("encoder-path", "/instrumentation/altimeter"); } @@ -47,46 +69,153 @@ void Transponder::init() branch = "/instrumentation/" + _name; SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true ); + // Inputs - pressureAltitudeNode = fgGetNode(_mode_c_altitude.c_str(), true); - busPowerNode = fgGetNode("/systems/electrical/outputs/transponder", true); - serviceableNode = node->getChild("serviceable", 0, true); + _busPower_node = fgGetNode("/systems/electrical/outputs/transponder", true); + _pressureAltitude_node = fgGetNode(_altitudeSourcePath, true); + + SGPropertyNode *in_node = node->getChild("inputs", 0, true); + for (int i=0; i<4;++i) { + _digit_node[i] = in_node->getChild("digit", i, true); + _digit_node[i]->addChangeListener(this); + } + + _knob_node = in_node->getChild("knob-mode", 0, true); // 0=OFF, 1=SBY, 2=ON, 3=ALT, 4=TST + if (!_knob_node->hasValue()) { + _knob_node->setIntValue(0); + } + + _mode_node = in_node->getChild("mode", 0, true); + _mode_node->setIntValue(_mode); + _mode_node->addChangeListener(this); + + _identBtn_node = in_node->getChild("ident-btn", 0, true); + _identBtn_node->setBoolValue(false); + _identBtn_node->addChangeListener(this); + + _serviceable_node = node->getChild("serviceable", 0, true); + _serviceable_node->setBoolValue(true); + + _idCode_node = node->getChild("id-code", 0, true); + _idCode_node->addChangeListener(this); + // set default, but don't overwrite value from preferences.xml or -set.xml + if (!_idCode_node->hasValue()) { + _idCode_node->setIntValue(1200); + } + // Outputs - idCodeNode = node->getChild("id-code", 0, true); - flightLevelNode = node->getChild("flight-level", 0, true); + _altitude_node = node->getChild("altitude", 0, true); + _altitudeValid_node = node->getChild("altitude-valid", 0, true); + _ident_node = node->getChild("ident", 0, true); + _transmittedId_node = node->getChild("transmitted-id", 0, true); } void Transponder::update(double dt) { - if (serviceableNode->getBoolValue()) + if (has_power() && _serviceable_node->getBoolValue()) + { + // Mode C & S send also altitude + Mode effectiveMode = (_knob_node->getIntValue() == KNOB_ALT) ? _mode : MODE_A; + SGPropertyNode* altitudeSource = NULL; + + switch (effectiveMode) { + case MODE_C: + altitudeSource = _pressureAltitude_node->getChild("mode-c-alt-ft"); + break; + case MODE_S: + altitudeSource = _pressureAltitude_node->getChild("mode-s-alt-ft"); + break; + default: + break; + } + + int alt = INVALID_ALTITUDE; + if (effectiveMode != MODE_A) { + if (altitudeSource) { + alt = altitudeSource->getIntValue(); + } else { + // warn if altitude input is misconfigured + SG_LOG(SG_INSTR, SG_INFO, "transponder altitude input for mode " << _mode << " is missing"); + } + } + + _altitude_node->setIntValue(alt); + _altitudeValid_node->setBoolValue(alt != INVALID_ALTITUDE); + + if ( _identMode ) { + _identTime += dt; + if ( _identTime > IDENT_TIMEOUT ) { + // reset ident mode + _ident_node->setBoolValue(false); + _identMode = false; + } + } + + _transmittedId_node->setIntValue(_idCode_node->getIntValue()); + } + else { - int idCode = idCodeNode->getIntValue(); - if (idCode < 0) - idCode = 0; - int firstDigit = idCode % 10; - int secondDigit = (idCode/10) % 10; - int thirdDigit = (idCode/100) % 10; - int fourthDigit = (idCode/1000) % 10; - - if (firstDigit-7 > 0) - idCode -= firstDigit-7; - if (secondDigit-7 > 0) - idCode -= (secondDigit-7) * 10; - if (thirdDigit-7 > 0) - idCode -= (thirdDigit-7) * 100; - if (fourthDigit-7 > 0) - idCode -= (fourthDigit-7) * 1000; - - if (idCode > 7777) - idCode = 7777; - else if (idCode < 0) - idCode = 0; - - idCodeNode->setIntValue(idCode); - - int pressureAltitude = pressureAltitudeNode->getIntValue(); - int flightLevel = pressureAltitude / 100; - flightLevelNode->setIntValue(flightLevel); + _altitude_node->setIntValue(INVALID_ALTITUDE); + _altitudeValid_node->setBoolValue(false); + _ident_node->setBoolValue(false); + _transmittedId_node->setIntValue(INVALID_ID); } } + +static int powersOf10[4] = {1, 10, 100, 1000}; + +static int extractCodeDigit(int code, int index) +{ + return (code / powersOf10[index]) % 10; +} + +static int modifyCodeDigit(int code, int index, int digitValue) +{ + assert(digitValue >= 0 && digitValue < 8); + int p = powersOf10[index]; + int codeWithoutDigit = code - (extractCodeDigit(code, index) * p); + return codeWithoutDigit + (digitValue * p); +} + +void Transponder::valueChanged(SGPropertyNode *prop) +{ + // Ident button pressed + if ((prop == _identBtn_node) && prop->getBoolValue()) { + _identTime = 0.0; + _ident_node->setBoolValue(true); + _identMode = true; + return; + } + + if (prop == _mode_node) { + _mode = static_cast(prop->getIntValue()); + return; + } + + if (_listener_active) + return; + + _listener_active++; + + if (prop == _idCode_node) { + // keep the digits in-sync + for (int i=0; i<4; ++i) { + _digit_node[i]->setIntValue(extractCodeDigit(prop->getIntValue(), i)); + } + } else { + // digit node + int index = prop->getIndex(); + int digitValue = prop->getIntValue(); + SG_CLAMP_RANGE(digitValue, 0, 7); + _idCode_node->setIntValue(modifyCodeDigit(_idCode_node->getIntValue(), index, digitValue)); + prop->setIntValue(digitValue); + } + + _listener_active--; +} + +bool Transponder::has_power() const +{ + return (_knob_node->getIntValue() > KNOB_STANDBY) && (_busPower_node->getDoubleValue() > _requiredBusVolts); +} diff --git a/src/Instrumentation/transponder.hxx b/src/Instrumentation/transponder.hxx index d41514e08..728250f8b 100644 --- a/src/Instrumentation/transponder.hxx +++ b/src/Instrumentation/transponder.hxx @@ -3,6 +3,7 @@ // Written by Roy Vegard Ovesen, started September 2004. // // Copyright (C) 2004 Roy Vegard Ovesen - rvovesen@tiscali.no +// Copyright (C) 2013 Clement de l'Hamaide - clemaez@hotmail.fr // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -30,29 +31,64 @@ #include -class Transponder : public SGSubsystem +class Transponder : public SGSubsystem, public SGPropertyChangeListener { public: Transponder(SGPropertyNode *node); - ~Transponder(); + virtual ~Transponder(); - void init (); - void update (double dt); + virtual void init (); + virtual void update (double dt); private: + enum Mode + { + MODE_A = 0, + MODE_C, + MODE_S + }; + + enum KnobPosition + { + KNOB_OFF = 0, + KNOB_STANDBY, + KNOB_ON, + KNOB_ALT, + KNOB_TEST + }; + // Inputs - SGPropertyNode_ptr pressureAltitudeNode; - SGPropertyNode_ptr busPowerNode; - SGPropertyNode_ptr serviceableNode; + SGPropertyNode_ptr _pressureAltitude_node; + SGPropertyNode_ptr _busPower_node; + SGPropertyNode_ptr _serviceable_node; + + SGPropertyNode_ptr _mode_node; + SGPropertyNode_ptr _knob_node; + SGPropertyNode_ptr _idCode_node; + SGPropertyNode_ptr _digit_node[4]; + + + SGPropertyNode_ptr _identBtn_node; + bool _identMode; // Outputs - SGPropertyNode_ptr idCodeNode; - SGPropertyNode_ptr flightLevelNode; + SGPropertyNode_ptr _altitude_node; + SGPropertyNode_ptr _altitudeValid_node; + SGPropertyNode_ptr _transmittedId_node; + SGPropertyNode_ptr _ident_node; // Internal std::string _name; int _num; - std::string _mode_c_altitude; + Mode _mode; + double _identTime; + int _listener_active; + double _requiredBusVolts; + std::string _altitudeSourcePath; + + void valueChanged (SGPropertyNode *); + int setMinMax(int val); + bool has_power() const; }; #endif // TRANSPONDER_HXX diff --git a/src/MultiPlayer/multiplaymgr.cxx b/src/MultiPlayer/multiplaymgr.cxx index 7d6ce8b33..62ca039de 100644 --- a/src/MultiPlayer/multiplaymgr.cxx +++ b/src/MultiPlayer/multiplaymgr.cxx @@ -173,6 +173,10 @@ static const IdPropertyList sIdPropertyList[] = { {1400, "scenery/events", simgear::props::STRING}, + {1500, "instrumentation/transponder/transmitted-id", simgear::props::INT}, + {1501, "instrumentation/transponder/altitude", simgear::props::INT}, + {1502, "instrumentation/transponder/ident", simgear::props::BOOL}, + {10001, "sim/multiplay/transmission-freq-hz", simgear::props::STRING}, {10002, "sim/multiplay/chat", simgear::props::STRING}, -- 2.39.5