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