]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/transponder.cxx
Improve transponder instrumentation: new version
[flightgear.git] / src / Instrumentation / transponder.cxx
1 // transponder.cxx -- class to impliment a transponder
2 //
3 // Written by Roy Vegard Ovesen, started September 2004.
4 //
5 // Copyright (C) 2004  Roy Vegard Ovesen - rvovesen@tiscali.no
6 // Copyright (C) 2013  Clement de l'Hamaide - clemaez@hotmail.fr
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 //
22 // Example invocation, in the instrumentation.xml file:
23 //      <transponder>
24 //        <name>encoder</name>
25 //        <number>0</number>
26 //        <mode>0</mode>  // Mode A = 0, Mode C = 1, Mode S = 2
27 //      </altimeter>
28
29 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif
32
33 #include "transponder.hxx"
34
35 #include <simgear/compiler.h>
36 #include <simgear/sg_inlines.h>
37 #include <simgear/debug/logstream.hxx>
38
39 #include <Main/fg_props.hxx>
40
41 #include <cstdio>
42
43 using std::string;
44
45 const double IDENT_TIMEOUT = 18.0; // 18 seconds
46 const int INVALID_ALTITUDE = -9999;
47 const int INVALID_ID = -9999;
48
49 Transponder::Transponder(SGPropertyNode *node)
50     :
51     _name(node->getStringValue("name", "transponder")),
52     _num(node->getIntValue("number", 0)),
53     _mode((Mode) node->getIntValue("mode", 1)),
54     _listener_active(0)
55 {
56     _requiredBusVolts = node->getDoubleValue("bus-volts", 8.0);
57     _altitudeSourcePath = node->getStringValue("encoder-path", "/instrumentation/altimeter");
58 }
59
60
61 Transponder::~Transponder()
62 {
63 }
64
65
66 void Transponder::init()
67 {
68     string branch;
69     branch = "/instrumentation/" + _name;
70
71     SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true );
72
73     // Inputs
74     _busPower_node = fgGetNode("/systems/electrical/outputs/transponder", true);
75     _pressureAltitude_node = fgGetNode(_altitudeSourcePath, true);
76
77     SGPropertyNode *in_node = node->getChild("inputs", 0, true);
78     for (int i=0; i<4;++i) {
79         _digit_node[i] = in_node->getChild("digit", i, true);
80         _digit_node[i]->addChangeListener(this);
81     }
82    
83     _knob_node = in_node->getChild("knob-mode", 0, true); // 0=OFF, 1=SBY, 2=ON, 3=ALT, 4=TST
84     if (!_knob_node->hasValue()) { 
85         _knob_node->setIntValue(0);
86     }
87     
88     _mode_node = in_node->getChild("mode", 0, true);
89     _mode_node->setIntValue(_mode);
90     _mode_node->addChangeListener(this);
91     
92     _identBtn_node = in_node->getChild("ident-btn", 0, true);
93     _identBtn_node->setBoolValue(false);
94     _identBtn_node->addChangeListener(this);
95     
96     _serviceable_node = node->getChild("serviceable", 0, true);
97     _serviceable_node->setBoolValue(true);
98     
99     _idCode_node = node->getChild("id-code", 0, true);
100     _idCode_node->addChangeListener(this);
101     // set default, but don't overwrite value from preferences.xml or -set.xml
102     if (!_idCode_node->hasValue()) { 
103         _idCode_node->setIntValue(1200);
104     }
105     
106     // Outputs
107     _altitude_node = node->getChild("altitude", 0, true);
108     _altitudeValid_node = node->getChild("altitude-valid", 0, true);
109     _ident_node = node->getChild("ident", 0, true);
110     _transmittedId_node = node->getChild("transmitted-id", 0, true);
111 }
112
113
114 void Transponder::update(double dt)
115 {
116     if (has_power() && _serviceable_node->getBoolValue())
117     {
118         // Mode C & S send also altitude
119         Mode effectiveMode = (_knob_node->getIntValue() == KNOB_ALT) ? _mode : MODE_A;
120         SGPropertyNode* altitudeSource = NULL;
121         
122         switch (effectiveMode) {
123         case MODE_C:
124             altitudeSource = _pressureAltitude_node->getChild("mode-c-alt-ft");
125             break;
126         case MODE_S:
127             altitudeSource = _pressureAltitude_node->getChild("mode-s-alt-ft");
128             break;
129         default:
130             break;
131         }
132         
133         int alt = INVALID_ALTITUDE;
134         if (effectiveMode != MODE_A) {
135             if (altitudeSource) {
136                 alt = altitudeSource->getIntValue();
137             } else {
138                 // warn if altitude input is misconfigured
139                 SG_LOG(SG_INSTR, SG_INFO, "transponder altitude input for mode " << _mode << " is missing");
140             }
141         }
142         
143         _altitude_node->setIntValue(alt);
144         _altitudeValid_node->setBoolValue(alt != INVALID_ALTITUDE);
145
146         if ( _identMode ) {
147             _identTime += dt;
148             if ( _identTime > IDENT_TIMEOUT ) {
149                 // reset ident mode
150                 _ident_node->setBoolValue(false);
151                 _identMode = false;
152             }
153         }
154         
155         _transmittedId_node->setIntValue(_idCode_node->getIntValue());
156     }
157     else
158     {
159       _altitude_node->setIntValue(INVALID_ALTITUDE);
160       _altitudeValid_node->setBoolValue(false);
161       _ident_node->setBoolValue(false);
162       _transmittedId_node->setIntValue(INVALID_ID);
163     }
164 }
165
166 static int powersOf10[4] = {1, 10, 100, 1000};
167
168 static int extractCodeDigit(int code, int index)
169 {
170     return (code / powersOf10[index]) % 10;
171 }
172
173 static int modifyCodeDigit(int code, int index, int digitValue)
174 {
175     assert(digitValue >= 0 && digitValue < 8);
176     int p = powersOf10[index];
177     int codeWithoutDigit = code - (extractCodeDigit(code, index) * p);
178     return codeWithoutDigit + (digitValue * p);
179 }
180
181 void Transponder::valueChanged(SGPropertyNode *prop)
182 {
183     // Ident button pressed
184     if ((prop == _identBtn_node) && prop->getBoolValue()) {
185         _identTime = 0.0;
186         _ident_node->setBoolValue(true);
187         _identMode = true;
188         return;
189     }
190     
191     if (prop == _mode_node) {
192         _mode = static_cast<Mode>(prop->getIntValue());
193         return;
194     }
195     
196     if (_listener_active)
197         return;
198
199     _listener_active++;
200
201     if (prop == _idCode_node) {
202         // keep the digits in-sync
203         for (int i=0; i<4; ++i) {
204             _digit_node[i]->setIntValue(extractCodeDigit(prop->getIntValue(), i));
205         }
206     } else {
207         // digit node
208         int index = prop->getIndex();
209         int digitValue = prop->getIntValue();
210         SG_CLAMP_RANGE<int>(digitValue, 0, 7);
211         _idCode_node->setIntValue(modifyCodeDigit(_idCode_node->getIntValue(), index, digitValue));
212         prop->setIntValue(digitValue);
213     }
214     
215     _listener_active--;
216 }
217
218 bool Transponder::has_power() const
219 {
220     return (_knob_node->getIntValue() > KNOB_STANDBY) && (_busPower_node->getDoubleValue() > _requiredBusVolts);
221 }