]> git.mxchange.org Git - flightgear.git/commitdiff
Improve transponder instrumentation: new version
authorf-jjth <clemaez@hotmail.fr>
Wed, 8 May 2013 15:34:20 +0000 (17:34 +0200)
committerJames Turner <zakalawe@mac.com>
Fri, 10 May 2013 18:04:53 +0000 (19:04 +0100)
src/Instrumentation/altimeter.cxx
src/Instrumentation/altimeter.hxx
src/Instrumentation/transponder.cxx
src/Instrumentation/transponder.hxx
src/MultiPlayer/multiplaymgr.cxx

index d9e858515a2bb1ac4ebf74f82f12c66598b79349..700a48c501723f089c55bd3c6b5078a11de3de6f 100644 (file)
@@ -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);
index 121cafa7ce72b2ea1af6a8c0bc146112b09d8fca..d45a1249eeb340c114fdc43008d575e59ef2d50a 100644 (file)
@@ -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;
index 01b34b6620ac12796625ec4710b93b5f38af7f65..002b6c0bdf34b634b60964c730d1a62dde3a7cc5 100644 (file)
@@ -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
 // 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:
+//      <transponder>
+//        <name>encoder</name>
+//        <number>0</number>
+//        <mode>0</mode>  // Mode A = 0, Mode C = 1, Mode S = 2
+//      </altimeter>
 
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 
 #include "transponder.hxx"
 
+#include <simgear/compiler.h>
+#include <simgear/sg_inlines.h>
+#include <simgear/debug/logstream.hxx>
+
+#include <Main/fg_props.hxx>
+
+#include <cstdio>
+
 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<Mode>(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<int>(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);
+}
index d41514e0849aee90f4712bd7768866872d9c9f6e..728250f8b8c1943c1001a915ecb94a2dc13942b6 100644 (file)
@@ -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
 #include <simgear/structure/subsystem_mgr.hxx>
 
 
-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
index 7d6ce8b33dc8909e2cb0655d88702ace460edaca..62ca039de3c56ebb0ad681e06ac5d8b34fbfc680 100644 (file)
@@ -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},