]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGFCS.cpp
Updated to match changes in radiostack.[ch]xx
[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 "FGState.h"
42 #include "FGFDMExec.h"
43 #include "FGAtmosphere.h"
44 #include "FGAircraft.h"
45 #include "FGTranslation.h"
46 #include "FGRotation.h"
47 #include "FGPosition.h"
48 #include "FGAuxiliary.h"
49 #include "FGOutput.h"
50 #include "FGPropertyManager.h"
51
52 #include "filtersjb/FGFilter.h"
53 #include "filtersjb/FGDeadBand.h"
54 #include "filtersjb/FGGain.h"
55 #include "filtersjb/FGGradient.h"
56 #include "filtersjb/FGSwitch.h"
57 #include "filtersjb/FGSummer.h"
58 #include "filtersjb/FGKinemat.h"
59
60 static const char *IdSrc = "$Id$";
61 static const char *IdHdr = ID_FCS;
62
63 #if defined(WIN32) && !defined(__CYGWIN__)
64 #define snprintf _snprintf
65 #endif
66
67 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68 CLASS IMPLEMENTATION
69 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
70
71 FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
72 {
73   int i;
74   Name = "FGFCS";
75
76   DaCmd = DeCmd = DrCmd = DfCmd = DsbCmd = DspCmd = 0.0;
77   PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
78   GearCmd = GearPos = 1; // default to gear down
79   LeftBrake = RightBrake = CenterBrake = 0.0;
80   DoNormalize=true;
81   
82   bind();
83   for (i=0;i<=NForms;i++) {
84     DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
85     DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
86   }
87     
88   for (i=0;i<NNorm;i++) { ToNormalize[i]=-1;}
89   Debug(0);
90 }
91
92 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93
94 FGFCS::~FGFCS()
95 {
96   ThrottleCmd.clear();
97   ThrottlePos.clear();
98   MixtureCmd.clear();
99   MixturePos.clear();
100   PropAdvanceCmd.clear();
101   PropAdvance.clear();
102
103   unsigned int i;
104   
105   unbind();
106
107   for (i=0;i<Components.size();i++) delete Components[i];
108   Debug(1);
109 }
110
111 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112
113 bool FGFCS::Run(void)
114 {
115   unsigned int i;
116
117   if (!FGModel::Run()) {
118     for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
119     for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
120     for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
121     for (i=0; i<Components.size(); i++)  Components[i]->Run();
122     if (DoNormalize) Normalize();
123   } else {
124   }
125
126   return false;
127 }
128
129 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130
131 void FGFCS::SetThrottleCmd(int engineNum, double setting)
132 {
133   unsigned int ctr;
134
135   if (engineNum < (int)ThrottlePos.size()) {
136     if (engineNum < 0) {
137       for (ctr=0;ctr<ThrottleCmd.size();ctr++) ThrottleCmd[ctr] = setting;
138     } else {
139       ThrottleCmd[engineNum] = setting;
140     }
141   } else {
142     cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
143          << " engines exist, but attempted throttle command is for engine "
144          << engineNum << endl;
145   }
146 }
147
148 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149
150 void FGFCS::SetThrottlePos(int engineNum, double setting)
151 {
152   unsigned int ctr;
153
154   if (engineNum < (int)ThrottlePos.size()) {
155     if (engineNum < 0) {
156       for (ctr=0;ctr<ThrottlePos.size();ctr++) ThrottlePos[ctr] = setting;
157     } else {
158       ThrottlePos[engineNum] = setting;
159     }
160   } else {
161     cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
162          << " engines exist, but attempted throttle position setting is for engine "
163          << engineNum << endl;
164   }
165 }
166
167 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168
169 double FGFCS::GetThrottleCmd(int engineNum) const
170 {
171   if (engineNum < (int)ThrottlePos.size()) {
172     if (engineNum < 0) {
173        cerr << "Cannot get throttle value for ALL engines" << endl;
174     } else {
175       return ThrottleCmd[engineNum];
176     }
177   } else {
178     cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
179          << " engines exist, but throttle setting for engine " << engineNum
180          << " is selected" << endl;
181   }
182   return 0.0;
183 }
184
185 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186
187 double FGFCS::GetThrottlePos(int engineNum) const
188 {
189   if (engineNum < (int)ThrottlePos.size()) {
190     if (engineNum < 0) {
191        cerr << "Cannot get throttle value for ALL engines" << endl;
192     } else {
193       return ThrottlePos[engineNum];
194     }
195   } else {
196     cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
197          << " engines exist, but attempted throttle position setting is for engine "
198          << engineNum << endl;
199   }
200   return 0.0; 
201 }
202
203 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204
205 void FGFCS::SetMixtureCmd(int engineNum, double setting)
206 {
207   unsigned int ctr;
208
209   if (engineNum < (int)ThrottlePos.size()) {
210     if (engineNum < 0) {
211       for (ctr=0;ctr<MixtureCmd.size();ctr++) MixtureCmd[ctr] = setting;
212     } else {
213       MixtureCmd[engineNum] = setting;
214     }
215   }
216 }
217
218 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219
220 void FGFCS::SetMixturePos(int engineNum, double setting)
221 {
222   unsigned int ctr;
223
224   if (engineNum < (int)ThrottlePos.size()) {
225     if (engineNum < 0) {
226       for (ctr=0;ctr<=MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
227     } else {
228       MixturePos[engineNum] = setting;
229     }
230   }
231 }
232
233 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234
235 void FGFCS::SetPropAdvanceCmd(int engineNum, double setting)
236 {
237   unsigned int ctr;
238
239   if (engineNum < (int)ThrottlePos.size()) {
240     if (engineNum < 0) {
241       for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvanceCmd[ctr] = setting;
242     } else {
243       PropAdvanceCmd[engineNum] = setting;
244     }
245   }
246 }
247
248 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249
250 void FGFCS::SetPropAdvance(int engineNum, double setting)
251 {
252   unsigned int ctr;
253
254   if (engineNum < (int)ThrottlePos.size()) {
255     if (engineNum < 0) {
256       for (ctr=0;ctr<=PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
257     } else {
258       PropAdvance[engineNum] = setting;
259     }
260   }
261 }
262
263 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264
265 bool FGFCS::Load(FGConfigFile* AC_cfg)
266 {
267   string token;
268   unsigned i;
269   
270   Name = Name + ":" + AC_cfg->GetValue("NAME");
271   if (debug_lvl > 0) cout << "    Control System Name: " << Name << endl;
272   if ( AC_cfg->GetValue("NORMALIZE") == "FALSE") {
273       DoNormalize=false;
274       cout << "    Automatic Control Surface Normalization Disabled" << endl;
275   }    
276   AC_cfg->GetNextConfigLine();
277   while ((token = AC_cfg->GetValue()) != string("/FLIGHT_CONTROL")) {
278     if (token == "COMPONENT") {
279       token = AC_cfg->GetValue("TYPE");
280       if (debug_lvl > 0) cout << endl << "    Loading Component \""
281                               << AC_cfg->GetValue("NAME")
282                               << "\" of type: " << token << endl;
283       if ((token == "LAG_FILTER") ||
284           (token == "LEAD_LAG_FILTER") ||
285           (token == "SECOND_ORDER_FILTER") ||
286           (token == "WASHOUT_FILTER") ||
287           (token == "INTEGRATOR") ) {
288         Components.push_back(new FGFilter(this, AC_cfg));
289       } else if ((token == "PURE_GAIN") ||
290                  (token == "SCHEDULED_GAIN") ||
291                  (token == "AEROSURFACE_SCALE") ) {
292
293         Components.push_back(new FGGain(this, AC_cfg));
294
295       } else if (token == "SUMMER") {
296         Components.push_back(new FGSummer(this, AC_cfg));
297       } else if (token == "DEADBAND") {
298         Components.push_back(new FGDeadBand(this, AC_cfg));
299       } else if (token == "GRADIENT") {
300         Components.push_back(new FGGradient(this, AC_cfg));
301       } else if (token == "SWITCH") {
302         Components.push_back(new FGSwitch(this, AC_cfg));
303       } else if (token == "KINEMAT") {
304         Components.push_back(new FGKinemat(this, AC_cfg));
305       } else {
306         cerr << "Unknown token [" << token << "] in FCS portion of config file" << endl;
307         return false;
308       }
309       AC_cfg->GetNextConfigLine();
310     }
311   }
312   //collect information for normalizing control surfaces
313   string nodeName;
314   for (i=0;i<Components.size();i++) {
315     
316     if ( (Components[i]->GetType() == "AEROSURFACE_SCALE" 
317           || Components[i]->GetType() == "KINEMAT")  
318                     && Components[i]->GetOutputNode() ) { 
319       nodeName= Components[i]->GetOutputNode()->GetName();  
320       if ( nodeName == "elevator-pos-rad" ) {
321         ToNormalize[iDe]=i;
322       } else if ( nodeName  == "left-aileron-pos-rad" 
323                    || nodeName == "aileron-pos-rad" ) {
324         ToNormalize[iDaL]=i;
325       } else if ( nodeName == "right-aileron-pos-rad" ) {
326         ToNormalize[iDaR]=i;
327       } else if ( nodeName == "rudder-pos-rad" ) {
328         ToNormalize[iDr]=i;
329       } else if ( nodeName == "speedbrake-pos-rad" ) {
330         ToNormalize[iDsb]=i;
331       } else if ( nodeName == "spoiler-pos-rad" ) {
332         ToNormalize[iDsp]=i;
333       } else if ( nodeName == "flap-pos-deg" ) {
334         ToNormalize[iDf]=i;
335       }
336     }
337   }     
338   
339   bindModel();
340   
341   return true;
342 }
343
344 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345
346 double FGFCS::GetComponentOutput(int idx) {
347   return Components[idx]->GetOutput();
348 }
349
350 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351
352 string FGFCS::GetComponentName(int idx) {
353   return Components[idx]->GetName();
354 }
355
356 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357
358 double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
359 {
360   switch (bg) {
361   case FGLGear::bgLeft:
362     return LeftBrake;
363   case FGLGear::bgRight:
364     return RightBrake;
365   case FGLGear::bgCenter:
366     return CenterBrake;
367   default:
368     cerr << "GetBrake asked to return a bogus brake value" << endl;
369   }
370   return 0.0;
371 }
372
373 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374
375 string FGFCS::GetComponentStrings(void)
376 {
377   unsigned int comp;
378   string CompStrings = "";
379   bool firstime = true;
380
381   for (comp = 0; comp < Components.size(); comp++) {
382     if (firstime) firstime = false;
383     else          CompStrings += ", ";
384
385     CompStrings += Components[comp]->GetName();
386   }
387
388   return CompStrings;
389 }
390
391 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392
393 string FGFCS::GetComponentValues(void)
394 {
395   unsigned int comp;
396   string CompValues = "";
397   char buffer[10];
398   bool firstime = true;
399
400   for (comp = 0; comp < Components.size(); comp++) {
401     if (firstime) firstime = false;
402     else          CompValues += ", ";
403
404     sprintf(buffer, "%9.6f", Components[comp]->GetOutput());
405     CompValues += string(buffer);
406   }
407
408   return CompValues;
409 }
410
411 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412
413 void FGFCS::AddThrottle(void)
414 {
415   ThrottleCmd.push_back(0.0);
416   ThrottlePos.push_back(0.0);
417   MixtureCmd.push_back(0.0);     // assume throttle and mixture are coupled
418   MixturePos.push_back(0.0);
419   PropAdvanceCmd.push_back(0.0); // assume throttle and prop pitch are coupled
420   PropAdvance.push_back(0.0);
421 }
422
423 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
424
425 void FGFCS::Normalize(void) {
426   
427   //not all of these are guaranteed to be defined for every model
428   //those that are have an index >=0 in the ToNormalize array
429   //ToNormalize is filled in Load()
430   
431   if ( ToNormalize[iDe] > -1 ) {
432     DePos[ofNorm] = Components[ToNormalize[iDe]]->GetOutputPct();
433   }
434   
435   if ( ToNormalize[iDaL] > -1 ) {
436     DaLPos[ofNorm] = Components[ToNormalize[iDaL]]->GetOutputPct();
437   }
438   
439   if ( ToNormalize[iDaR] > -1 ) {
440     DaRPos[ofNorm] = Components[ToNormalize[iDaR]]->GetOutputPct();
441   }
442
443   if ( ToNormalize[iDr] > -1 ) {
444     DrPos[ofNorm] = Components[ToNormalize[iDr]]->GetOutputPct();
445   }
446        
447   if ( ToNormalize[iDsb] > -1 ) { 
448     DsbPos[ofNorm] = Components[ToNormalize[iDsb]]->GetOutputPct();
449   }
450   
451   if ( ToNormalize[iDsp] > -1 ) {
452     DspPos[ofNorm] = Components[ToNormalize[iDsp]]->GetOutputPct();
453   }
454   
455   if ( ToNormalize[iDf] > -1 ) {
456     DfPos[ofNorm] = Components[ToNormalize[iDf]]->GetOutputPct();
457   }
458   
459   DePos[ofMag]  = fabs(DePos[ofRad]);
460   DaLPos[ofMag] = fabs(DaLPos[ofRad]);
461   DaRPos[ofMag] = fabs(DaRPos[ofRad]);
462   DrPos[ofMag]  = fabs(DrPos[ofRad]);
463   DsbPos[ofMag] = fabs(DsbPos[ofRad]);
464   DspPos[ofMag] = fabs(DspPos[ofRad]);
465   DfPos[ofMag]  = fabs(DfPos[ofRad]);
466    
467 }  
468     
469 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
470
471 void FGFCS::bind(void)
472 {
473   PropertyManager->Tie("fcs/aileron-cmd-norm", this,
474                        &FGFCS::GetDaCmd,
475                        &FGFCS::SetDaCmd,
476                        true);
477   PropertyManager->Tie("fcs/elevator-cmd-norm", this,
478                        &FGFCS::GetDeCmd,
479                        &FGFCS::SetDeCmd,
480                        true);
481   PropertyManager->Tie("fcs/rudder-cmd-norm", this,
482                        &FGFCS::GetDrCmd,
483                        &FGFCS::SetDrCmd,
484                        true);
485   PropertyManager->Tie("fcs/flap-cmd-norm", this,
486                        &FGFCS::GetDfCmd,
487                        &FGFCS::SetDfCmd,
488                        true);
489   PropertyManager->Tie("fcs/speedbrake-cmd-norm", this,
490                        &FGFCS::GetDsbCmd,
491                        &FGFCS::SetDsbCmd,
492                        true);
493   PropertyManager->Tie("fcs/spoiler-cmd-norm", this,
494                        &FGFCS::GetDspCmd,
495                        &FGFCS::SetDspCmd,
496                        true);
497   PropertyManager->Tie("fcs/pitch-trim-cmd-norm", this,
498                        &FGFCS::GetPitchTrimCmd,
499                        &FGFCS::SetPitchTrimCmd,
500                        true);
501   PropertyManager->Tie("fcs/roll-trim-cmd-norm", this,
502                        &FGFCS::GetYawTrimCmd,
503                        &FGFCS::SetYawTrimCmd,
504                        true);
505   PropertyManager->Tie("fcs/yaw-trim-cmd-norm", this,
506                        &FGFCS::GetRollTrimCmd,
507                        &FGFCS::SetRollTrimCmd,
508                        true);
509   PropertyManager->Tie("gear/gear-cmd-norm", this,
510                        &FGFCS::GetGearCmd,
511                        &FGFCS::SetGearCmd,
512                        true);
513   
514   PropertyManager->Tie("fcs/left-aileron-pos-rad", this,ofRad,
515                        &FGFCS::GetDaLPos,
516                        &FGFCS::SetDaLPos,
517                        true);
518   PropertyManager->Tie("fcs/left-aileron-pos-norm", this,ofNorm,
519                        &FGFCS::GetDaLPos,
520                        &FGFCS::SetDaLPos,
521                        true);
522   PropertyManager->Tie("fcs/mag-left-aileron-pos-rad", this,ofMag,
523                        &FGFCS::GetDaLPos,
524                        &FGFCS::SetDaLPos,
525                        true);
526  
527   PropertyManager->Tie("fcs/right-aileron-pos-rad", this,ofRad,
528                        &FGFCS::GetDaRPos,
529                        &FGFCS::SetDaRPos,
530                        true);
531   PropertyManager->Tie("fcs/right-aileron-pos-norm", this,ofNorm,
532                        &FGFCS::GetDaRPos,
533                        &FGFCS::SetDaRPos,
534                        true);
535   PropertyManager->Tie("fcs/mag-right-aileron-pos-rad", this,ofMag,
536                        &FGFCS::GetDaRPos,
537                        &FGFCS::SetDaRPos,
538                        true);
539   
540   PropertyManager->Tie("fcs/elevator-pos-rad", this, ofRad,
541                        &FGFCS::GetDePos,
542                        &FGFCS::SetDePos,
543                        true );
544   PropertyManager->Tie("fcs/elevator-pos-norm", this,ofNorm,
545                        &FGFCS::GetDePos,                       
546                        &FGFCS::SetDePos,
547                        true );
548   PropertyManager->Tie("fcs/mag-elevator-pos-rad", this,ofMag,
549                        &FGFCS::GetDePos,
550                        &FGFCS::SetDePos,
551                        true );
552   
553   PropertyManager->Tie("fcs/rudder-pos-rad", this,ofRad,
554                        &FGFCS::GetDrPos,
555                        &FGFCS::SetDrPos,
556                        true);
557   PropertyManager->Tie("fcs/rudder-pos-norm", this,ofNorm,
558                        &FGFCS::GetDrPos,
559                        &FGFCS::SetDrPos,
560                        true);
561   PropertyManager->Tie("fcs/mag-rudder-pos-rad", this,ofMag,
562                        &FGFCS::GetDrPos,
563                        &FGFCS::SetDrPos,
564                        true);
565                        
566   PropertyManager->Tie("fcs/flap-pos-deg", this,ofRad,
567                        &FGFCS::GetDfPos,
568                        &FGFCS::SetDfPos,
569                        true);
570   PropertyManager->Tie("fcs/flap-pos-norm", this,ofNorm,
571                        &FGFCS::GetDfPos,
572                        &FGFCS::SetDfPos,
573                        true);
574   
575   PropertyManager->Tie("fcs/speedbrake-pos-rad", this,ofRad,
576                        &FGFCS::GetDsbPos,
577                        &FGFCS::SetDsbPos,
578                        true);
579   PropertyManager->Tie("fcs/speedbrake-pos-norm", this,ofNorm,
580                        &FGFCS::GetDsbPos,
581                        &FGFCS::SetDsbPos,
582                        true);
583   PropertyManager->Tie("fcs/mag-speedbrake-pos-rad", this,ofMag,
584                        &FGFCS::GetDsbPos,
585                        &FGFCS::SetDsbPos,
586                        true);
587                        
588   PropertyManager->Tie("fcs/spoiler-pos-rad", this,ofRad,
589                        &FGFCS::GetDspPos,
590                        &FGFCS::SetDspPos,
591                        true);
592   PropertyManager->Tie("fcs/spoiler-pos-norm", this,ofNorm,
593                        &FGFCS::GetDspPos,
594                        &FGFCS::SetDspPos,
595                        true);
596   PropertyManager->Tie("fcs/mag-spoiler-pos-rad", this,ofMag,
597                        &FGFCS::GetDspPos,
598                        &FGFCS::SetDspPos,
599                        true);
600                        
601   PropertyManager->Tie("gear/gear-pos-norm", this,
602                        &FGFCS::GetGearPos,
603                        &FGFCS::SetGearPos,
604                        true);
605 }
606
607 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608
609 void FGFCS::bindModel(void)
610 {
611   unsigned i;
612   char tmp[80];
613   
614   for (i=0; i<ThrottleCmd.size(); i++) {
615     snprintf(tmp,80,"fcs/throttle-cmd-norm[%u]",i);
616     PropertyManager->Tie( tmp,this,i,
617                           &FGFCS::GetThrottleCmd,
618                           &FGFCS::SetThrottleCmd,
619                           true );
620     snprintf(tmp,80,"fcs/throttle-pos-norm[%u]",i);                      
621     PropertyManager->Tie( tmp,this,i,
622                           &FGFCS::GetThrottlePos,
623                           &FGFCS::SetThrottlePos,
624                           true );
625     if ( MixtureCmd.size() > i ) {
626       snprintf(tmp,80,"fcs/mixture-cmd-norm[%u]",i); 
627       PropertyManager->Tie( tmp,this,i,
628                             &FGFCS::GetMixtureCmd,
629                             &FGFCS::SetMixtureCmd,
630                             true );
631       snprintf(tmp,80,"fcs/mixture-pos-norm[%u]",i);                    
632       PropertyManager->Tie( tmp,this,i,
633                             &FGFCS::GetMixturePos,
634                             &FGFCS::SetMixturePos,
635                             true );
636     }
637     if ( PropAdvanceCmd.size() > i ) {
638       snprintf(tmp,80,"fcs/advance-cmd-norm[%u]",i); 
639       PropertyManager->Tie( tmp,this,i,
640                             &FGFCS::GetPropAdvanceCmd,
641                             &FGFCS::SetPropAdvanceCmd,
642                             true );
643       snprintf(tmp,80,"fcs/advance-pos-norm[%u]",i);                       
644       PropertyManager->Tie( tmp,this,i,
645                             &FGFCS::GetPropAdvance,
646                             &FGFCS::SetPropAdvance,
647                             true );
648     }
649   }
650 }                            
651                           
652 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
653
654 void FGFCS::unbind(void)
655 {
656   PropertyManager->Untie("fcs/aileron-cmd-norm");
657   PropertyManager->Untie("fcs/elevator-cmd-norm");
658   PropertyManager->Untie("fcs/rudder-cmd-norm");
659   PropertyManager->Untie("fcs/flap-cmd-norm");
660   PropertyManager->Untie("fcs/speedbrake-cmd-norm");
661   PropertyManager->Untie("fcs/spoiler-cmd-norm");
662   PropertyManager->Untie("fcs/pitch-trim-cmd-norm");
663   PropertyManager->Untie("fcs/roll-trim-cmd-norm");
664   PropertyManager->Untie("fcs/yaw-trim-cmd-norm");
665   PropertyManager->Untie("gear/gear-cmd-norm");
666   PropertyManager->Untie("fcs/left-aileron-pos-rad");
667   PropertyManager->Untie("fcs/mag-left-aileron-pos-rad");
668   PropertyManager->Untie("fcs/left-aileron-pos-norm");
669   PropertyManager->Untie("fcs/right-aileron-pos-rad");
670   PropertyManager->Untie("fcs/mag-right-aileron-pos-rad");
671   PropertyManager->Untie("fcs/right-aileron-pos-norm");
672   PropertyManager->Untie("fcs/elevator-pos-rad");
673   PropertyManager->Untie("fcs/mag-elevator-pos-rad");
674   PropertyManager->Untie("fcs/elevator-pos-norm");
675   PropertyManager->Untie("fcs/rudder-pos-rad");
676   PropertyManager->Untie("fcs/mag-rudder-pos-rad");
677   PropertyManager->Untie("fcs/rudder-pos-norm");
678   PropertyManager->Untie("fcs/flap-pos-deg");
679   PropertyManager->Untie("fcs/flap-pos-norm");
680   PropertyManager->Untie("fcs/speedbrake-pos-rad");
681   PropertyManager->Untie("fcs/mag-speedbrake-pos-rad");
682   PropertyManager->Untie("fcs/speedbrake-pos-norm");
683   PropertyManager->Untie("fcs/spoiler-pos-rad");
684   PropertyManager->Untie("fcs/mag-spoiler-pos-rad");
685   PropertyManager->Untie("fcs/spoiler-pos-norm");
686   PropertyManager->Untie("gear/gear-pos-norm");
687 }
688
689 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
690 //    The bitmasked value choices are as follows:
691 //    unset: In this case (the default) JSBSim would only print
692 //       out the normally expected messages, essentially echoing
693 //       the config files as they are read. If the environment
694 //       variable is not set, debug_lvl is set to 1 internally
695 //    0: This requests JSBSim not to output any messages
696 //       whatsoever.
697 //    1: This value explicity requests the normal JSBSim
698 //       startup messages
699 //    2: This value asks for a message to be printed out when
700 //       a class is instantiated
701 //    4: When this value is set, a message is displayed when a
702 //       FGModel object executes its Run() method
703 //    8: When this value is set, various runtime state variables
704 //       are printed out periodically
705 //    16: When set various parameters are sanity checked and
706 //       a message is printed out when they go out of bounds
707
708 void FGFCS::Debug(int from)
709 {
710   if (debug_lvl <= 0) return;
711
712   if (debug_lvl & 1) { // Standard console startup message output
713     if (from == 0) { // Constructor
714
715     }
716   }
717   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
718     if (from == 0) cout << "Instantiated: FGFCS" << endl;
719     if (from == 1) cout << "Destroyed:    FGFCS" << endl;
720   }
721   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
722   }
723   if (debug_lvl & 8 ) { // Runtime state variables
724   }
725   if (debug_lvl & 16) { // Sanity checking
726   }
727   if (debug_lvl & 64) {
728     if (from == 0) { // Constructor
729       cout << IdSrc << endl;
730       cout << IdHdr << endl;
731     }
732   }
733 }
734