1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module:       FGSwitch.cpp
4  Author:       Jon S. Berndt
5  Date started: 4/2000
6 
7  ------------- Copyright (C) 2000 -------------
8 
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free
11  Software Foundation; either version 2 of the License, or (at your option) any
12  later version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
17  details.
18 
19  You should have received a copy of the GNU Lesser General Public License along
20  with this program; if not, write to the Free Software Foundation, Inc., 59
21  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23  Further information about the GNU Lesser General Public License can also be
24  found on the world wide web at http://www.gnu.org.
25 
26 FUNCTIONAL DESCRIPTION
27 --------------------------------------------------------------------------------
28 
29 HISTORY
30 --------------------------------------------------------------------------------
31 
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 COMMENTS, REFERENCES,  and NOTES
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 
36 The switch component is defined as follows (see the API documentation for more
37 information):
38 
39 @code
40 <switch name="switch1">
41   <default value="{property|value}"/>
42   <test logic="{AND|OR}" value="{property|value}">
43     {property} {conditional} {property|value}
44     <test logic="{AND|OR}">
45       {property} {conditional} {property|value}
46       ...
47     </test>
48     ...
49   </test>
50   <test logic="{AND|OR}" value="{property|value}">
51     {property} {conditional} {property|value}
52     ...
53   </test>
54   ...
55 </switch>
56 @endcode
57 
58 Also, see the header file (FGSwitch.h) for further details.
59 
60 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61 INCLUDES
62 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
63 
64 #include "FGSwitch.h"
65 #include "math/FGCondition.h"
66 
67 using namespace std;
68 
69 namespace JSBSim {
70 
71 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 CLASS IMPLEMENTATION
73 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
74 
FGSwitch(FGFCS * fcs,Element * element)75 FGSwitch::FGSwitch(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
76 {
77   string value;
78   Test *current_test;
79 
80   bind(element); // Bind() this component here in case it is used in its own
81                  // definition for a sample-and-hold
82   Element* test_element = element->FindElement("default");
83   if (test_element) {
84     current_test = new Test;
85     value = test_element->GetAttributeValue("value");
86     current_test->setTestValue(value, Name, PropertyManager);
87     current_test->Default = true;
88     if (delay > 0 && is_number(value)) {        // If there is a delay, initialize the
89       for (unsigned int i=0; i<delay-1; i++) {  // delay buffer to the default value
90         output_array[i] = atof(value.c_str());  // for the switch if that value is a number.
91       }
92     }
93     tests.push_back(current_test);
94   }
95 
96   test_element = element->FindElement("test");
97   while (test_element) {
98     current_test = new Test;
99     current_test->condition = new FGCondition(test_element, PropertyManager);
100     value = test_element->GetAttributeValue("value");
101     current_test->setTestValue(value, Name, PropertyManager);
102     tests.push_back(current_test);
103     test_element = element->FindNextElement("test");
104   }
105 
106   Debug(0);
107 }
108 
109 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 
~FGSwitch()111 FGSwitch::~FGSwitch()
112 {
113   for (auto test: tests) {
114     delete test->condition;
115     delete test;
116   }
117 
118   Debug(1);
119 }
120 
121 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122 
Run(void)123 bool FGSwitch::Run(void )
124 {
125   bool pass = false;
126   double default_output=0.0;
127 
128   // To detect errors early, make sure all conditions and values can be
129   // evaluated in the first time step.
130   if (!initialized) {
131     initialized = true;
132     VerifyProperties();
133   }
134 
135   for (auto test: tests) {
136     if (test->Default) {
137       default_output = test->OutputValue->GetValue();
138     } else {
139       pass = test->condition->Evaluate();
140     }
141 
142     if (pass) {
143       Output = test->OutputValue->GetValue();
144       break;
145     }
146   }
147 
148   if (!pass) Output = default_output;
149 
150   if (delay != 0) Delay();
151   Clip();
152   SetOutput();
153 
154   return true;
155 }
156 
157 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
158 
VerifyProperties(void)159 void FGSwitch::VerifyProperties(void)
160 {
161   for (auto test: tests) {
162     if (!test->Default) {
163       test->condition->Evaluate();
164     }
165     test->OutputValue->GetValue();
166   }
167 }
168 
169 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 //    The bitmasked value choices are as follows:
171 //    unset: In this case (the default) JSBSim would only print
172 //       out the normally expected messages, essentially echoing
173 //       the config files as they are read. If the environment
174 //       variable is not set, debug_lvl is set to 1 internally
175 //    0: This requests JSBSim not to output any messages
176 //       whatsoever.
177 //    1: This value explicity requests the normal JSBSim
178 //       startup messages
179 //    2: This value asks for a message to be printed out when
180 //       a class is instantiated
181 //    4: When this value is set, a message is displayed when a
182 //       FGModel object executes its Run() method
183 //    8: When this value is set, various runtime state variables
184 //       are printed out periodically
185 //    16: When set various parameters are sanity checked and
186 //       a message is printed out when they go out of bounds
187 
Debug(int from)188 void FGSwitch::Debug(int from)
189 {
190   if (debug_lvl <= 0) return;
191 
192   if (debug_lvl & 1) { // Standard console startup message output
193     if (from == 0) { // Constructor
194       unsigned int i = 0;
195       for (auto test: tests) {
196         if (test->Default) {
197           cout << "      Switch default value is: " << test->GetOutputName();
198         } else {
199           cout << "      Switch takes test " << i << " value (" << test->GetOutputName() << ")" << endl;
200 
201           test->condition->PrintCondition("      ");
202         }
203         cout << endl;
204         ++i;
205       }
206       for (auto node: OutputNodes)
207         cout << "      OUTPUT: " << node->getName() << endl;
208     }
209   }
210   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
211     if (from == 0) cout << "Instantiated: FGSwitch" << endl;
212     if (from == 1) cout << "Destroyed:    FGSwitch" << endl;
213   }
214   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
215   }
216   if (debug_lvl & 8 ) { // Runtime state variables
217   }
218   if (debug_lvl & 16) { // Sanity checking
219   }
220   if (debug_lvl & 64) {
221     if (from == 0) { // Constructor
222     }
223   }
224 }
225 
226 } //namespace JSBSim
227 
228