JSBSim Flight Dynamics Model  1.0 (02 March 2017)
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 Software
13  Foundation; either version 2 of the License, or (at your option) any later
14  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 with
22  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23  Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25  Further information about the GNU Lesser General Public License can also be found on
26  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 "FGFDMExec.h"
44 #include "input_output/FGOutputSocket.h"
45 #include "input_output/FGOutputTextFile.h"
46 #include "input_output/FGOutputFG.h"
47 #include "input_output/FGUDPOutputSocket.h"
48 #include "input_output/FGXMLFileRead.h"
49 #include "input_output/FGXMLElement.h"
50 #include "input_output/FGModelLoader.h"
51 
52 using namespace std;
53 
54 namespace JSBSim {
55 
56 IDENT(IdSrc,"$Id: FGOutput.cpp,v 1.87 2017/02/25 14:23:19 bcoconni Exp $");
57 IDENT(IdHdr,ID_OUTPUT);
58 
59 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60 CLASS IMPLEMENTATION
61 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
62 
63 FGOutput::FGOutput(FGFDMExec* fdmex) : FGModel(fdmex)
64 {
65  typedef int (FGOutput::*iOPV)(void) const;
66 
67  Name = "FGOutput";
68  enabled = true;
69 
70  PropertyManager->Tie("simulation/force-output", this, (iOPV)0, &FGOutput::ForceOutput, false);
71 
72  Debug(0);
73 }
74 
75 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 
77 FGOutput::~FGOutput()
78 {
79  vector<FGOutputType*>::iterator it;
80  for (it = OutputTypes.begin(); it != OutputTypes.end(); ++it)
81  delete (*it);
82 
83  Debug(1);
84 }
85 
86 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 
89 {
90  bool ret = false;
91 
92  if (!FGModel::InitModel()) return false;
93 
94  vector<FGOutputType*>::iterator it;
95  for (it = OutputTypes.begin(); it != OutputTypes.end(); ++it)
96  ret &= (*it)->InitModel();
97 
98  return ret;
99 }
100 
101 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102 
103 bool FGOutput::Run(bool Holding)
104 {
105  if (FDMExec->GetTrimStatus()) return true;
106  if (FGModel::Run(Holding)) return true;
107  if (Holding) return false;
108  if (!enabled) return true;
109 
110  vector<FGOutputType*>::iterator it;
111  for (it = OutputTypes.begin(); it != OutputTypes.end(); ++it)
112  (*it)->Run();
113 
114  return false;
115 }
116 
117 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118 
119 void FGOutput::Print(void)
120 {
121  vector<FGOutputType*>::iterator it;
122  for (it = OutputTypes.begin(); it != OutputTypes.end(); ++it)
123  (*it)->Print();
124 }
125 
126 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127 
129 {
130  vector<FGOutputType*>::iterator it;
131  for (it = OutputTypes.begin(); it != OutputTypes.end(); ++it)
132  (*it)->SetStartNewOutput();
133 }
134 
135 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136 
137 bool FGOutput::Toggle(int idx)
138 {
139  if (idx >= (int)0 && idx < (int)OutputTypes.size())
140  return OutputTypes[idx]->Toggle();
141 
142  return false;
143 }
144 
145 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146 
147 void FGOutput::SetRateHz(double rate)
148 {
149  vector<FGOutputType*>::iterator it;
150  for (it = OutputTypes.begin(); it != OutputTypes.end(); ++it)
151  (*it)->SetRateHz(rate);
152 }
153 
154 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155 
157 {
158  if (idx >= (int)0 && idx < (int)OutputTypes.size())
159  OutputTypes[idx]->Print();
160 }
161 
162 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163 
164 bool FGOutput::SetOutputName(unsigned int idx, const std::string& name)
165 {
166  if (idx >= OutputTypes.size()) return false;
167 
168  OutputTypes[idx]->SetOutputName(name);
169  return true;
170 }
171 
172 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173 
174 string FGOutput::GetOutputName(unsigned int idx) const
175 {
176  string name;
177 
178  if (idx < OutputTypes.size())
179  name = OutputTypes[idx]->GetOutputName();
180  return name;
181 }
182 
183 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
184 
185 bool FGOutput::SetDirectivesFile(const SGPath& fname)
186 {
188  Element* document = XMLFile.LoadXMLDocument(fname);
189  bool result = Load(document);
190 
191  if (!result)
192  cerr << endl << "Aircraft output element has problems in file " << fname << endl;
193 
194  return result;
195 }
196 
197 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 
199 bool FGOutput::Load(int subSystems, std::string protocol, std::string type,
200  std::string port, std::string name, double outRate,
201  std::vector<FGPropertyNode_ptr> & outputProperties)
202 {
203  size_t idx = OutputTypes.size();
204  FGOutputType* Output = 0;
205 
206  if (debug_lvl > 0) cout << endl << " Output data set: " << idx << endl;
207 
208  type = to_upper(type);
209 
210  if (type == "CSV") {
211  FGOutputTextFile* OutputTextFile = new FGOutputTextFile(FDMExec);
212  OutputTextFile->SetDelimiter(",");
213  Output = OutputTextFile;
214  } else if (type == "TABULAR") {
215  FGOutputTextFile* OutputTextFile = new FGOutputTextFile(FDMExec);
216  OutputTextFile->SetDelimiter("\t");
217  Output = OutputTextFile;
218  } else if (type == "SOCKET") {
219  Output = new FGOutputSocket(FDMExec);
220  name += ":" + port + "/" + protocol;
221  } else if (type == "FLIGHTGEAR") {
222  Output = new FGOutputFG(FDMExec);
223  name += ":" + port + "/" + protocol;
224  } else if (type == "QTJSBSIM") {
225  Output = new FGUDPOutputSocket(FDMExec);
226  name += ":" + port + "/" + protocol;
227  } else if (type == "TERMINAL") {
228  // Not done yet
229  } else if (type != string("NONE")) {
230  cerr << "Unknown type of output specified in config file" << endl;
231  }
232 
233  if (!Output) return false;
234 
235  Output->SetIdx(idx);
236  Output->SetOutputName(name);
237  Output->SetRateHz(outRate);
238  Output->SetSubSystems(subSystems);
239  Output->SetOutputProperties(outputProperties);
240 
241  OutputTypes.push_back(Output);
242 
243  Debug(2);
244  return true;
245 }
246 
247 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248 
250 {
251  // Unlike the other FGModel classes, properties listed in the <output> section
252  // are not intended to create new properties. For that reason, FGOutput
253  // cannot load its XML directives with FGModel::Load().
254  // Instead FGModelLoader::Open() and FGModel::PreLoad() must be explicitely
255  // called.
256  FGModelLoader ModelLoader(this);
257  Element* element = ModelLoader.Open(el);
258 
259  if (!element) return false;
260 
261  FGModel::PreLoad(element, PropertyManager);
262 
263  size_t idx = OutputTypes.size();
264  string type = element->GetAttributeValue("type");
265  FGOutputType* Output = 0;
266 
267  if (debug_lvl > 0) cout << endl << " Output data set: " << idx << " " << endl;
268 
269  type = to_upper(type);
270 
271  if (type == "CSV") {
272  Output = new FGOutputTextFile(FDMExec);
273  } else if (type == "TABULAR") {
274  Output = new FGOutputTextFile(FDMExec);
275  } else if (type == "SOCKET") {
276  Output = new FGOutputSocket(FDMExec);
277  } else if (type == "FLIGHTGEAR") {
278  Output = new FGOutputFG(FDMExec);
279  } else if (type == "QTJSBSIM") {
280  Output = new FGUDPOutputSocket(FDMExec);
281  } else if (type == "TERMINAL") {
282  // Not done yet
283  } else if (type != string("NONE")) {
284  cerr << "Unknown type of output specified in config file" << endl;
285  }
286 
287  if (!Output) return false;
288 
289  Output->SetIdx(idx);
290  Output->Load(element);
291  PostLoad(element, PropertyManager);
292 
293  OutputTypes.push_back(Output);
294 
295  Debug(2);
296  return true;
297 }
298 
299 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
300 // The bitmasked value choices are as follows:
301 // unset: In this case (the default) JSBSim would only print
302 // out the normally expected messages, essentially echoing
303 // the config files as they are read. If the environment
304 // variable is not set, debug_lvl is set to 1 internally
305 // 0: This requests JSBSim not to output any messages
306 // whatsoever.
307 // 1: This value explicity requests the normal JSBSim
308 // startup messages
309 // 2: This value asks for a message to be printed out when
310 // a class is instantiated
311 // 4: When this value is set, a message is displayed when a
312 // FGModel object executes its Run() method
313 // 8: When this value is set, various runtime state variables
314 // are printed out periodically
315 // 16: When set various parameters are sanity checked and
316 // a message is printed out when they go out of bounds
317 
318 void FGOutput::Debug(int from)
319 {
320  string scratch="";
321 
322  if (debug_lvl <= 0) return;
323 
324  if (debug_lvl & 1) { // Standard console startup message output
325  if (from == 0) { // Constructor
326 
327  }
328  if (from == 2) {
329  }
330  }
331  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
332  if (from == 0) cout << "Instantiated: FGOutput" << endl;
333  if (from == 1) cout << "Destroyed: FGOutput" << endl;
334  }
335  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
336  }
337  if (debug_lvl & 8 ) { // Runtime state variables
338  }
339  if (debug_lvl & 16) { // Sanity checking
340  }
341  if (debug_lvl & 64) {
342  if (from == 0) { // Constructor
343  cout << IdSrc << endl;
344  cout << IdHdr << endl;
345  }
346  }
347 }
348 }
void ForceOutput(int idx)
Force an output instance to generate its output.
Definition: FGOutput.cpp:156
void SetSubSystems(int subSystems)
Set the activated subsystems for this output instance.
Definition: FGOutputType.h:122
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
bool SetDirectivesFile(const SGPath &fname)
Adds a new output instance to the Output Manager.
Definition: FGOutput.cpp:185
Implements the output to a FlightGear socket.
Definition: FGOutputFG.h:69
bool SetOutputName(unsigned int idx, const std::string &name)
Overwrites the name identifier under which the output will be logged.
Definition: FGOutput.cpp:164
STL namespace.
void SetOutputProperties(std::vector< FGPropertyNode_ptr > &outputProperties)
Set the list of properties that should be output for this output instance.
Definition: FGOutputType.h:127
Implements the output to a human readable text file.
virtual bool Run(bool Holding)
Runs the model; called by the Executive.
Definition: FGModel.cpp:92
void SetRateHz(double rtHz)
Set the output rate for this output instances.
void SetRateHz(double rate)
Modifies the output rate for all output instances.
Definition: FGOutput.cpp:147
bool Toggle(int idx)
Toggles the output generation of each ouput instance.
Definition: FGOutput.cpp:137
virtual bool Load(Element *el)
Init the output directives from an XML file (implement the FGModel interface).
void SetDelimiter(const std::string &delim)
Set the delimiter.
bool Run(bool Holding)
Runs the Output model; called by the Executive.
Definition: FGOutput.cpp:103
bool Load(Element *el)
Load the output directives and adds a new output instance to the Output Manager list.
Definition: FGOutput.cpp:249
This class is solely for the purpose of determining what type of file is given on the command line...
Definition: JSBSim.cpp:152
Abstract class to provide functions generic to all the output directives.
Definition: FGOutputType.h:95
virtual void SetOutputName(const std::string &name)
Overwrites the name identifier under which the output will be logged.
Definition: FGOutputType.h:137
void SetIdx(unsigned int idx)
Set the idx for this output instance.
void SetStartNewOutput(void)
Reset the output prior to a restart of the simulation.
Definition: FGOutput.cpp:128
bool InitModel(void)
Initializes the instance.
Definition: FGOutput.cpp:88
Implements the output to a socket.
Implements the output to a UDP socket.
std::string GetOutputName(unsigned int idx) const
Get the name identifier to which the output will be directed.
Definition: FGOutput.cpp:174
void Print(void)
Makes all the output instances to generate their ouput.
Definition: FGOutput.cpp:119