]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/transponder.cxx
Handle libCurl linkage when enabled in SimGear
[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     _identMode(false),
52     _name(node->getStringValue("name", "transponder")),
53     _num(node->getIntValue("number", 0)),
54     _mode((Mode) node->getIntValue("mode", 1)),
55     _listener_active(0)
56 {
57     _requiredBusVolts = node->getDoubleValue("bus-volts", 8.0);
58     _altitudeSourcePath = node->getStringValue("encoder-path", "/instrumentation/altimeter");
59     _kt70Compat = node->getBoolValue("kt70-compatibility", false);
60 }
61
62
63 Transponder::~Transponder()
64 {
65 }
66
67
68 void Transponder::init()
69 {
70     SGPropertyNode *node = fgGetNode("/instrumentation/" + _name, _num, true );
71
72     // Inputs
73     _busPower_node = fgGetNode("/systems/electrical/outputs/transponder", true);
74     _pressureAltitude_node = fgGetNode(_altitudeSourcePath, true);
75
76     SGPropertyNode *in_node = node->getChild("inputs", 0, true);
77     for (int i=0; i<4;++i) {
78         _digit_node[i] = in_node->getChild("digit", i, true);
79         _digit_node[i]->addChangeListener(this);
80     }
81    
82     _knob_node = in_node->getChild("knob-mode", 0, true);
83     if (!_knob_node->hasValue()) {
84         _knob = KNOB_ON;
85         // default to, if aircraft wants to start dark, it can do this
86         // in its -set.xml
87         _knob_node->setIntValue(_knob);
88     } else {
89         _knob = static_cast<KnobPosition>(_knob_node->getIntValue());
90     }
91     
92     _knob_node->addChangeListener(this);
93     
94     _mode_node = in_node->getChild("mode", 0, true);
95     _mode_node->setIntValue(_mode);
96     _mode_node->addChangeListener(this);
97     
98     _identBtn_node = in_node->getChild("ident-btn", 0, true);
99     _identBtn_node->setBoolValue(false);
100     _identBtn_node->addChangeListener(this);
101     
102     _serviceable_node = node->getChild("serviceable", 0, true);
103     _serviceable_node->setBoolValue(true);
104     
105     _idCode_node = node->getChild("id-code", 0, true);
106     _idCode_node->addChangeListener(this);
107     // set default, but don't overwrite value from preferences.xml or -set.xml
108     if (!_idCode_node->hasValue()) { 
109         _idCode_node->setIntValue(1200);
110     }
111     
112     // Outputs
113     _altitude_node = node->getChild("altitude", 0, true);
114     _altitudeValid_node = node->getChild("altitude-valid", 0, true);
115     _ident_node = node->getChild("ident", 0, true);
116     _transmittedId_node = node->getChild("transmitted-id", 0, true);
117     
118     if (_kt70Compat) {
119         // alias the properties through
120         SGPropertyNode_ptr output = node->getChild("outputs", 0, true);
121         output->getChild("flight-level", 0, true)->alias(_altitude_node);
122         output->getChild("id-code", 0, true)->alias(_idCode_node);
123         in_node->getChild("func-knob", 0, true)->alias(_knob_node);
124     }
125 }
126
127 void Transponder::bind()
128 {
129     if (_kt70Compat) {
130         SGPropertyNode *node = fgGetNode("/instrumentation/" + _name, _num, true );
131         _tiedProperties.setRoot(node);
132         
133         _tiedProperties.Tie("annunciators/fl", this,
134                             &Transponder::getFLAnnunciator );
135         _tiedProperties.Tie("annunciators/alt", this,
136                             &Transponder::getAltAnnunciator );
137         _tiedProperties.Tie("annunciators/gnd", this,
138                             &Transponder::getGroundAnnuciator );
139         _tiedProperties.Tie("annunciators/on", this,
140                             &Transponder::getOnAnnunciator );
141         _tiedProperties.Tie("annunciators/sby", this,
142                             &Transponder::getStandbyAnnunciator );
143         _tiedProperties.Tie("annunciators/reply", this,
144                             &Transponder::getReplyAnnunciator );
145     } // of kt70 backwards compatibility
146 }
147
148 void Transponder::unbind()
149 {
150     _tiedProperties.Untie();
151 }
152
153
154 void Transponder::update(double dt)
155 {
156     if (has_power() && _serviceable_node->getBoolValue())
157     {
158         // Mode C & S send also altitude
159         Mode effectiveMode = (_knob == KNOB_ALT) ? _mode : MODE_A;
160         SGPropertyNode* altitudeSource = NULL;
161         
162         switch (effectiveMode) {
163         case MODE_C:
164             altitudeSource = _pressureAltitude_node->getChild("mode-c-alt-ft");
165             break;
166         case MODE_S:
167             altitudeSource = _pressureAltitude_node->getChild("mode-s-alt-ft");
168             break;
169         default:
170             break;
171         }
172         
173         int alt = INVALID_ALTITUDE;
174         if (effectiveMode != MODE_A) {
175             if (altitudeSource) {
176                 alt = altitudeSource->getIntValue();
177             } else {
178                 // warn if altitude input is misconfigured
179                 SG_LOG(SG_INSTR, SG_INFO, "transponder altitude input for mode " << _mode << " is missing");
180             }
181         }
182         
183         _altitude_node->setIntValue(alt);
184         _altitudeValid_node->setBoolValue(alt != INVALID_ALTITUDE);
185
186         if ( _identMode ) {
187             _identTime += dt;
188             if ( _identTime > IDENT_TIMEOUT ) {
189                 // reset ident mode
190                 _ident_node->setBoolValue(false);
191                 _identMode = false;
192             }
193         }
194         
195         if (_knob >= KNOB_ON) {
196             _transmittedId_node->setIntValue(_idCode_node->getIntValue());
197         } else {
198             _transmittedId_node->setIntValue(INVALID_ID);
199         }
200     }
201     else
202     {
203       _altitude_node->setIntValue(INVALID_ALTITUDE);
204       _altitudeValid_node->setBoolValue(false);
205       _ident_node->setBoolValue(false);
206       _transmittedId_node->setIntValue(INVALID_ID);
207     }
208 }
209
210 static int powersOf10[4] = {1, 10, 100, 1000};
211
212 static int extractCodeDigit(int code, int index)
213 {
214     return (code / powersOf10[index]) % 10;
215 }
216
217 static int modifyCodeDigit(int code, int index, int digitValue)
218 {
219     assert(digitValue >= 0 && digitValue < 8);
220     int p = powersOf10[index];
221     int codeWithoutDigit = code - (extractCodeDigit(code, index) * p);
222     return codeWithoutDigit + (digitValue * p);
223 }
224
225 void Transponder::valueChanged(SGPropertyNode *prop)
226 {
227     // Ident button pressed
228     if (prop == _identBtn_node) {
229         if (prop->getBoolValue()) {
230             _identTime = 0.0;
231             _ident_node->setBoolValue(true);
232             _identMode = true;
233         } else {
234             // don't cancel state on release
235         }
236         return;
237     }
238     
239     if (prop == _mode_node) {
240         _mode = static_cast<Mode>(prop->getIntValue());
241         return;
242     }
243     
244     if (prop == _knob_node) {
245         _knob = static_cast<KnobPosition>(prop->getIntValue());
246         return;
247     }
248     
249     if (_listener_active)
250         return;
251
252     _listener_active++;
253
254     if (prop == _idCode_node) {
255         // keep the digits in-sync
256         for (int i=0; i<4; ++i) {
257             _digit_node[i]->setIntValue(extractCodeDigit(prop->getIntValue(), i));
258         }
259     } else {
260         // digit node
261         int index = prop->getIndex();
262         int digitValue = prop->getIntValue();
263         SG_CLAMP_RANGE<int>(digitValue, 0, 7);
264         _idCode_node->setIntValue(modifyCodeDigit(_idCode_node->getIntValue(), index, digitValue));
265         prop->setIntValue(digitValue);
266     }
267     
268     _listener_active--;
269 }
270
271 bool Transponder::has_power() const
272 {
273     return (_knob_node->getIntValue() > KNOB_STANDBY) && (_busPower_node->getDoubleValue() > _requiredBusVolts);
274 }
275
276 bool Transponder::getFLAnnunciator() const
277 {
278     return (_knob == KNOB_ALT) || (_knob == KNOB_GROUND) || (_knob == KNOB_TEST);
279 }
280
281 bool Transponder::getAltAnnunciator() const
282 {
283     return (_knob == KNOB_ALT) || (_knob == KNOB_TEST);
284 }
285
286 bool Transponder::getGroundAnnuciator() const
287 {
288     return (_knob == KNOB_GROUND) || (_knob == KNOB_TEST);
289 }
290
291 bool Transponder::getOnAnnunciator() const
292 {
293     return (_knob == KNOB_ON) || (_knob == KNOB_TEST);
294 }
295
296 bool Transponder::getStandbyAnnunciator() const
297 {
298     return (_knob == KNOB_STANDBY) || (_knob == KNOB_TEST);
299 }
300
301 bool Transponder::getReplyAnnunciator() const
302 {
303     return _identMode || (_knob == KNOB_TEST);
304 }
305