]> git.mxchange.org Git - flightgear.git/blob - src/Network/native_gui.cxx
Merge branch 'work4' into next
[flightgear.git] / src / Network / native_gui.cxx
1 // native_gui.cxx -- FGFS external gui data export class
2 //
3 // Written by Curtis Olson, started January 2002.
4 //
5 // Copyright (C) 2002  Curtis L. Olson - http://www.flightgear.org/~curt
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <simgear/debug/logstream.hxx>
29 #include <simgear/io/lowlevel.hxx> // endian tests
30 #include <simgear/io/iochannel.hxx>
31 #include <simgear/timing/sg_time.hxx>
32
33 #include <Time/tmp.hxx>
34 #include <Main/fg_props.hxx>
35 #include <Main/globals.hxx>
36 #include <Scenery/scenery.hxx>
37 #include <FDM/flightProperties.hxx>
38
39 #include "native_gui.hxx"
40
41 // FreeBSD works better with this included last ... (?)
42 #if defined( _MSC_VER )
43 #  include <windows.h>
44 #elif defined( __MINGW32__ )
45 #  include <winsock2.h>
46 #else
47 #  include <netinet/in.h>       // htonl() ntohl()
48 #endif
49
50
51 // #define FG_USE_NETWORK_BYTE_ORDER
52 #if defined( FG_USE_NETWORK_BYTE_ORDER )
53
54 // The function htond is defined this way due to the way some
55 // processors and OSes treat floating point values.  Some will raise
56 // an exception whenever a "bad" floating point value is loaded into a
57 // floating point register.  Solaris is notorious for this, but then
58 // so is LynxOS on the PowerPC.  By translating the data in place,
59 // there is no need to load a FP register with the "corruped" floating
60 // point value.  By doing the BIG_ENDIAN test, I can optimize the
61 // routine for big-endian processors so it can be as efficient as
62 // possible
63 static void htond (double &x)   
64 {
65     if ( sgIsLittleEndian() ) {
66         int    *Double_Overlay;
67         int     Holding_Buffer;
68     
69         Double_Overlay = (int *) &x;
70         Holding_Buffer = Double_Overlay [0];
71     
72         Double_Overlay [0] = htonl (Double_Overlay [1]);
73         Double_Overlay [1] = htonl (Holding_Buffer);
74     } else {
75         return;
76     }
77 }
78 static void htonf (float &x)    
79 {
80     if ( sgIsLittleEndian() ) {
81         int    *Float_Overlay;
82         int     Holding_Buffer;
83     
84         Float_Overlay = (int *) &x;
85         Holding_Buffer = Float_Overlay [0];
86     
87         Float_Overlay [0] = htonl (Holding_Buffer);
88     } else {
89         return;
90     }
91 }
92 #endif
93
94
95 FGNativeGUI::FGNativeGUI() {
96 }
97
98 FGNativeGUI::~FGNativeGUI() {
99 }
100
101
102 // open hailing frequencies
103 bool FGNativeGUI::open() {
104     if ( is_enabled() ) {
105         SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel " 
106                 << "is already in use, ignoring" );
107         return false;
108     }
109
110     SGIOChannel *io = get_io_channel();
111
112     if ( ! io->open( get_direction() ) ) {
113         SG_LOG( SG_IO, SG_ALERT, "Error opening channel communication layer." );
114         return false;
115     }
116
117     set_enabled( true );
118
119     fgSetDouble("/position/sea-level-radius-ft", SG_EQUATORIAL_RADIUS_FT);
120     return true;
121 }
122
123
124 void FGProps2NetGUI( FGNetGUI *net ) {
125     static SGPropertyNode *nav_freq
126         = fgGetNode("/instrumentation/nav/frequencies/selected-mhz", true);
127     static SGPropertyNode *nav_target_radial
128         = fgGetNode("/instrumentation/nav/radials/target-radial-deg", true);
129     static SGPropertyNode *nav_inrange
130         = fgGetNode("/instrumentation/nav/in-range", true);
131     static SGPropertyNode *nav_loc
132         = fgGetNode("/instrumentation/nav/nav-loc", true);
133     static SGPropertyNode *nav_gs_dist_signed
134         = fgGetNode("/instrumentation/nav/gs-distance", true);
135     static SGPropertyNode *nav_loc_dist
136         = fgGetNode("/instrumentation/nav/nav-distance", true);
137     static SGPropertyNode *nav_reciprocal_radial
138         = fgGetNode("/instrumentation/nav/radials/reciprocal-radial-deg", true);
139     static SGPropertyNode *nav_gs_deflection
140         = fgGetNode("/instrumentation/nav/gs-needle-deflection", true);
141     unsigned int i;
142
143     static FlightProperties* fdm_state = new FlightProperties;
144
145     // Version sanity checking
146     net->version = FG_NET_GUI_VERSION;
147
148     // Aero parameters
149     net->longitude = fdm_state->get_Longitude();
150     net->latitude = fdm_state->get_Latitude();
151     net->altitude = fdm_state->get_Altitude() * SG_FEET_TO_METER;
152     net->phi = fdm_state->get_Phi();
153     net->theta = fdm_state->get_Theta();
154     net->psi = fdm_state->get_Psi();
155
156     // Velocities
157     net->vcas = fdm_state->get_V_calibrated_kts();
158     net->climb_rate = fdm_state->get_Climb_Rate();
159
160     // Consumables
161     net->num_tanks = FGNetGUI::FG_MAX_TANKS;
162     for ( i = 0; i < net->num_tanks; ++i ) {
163         SGPropertyNode *node = fgGetNode("/consumables/fuel/tank", i, true);
164         net->fuel_quantity[i] = node->getDoubleValue("level-gal_us");
165     }
166
167     // Environment
168     net->cur_time = globals->get_time_params()->get_cur_time();
169     net->warp = globals->get_warp();
170     net->ground_elev = fdm_state->get_Runway_altitude_m();
171
172     // Approach
173     net->tuned_freq = nav_freq->getDoubleValue();
174     net->nav_radial = nav_target_radial->getDoubleValue();
175     net->in_range = nav_inrange->getBoolValue();
176
177     if ( nav_loc->getBoolValue() ) {
178         // is an ILS
179         net->dist_nm
180             = nav_gs_dist_signed->getDoubleValue()
181               * SG_METER_TO_NM;
182     } else {
183         // is a VOR
184         net->dist_nm = nav_loc_dist->getDoubleValue()
185             * SG_METER_TO_NM;
186     }
187
188     net->course_deviation_deg
189         = nav_reciprocal_radial->getDoubleValue()
190         - nav_target_radial->getDoubleValue();
191
192     if ( net->course_deviation_deg < -1000.0 
193          || net->course_deviation_deg > 1000.0 )
194     {
195         // Sanity check ...
196         net->course_deviation_deg = 0.0;
197     }
198     while ( net->course_deviation_deg >  180.0 ) {
199         net->course_deviation_deg -= 360.0;
200     }
201     while ( net->course_deviation_deg < -180.0 ) {
202         net->course_deviation_deg += 360.0;
203     }
204     if ( fabs(net->course_deviation_deg) > 90.0 )
205         net->course_deviation_deg
206             = ( net->course_deviation_deg<0.0
207                 ? -net->course_deviation_deg - 180.0
208                 : -net->course_deviation_deg + 180.0 );
209
210     if ( nav_loc->getBoolValue() ) {
211         // is an ILS
212         net->gs_deviation_deg
213             = nav_gs_deflection->getDoubleValue()
214             / 5.0;
215     } else {
216         // is an ILS
217         net->gs_deviation_deg = -9999.0;
218     }
219
220 #if defined( FG_USE_NETWORK_BYTE_ORDER )
221     // Convert the net buffer to network format
222     net->version = htonl(net->version);
223
224     htond(net->longitude);
225     htond(net->latitude);
226     htonf(net->altitude);
227     htonf(net->phi);
228     htonf(net->theta);
229     htonf(net->psi);
230     htonf(net->vcas);
231     htonf(net->climb_rate);
232
233     for ( i = 0; i < net->num_tanks; ++i ) {
234         htonf(net->fuel_quantity[i]);
235     }
236     net->num_tanks = htonl(net->num_tanks);
237
238     net->cur_time = htonl( net->cur_time );
239     net->warp = htonl( net->warp );
240     net->ground_elev = htonl( net->ground_elev );
241
242     htonf(net->tuned_freq);
243     htonf(net->nav_radial);
244     net->in_range = htonl( net->in_range );
245     htonf(net->dist_nm);
246     htonf(net->course_deviation_deg);
247     htonf(net->gs_deviation_deg);
248 #endif
249 }
250
251
252 void FGNetGUI2Props( FGNetGUI *net ) {
253     unsigned int i;
254
255 #if defined( FG_USE_NETWORK_BYTE_ORDER )
256     // Convert to the net buffer from network format
257     net->version = ntohl(net->version);
258
259     htond(net->longitude);
260     htond(net->latitude);
261     htonf(net->altitude);
262     htonf(net->phi);
263     htonf(net->theta);
264     htonf(net->psi);
265     htonf(net->vcas);
266     htonf(net->climb_rate);
267
268     net->num_tanks = htonl(net->num_tanks);
269     for ( i = 0; i < net->num_tanks; ++i ) {
270         htonf(net->fuel_quantity[i]);
271     }
272
273     net->cur_time = ntohl(net->cur_time);
274     net->warp = ntohl(net->warp);
275     net->ground_elev = htonl( net->ground_elev );
276
277     htonf(net->tuned_freq);
278     htonf(net->nav_radial);
279     net->in_range = htonl( net->in_range );
280     htonf(net->dist_nm);
281     htonf(net->course_deviation_deg);
282     htonf(net->gs_deviation_deg);
283 #endif
284
285     if ( net->version == FG_NET_GUI_VERSION ) {
286         FlightProperties fdm_state;
287         
288         // cout << "pos = " << net->longitude << " " << net->latitude << endl;
289         // cout << "sea level rad = " << fdm_state->get_Sea_level_radius()
290         //      << endl;
291   
292         fdm_state.set_Latitude(net->latitude);
293         fdm_state.set_Longitude(net->longitude);
294         fdm_state.set_Altitude(net->altitude * SG_METER_TO_FEET);
295
296         fdm_state.set_Euler_Angles( net->phi,
297                                           net->theta,
298                                           net->psi );
299
300         fdm_state.set_V_calibrated_kts( net->vcas );
301         fdm_state.set_Climb_Rate( net->climb_rate );
302
303         for (i = 0; i < net->num_tanks; ++i ) {
304             SGPropertyNode * node
305                 = fgGetNode("/consumables/fuel/tank", i, true);
306             node->setDoubleValue("level-gal_us", net->fuel_quantity[i] );
307         }
308
309         if ( net->cur_time ) {
310             fgSetLong("/sim/time/cur-time-override", net->cur_time);
311         }
312
313         globals->set_warp( net->warp );
314
315         // Approach
316         fgSetDouble( "/instrumentation/nav[0]/frequencies/selected-mhz",
317                      net->tuned_freq );
318         fgSetBool( "/instrumentation/nav[0]/in-range", net->in_range );
319         fgSetDouble( "/instrumentation/dme/indicated-distance-nm", net->dist_nm );
320         fgSetDouble( "/instrumentation/nav[0]/heading-needle-deflection",
321                      net->course_deviation_deg );
322         fgSetDouble( "/instrumentation/nav[0]/gs-needle-deflection",
323                      net->gs_deviation_deg );
324     } else {
325         SG_LOG( SG_IO, SG_ALERT,
326                 "Error: version mismatch in FGNetNativeGUI2Props()" );
327         SG_LOG( SG_IO, SG_ALERT,
328                 "\tread " << net->version << " need " << FG_NET_GUI_VERSION );
329         SG_LOG( SG_IO, SG_ALERT,
330                 "\tNeed to upgrade net_fdm.hxx and recompile." );
331     }
332 }
333
334
335 // process work for this port
336 bool FGNativeGUI::process() {
337     SGIOChannel *io = get_io_channel();
338     int length = sizeof(buf);
339
340     if ( get_direction() == SG_IO_OUT ) {
341         // cout << "size of fdm_state = " << length << endl;
342         FGProps2NetGUI( &buf );
343         if ( ! io->write( (char *)(& buf), length ) ) {
344             SG_LOG( SG_IO, SG_ALERT, "Error writing data." );
345             return false;
346         }
347     } else if ( get_direction() == SG_IO_IN ) {
348         if ( io->get_type() == sgFileType ) {
349             if ( io->read( (char *)(& buf), length ) == length ) {
350                 SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
351                 FGNetGUI2Props( &buf );
352             }
353         } else {
354             while ( io->read( (char *)(& buf), length ) == length ) {
355                 SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
356                 FGNetGUI2Props( &buf );
357             }
358         }
359     }
360
361     return true;
362 }
363
364
365 // close the channel
366 bool FGNativeGUI::close() {
367     SGIOChannel *io = get_io_channel();
368
369     set_enabled( false );
370
371     if ( ! io->close() ) {
372         return false;
373     }
374
375     return true;
376 }