]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGOutput.cpp
include cstring for memset() (necessary for gcc 4.3.*; backported
[flightgear.git] / src / FDM / JSBSim / models / 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 or stdout
7  Called by:    FGSimExec
8
9  ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.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 "FGState.h"
44 #include "FGFDMExec.h"
45 #include "FGAtmosphere.h"
46 #include "FGFCS.h"
47 #include "FGAerodynamics.h"
48 #include "FGGroundReactions.h"
49 #include "FGAircraft.h"
50 #include "FGMassBalance.h"
51 #include "FGPropagate.h"
52 #include "FGAuxiliary.h"
53 #include "FGInertial.h"
54 #include "FGPropulsion.h"   //access to FGEngine, FGTank
55 #include "models/propulsion/FGPiston.h"
56 #include <fstream>
57 #include <iomanip>
58 #include <cstring>
59
60 #include "input_output/net_fdm.hxx"
61
62 #if defined(WIN32) && !defined(__CYGWIN__)
63 #  include <windows.h>
64 #else
65 #  include <netinet/in.h>       // htonl() ntohl()
66 #endif
67
68 static const int endianTest = 1;
69 #define isLittleEndian (*((char *) &endianTest ) != 0)
70
71
72 namespace JSBSim {
73
74 static const char *IdSrc = "$Id$";
75 static const char *IdHdr = ID_OUTPUT;
76
77 // (stolen from FGFS native_fdm.cxx)
78 // The function htond is defined this way due to the way some
79 // processors and OSes treat floating point values.  Some will raise
80 // an exception whenever a "bad" floating point value is loaded into a
81 // floating point register.  Solaris is notorious for this, but then
82 // so is LynxOS on the PowerPC.  By translating the data in place,
83 // there is no need to load a FP register with the "corruped" floating
84 // point value.  By doing the BIG_ENDIAN test, I can optimize the
85 // routine for big-endian processors so it can be as efficient as
86 // possible
87 static void htond (double &x)
88 {
89     if ( isLittleEndian ) {
90         int    *Double_Overlay;
91         int     Holding_Buffer;
92
93         Double_Overlay = (int *) &x;
94         Holding_Buffer = Double_Overlay [0];
95
96         Double_Overlay [0] = htonl (Double_Overlay [1]);
97         Double_Overlay [1] = htonl (Holding_Buffer);
98     } else {
99         return;
100     }
101 }
102
103 // Float version
104 static void htonf (float &x)
105 {
106     if ( isLittleEndian ) {
107         int    *Float_Overlay;
108         int     Holding_Buffer;
109
110         Float_Overlay = (int *) &x;
111         Holding_Buffer = Float_Overlay [0];
112
113         Float_Overlay [0] = htonl (Holding_Buffer);
114     } else {
115         return;
116     }
117 }
118
119
120 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121 CLASS IMPLEMENTATION
122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
123
124 FGOutput::FGOutput(FGFDMExec* fdmex) : FGModel(fdmex)
125 {
126   Name = "FGOutput";
127   sFirstPass = dFirstPass = true;
128   socket = 0;
129   flightGearSocket = 0;
130   Type = otNone;
131   SubSystems = 0;
132   enabled = true;
133   delimeter = ", ";
134   Filename = "";
135   DirectivesFile = "";
136   output_file_name = "";
137
138   memset(&fgSockBuf, 0x00, sizeof(fgSockBuf));
139
140   Debug(0);
141 }
142
143 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144
145 FGOutput::~FGOutput()
146 {
147   delete socket;
148   delete flightGearSocket;
149   OutputProperties.clear();
150   Debug(1);
151 }
152
153 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154
155 bool FGOutput::InitModel(void)
156 {
157   if (!FGModel::InitModel()) return false;
158
159   return true;
160 }
161
162 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163
164 bool FGOutput::Run(void)
165 {
166   if (FGModel::Run()) return true;
167
168   if (enabled && !State->IntegrationSuspended()&& !FDMExec->Holding()) {
169     if (Type == otSocket) {
170       SocketOutput();
171     } else if (Type == otFlightGear) {
172       FlightGearSocketOutput();
173     } else if (Type == otCSV || Type == otTab) {
174       DelimitedOutput(Filename);
175     } else if (Type == otTerminal) {
176       // Not done yet
177     } else if (Type == otNone) {
178       // Do nothing
179     } else {
180       // Not a valid type of output
181     }
182   }
183   return false;
184 }
185
186 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187
188 void FGOutput::SetType(string type)
189 {
190   if (type == "CSV") {
191     Type = otCSV;
192     delimeter = ", ";
193   } else if (type == "TABULAR") {
194     Type = otTab;
195     delimeter = "\t";
196   } else if (type == "SOCKET") {
197     Type = otSocket;
198   } else if (type == "FLIGHTGEAR") {
199     Type = otFlightGear;
200   } else if (type == "TERMINAL") {
201     Type = otTerminal;
202   } else if (type != string("NONE")) {
203     Type = otUnknown;
204     cerr << "Unknown type of output specified in config file" << endl;
205   }
206 }
207
208 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
209
210 void FGOutput::DelimitedOutput(string fname)
211 {
212   streambuf* buffer;
213   string scratch = "";
214
215   if (fname == "COUT" || fname == "cout") {
216     buffer = cout.rdbuf();
217   } else {
218     datafile.open(fname.c_str());
219     buffer = datafile.rdbuf();
220   }
221
222   ostream outstream(buffer);
223
224   outstream.precision(10);
225
226   if (dFirstPass) {
227     outstream << "Time";
228     if (SubSystems & ssSimulation) {
229       // Nothing here, yet
230     }
231     if (SubSystems & ssAerosurfaces) {
232       outstream << delimeter;
233       outstream << "Aileron Command (norm)" + delimeter;
234       outstream << "Elevator Command (norm)" + delimeter;
235       outstream << "Rudder Command (norm)" + delimeter;
236       outstream << "Flap Command (norm)" + delimeter;
237       outstream << "Left Aileron Position (deg)" + delimeter;
238       outstream << "Right Aileron Position (deg)" + delimeter;
239       outstream << "Elevator Position (deg)" + delimeter;
240       outstream << "Rudder Position (deg)" + delimeter;
241       outstream << "Flap Position (deg)";
242     }
243     if (SubSystems & ssRates) {
244       outstream << delimeter;
245       outstream << "P (deg/s)" + delimeter + "Q (deg/s)" + delimeter + "R (deg/s)" + delimeter;
246       outstream << "P dot (deg/s^2)" + delimeter + "Q dot (deg/s^2)" + delimeter + "R dot (deg/s^2)";
247     }
248     if (SubSystems & ssVelocities) {
249       outstream << delimeter;
250       outstream << "q bar (psf)" + delimeter;
251       outstream << "V_{Total} (ft/s)" + delimeter;
252       outstream << "V_{Inertial} (ft/s)" + delimeter;
253       outstream << "UBody" + delimeter + "VBody" + delimeter + "WBody" + delimeter;
254       outstream << "Aero V_{X Body} (ft/s)" + delimeter + "Aero V_{Y Body} (ft/s)" + delimeter + "Aero V_{Z Body} (ft/s)" + delimeter;
255       outstream << "V_{North} (ft/s)" + delimeter + "V_{East} (ft/s)" + delimeter + "V_{Down} (ft/s)";
256     }
257     if (SubSystems & ssForces) {
258       outstream << delimeter;
259       outstream << "F_{Drag} (lbs)" + delimeter + "F_{Side} (lbs)" + delimeter + "F_{Lift} (lbs)" + delimeter;
260       outstream << "L/D" + delimeter;
261       outstream << "F_X (lbs)" + delimeter + "F_Y (lbs)" + delimeter + "F_Z (lbs)";
262     }
263     if (SubSystems & ssMoments) {
264       outstream << delimeter;
265       outstream << "L (ft-lbs)" + delimeter + "M (ft-lbs)" + delimeter + "N (ft-lbs)";
266     }
267     if (SubSystems & ssAtmosphere) {
268       outstream << delimeter;
269       outstream << "Rho (slugs/ft^3)" + delimeter;
270       outstream << "P_{SL} (psf)" + delimeter;
271       outstream << "P_{Ambient} (psf)" + delimeter;
272       outstream << "Turbulence Magnitude (ft/sec)" + delimeter;
273       outstream << "Turbulence X Direction (rad)" + delimeter + "Turbulence Y Direction (rad)" + delimeter + "Turbulence Z Direction (rad)" + delimeter;
274       outstream << "Wind V_{North} (ft/s)" + delimeter + "Wind V_{East} (ft/s)" + delimeter + "Wind V_{Down} (ft/s)";
275     }
276     if (SubSystems & ssMassProps) {
277       outstream << delimeter;
278       outstream << "I_xx" + delimeter;
279       outstream << "I_xy" + delimeter;
280       outstream << "I_xz" + delimeter;
281       outstream << "I_yx" + delimeter;
282       outstream << "I_yy" + delimeter;
283       outstream << "I_yz" + delimeter;
284       outstream << "I_zx" + delimeter;
285       outstream << "I_zy" + delimeter;
286       outstream << "I_zz" + delimeter;
287       outstream << "Mass" + delimeter;
288       outstream << "X_cg" + delimeter + "Y_cg" + delimeter + "Z_cg";
289     }
290     if (SubSystems & ssPropagate) {
291       outstream << delimeter;
292       outstream << "Altitude (ft)" + delimeter;
293       outstream << "Phi (deg)" + delimeter + "Theta (deg)" + delimeter + "Psi (deg)" + delimeter;
294       outstream << "Alpha (deg)" + delimeter;
295       outstream << "Beta (deg)" + delimeter;
296       outstream << "Latitude (deg)" + delimeter;
297       outstream << "Longitude (deg)" + delimeter;
298       outstream << "ECEF X (ft)" + delimeter + "ECEF Y (ft)" + delimeter + "ECEF Z (ft)" + delimeter;
299       outstream << "EPA (deg)" + delimeter;
300       outstream << "Distance AGL (ft)" + delimeter;
301       outstream << "Runway Radius (ft)";
302     }
303     if (SubSystems & ssCoefficients) {
304       scratch = Aerodynamics->GetCoefficientStrings(delimeter);
305       if (scratch.length() != 0) outstream << delimeter << scratch;
306     }
307     if (SubSystems & ssFCS) {
308       scratch = FCS->GetComponentStrings(delimeter);
309       if (scratch.length() != 0) outstream << delimeter << scratch;
310     }
311     if (SubSystems & ssGroundReactions) {
312       outstream << delimeter;
313       outstream << GroundReactions->GetGroundReactionStrings(delimeter);
314     }
315     if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
316       outstream << delimeter;
317       outstream << Propulsion->GetPropulsionStrings(delimeter);
318     }
319     if (OutputProperties.size() > 0) {
320       for (unsigned int i=0;i<OutputProperties.size();i++) {
321         outstream << delimeter << OutputProperties[i]->GetPrintableName();
322       }
323     }
324
325     outstream << endl;
326     dFirstPass = false;
327   }
328
329   outstream << State->Getsim_time();
330   if (SubSystems & ssSimulation) {
331   }
332   if (SubSystems & ssAerosurfaces) {
333     outstream << delimeter;
334     outstream << FCS->GetDaCmd() << delimeter;
335     outstream << FCS->GetDeCmd() << delimeter;
336     outstream << FCS->GetDrCmd() << delimeter;
337     outstream << FCS->GetDfCmd() << delimeter;
338     outstream << FCS->GetDaLPos(ofDeg) << delimeter;
339     outstream << FCS->GetDaRPos(ofDeg) << delimeter;
340     outstream << FCS->GetDePos(ofDeg) << delimeter;
341     outstream << FCS->GetDrPos(ofDeg) << delimeter;
342     outstream << FCS->GetDfPos(ofDeg);
343   }
344   if (SubSystems & ssRates) {
345     outstream << delimeter;
346     outstream << (radtodeg*Propagate->GetPQR()).Dump(delimeter) << delimeter;
347     outstream << (radtodeg*Propagate->GetPQRdot()).Dump(delimeter);
348   }
349   if (SubSystems & ssVelocities) {
350     outstream << delimeter;
351     outstream << Auxiliary->Getqbar() << delimeter;
352     outstream << setprecision(12) << Auxiliary->GetVt() << delimeter;
353     outstream << Propagate->GetInertialVelocityMagnitude() << delimeter;
354     outstream << setprecision(12) << Propagate->GetUVW().Dump(delimeter) << delimeter;
355     outstream << Auxiliary->GetAeroUVW().Dump(delimeter) << delimeter;
356     outstream << Propagate->GetVel().Dump(delimeter);
357   }
358   if (SubSystems & ssForces) {
359     outstream << delimeter;
360     outstream << Aerodynamics->GetvFw() << delimeter;
361     outstream << Aerodynamics->GetLoD() << delimeter;
362     outstream << Aircraft->GetForces().Dump(delimeter);
363   }
364   if (SubSystems & ssMoments) {
365     outstream << delimeter;
366     outstream << Aircraft->GetMoments().Dump(delimeter);
367   }
368   if (SubSystems & ssAtmosphere) {
369     outstream << delimeter;
370     outstream << Atmosphere->GetDensity() << delimeter;
371     outstream << Atmosphere->GetPressureSL() << delimeter;
372     outstream << Atmosphere->GetPressure() << delimeter;
373     outstream << Atmosphere->GetTurbMagnitude() << delimeter;
374     outstream << Atmosphere->GetTurbDirection().Dump(delimeter) << delimeter;
375     outstream << Atmosphere->GetWindNED().Dump(delimeter);
376   }
377   if (SubSystems & ssMassProps) {
378     outstream << delimeter;
379     outstream << MassBalance->GetJ() << delimeter;
380     outstream << MassBalance->GetMass() << delimeter;
381     outstream << MassBalance->GetXYZcg();
382   }
383   if (SubSystems & ssPropagate) {
384     outstream << delimeter;
385     outstream << Propagate->Geth() << delimeter;
386     outstream << (radtodeg*Propagate->GetEuler()).Dump(delimeter) << delimeter;
387     outstream << Auxiliary->Getalpha(inDegrees) << delimeter;
388     outstream << Auxiliary->Getbeta(inDegrees) << delimeter;
389     outstream << Propagate->GetLocation().GetLatitudeDeg() << delimeter;
390     outstream << Propagate->GetLocation().GetLongitudeDeg() << delimeter;
391     outstream << ((FGColumnVector3)Propagate->GetLocation()).Dump(delimeter) << delimeter;
392     outstream << Inertial->GetEarthPositionAngleDeg() << delimeter;
393     outstream << Propagate->GetDistanceAGL() << delimeter;
394     outstream << Propagate->GetRunwayRadius();
395   }
396   if (SubSystems & ssCoefficients) {
397     scratch = Aerodynamics->GetCoefficientValues(delimeter);
398     if (scratch.length() != 0) outstream << delimeter << scratch;
399   }
400   if (SubSystems & ssFCS) {
401     scratch = FCS->GetComponentValues(delimeter);
402     if (scratch.length() != 0) outstream << delimeter << scratch;
403   }
404   if (SubSystems & ssGroundReactions) {
405     outstream << delimeter;
406     outstream << GroundReactions->GetGroundReactionValues(delimeter);
407   }
408   if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
409     outstream << delimeter;
410     outstream << Propulsion->GetPropulsionValues(delimeter);
411   }
412
413   for (unsigned int i=0;i<OutputProperties.size();i++) {
414     outstream << delimeter << OutputProperties[i]->getDoubleValue();
415   }
416
417   outstream << endl;
418   outstream.flush();
419 }
420
421 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
422
423 void FGOutput::SocketDataFill(FGNetFDM* net)
424 {
425     unsigned int i;
426
427     // Version
428     net->version = FG_NET_FDM_VERSION;
429
430     // Positions
431     net->longitude = Propagate->GetLocation().GetLongitude(); // geodetic (radians)
432     net->latitude  = Propagate->GetLocation().GetLatitude(); // geodetic (radians)
433     net->altitude  = Propagate->Geth()*0.3048; // altitude, above sea level (meters)
434     net->agl       = (float)(Propagate->GetDistanceAGL()*0.3048); // altitude, above ground level (meters)
435
436     net->phi       = (float)(Propagate->GetEuler(ePhi)); // roll (radians)
437     net->theta     = (float)(Propagate->GetEuler(eTht)); // pitch (radians)
438     net->psi       = (float)(Propagate->GetEuler(ePsi)); // yaw or true heading (radians)
439
440     net->alpha     = (float)(Auxiliary->Getalpha()); // angle of attack (radians)
441     net->beta      = (float)(Auxiliary->Getbeta()); // side slip angle (radians)
442
443     // Velocities
444     net->phidot     = (float)(Auxiliary->GetEulerRates(ePhi)); // roll rate (radians/sec)
445     net->thetadot   = (float)(Auxiliary->GetEulerRates(eTht)); // pitch rate (radians/sec)
446     net->psidot     = (float)(Auxiliary->GetEulerRates(ePsi)); // yaw rate (radians/sec)
447     net->vcas       = (float)(Auxiliary->GetVcalibratedFPS()); // VCAS, ft/sec
448     net->climb_rate = (float)(Propagate->Gethdot());           // altitude rate, ft/sec
449     net->v_north    = (float)(Propagate->GetVel(eNorth));      // north vel in NED frame, fps
450     net->v_east     = (float)(Propagate->GetVel(eEast));       // east vel in NED frame, fps
451     net->v_down     = (float)(Propagate->GetVel(eDown));       // down vel in NED frame, fps
452 //---ADD METHOD TO CALCULATE THESE TERMS---
453     net->v_wind_body_north = (float)(Propagate->GetVel(eNorth)); // north vel in NED relative to airmass, fps
454     net->v_wind_body_east = (float)(Propagate->GetVel(eEast)); // east vel in NED relative to airmass, fps
455     net->v_wind_body_down = (float)(Propagate->GetVel(eDown)); // down vel in NED relative to airmass, fps
456
457     // Accelerations
458     net->A_X_pilot   = (float)(Auxiliary->GetPilotAccel(1));    // X body accel, ft/s/s
459     net->A_Y_pilot   = (float)(Auxiliary->GetPilotAccel(2));    // Y body accel, ft/s/s
460     net->A_Z_pilot   = (float)(Auxiliary->GetPilotAccel(3));    // Z body accel, ft/s/s
461
462     // Stall
463     net->stall_warning = 0.0;  // 0.0 - 1.0 indicating the amount of stall
464     net->slip_deg    = (float)(Auxiliary->Getbeta(inDegrees));  // slip ball deflection, deg
465
466     // Engine status
467     net->num_engines = Propulsion->GetNumEngines(); // Number of valid engines
468
469     for (i=0; i<net->num_engines; i++) {
470        if (Propulsion->GetEngine(i)->GetRunning())
471           net->eng_state[i] = 2;       // Engine state running
472        else if (Propulsion->GetEngine(i)->GetCranking())
473           net->eng_state[i] = 1;       // Engine state cranking
474        else
475           net->eng_state[i] = 0;       // Engine state off
476
477        switch (Propulsion->GetEngine(i)->GetType()) {
478        case (FGEngine::etRocket):
479        break;
480        case (FGEngine::etPiston):
481           net->rpm[i]       = (float)(((FGPiston *)Propulsion->GetEngine(i))->getRPM());
482           net->fuel_flow[i] = (float)(((FGPiston *)Propulsion->GetEngine(i))->getFuelFlow_gph());
483           net->fuel_px[i]   = 0; // Fuel pressure, psi  (N/A in current model)
484           net->egt[i]       = (float)(((FGPiston *)Propulsion->GetEngine(i))->GetEGT());
485           net->cht[i]       = (float)(((FGPiston *)Propulsion->GetEngine(i))->getCylinderHeadTemp_degF());
486           net->mp_osi[i]    = (float)(((FGPiston *)Propulsion->GetEngine(i))->getManifoldPressure_inHg());
487           net->oil_temp[i]  = (float)(((FGPiston *)Propulsion->GetEngine(i))->getOilTemp_degF());
488           net->oil_px[i]    = (float)(((FGPiston *)Propulsion->GetEngine(i))->getOilPressure_psi());
489           net->tit[i]       = 0; // Turbine Inlet Temperature  (N/A for piston)
490        break;
491        case (FGEngine::etTurbine):
492        break;
493        case (FGEngine::etTurboprop):
494        break;
495        case (FGEngine::etElectric):
496        break;
497        case (FGEngine::etUnknown):
498        break;
499        }
500     }
501
502
503     // Consumables
504     net->num_tanks = Propulsion->GetNumTanks();   // Max number of fuel tanks
505
506     for (i=0; i<net->num_tanks; i++) {
507        net->fuel_quantity[i] = (float)(((FGTank *)Propulsion->GetTank(i))->GetContents());
508     }
509
510
511     // Gear status
512     net->num_wheels  = GroundReactions->GetNumGearUnits();
513
514     for (i=0; i<net->num_wheels; i++) {
515        net->wow[i]              = GroundReactions->GetGearUnit(i)->GetWOW();
516        if (GroundReactions->GetGearUnit(i)->GetGearUnitDown())
517           net->gear_pos[i]      = 1;  //gear down, using FCS convention
518        else
519           net->gear_pos[i]      = 0;  //gear up, using FCS convention
520        net->gear_steer[i]       = (float)(GroundReactions->GetGearUnit(i)->GetSteerNorm());
521        net->gear_compression[i] = (float)(GroundReactions->GetGearUnit(i)->GetCompLen());
522     }
523
524
525     // Environment
526     net->cur_time    = (long int)1234567890;    // Friday, Feb 13, 2009, 23:31:30 UTC (not processed by FGFS anyway)
527     net->warp        = 0;                       // offset in seconds to unix time
528     net->visibility  = 25000.0;                 // visibility in meters (for env. effects)
529
530
531     // Control surface positions (normalized values)
532     net->elevator          = (float)(FCS->GetDePos(ofNorm));    // Norm Elevator Pos, --
533     net->elevator_trim_tab = (float)(FCS->GetPitchTrimCmd());   // Norm Elev Trim Tab Pos, --
534     net->left_flap         = (float)(FCS->GetDfPos(ofNorm));    // Norm Flap Pos, --
535     net->right_flap        = (float)(FCS->GetDfPos(ofNorm));    // Norm Flap Pos, --
536     net->left_aileron      = (float)(FCS->GetDaLPos(ofNorm));   // Norm L Aileron Pos, --
537     net->right_aileron     = (float)(FCS->GetDaRPos(ofNorm));   // Norm R Aileron Pos, --
538     net->rudder            = (float)(FCS->GetDrPos(ofNorm));    // Norm Rudder Pos, --
539     net->nose_wheel        = (float)(FCS->GetDrPos(ofNorm));    // *** FIX ***  Using Rudder Pos for NWS, --
540     net->speedbrake        = (float)(FCS->GetDsbPos(ofNorm));   // Norm Speedbrake Pos, --
541     net->spoilers          = (float)(FCS->GetDspPos(ofNorm));   // Norm Spoiler Pos, --
542
543
544     // Convert the net buffer to network format
545     if ( isLittleEndian ) {
546         net->version = htonl(net->version);
547
548         htond(net->longitude);
549         htond(net->latitude);
550         htond(net->altitude);
551         htonf(net->agl);
552         htonf(net->phi);
553         htonf(net->theta);
554         htonf(net->psi);
555         htonf(net->alpha);
556         htonf(net->beta);
557
558         htonf(net->phidot);
559         htonf(net->thetadot);
560         htonf(net->psidot);
561         htonf(net->vcas);
562         htonf(net->climb_rate);
563         htonf(net->v_north);
564         htonf(net->v_east);
565         htonf(net->v_down);
566         htonf(net->v_wind_body_north);
567         htonf(net->v_wind_body_east);
568         htonf(net->v_wind_body_down);
569
570         htonf(net->A_X_pilot);
571         htonf(net->A_Y_pilot);
572         htonf(net->A_Z_pilot);
573
574         htonf(net->stall_warning);
575         htonf(net->slip_deg);
576
577         for (i=0; i<net->num_engines; ++i ) {
578             net->eng_state[i] = htonl(net->eng_state[i]);
579             htonf(net->rpm[i]);
580             htonf(net->fuel_flow[i]);
581             htonf(net->fuel_px[i]);
582             htonf(net->egt[i]);
583             htonf(net->cht[i]);
584             htonf(net->mp_osi[i]);
585             htonf(net->tit[i]);
586             htonf(net->oil_temp[i]);
587             htonf(net->oil_px[i]);
588         }
589         net->num_engines = htonl(net->num_engines);
590
591         for (i=0; i<net->num_tanks; ++i ) {
592             htonf(net->fuel_quantity[i]);
593         }
594         net->num_tanks = htonl(net->num_tanks);
595
596         for (i=0; i<net->num_wheels; ++i ) {
597             net->wow[i] = htonl(net->wow[i]);
598             htonf(net->gear_pos[i]);
599             htonf(net->gear_steer[i]);
600             htonf(net->gear_compression[i]);
601         }
602         net->num_wheels = htonl(net->num_wheels);
603
604         net->cur_time = htonl( net->cur_time );
605         net->warp = htonl( net->warp );
606         htonf(net->visibility);
607
608         htonf(net->elevator);
609         htonf(net->elevator_trim_tab);
610         htonf(net->left_flap);
611         htonf(net->right_flap);
612         htonf(net->left_aileron);
613         htonf(net->right_aileron);
614         htonf(net->rudder);
615         htonf(net->nose_wheel);
616         htonf(net->speedbrake);
617         htonf(net->spoilers);
618     }
619 }
620
621 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622
623 void FGOutput::FlightGearSocketOutput(void)
624 {
625   int length = sizeof(fgSockBuf);
626
627
628   if (flightGearSocket == NULL) return;
629   if (!flightGearSocket->GetConnectStatus()) return;
630
631   SocketDataFill(&fgSockBuf);
632   flightGearSocket->Send((char *)&fgSockBuf, length);
633 }
634
635 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636
637 void FGOutput::SocketOutput(void)
638 {
639   string asciiData, scratch;
640
641   if (socket == NULL) return;
642   if (!socket->GetConnectStatus()) return;
643
644   socket->Clear();
645   if (sFirstPass) {
646     socket->Clear("<LABELS>");
647     socket->Append("Time");
648
649     if (SubSystems & ssAerosurfaces) {
650       socket->Append("Aileron Command");
651       socket->Append("Elevator Command");
652       socket->Append("Rudder Command");
653       socket->Append("Flap Command");
654       socket->Append("Left Aileron Position");
655       socket->Append("Right Aileron Position");
656       socket->Append("Elevator Position");
657       socket->Append("Rudder Position");
658       socket->Append("Flap Position");
659     }
660
661     if (SubSystems & ssRates) {
662       socket->Append("P");
663       socket->Append("Q");
664       socket->Append("R");
665       socket->Append("PDot");
666       socket->Append("QDot");
667       socket->Append("RDot");
668     }
669
670     if (SubSystems & ssVelocities) {
671       socket->Append("QBar");
672       socket->Append("Vtotal");
673       socket->Append("UBody");
674       socket->Append("VBody");
675       socket->Append("WBody");
676       socket->Append("UAero");
677       socket->Append("VAero");
678       socket->Append("WAero");
679       socket->Append("Vn");
680       socket->Append("Ve");
681       socket->Append("Vd");
682     }
683     if (SubSystems & ssForces) {
684       socket->Append("F_Drag");
685       socket->Append("F_Side");
686       socket->Append("F_Lift");
687       socket->Append("LoD");
688       socket->Append("Fx");
689       socket->Append("Fy");
690       socket->Append("Fz");
691     }
692     if (SubSystems & ssMoments) {
693       socket->Append("L");
694       socket->Append("M");
695       socket->Append("N");
696     }
697     if (SubSystems & ssAtmosphere) {
698       socket->Append("Rho");
699       socket->Append("SL pressure");
700       socket->Append("Ambient pressure");
701       socket->Append("Turbulence Magnitude");
702       socket->Append("Turbulence Direction X");
703       socket->Append("Turbulence Direction Y");
704       socket->Append("Turbulence Direction Z");
705       socket->Append("NWind");
706       socket->Append("EWind");
707       socket->Append("DWind");
708     }
709     if (SubSystems & ssMassProps) {
710       socket->Append("Ixx");
711       socket->Append("Ixy");
712       socket->Append("Ixz");
713       socket->Append("Iyx");
714       socket->Append("Iyy");
715       socket->Append("Iyz");
716       socket->Append("Izx");
717       socket->Append("Izy");
718       socket->Append("Izz");
719       socket->Append("Mass");
720       socket->Append("Xcg");
721       socket->Append("Ycg");
722       socket->Append("Zcg");
723     }
724     if (SubSystems & ssPropagate) {
725         socket->Append("Altitude");
726         socket->Append("Phi (deg)");
727         socket->Append("Tht (deg)");
728         socket->Append("Psi (deg)");
729         socket->Append("Alpha (deg)");
730         socket->Append("Beta (deg)");
731         socket->Append("Latitude (deg)");
732         socket->Append("Longitude (deg)");
733     }
734     if (SubSystems & ssCoefficients) {
735       scratch = Aerodynamics->GetCoefficientStrings(",");
736       if (scratch.length() != 0) socket->Append(scratch);
737     }
738     if (SubSystems & ssFCS) {
739       scratch = FCS->GetComponentStrings(",");
740       if (scratch.length() != 0) socket->Append(scratch);
741     }
742     if (SubSystems & ssGroundReactions) {
743       socket->Append(GroundReactions->GetGroundReactionStrings(","));
744     }
745     if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
746       socket->Append(Propulsion->GetPropulsionStrings(","));
747     }
748     if (OutputProperties.size() > 0) {
749       for (unsigned int i=0;i<OutputProperties.size();i++) {
750         socket->Append(OutputProperties[i]->GetPrintableName());
751       }
752     }
753
754     sFirstPass = false;
755     socket->Send();
756   }
757
758   socket->Clear();
759   socket->Append(State->Getsim_time());
760
761   if (SubSystems & ssAerosurfaces) {
762     socket->Append(FCS->GetDaCmd());
763     socket->Append(FCS->GetDeCmd());
764     socket->Append(FCS->GetDrCmd());
765     socket->Append(FCS->GetDfCmd());
766     socket->Append(FCS->GetDaLPos());
767     socket->Append(FCS->GetDaRPos());
768     socket->Append(FCS->GetDePos());
769     socket->Append(FCS->GetDrPos());
770     socket->Append(FCS->GetDfPos());
771   }
772   if (SubSystems & ssRates) {
773     socket->Append(radtodeg*Propagate->GetPQR(eP));
774     socket->Append(radtodeg*Propagate->GetPQR(eQ));
775     socket->Append(radtodeg*Propagate->GetPQR(eR));
776     socket->Append(radtodeg*Propagate->GetPQRdot(eP));
777     socket->Append(radtodeg*Propagate->GetPQRdot(eQ));
778     socket->Append(radtodeg*Propagate->GetPQRdot(eR));
779   }
780   if (SubSystems & ssVelocities) {
781     socket->Append(Auxiliary->Getqbar());
782     socket->Append(Auxiliary->GetVt());
783     socket->Append(Propagate->GetUVW(eU));
784     socket->Append(Propagate->GetUVW(eV));
785     socket->Append(Propagate->GetUVW(eW));
786     socket->Append(Auxiliary->GetAeroUVW(eU));
787     socket->Append(Auxiliary->GetAeroUVW(eV));
788     socket->Append(Auxiliary->GetAeroUVW(eW));
789     socket->Append(Propagate->GetVel(eNorth));
790     socket->Append(Propagate->GetVel(eEast));
791     socket->Append(Propagate->GetVel(eDown));
792   }
793   if (SubSystems & ssForces) {
794     socket->Append(Aerodynamics->GetvFw()(eDrag));
795     socket->Append(Aerodynamics->GetvFw()(eSide));
796     socket->Append(Aerodynamics->GetvFw()(eLift));
797     socket->Append(Aerodynamics->GetLoD());
798     socket->Append(Aircraft->GetForces(eX));
799     socket->Append(Aircraft->GetForces(eY));
800     socket->Append(Aircraft->GetForces(eZ));
801   }
802   if (SubSystems & ssMoments) {
803     socket->Append(Aircraft->GetMoments(eL));
804     socket->Append(Aircraft->GetMoments(eM));
805     socket->Append(Aircraft->GetMoments(eN));
806   }
807   if (SubSystems & ssAtmosphere) {
808     socket->Append(Atmosphere->GetDensity());
809     socket->Append(Atmosphere->GetPressureSL());
810     socket->Append(Atmosphere->GetPressure());
811     socket->Append(Atmosphere->GetTurbMagnitude());
812     socket->Append(Atmosphere->GetTurbDirection().Dump(","));
813     socket->Append(Atmosphere->GetWindNED().Dump(","));
814   }
815   if (SubSystems & ssMassProps) {
816     socket->Append(MassBalance->GetJ()(1,1));
817     socket->Append(MassBalance->GetJ()(1,2));
818     socket->Append(MassBalance->GetJ()(1,3));
819     socket->Append(MassBalance->GetJ()(2,1));
820     socket->Append(MassBalance->GetJ()(2,2));
821     socket->Append(MassBalance->GetJ()(2,3));
822     socket->Append(MassBalance->GetJ()(3,1));
823     socket->Append(MassBalance->GetJ()(3,2));
824     socket->Append(MassBalance->GetJ()(3,3));
825     socket->Append(MassBalance->GetMass());
826     socket->Append(MassBalance->GetXYZcg()(eX));
827     socket->Append(MassBalance->GetXYZcg()(eY));
828     socket->Append(MassBalance->GetXYZcg()(eZ));
829   }
830   if (SubSystems & ssPropagate) {
831     socket->Append(Propagate->Geth());
832     socket->Append(radtodeg*Propagate->GetEuler(ePhi));
833     socket->Append(radtodeg*Propagate->GetEuler(eTht));
834     socket->Append(radtodeg*Propagate->GetEuler(ePsi));
835     socket->Append(Auxiliary->Getalpha(inDegrees));
836     socket->Append(Auxiliary->Getbeta(inDegrees));
837     socket->Append(Propagate->GetLocation().GetLatitudeDeg());
838     socket->Append(Propagate->GetLocation().GetLongitudeDeg());
839   }
840   if (SubSystems & ssCoefficients) {
841     scratch = Aerodynamics->GetCoefficientValues(",");
842     if (scratch.length() != 0) socket->Append(scratch);
843   }
844   if (SubSystems & ssFCS) {
845     scratch = FCS->GetComponentValues(",");
846     if (scratch.length() != 0) socket->Append(scratch);
847   }
848   if (SubSystems & ssGroundReactions) {
849     socket->Append(GroundReactions->GetGroundReactionValues(","));
850   }
851   if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
852     socket->Append(Propulsion->GetPropulsionValues(","));
853   }
854
855   for (unsigned int i=0;i<OutputProperties.size();i++) {
856     socket->Append(OutputProperties[i]->getDoubleValue());
857   }
858
859   socket->Send();
860 }
861
862 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
863
864 void FGOutput::SocketStatusOutput(string out_str)
865 {
866   string asciiData;
867
868   if (socket == NULL) return;
869
870   socket->Clear();
871   asciiData = string("<STATUS>") + out_str;
872   socket->Append(asciiData.c_str());
873   socket->Send();
874 }
875
876 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
877
878 bool FGOutput::Load(Element* element)
879 {
880   string type="", parameter="";
881   string name="";
882   string protocol="tcp";
883   int OutRate = 0;
884   string property;
885   unsigned int port;
886   Element *property_element;
887
888   string separator = "/";
889 # ifdef macintosh
890   separator = ";";
891 # endif
892
893   if (!DirectivesFile.empty()) { // A directives filename from the command line overrides
894     output_file_name = DirectivesFile;      // one found in the config file.
895     document = LoadXMLDocument(output_file_name);
896   } else if (!element->GetAttributeValue("file").empty()) {
897     output_file_name = element->GetAttributeValue("file");
898     document = LoadXMLDocument(output_file_name);
899   } else {
900     document = element;
901   }
902
903   name = document->GetAttributeValue("name");
904   type = document->GetAttributeValue("type");
905   SetType(type);
906   if (!document->GetAttributeValue("port").empty() && type == string("SOCKET")) {
907     port = atoi(document->GetAttributeValue("port").c_str());
908     socket = new FGfdmSocket(name, port);
909   } else if (!document->GetAttributeValue("port").empty() && type == string("FLIGHTGEAR")) {
910     port = atoi(document->GetAttributeValue("port").c_str());
911     if (!document->GetAttributeValue("protocol").empty())
912        protocol = document->GetAttributeValue("protocol");
913     if (protocol == "udp")
914        flightGearSocket = new FGfdmSocket(name, port, FGfdmSocket::ptUDP);  // create udp socket
915     else
916        flightGearSocket = new FGfdmSocket(name, port, FGfdmSocket::ptTCP);  // create tcp socket (default)
917   } else {
918     Filename = name;
919   }
920   if (!document->GetAttributeValue("rate").empty()) {
921     OutRate = (int)document->GetAttributeValueAsNumber("rate");
922   } else {
923     OutRate = 1;
924   }
925
926   if (document->FindElementValue("simulation") == string("ON"))
927     SubSystems += ssSimulation;
928   if (document->FindElementValue("aerosurfaces") == string("ON"))
929     SubSystems += ssAerosurfaces;
930   if (document->FindElementValue("rates") == string("ON"))
931     SubSystems += ssRates;
932   if (document->FindElementValue("velocities") == string("ON"))
933     SubSystems += ssVelocities;
934   if (document->FindElementValue("forces") == string("ON"))
935     SubSystems += ssForces;
936   if (document->FindElementValue("moments") == string("ON"))
937     SubSystems += ssMoments;
938   if (document->FindElementValue("atmosphere") == string("ON"))
939     SubSystems += ssAtmosphere;
940   if (document->FindElementValue("massprops") == string("ON"))
941     SubSystems += ssMassProps;
942   if (document->FindElementValue("position") == string("ON"))
943     SubSystems += ssPropagate;
944   if (document->FindElementValue("coefficients") == string("ON"))
945     SubSystems += ssCoefficients;
946   if (document->FindElementValue("ground_reactions") == string("ON"))
947     SubSystems += ssGroundReactions;
948   if (document->FindElementValue("fcs") == string("ON"))
949     SubSystems += ssFCS;
950   if (document->FindElementValue("propulsion") == string("ON"))
951     SubSystems += ssPropulsion;
952   property_element = document->FindElement("property");
953   while (property_element) {
954     string property_str = property_element->GetDataLine();
955     FGPropertyManager* node = PropertyManager->GetNode(property_str);
956     if (!node) {
957       cerr << fgred << highint << endl << "  No property by the name "
958            << property_str << " has been defined. This property will " << endl
959            << "  not be logged. You should check your configuration file."
960            << reset << endl;
961     } else {
962       OutputProperties.push_back(node);
963     }
964     property_element = document->FindNextElement("property");
965   }
966
967   OutRate = OutRate>1000?1000:(OutRate<0?0:OutRate);
968   rate = (int)(0.5 + 1.0/(State->Getdt()*OutRate));
969
970   Debug(2);
971
972   return true;
973 }
974
975 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976 //    The bitmasked value choices are as follows:
977 //    unset: In this case (the default) JSBSim would only print
978 //       out the normally expected messages, essentially echoing
979 //       the config files as they are read. If the environment
980 //       variable is not set, debug_lvl is set to 1 internally
981 //    0: This requests JSBSim not to output any messages
982 //       whatsoever.
983 //    1: This value explicity requests the normal JSBSim
984 //       startup messages
985 //    2: This value asks for a message to be printed out when
986 //       a class is instantiated
987 //    4: When this value is set, a message is displayed when a
988 //       FGModel object executes its Run() method
989 //    8: When this value is set, various runtime state variables
990 //       are printed out periodically
991 //    16: When set various parameters are sanity checked and
992 //       a message is printed out when they go out of bounds
993
994 void FGOutput::Debug(int from)
995 {
996   string scratch="";
997
998   if (debug_lvl <= 0) return;
999
1000   if (debug_lvl & 1) { // Standard console startup message output
1001     if (from == 0) { // Constructor
1002
1003     }
1004     if (from == 2) {
1005       if (output_file_name.empty())
1006         cout << "  " << "Output parameters read inline" << endl;
1007       else
1008         cout << "    Output parameters read from file: " << output_file_name << endl;
1009
1010       if (Filename == "cout" || Filename == "COUT") {
1011         scratch = "    Log output goes to screen console";
1012       } else if (!Filename.empty()) {
1013         scratch = "    Log output goes to file: " + Filename;
1014       }
1015       switch (Type) {
1016       case otCSV:
1017         cout << scratch << " in CSV format output at rate " << 1/(State->Getdt()*rate) << " Hz" << endl;
1018         break;
1019       case otNone:
1020         cout << "  No log output" << endl;
1021         break;
1022       }
1023
1024       if (SubSystems & ssSimulation)      cout << "    Simulation parameters logged" << endl;
1025       if (SubSystems & ssAerosurfaces)    cout << "    Aerosurface parameters logged" << endl;
1026       if (SubSystems & ssRates)           cout << "    Rate parameters logged" << endl;
1027       if (SubSystems & ssVelocities)      cout << "    Velocity parameters logged" << endl;
1028       if (SubSystems & ssForces)          cout << "    Force parameters logged" << endl;
1029       if (SubSystems & ssMoments)         cout << "    Moments parameters logged" << endl;
1030       if (SubSystems & ssAtmosphere)      cout << "    Atmosphere parameters logged" << endl;
1031       if (SubSystems & ssMassProps)       cout << "    Mass parameters logged" << endl;
1032       if (SubSystems & ssCoefficients)    cout << "    Coefficient parameters logged" << endl;
1033       if (SubSystems & ssPropagate)       cout << "    Propagate parameters logged" << endl;
1034       if (SubSystems & ssGroundReactions) cout << "    Ground parameters logged" << endl;
1035       if (SubSystems & ssFCS)             cout << "    FCS parameters logged" << endl;
1036       if (SubSystems & ssPropulsion)      cout << "    Propulsion parameters logged" << endl;
1037       if (OutputProperties.size() > 0)    cout << "    Properties logged:" << endl;
1038       for (unsigned int i=0;i<OutputProperties.size();i++) {
1039         cout << "      - " << OutputProperties[i]->GetName() << endl;
1040       }
1041     }
1042   }
1043   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
1044     if (from == 0) cout << "Instantiated: FGOutput" << endl;
1045     if (from == 1) cout << "Destroyed:    FGOutput" << endl;
1046   }
1047   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
1048   }
1049   if (debug_lvl & 8 ) { // Runtime state variables
1050   }
1051   if (debug_lvl & 16) { // Sanity checking
1052   }
1053   if (debug_lvl & 64) {
1054     if (from == 0) { // Constructor
1055       cout << IdSrc << endl;
1056       cout << IdHdr << endl;
1057     }
1058   }
1059 }
1060 }