]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGFCS.cpp
Bugfix: no automatic runway selection with --parkpos=
[flightgear.git] / src / FDM / JSBSim / models / 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 (jon@jsbsim.org) -------------
10
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU Lesser 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 Lesser General Public License for more
19  details.
20
21  You should have received a copy of the GNU Lesser 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 Lesser 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 "FGGroundReactions.h"
43 #include "input_output/FGPropertyManager.h"
44 #include <fstream>
45 #include <sstream>
46 #include <iomanip>
47
48 #include "models/flight_control/FGFilter.h"
49 #include "models/flight_control/FGDeadBand.h"
50 #include "models/flight_control/FGGain.h"
51 #include "models/flight_control/FGPID.h"
52 #include "models/flight_control/FGSwitch.h"
53 #include "models/flight_control/FGSummer.h"
54 #include "models/flight_control/FGKinemat.h"
55 #include "models/flight_control/FGFCSFunction.h"
56 #include "models/flight_control/FGSensor.h"
57 #include "models/flight_control/FGActuator.h"
58 #include "models/flight_control/FGAccelerometer.h"
59 #include "models/flight_control/FGMagnetometer.h"
60 #include "models/flight_control/FGGyro.h"
61
62 using namespace std;
63
64 namespace JSBSim {
65
66 static const char *IdSrc = "$Id: FGFCS.cpp,v 1.71 2010/09/28 02:54:03 jberndt Exp $";
67 static const char *IdHdr = ID_FCS;
68
69 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
70 CLASS IMPLEMENTATION
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
72
73 FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
74 {
75   int i;
76   Name = "FGFCS";
77
78   DaCmd = DeCmd = DrCmd = DsCmd = DfCmd = DsbCmd = DspCmd = 0;
79   PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
80   GearCmd = GearPos = 1; // default to gear down
81   LeftBrake = RightBrake = CenterBrake = 0.0;
82   TailhookPos = WingFoldPos = 0.0; 
83
84   bind();
85   for (i=0;i<NForms;i++) {
86     DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
87     DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
88   }
89
90   Debug(0);
91 }
92
93 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94
95 FGFCS::~FGFCS()
96 {
97   ThrottleCmd.clear();
98   ThrottlePos.clear();
99   MixtureCmd.clear();
100   MixturePos.clear();
101   PropAdvanceCmd.clear();
102   PropAdvance.clear();
103   SteerPosDeg.clear();
104   PropFeatherCmd.clear();
105   PropFeather.clear();
106
107   unsigned int i;
108
109   for (i=0;i<APComponents.size();i++) delete APComponents[i];
110   APComponents.clear();
111   for (i=0;i<FCSComponents.size();i++) delete FCSComponents[i];
112   FCSComponents.clear();
113   for (i=0;i<Systems.size();i++) delete Systems[i];
114   Systems.clear();
115
116
117   Debug(1);
118 }
119
120 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121
122 bool FGFCS::InitModel(void)
123 {
124   unsigned int i;
125
126   if (!FGModel::InitModel()) return false;
127
128   for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = 0.0;
129   for (i=0; i<MixturePos.size(); i++) MixturePos[i] = 0.0;
130   for (i=0; i<ThrottleCmd.size(); i++) ThrottleCmd[i] = 0.0;
131   for (i=0; i<MixtureCmd.size(); i++) MixtureCmd[i] = 0.0;
132   for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = 0.0;
133   for (i=0; i<PropFeather.size(); i++) PropFeather[i] = 0.0;
134
135   DaCmd = DeCmd = DrCmd = DsCmd = DfCmd = DsbCmd = DspCmd = 0;
136   PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
137   TailhookPos = WingFoldPos = 0.0;
138
139   for (i=0;i<NForms;i++) {
140     DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
141     DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
142   }
143
144   for (unsigned int i=0; i<Systems.size(); i++) {
145     if (Systems[i]->GetType() == "LAG" ||
146         Systems[i]->GetType() == "LEAD_LAG" ||
147         Systems[i]->GetType() == "WASHOUT" ||
148         Systems[i]->GetType() == "SECOND_ORDER_FILTER" ||
149         Systems[i]->GetType() == "INTEGRATOR")
150     {
151       ((FGFilter*)Systems[i])->ResetPastStates();
152     } else if (Systems[i]->GetType() == "PID" ) {
153       ((FGPID*)Systems[i])->ResetPastStates();
154     }
155   }
156
157   for (unsigned int i=0; i<FCSComponents.size(); i++) {
158     if (FCSComponents[i]->GetType() == "LAG" ||
159         FCSComponents[i]->GetType() == "LEAD_LAG" ||
160         FCSComponents[i]->GetType() == "WASHOUT" ||
161         FCSComponents[i]->GetType() == "SECOND_ORDER_FILTER" ||
162         FCSComponents[i]->GetType() == "INTEGRATOR")
163     {
164       ((FGFilter*)FCSComponents[i])->ResetPastStates();
165     } else if (FCSComponents[i]->GetType() == "PID" ) {
166       ((FGPID*)FCSComponents[i])->ResetPastStates();
167     }
168   }
169
170   for (unsigned int i=0; i<APComponents.size(); i++) {
171     if (APComponents[i]->GetType() == "LAG" ||
172         APComponents[i]->GetType() == "LEAD_LAG" ||
173         APComponents[i]->GetType() == "WASHOUT" ||
174         APComponents[i]->GetType() == "SECOND_ORDER_FILTER" ||
175         APComponents[i]->GetType() == "INTEGRATOR")
176     {
177       ((FGFilter*)APComponents[i])->ResetPastStates();
178     } else if (APComponents[i]->GetType() == "PID" ) {
179       ((FGPID*)APComponents[i])->ResetPastStates();
180     }
181   }
182
183   return true;
184 }
185   
186 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187
188 void FGFCS::LateBind(void)
189 {
190   unsigned int i;
191
192   for (i=0; i<Systems.size(); i++) Systems[i]->LateBind();
193   for (i=0; i<APComponents.size(); i++) APComponents[i]->LateBind();
194   for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->LateBind();
195 }
196
197 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 // Notes: In this logic the default engine commands are set. This is simply a
199 // sort of safe-mode method in case the user has not defined control laws for
200 // throttle, mixture, and prop-advance. The throttle, mixture, and prop advance
201 // positions are set equal to the respective commands. Any control logic that is
202 // actually present in the flight_control or autopilot section will override
203 // these simple assignments.
204
205 bool FGFCS::Run(void)
206 {
207   unsigned int i;
208
209   if (FGModel::Run()) return true; // fast exit if nothing to do
210   if (FDMExec->Holding()) return false;
211
212   RunPreFunctions();
213
214   for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
215   for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
216   for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
217   for (i=0; i<PropFeather.size(); i++) PropFeather[i] = PropFeatherCmd[i];
218
219   // Set the default steering angle
220   for (i=0; i<SteerPosDeg.size(); i++) {
221     FGLGear* gear = GroundReactions->GetGearUnit(i);
222     SteerPosDeg[i] = gear->GetDefaultSteerAngle( GetDsCmd() );
223   }
224
225   // Execute Systems in order
226   for (i=0; i<Systems.size(); i++) Systems[i]->Run();
227
228   // Execute Autopilot
229   for (i=0; i<APComponents.size(); i++) APComponents[i]->Run();
230
231   // Execute Flight Control System
232   for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
233
234   RunPostFunctions();
235
236   return false;
237 }
238
239 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240
241 void FGFCS::SetDaLPos( int form , double pos )
242 {
243   switch(form) {
244   case ofRad:
245     DaLPos[ofRad] = pos;
246     DaLPos[ofDeg] = pos*radtodeg;
247     break;
248   case ofDeg:
249     DaLPos[ofRad] = pos*degtorad;
250     DaLPos[ofDeg] = pos;
251     break;
252   case ofNorm:
253     DaLPos[ofNorm] = pos;
254   }
255   DaLPos[ofMag] = fabs(DaLPos[ofRad]);
256 }
257
258 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259
260 void FGFCS::SetDaRPos( int form , double pos )
261 {
262   switch(form) {
263   case ofRad:
264     DaRPos[ofRad] = pos;
265     DaRPos[ofDeg] = pos*radtodeg;
266     break;
267   case ofDeg:
268     DaRPos[ofRad] = pos*degtorad;
269     DaRPos[ofDeg] = pos;
270     break;
271   case ofNorm:
272     DaRPos[ofNorm] = pos;
273   }
274   DaRPos[ofMag] = fabs(DaRPos[ofRad]);
275 }
276
277 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278
279 void FGFCS::SetDePos( int form , double pos )
280 {
281   switch(form) {
282   case ofRad:
283     DePos[ofRad] = pos;
284     DePos[ofDeg] = pos*radtodeg;
285     break;
286   case ofDeg:
287     DePos[ofRad] = pos*degtorad;
288     DePos[ofDeg] = pos;
289     break;
290   case ofNorm:
291     DePos[ofNorm] = pos;
292   }
293   DePos[ofMag] = fabs(DePos[ofRad]);
294 }
295
296 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
297
298 void FGFCS::SetDrPos( int form , double pos )
299 {
300   switch(form) {
301   case ofRad:
302     DrPos[ofRad] = pos;
303     DrPos[ofDeg] = pos*radtodeg;
304     break;
305   case ofDeg:
306     DrPos[ofRad] = pos*degtorad;
307     DrPos[ofDeg] = pos;
308     break;
309   case ofNorm:
310     DrPos[ofNorm] = pos;
311   }
312   DrPos[ofMag] = fabs(DrPos[ofRad]);
313 }
314
315 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316
317 void FGFCS::SetDfPos( int form , double pos )
318 {
319   switch(form) {
320   case ofRad:
321     DfPos[ofRad] = pos;
322     DfPos[ofDeg] = pos*radtodeg;
323     break;
324   case ofDeg:
325     DfPos[ofRad] = pos*degtorad;
326     DfPos[ofDeg] = pos;
327     break;
328   case ofNorm:
329     DfPos[ofNorm] = pos;
330   }
331   DfPos[ofMag] = fabs(DfPos[ofRad]);
332 }
333
334 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335
336 void FGFCS::SetDsbPos( int form , double pos )
337 {
338   switch(form) {
339   case ofRad:
340     DsbPos[ofRad] = pos;
341     DsbPos[ofDeg] = pos*radtodeg;
342     break;
343   case ofDeg:
344     DsbPos[ofRad] = pos*degtorad;
345     DsbPos[ofDeg] = pos;
346     break;
347   case ofNorm:
348     DsbPos[ofNorm] = pos;
349   }
350   DsbPos[ofMag] = fabs(DsbPos[ofRad]);
351 }
352
353 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354
355 void FGFCS::SetDspPos( int form , double pos )
356 {
357   switch(form) {
358   case ofRad:
359     DspPos[ofRad] = pos;
360     DspPos[ofDeg] = pos*radtodeg;
361     break;
362   case ofDeg:
363     DspPos[ofRad] = pos*degtorad;
364     DspPos[ofDeg] = pos;
365     break;
366   case ofNorm:
367     DspPos[ofNorm] = pos;
368   }
369   DspPos[ofMag] = fabs(DspPos[ofRad]);
370 }
371
372 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373
374 void FGFCS::SetThrottleCmd(int engineNum, double setting)
375 {
376   unsigned int ctr;
377
378   if (engineNum < (int)ThrottlePos.size()) {
379     if (engineNum < 0) {
380       for (ctr=0;ctr<ThrottleCmd.size();ctr++) ThrottleCmd[ctr] = setting;
381     } else {
382       ThrottleCmd[engineNum] = setting;
383     }
384   } else {
385     cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
386          << " engines exist, but attempted throttle command is for engine "
387          << engineNum << endl;
388   }
389 }
390
391 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392
393 void FGFCS::SetThrottlePos(int engineNum, double setting)
394 {
395   unsigned int ctr;
396
397   if (engineNum < (int)ThrottlePos.size()) {
398     if (engineNum < 0) {
399       for (ctr=0;ctr<ThrottlePos.size();ctr++) ThrottlePos[ctr] = setting;
400     } else {
401       ThrottlePos[engineNum] = setting;
402     }
403   } else {
404     cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
405          << " engines exist, but attempted throttle position setting is for engine "
406          << engineNum << endl;
407   }
408 }
409
410 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411
412 double FGFCS::GetThrottleCmd(int engineNum) const
413 {
414   if (engineNum < (int)ThrottlePos.size()) {
415     if (engineNum < 0) {
416        cerr << "Cannot get throttle value for ALL engines" << endl;
417     } else {
418       return ThrottleCmd[engineNum];
419     }
420   } else {
421     cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
422          << " engines exist, but throttle setting for engine " << engineNum
423          << " is selected" << endl;
424   }
425   return 0.0;
426 }
427
428 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429
430 double FGFCS::GetThrottlePos(int engineNum) const
431 {
432   if (engineNum < (int)ThrottlePos.size()) {
433     if (engineNum < 0) {
434        cerr << "Cannot get throttle value for ALL engines" << endl;
435     } else {
436       return ThrottlePos[engineNum];
437     }
438   } else {
439     cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
440          << " engines exist, but attempted throttle position setting is for engine "
441          << engineNum << endl;
442   }
443   return 0.0;
444 }
445
446 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
447
448 void FGFCS::SetMixtureCmd(int engineNum, double setting)
449 {
450   unsigned int ctr;
451
452   if (engineNum < (int)ThrottlePos.size()) {
453     if (engineNum < 0) {
454       for (ctr=0;ctr<MixtureCmd.size();ctr++) MixtureCmd[ctr] = setting;
455     } else {
456       MixtureCmd[engineNum] = setting;
457     }
458   }
459 }
460
461 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
462
463 void FGFCS::SetMixturePos(int engineNum, double setting)
464 {
465   unsigned int ctr;
466
467   if (engineNum < (int)ThrottlePos.size()) {
468     if (engineNum < 0) {
469       for (ctr=0;ctr<MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
470     } else {
471       MixturePos[engineNum] = setting;
472     }
473   }
474 }
475
476 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477
478 void FGFCS::SetPropAdvanceCmd(int engineNum, double setting)
479 {
480   unsigned int ctr;
481
482   if (engineNum < (int)ThrottlePos.size()) {
483     if (engineNum < 0) {
484       for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvanceCmd[ctr] = setting;
485     } else {
486       PropAdvanceCmd[engineNum] = setting;
487     }
488   }
489 }
490
491 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492
493 void FGFCS::SetPropAdvance(int engineNum, double setting)
494 {
495   unsigned int ctr;
496
497   if (engineNum < (int)ThrottlePos.size()) {
498     if (engineNum < 0) {
499       for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
500     } else {
501       PropAdvance[engineNum] = setting;
502     }
503   }
504 }
505
506 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507
508 void FGFCS::SetFeatherCmd(int engineNum, bool setting)
509 {
510   unsigned int ctr;
511
512   if (engineNum < (int)ThrottlePos.size()) {
513     if (engineNum < 0) {
514       for (ctr=0;ctr<PropFeatherCmd.size();ctr++) PropFeatherCmd[ctr] = setting;
515     } else {
516       PropFeatherCmd[engineNum] = setting;
517     }
518   }
519 }
520
521 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
522
523 void FGFCS::SetPropFeather(int engineNum, bool setting)
524 {
525   unsigned int ctr;
526
527   if (engineNum < (int)ThrottlePos.size()) {
528     if (engineNum < 0) {
529       for (ctr=0;ctr<PropFeatherCmd.size();ctr++) PropFeather[ctr] = PropFeatherCmd[ctr];
530     } else {
531       PropFeather[engineNum] = setting;
532     }
533   }
534 }
535
536 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
537
538 bool FGFCS::Load(Element* el, SystemType systype)
539 {
540   string name, file, fname="", interface_property_string, parent_name;
541   vector <FGFCSComponent*> *Components;
542   Element *component_element;
543   Element *channel_element;
544
545   Components=0;
546
547 // ToDo: The handling of name and file attributes could be improved, here,
548 //       considering that a name can be in the external file, as well.
549
550   name = el->GetAttributeValue("name");
551
552   if (name.empty() || !el->GetAttributeValue("file").empty()) {
553     fname = el->GetAttributeValue("file");
554     if (systype == stSystem) {
555       file = FindSystemFullPathname(fname);
556     } else { 
557       file = FDMExec->GetFullAircraftPath() + "/" + fname + ".xml";
558     }
559     if (fname.empty()) {
560       cerr << "FCS, Autopilot, or system does not appear to be defined inline nor in a file" << endl;
561       return false;
562     } else {
563       document = LoadXMLDocument(file);
564       if (!document) {
565         cerr << "Error loading file " << file << endl;
566         return false;
567       }
568       name = document->GetAttributeValue("name");
569     }
570   } else {
571     document = el;
572   }
573
574   if (document->GetName() == "autopilot") {
575     Components = &APComponents;
576     Name = "Autopilot: " + document->GetAttributeValue("name");
577   } else if (document->GetName() == "flight_control") {
578     Components = &FCSComponents;
579     Name = "FCS: " + document->GetAttributeValue("name");
580   } else if (document->GetName() == "system") {
581     Components = &Systems;
582     Name = "System: " + document->GetAttributeValue("name");
583   }
584   Debug(2);
585
586   if (document->GetName() == "flight_control") bindModel();
587
588   FGModel::Load(document); // Load interface properties from document
589
590   // After reading interface properties in a file, read properties in the local
591   // flight_control, autopilot, or system element. This allows general-purpose
592   // systems to be defined in a file, with overrides or initial loaded constants
593   // supplied in the relevant element of the aircraft configuration file.
594
595   Element* property_element = 0;
596
597   if (!fname.empty()) {
598     property_element = el->FindElement("property");
599     if (property_element && debug_lvl > 0) cout << endl << "    Overriding properties" << endl << endl;
600     while (property_element) {
601       double value=0.0;
602       if ( ! property_element->GetAttributeValue("value").empty())
603         value = property_element->GetAttributeValueAsNumber("value");
604
605       interface_property_string = property_element->GetDataLine();
606       if (PropertyManager->HasNode(interface_property_string)) {
607         FGPropertyManager* node = PropertyManager->GetNode(interface_property_string);
608         if (debug_lvl > 0)
609           cout << "      " << "Overriding value for property " << interface_property_string
610                << " (old value: " << node->getDoubleValue() << "  new value: " << value << ")" << endl;
611         node->setDoubleValue(value);
612       } else {
613         interface_properties.push_back(new double(value));
614         PropertyManager->Tie(interface_property_string, interface_properties.back());
615         if (debug_lvl > 0)
616           cout << "      " << interface_property_string << " (initial value: " << value << ")" << endl;
617       }
618       
619       property_element = el->FindNextElement("property");
620     }
621   }
622
623   channel_element = document->FindElement("channel");
624   while (channel_element) {
625   
626     if (debug_lvl > 0)
627       cout << endl << highint << fgblue << "    Channel " 
628          << normint << channel_element->GetAttributeValue("name") << reset << endl;
629   
630     component_element = channel_element->GetElement();
631     while (component_element) {
632       try {
633         if ((component_element->GetName() == string("lag_filter")) ||
634             (component_element->GetName() == string("lead_lag_filter")) ||
635             (component_element->GetName() == string("washout_filter")) ||
636             (component_element->GetName() == string("second_order_filter")) ||
637             (component_element->GetName() == string("integrator")) )
638         {
639           Components->push_back(new FGFilter(this, component_element));
640         } else if ((component_element->GetName() == string("pure_gain")) ||
641                    (component_element->GetName() == string("scheduled_gain")) ||
642                    (component_element->GetName() == string("aerosurface_scale")))
643         {
644           Components->push_back(new FGGain(this, component_element));
645         } else if (component_element->GetName() == string("summer")) {
646           Components->push_back(new FGSummer(this, component_element));
647         } else if (component_element->GetName() == string("deadband")) {
648           Components->push_back(new FGDeadBand(this, component_element));
649         } else if (component_element->GetName() == string("switch")) {
650           Components->push_back(new FGSwitch(this, component_element));
651         } else if (component_element->GetName() == string("kinematic")) {
652           Components->push_back(new FGKinemat(this, component_element));
653         } else if (component_element->GetName() == string("fcs_function")) {
654           Components->push_back(new FGFCSFunction(this, component_element));
655         } else if (component_element->GetName() == string("pid")) {
656           Components->push_back(new FGPID(this, component_element));
657         } else if (component_element->GetName() == string("actuator")) {
658           Components->push_back(new FGActuator(this, component_element));
659         } else if (component_element->GetName() == string("sensor")) {
660           Components->push_back(new FGSensor(this, component_element));
661         } else if (component_element->GetName() == string("accelerometer")) {
662           Components->push_back(new FGAccelerometer(this, component_element));
663         } else if (component_element->GetName() == string("magnetometer")) {
664           Components->push_back(new FGMagnetometer(this, component_element));
665         } else if (component_element->GetName() == string("gyro")) {
666           Components->push_back(new FGGyro(this, component_element));
667         } else {
668           cerr << "Unknown FCS component: " << component_element->GetName() << endl;
669         }
670       } catch(string s) {
671         cerr << highint << fgred << endl << "  " << s << endl;
672         cerr << reset << endl;
673         return false;
674       }
675       component_element = channel_element->GetNextElement();
676     }
677     channel_element = document->FindNextElement("channel");
678   }
679
680   ResetParser();
681
682   return true;
683 }
684
685 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686
687 double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
688 {
689   switch (bg) {
690   case FGLGear::bgLeft:
691     return LeftBrake;
692   case FGLGear::bgRight:
693     return RightBrake;
694   case FGLGear::bgCenter:
695     return CenterBrake;
696   default:
697     cerr << "GetBrake asked to return a bogus brake value" << endl;
698   }
699   return 0.0;
700 }
701
702 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703
704 string FGFCS::FindSystemFullPathname(const string& sysfilename)
705 {
706   string fullpath, localpath;
707   string system_filename = sysfilename;
708   string systemPath = FDMExec->GetSystemsPath();
709   string aircraftPath = FDMExec->GetFullAircraftPath();
710   ifstream system_file;
711
712   fullpath = systemPath + "/";
713   localpath = aircraftPath + "/Systems/";
714
715   if (system_filename.length() <=4 || system_filename.substr(system_filename.length()-4, 4) != ".xml") {
716     system_filename.append(".xml");
717   }
718
719   system_file.open(string(localpath + system_filename).c_str());
720   if ( !system_file.is_open()) {
721     system_file.open(string(fullpath + system_filename).c_str());
722       if ( !system_file.is_open()) {
723         cerr << " Could not open system file: " << system_filename << " in path "
724              << fullpath << " or " << localpath << endl;
725         return string("");
726       } else {
727         return string(fullpath + system_filename);
728       }
729   }
730   return string(localpath + system_filename);
731 }
732
733 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
734
735 ifstream* FGFCS::FindSystemFile(const string& sysfilename)
736 {
737   string fullpath, localpath;
738   string system_filename = sysfilename;
739   string systemPath = FDMExec->GetSystemsPath();
740   string aircraftPath = FDMExec->GetFullAircraftPath();
741   ifstream* system_file = new ifstream();
742
743   fullpath = systemPath + "/";
744   localpath = aircraftPath + "/Systems/";
745
746   if (system_filename.substr(system_filename.length()-4, 4) != ".xml") {
747     system_filename.append(".xml");
748   }
749
750   system_file->open(string(localpath + system_filename).c_str());
751   if ( !system_file->is_open()) {
752     system_file->open(string(fullpath + system_filename).c_str());
753       if ( !system_file->is_open()) {
754         cerr << " Could not open system file: " << system_filename << " in path "
755              << fullpath << " or " << localpath << endl;
756       }
757   }
758   return system_file;
759 }
760
761 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
762
763 string FGFCS::GetComponentStrings(const string& delimiter)
764 {
765   unsigned int comp;
766   string CompStrings = "";
767   bool firstime = true;
768   int total_count=0;
769
770   for (unsigned int i=0; i<Systems.size(); i++) {
771     if (firstime) firstime = false;
772     else          CompStrings += delimiter;
773
774     CompStrings += Systems[i]->GetName();
775     total_count++;
776   }
777
778   for (comp = 0; comp < APComponents.size(); comp++)
779   {
780     if (firstime) firstime = false;
781     else          CompStrings += delimiter;
782
783     CompStrings += APComponents[comp]->GetName();
784     total_count++;
785   }
786
787   for (comp = 0; comp < FCSComponents.size(); comp++) {
788     if (firstime) firstime = false;
789     else          CompStrings += delimiter;
790
791     CompStrings += FCSComponents[comp]->GetName();
792     total_count++;
793   }
794
795   return CompStrings;
796 }
797
798 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
799
800 string FGFCS::GetComponentValues(const string& delimiter)
801 {
802   std::ostringstream buf;
803
804   unsigned int comp;
805   bool firstime = true;
806   int total_count=0;
807
808   for (unsigned int i=0; i<Systems.size(); i++) {
809     if (firstime) firstime = false;
810     else          buf << delimiter;
811
812     buf << setprecision(9) << Systems[i]->GetOutput();
813     total_count++;
814   }
815
816   for (comp = 0; comp < APComponents.size(); comp++) {
817     if (firstime) firstime = false;
818     else          buf << delimiter;
819
820     buf << setprecision(9) << APComponents[comp]->GetOutput();
821     total_count++;
822   }
823
824   for (comp = 0; comp < FCSComponents.size(); comp++) {
825     if (firstime) firstime = false;
826     else          buf << delimiter;
827
828     buf << setprecision(9) << FCSComponents[comp]->GetOutput();
829     total_count++;
830   }
831
832   return buf.str();
833 }
834
835 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
836
837 void FGFCS::AddThrottle(void)
838 {
839   ThrottleCmd.push_back(0.0);
840   ThrottlePos.push_back(0.0);
841   MixtureCmd.push_back(0.0);     // assume throttle and mixture are coupled
842   MixturePos.push_back(0.0);
843   PropAdvanceCmd.push_back(0.0); // assume throttle and prop pitch are coupled
844   PropAdvance.push_back(0.0);
845   PropFeatherCmd.push_back(false);
846   PropFeather.push_back(false);
847
848   unsigned int num = (unsigned int)ThrottleCmd.size()-1;
849   bindThrottle(num);
850 }
851
852 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
853
854 void FGFCS::AddGear(void)
855 {
856   SteerPosDeg.push_back(0.0);
857 }
858
859 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860
861 double FGFCS::GetDt(void)
862 {
863   return FDMExec->GetDeltaT()*rate;
864 }
865
866 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867
868 void FGFCS::bind(void)
869 {
870   PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);
871   PropertyManager->Tie("fcs/elevator-cmd-norm", this, &FGFCS::GetDeCmd, &FGFCS::SetDeCmd);
872   PropertyManager->Tie("fcs/rudder-cmd-norm", this, &FGFCS::GetDrCmd, &FGFCS::SetDrCmd);
873   PropertyManager->Tie("fcs/flap-cmd-norm", this, &FGFCS::GetDfCmd, &FGFCS::SetDfCmd);
874   PropertyManager->Tie("fcs/speedbrake-cmd-norm", this, &FGFCS::GetDsbCmd, &FGFCS::SetDsbCmd);
875   PropertyManager->Tie("fcs/spoiler-cmd-norm", this, &FGFCS::GetDspCmd, &FGFCS::SetDspCmd);
876   PropertyManager->Tie("fcs/pitch-trim-cmd-norm", this, &FGFCS::GetPitchTrimCmd, &FGFCS::SetPitchTrimCmd);
877   PropertyManager->Tie("fcs/roll-trim-cmd-norm", this, &FGFCS::GetRollTrimCmd, &FGFCS::SetRollTrimCmd);
878   PropertyManager->Tie("fcs/yaw-trim-cmd-norm", this, &FGFCS::GetYawTrimCmd, &FGFCS::SetYawTrimCmd);
879
880   PropertyManager->Tie("fcs/left-aileron-pos-rad", this, ofRad, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
881   PropertyManager->Tie("fcs/left-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
882   PropertyManager->Tie("fcs/left-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
883   PropertyManager->Tie("fcs/mag-left-aileron-pos-rad", this, ofMag, &FGFCS::GetDaLPos);
884
885   PropertyManager->Tie("fcs/right-aileron-pos-rad", this, ofRad, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
886   PropertyManager->Tie("fcs/right-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
887   PropertyManager->Tie("fcs/right-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
888   PropertyManager->Tie("fcs/mag-right-aileron-pos-rad", this, ofMag, &FGFCS::GetDaRPos);
889
890   PropertyManager->Tie("fcs/elevator-pos-rad", this, ofRad, &FGFCS::GetDePos, &FGFCS::SetDePos);
891   PropertyManager->Tie("fcs/elevator-pos-deg", this, ofDeg, &FGFCS::GetDePos, &FGFCS::SetDePos);
892   PropertyManager->Tie("fcs/elevator-pos-norm", this, ofNorm, &FGFCS::GetDePos, &FGFCS::SetDePos);
893   PropertyManager->Tie("fcs/mag-elevator-pos-rad", this, ofMag, &FGFCS::GetDePos);
894
895   PropertyManager->Tie("fcs/rudder-pos-rad", this,ofRad, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
896   PropertyManager->Tie("fcs/rudder-pos-deg", this,ofDeg, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
897   PropertyManager->Tie("fcs/rudder-pos-norm", this,ofNorm, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
898   PropertyManager->Tie("fcs/mag-rudder-pos-rad", this,ofMag, &FGFCS::GetDrPos);
899
900   PropertyManager->Tie("fcs/flap-pos-rad", this,ofRad, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
901   PropertyManager->Tie("fcs/flap-pos-deg", this,ofDeg, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
902   PropertyManager->Tie("fcs/flap-pos-norm", this,ofNorm, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
903
904   PropertyManager->Tie("fcs/speedbrake-pos-rad", this,ofRad, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
905   PropertyManager->Tie("fcs/speedbrake-pos-deg", this,ofDeg, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
906   PropertyManager->Tie("fcs/speedbrake-pos-norm", this,ofNorm, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
907   PropertyManager->Tie("fcs/mag-speedbrake-pos-rad", this,ofMag, &FGFCS::GetDsbPos);
908
909   PropertyManager->Tie("fcs/spoiler-pos-rad", this, ofRad, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
910   PropertyManager->Tie("fcs/spoiler-pos-deg", this, ofDeg, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
911   PropertyManager->Tie("fcs/spoiler-pos-norm", this, ofNorm, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
912   PropertyManager->Tie("fcs/mag-spoiler-pos-rad", this, ofMag, &FGFCS::GetDspPos);
913
914   PropertyManager->Tie("gear/gear-pos-norm", this, &FGFCS::GetGearPos, &FGFCS::SetGearPos);
915   PropertyManager->Tie("gear/gear-cmd-norm", this, &FGFCS::GetGearCmd, &FGFCS::SetGearCmd);
916   PropertyManager->Tie("fcs/left-brake-cmd-norm", this, &FGFCS::GetLBrake, &FGFCS::SetLBrake);
917   PropertyManager->Tie("fcs/right-brake-cmd-norm", this, &FGFCS::GetRBrake, &FGFCS::SetRBrake);
918   PropertyManager->Tie("fcs/center-brake-cmd-norm", this, &FGFCS::GetCBrake, &FGFCS::SetCBrake);
919   PropertyManager->Tie("fcs/steer-cmd-norm", this, &FGFCS::GetDsCmd, &FGFCS::SetDsCmd);
920
921   PropertyManager->Tie("gear/tailhook-pos-norm", this, &FGFCS::GetTailhookPos, &FGFCS::SetTailhookPos);
922   PropertyManager->Tie("fcs/wing-fold-pos-norm", this, &FGFCS::GetWingFoldPos, &FGFCS::SetWingFoldPos);
923 }
924
925 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926 // Technically, this function should probably bind propulsion type specific controls
927 // rather than mixture and prop-advance.
928
929 void FGFCS::bindThrottle(unsigned int num)
930 {
931   string tmp;
932
933   tmp = CreateIndexedPropertyName("fcs/throttle-cmd-norm", num);
934   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetThrottleCmd,
935                                         &FGFCS::SetThrottleCmd);
936   tmp = CreateIndexedPropertyName("fcs/throttle-pos-norm", num);
937   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetThrottlePos,
938                                         &FGFCS::SetThrottlePos);
939   tmp = CreateIndexedPropertyName("fcs/mixture-cmd-norm", num);
940   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetMixtureCmd,
941                                         &FGFCS::SetMixtureCmd);
942   tmp = CreateIndexedPropertyName("fcs/mixture-pos-norm", num);
943   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetMixturePos,
944                                         &FGFCS::SetMixturePos);
945   tmp = CreateIndexedPropertyName("fcs/advance-cmd-norm", num);
946   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetPropAdvanceCmd,
947                                         &FGFCS::SetPropAdvanceCmd);
948   tmp = CreateIndexedPropertyName("fcs/advance-pos-norm", num);
949   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetPropAdvance,
950                                         &FGFCS::SetPropAdvance);
951   tmp = CreateIndexedPropertyName("fcs/feather-cmd-norm", num);
952   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetFeatherCmd,
953                                         &FGFCS::SetFeatherCmd);
954   tmp = CreateIndexedPropertyName("fcs/feather-pos-norm", num);
955   PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetPropFeather,
956                                         &FGFCS::SetPropFeather);
957 }
958
959 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
960
961 void FGFCS::bindModel(void)
962 {
963   unsigned int i;
964   string tmp;
965
966   for (i=0; i<SteerPosDeg.size(); i++) {
967     if (GroundReactions->GetGearUnit(i)->GetSteerable()) {
968       tmp = CreateIndexedPropertyName("fcs/steer-pos-deg", i);
969       PropertyManager->Tie( tmp.c_str(), this, i, &FGFCS::GetSteerPosDeg, &FGFCS::SetSteerPosDeg);
970     }
971   }
972 }
973
974 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 //    The bitmasked value choices are as follows:
976 //    unset: In this case (the default) JSBSim would only print
977 //       out the normally expected messages, essentially echoing
978 //       the config files as they are read. If the environment
979 //       variable is not set, debug_lvl is set to 1 internally
980 //    0: This requests JSBSim not to output any messages
981 //       whatsoever.
982 //    1: This value explicity requests the normal JSBSim
983 //       startup messages
984 //    2: This value asks for a message to be printed out when
985 //       a class is instantiated
986 //    4: When this value is set, a message is displayed when a
987 //       FGModel object executes its Run() method
988 //    8: When this value is set, various runtime state variables
989 //       are printed out periodically
990 //    16: When set various parameters are sanity checked and
991 //       a message is printed out when they go out of bounds
992
993 void FGFCS::Debug(int from)
994 {
995   if (debug_lvl <= 0) return;
996
997   if (debug_lvl & 1) { // Standard console startup message output
998     if (from == 2) { // Loader
999       cout << endl << "  " << Name << endl;
1000     }
1001   }
1002   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
1003     if (from == 0) cout << "Instantiated: FGFCS" << endl;
1004     if (from == 1) cout << "Destroyed:    FGFCS" << endl;
1005   }
1006   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
1007   }
1008   if (debug_lvl & 8 ) { // Runtime state variables
1009   }
1010   if (debug_lvl & 16) { // Sanity checking
1011   }
1012   if (debug_lvl & 64) {
1013     if (from == 0) { // Constructor
1014       cout << IdSrc << endl;
1015       cout << IdHdr << endl;
1016     }
1017   }
1018 }
1019
1020 }