]> git.mxchange.org Git - flightgear.git/blob - src/FDM/ExternalNet.cxx
Commented out cout statements that were not in the std namespace.
[flightgear.git] / src / FDM / ExternalNet.cxx
1 // ExternalNet.hxx -- an net interface to an external flight dynamics model
2 //
3 // Written by Curtis Olson, started November 2001.
4 //
5 // Copyright (C) 2001  Curtis L. Olson  - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23 #include <simgear/debug/logstream.hxx>
24 #include <simgear/io/lowlevel.hxx> // endian tests
25
26 #include <Main/fg_props.hxx>
27
28 #include "ExternalNet.hxx"
29
30
31 // FreeBSD works better with this included last ... (?)
32 #if defined(WIN32) && !defined(__CYGWIN__)
33 #  include <windows.h>
34 #else
35 #  include <netinet/in.h>       // htonl() ntohl()
36 #endif
37
38
39 // The function htond is defined this way due to the way some
40 // processors and OSes treat floating point values.  Some will raise
41 // an exception whenever a "bad" floating point value is loaded into a
42 // floating point register.  Solaris is notorious for this, but then
43 // so is LynxOS on the PowerPC.  By translating the data in place,
44 // there is no need to load a FP register with the "corruped" floating
45 // point value.  By doing the BIG_ENDIAN test, I can optimize the
46 // routine for big-endian processors so it can be as efficient as
47 // possible
48 static void htond (double &x)   
49 {
50     if ( sgIsLittleEndian() ) {
51         int    *Double_Overlay;
52         int     Holding_Buffer;
53     
54         Double_Overlay = (int *) &x;
55         Holding_Buffer = Double_Overlay [0];
56     
57         Double_Overlay [0] = htonl (Double_Overlay [1]);
58         Double_Overlay [1] = htonl (Holding_Buffer);
59     } else {
60         return;
61     }
62 }
63
64
65 static void global2raw( FGRawCtrls *raw ) {
66     int i;
67
68     static const SGPropertyNode *aileron
69         = fgGetNode("/controls/aileron");
70     static const SGPropertyNode *elevator
71         = fgGetNode("/controls/elevator");
72     static const SGPropertyNode *elevator_trim
73         = fgGetNode("/controls/elevator-trim");
74     static const SGPropertyNode *rudder
75         = fgGetNode("/controls/rudder");
76     static const SGPropertyNode *flaps
77         = fgGetNode("/controls/flaps");
78     char buf[256];
79
80     // fill in values
81     raw->version = FG_RAW_CTRLS_VERSION;
82     raw->aileron = fgGetDouble( "/controls/aileron" );
83     raw->elevator = fgGetDouble( "/controls/elevator" );
84     raw->elevator_trim = fgGetDouble( "/controls/elevator-trim" );
85     raw->rudder = fgGetDouble( "/controls/rudder" );
86     raw->flaps = fgGetDouble( "/controls/flaps" );
87     for ( i = 0; i < FG_MAX_ENGINES; ++i ) {
88         sprintf( buf, "/controls/throttle[%d]", i );
89         raw->throttle[i] = fgGetDouble( buf );
90         sprintf( buf, "/controls/mixture[%d]", i );
91         raw->mixture[i] = fgGetDouble( buf );
92         sprintf( buf, "/controls/propeller-pitch[%d]", i );
93         raw->prop_advance[i] = fgGetDouble( buf );
94     }
95     for ( i = 0; i < FG_MAX_WHEELS; ++i ) {
96         sprintf( buf, "/controls/brakes[%d]", i );
97         raw->brake[i] = fgGetDouble( buf );
98     }
99     raw->hground = fgGetDouble( "/environment/ground-elevation-m" );
100
101     // convert to network byte order
102     raw->version = htonl(raw->version);
103     htond(raw->aileron);
104     htond(raw->elevator);
105     htond(raw->elevator_trim);
106     htond(raw->rudder);
107     htond(raw->flaps);
108     for ( i = 0; i < FG_MAX_ENGINES; ++i ) {
109         htond(raw->throttle[i]);
110         htond(raw->mixture[i]);
111         htond(raw->prop_advance[i]);
112     }
113     for ( i = 0; i < FG_MAX_WHEELS; ++i ) {
114         htond(raw->brake[i]);
115     }
116     htond(raw->hground);
117
118 }
119
120
121 static void net2global( FGNetFDM *net ) {
122     // Convert to the net buffer from network format
123     net->version = ntohl(net->version);
124     htond(net->longitude);
125     htond(net->latitude);
126     htond(net->altitude);
127     htond(net->phi);
128     htond(net->theta);
129     htond(net->psi);
130     htond(net->vcas);
131     htond(net->climb_rate);
132     net->cur_time = ntohl(net->cur_time);
133     net->warp = ntohl(net->warp);
134     htond(net->visibility);
135
136     if ( net->version == FG_NET_FDM_VERSION ) {
137         // cout << "pos = " << net->longitude << " " << net->latitude << endl;
138         // cout << "sea level rad = " << cur_fdm_state->get_Sea_level_radius() << endl;
139         cur_fdm_state->_updateGeodeticPosition( net->latitude,
140                                                 net->longitude,
141                                                 net->altitude
142                                                   * SG_METER_TO_FEET );
143         cur_fdm_state->_set_Euler_Angles( net->phi,
144                                           net->theta,
145                                           net->psi );
146         cur_fdm_state->_set_V_calibrated_kts( net->vcas );
147         cur_fdm_state->_set_Climb_Rate( net->climb_rate );
148
149         /* these are ignored for now  ... */
150         /*
151         if ( net->cur_time ) {
152             fgSetLong("/sim/time/cur-time-override", net->cur_time);
153         }
154
155         globals->set_warp( net->warp );
156         last_warp = net->warp;
157         */
158     } else {
159         SG_LOG( SG_IO, SG_ALERT, "Error: version mismatch in net2global()" );
160         SG_LOG( SG_IO, SG_ALERT,
161                 "\tread " << net->version << " need " << FG_NET_FDM_VERSION );
162         SG_LOG( SG_IO, SG_ALERT,
163                 "\tsomeone needs to upgrade net_fdm.hxx and recompile." );
164     }
165 }
166
167
168 FGExternalNet::FGExternalNet( double dt, int dop, int dip, int cp,
169                               string host )
170 {
171     set_delta_t( dt );
172
173     valid = true;
174
175     data_in_port = dip;
176     data_out_port = dop;
177     cmd_port = cp;
178     fdm_host = host;
179
180     /////////////////////////////////////////////////////////
181     // Setup client udp connection (sends data to remote fdm)
182
183     if ( ! data_client.open( false ) ) {
184         SG_LOG( SG_FLIGHT, SG_ALERT, "Error opening client data channel" );
185         valid = false;
186     }
187
188     // fire and forget
189     data_client.setBlocking( false );
190
191     if ( data_client.connect( fdm_host.c_str(), data_out_port ) == -1 ) {
192         printf("error connecting to %s:%d\n", fdm_host.c_str(), data_out_port);
193         valid = false;
194     }
195
196     /////////////////////////////////////////////////////////
197     // Setup server udp connection (for receiving data)
198
199     if ( ! data_server.open( false ) ) {
200         SG_LOG( SG_FLIGHT, SG_ALERT, "Error opening client server channel" );
201         valid = false;
202     }
203
204     // we want to block for incoming data in order to syncronize frame
205     // rates.
206     data_server.setBlocking( false /* don't block while testing */ );
207     // data_server.setBlocking( true /* don't block while testing */ );
208
209     // if we bind to fdm_host = "" then we accept messages from
210     // anyone.
211     if ( data_server.bind( fdm_host.c_str(), data_in_port ) == -1 ) {
212         printf("error binding to port %d\n", data_in_port);
213         valid = false;
214     }
215 }
216
217
218 FGExternalNet::~FGExternalNet() {
219     data_client.close();
220     data_server.close();
221 }
222
223
224 // Initialize the ExternalNet flight model, dt is the time increment
225 // for each subsequent iteration through the EOM
226 void FGExternalNet::init() {
227     // cout << "FGExternalNet::init()" << endl;
228
229     // Explicitly call the superclass's
230     // init method first.
231     common_init();
232
233     double lon = fgGetDouble( "/position/longitude-deg" );
234     double lat = fgGetDouble( "/position/latitude-deg" );
235     double ground = fgGetDouble( "/environment/ground-elevation-m" );
236     double heading = fgGetDouble("/orientation/heading-deg");
237
238     char cmd[256];
239
240     sprintf( cmd, "/longitude-deg?value=%.8f", lon );
241     new HTTPClient( fdm_host.c_str(), cmd_port, cmd );
242 //     cout << "before loop()" << endl;
243     netChannel::loop(0);
244 //     cout << "here" << endl;
245
246     sprintf( cmd, "/latitude-deg?value=%.8f", lat );
247     new HTTPClient( fdm_host.c_str(), cmd_port, cmd );
248     netChannel::loop(0);
249
250     sprintf( cmd, "/ground-m?value=%.8f", ground );
251     new HTTPClient( fdm_host.c_str(), cmd_port, cmd );
252     netChannel::loop(0);
253
254     sprintf( cmd, "/heading-deg?value=%.8f", heading );
255     new HTTPClient( fdm_host.c_str(), cmd_port, cmd );
256     netChannel::loop(0);
257
258     sprintf( cmd, "/reset?value=ground" );
259     new HTTPClient( fdm_host.c_str(), cmd_port, cmd );
260     netChannel::loop(0);
261 }
262
263
264 // Run an iteration of the EOM.  This is a NOP here because the flight
265 // model values are getting filled in elsewhere (most likely from some
266 // external source.)
267 void FGExternalNet::update( int multiloop ) {
268     int length;
269     int result;
270
271     // Send control positions to remote fdm
272     length = sizeof(ctrls);
273     global2raw( &ctrls );
274     if ( data_client.send( (char *)(& ctrls), length, 0 ) != length ) {
275         SG_LOG( SG_IO, SG_ALERT, "Error writing data." );
276     }
277
278     // Read next set of FDM data (blocking enabled to maintain 'sync')
279     length = sizeof(fdm);
280     if ( (result = data_server.recv( (char *)(& fdm), length, 0)) >= 0 ) {
281         SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
282         net2global( &fdm );
283     }
284 }