]> git.mxchange.org Git - flightgear.git/blob - src/FDM/fdm_shell.cxx
6c2d095370322c0ae5abf1c6a8edf5bb2fc38b44
[flightgear.git] / src / FDM / fdm_shell.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4
5 #include <simgear/structure/exception.hxx>
6
7 #include <FDM/fdm_shell.hxx>
8 #include <FDM/flight.hxx>
9 #include <Aircraft/replay.hxx>
10 #include <Main/globals.hxx>
11 #include <Main/fg_props.hxx>
12 #include <Scenery/scenery.hxx>
13
14 // all the FDMs, since we are the factory method
15 #if ENABLE_SP_FDM
16 #include <FDM/SP/ADA.hxx>
17 #include <FDM/SP/ACMS.hxx>
18 #include <FDM/SP/MagicCarpet.hxx>
19 #include <FDM/SP/Balloon.h>
20 #endif
21 #include <FDM/ExternalNet/ExternalNet.hxx>
22 #include <FDM/ExternalPipe/ExternalPipe.hxx>
23 #include <FDM/JSBSim/JSBSim.hxx>
24 #include <FDM/LaRCsim/LaRCsim.hxx>
25 #include <FDM/UFO.hxx>
26 #include <FDM/NullFDM.hxx>
27 #include <FDM/YASim/YASim.hxx>
28
29 /*
30  * Evil global variable required by Network/FGNative,
31  * see that class for more information
32  */
33 FGInterface* evil_global_fdm_state = NULL;
34
35 FDMShell::FDMShell() :
36   _impl(NULL),
37   _dataLogging(false)
38 {
39 }
40
41 FDMShell::~FDMShell()
42 {
43   delete _impl;
44 }
45
46 void FDMShell::init()
47 {
48   _props = globals->get_props();
49   createImplementation();
50 }
51
52 void FDMShell::reinit()
53 {
54   if (_impl) {
55     fgSetBool("/sim/signals/fdm-initialized", false);
56     evil_global_fdm_state = NULL;
57     _impl->unbind();
58     delete _impl;
59     _impl = NULL;
60   }
61   
62   init();
63 }
64
65 void FDMShell::bind()
66 {
67   if (_impl && _impl->get_inited()) {
68     if (_impl->get_bound()) {
69       throw sg_exception("FDMShell::bind of bound FGInterface impl");
70     }
71     
72     _impl->bind();
73   }
74 }
75
76 void FDMShell::unbind()
77 {
78   _impl->unbind();
79 }
80
81 void FDMShell::update(double dt)
82 {
83   if (!_impl) {
84     return;
85   }
86   
87   if (!_impl->get_inited()) {
88     // Check for scenery around the aircraft.
89     double lon = fgGetDouble("/sim/presets/longitude-deg");
90     double lat = fgGetDouble("/sim/presets/latitude-deg");
91         
92     double range = 1000.0; // in metres
93     SGGeod geod = SGGeod::fromDeg(lon, lat);
94     if (globals->get_scenery()->scenery_available(geod, range)) {
95         SG_LOG(SG_FLIGHT, SG_INFO, "Scenery loaded, will init FDM");
96         _impl->init();
97         if (_impl->get_bound()) {
98           _impl->unbind();
99         }
100         _impl->bind();
101         
102         evil_global_fdm_state = _impl;
103         fgSetBool("/sim/signals/fdm-initialized", true);
104     }
105   }
106
107   if (!_impl->get_inited()) {
108     return; // still waiting
109   }
110
111 // pull environmental data in, since the FDMs are lazy
112   _impl->set_Velocities_Local_Airmass(
113       _props->getDoubleValue("environment/wind-from-north-fps", 0.0),
114                         _props->getDoubleValue("environment/wind-from-east-fps", 0.0),
115                         _props->getDoubleValue("environment/wind-from-down-fps", 0.0));
116
117   if (_props->getBoolValue("environment/params/control-fdm-atmosphere")) {
118     // convert from Rankine to Celsius
119     double tempDegC = _props->getDoubleValue("environment/temperature-degc");
120     _impl->set_Static_temperature((9.0/5.0) * (tempDegC + 273.15));
121     
122     // convert from inHG to PSF
123     double pressureInHg = _props->getDoubleValue("environment/pressure-inhg");
124     _impl->set_Static_pressure(pressureInHg * 70.726566);
125     // keep in slugs/ft^3
126     _impl->set_Density(_props->getDoubleValue("environment/density-slugft3"));
127   }
128
129   bool doLog = _props->getBoolValue("/sim/temp/fdm-data-logging", false);
130   if (doLog != _dataLogging) {
131     _dataLogging = doLog;
132     _impl->ToggleDataLogging(doLog);
133   }
134
135 // FIXME - replay manager should handle most of this           
136   int replayState = fgGetInt("/sim/freeze/replay-state", 0);
137   if (replayState == 0) {
138     _impl->update(dt); // normal code path
139   } else if (replayState == 1) {
140     // should be inside FGReplay!
141     SGPropertyNode* replay_time = fgGetNode("/sim/replay/time", true);
142     FGReplay *r = (FGReplay *)(globals->get_subsystem( "replay" ));
143     r->replay( replay_time->getDoubleValue() );
144     replay_time->setDoubleValue( replay_time->getDoubleValue()
145                                              + ( dt
146                                                  * fgGetInt("/sim/speed-up") ) );
147   
148   } else if (replayState == 2) {
149     // paused replay, no-op
150   } else {
151     throw sg_range_exception("unknown FGReplay state");
152   }  
153 }
154
155 void FDMShell::createImplementation()
156 {
157   assert(!_impl);
158   
159   double dt = 1.0 / fgGetInt("/sim/model-hz");
160   string model = fgGetString("/sim/flight-model");
161
162     if ( model == "larcsim" ) {
163         _impl = new FGLaRCsim( dt );
164     } else if ( model == "jsb" ) {
165         _impl = new FGJSBsim( dt );
166 #if ENABLE_SP_FDM
167     } else if ( model == "ada" ) {
168         _impl = new FGADA( dt );
169     } else if ( model == "acms" ) {
170         _impl = new FGACMS( dt );
171     } else if ( model == "balloon" ) {
172         _impl = new FGBalloonSim( dt );
173     } else if ( model == "magic" ) {
174         _impl = new FGMagicCarpet( dt );
175 #endif
176     } else if ( model == "ufo" ) {
177         _impl = new FGUFO( dt );
178     } else if ( model == "external" ) {
179         // external is a synonym for "--fdm=null" and is
180         // maintained here for backwards compatibility
181         _impl = new FGNullFDM( dt );
182     } else if ( model.find("network") == 0 ) {
183         string host = "localhost";
184         int port1 = 5501;
185         int port2 = 5502;
186         int port3 = 5503;
187         string net_options = model.substr(8);
188         string::size_type begin, end;
189         begin = 0;
190         // host
191         end = net_options.find( ",", begin );
192         if ( end != string::npos ) {
193             host = net_options.substr(begin, end - begin);
194             begin = end + 1;
195         }
196         // port1
197         end = net_options.find( ",", begin );
198         if ( end != string::npos ) {
199             port1 = atoi( net_options.substr(begin, end - begin).c_str() );
200             begin = end + 1;
201         }
202         // port2
203         end = net_options.find( ",", begin );
204         if ( end != string::npos ) {
205             port2 = atoi( net_options.substr(begin, end - begin).c_str() );
206             begin = end + 1;
207         }
208         // port3
209         end = net_options.find( ",", begin );
210         if ( end != string::npos ) {
211             port3 = atoi( net_options.substr(begin, end - begin).c_str() );
212             begin = end + 1;
213         }
214         _impl = new FGExternalNet( dt, host, port1, port2, port3 );
215     } else if ( model.find("pipe") == 0 ) {
216         // /* old */ string pipe_path = model.substr(5);
217         // /* old */ _impl = new FGExternalPipe( dt, pipe_path );
218         string pipe_path = "";
219         string pipe_protocol = "";
220         string pipe_options = model.substr(5);
221         string::size_type begin, end;
222         begin = 0;
223         // pipe file path
224         end = pipe_options.find( ",", begin );
225         if ( end != string::npos ) {
226             pipe_path = pipe_options.substr(begin, end - begin);
227             begin = end + 1;
228         }
229         // protocol (last option)
230         pipe_protocol = pipe_options.substr(begin);
231         _impl = new FGExternalPipe( dt, pipe_path, pipe_protocol );
232     } else if ( model == "null" ) {
233         _impl = new FGNullFDM( dt );
234     } else if ( model == "yasim" ) {
235         _impl = new YASim( dt );
236     } else {
237         throw sg_exception(string("Unrecognized flight model '") + model
238                + "', cannot init flight dynamics model.");
239     }
240
241 }
242