]> git.mxchange.org Git - flightgear.git/blob - src/Network/native_gui.cxx
Merge branch 'jmt/track-bug' 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 <FDM/flight.hxx>
34 #include <Time/tmp.hxx>
35 #include <Main/fg_props.hxx>
36 #include <Main/globals.hxx>
37 #include <Scenery/scenery.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     cur_fdm_state->_set_Sea_level_radius( 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     // Version sanity checking
144     net->version = FG_NET_GUI_VERSION;
145
146     // Aero parameters
147     net->longitude = cur_fdm_state->get_Longitude();
148     net->latitude = cur_fdm_state->get_Latitude();
149     net->altitude = cur_fdm_state->get_Altitude() * SG_FEET_TO_METER;
150     net->phi = cur_fdm_state->get_Phi();
151     net->theta = cur_fdm_state->get_Theta();
152     net->psi = cur_fdm_state->get_Psi();
153
154     // Velocities
155     net->vcas = cur_fdm_state->get_V_calibrated_kts();
156     net->climb_rate = cur_fdm_state->get_Climb_Rate();
157
158     // Consumables
159     net->num_tanks = FGNetGUI::FG_MAX_TANKS;
160     for ( i = 0; i < net->num_tanks; ++i ) {
161         SGPropertyNode *node = fgGetNode("/consumables/fuel/tank", i, true);
162         net->fuel_quantity[i] = node->getDoubleValue("level-gal_us");
163     }
164
165     // Environment
166     net->cur_time = globals->get_time_params()->get_cur_time();
167     net->warp = globals->get_warp();
168     net->ground_elev = cur_fdm_state->get_Runway_altitude_m();
169
170     // Approach
171     net->tuned_freq = nav_freq->getDoubleValue();
172     net->nav_radial = nav_target_radial->getDoubleValue();
173     net->in_range = nav_inrange->getBoolValue();
174
175     if ( nav_loc->getBoolValue() ) {
176         // is an ILS
177         net->dist_nm
178             = nav_gs_dist_signed->getDoubleValue()
179               * SG_METER_TO_NM;
180     } else {
181         // is a VOR
182         net->dist_nm = nav_loc_dist->getDoubleValue()
183             * SG_METER_TO_NM;
184     }
185
186     net->course_deviation_deg
187         = nav_reciprocal_radial->getDoubleValue()
188         - nav_target_radial->getDoubleValue();
189
190     if ( net->course_deviation_deg < -1000.0 
191          || net->course_deviation_deg > 1000.0 )
192     {
193         // Sanity check ...
194         net->course_deviation_deg = 0.0;
195     }
196     while ( net->course_deviation_deg >  180.0 ) {
197         net->course_deviation_deg -= 360.0;
198     }
199     while ( net->course_deviation_deg < -180.0 ) {
200         net->course_deviation_deg += 360.0;
201     }
202     if ( fabs(net->course_deviation_deg) > 90.0 )
203         net->course_deviation_deg
204             = ( net->course_deviation_deg<0.0
205                 ? -net->course_deviation_deg - 180.0
206                 : -net->course_deviation_deg + 180.0 );
207
208     if ( nav_loc->getBoolValue() ) {
209         // is an ILS
210         net->gs_deviation_deg
211             = nav_gs_deflection->getDoubleValue()
212             / 5.0;
213     } else {
214         // is an ILS
215         net->gs_deviation_deg = -9999.0;
216     }
217
218 #if defined( FG_USE_NETWORK_BYTE_ORDER )
219     // Convert the net buffer to network format
220     net->version = htonl(net->version);
221
222     htond(net->longitude);
223     htond(net->latitude);
224     htonf(net->altitude);
225     htonf(net->phi);
226     htonf(net->theta);
227     htonf(net->psi);
228     htonf(net->vcas);
229     htonf(net->climb_rate);
230
231     for ( i = 0; i < net->num_tanks; ++i ) {
232         htonf(net->fuel_quantity[i]);
233     }
234     net->num_tanks = htonl(net->num_tanks);
235
236     net->cur_time = htonl( net->cur_time );
237     net->warp = htonl( net->warp );
238     net->ground_elev = htonl( net->ground_elev );
239
240     htonf(net->tuned_freq);
241     htonf(net->nav_radial);
242     net->in_range = htonl( net->in_range );
243     htonf(net->dist_nm);
244     htonf(net->course_deviation_deg);
245     htonf(net->gs_deviation_deg);
246 #endif
247 }
248
249
250 void FGNetGUI2Props( FGNetGUI *net ) {
251     unsigned int i;
252
253 #if defined( FG_USE_NETWORK_BYTE_ORDER )
254     // Convert to the net buffer from network format
255     net->version = ntohl(net->version);
256
257     htond(net->longitude);
258     htond(net->latitude);
259     htonf(net->altitude);
260     htonf(net->phi);
261     htonf(net->theta);
262     htonf(net->psi);
263     htonf(net->vcas);
264     htonf(net->climb_rate);
265
266     net->num_tanks = htonl(net->num_tanks);
267     for ( i = 0; i < net->num_tanks; ++i ) {
268         htonf(net->fuel_quantity[i]);
269     }
270
271     net->cur_time = ntohl(net->cur_time);
272     net->warp = ntohl(net->warp);
273     net->ground_elev = htonl( net->ground_elev );
274
275     htonf(net->tuned_freq);
276     htonf(net->nav_radial);
277     net->in_range = htonl( net->in_range );
278     htonf(net->dist_nm);
279     htonf(net->course_deviation_deg);
280     htonf(net->gs_deviation_deg);
281 #endif
282
283     if ( net->version == FG_NET_GUI_VERSION ) {
284         // cout << "pos = " << net->longitude << " " << net->latitude << endl;
285         // cout << "sea level rad = " << cur_fdm_state->get_Sea_level_radius()
286         //      << endl;
287         cur_fdm_state->_updateGeodeticPosition( net->latitude,
288                                                 net->longitude,
289                                                 net->altitude
290                                                   * SG_METER_TO_FEET );
291         cur_fdm_state->_set_Euler_Angles( net->phi,
292                                           net->theta,
293                                           net->psi );
294
295         cur_fdm_state->_set_V_calibrated_kts( net->vcas );
296         cur_fdm_state->_set_Climb_Rate( net->climb_rate );
297
298         for (i = 0; i < net->num_tanks; ++i ) {
299             SGPropertyNode * node
300                 = fgGetNode("/consumables/fuel/tank", i, true);
301             node->setDoubleValue("level-gal_us", net->fuel_quantity[i] );
302         }
303
304         if ( net->cur_time ) {
305             fgSetLong("/sim/time/cur-time-override", net->cur_time);
306         }
307
308         globals->set_warp( net->warp );
309
310         // Approach
311         fgSetDouble( "/instrumentation/nav[0]/frequencies/selected-mhz",
312                      net->tuned_freq );
313         fgSetBool( "/instrumentation/nav[0]/in-range", net->in_range );
314         fgSetDouble( "/instrumentation/dme/indicated-distance-nm", net->dist_nm );
315         fgSetDouble( "/instrumentation/nav[0]/heading-needle-deflection",
316                      net->course_deviation_deg );
317         fgSetDouble( "/instrumentation/nav[0]/gs-needle-deflection",
318                      net->gs_deviation_deg );
319     } else {
320         SG_LOG( SG_IO, SG_ALERT,
321                 "Error: version mismatch in FGNetNativeGUI2Props()" );
322         SG_LOG( SG_IO, SG_ALERT,
323                 "\tread " << net->version << " need " << FG_NET_GUI_VERSION );
324         SG_LOG( SG_IO, SG_ALERT,
325                 "\tNeed to upgrade net_fdm.hxx and recompile." );
326     }
327 }
328
329
330 // process work for this port
331 bool FGNativeGUI::process() {
332     SGIOChannel *io = get_io_channel();
333     int length = sizeof(buf);
334
335     if ( get_direction() == SG_IO_OUT ) {
336         // cout << "size of cur_fdm_state = " << length << endl;
337         FGProps2NetGUI( &buf );
338         if ( ! io->write( (char *)(& buf), length ) ) {
339             SG_LOG( SG_IO, SG_ALERT, "Error writing data." );
340             return false;
341         }
342     } else if ( get_direction() == SG_IO_IN ) {
343         if ( io->get_type() == sgFileType ) {
344             if ( io->read( (char *)(& buf), length ) == length ) {
345                 SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
346                 FGNetGUI2Props( &buf );
347             }
348         } else {
349             while ( io->read( (char *)(& buf), length ) == length ) {
350                 SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
351                 FGNetGUI2Props( &buf );
352             }
353         }
354     }
355
356     return true;
357 }
358
359
360 // close the channel
361 bool FGNativeGUI::close() {
362     SGIOChannel *io = get_io_channel();
363
364     set_enabled( false );
365
366     if ( ! io->close() ) {
367         return false;
368     }
369
370     return true;
371 }