]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGScript.cpp
aa85b427f9dab906c4796e821542bf46f74fac68
[flightgear.git] / src / FDM / JSBSim / FGScript.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGScript.cpp
4  Author:       Jon S. Berndt
5  Date started: 12/21/01
6  Purpose:      Loads and runs JSBSim scripts.
7
8  ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------
9
10  This program is free software; you can redistribute it and/or modify it under
11  the terms of the GNU General Public License as published by the Free Software
12  Foundation; either version 2 of the License, or (at your option) any later
13  version.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  details.
19
20  You should have received a copy of the GNU General Public License along with
21  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  Place - Suite 330, Boston, MA  02111-1307, USA.
23
24  Further information about the GNU General Public License can also be found on
25  the world wide web at http://www.gnu.org.
26
27 FUNCTIONAL DESCRIPTION
28 --------------------------------------------------------------------------------
29
30 This class wraps up the simulation scripting routines.
31
32 HISTORY
33 --------------------------------------------------------------------------------
34 12/21/01   JSB   Created
35
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 COMMENTS, REFERENCES,  and NOTES
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39
40 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41 INCLUDES
42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
43
44 #ifdef FGFS
45 #  include <simgear/compiler.h>
46 #  include STL_IOSTREAM
47 #  include STL_ITERATOR
48 #else
49 #  if defined(sgi) && !defined(__GNUC__)
50 #    include <iostream.h>
51 #  else
52 #    include <iostream>
53 #  endif
54 #  include <iterator>
55 #endif
56
57 #include "FGScript.h"
58 #include "FGConfigFile.h"
59
60 namespace JSBSim {
61
62 static const char *IdSrc = "$Id$";
63 static const char *IdHdr = ID_FGSCRIPT;
64
65 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 GLOBAL DECLARATIONS
67 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
68
69 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
70 CLASS IMPLEMENTATION
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
72
73 // Constructor
74
75 FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
76 {
77   State = FDMExec->GetState();
78   PropertyManager=FDMExec->GetPropertyManager();
79   Debug(0);
80 }
81
82 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83
84 FGScript::~FGScript()
85 {
86   Debug(1);
87 }
88
89 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90
91 bool FGScript::LoadScript( string script )
92 {
93   FGConfigFile Script(script);
94   string token="";
95   string aircraft="";
96   string initialize="";
97   string prop_name;
98   bool result = false;
99   double dt = 0.0;
100   struct condition *newCondition;
101
102   if (!Script.IsOpen()) return false;
103
104   Script.GetNextConfigLine();
105   if (Script.GetValue("runscript").length() <= 0) {
106     cerr << "File: " << script << " is not a script file" << endl;
107     delete FDMExec;
108     return false; 
109   }
110   ScriptName = Script.GetValue("name");
111   Scripted = true;
112
113   if (debug_lvl > 0) cout << "Reading and running from script file " << ScriptName << endl << endl;
114
115   while (Script.GetNextConfigLine() != string("EOF") && Script.GetValue() != string("/runscript")) {
116     token = Script.GetValue();
117     if (token == "use") {
118       if ((token = Script.GetValue("aircraft")) != string("")) {
119         aircraft = token;
120         result = FDMExec->LoadModel(aircraft);
121         if (!result) {
122           cerr << "Aircraft file " << aircraft << " was not found" << endl;
123           exit(-1);
124         }
125         if (debug_lvl > 0) cout << "  Use aircraft: " << token << endl;
126       } else if ((token = Script.GetValue("initialize")) != string("")) {
127         initialize = token;
128         if (debug_lvl > 0) cout << "  Use reset file: " << token << endl;
129       } else {
130         cerr << "Unknown 'use' keyword: \"" << token << "\"" << endl;
131       }
132     } else if (token == "run") {
133       StartTime = strtod(Script.GetValue("start").c_str(), NULL);
134       State->Setsim_time(StartTime);
135       EndTime   = strtod(Script.GetValue("end").c_str(), NULL);
136       dt        = strtod(Script.GetValue("dt").c_str(), NULL);
137       State->Setdt(dt);
138       Script.GetNextConfigLine();
139       token = Script.GetValue();
140       while (token != string("/run")) {
141
142         if (token == "when") {
143           Script.GetNextConfigLine();
144           token = Script.GetValue();
145           newCondition = new struct condition();
146           while (token != string("/when")) {
147             if (token == "parameter") {
148               prop_name = Script.GetValue("name");
149               newCondition->TestParam.push_back( PropertyManager->GetNode(prop_name) );
150               newCondition->TestValue.push_back(strtod(Script.GetValue("value").c_str(), NULL));
151               newCondition->Comparison.push_back(Script.GetValue("comparison"));
152             } else if (token == "set") {
153               prop_name = Script.GetValue("name");
154               newCondition->SetParam.push_back( PropertyManager->GetNode(prop_name) );
155               newCondition->SetValue.push_back(strtod(Script.GetValue("value").c_str(), NULL));
156               newCondition->Triggered.push_back(false);
157               newCondition->OriginalValue.push_back(0.0);
158               newCondition->newValue.push_back(0.0);
159               newCondition->StartTime.push_back(0.0);
160               newCondition->EndTime.push_back(0.0);
161               string tempCompare = Script.GetValue("type");
162               if      (tempCompare == "FG_DELTA") newCondition->Type.push_back(FG_DELTA);
163               else if (tempCompare == "FG_BOOL")  newCondition->Type.push_back(FG_BOOL);
164               else if (tempCompare == "FG_VALUE") newCondition->Type.push_back(FG_VALUE);
165               else                                newCondition->Type.push_back((eType)0);
166               tempCompare = Script.GetValue("action");
167               if      (tempCompare == "FG_RAMP") newCondition->Action.push_back(FG_RAMP);
168               else if (tempCompare == "FG_STEP") newCondition->Action.push_back(FG_STEP);
169               else if (tempCompare == "FG_EXP")  newCondition->Action.push_back(FG_EXP);
170               else                               newCondition->Action.push_back((eAction)0);
171               
172               if (Script.GetValue("persistent") == "true")
173                 newCondition->Persistent.push_back(true);
174               else
175                 newCondition->Persistent.push_back(false);
176                 
177               newCondition->TC.push_back(strtod(Script.GetValue("tc").c_str(), NULL));
178               
179             } else {
180               cerr << "Unrecognized keyword in script file: \" [when] " << token << "\"" << endl;
181             }
182             Script.GetNextConfigLine();
183             token = Script.GetValue();
184           }
185           Conditions.push_back(*newCondition);
186           Script.GetNextConfigLine();
187           token = Script.GetValue();
188
189         } else {
190           cerr << "Error reading script file: expected \"when\", got \"" << token << "\"" << endl;
191         }
192
193       }
194     } else if (token.empty()) {
195      // do nothing
196     } else {
197       cerr << "Unrecognized keyword in script file: \"" << token << "\" [runscript] " << endl;
198     }
199   }
200
201   if (aircraft == "") {
202     cerr << "Aircraft file not loaded in script" << endl;
203     exit(-1);
204   }
205
206   Debug(4);
207
208
209   FGInitialCondition *IC=FDMExec->GetIC();
210   if ( ! IC->Load( initialize )) {
211     cerr << "Initialization unsuccessful" << endl;
212     exit(-1);
213   }
214
215   return true;
216 }
217
218 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219
220 bool FGScript::RunScript(void)
221 {
222   vector <struct condition>::iterator iC = Conditions.begin();
223   bool truth = false;
224   bool WholeTruth = false;
225   unsigned i;
226
227   double currentTime = State->Getsim_time();
228   double newSetValue = 0;
229
230   if (currentTime > EndTime) return false;
231
232   while (iC < Conditions.end()) {
233     // determine whether the set of conditional tests for this condition equate
234     // to true
235     for (i=0; i<iC->TestValue.size(); i++) {
236            if (iC->Comparison[i] == "lt")
237               truth = iC->TestParam[i]->getDoubleValue() <  iC->TestValue[i];
238       else if (iC->Comparison[i] == "le")
239               truth = iC->TestParam[i]->getDoubleValue() <= iC->TestValue[i];
240       else if (iC->Comparison[i] == "eq")
241               truth = iC->TestParam[i]->getDoubleValue() == iC->TestValue[i];
242       else if (iC->Comparison[i] == "ge")
243               truth = iC->TestParam[i]->getDoubleValue() >= iC->TestValue[i];
244       else if (iC->Comparison[i] == "gt")
245               truth = iC->TestParam[i]->getDoubleValue() >  iC->TestValue[i];
246       else if (iC->Comparison[i] == "ne")
247               truth = iC->TestParam[i]->getDoubleValue() != iC->TestValue[i];
248       else
249               cerr << "Bad comparison" << endl;
250
251       if (i == 0) WholeTruth = truth;
252       else        WholeTruth = WholeTruth && truth;
253
254       if (!truth && iC->Persistent[i] && iC->Triggered[i]) iC->Triggered[i] = false;
255     }
256
257     // if the conditions are true, do the setting of the desired parameters
258
259     if (WholeTruth) {
260       for (i=0; i<iC->SetValue.size(); i++) {
261         if ( ! iC->Triggered[i]) {
262           iC->OriginalValue[i] = iC->SetParam[i]->getDoubleValue();
263           switch (iC->Type[i]) {
264           case FG_VALUE:
265             iC->newValue[i] = iC->SetValue[i];
266             break;
267           case FG_DELTA:
268             iC->newValue[i] = iC->OriginalValue[i] + iC->SetValue[i];
269             break;
270           case FG_BOOL:
271             iC->newValue[i] = iC->SetValue[i];
272             break;
273           default:
274             cerr << "Invalid Type specified" << endl;
275             break;
276           }
277           iC->Triggered[i] = true;
278           iC->StartTime[i] = currentTime;
279         }
280
281         switch (iC->Action[i]) {
282         case FG_RAMP:
283         newSetValue = (currentTime - iC->StartTime[i])/(iC->TC[i])
284                       * (iC->newValue[i] - iC->OriginalValue[i]) + iC->OriginalValue[i];
285           if (newSetValue > iC->newValue[i]) newSetValue = iC->newValue[i];
286           break;
287         case FG_STEP:
288           newSetValue = iC->newValue[i];
289           break;
290         case FG_EXP:
291           newSetValue = (1 - exp(-(currentTime - iC->StartTime[i])/(iC->TC[i])))
292               * (iC->newValue[i] - iC->OriginalValue[i]) + iC->OriginalValue[i];
293           break;
294         default:
295           cerr << "Invalid Action specified" << endl;
296           break;
297         }
298         iC->SetParam[i]->setDoubleValue(newSetValue);
299       }
300     }
301     iC++;
302   }
303   return true;
304 }
305
306 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
307 //    The bitmasked value choices are as follows:
308 //    unset: In this case (the default) JSBSim would only print
309 //       out the normally expected messages, essentially echoing
310 //       the config files as they are read. If the environment
311 //       variable is not set, debug_lvl is set to 1 internally
312 //    0: This requests JSBSim not to output any messages
313 //       whatsoever.
314 //    1: This value explicity requests the normal JSBSim
315 //       startup messages
316 //    2: This value asks for a message to be printed out when
317 //       a class is instantiated
318 //    4: When this value is set, a message is displayed when a
319 //       FGModel object executes its Run() method
320 //    8: When this value is set, various runtime state variables
321 //       are printed out periodically
322 //    16: When set various parameters are sanity checked and
323 //       a message is printed out when they go out of bounds
324
325 void FGScript::Debug(int from)
326 {
327   unsigned int i;
328
329   if (debug_lvl <= 0) return;
330
331   if (debug_lvl & 1) { // Standard console startup message output
332     if (from == 0) { // Constructor
333     } else if (from == 3) {
334     } else if (from == 4)  { // print out script data
335       vector <struct condition>::iterator iterConditions = Conditions.begin();
336       int count=0;
337
338       cout << "\n  Script goes from " << StartTime << " to " << EndTime
339            << " with dt = " << State->Getdt() << endl << endl;
340
341       while (iterConditions < Conditions.end()) {
342         cout << "  Condition: " << count++ << endl;
343         cout << "    if (";
344
345         for (i=0; i<iterConditions->TestValue.size(); i++) {
346           if (i>0) cout << " and" << endl << "        ";
347           cout << "(" << iterConditions->TestParam[i]->GetName()
348                       << " " << iterConditions->Comparison[i] << " "
349                       << iterConditions->TestValue[i] << ")";
350         }
351         cout << ") then {";
352
353         for (i=0; i<iterConditions->SetValue.size(); i++) {
354           cout << endl << "      set " << iterConditions->SetParam[i]->GetName()
355                << " to " << iterConditions->SetValue[i];
356
357           switch (iterConditions->Type[i]) {
358           case FG_VALUE:
359             cout << " (constant";
360             break;
361           case FG_DELTA:
362             cout << " (delta";
363             break;
364           case FG_BOOL:
365             cout << " (boolean";
366             break;
367           default:
368             cout << " (unspecified type";
369           }
370
371           switch (iterConditions->Action[i]) {
372           case FG_RAMP:
373             cout << " via ramp";
374             break;
375           case FG_STEP:
376             cout << " via step";
377             break;
378           case FG_EXP:
379             cout << " via exponential approach";
380             break;
381           default:
382             cout << " via unspecified action";
383           }
384
385           if (!iterConditions->Persistent[i]) cout << endl
386                              << "                              once";
387           else cout << endl
388                              << "                              repeatedly";
389
390           if (iterConditions->Action[i] == FG_RAMP ||
391               iterConditions->Action[i] == FG_EXP) cout << endl
392                              << "                              with time constant "
393                              << iterConditions->TC[i];
394         }
395         cout << ")" << endl << "    }" << endl << endl;
396
397         iterConditions++;
398       }
399
400       cout << endl;
401     }
402   }
403   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
404     if (from == 0) cout << "Instantiated: FGScript" << endl;
405     if (from == 1) cout << "Destroyed:    FGScript" << endl;
406   }
407   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
408   }
409   if (debug_lvl & 8 ) { // Runtime state variables
410   }
411   if (debug_lvl & 16) { // Sanity checking
412   }
413   if (debug_lvl & 64) {
414     if (from == 0) { // Constructor
415       cout << IdSrc << endl;
416       cout << IdHdr << endl;
417     }
418   }
419 }
420 }