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