FlightGear next
FGOutputFG.cpp
Go to the documentation of this file.
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGOutputFG.cpp
4 Author: Bertrand Coconnier
5 Date started: 09/10/11
6 Purpose: Manage output of sim parameters to FlightGear
7 Called by: FGOutput
8
9 ------------- Copyright (C) 2011 Bertrand Coconnier -------------
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
28FUNCTIONAL DESCRIPTION
29--------------------------------------------------------------------------------
30This is the place where you create output routines to dump data for perusal
31later.
32
33HISTORY
34--------------------------------------------------------------------------------
3511/09/07 HDW Added FlightGear Socket Interface
3609/10/11 BC Moved the FlightGear socket in a separate class
37
38%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39INCLUDES
40%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
41
42#include <cstring>
43
44#include "FGOutputFG.h"
45#include "FGXMLElement.h"
46#include "models/FGAuxiliary.h"
47#include "models/FGPropulsion.h"
48#include "models/FGFCS.h"
52
53#if defined(WIN32) && !defined(__CYGWIN__)
54# include <windows.h>
55#else
56# include <netinet/in.h> // htonl() ntohl()
57#endif
58
59#if !defined (min)
60# define min(X,Y) X<Y?X:Y
61#endif
62
63static const int endianTest = 1;
64#define isLittleEndian (*((char *) &endianTest ) != 0)
65
66using namespace std;
67
68namespace JSBSim {
69
70// (stolen from FGFS native_fdm.cxx)
71// The function htond is defined this way due to the way some
72// processors and OSes treat floating point values. Some will raise
73// an exception whenever a "bad" floating point value is loaded into a
74// floating point register. Solaris is notorious for this, but then
75// so is LynxOS on the PowerPC. By translating the data in place,
76// there is no need to load a FP register with the "corruped" floating
77// point value. By doing the BIG_ENDIAN test, I can optimize the
78// routine for big-endian processors so it can be as efficient as
79// possible
80static void htond (double &x)
81{
82 if ( isLittleEndian ) {
83 int *Double_Overlay;
84 int Holding_Buffer;
85
86 Double_Overlay = (int *) &x;
87 Holding_Buffer = Double_Overlay [0];
88
89 Double_Overlay [0] = htonl (Double_Overlay [1]);
90 Double_Overlay [1] = htonl (Holding_Buffer);
91 } else {
92 return;
93 }
94}
95
96// Float version
97static void htonf (float &x)
98{
99 if ( isLittleEndian ) {
100 int *Float_Overlay;
101 int Holding_Buffer;
102
103 Float_Overlay = (int *) &x;
104 Holding_Buffer = Float_Overlay [0];
105
106 Float_Overlay [0] = htonl (Holding_Buffer);
107 } else {
108 return;
109 }
110}
111
112
113/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
114CLASS IMPLEMENTATION
115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
116
118 FGOutputSocket(fdmex), outputOptions{false, 1e6}
119{
120 memset(&fgSockBuf, 0x0, sizeof(fgSockBuf));
121
122 if (fdmex->GetDebugLevel() > 0) {
123 // Engine status
124 if (Propulsion->GetNumEngines() > FGNetFDM::FG_MAX_ENGINES)
125 cerr << "This vehicle has " << Propulsion->GetNumEngines() << " engines, but the current " << endl
126 << "version of FlightGear's FGNetFDM only supports " << FGNetFDM::FG_MAX_ENGINES << " engines." << endl
127 << "Only the first " << FGNetFDM::FG_MAX_ENGINES << " engines will be used." << endl;
128
129 // Consumables
130 if (Propulsion->GetNumTanks() > FGNetFDM::FG_MAX_TANKS)
131 cerr << "This vehicle has " << Propulsion->GetNumTanks() << " tanks, but the current " << endl
132 << "version of FlightGear's FGNetFDM only supports " << FGNetFDM::FG_MAX_TANKS << " tanks." << endl
133 << "Only the first " << FGNetFDM::FG_MAX_TANKS << " tanks will be used." << endl;
134
135 // Gear status
136 if (GroundReactions->GetNumGearUnits() > FGNetFDM::FG_MAX_WHEELS)
137 cerr << "This vehicle has " << GroundReactions->GetNumGearUnits() << " bogeys, but the current " << endl
138 << "version of FlightGear's FGNetFDM only supports " << FGNetFDM::FG_MAX_WHEELS << " bogeys." << endl
139 << "Only the first " << FGNetFDM::FG_MAX_WHEELS << " bogeys will be used." << endl;
140 }
141}
142
143//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144
146{
147 if (!FGOutputSocket::Load(el)) {
148 return false;
149 }
150
151 // Check if there is a <time> element
152 Element* time_el = el->FindElement("time");
153 if (time_el) {
154 // Check if the attribute "type" is specified and is set to "simulation"
155 if (time_el->HasAttribute("type") && time_el->GetAttributeValue("type") == "simulation") {
156 outputOptions.useSimTime = true;
157 }
158
159 // Check if the attribute "resolution" is specified and set to a valid value
160 if (time_el->HasAttribute("resolution")) {
161 if (time_el->GetAttributeValueAsNumber("resolution") <= 1 &&
162 time_el->GetAttributeValueAsNumber("resolution") >= 1e-9) {
163 outputOptions.timeFactor = 1./time_el->GetAttributeValueAsNumber("resolution");
164 } else {
165 return false;
166 }
167 }
168 }
169 return true;
170}
171
172//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173
174void FGOutputFG::SocketDataFill(FGNetFDM* net)
175{
176 unsigned int i;
177
178 // Version
180
181 // Positions
182 net->longitude = Propagate->GetLongitude(); // longitude (radians)
183 net->latitude = Propagate->GetGeodLatitudeRad(); // geodetic (radians)
184 net->altitude = Propagate->GetAltitudeASL()*0.3048; // altitude, above sea level (meters)
185 net->agl = (float)(Propagate->GetDistanceAGL()*0.3048); // altitude, above ground level (meters)
186
187 net->phi = (float)(Propagate->GetEuler(ePhi)); // roll (radians)
188 net->theta = (float)(Propagate->GetEuler(eTht)); // pitch (radians)
189 net->psi = (float)(Propagate->GetEuler(ePsi)); // yaw or true heading (radians)
190
191 net->alpha = (float)(Auxiliary->Getalpha()); // angle of attack (radians)
192 net->beta = (float)(Auxiliary->Getbeta()); // side slip angle (radians)
193
194 // Velocities
195 net->phidot = (float)(Auxiliary->GetEulerRates(ePhi)); // roll rate (radians/sec)
196 net->thetadot = (float)(Auxiliary->GetEulerRates(eTht)); // pitch rate (radians/sec)
197 net->psidot = (float)(Auxiliary->GetEulerRates(ePsi)); // yaw rate (radians/sec)
198 net->vcas = (float)(Auxiliary->GetVcalibratedKTS()); // VCAS, knots
199 net->climb_rate = (float)(Propagate->Gethdot()); // altitude rate, ft/sec
200 net->v_north = (float)(Propagate->GetVel(eNorth)); // north vel in NED frame, fps
201 net->v_east = (float)(Propagate->GetVel(eEast)); // east vel in NED frame, fps
202 net->v_down = (float)(Propagate->GetVel(eDown)); // down vel in NED frame, fps
203//---ADD METHOD TO CALCULATE THESE TERMS---
204 net->v_body_u = (float)(Propagate->GetUVW(1)); // ECEF speed in body axis
205 net->v_body_v = (float)(Propagate->GetUVW(2)); // ECEF speed in body axis
206 net->v_body_w = (float)(Propagate->GetUVW(3)); // ECEF speed in body axis
207
208 // Accelerations
209 net->A_X_pilot = (float)(Auxiliary->GetPilotAccel(1)); // X body accel, ft/s/s
210 net->A_Y_pilot = (float)(Auxiliary->GetPilotAccel(2)); // Y body accel, ft/s/s
211 net->A_Z_pilot = (float)(Auxiliary->GetPilotAccel(3)); // Z body accel, ft/s/s
212
213 // Stall
214 net->stall_warning = 0.0; // 0.0 - 1.0 indicating the amount of stall
215 net->slip_deg = (float)(Auxiliary->Getbeta(inDegrees)); // slip ball deflection, deg
216
217 net->num_engines = min(FGNetFDM::FG_MAX_ENGINES,Propulsion->GetNumEngines()); // Number of valid engines
218
219 for (i=0; i<net->num_engines; i++) {
220 FGEngine* engine = Propulsion->GetEngine(i);
221 if (engine->GetRunning())
222 net->eng_state[i] = 2; // Engine state running
223 else if (engine->GetCranking())
224 net->eng_state[i] = 1; // Engine state cranking
225 else
226 net->eng_state[i] = 0; // Engine state off
227
228 switch (engine->GetType()) {
229 case (FGEngine::etRocket):
230 break;
231 case (FGEngine::etPiston):
232 {
233 FGPiston* piston_engine = static_cast<FGPiston*>(engine);
234 net->rpm[i] = (float)(piston_engine->getRPM());
235 net->fuel_flow[i] = (float)(piston_engine->getFuelFlow_gph());
236 net->fuel_px[i] = 0; // Fuel pressure, psi (N/A in current model)
237 net->egt[i] = (float)(piston_engine->GetEGT());
238 net->cht[i] = (float)(piston_engine->getCylinderHeadTemp_degF());
239 net->mp_osi[i] = (float)(piston_engine->getManifoldPressure_inHg());
240 net->oil_temp[i] = (float)(piston_engine->getOilTemp_degF());
241 net->oil_px[i] = (float)(piston_engine->getOilPressure_psi());
242 net->tit[i] = 0; // Turbine Inlet Temperature (N/A for piston)
243 }
244 break;
245 case (FGEngine::etTurbine):
246 break;
248 break;
250 net->rpm[i] = static_cast<float>(static_cast<FGElectric*>(engine)->getRPM());
251 break;
252 case (FGEngine::etUnknown):
253 break;
254 }
255 }
256
257 net->num_tanks = min(FGNetFDM::FG_MAX_TANKS, Propulsion->GetNumTanks()); // Max number of fuel tanks
258
259 for (i=0; i<net->num_tanks; i++) {
260 net->fuel_quantity[i] = (float)(((FGTank *)Propulsion->GetTank(i))->GetContents());
261 }
262
263 net->num_wheels = min(FGNetFDM::FG_MAX_WHEELS, GroundReactions->GetNumGearUnits());
264
265 for (i=0; i<net->num_wheels; i++) {
266 net->wow[i] = GroundReactions->GetGearUnit(i)->GetWOW();
267 if (GroundReactions->GetGearUnit(i)->GetGearUnitDown())
268 net->gear_pos[i] = 1; //gear down, using FCS convention
269 else
270 net->gear_pos[i] = 0; //gear up, using FCS convention
271 net->gear_steer[i] = (float)(GroundReactions->GetGearUnit(i)->GetSteerNorm());
272 net->gear_compression[i] = (float)(GroundReactions->GetGearUnit(i)->GetCompLen());
273 }
274
275 // Environment
276 if (outputOptions.useSimTime) {
277 // Send simulation time with specified resolution
278 net->cur_time = static_cast<uint32_t>(FDMExec->GetSimTime()*outputOptions.timeFactor);
279 } else {
280 // Default to sending constant dummy value to ensure backwards-compatibility
281 net->cur_time = 1234567890u;
282 }
283
284 net->warp = 0; // offset in seconds to unix time
285 net->visibility = 25000.0; // visibility in meters (for env. effects)
286
287 // Control surface positions (normalized values)
288 net->elevator = (float)(FCS->GetDePos(ofNorm)); // Norm Elevator Pos, --
289 net->elevator_trim_tab = (float)(FCS->GetPitchTrimCmd()); // Norm Elev Trim Tab Pos, --
290 net->left_flap = (float)(FCS->GetDfPos(ofNorm)); // Norm Flap Pos, --
291 net->right_flap = (float)(FCS->GetDfPos(ofNorm)); // Norm Flap Pos, --
292 net->left_aileron = (float)(FCS->GetDaLPos(ofNorm)); // Norm L Aileron Pos, --
293 net->right_aileron = (float)(FCS->GetDaRPos(ofNorm)); // Norm R Aileron Pos, --
294 net->rudder = (float)(FCS->GetDrPos(ofNorm)); // Norm Rudder Pos, --
295 net->nose_wheel = (float)(FCS->GetDrPos(ofNorm)); // *** FIX *** Using Rudder Pos for NWS, --
296 net->speedbrake = (float)(FCS->GetDsbPos(ofNorm)); // Norm Speedbrake Pos, --
297 net->spoilers = (float)(FCS->GetDspPos(ofNorm)); // Norm Spoiler Pos, --
298
299 // Convert the net buffer to network format
300 if ( isLittleEndian ) {
301 net->version = htonl(net->version);
302
303 htond(net->longitude);
304 htond(net->latitude);
305 htond(net->altitude);
306 htonf(net->agl);
307 htonf(net->phi);
308 htonf(net->theta);
309 htonf(net->psi);
310 htonf(net->alpha);
311 htonf(net->beta);
312
313 htonf(net->phidot);
314 htonf(net->thetadot);
315 htonf(net->psidot);
316 htonf(net->vcas);
317 htonf(net->climb_rate);
318 htonf(net->v_north);
319 htonf(net->v_east);
320 htonf(net->v_down);
321 htonf(net->v_body_u);
322 htonf(net->v_body_v);
323 htonf(net->v_body_w);
324
325 htonf(net->A_X_pilot);
326 htonf(net->A_Y_pilot);
327 htonf(net->A_Z_pilot);
328
329 htonf(net->stall_warning);
330 htonf(net->slip_deg);
331
332 for (i=0; i<net->num_engines; ++i ) {
333 net->eng_state[i] = htonl(net->eng_state[i]);
334 htonf(net->rpm[i]);
335 htonf(net->fuel_flow[i]);
336 htonf(net->fuel_px[i]);
337 htonf(net->egt[i]);
338 htonf(net->cht[i]);
339 htonf(net->mp_osi[i]);
340 htonf(net->tit[i]);
341 htonf(net->oil_temp[i]);
342 htonf(net->oil_px[i]);
343 }
344 net->num_engines = htonl(net->num_engines);
345
346 for (i=0; i<net->num_tanks; ++i ) {
347 htonf(net->fuel_quantity[i]);
348 }
349 net->num_tanks = htonl(net->num_tanks);
350
351 for (i=0; i<net->num_wheels; ++i ) {
352 net->wow[i] = htonl(net->wow[i]);
353 htonf(net->gear_pos[i]);
354 htonf(net->gear_steer[i]);
355 htonf(net->gear_compression[i]);
356 }
357 net->num_wheels = htonl(net->num_wheels);
358
359 net->cur_time = htonl( net->cur_time );
360 net->warp = htonl( net->warp );
361 htonf(net->visibility);
362
363 htonf(net->elevator);
365 htonf(net->left_flap);
366 htonf(net->right_flap);
367 htonf(net->left_aileron);
368 htonf(net->right_aileron);
369 htonf(net->rudder);
370 htonf(net->nose_wheel);
371 htonf(net->speedbrake);
372 htonf(net->spoilers);
373 }
374}
375
376//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377
379{
380 int length = sizeof(fgSockBuf);
381
382 if (socket == 0) return;
383 if (!socket->GetConnectStatus()) return;
384
385 SocketDataFill(&fgSockBuf);
386 socket->Send((char *)&fgSockBuf, length);
387}
388}
const uint32_t FG_NET_FDM_VERSION
#define isLittleEndian
static const int endianTest
#define min(X, Y)
#define i(x)
uint32_t wow[FG_MAX_WHEELS]
float cht[FG_MAX_ENGINES]
float fuel_flow[FG_MAX_ENGINES]
float mp_osi[FG_MAX_ENGINES]
float gear_steer[FG_MAX_WHEELS]
float gear_pos[FG_MAX_WHEELS]
float tit[FG_MAX_ENGINES]
float egt[FG_MAX_ENGINES]
float oil_temp[FG_MAX_ENGINES]
float rpm[FG_MAX_ENGINES]
uint32_t eng_state[FG_MAX_ENGINES]
float gear_compression[FG_MAX_WHEELS]
float fuel_quantity[FG_MAX_TANKS]
float fuel_px[FG_MAX_ENGINES]
float oil_px[FG_MAX_ENGINES]
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
Element * FindElement(const std::string &el="")
Searches for a specified element.
double Getbeta(void) const
double GetPilotAccel(int idx) const
double GetEulerRates(int axis) const
double Getalpha(void) const
double GetVcalibratedKTS(void) const
Returns Calibrated airspeed in knots.
Base class for all engines.
Definition FGEngine.h:104
virtual double getFuelFlow_gph() const
Definition FGEngine.h:146
virtual bool GetCranking(void) const
Definition FGEngine.h:153
virtual bool GetRunning(void) const
Definition FGEngine.h:152
EngineType GetType(void) const
Definition FGEngine.h:138
int GetDebugLevel(void) const
Retrieves the current debug level setting.
Definition FGFDMExec.h:594
FGFDMExec * FDMExec
Definition FGModel.h:116
bool Load(Element *) override
Evaluate the output directives from an XML file.
void Print(void) override
Generate the output.
FGOutputFG(FGFDMExec *fdmex)
Constructor.
FGOutputSocket(FGFDMExec *fdmex)
Constructor.
bool Load(Element *el) override
Init the output directives from an XML file.
FGGroundReactions * GroundReactions
FGPropulsion * Propulsion
FGAuxiliary * Auxiliary
FGPropagate * Propagate
Models a Supercharged Piston engine.
Definition FGPiston.h:224
double getOilPressure_psi(void) const
Definition FGPiston.h:247
double getOilTemp_degF(void) const
Definition FGPiston.h:248
double getRPM(void) const
Definition FGPiston.h:249
double getCylinderHeadTemp_degF(void) const
Definition FGPiston.h:246
double GetEGT(void) const
Definition FGPiston.h:241
double getManifoldPressure_inHg(void) const
Definition FGPiston.h:245
double GetGeodLatitudeRad(void) const
double GetLongitude(void) const
const FGColumnVector3 & GetEuler(void) const
Retrieves the Euler angles that define the vehicle orientation.
double GetAltitudeASL(void) const
Returns the current altitude above sea level.
double GetDistanceAGL(void) const
double Gethdot(void) const
Returns the current altitude rate.
const FGColumnVector3 & GetUVW(void) const
Retrieves the body frame vehicle velocity vector.
const FGColumnVector3 & GetVel(void) const
Retrieves the velocity vector.
unsigned int GetNumEngines(void) const
Retrieves the number of engines defined for the aircraft.
FGEngine * GetEngine(unsigned int index) const
Retrieves an engine object pointer from the list of engines.
@ ofNorm
Definition FGFCS.h:56
static void htonf(float &x)
static void htond(double &x)