FlightGear next
FGScript.cpp
Go to the documentation of this file.
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 (jon@jsbsim.org) -------------
9
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free
12 Software Foundation; either version 2 of the License, or (at your option) any
13 later 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 Lesser General Public License for more
18 details.
19
20 You should have received a copy of the GNU Lesser General Public License along
21 with this program; if not, write to the Free Software Foundation, Inc., 59
22 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 Further information about the GNU Lesser General Public License can also be
25 found on the world wide web at http://www.gnu.org.
26
27FUNCTIONAL DESCRIPTION
28--------------------------------------------------------------------------------
29
30This class wraps up the simulation scripting routines.
31
32HISTORY
33--------------------------------------------------------------------------------
3412/21/01 JSB Created
35
36%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37COMMENTS, REFERENCES, and NOTES
38%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39
40%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41INCLUDES
42%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
43
44#include <iomanip>
45
46#include "FGScript.h"
47#include "FGFDMExec.h"
50#include "models/FGInput.h"
51#include "math/FGCondition.h"
53
54using namespace std;
55
56namespace JSBSim {
57
58/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
59CLASS IMPLEMENTATION
60%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
61
62// Constructor
63
64FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
65{
66 PropertyManager=FDMExec->GetPropertyManager();
67
68 Debug(0);
69}
70
71//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72
74{
75 unsigned int i, j;
76
77 for (i=0; i<Events.size(); i++) {
78 delete Events[i].Condition;
79 for (j=0; j<Events[i].Functions.size(); j++)
80 delete Events[i].Functions[j];
81 for (j=0; j<Events[i].NotifyProperties.size(); j++)
82 delete Events[i].NotifyProperties[j];
83 }
84 Events.clear();
85
86 Debug(1);
87}
88
89//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90
91bool FGScript::LoadScript(const SGPath& script, double default_dT,
92 const SGPath& initfile)
93{
94 SGPath initialize;
95 string aircraft="", prop_name="";
96 string notifyPropertyName="";
97 Element *element=0, *run_element=0, *event_element=0;
98 Element *set_element=0;
99 Element *notify_element = 0L, *notify_property_element = 0L;
100 double dt = 0.0, value = 0.0;
101 FGCondition *newCondition;
102
103 FGXMLFileRead XMLFileRead;
104 Element* document = XMLFileRead.LoadXMLDocument(script);
105
106 if (!document) {
107 cerr << "File: " << script << " could not be loaded." << endl;
108 return false;
109 }
110
111 if (document->GetName() != string("runscript")) {
112 cerr << "File: " << script << " is not a script file" << endl;
113 return false;
114 }
115
116 ScriptName = document->GetAttributeValue("name");
117
118 // First, find "run" element and set delta T
119
120 run_element = document->FindElement("run");
121
122 if (!run_element) {
123 cerr << "No \"run\" element found in script." << endl;
124 return false;
125 }
126
127 // Set sim timing
128
129 if (run_element->HasAttribute("start"))
130 StartTime = run_element->GetAttributeValueAsNumber("start");
131 else
132 StartTime = 0.0;
133 FDMExec->Setsim_time(StartTime);
134 if (run_element->HasAttribute("end")) {
135 EndTime = run_element->GetAttributeValueAsNumber("end");
136 } else {
137 cerr << "An end time (duration) for the script must be specified in the script <run> element." << endl;
138 return false;
139 }
140
141 if (default_dT == 0.0)
142 dt = run_element->GetAttributeValueAsNumber("dt");
143 else {
144 dt = default_dT;
145 cout << endl << "Overriding simulation step size from the command line. New step size is: "
146 << default_dT << " seconds (" << 1/default_dT << " Hz)" << endl << endl;
147 }
148
149 FDMExec->Setdt(dt);
150
151 // Make sure that the desired time is reached and executed.
152 EndTime += 0.99*FDMExec->GetDeltaT();
153
154 // read aircraft and initialization files
155
156 element = document->FindElement("use");
157 if (element) {
158 aircraft = element->GetAttributeValue("aircraft");
159 if (!aircraft.empty()) {
160 if (!FDMExec->LoadModel(aircraft))
161 return false;
162 } else {
163 cerr << "Aircraft must be specified in use element." << endl;
164 return false;
165 }
166
167 initialize = SGPath::fromLocal8Bit(element->GetAttributeValue("initialize").c_str());
168 if (initfile.isNull()) {
169 if (initialize.isNull()) {
170 cerr << "Initialization file must be specified in use element." << endl;
171 return false;
172 }
173 } else {
174 cout << endl << "The initialization file specified in the script file ("
175 << initialize << ") has been overridden with a specified file ("
176 << initfile << ")." << endl;
177 initialize = initfile;
178 }
179
180 } else {
181 cerr << "No \"use\" directives in the script file." << endl;
182 return false;
183 }
184
185 FGInitialCondition *IC=FDMExec->GetIC();
186 if ( ! IC->Load( initialize )) {
187 cerr << "Initialization unsuccessful" << endl;
188 return false;
189 }
190
191 // Now, read input spec if given.
192 element = document->FindElement("input");
193 while (element) {
194 if (!FDMExec->GetInput()->Load(element))
195 return false;
196
197 element = document->FindNextElement("input");
198 }
199
200 // Now, read output spec if given.
201 element = document->FindElement("output");
202 SGPath scriptDir = SGPath(script.dir());
203 if (scriptDir.isNull())
204 scriptDir = SGPath(".");
205
206 while (element) {
207 if (!FDMExec->GetOutput()->Load(element, scriptDir))
208 return false;
209
210 element = document->FindNextElement("output");
211 }
212
213 // Read local property/value declarations
214 int saved_debug_lvl = debug_lvl;
215 debug_lvl = 0; // Disable messages
216 LocalProperties.Load(run_element, PropertyManager, true);
217 debug_lvl = saved_debug_lvl;
218
219 // Read "events" from script
220
221 event_element = run_element->FindElement("event");
222 while (event_element) { // event processing
223
224 // Create the event structure
225 struct event *newEvent = new struct event();
226
227 // Retrieve the event name if given
228 newEvent->Name = event_element->GetAttributeValue("name");
229
230 // Is this event persistent? That is, does it execute every time the
231 // condition triggers to true, or does it execute as a one-shot event, only?
232 if (event_element->GetAttributeValue("persistent") == string("true")) {
233 newEvent->Persistent = true;
234 }
235
236 // Does this event execute continuously when triggered to true?
237 if (event_element->GetAttributeValue("continuous") == string("true")) {
238 newEvent->Continuous = true;
239 }
240
241 // Process the conditions
242 Element* condition_element = event_element->FindElement("condition");
243 if (condition_element != 0) {
244 try {
245 newCondition = new FGCondition(condition_element, PropertyManager);
246 } catch(string& str) {
247 cout << endl << fgred << str << reset << endl << endl;
248 delete newEvent;
249 return false;
250 }
251 newEvent->Condition = newCondition;
252 } else {
253 cerr << "No condition specified in script event " << newEvent->Name
254 << endl;
255 delete newEvent;
256 return false;
257 }
258
259 // Is there a delay between the time this event is triggered, and when the
260 // event actions are executed?
261
262 Element* delay_element = event_element->FindElement("delay");
263 if (delay_element)
264 newEvent->Delay = event_element->FindElementValueAsNumber("delay");
265 else
266 newEvent->Delay = 0.0;
267
268 // Notify about when this event is triggered?
269 if ((notify_element = event_element->FindElement("notify")) != 0) {
270 if (notify_element->HasAttribute("format")) {
271 if (notify_element->GetAttributeValue("format") == "kml") newEvent->NotifyKML = true;
272 }
273 newEvent->Notify = true;
274 // Check here for new <description> tag that gets echoed
275 string notify_description = notify_element->FindElementValue("description");
276 if (!notify_description.empty()) {
277 newEvent->Description = notify_description;
278 }
279 notify_property_element = notify_element->FindElement("property");
280 while (notify_property_element) {
281 notifyPropertyName = notify_property_element->GetDataLine();
282
283 if (notify_property_element->HasAttribute("apply")) {
284 string function_str = notify_property_element->GetAttributeValue("apply");
285 FGTemplateFunc* f = FDMExec->GetTemplateFunc(function_str);
286 if (f)
287 newEvent->NotifyProperties.push_back(new FGFunctionValue(notifyPropertyName, PropertyManager, f));
288 else {
289 cerr << notify_property_element->ReadFrom()
290 << fgred << highint << " No function by the name "
291 << function_str << " has been defined. This property will "
292 << "not be logged. You should check your configuration file."
293 << reset << endl;
294 }
295 }
296 else
297 newEvent->NotifyProperties.push_back(new FGPropertyValue(notifyPropertyName, PropertyManager));
298
299 string caption_attribute = notify_property_element->GetAttributeValue("caption");
300 if (caption_attribute.empty()) {
301 newEvent->DisplayString.push_back(notifyPropertyName);
302 } else {
303 newEvent->DisplayString.push_back(caption_attribute);
304 }
305
306 notify_property_element = notify_element->FindNextElement("property");
307 }
308 }
309
310 // Read set definitions (these define the actions to be taken when the event
311 // is triggered).
312 set_element = event_element->FindElement("set");
313 while (set_element) {
314 prop_name = set_element->GetAttributeValue("name");
315 if (PropertyManager->HasNode(prop_name)) {
316 newEvent->SetParam.push_back( PropertyManager->GetNode(prop_name) );
317 } else {
318 newEvent->SetParam.push_back( 0L );
319 }
320 newEvent->SetParamName.push_back( prop_name );
321
322 // Todo - should probably do some safety checking here to make sure one or
323 // the other of value or function is specified.
324 if (!set_element->GetAttributeValue("value").empty()) {
325 value = set_element->GetAttributeValueAsNumber("value");
326 newEvent->Functions.push_back(nullptr);
327 } else if (set_element->FindElement("function")) {
328 value = 0.0;
329 newEvent->Functions.push_back(new FGFunction(FDMExec, set_element->FindElement("function")));
330 }
331 newEvent->SetValue.push_back(value);
332 newEvent->OriginalValue.push_back(0.0);
333 newEvent->newValue.push_back(0.0);
334 newEvent->ValueSpan.push_back(0.0);
335 string tempCompare = set_element->GetAttributeValue("type");
336 if (to_lower(tempCompare).find("delta") != string::npos) newEvent->Type.push_back(FG_DELTA);
337 else if (to_lower(tempCompare).find("bool") != string::npos) newEvent->Type.push_back(FG_BOOL);
338 else if (to_lower(tempCompare).find("value") != string::npos) newEvent->Type.push_back(FG_VALUE);
339 else newEvent->Type.push_back(FG_VALUE); // DEFAULT
340 tempCompare = set_element->GetAttributeValue("action");
341 if (to_lower(tempCompare).find("ramp") != string::npos) newEvent->Action.push_back(FG_RAMP);
342 else if (to_lower(tempCompare).find("step") != string::npos) newEvent->Action.push_back(FG_STEP);
343 else if (to_lower(tempCompare).find("exp") != string::npos) newEvent->Action.push_back(FG_EXP);
344 else newEvent->Action.push_back(FG_STEP); // DEFAULT
345
346 if (!set_element->GetAttributeValue("tc").empty())
347 newEvent->TC.push_back(set_element->GetAttributeValueAsNumber("tc"));
348 else
349 newEvent->TC.push_back(1.0); // DEFAULT
350
351 newEvent->Transiting.push_back(false);
352
353 set_element = event_element->FindNextElement("set");
354 }
355 Events.push_back(*newEvent);
356 delete newEvent;
357
358 event_element = run_element->FindNextElement("event");
359 }
360
361 Debug(4);
362
363 return true;
364}
365
366//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
367
369{
370 LocalProperties.ResetToIC();
371 FDMExec->Setsim_time(StartTime);
372
373 for (unsigned int i=0; i<Events.size(); i++)
374 Events[i].reset();
375}
376
377//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378
380{
381 unsigned i, j;
382 unsigned event_ctr = 0;
383
384 double currentTime = FDMExec->GetSimTime();
385 double newSetValue = 0;
386
387 if (currentTime > EndTime) return false;
388
389 // Iterate over all events.
390 for (unsigned int ev_ctr=0; ev_ctr < Events.size(); ev_ctr++) {
391
392 struct event &thisEvent = Events[ev_ctr];
393
394 // Determine whether the set of conditional tests for this condition equate
395 // to true and should cause the event to execute. If the conditions evaluate
396 // to true, then the event is triggered. If the event is not persistent,
397 // then this trigger will remain set true. If the event is persistent, the
398 // trigger will reset to false when the condition evaluates to false.
399 if (thisEvent.Condition->Evaluate()) {
400 if (!thisEvent.Triggered) {
401
402 // The conditions are true, do the setting of the desired Event
403 // parameters
404 for (i=0; i<thisEvent.SetValue.size(); i++) {
405 if (thisEvent.SetParam[i] == 0L) { // Late bind property if necessary
406 if (PropertyManager->HasNode(thisEvent.SetParamName[i])) {
407 thisEvent.SetParam[i] = PropertyManager->GetNode(thisEvent.SetParamName[i]);
408 } else {
409 throw("No property, \""+thisEvent.SetParamName[i]+"\" is defined.");
410 }
411 }
412 thisEvent.OriginalValue[i] = thisEvent.SetParam[i]->getDoubleValue();
413 if (thisEvent.Functions[i] != 0) { // Parameter should be set to a function value
414 try {
415 thisEvent.SetValue[i] = thisEvent.Functions[i]->GetValue();
416 } catch (string& msg) {
417 std::cerr << std::endl << "A problem occurred in the execution of the script. " << msg << endl;
418 throw;
419 }
420 }
421 switch (thisEvent.Type[i]) {
422 case FG_VALUE:
423 case FG_BOOL:
424 thisEvent.newValue[i] = thisEvent.SetValue[i];
425 break;
426 case FG_DELTA:
427 thisEvent.newValue[i] = thisEvent.OriginalValue[i] + thisEvent.SetValue[i];
428 break;
429 default:
430 cerr << "Invalid Type specified" << endl;
431 break;
432 }
433 thisEvent.StartTime = currentTime + thisEvent.Delay;
434 thisEvent.ValueSpan[i] = thisEvent.newValue[i] - thisEvent.OriginalValue[i];
435 thisEvent.Transiting[i] = true;
436 }
437 }
438 thisEvent.Triggered = true;
439
440 } else if (thisEvent.Persistent) { // If the event is persistent, reset the trigger.
441 thisEvent.Triggered = false; // Reset the trigger for persistent events
442 thisEvent.Notified = false; // Also reset the notification flag
443 } else if (thisEvent.Continuous) { // If the event is continuous, reset the trigger.
444 thisEvent.Triggered = false; // Reset the trigger for persistent events
445 thisEvent.Notified = false; // Also reset the notification flag
446 }
447
448 if ((currentTime >= thisEvent.StartTime) && thisEvent.Triggered) {
449
450 for (i=0; i<thisEvent.SetValue.size(); i++) {
451 if (thisEvent.Transiting[i]) {
452 thisEvent.TimeSpan = currentTime - thisEvent.StartTime;
453 switch (thisEvent.Action[i]) {
454 case FG_RAMP:
455 if (thisEvent.TimeSpan <= thisEvent.TC[i]) {
456 newSetValue = thisEvent.TimeSpan/thisEvent.TC[i] * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
457 } else {
458 newSetValue = thisEvent.newValue[i];
459 if (thisEvent.Continuous != true) thisEvent.Transiting[i] = false;
460 }
461 break;
462 case FG_STEP:
463 newSetValue = thisEvent.newValue[i];
464
465 // If this is not a continuous event, reset the transiting flag.
466 // Otherwise, it is known that the event is a continuous event.
467 // Furthermore, if the event is to be determined by a function,
468 // then the function will be continuously calculated.
469 if (thisEvent.Continuous != true)
470 thisEvent.Transiting[i] = false;
471 else if (thisEvent.Functions[i] != 0)
472 newSetValue = thisEvent.Functions[i]->GetValue();
473
474 break;
475 case FG_EXP:
476 newSetValue = (1 - exp( -thisEvent.TimeSpan/thisEvent.TC[i] )) * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
477 break;
478 default:
479 cerr << "Invalid Action specified" << endl;
480 break;
481 }
482 thisEvent.SetParam[i]->setDoubleValue(newSetValue);
483 }
484 }
485
486 // Print notification values after setting them
487 if (thisEvent.Notify && !thisEvent.Notified) {
488 if (thisEvent.NotifyKML) {
489 cout << endl << "<Placemark>" << endl;
490 cout << " <name> " << currentTime << " seconds" << " </name>"
491 << endl;
492 cout << " <description>" << endl;
493 cout << " <![CDATA[" << endl;
494 cout << " <b>" << thisEvent.Name << " (Event " << event_ctr << ")"
495 << " executed at time: " << currentTime << "</b><br/>" << endl;
496 } else {
497 cout << endl << underon
498 << highint << thisEvent.Name << normint << underoff
499 << " (Event " << event_ctr << ")"
500 << " executed at time: " << highint << currentTime << normint
501 << endl;
502 }
503 if (!thisEvent.Description.empty()) {
504 cout << " " << thisEvent.Description << endl;
505 }
506 for (j=0; j<thisEvent.NotifyProperties.size();j++) {
507 cout << " " << thisEvent.DisplayString[j] << " = "
508 << thisEvent.NotifyProperties[j]->getDoubleValue();
509 if (thisEvent.NotifyKML) cout << " <br/>";
510 cout << endl;
511 }
512 if (thisEvent.NotifyKML) {
513 cout << " ]]>" << endl;
514 cout << " </description>" << endl;
515 cout << " <Point>" << endl;
516 cout << " <altitudeMode> absolute </altitudeMode>" << endl;
517 cout << " <extrude> 1 </extrude>" << endl;
518 cout << " <coordinates>"
519 << FDMExec->GetPropagate()->GetLongitudeDeg() << ","
520 << FDMExec->GetPropagate()->GetGeodLatitudeDeg() << ","
521 << FDMExec->GetPropagate()->GetAltitudeASLmeters()
522 << "</coordinates>" << endl;
523 cout << " </Point>" << endl;
524 cout << "</Placemark>" << endl;
525 }
526 cout << endl;
527 thisEvent.Notified = true;
528 }
529
530 }
531
532 event_ctr++;
533 }
534 return true;
535}
536
537//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
538// The bitmasked value choices are as follows:
539// unset: In this case (the default) JSBSim would only print
540// out the normally expected messages, essentially echoing
541// the config files as they are read. If the environment
542// variable is not set, debug_lvl is set to 1 internally
543// 0: This requests JSBSim not to output any messages
544// whatsoever.
545// 1: This value explicity requests the normal JSBSim
546// startup messages
547// 2: This value asks for a message to be printed out when
548// a class is instantiated
549// 4: When this value is set, a message is displayed when a
550// FGModel object executes its Run() method
551// 8: When this value is set, various runtime state variables
552// are printed out periodically
553// 16: When set various parameters are sanity checked and
554// a message is printed out when they go out of bounds
555
556void FGScript::Debug(int from)
557{
558 if (debug_lvl <= 0) return;
559
560 if (debug_lvl & 1) { // Standard console startup message output
561 if (from == 0) { // Constructor
562 } else if (from == 3) {
563 } else if (from == 4) { // print out script data
564 cout << endl;
565 cout << "Script: \"" << ScriptName << "\"" << endl;
566 cout << " begins at " << StartTime << " seconds and runs to " << EndTime
567 << " seconds with dt = " << setprecision(6) << FDMExec->GetDeltaT()
568 << " (" << ceil(1.0/FDMExec->GetDeltaT()) << " Hz)" << endl;
569 cout << endl;
570
571 for (auto node: LocalProperties) {
572 cout << "Local property: " << node->GetName()
573 << " = " << node->getDoubleValue()
574 << endl;
575 }
576
577 if (LocalProperties.empty()) cout << endl;
578
579 for (unsigned i=0; i<Events.size(); i++) {
580 cout << "Event " << i;
581 if (!Events[i].Name.empty()) cout << " (" << Events[i].Name << ")";
582 cout << ":" << endl;
583
584 if (Events[i].Persistent)
585 cout << " " << "Whenever triggered, executes once";
586 else if (Events[i].Continuous)
587 cout << " " << "While true, always executes";
588 else
589 cout << " " << "When first triggered, executes once";
590
591 Events[i].Condition->PrintCondition();
592
593 cout << endl << " Actions taken";
594 if (Events[i].Delay > 0.0)
595 cout << " (after a delay of " << Events[i].Delay << " secs)";
596 cout << ":" << endl << " {";
597 for (unsigned j=0; j<Events[i].SetValue.size(); j++) {
598 if (Events[i].SetValue[j] == 0.0 && Events[i].Functions[j] != 0L) {
599 if (Events[i].SetParam[j] == 0) {
600 if (Events[i].SetParamName[j].empty()) {
601 stringstream s;
602 s << " An attempt has been made to access a non-existent property" << endl
603 << " in this event. Please check the property names used, spelling, etc.";
604 cerr << fgred << highint << endl << s.str() << reset << endl;
605 throw BaseException(s.str());
606 } else {
607 cout << endl << " set " << Events[i].SetParamName[j]
608 << " to function value (Late Bound)";
609 }
610 } else {
611 cout << endl << " set "
612 << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
613 << " to function value";
614 }
615 } else {
616 if (Events[i].SetParam[j] == 0) {
617 if (Events[i].SetParamName[j].empty()) {
618 stringstream s;
619 s << " An attempt has been made to access a non-existent property" << endl
620 << " in this event. Please check the property names used, spelling, etc.";
621 cerr << fgred << highint << endl << s.str() << reset << endl;
622 throw BaseException(s.str());
623 } else {
624 cout << endl << " set " << Events[i].SetParamName[j]
625 << " to function value (Late Bound)";
626 }
627 } else {
628 cout << endl << " set "
629 << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
630 << " to " << Events[i].SetValue[j];
631 }
632 }
633
634 switch (Events[i].Type[j]) {
635 case FG_VALUE:
636 case FG_BOOL:
637 cout << " (constant";
638 break;
639 case FG_DELTA:
640 cout << " (delta";
641 break;
642 default:
643 cout << " (unspecified type";
644 }
645
646 switch (Events[i].Action[j]) {
647 case FG_RAMP:
648 cout << " via ramp";
649 break;
650 case FG_STEP:
651 cout << " via step)";
652 break;
653 case FG_EXP:
654 cout << " via exponential approach";
655 break;
656 default:
657 cout << " via unspecified action)";
658 }
659
660 if (Events[i].Action[j] == FG_RAMP || Events[i].Action[j] == FG_EXP)
661 cout << " with time constant " << Events[i].TC[j] << ")";
662 }
663 cout << endl << " }" << endl;
664
665 // Print notifications
666 if (Events[i].Notify) {
667 if (Events[i].NotifyProperties.size() > 0) {
668 if (Events[i].NotifyKML) {
669 cout << " Notifications (KML Format):" << endl << " {"
670 << endl;
671 } else {
672 cout << " Notifications:" << endl << " {" << endl;
673 }
674 for (unsigned j=0; j<Events[i].NotifyProperties.size();j++) {
675 cout << " "
676 << Events[i].NotifyProperties[j]->GetPrintableName()
677 << endl;
678 }
679 cout << " }" << endl;
680 }
681 }
682 cout << endl;
683 }
684 }
685 }
686 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
687 if (from == 0) cout << "Instantiated: FGScript" << endl;
688 if (from == 1) cout << "Destroyed: FGScript" << endl;
689 }
690 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
691 }
692 if (debug_lvl & 8 ) { // Runtime state variables
693 }
694 if (debug_lvl & 16) { // Sanity checking
695 }
696 if (debug_lvl & 64) {
697 if (from == 0) { // Constructor
698 }
699 }
700}
701}
JSBSim::FGFDMExec * FDMExec
Definition JSBSim.cpp:88
SGPath ScriptName
Definition JSBSim.cpp:81
#define i(x)
const std::string & GetName(void) const
Retrieves the element name.
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
std::string FindElementValue(const std::string &el="")
Searches for the named element and returns the string data belonging to it.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
Element * FindElement(const std::string &el="")
Searches for a specified element.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
Encapsulates a condition, which is used in parts of JSBSim including switches.
Definition FGCondition.h:67
Represents a property value on which a function is applied.
Represents a mathematical function.
Definition FGFunction.h:753
bool Load(const SGPath &rstname, bool useStoredPath=true)
Loads the initial conditions.
static char highint[5]
highlights text
Definition FGJSBBase.h:123
static char reset[5]
resets text properties
Definition FGJSBBase.h:129
static char normint[6]
normal intensity text
Definition FGJSBBase.h:127
static char fgred[6]
red text
Definition FGJSBBase.h:139
static char underoff[6]
underline off
Definition FGJSBBase.h:133
static short debug_lvl
Definition FGJSBBase.h:190
static char underon[5]
underlines text
Definition FGJSBBase.h:131
Represents a property value which can use late binding.
bool LoadScript(const SGPath &script, double default_dT, const SGPath &initfile)
Loads a script to drive JSBSim (usually in standalone mode).
Definition FGScript.cpp:91
void ResetEvents(void)
Definition FGScript.cpp:368
~FGScript()
Default destructor.
Definition FGScript.cpp:73
bool RunScript(void)
This function is called each pass through the executive Run() method IF scripting is enabled.
Definition FGScript.cpp:379
FGScript(FGFDMExec *exec)
Default constructor.
Definition FGScript.cpp:64
Element * LoadXMLDocument(const SGPath &XML_filename, bool verbose=true)
short debug_lvl
std::string & to_lower(std::string &str)