634e79353f
I've finished the emigration of the radiostack, and I've also removed it completely. It turned out that the comm radio is completely implemented in the ATC subsystem. I've changed the affected ATC files to point to /instrumentation/com, but I guess that the maintainer of the ATC code should decide wether to make it configureable, and how. I also had to change some files in Network and Main. The changes in network should be obvious, but the changes in Main were a bit suspect. The files included radiostack.hxx, but they weren't directly depending on radiostack-hxx. They were depending on other files that were included by radiostack.hxx. I got it to compile, but I'm not sure if I included the correct directly depending file. For the data directory I changed every occurrence of /radios/ with /instrumentation/ with this simple one-liner that I found on the net: find -name '*.xml' -type f | xargs perl -pi -e 's/\/radios\//\/instrumentation\//g' Instead of me sending all the files that got changed by this I suggest that you execute the one-liner yourself. Of course I can not guarantee that this will work perfectly, but I considered hand editing to be not an option (I'm lazy). I don't want to test every aircraft to see if everything still works, I think it's better to wait and see if anyone complaints about broken nav radios/instruments.
369 lines
11 KiB
C++
369 lines
11 KiB
C++
// native_gui.cxx -- FGFS external gui data export class
|
|
//
|
|
// Written by Curtis Olson, started January 2002.
|
|
//
|
|
// Copyright (C) 2002 Curtis L. Olson - http://www.flightgear.org/~curt
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License as
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
//
|
|
// $Id$
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <simgear/debug/logstream.hxx>
|
|
#include <simgear/io/lowlevel.hxx> // endian tests
|
|
#include <simgear/io/iochannel.hxx>
|
|
#include <simgear/timing/sg_time.hxx>
|
|
|
|
#include <FDM/flight.hxx>
|
|
#include <Time/tmp.hxx>
|
|
#include <Main/fg_props.hxx>
|
|
#include <Main/globals.hxx>
|
|
#include <Scenery/scenery.hxx>
|
|
|
|
#include "native_gui.hxx"
|
|
|
|
// FreeBSD works better with this included last ... (?)
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
# include <windows.h>
|
|
#else
|
|
# include <netinet/in.h> // htonl() ntohl()
|
|
#endif
|
|
|
|
|
|
// #define FG_USE_NETWORK_BYTE_ORDER
|
|
#if defined( FG_USE_NETWORK_BYTE_ORDER )
|
|
|
|
// The function htond is defined this way due to the way some
|
|
// processors and OSes treat floating point values. Some will raise
|
|
// an exception whenever a "bad" floating point value is loaded into a
|
|
// floating point register. Solaris is notorious for this, but then
|
|
// so is LynxOS on the PowerPC. By translating the data in place,
|
|
// there is no need to load a FP register with the "corruped" floating
|
|
// point value. By doing the BIG_ENDIAN test, I can optimize the
|
|
// routine for big-endian processors so it can be as efficient as
|
|
// possible
|
|
static void htond (double &x)
|
|
{
|
|
if ( sgIsLittleEndian() ) {
|
|
int *Double_Overlay;
|
|
int Holding_Buffer;
|
|
|
|
Double_Overlay = (int *) &x;
|
|
Holding_Buffer = Double_Overlay [0];
|
|
|
|
Double_Overlay [0] = htonl (Double_Overlay [1]);
|
|
Double_Overlay [1] = htonl (Holding_Buffer);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
static void htonf (float &x)
|
|
{
|
|
if ( sgIsLittleEndian() ) {
|
|
int *Float_Overlay;
|
|
int Holding_Buffer;
|
|
|
|
Float_Overlay = (int *) &x;
|
|
Holding_Buffer = Float_Overlay [0];
|
|
|
|
Float_Overlay [0] = htonl (Holding_Buffer);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
FGNativeGUI::FGNativeGUI() {
|
|
}
|
|
|
|
FGNativeGUI::~FGNativeGUI() {
|
|
}
|
|
|
|
|
|
// open hailing frequencies
|
|
bool FGNativeGUI::open() {
|
|
if ( is_enabled() ) {
|
|
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
|
|
<< "is already in use, ignoring" );
|
|
return false;
|
|
}
|
|
|
|
SGIOChannel *io = get_io_channel();
|
|
|
|
if ( ! io->open( get_direction() ) ) {
|
|
SG_LOG( SG_IO, SG_ALERT, "Error opening channel communication layer." );
|
|
return false;
|
|
}
|
|
|
|
set_enabled( true );
|
|
|
|
cur_fdm_state->_set_Sea_level_radius( SG_EQUATORIAL_RADIUS_FT );
|
|
return true;
|
|
}
|
|
|
|
|
|
void FGProps2NetGUI( FGNetGUI *net ) {
|
|
static SGPropertyNode *nav_freq
|
|
= fgGetNode("/instrumentation/nav/frequencies/selected-mhz", false);
|
|
static SGPropertyNode *nav_target_radial
|
|
= fgGetNode("/instrumentation/nav/radials/target-radial2-deg", false);
|
|
static SGPropertyNode *nav_inrange
|
|
= fgGetNode("instrumentation/nav/in-range", false);
|
|
static SGPropertyNode *nav_loc
|
|
= fgGetNode("instrumentation/nav/nav-loc", false);
|
|
static SGPropertyNode *nav_gs_dist_signed
|
|
= fgGetNode("instrumentation/nav/gs-distance", false);
|
|
static SGPropertyNode *nav_loc_dist
|
|
= fgGetNode("instrumentation/nav/nav-distance", false);
|
|
static SGPropertyNode *nav_reciprocal_radial
|
|
= fgGetNode("instrumentation/nav/reciprocal-radial-deg", false);
|
|
static SGPropertyNode *nav_gs_deflection
|
|
= fgGetNode("instrumentation/nav/gs-needle-deflection", false);
|
|
int i;
|
|
|
|
// Version sanity checking
|
|
net->version = FG_NET_GUI_VERSION;
|
|
|
|
// Aero parameters
|
|
net->longitude = cur_fdm_state->get_Longitude();
|
|
net->latitude = cur_fdm_state->get_Latitude();
|
|
net->altitude = cur_fdm_state->get_Altitude() * SG_FEET_TO_METER;
|
|
net->phi = cur_fdm_state->get_Phi();
|
|
net->theta = cur_fdm_state->get_Theta();
|
|
net->psi = cur_fdm_state->get_Psi();
|
|
|
|
// Velocities
|
|
net->vcas = cur_fdm_state->get_V_calibrated_kts();
|
|
net->climb_rate = cur_fdm_state->get_Climb_Rate();
|
|
|
|
// Consumables
|
|
net->num_tanks = FGNetGUI::FG_MAX_TANKS;
|
|
for ( i = 0; i < net->num_tanks; ++i ) {
|
|
SGPropertyNode *node = fgGetNode("/consumables/fuel/tank", i, true);
|
|
net->fuel_quantity[i] = node->getDoubleValue("level-gal_us");
|
|
}
|
|
|
|
// Environment
|
|
net->cur_time = globals->get_time_params()->get_cur_time();
|
|
net->warp = globals->get_warp();
|
|
net->ground_elev = globals->get_scenery()->get_cur_elev();
|
|
|
|
// Approach
|
|
net->tuned_freq = nav_freq->getDoubleValue();
|
|
net->nav_radial = nav_target_radial->getDoubleValue();
|
|
net->in_range = nav_inrange->getBoolValue();
|
|
|
|
if ( nav_loc->getBoolValue() ) {
|
|
// is an ILS
|
|
net->dist_nm
|
|
= nav_gs_dist_signed->getDoubleValue()
|
|
* SG_METER_TO_NM;
|
|
} else {
|
|
// is a VOR
|
|
net->dist_nm = nav_loc_dist->getDoubleValue()
|
|
* SG_METER_TO_NM;
|
|
}
|
|
|
|
net->course_deviation_deg
|
|
= nav_reciprocal_radial->getDoubleValue()
|
|
- nav_target_radial->getDoubleValue();
|
|
|
|
if ( net->course_deviation_deg < -1000.0
|
|
|| net->course_deviation_deg > 1000.0 )
|
|
{
|
|
// Sanity check ...
|
|
net->course_deviation_deg = 0.0;
|
|
}
|
|
while ( net->course_deviation_deg > 180.0 ) {
|
|
net->course_deviation_deg -= 360.0;
|
|
}
|
|
while ( net->course_deviation_deg < -180.0 ) {
|
|
net->course_deviation_deg += 360.0;
|
|
}
|
|
if ( fabs(net->course_deviation_deg) > 90.0 )
|
|
net->course_deviation_deg
|
|
= ( net->course_deviation_deg<0.0
|
|
? -net->course_deviation_deg - 180.0
|
|
: -net->course_deviation_deg + 180.0 );
|
|
|
|
if ( nav_loc->getBoolValue() ) {
|
|
// is an ILS
|
|
net->gs_deviation_deg
|
|
= nav_gs_deflection->getDoubleValue()
|
|
/ 5.0;
|
|
} else {
|
|
// is an ILS
|
|
net->gs_deviation_deg = -9999.0;
|
|
}
|
|
|
|
#if defined( FG_USE_NETWORK_BYTE_ORDER )
|
|
// Convert the net buffer to network format
|
|
net->version = htonl(net->version);
|
|
|
|
htond(net->longitude);
|
|
htond(net->latitude);
|
|
htonf(net->altitude);
|
|
htonf(net->phi);
|
|
htonf(net->theta);
|
|
htonf(net->psi);
|
|
htonf(net->vcas);
|
|
htonf(net->climb_rate);
|
|
|
|
for ( i = 0; i < net->num_tanks; ++i ) {
|
|
htonf(net->fuel_quantity[i]);
|
|
}
|
|
net->num_tanks = htonl(net->num_tanks);
|
|
|
|
net->cur_time = htonl( net->cur_time );
|
|
net->warp = htonl( net->warp );
|
|
net->ground_elev = htonl( net->ground_elev );
|
|
|
|
htonf(net->tuned_freq);
|
|
htonf(net->nav_radial);
|
|
net->in_range = htonl(net->in_range);
|
|
htonf(net->dist_nm);
|
|
htonf(net->course_deviation_deg);
|
|
htonf(net->gs_deviation_deg);
|
|
#endif
|
|
}
|
|
|
|
|
|
void FGNetGUI2Props( FGNetGUI *net ) {
|
|
int i;
|
|
|
|
#if defined( FG_USE_NETWORK_BYTE_ORDER )
|
|
// Convert to the net buffer from network format
|
|
net->version = ntohl(net->version);
|
|
|
|
htond(net->longitude);
|
|
htond(net->latitude);
|
|
htonf(net->altitude);
|
|
htonf(net->phi);
|
|
htonf(net->theta);
|
|
htonf(net->psi);
|
|
htonf(net->vcas);
|
|
htonf(net->climb_rate);
|
|
|
|
net->num_tanks = htonl(net->num_tanks);
|
|
for ( i = 0; i < net->num_tanks; ++i ) {
|
|
htonf(net->fuel_quantity[i]);
|
|
}
|
|
|
|
net->cur_time = ntohl(net->cur_time);
|
|
net->warp = ntohl(net->warp);
|
|
net->ground_elev = htonl( net->ground_elev );
|
|
|
|
htonf(net->tuned_freq);
|
|
net->in_range = htonl(net->in_range);
|
|
htonf(net->dist_nm);
|
|
htonf(net->course_deviation_deg);
|
|
htonf(net->gs_deviation_deg);
|
|
#endif
|
|
|
|
if ( net->version == FG_NET_GUI_VERSION ) {
|
|
// cout << "pos = " << net->longitude << " " << net->latitude << endl;
|
|
// cout << "sea level rad = " << cur_fdm_state->get_Sea_level_radius()
|
|
// << endl;
|
|
cur_fdm_state->_updateGeodeticPosition( net->latitude,
|
|
net->longitude,
|
|
net->altitude
|
|
* SG_METER_TO_FEET );
|
|
cur_fdm_state->_set_Euler_Angles( net->phi,
|
|
net->theta,
|
|
net->psi );
|
|
|
|
cur_fdm_state->_set_V_calibrated_kts( net->vcas );
|
|
cur_fdm_state->_set_Climb_Rate( net->climb_rate );
|
|
|
|
for (i = 0; i < net->num_tanks; ++i ) {
|
|
SGPropertyNode * node
|
|
= fgGetNode("/consumables/fuel/tank", i, true);
|
|
node->setDoubleValue("level-gal_us", net->fuel_quantity[i] );
|
|
}
|
|
|
|
if ( net->cur_time ) {
|
|
fgSetLong("/sim/time/cur-time-override", net->cur_time);
|
|
}
|
|
|
|
globals->set_warp( net->warp );
|
|
globals->get_scenery()->set_cur_elev( net->ground_elev );
|
|
|
|
// Approach
|
|
fgSetDouble( "/radios/nav[0]/frequencies/selected-mhz",
|
|
net->tuned_freq );
|
|
fgSetBool( "/radios/nav[0]/in-range", net->in_range );
|
|
fgSetDouble( "/radios/dme/distance-nm", net->dist_nm );
|
|
fgSetDouble( "/radios/nav[0]/heading-needle-deflection",
|
|
net->course_deviation_deg );
|
|
fgSetDouble( "/radios/nav[0]/gs-needle-deflection",
|
|
net->gs_deviation_deg );
|
|
} else {
|
|
SG_LOG( SG_IO, SG_ALERT,
|
|
"Error: version mismatch in FGNetNativeGUI2Props()" );
|
|
SG_LOG( SG_IO, SG_ALERT,
|
|
"\tread " << net->version << " need " << FG_NET_GUI_VERSION );
|
|
SG_LOG( SG_IO, SG_ALERT,
|
|
"\tNeed to upgrade net_fdm.hxx and recompile." );
|
|
}
|
|
}
|
|
|
|
|
|
// process work for this port
|
|
bool FGNativeGUI::process() {
|
|
SGIOChannel *io = get_io_channel();
|
|
int length = sizeof(buf);
|
|
|
|
if ( get_direction() == SG_IO_OUT ) {
|
|
// cout << "size of cur_fdm_state = " << length << endl;
|
|
FGProps2NetGUI( &buf );
|
|
if ( ! io->write( (char *)(& buf), length ) ) {
|
|
SG_LOG( SG_IO, SG_ALERT, "Error writing data." );
|
|
return false;
|
|
}
|
|
} else if ( get_direction() == SG_IO_IN ) {
|
|
if ( io->get_type() == sgFileType ) {
|
|
if ( io->read( (char *)(& buf), length ) == length ) {
|
|
SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
|
|
FGNetGUI2Props( &buf );
|
|
}
|
|
} else {
|
|
while ( io->read( (char *)(& buf), length ) == length ) {
|
|
SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
|
|
FGNetGUI2Props( &buf );
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// close the channel
|
|
bool FGNativeGUI::close() {
|
|
SGIOChannel *io = get_io_channel();
|
|
|
|
set_enabled( false );
|
|
|
|
if ( ! io->close() ) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|