47 #include "FGFDMExec.h"
48 #include "input_output/FGXMLFileRead.h"
49 #include "initialization/FGInitialCondition.h"
50 #include "models/FGInput.h"
51 #include "math/FGCondition.h"
52 #include "math/FGFunctionValue.h"
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];
92 const SGPath& initfile)
95 string aircraft=
"", prop_name=
"";
96 string notifyPropertyName=
"";
97 Element *element=0, *run_element=0, *event_element=0;
99 Element *notify_element = 0L, *notify_property_element = 0L;
100 double dt = 0.0, value = 0.0;
104 Element* document = XMLFileRead.LoadXMLDocument(script);
107 cerr <<
"File: " << script <<
" could not be loaded." << endl;
111 if (document->
GetName() !=
string(
"runscript")) {
112 cerr <<
"File: " << script <<
" is not a script file" << endl;
123 cerr <<
"No \"run\" element found in script." << endl;
129 if (run_element->HasAttribute(
"start"))
130 StartTime = run_element->GetAttributeValueAsNumber(
"start");
134 if (run_element->HasAttribute(
"end")) {
135 EndTime = run_element->GetAttributeValueAsNumber(
"end");
137 cerr <<
"An end time (duration) for the script must be specified in the script <run> element." << endl;
141 if (default_dT == 0.0)
142 dt = run_element->GetAttributeValueAsNumber(
"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;
159 if (!aircraft.empty()) {
163 cerr <<
"Aircraft must be specified in use element." << endl;
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;
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;
181 cerr <<
"No \"use\" directives in the script file." << endl;
186 if ( ! IC->
Load( initialize )) {
187 cerr <<
"Initialization unsuccessful" << endl;
202 SGPath scriptDir = SGPath(script.dir());
203 if (scriptDir.isNull())
204 scriptDir = SGPath(
".");
214 int saved_debug_lvl = debug_lvl;
216 LocalProperties.Load(run_element, PropertyManager,
true);
217 debug_lvl = saved_debug_lvl;
221 event_element = run_element->FindElement(
"event");
222 while (event_element) {
225 struct event *newEvent =
new struct event();
228 newEvent->Name = event_element->GetAttributeValue(
"name");
232 if (event_element->GetAttributeValue(
"persistent") ==
string(
"true")) {
233 newEvent->Persistent =
true;
237 if (event_element->GetAttributeValue(
"continuous") ==
string(
"true")) {
238 newEvent->Continuous =
true;
243 if (condition_element != 0) {
245 newCondition =
new FGCondition(condition_element, PropertyManager);
246 }
catch(
string& str) {
247 cout << endl <<
fgred << str <<
reset << endl << endl;
251 newEvent->Condition = newCondition;
253 cerr <<
"No condition specified in script event " << newEvent->Name
266 newEvent->Delay = 0.0;
269 if ((notify_element = event_element->
FindElement(
"notify")) != 0) {
271 if (notify_element->
GetAttributeValue(
"format") ==
"kml") newEvent->NotifyKML =
true;
273 newEvent->Notify =
true;
275 string notify_description = notify_element->
FindElementValue(
"description");
276 if (!notify_description.empty()) {
277 newEvent->Description = notify_description;
279 notify_property_element = notify_element->
FindElement(
"property");
280 while (notify_property_element) {
281 notifyPropertyName = notify_property_element->
GetDataLine();
283 if (notify_property_element->HasAttribute(
"apply")) {
284 string function_str = notify_property_element->GetAttributeValue(
"apply");
287 newEvent->NotifyProperties.push_back(
new FGFunctionValue(notifyPropertyName, PropertyManager, f));
289 cerr << notify_property_element->ReadFrom()
291 << function_str <<
" has been defined. This property will "
292 <<
"not be logged. You should check your configuration file."
297 newEvent->NotifyProperties.push_back(
new FGPropertyValue(notifyPropertyName, PropertyManager));
299 string caption_attribute = notify_property_element->GetAttributeValue(
"caption");
300 if (caption_attribute.empty()) {
301 newEvent->DisplayString.push_back(notifyPropertyName);
303 newEvent->DisplayString.push_back(caption_attribute);
313 while (set_element) {
315 if (PropertyManager->HasNode(prop_name)) {
316 newEvent->SetParam.push_back( PropertyManager->GetNode(prop_name) );
318 newEvent->SetParam.push_back( 0L );
320 newEvent->SetParamName.push_back( prop_name );
326 newEvent->Functions.push_back(
nullptr);
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);
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);
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);
349 newEvent->TC.push_back(1.0);
351 newEvent->Transiting.push_back(
false);
355 Events.push_back(*newEvent);
358 event_element = run_element->FindNextElement(
"event");
368 void FGScript::ResetEvents(
void)
370 LocalProperties.ResetToIC();
373 for (
unsigned int i=0; i<Events.size(); i++)
382 unsigned event_ctr = 0;
385 double newSetValue = 0;
387 if (currentTime > EndTime)
return false;
390 for (
unsigned int ev_ctr=0; ev_ctr < Events.size(); ev_ctr++) {
392 struct event &thisEvent = Events[ev_ctr];
399 if (thisEvent.Condition->Evaluate()) {
400 if (!thisEvent.Triggered) {
404 for (i=0; i<thisEvent.SetValue.size(); i++) {
405 if (thisEvent.SetParam[i] == 0L) {
406 if (PropertyManager->HasNode(thisEvent.SetParamName[i])) {
407 thisEvent.SetParam[i] = PropertyManager->GetNode(thisEvent.SetParamName[i]);
409 throw(
"No property, \""+thisEvent.SetParamName[i]+
"\" is defined.");
412 thisEvent.OriginalValue[i] = thisEvent.SetParam[i]->getDoubleValue();
413 if (thisEvent.Functions[i] != 0) {
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;
421 switch (thisEvent.Type[i]) {
424 thisEvent.newValue[i] = thisEvent.SetValue[i];
427 thisEvent.newValue[i] = thisEvent.OriginalValue[i] + thisEvent.SetValue[i];
430 cerr <<
"Invalid Type specified" << endl;
433 thisEvent.StartTime = currentTime + thisEvent.Delay;
434 thisEvent.ValueSpan[i] = thisEvent.newValue[i] - thisEvent.OriginalValue[i];
435 thisEvent.Transiting[i] =
true;
438 thisEvent.Triggered =
true;
440 }
else if (thisEvent.Persistent) {
441 thisEvent.Triggered =
false;
442 thisEvent.Notified =
false;
443 }
else if (thisEvent.Continuous) {
444 thisEvent.Triggered =
false;
445 thisEvent.Notified =
false;
448 if ((currentTime >= thisEvent.StartTime) && thisEvent.Triggered) {
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]) {
455 if (thisEvent.TimeSpan <= thisEvent.TC[i]) {
456 newSetValue = thisEvent.TimeSpan/thisEvent.TC[i] * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
458 newSetValue = thisEvent.newValue[i];
459 if (thisEvent.Continuous !=
true) thisEvent.Transiting[i] =
false;
463 newSetValue = thisEvent.newValue[i];
469 if (thisEvent.Continuous !=
true)
470 thisEvent.Transiting[i] =
false;
471 else if (thisEvent.Functions[i] != 0)
472 newSetValue = thisEvent.Functions[i]->GetValue();
476 newSetValue = (1 - exp( -thisEvent.TimeSpan/thisEvent.TC[i] )) * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
479 cerr <<
"Invalid Action specified" << endl;
482 thisEvent.SetParam[i]->setDoubleValue(newSetValue);
487 if (thisEvent.Notify && !thisEvent.Notified) {
488 if (thisEvent.NotifyKML) {
489 cout << endl <<
"<Placemark>" << endl;
490 cout <<
" <name> " << currentTime <<
" seconds" <<
" </name>"
492 cout <<
" <description>" << endl;
493 cout <<
" <![CDATA[" << endl;
494 cout <<
" <b>" << thisEvent.Name <<
" (Event " << event_ctr <<
")"
495 <<
" executed at time: " << currentTime <<
"</b><br/>" << endl;
499 <<
" (Event " << event_ctr <<
")"
503 if (!thisEvent.Description.empty()) {
504 cout <<
" " << thisEvent.Description << endl;
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/>";
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>"
522 <<
"</coordinates>" << endl;
523 cout <<
" </Point>" << endl;
524 cout <<
"</Placemark>" << endl;
527 thisEvent.Notified =
true;
556 void FGScript::Debug(
int from)
558 if (debug_lvl <= 0)
return;
562 }
else if (from == 3) {
563 }
else if (from == 4) {
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;
571 for (
auto node: LocalProperties) {
572 cout <<
"Local property: " << node->GetName()
573 <<
" = " << node->getDoubleValue()
577 if (LocalProperties.empty()) cout << endl;
579 for (
unsigned i=0; i<Events.size(); i++) {
580 cout <<
"Event " << i;
581 if (!Events[i].Name.empty()) cout <<
" (" << Events[i].Name <<
")";
584 if (Events[i].Persistent)
585 cout <<
" " <<
"Whenever triggered, executes once";
586 else if (Events[i].Continuous)
587 cout <<
" " <<
"While true, always executes";
589 cout <<
" " <<
"When first triggered, executes once";
591 Events[i].Condition->PrintCondition();
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()) {
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.";
605 throw BaseException(s.str());
607 cout << endl <<
" set " << Events[i].SetParamName[j]
608 <<
" to function value (Late Bound)";
611 cout << endl <<
" set "
612 << Events[i].SetParam[j]->GetRelativeName(
"/fdm/jsbsim/")
613 <<
" to function value";
616 if (Events[i].SetParam[j] == 0) {
617 if (Events[i].SetParamName[j].empty()) {
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.";
622 throw BaseException(s.str());
624 cout << endl <<
" set " << Events[i].SetParamName[j]
625 <<
" to function value (Late Bound)";
628 cout << endl <<
" set "
629 << Events[i].SetParam[j]->GetRelativeName(
"/fdm/jsbsim/")
630 <<
" to " << Events[i].SetValue[j];
634 switch (Events[i].Type[j]) {
637 cout <<
" (constant";
643 cout <<
" (unspecified type";
646 switch (Events[i].Action[j]) {
651 cout <<
" via step)";
654 cout <<
" via exponential approach";
657 cout <<
" via unspecified action)";
660 if (Events[i].Action[j] == FG_RAMP || Events[i].Action[j] == FG_EXP)
661 cout <<
" with time constant " << Events[i].TC[j] <<
")";
663 cout << endl <<
" }" << endl;
666 if (Events[i].Notify) {
667 if (Events[i].NotifyProperties.size() > 0) {
668 if (Events[i].NotifyKML) {
669 cout <<
" Notifications (KML Format):" << endl <<
" {"
672 cout <<
" Notifications:" << endl <<
" {" << endl;
674 for (
unsigned j=0; j<Events[i].NotifyProperties.size();j++) {
676 << Events[i].NotifyProperties[j]->GetPrintableName()
679 cout <<
" }" << endl;
686 if (debug_lvl & 2 ) {
687 if (from == 0) cout <<
"Instantiated: FGScript" << endl;
688 if (from == 1) cout <<
"Destroyed: FGScript" << endl;
690 if (debug_lvl & 4 ) {
692 if (debug_lvl & 8 ) {
694 if (debug_lvl & 16) {
696 if (debug_lvl & 64) {