Improve transponder instrumentation: new version
This commit is contained in:
parent
64ab1e96ee
commit
977cfb77b5
5 changed files with 240 additions and 47 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
// <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>
|
||||
|
@ -24,15 +32,29 @@
|
|||
|
||||
#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())
|
||||
{
|
||||
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;
|
||||
// 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 (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);
|
||||
if ( _identMode ) {
|
||||
_identTime += dt;
|
||||
if ( _identTime > IDENT_TIMEOUT ) {
|
||||
// reset ident mode
|
||||
_ident_node->setBoolValue(false);
|
||||
_identMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
_transmittedId_node->setIntValue(_idCode_node->getIntValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
_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);
|
||||
}
|
||||
|
|
|
@ -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 <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
|
||||
|
|
|
@ -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},
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue