]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGScript.cpp
#include <config.h> where needed for cygwin/gcc-3.2.
[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 static const char *IdSrc = "$Id$";
61 static const char *IdHdr = ID_FGSCRIPT;
62
63 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64 GLOBAL DECLARATIONS
65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
66
67 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68 CLASS IMPLEMENTATION
69 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
70
71 // Constructor
72
73 FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
74 {
75   State = FDMExec->GetState();
76   PropertyManager=FDMExec->GetPropertyManager();
77   Debug(0);
78 }
79
80 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81
82 FGScript::~FGScript()
83 {
84   Debug(1);
85 }
86
87 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88
89 bool FGScript::LoadScript( string script )
90 {
91   FGConfigFile Script(script);
92   string token="";
93   string aircraft="";
94   string initialize="";
95   string prop_name;
96   bool result = false;
97   double dt = 0.0;
98   struct condition *newCondition;
99
100   if (!Script.IsOpen()) return false;
101
102   Script.GetNextConfigLine();
103   if (Script.GetValue("runscript").length() <= 0) {
104     cerr << "File: " << script << " is not a script file" << endl;
105     delete FDMExec;
106     return false; 
107   }
108   ScriptName = Script.GetValue("name");
109   Scripted = true;
110
111   if (debug_lvl > 0) cout << "Reading and running from script file " << ScriptName << endl << endl;
112
113   while (Script.GetNextConfigLine() != string("EOF") && Script.GetValue() != string("/runscript")) {
114     token = Script.GetValue();
115     if (token == "use") {
116       if ((token = Script.GetValue("aircraft")) != string("")) {
117         aircraft = token;
118         result = FDMExec->LoadModel(aircraft);
119         if (!result) {
120           cerr << "Aircraft file " << aircraft << " was not found" << endl;
121           exit(-1);
122         }
123         if (debug_lvl > 0) cout << "  Use aircraft: " << token << endl;
124       } else if ((token = Script.GetValue("initialize")) != string("")) {
125         initialize = token;
126         if (debug_lvl > 0) cout << "  Use reset file: " << token << endl;
127       } else {
128         cerr << "Unknown 'use' keyword: \"" << token << "\"" << endl;
129       }
130     } else if (token == "run") {
131       StartTime = strtod(Script.GetValue("start").c_str(), NULL);
132       State->Setsim_time(StartTime);
133       EndTime   = strtod(Script.GetValue("end").c_str(), NULL);
134       dt        = strtod(Script.GetValue("dt").c_str(), NULL);
135       State->Setdt(dt);
136       Script.GetNextConfigLine();
137       token = Script.GetValue();
138       while (token != string("/run")) {
139
140         if (token == "when") {
141           Script.GetNextConfigLine();
142           token = Script.GetValue();
143           newCondition = new struct condition();
144           while (token != string("/when")) {
145             if (token == "parameter") {
146               prop_name = Script.GetValue("name");
147               newCondition->TestParam.push_back( PropertyManager->GetNode(prop_name) );
148               newCondition->TestValue.push_back(strtod(Script.GetValue("value").c_str(), NULL));
149               newCondition->Comparison.push_back(Script.GetValue("comparison"));
150             } else if (token == "set") {
151               prop_name = Script.GetValue("name");
152               newCondition->SetParam.push_back( PropertyManager->GetNode(prop_name) );
153               newCondition->SetValue.push_back(strtod(Script.GetValue("value").c_str(), NULL));
154               newCondition->Triggered.push_back(false);
155               newCondition->OriginalValue.push_back(0.0);
156               newCondition->newValue.push_back(0.0);
157               newCondition->StartTime.push_back(0.0);
158               newCondition->EndTime.push_back(0.0);
159               string tempCompare = Script.GetValue("type");
160               if      (tempCompare == "FG_DELTA") newCondition->Type.push_back(FG_DELTA);
161               else if (tempCompare == "FG_BOOL")  newCondition->Type.push_back(FG_BOOL);
162               else if (tempCompare == "FG_VALUE") newCondition->Type.push_back(FG_VALUE);
163               else                                newCondition->Type.push_back((eType)0);
164               tempCompare = Script.GetValue("action");
165               if      (tempCompare == "FG_RAMP") newCondition->Action.push_back(FG_RAMP);
166               else if (tempCompare == "FG_STEP") newCondition->Action.push_back(FG_STEP);
167               else if (tempCompare == "FG_EXP")  newCondition->Action.push_back(FG_EXP);
168               else                               newCondition->Action.push_back((eAction)0);
169               
170               if (Script.GetValue("persistent") == "true")
171                 newCondition->Persistent.push_back(true);
172               else
173                 newCondition->Persistent.push_back(false);
174                 
175               newCondition->TC.push_back(strtod(Script.GetValue("tc").c_str(), NULL));
176               
177             } else {
178               cerr << "Unrecognized keyword in script file: \" [when] " << token << "\"" << endl;
179             }
180             Script.GetNextConfigLine();
181             token = Script.GetValue();
182           }
183           Conditions.push_back(*newCondition);
184           Script.GetNextConfigLine();
185           token = Script.GetValue();
186
187         } else {
188           cerr << "Error reading script file: expected \"when\", got \"" << token << "\"" << endl;
189         }
190
191       }
192     } else if (token.empty()) {
193      // do nothing
194     } else {
195       cerr << "Unrecognized keyword in script file: \"" << token << "\" [runscript] " << endl;
196     }
197   }
198
199   if (aircraft == "") {
200     cerr << "Aircraft file not loaded in script" << endl;
201     exit(-1);
202   }
203
204   Debug(4);
205
206
207   FGInitialCondition *IC=FDMExec->GetIC();
208   if ( ! IC->Load( initialize )) {
209     cerr << "Initialization unsuccessful" << endl;
210     exit(-1);
211   }
212
213   return true;
214 }
215
216 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217
218 bool FGScript::RunScript(void)
219 {
220   vector <struct condition>::iterator iC = Conditions.begin();
221   bool truth = false;
222   bool WholeTruth = false;
223   unsigned i;
224
225   double currentTime = State->Getsim_time();
226   double newSetValue = 0;
227
228   if (currentTime > EndTime) return false;
229
230   while (iC < Conditions.end()) {
231     // determine whether the set of conditional tests for this condition equate
232     // to true
233     for (i=0; i<iC->TestValue.size(); i++) {
234            if (iC->Comparison[i] == "lt")
235               truth = iC->TestParam[i]->getDoubleValue() <  iC->TestValue[i];
236       else if (iC->Comparison[i] == "le")
237               truth = iC->TestParam[i]->getDoubleValue() <= iC->TestValue[i];
238       else if (iC->Comparison[i] == "eq")
239               truth = iC->TestParam[i]->getDoubleValue() == iC->TestValue[i];
240       else if (iC->Comparison[i] == "ge")
241               truth = iC->TestParam[i]->getDoubleValue() >= iC->TestValue[i];
242       else if (iC->Comparison[i] == "gt")
243               truth = iC->TestParam[i]->getDoubleValue() >  iC->TestValue[i];
244       else if (iC->Comparison[i] == "ne")
245               truth = iC->TestParam[i]->getDoubleValue() != iC->TestValue[i];
246       else
247               cerr << "Bad comparison" << endl;
248
249       if (i == 0) WholeTruth = truth;
250       else        WholeTruth = WholeTruth && truth;
251
252       if (!truth && iC->Persistent[i] && iC->Triggered[i]) iC->Triggered[i] = false;
253     }
254
255     // if the conditions are true, do the setting of the desired parameters
256
257     if (WholeTruth) {
258       for (i=0; i<iC->SetValue.size(); i++) {
259         if ( ! iC->Triggered[i]) {
260           iC->OriginalValue[i] = iC->SetParam[i]->getDoubleValue();
261           switch (iC->Type[i]) {
262           case FG_VALUE:
263             iC->newValue[i] = iC->SetValue[i];
264             break;
265           case FG_DELTA:
266             iC->newValue[i] = iC->OriginalValue[i] + iC->SetValue[i];
267             break;
268           case FG_BOOL:
269             iC->newValue[i] = iC->SetValue[i];
270             break;
271           default:
272             cerr << "Invalid Type specified" << endl;
273             break;
274           }
275           iC->Triggered[i] = true;
276           iC->StartTime[i] = currentTime;
277         }
278
279         switch (iC->Action[i]) {
280         case FG_RAMP:
281         newSetValue = (currentTime - iC->StartTime[i])/(iC->TC[i])
282                       * (iC->newValue[i] - iC->OriginalValue[i]) + iC->OriginalValue[i];
283           if (newSetValue > iC->newValue[i]) newSetValue = iC->newValue[i];
284           break;
285         case FG_STEP:
286           newSetValue = iC->newValue[i];
287           break;
288         case FG_EXP:
289           newSetValue = (1 - exp(-(currentTime - iC->StartTime[i])/(iC->TC[i])))
290               * (iC->newValue[i] - iC->OriginalValue[i]) + iC->OriginalValue[i];
291           break;
292         default:
293           cerr << "Invalid Action specified" << endl;
294           break;
295         }
296         iC->SetParam[i]->setDoubleValue(newSetValue);
297       }
298     }
299     iC++;
300   }
301   return true;
302 }
303
304 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
305 //    The bitmasked value choices are as follows:
306 //    unset: In this case (the default) JSBSim would only print
307 //       out the normally expected messages, essentially echoing
308 //       the config files as they are read. If the environment
309 //       variable is not set, debug_lvl is set to 1 internally
310 //    0: This requests JSBSim not to output any messages
311 //       whatsoever.
312 //    1: This value explicity requests the normal JSBSim
313 //       startup messages
314 //    2: This value asks for a message to be printed out when
315 //       a class is instantiated
316 //    4: When this value is set, a message is displayed when a
317 //       FGModel object executes its Run() method
318 //    8: When this value is set, various runtime state variables
319 //       are printed out periodically
320 //    16: When set various parameters are sanity checked and
321 //       a message is printed out when they go out of bounds
322
323 void FGScript::Debug(int from)
324 {
325   unsigned int i;
326
327   if (debug_lvl <= 0) return;
328
329   if (debug_lvl & 1) { // Standard console startup message output
330     if (from == 0) { // Constructor
331     } else if (from == 3) {
332     } else if (from == 4)  { // print out script data
333       vector <struct condition>::iterator iterConditions = Conditions.begin();
334       int count=0;
335
336       cout << "\n  Script goes from " << StartTime << " to " << EndTime
337            << " with dt = " << State->Getdt() << endl << endl;
338
339       while (iterConditions < Conditions.end()) {
340         cout << "  Condition: " << count++ << endl;
341         cout << "    if (";
342
343         for (i=0; i<iterConditions->TestValue.size(); i++) {
344           if (i>0) cout << " and" << endl << "        ";
345           cout << "(" << iterConditions->TestParam[i]->GetName()
346                       << " " << iterConditions->Comparison[i] << " "
347                       << iterConditions->TestValue[i] << ")";
348         }
349         cout << ") then {";
350
351         for (i=0; i<iterConditions->SetValue.size(); i++) {
352           cout << endl << "      set " << iterConditions->SetParam[i]->GetName()
353                << " to " << iterConditions->SetValue[i];
354
355           switch (iterConditions->Type[i]) {
356           case FG_VALUE:
357             cout << " (constant";
358             break;
359           case FG_DELTA:
360             cout << " (delta";
361             break;
362           case FG_BOOL:
363             cout << " (boolean";
364             break;
365           default:
366             cout << " (unspecified type";
367           }
368
369           switch (iterConditions->Action[i]) {
370           case FG_RAMP:
371             cout << " via ramp";
372             break;
373           case FG_STEP:
374             cout << " via step";
375             break;
376           case FG_EXP:
377             cout << " via exponential approach";
378             break;
379           default:
380             cout << " via unspecified action";
381           }
382
383           if (!iterConditions->Persistent[i]) cout << endl
384                              << "                              once";
385           else cout << endl
386                              << "                              repeatedly";
387
388           if (iterConditions->Action[i] == FG_RAMP ||
389               iterConditions->Action[i] == FG_EXP) cout << endl
390                              << "                              with time constant "
391                              << iterConditions->TC[i];
392         }
393         cout << ")" << endl << "    }" << endl << endl;
394
395         iterConditions++;
396       }
397
398       cout << endl;
399     }
400   }
401   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
402     if (from == 0) cout << "Instantiated: FGScript" << endl;
403     if (from == 1) cout << "Destroyed:    FGScript" << endl;
404   }
405   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
406   }
407   if (debug_lvl & 8 ) { // Runtime state variables
408   }
409   if (debug_lvl & 16) { // Sanity checking
410   }
411   if (debug_lvl & 64) {
412     if (from == 0) { // Constructor
413       cout << IdSrc << endl;
414       cout << IdHdr << endl;
415     }
416   }
417 }
418