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