JSBSim Flight Dynamics Model  1.2.0 (05 Nov 2023)
An Open Source Flight Dynamics and Control Software Library in C++
FGOutput.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module: FGOutput.cpp
4  Author: Jon Berndt
5  Date started: 12/02/98
6  Purpose: Manage output of sim parameters to file, stdout or socket
7  Called by: FGSimExec
8 
9  ------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
10 
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU Lesser General Public License as published by the Free
13  Software Foundation; either version 2 of the License, or (at your option) any
14  later version.
15 
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
19  details.
20 
21  You should have received a copy of the GNU Lesser General Public License along
22  with this program; if not, write to the Free Software Foundation, Inc., 59
23  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25  Further information about the GNU Lesser General Public License can also be
26  found on the world wide web at http://www.gnu.org.
27 
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 This is the place where you create output routines to dump data for perusal
31 later.
32 
33 HISTORY
34 --------------------------------------------------------------------------------
35 12/02/98 JSB Created
36 11/09/07 HDW Added FlightGear Socket Interface
37 
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 INCLUDES
40 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
41 
42 #include "FGOutput.h"
43 #include "input_output/FGOutputTextFile.h"
44 #include "input_output/FGOutputFG.h"
45 #include "input_output/FGXMLFileRead.h"
46 #include "input_output/FGModelLoader.h"
47 
48 using namespace std;
49 
50 namespace JSBSim {
51 
52 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53 CLASS IMPLEMENTATION
54 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55 
56 FGOutput::FGOutput(FGFDMExec* fdmex) : FGModel(fdmex)
57 {
58  typedef int (FGOutput::*iOPV)(void) const;
59 
60  Name = "FGOutput";
61  enabled = true;
62 
63  PropertyManager->Tie("simulation/force-output", this, (iOPV)0, &FGOutput::ForceOutput);
64 
65  Debug(0);
66 }
67 
68 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69 
70 FGOutput::~FGOutput()
71 {
72  for (auto output: OutputTypes)
73  delete output;
74 
75  Debug(1);
76 }
77 
78 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 
80 bool FGOutput::InitModel(void)
81 {
82  bool ret = false;
83 
84  if (!FGModel::InitModel()) return false;
85 
86  for (auto output: OutputTypes)
87  ret &= output->InitModel();
88 
89  return ret;
90 }
91 
92 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 
94 bool FGOutput::Run(bool Holding)
95 {
96  if (FDMExec->GetTrimStatus()) return true;
97  if (FGModel::Run(Holding)) return true;
98  if (Holding) return false;
99  if (!enabled) return true;
100 
101  for (auto output: OutputTypes)
102  output->Run();
103 
104  return false;
105 }
106 
107 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108 
109 void FGOutput::Print(void)
110 {
111  for (auto output: OutputTypes)
112  output->Print();
113 }
114 
115 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 
117 void FGOutput::SetStartNewOutput(void)
118 {
119  for (auto output: OutputTypes)
120  output->SetStartNewOutput();
121 }
122 
123 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124 
125 bool FGOutput::Toggle(int idx)
126 {
127  if (idx >= (int)0 && idx < (int)OutputTypes.size())
128  return OutputTypes[idx]->Toggle();
129 
130  return false;
131 }
132 
133 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134 
135 void FGOutput::SetRateHz(double rate)
136 {
137  for (auto output: OutputTypes)
138  output->SetRateHz(rate);
139 }
140 
141 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142 
143 void FGOutput::ForceOutput(int idx)
144 {
145  if (idx >= (int)0 && idx < (int)OutputTypes.size())
146  OutputTypes[idx]->Print();
147 }
148 
149 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150 
151 bool FGOutput::SetOutputName(unsigned int idx, const std::string& name)
152 {
153  if (idx >= OutputTypes.size()) return false;
154 
155  OutputTypes[idx]->SetOutputName(name);
156  return true;
157 }
158 
159 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 
161 string FGOutput::GetOutputName(unsigned int idx) const
162 {
163  string name;
164 
165  if (idx < OutputTypes.size())
166  name = OutputTypes[idx]->GetOutputName();
167  return name;
168 }
169 
170 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171 
172 bool FGOutput::SetDirectivesFile(const SGPath& fname)
173 {
175  Element* document = XMLFile.LoadXMLDocument(fname);
176  if (!document) {
177  stringstream s;
178  s << "Could not read directive file: " << fname;
179  throw BaseException(s.str());
180  }
181 
182  bool result = Load(document);
183  if (!result)
184  cerr << endl << "Aircraft output element has problems in file " << fname << endl;
185 
186  return result;
187 }
188 
189 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190 
191 bool FGOutput::Load(int subSystems, std::string protocol, std::string type,
192  std::string port, std::string name, double outRate,
193  std::vector<FGPropertyNode_ptr> & outputProperties)
194 {
195  size_t idx = OutputTypes.size();
196  FGOutputType* Output = 0;
197 
198  if (debug_lvl > 0) cout << endl << " Output data set: " << idx << endl;
199 
200  type = to_upper(type);
201 
202  if (type == "CSV") {
203  FGOutputTextFile* OutputTextFile = new FGOutputTextFile(FDMExec);
204  OutputTextFile->SetDelimiter(",");
205  Output = OutputTextFile;
206  } else if (type == "TABULAR") {
207  FGOutputTextFile* OutputTextFile = new FGOutputTextFile(FDMExec);
208  OutputTextFile->SetDelimiter("\t");
209  Output = OutputTextFile;
210  } else if (type == "SOCKET") {
211  Output = new FGOutputSocket(FDMExec);
212  name += ":" + port + "/" + protocol;
213  } else if (type == "FLIGHTGEAR") {
214  Output = new FGOutputFG(FDMExec);
215  name += ":" + port + "/" + protocol;
216  } else if (type == "TERMINAL") {
217  // Not done yet
218  } else if (type != string("NONE")) {
219  cerr << "Unknown type of output specified in config file" << endl;
220  }
221 
222  if (!Output) return false;
223 
224  Output->SetIdx(idx);
225  Output->SetOutputName(name);
226  Output->SetRateHz(outRate);
227  Output->SetSubSystems(subSystems);
228  Output->SetOutputProperties(outputProperties);
229 
230  OutputTypes.push_back(Output);
231 
232  Debug(2);
233  return true;
234 }
235 
236 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 
238 bool FGOutput::Load(Element* document, const SGPath& dir)
239 {
240  // Optional path to use for included files
241  includePath = dir;
242 
243  // Perform base class Pre-Load
244  if (!FGModel::Upload(document, false))
245  return false;
246 
247  size_t idx = OutputTypes.size();
248  string type = document->GetAttributeValue("type");
249  FGOutputType* Output = 0;
250 
251  if (debug_lvl > 0) cout << endl << " Output data set: " << idx << " " << endl;
252 
253  type = to_upper(type);
254 
255  if (type == "CSV") {
256  Output = new FGOutputTextFile(FDMExec);
257  } else if (type == "TABULAR") {
258  Output = new FGOutputTextFile(FDMExec);
259  } else if (type == "SOCKET") {
260  Output = new FGOutputSocket(FDMExec);
261  } else if (type == "FLIGHTGEAR") {
262  Output = new FGOutputFG(FDMExec);
263  } else if (type == "TERMINAL") {
264  // Not done yet
265  } else if (type != string("NONE")) {
266  cerr << "Unknown type of output specified in config file" << endl;
267  }
268 
269  if (!Output) return false;
270 
271  Output->SetIdx(idx);
272  Output->PreLoad(document, FDMExec);
273  Output->Load(document);
274  Output->PostLoad(document, FDMExec);
275 
276  OutputTypes.push_back(Output);
277 
278  Debug(2);
279  return true;
280 }
281 
282 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283 
284 SGPath FGOutput::FindFullPathName(const SGPath& path) const
285 {
286  // Check optional include path if set
287  if (!includePath.isNull()) {
288  SGPath name = CheckPathName(includePath, path);
289  if (!name.isNull()) return name;
290  }
291 
292  return FGModel::FindFullPathName(path);
293 }
294 
295 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 // The bitmasked value choices are as follows:
297 // unset: In this case (the default) JSBSim would only print
298 // out the normally expected messages, essentially echoing
299 // the config files as they are read. If the environment
300 // variable is not set, debug_lvl is set to 1 internally
301 // 0: This requests JSBSim not to output any messages
302 // whatsoever.
303 // 1: This value explicity requests the normal JSBSim
304 // startup messages
305 // 2: This value asks for a message to be printed out when
306 // a class is instantiated
307 // 4: When this value is set, a message is displayed when a
308 // FGModel object executes its Run() method
309 // 8: When this value is set, various runtime state variables
310 // are printed out periodically
311 // 16: When set various parameters are sanity checked and
312 // a message is printed out when they go out of bounds
313 
314 void FGOutput::Debug(int from)
315 {
316  if (debug_lvl <= 0) return;
317 
318  if (debug_lvl & 1) { // Standard console startup message output
319  if (from == 0) { // Constructor
320 
321  }
322  if (from == 2) {
323  }
324  }
325  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
326  if (from == 0) cout << "Instantiated: FGOutput" << endl;
327  if (from == 1) cout << "Destroyed: FGOutput" << endl;
328  }
329  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
330  }
331  if (debug_lvl & 8 ) { // Runtime state variables
332  }
333  if (debug_lvl & 16) { // Sanity checking
334  }
335  if (debug_lvl & 64) {
336  if (from == 0) { // Constructor
337  }
338  }
339 }
340 }
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
Implements the output to a FlightGear socket.
Definition: FGOutputFG.h:64
Implements the output to a socket.
Implements the output to a human readable text file.
void SetDelimiter(const std::string &delim)
Set the delimiter.
Abstract class to provide functions generic to all the output directives.
Definition: FGOutputType.h:92
bool Load(Element *el) override
Init the output directives from an XML file (implement the FGModel interface).
void SetRateHz(double rtHz)
Set the output rate for this output instances.
void SetIdx(unsigned int idx)
Set the idx for this output instance.
virtual void SetOutputName(const std::string &name)
Overwrites the name identifier under which the output will be logged.
Definition: FGOutputType.h:130
void SetSubSystems(int subSystems)
Set the activated subsystems for this output instance.
Definition: FGOutputType.h:118
void SetOutputProperties(std::vector< FGPropertyNode_ptr > &outputProperties)
Set the list of properties that should be output for this output instance.
This class is solely for the purpose of determining what type of file is given on the command line.
Definition: JSBSim.cpp:149