]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/flight_control/FGSwitch.cpp
Merge branch 'next' of git://gitorious.org/fg/flightgear into next
[flightgear.git] / src / FDM / JSBSim / models / flight_control / FGSwitch.cpp
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 Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  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 with
20  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21  Place - Suite 330, Boston, MA  02111-1307, USA.
22
23  Further information about the GNU Lesser General Public License can also be found on
24  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 <iostream>
66 #include <cstdlib>
67
68 using namespace std;
69
70 namespace JSBSim {
71
72 static const char *IdSrc = "$Id: FGSwitch.cpp,v 1.22 2011/06/17 12:12:19 jberndt Exp $";
73 static const char *IdHdr = ID_SWITCH;
74
75 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 CLASS IMPLEMENTATION
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
78
79 FGSwitch::FGSwitch(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
80 {
81   string value, logic;
82   struct test *current_test;
83   Element *test_element, *condition_element;
84
85   FGFCSComponent::bind(); // Bind() this component here in case it is used
86                           // in its own definition for a sample-and-hold
87
88   test_element = element->GetElement();
89   while (test_element) {
90     if (test_element->GetName() == "default") {
91       current_test = new struct test;
92       current_test->Logic = eDefault;
93       tests.push_back(current_test);
94     } else if (test_element->GetName() == "test") { // here's a test
95       current_test = new struct test;
96       logic = test_element->GetAttributeValue("logic");
97       if (logic == "OR") current_test->Logic = eOR;
98       else if (logic == "AND") current_test->Logic = eAND;
99       else if (logic.size() == 0) current_test->Logic = eAND; // default
100       else { // error
101         cerr << "Unrecognized LOGIC token " << logic << " in switch component: " << Name << endl;
102       }
103       for (unsigned int i=0; i<test_element->GetNumDataLines(); i++) {
104         string input_data = test_element->GetDataLine(i);
105         if (input_data.size() <= 1) {
106           // Make sure there are no bad data lines that consist solely of whitespace
107           cerr << fgred << "  Bad data line in switch component: " << Name << reset << endl;
108           continue;
109         }
110         current_test->conditions.push_back(new FGCondition(input_data, PropertyManager));
111       }
112
113       condition_element = test_element->GetElement(); // retrieve condition groups
114       while (condition_element) {
115         current_test->conditions.push_back(new FGCondition(condition_element, PropertyManager));
116         condition_element = test_element->GetNextElement();
117       }
118
119       tests.push_back(current_test);
120     }
121
122     string el_name = test_element->GetName();
123     if (   el_name != "output"
124         && el_name != "description"
125         && el_name != "delay" )
126     {
127       value = test_element->GetAttributeValue("value");
128       if (value.empty()) {
129         cerr << "No VALUE supplied for switch component: " << Name << endl;
130       } else {
131         if (is_number(value)) {
132           current_test->OutputVal = atof(value.c_str());
133         } else {
134           // "value" must be a property if execution passes to here.
135           if (value[0] == '-') {
136             current_test->sign = -1.0;
137             value.erase(0,1);
138           } else {
139             current_test->sign = 1.0;
140           }
141           FGPropertyManager *node = PropertyManager->GetNode(value, false);
142           if (node) {
143             current_test->OutputProp = new FGPropertyValue(node);
144           } else {
145             current_test->OutputProp = new FGPropertyValue(value,
146                                                            PropertyManager);
147           }
148         }
149       }
150     }
151     test_element = element->GetNextElement();
152   }
153
154   Debug(0);
155 }
156
157 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
158
159 FGSwitch::~FGSwitch()
160 {
161   for (unsigned int i=0; i<tests.size(); i++) {
162     for (unsigned int j=0; j<tests[i]->conditions.size(); j++) delete tests[i]->conditions[j];
163     delete tests[i]->OutputProp;
164     delete tests[i];
165   }
166
167   Debug(1);
168 }
169
170 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171
172 bool FGSwitch::Run(void )
173 {
174   bool pass = false;
175   double default_output=0.0;
176
177   for (unsigned int i=0; i<tests.size(); i++) {
178     if (tests[i]->Logic == eDefault) {
179       default_output = tests[i]->GetValue();
180     } else if (tests[i]->Logic == eAND) {
181       pass = true;
182       for (unsigned int j=0; j<tests[i]->conditions.size(); j++) {
183         if (!tests[i]->conditions[j]->Evaluate()) pass = false;
184       }
185     } else if (tests[i]->Logic == eOR) {
186       pass = false;
187       for (unsigned int j=0; j<tests[i]->conditions.size(); j++) {
188         if (tests[i]->conditions[j]->Evaluate()) pass = true;
189       }
190     } else {
191       cerr << "Invalid logic test" << endl;
192     }
193
194     if (pass) {
195       Output = tests[i]->GetValue();
196       break;
197     }
198   }
199   
200   if (!pass) Output = default_output;
201
202   if (delay != 0) Delay();
203   Clip();
204   if (IsOutput) SetOutput();
205
206   return true;
207 }
208
209 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210 //    The bitmasked value choices are as follows:
211 //    unset: In this case (the default) JSBSim would only print
212 //       out the normally expected messages, essentially echoing
213 //       the config files as they are read. If the environment
214 //       variable is not set, debug_lvl is set to 1 internally
215 //    0: This requests JSBSim not to output any messages
216 //       whatsoever.
217 //    1: This value explicity requests the normal JSBSim
218 //       startup messages
219 //    2: This value asks for a message to be printed out when
220 //       a class is instantiated
221 //    4: When this value is set, a message is displayed when a
222 //       FGModel object executes its Run() method
223 //    8: When this value is set, various runtime state variables
224 //       are printed out periodically
225 //    16: When set various parameters are sanity checked and
226 //       a message is printed out when they go out of bounds
227
228 void FGSwitch::Debug(int from)
229 {
230   string comp, scratch;
231   string indent = "        ";
232   bool first = false;
233
234   if (debug_lvl <= 0) return;
235
236   if (debug_lvl & 1) { // Standard console startup message output
237     if (from == 0) { // Constructor
238       for (unsigned int i=0; i<tests.size(); i++) {
239
240         scratch = " if ";
241
242         switch(tests[i]->Logic) {
243         case (elUndef):
244           comp = " UNSET ";
245           cerr << "Unset logic for test condition" << endl;
246           break;
247         case (eAND):
248           comp = " AND ";
249           break;
250         case (eOR):
251           comp=" OR ";
252           break;
253         case (eDefault):
254           scratch = " by default.";
255           break;
256         default:
257           comp = " UNKNOWN ";
258           cerr << "Unknown logic for test condition" << endl;
259         }
260
261         if (tests[i]->OutputProp != 0L)
262           if (tests[i]->sign < 0)
263             cout << indent << "Switch VALUE is - " << tests[i]->OutputProp->GetName() << scratch << endl;
264           else
265             cout << indent << "Switch VALUE is " << tests[i]->OutputProp->GetName() << scratch << endl;
266         else
267           cout << indent << "Switch VALUE is " << tests[i]->OutputVal << scratch << endl;
268
269         first = true;
270         for (unsigned int j=0; j<tests[i]->conditions.size(); j++) {
271           if (!first) cout << indent << comp << " ";
272           else cout << indent << " ";
273           first = false;
274           tests[i]->conditions[j]->PrintCondition();
275           cout << endl;
276         }
277         cout << endl;
278       }
279       if (IsOutput) {
280         for (unsigned int i=0; i<OutputNodes.size(); i++)
281           cout << "      OUTPUT: " << OutputNodes[i]->getName() << endl;
282       }
283     }
284   }
285   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
286     if (from == 0) cout << "Instantiated: FGSwitch" << endl;
287     if (from == 1) cout << "Destroyed:    FGSwitch" << endl;
288   }
289   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
290   }
291   if (debug_lvl & 8 ) { // Runtime state variables
292   }
293   if (debug_lvl & 16) { // Sanity checking
294   }
295   if (debug_lvl & 64) {
296     if (from == 0) { // Constructor
297       cout << IdSrc << endl;
298       cout << IdHdr << endl;
299     }
300   }
301 }
302
303 } //namespace JSBSim
304