]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGFCS.cpp
Sync w. JSBSim CVS
[flightgear.git] / src / FDM / JSBSim / FGFCS.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGFCS.cpp
4  Author:       Jon Berndt
5  Date started: 12/12/98
6  Purpose:      Model the flight controls
7  Called by:    FDMExec
8
9  ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------
10
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU General Public License as published by the Free Software
13  Foundation; either version 2 of the License, or (at your option) any later
14  version.
15
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  details.
20
21  You should have received a copy of the GNU General Public License along with
22  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23  Place - Suite 330, Boston, MA  02111-1307, USA.
24
25  Further information about the GNU General Public License can also be found on
26  the world wide web at http://www.gnu.org.
27
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 This class models the flight controls for a specific airplane
31
32 HISTORY
33 --------------------------------------------------------------------------------
34 12/12/98   JSB   Created
35
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 INCLUDES
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39
40 #include "FGFCS.h"
41 #include "FGFDMExec.h"
42 #include "FGPropertyManager.h"
43
44 #include "filtersjb/FGFilter.h"
45 #include "filtersjb/FGDeadBand.h"
46 #include "filtersjb/FGGain.h"
47 #include "filtersjb/FGGradient.h"
48 #include "filtersjb/FGSwitch.h"
49 #include "filtersjb/FGSummer.h"
50 #include "filtersjb/FGKinemat.h"
51
52 namespace JSBSim {
53
54 static const char *IdSrc = "$Id$";
55 static const char *IdHdr = ID_FCS;
56
57 #if defined(WIN32) && !defined(__CYGWIN__)
58 #define snprintf _snprintf
59 #endif
60
61 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
62 CLASS IMPLEMENTATION
63 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
64
65 FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
66 {
67   int i;
68   Name = "FGFCS";
69
70   DaCmd = DeCmd = DrCmd = DfCmd = DsbCmd = DspCmd = 0.0;
71   AP_DaCmd = AP_DeCmd = AP_DrCmd = AP_ThrottleCmd = 0.0;
72   PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
73   GearCmd = GearPos = 1; // default to gear down
74   LeftBrake = RightBrake = CenterBrake = 0.0;
75   APAttitudeSetPt = APAltitudeSetPt = APHeadingSetPt = APAirspeedSetPt = 0.0;
76   DoNormalize=true;
77
78   bind();
79   for (i=0;i<=NForms;i++) {
80     DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
81     DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
82   }
83
84   for (i=0;i<NNorm;i++) { ToNormalize[i]=-1;}
85   Debug(0);
86 }
87
88 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89
90 FGFCS::~FGFCS()
91 {
92   unbind( PropertyManager->GetNode("fcs") );
93   unbind( PropertyManager->GetNode("ap") );
94   PropertyManager->Untie( "gear/gear-cmd-norm" );
95   PropertyManager->Untie( "gear/gear-pos-norm" );
96
97   ThrottleCmd.clear();
98   ThrottlePos.clear();
99   MixtureCmd.clear();
100   MixturePos.clear();
101   PropAdvanceCmd.clear();
102   PropAdvance.clear();
103
104   unsigned int i;
105
106   for (i=0;i<APComponents.size();i++) delete APComponents[i];
107   for (i=0;i<FCSComponents.size();i++) delete FCSComponents[i];
108
109   Debug(1);
110 }
111
112 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113
114 bool FGFCS::Run(void)
115 {
116   unsigned int i;
117
118   if (FGModel::Run()) return true; // fast exit if nothing to do
119
120   for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
121   for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
122   for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
123
124   for (i=0; i<APComponents.size(); i++) APComponents[i]->Run(); // cycle AP components
125   for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run(); // cycle FCS components
126
127   if (DoNormalize) Normalize();
128
129   return false;
130 }
131
132 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133
134 void FGFCS::SetThrottleCmd(int engineNum, double setting)
135 {
136   unsigned int ctr;
137
138   if (engineNum < (int)ThrottlePos.size()) {
139     if (engineNum < 0) {
140       for (ctr=0;ctr<ThrottleCmd.size();ctr++) ThrottleCmd[ctr] = setting;
141     } else {
142       ThrottleCmd[engineNum] = setting;
143     }
144   } else {
145     cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
146          << " engines exist, but attempted throttle command is for engine "
147          << engineNum << endl;
148   }
149 }
150
151 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152
153 void FGFCS::SetThrottlePos(int engineNum, double setting)
154 {
155   unsigned int ctr;
156
157   if (engineNum < (int)ThrottlePos.size()) {
158     if (engineNum < 0) {
159       for (ctr=0;ctr<ThrottlePos.size();ctr++) ThrottlePos[ctr] = setting;
160     } else {
161       ThrottlePos[engineNum] = setting;
162     }
163   } else {
164     cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
165          << " engines exist, but attempted throttle position setting is for engine "
166          << engineNum << endl;
167   }
168 }
169
170 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171
172 double FGFCS::GetThrottleCmd(int engineNum) const
173 {
174   if (engineNum < (int)ThrottlePos.size()) {
175     if (engineNum < 0) {
176        cerr << "Cannot get throttle value for ALL engines" << endl;
177     } else {
178       return ThrottleCmd[engineNum];
179     }
180   } else {
181     cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
182          << " engines exist, but throttle setting for engine " << engineNum
183          << " is selected" << endl;
184   }
185   return 0.0;
186 }
187
188 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189
190 double FGFCS::GetThrottlePos(int engineNum) const
191 {
192   if (engineNum < (int)ThrottlePos.size()) {
193     if (engineNum < 0) {
194        cerr << "Cannot get throttle value for ALL engines" << endl;
195     } else {
196       return ThrottlePos[engineNum];
197     }
198   } else {
199     cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
200          << " engines exist, but attempted throttle position setting is for engine "
201          << engineNum << endl;
202   }
203   return 0.0;
204 }
205
206 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207
208 void FGFCS::SetMixtureCmd(int engineNum, double setting)
209 {
210   unsigned int ctr;
211
212   if (engineNum < (int)ThrottlePos.size()) {
213     if (engineNum < 0) {
214       for (ctr=0;ctr<MixtureCmd.size();ctr++) MixtureCmd[ctr] = setting;
215     } else {
216       MixtureCmd[engineNum] = setting;
217     }
218   }
219 }
220
221 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222
223 void FGFCS::SetMixturePos(int engineNum, double setting)
224 {
225   unsigned int ctr;
226
227   if (engineNum < (int)ThrottlePos.size()) {
228     if (engineNum < 0) {
229       for (ctr=0;ctr<=MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
230     } else {
231       MixturePos[engineNum] = setting;
232     }
233   }
234 }
235
236 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237
238 void FGFCS::SetPropAdvanceCmd(int engineNum, double setting)
239 {
240   unsigned int ctr;
241
242   if (engineNum < (int)ThrottlePos.size()) {
243     if (engineNum < 0) {
244       for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvanceCmd[ctr] = setting;
245     } else {
246       PropAdvanceCmd[engineNum] = setting;
247     }
248   }
249 }
250
251 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252
253 void FGFCS::SetPropAdvance(int engineNum, double setting)
254 {
255   unsigned int ctr;
256
257   if (engineNum < (int)ThrottlePos.size()) {
258     if (engineNum < 0) {
259       for (ctr=0;ctr<=PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
260     } else {
261       PropAdvance[engineNum] = setting;
262     }
263   }
264 }
265
266 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267
268 bool FGFCS::Load(FGConfigFile* AC_cfg)
269 {
270   string token, delimiter;
271   string name, file, fname;
272   unsigned i;
273   vector <FGFCSComponent*> *Components;
274   FGConfigFile *FCS_cfg;
275
276   Components=0;
277   // Determine if the FCS/Autopilot is defined inline in the aircraft configuration
278   // file or in a separate file. Set up the config file class as appropriate.
279
280   delimiter = AC_cfg->GetValue();
281   name  = AC_cfg->GetValue("NAME");
282   fname = AC_cfg->GetValue("FILE");
283
284   if ( AC_cfg->GetValue("NORMALIZE") == "FALSE") {
285     DoNormalize = false;
286     cout << "    Automatic Control Surface Normalization Disabled" << endl;
287   }
288
289 # ifndef macintosh
290 //  file = "control/" + fname + ".xml";
291   file = FDMExec->GetAircraftPath() + "/" + FDMExec->GetModelName() + "/" + fname + ".xml";
292 # else
293 //  file = "control;" + fname + ".xml";
294   file = FDMExec->GetAircraftPath() + ";" + FDMExec->GetModelName() + ";" + fname + ".xml";
295 # endif
296
297   if (name.empty()) {
298     name = fname;
299     if (file.empty()) {
300       cerr << "FCS/Autopilot does not appear to be defined inline nor in a file" << endl;
301     } else {
302       FCS_cfg = new FGConfigFile(file);
303       if (!FCS_cfg->IsOpen()) {
304         cerr << "Could not open " << delimiter << " file: " << file << endl;
305         return false;
306       } else {
307         AC_cfg = FCS_cfg; // set local config file object pointer to FCS config
308                           // file object pointer
309       }
310     }
311   } else {
312     AC_cfg->GetNextConfigLine();
313   }
314
315   if (delimiter == "AUTOPILOT") {
316     Components = &APComponents;
317     Name = "Autopilot: " + name;
318   } else if (delimiter == "FLIGHT_CONTROL") {
319     Components = &FCSComponents;
320     Name = "FCS: " + name;
321   } else {
322     cerr << endl << "Unknown FCS delimiter" << endl << endl;
323   }
324
325   if (debug_lvl > 0) cout << "    Control System Name: " << Name << endl;
326
327   while ((token = AC_cfg->GetValue()) != string("/" + delimiter)) {
328     if (token == "COMPONENT") {
329       token = AC_cfg->GetValue("TYPE");
330       if (debug_lvl > 0) cout << endl << "    Loading Component \""
331                               << AC_cfg->GetValue("NAME")
332                               << "\" of type: " << token << endl;
333       if ((token == "LAG_FILTER") ||
334           (token == "LEAD_LAG_FILTER") ||
335           (token == "SECOND_ORDER_FILTER") ||
336           (token == "WASHOUT_FILTER") ||
337           (token == "INTEGRATOR") ) {
338         Components->push_back(new FGFilter(this, AC_cfg));
339       } else if ((token == "PURE_GAIN") ||
340                  (token == "SCHEDULED_GAIN") ||
341                  (token == "AEROSURFACE_SCALE") ) {
342
343         Components->push_back(new FGGain(this, AC_cfg));
344
345       } else if (token == "SUMMER") {
346         Components->push_back(new FGSummer(this, AC_cfg));
347       } else if (token == "DEADBAND") {
348         Components->push_back(new FGDeadBand(this, AC_cfg));
349       } else if (token == "GRADIENT") {
350         Components->push_back(new FGGradient(this, AC_cfg));
351       } else if (token == "SWITCH") {
352         Components->push_back(new FGSwitch(this, AC_cfg));
353       } else if (token == "KINEMAT") {
354         Components->push_back(new FGKinemat(this, AC_cfg));
355       } else {
356         cerr << "Unknown token [" << token << "] in FCS portion of config file" << endl;
357         return false;
358       }
359       if (AC_cfg->GetNextConfigLine() == "EOF") break;
360     }
361   }
362
363   //collect information for normalizing control surfaces
364
365   string nodeName;
366   for (i=0; i<Components->size(); i++) {
367
368     if ( (((*Components)[i])->GetType() == "AEROSURFACE_SCALE"
369           || ((*Components)[i])->GetType() == "KINEMAT")
370                     && ((*Components)[i])->GetOutputNode() ) {
371       nodeName = ((*Components)[i])->GetOutputNode()->GetName();
372       if ( nodeName == "elevator-pos-rad" ) {
373         ToNormalize[iDe]=i;
374       } else if ( nodeName  == "left-aileron-pos-rad"
375                    || nodeName == "aileron-pos-rad" ) {
376         ToNormalize[iDaL]=i;
377       } else if ( nodeName == "right-aileron-pos-rad" ) {
378         ToNormalize[iDaR]=i;
379       } else if ( nodeName == "rudder-pos-rad" ) {
380         ToNormalize[iDr]=i;
381       } else if ( nodeName == "speedbrake-pos-rad" ) {
382         ToNormalize[iDsb]=i;
383       } else if ( nodeName == "spoiler-pos-rad" ) {
384         ToNormalize[iDsp]=i;
385       } else if ( nodeName == "flap-pos-deg" ) {
386         ToNormalize[iDf]=i;
387       }
388     }
389   }
390
391   if (delimiter == "FLIGHT_CONTROL") bindModel();
392
393   return true;
394 }
395
396 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397
398 double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
399 {
400   switch (bg) {
401   case FGLGear::bgLeft:
402     return LeftBrake;
403   case FGLGear::bgRight:
404     return RightBrake;
405   case FGLGear::bgCenter:
406     return CenterBrake;
407   default:
408     cerr << "GetBrake asked to return a bogus brake value" << endl;
409   }
410   return 0.0;
411 }
412
413 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414
415 string FGFCS::GetComponentStrings(void)
416 {
417   unsigned int comp;
418   string CompStrings = "";
419   bool firstime = true;
420
421   for (comp = 0; comp < FCSComponents.size(); comp++) {
422     if (firstime) firstime = false;
423     else          CompStrings += ", ";
424
425     CompStrings += FCSComponents[comp]->GetName();
426   }
427
428   for (comp = 0; comp < APComponents.size(); comp++)
429   {
430     CompStrings += ", ";
431     CompStrings += APComponents[comp]->GetName();
432   }
433
434   return CompStrings;
435 }
436
437 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438
439 string FGFCS::GetComponentValues(void)
440 {
441   unsigned int comp;
442   string CompValues = "";
443   char buffer[12];
444   bool firstime = true;
445
446   for (comp = 0; comp < FCSComponents.size(); comp++) {
447     if (firstime) firstime = false;
448     else          CompValues += ", ";
449
450     sprintf(buffer, "%9.6f", FCSComponents[comp]->GetOutput());
451     CompValues += string(buffer);
452   }
453
454   for (comp = 0; comp < APComponents.size(); comp++) {
455     sprintf(buffer, ", %9.6f", APComponents[comp]->GetOutput());
456     CompValues += string(buffer);
457   }
458
459   return CompValues;
460 }
461
462 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
463
464 void FGFCS::AddThrottle(void)
465 {
466   ThrottleCmd.push_back(0.0);
467   ThrottlePos.push_back(0.0);
468   MixtureCmd.push_back(0.0);     // assume throttle and mixture are coupled
469   MixturePos.push_back(0.0);
470   PropAdvanceCmd.push_back(0.0); // assume throttle and prop pitch are coupled
471   PropAdvance.push_back(0.0);
472 }
473
474 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475
476 void FGFCS::Normalize(void) {
477
478   //not all of these are guaranteed to be defined for every model
479   //those that are have an index >=0 in the ToNormalize array
480   //ToNormalize is filled in Load()
481
482   if ( ToNormalize[iDe] > -1 ) {
483     DePos[ofNorm] = FCSComponents[ToNormalize[iDe]]->GetOutputPct();
484   }
485
486   if ( ToNormalize[iDaL] > -1 ) {
487     DaLPos[ofNorm] = FCSComponents[ToNormalize[iDaL]]->GetOutputPct();
488   }
489
490   if ( ToNormalize[iDaR] > -1 ) {
491     DaRPos[ofNorm] = FCSComponents[ToNormalize[iDaR]]->GetOutputPct();
492   }
493
494   if ( ToNormalize[iDr] > -1 ) {
495     DrPos[ofNorm] = FCSComponents[ToNormalize[iDr]]->GetOutputPct();
496   }
497
498   if ( ToNormalize[iDsb] > -1 ) {
499     DsbPos[ofNorm] = FCSComponents[ToNormalize[iDsb]]->GetOutputPct();
500   }
501
502   if ( ToNormalize[iDsp] > -1 ) {
503     DspPos[ofNorm] = FCSComponents[ToNormalize[iDsp]]->GetOutputPct();
504   }
505
506   if ( ToNormalize[iDf] > -1 ) {
507     DfPos[ofNorm] = FCSComponents[ToNormalize[iDf]]->GetOutputPct();
508   }
509
510   DePos[ofMag]  = fabs(DePos[ofRad]);
511   DaLPos[ofMag] = fabs(DaLPos[ofRad]);
512   DaRPos[ofMag] = fabs(DaRPos[ofRad]);
513   DrPos[ofMag]  = fabs(DrPos[ofRad]);
514   DsbPos[ofMag] = fabs(DsbPos[ofRad]);
515   DspPos[ofMag] = fabs(DspPos[ofRad]);
516   DfPos[ofMag]  = fabs(DfPos[ofRad]);
517
518 }
519
520 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
521
522 void FGFCS::bind(void)
523 {
524   PropertyManager->Tie("fcs/aileron-cmd-norm", this,
525                        &FGFCS::GetDaCmd,
526                        &FGFCS::SetDaCmd,
527                        true);
528   PropertyManager->Tie("fcs/elevator-cmd-norm", this,
529                        &FGFCS::GetDeCmd,
530                        &FGFCS::SetDeCmd,
531                        true);
532   PropertyManager->Tie("fcs/rudder-cmd-norm", this,
533                        &FGFCS::GetDrCmd,
534                        &FGFCS::SetDrCmd,
535                        true);
536   PropertyManager->Tie("fcs/flap-cmd-norm", this,
537                        &FGFCS::GetDfCmd,
538                        &FGFCS::SetDfCmd,
539                        true);
540   PropertyManager->Tie("fcs/speedbrake-cmd-norm", this,
541                        &FGFCS::GetDsbCmd,
542                        &FGFCS::SetDsbCmd,
543                        true);
544   PropertyManager->Tie("fcs/spoiler-cmd-norm", this,
545                        &FGFCS::GetDspCmd,
546                        &FGFCS::SetDspCmd,
547                        true);
548   PropertyManager->Tie("fcs/pitch-trim-cmd-norm", this,
549                        &FGFCS::GetPitchTrimCmd,
550                        &FGFCS::SetPitchTrimCmd,
551                        true);
552   PropertyManager->Tie("fcs/roll-trim-cmd-norm", this,
553                        &FGFCS::GetRollTrimCmd,
554                        &FGFCS::SetRollTrimCmd,
555                        true);
556   PropertyManager->Tie("fcs/yaw-trim-cmd-norm", this,
557                        &FGFCS::GetYawTrimCmd,
558                        &FGFCS::SetYawTrimCmd,
559                        true);
560   PropertyManager->Tie("gear/gear-cmd-norm", this,
561                        &FGFCS::GetGearCmd,
562                        &FGFCS::SetGearCmd,
563                        true);
564
565   PropertyManager->Tie("fcs/left-aileron-pos-rad", this,ofRad,
566                        &FGFCS::GetDaLPos,
567                        &FGFCS::SetDaLPos,
568                        true);
569   PropertyManager->Tie("fcs/left-aileron-pos-norm", this,ofNorm,
570                        &FGFCS::GetDaLPos,
571                        &FGFCS::SetDaLPos,
572                        true);
573   PropertyManager->Tie("fcs/mag-left-aileron-pos-rad", this,ofMag,
574                        &FGFCS::GetDaLPos,
575                        &FGFCS::SetDaLPos,
576                        true);
577
578   PropertyManager->Tie("fcs/right-aileron-pos-rad", this,ofRad,
579                        &FGFCS::GetDaRPos,
580                        &FGFCS::SetDaRPos,
581                        true);
582   PropertyManager->Tie("fcs/right-aileron-pos-norm", this,ofNorm,
583                        &FGFCS::GetDaRPos,
584                        &FGFCS::SetDaRPos,
585                        true);
586   PropertyManager->Tie("fcs/mag-right-aileron-pos-rad", this,ofMag,
587                        &FGFCS::GetDaRPos,
588                        &FGFCS::SetDaRPos,
589                        true);
590
591   PropertyManager->Tie("fcs/elevator-pos-rad", this, ofRad,
592                        &FGFCS::GetDePos,
593                        &FGFCS::SetDePos,
594                        true );
595   PropertyManager->Tie("fcs/elevator-pos-norm", this,ofNorm,
596                        &FGFCS::GetDePos,
597                        &FGFCS::SetDePos,
598                        true );
599   PropertyManager->Tie("fcs/mag-elevator-pos-rad", this,ofMag,
600                        &FGFCS::GetDePos,
601                        &FGFCS::SetDePos,
602                        true );
603
604   PropertyManager->Tie("fcs/rudder-pos-rad", this,ofRad,
605                        &FGFCS::GetDrPos,
606                        &FGFCS::SetDrPos,
607                        true);
608   PropertyManager->Tie("fcs/rudder-pos-norm", this,ofNorm,
609                        &FGFCS::GetDrPos,
610                        &FGFCS::SetDrPos,
611                        true);
612   PropertyManager->Tie("fcs/mag-rudder-pos-rad", this,ofMag,
613                        &FGFCS::GetDrPos,
614                        &FGFCS::SetDrPos,
615                        true);
616
617   PropertyManager->Tie("fcs/flap-pos-deg", this,ofRad,
618                        &FGFCS::GetDfPos,
619                        &FGFCS::SetDfPos,
620                        true);
621   PropertyManager->Tie("fcs/flap-pos-norm", this,ofNorm,
622                        &FGFCS::GetDfPos,
623                        &FGFCS::SetDfPos,
624                        true);
625
626   PropertyManager->Tie("fcs/speedbrake-pos-rad", this,ofRad,
627                        &FGFCS::GetDsbPos,
628                        &FGFCS::SetDsbPos,
629                        true);
630   PropertyManager->Tie("fcs/speedbrake-pos-norm", this,ofNorm,
631                        &FGFCS::GetDsbPos,
632                        &FGFCS::SetDsbPos,
633                        true);
634   PropertyManager->Tie("fcs/mag-speedbrake-pos-rad", this,ofMag,
635                        &FGFCS::GetDsbPos,
636                        &FGFCS::SetDsbPos,
637                        true);
638
639   PropertyManager->Tie("fcs/spoiler-pos-rad", this,ofRad,
640                        &FGFCS::GetDspPos,
641                        &FGFCS::SetDspPos,
642                        true);
643   PropertyManager->Tie("fcs/spoiler-pos-norm", this,ofNorm,
644                        &FGFCS::GetDspPos,
645                        &FGFCS::SetDspPos,
646                        true);
647   PropertyManager->Tie("fcs/mag-spoiler-pos-rad", this,ofMag,
648                        &FGFCS::GetDspPos,
649                        &FGFCS::SetDspPos,
650                        true);
651
652   PropertyManager->Tie("gear/gear-pos-norm", this,
653                        &FGFCS::GetGearPos,
654                        &FGFCS::SetGearPos,
655                        true);
656
657   PropertyManager->Tie("ap/elevator_cmd", this,
658                        &FGFCS::GetAPDeCmd,
659                        &FGFCS::SetAPDeCmd,
660                        true);
661
662   PropertyManager->Tie("ap/aileron_cmd", this,
663                        &FGFCS::GetAPDaCmd,
664                        &FGFCS::SetAPDaCmd,
665                        true);
666
667   PropertyManager->Tie("ap/rudder_cmd", this,
668                        &FGFCS::GetAPDrCmd,
669                        &FGFCS::SetAPDrCmd,
670                        true);
671
672   PropertyManager->Tie("ap/throttle_cmd", this,
673                        &FGFCS::GetAPThrottleCmd,
674                        &FGFCS::SetAPThrottleCmd,
675                        true);
676
677   PropertyManager->Tie("ap/attitude_setpoint", this,
678                        &FGFCS::GetAPAttitudeSetPt,
679                        &FGFCS::SetAPAttitudeSetPt,
680                        true);
681
682   PropertyManager->Tie("ap/altitude_setpoint", this,
683                        &FGFCS::GetAPAltitudeSetPt,
684                        &FGFCS::SetAPAltitudeSetPt,
685                        true);
686
687   PropertyManager->Tie("ap/heading_setpoint", this,
688                        &FGFCS::GetAPHeadingSetPt,
689                        &FGFCS::SetAPHeadingSetPt,
690                        true);
691
692   PropertyManager->Tie("ap/airspeed_setpoint", this,
693                        &FGFCS::GetAPAirspeedSetPt,
694                        &FGFCS::SetAPAirspeedSetPt,
695                        true);
696
697   PropertyManager->Tie("ap/acquire_attitude", this,
698                        &FGFCS::GetAPAcquireAttitude,
699                        &FGFCS::SetAPAcquireAttitude,
700                        true);
701
702   PropertyManager->Tie("ap/acquire_altitude", this,
703                        &FGFCS::GetAPAcquireAltitude,
704                        &FGFCS::SetAPAcquireAltitude,
705                        true);
706
707   PropertyManager->Tie("ap/acquire_heading", this,
708                        &FGFCS::GetAPAcquireHeading,
709                        &FGFCS::SetAPAcquireHeading,
710                        true);
711
712   PropertyManager->Tie("ap/acquire_airspeed", this,
713                        &FGFCS::GetAPAcquireAirspeed,
714                        &FGFCS::SetAPAcquireAirspeed,
715                        true);
716
717   PropertyManager->Tie("ap/attitude_hold", this,
718                        &FGFCS::GetAPAttitudeHold,
719                        &FGFCS::SetAPAttitudeHold,
720                        true);
721
722   PropertyManager->Tie("ap/altitude_hold", this,
723                        &FGFCS::GetAPAltitudeHold,
724                        &FGFCS::SetAPAltitudeHold,
725                        true);
726
727   PropertyManager->Tie("ap/heading_hold", this,
728                        &FGFCS::GetAPHeadingHold,
729                        &FGFCS::SetAPHeadingHold,
730                        true);
731
732   PropertyManager->Tie("ap/airspeed_hold", this,
733                        &FGFCS::GetAPAirspeedHold,
734                        &FGFCS::SetAPAirspeedHold,
735                        true);
736
737   PropertyManager->Tie("ap/wingslevel_hold", this,
738                        &FGFCS::GetAPWingsLevelHold,
739                        &FGFCS::SetAPWingsLevelHold,
740                        true);
741 }
742
743 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
744
745 void FGFCS::bindModel(void)
746 {
747   unsigned i;
748   char tmp[80];
749
750
751   for (i=0; i<ThrottleCmd.size(); i++) {
752     snprintf(tmp,80,"fcs/throttle-cmd-norm[%u]",i);
753     PropertyManager->Tie( tmp,this,i,
754                           &FGFCS::GetThrottleCmd,
755                           &FGFCS::SetThrottleCmd,
756                           true );
757     snprintf(tmp,80,"fcs/throttle-pos-norm[%u]",i);
758     PropertyManager->Tie( tmp,this,i,
759                           &FGFCS::GetThrottlePos,
760                           &FGFCS::SetThrottlePos,
761                           true );
762     if ( MixtureCmd.size() > i ) {
763       snprintf(tmp,80,"fcs/mixture-cmd-norm[%u]",i);
764       PropertyManager->Tie( tmp,this,i,
765                             &FGFCS::GetMixtureCmd,
766                             &FGFCS::SetMixtureCmd,
767                             true );
768       snprintf(tmp,80,"fcs/mixture-pos-norm[%u]",i);
769       PropertyManager->Tie( tmp,this,i,
770                             &FGFCS::GetMixturePos,
771                             &FGFCS::SetMixturePos,
772                             true );
773     }
774     if ( PropAdvanceCmd.size() > i ) {
775       snprintf(tmp,80,"fcs/advance-cmd-norm[%u]",i);
776       PropertyManager->Tie( tmp,this,i,
777                             &FGFCS::GetPropAdvanceCmd,
778                             &FGFCS::SetPropAdvanceCmd,
779                             true );
780       snprintf(tmp,80,"fcs/advance-pos-norm[%u]",i);
781       PropertyManager->Tie( tmp,this,i,
782                             &FGFCS::GetPropAdvance,
783                             &FGFCS::SetPropAdvance,
784                             true );
785     }
786   }
787 }
788
789 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790
791 void FGFCS::unbind(FGPropertyManager *node)
792 {
793   int N = node->nChildren();
794   for(int i=0;i<N;i++) {
795     if(node->getChild(i)->nChildren() ) {
796       unbind( (FGPropertyManager*)node->getChild(i) );
797     } else if( node->getChild(i)->isTied() ) {
798       node->getChild(i)->untie();
799     }
800   }
801 }
802
803 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
804 //    The bitmasked value choices are as follows:
805 //    unset: In this case (the default) JSBSim would only print
806 //       out the normally expected messages, essentially echoing
807 //       the config files as they are read. If the environment
808 //       variable is not set, debug_lvl is set to 1 internally
809 //    0: This requests JSBSim not to output any messages
810 //       whatsoever.
811 //    1: This value explicity requests the normal JSBSim
812 //       startup messages
813 //    2: This value asks for a message to be printed out when
814 //       a class is instantiated
815 //    4: When this value is set, a message is displayed when a
816 //       FGModel object executes its Run() method
817 //    8: When this value is set, various runtime state variables
818 //       are printed out periodically
819 //    16: When set various parameters are sanity checked and
820 //       a message is printed out when they go out of bounds
821
822 void FGFCS::Debug(int from)
823 {
824   if (debug_lvl <= 0) return;
825
826   if (debug_lvl & 1) { // Standard console startup message output
827     if (from == 0) { // Constructor
828
829     }
830   }
831   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
832     if (from == 0) cout << "Instantiated: FGFCS" << endl;
833     if (from == 1) cout << "Destroyed:    FGFCS" << endl;
834   }
835   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
836   }
837   if (debug_lvl & 8 ) { // Runtime state variables
838   }
839   if (debug_lvl & 16) { // Sanity checking
840   }
841   if (debug_lvl & 64) {
842     if (from == 0) { // Constructor
843       cout << IdSrc << endl;
844       cout << IdHdr << endl;
845     }
846   }
847 }
848
849 }