2000-03-21 20:51:03 +00:00
|
|
|
|
// steam.cxx - Steam Gauge Calculations
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 2000 Alexander Perry - alex.perry@ieee.org
|
|
|
|
|
//
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
|
|
#if defined( FG_HAVE_NATIVE_SGI_COMPILERS )
|
|
|
|
|
# include <iostream.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <iostream>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <simgear/constants.h>
|
2000-09-26 23:39:29 +00:00
|
|
|
|
#include <simgear/math/sg_types.hxx>
|
2000-09-06 00:07:48 +00:00
|
|
|
|
#include <simgear/misc/props.hxx>
|
2000-05-02 19:41:35 +00:00
|
|
|
|
#include <Aircraft/aircraft.hxx>
|
2000-03-21 20:51:03 +00:00
|
|
|
|
#include <Main/bfi.hxx>
|
2000-05-02 19:41:35 +00:00
|
|
|
|
#include <NetworkOLK/features.hxx>
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
|
|
|
|
FG_USING_NAMESPACE(std);
|
|
|
|
|
|
2000-04-25 03:09:26 +00:00
|
|
|
|
#include "radiostack.hxx"
|
2000-03-21 20:51:03 +00:00
|
|
|
|
#include "steam.hxx"
|
|
|
|
|
|
2000-09-06 00:07:48 +00:00
|
|
|
|
static bool isTied = false;
|
|
|
|
|
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Declare the functions that read the variables
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Anything that reads the BFI directly is not implemented at all!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double FGSteam::the_STATIC_inhg = 29.92;
|
2001-01-23 07:17:47 +00:00
|
|
|
|
double FGSteam::the_ALT_ft = 0.0; // Indicated altitude
|
2000-03-21 20:51:03 +00:00
|
|
|
|
double FGSteam::get_ALT_ft() { _CatchUp(); return the_ALT_ft; }
|
|
|
|
|
|
2001-01-23 07:17:47 +00:00
|
|
|
|
double FGSteam::the_ALT_datum_mb = 1013.0;
|
|
|
|
|
double FGSteam::get_ALT_datum_mb() { return the_ALT_datum_mb; }
|
|
|
|
|
|
|
|
|
|
void FGSteam::set_ALT_datum_mb ( double datum_mb ) {
|
|
|
|
|
the_ALT_datum_mb = datum_mb;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-21 20:51:03 +00:00
|
|
|
|
double FGSteam::get_ASI_kias() { return FGBFI::getAirspeed(); }
|
|
|
|
|
|
|
|
|
|
double FGSteam::the_VSI_case = 29.92;
|
|
|
|
|
double FGSteam::the_VSI_fps = 0.0;
|
|
|
|
|
double FGSteam::get_VSI_fps() { _CatchUp(); return the_VSI_fps; }
|
|
|
|
|
|
2000-03-22 21:59:59 +00:00
|
|
|
|
double FGSteam::the_VACUUM_inhg = 0.0;
|
|
|
|
|
double FGSteam::get_VACUUM_inhg() { _CatchUp(); return the_VACUUM_inhg; }
|
|
|
|
|
|
2000-05-02 19:41:35 +00:00
|
|
|
|
double FGSteam::the_MH_err = 0.0;
|
|
|
|
|
double FGSteam::the_MH_deg = 0.0;
|
|
|
|
|
double FGSteam::the_MH_degps = 0.0;
|
|
|
|
|
double FGSteam::get_MH_deg () { _CatchUp(); return the_MH_deg; }
|
|
|
|
|
|
2000-06-15 18:36:13 +00:00
|
|
|
|
double FGSteam::the_DG_err = 0.0;
|
2000-05-02 19:41:35 +00:00
|
|
|
|
double FGSteam::the_DG_deg = 0.0;
|
|
|
|
|
double FGSteam::the_DG_degps = 0.0;
|
|
|
|
|
double FGSteam::the_DG_inhg = 0.0;
|
|
|
|
|
double FGSteam::get_DG_deg () { _CatchUp(); return the_DG_deg; }
|
2000-06-15 18:36:13 +00:00
|
|
|
|
double FGSteam::get_DG_err () { _CatchUp(); return the_DG_err; }
|
|
|
|
|
|
|
|
|
|
void FGSteam::set_DG_err ( double approx_magvar ) {
|
|
|
|
|
the_DG_err = approx_magvar;
|
|
|
|
|
}
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
2000-05-02 19:41:35 +00:00
|
|
|
|
double FGSteam::the_TC_rad = 0.0;
|
|
|
|
|
double FGSteam::the_TC_std = 0.0;
|
|
|
|
|
double FGSteam::get_TC_rad () { _CatchUp(); return the_TC_rad; }
|
|
|
|
|
double FGSteam::get_TC_std () { _CatchUp(); return the_TC_std; }
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Recording the current time
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
2000-07-20 04:16:59 +00:00
|
|
|
|
int FGSteam::_UpdatesPending = 1000000; /* Forces filter to reset */
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
|
|
|
|
|
2000-12-19 23:29:16 +00:00
|
|
|
|
// FIXME: no need to use static
|
|
|
|
|
// functions any longer.
|
|
|
|
|
|
2000-03-21 20:51:03 +00:00
|
|
|
|
void FGSteam::update ( int timesteps )
|
|
|
|
|
{
|
2000-09-06 00:07:48 +00:00
|
|
|
|
if (!isTied) {
|
|
|
|
|
isTied = true;
|
2001-01-13 22:06:39 +00:00
|
|
|
|
fgTie("/steam/airspeed", FGSteam::get_ASI_kias);
|
|
|
|
|
fgTie("/steam/altitude", FGSteam::get_ALT_ft);
|
2001-01-23 07:17:47 +00:00
|
|
|
|
fgTie("/steam/altimeter-datum-mb",
|
|
|
|
|
FGSteam::get_ALT_datum_mb, FGSteam::set_ALT_datum_mb,
|
|
|
|
|
false); /* don't modify the value */
|
2001-01-13 22:06:39 +00:00
|
|
|
|
fgTie("/steam/turn-rate", FGSteam::get_TC_std);
|
|
|
|
|
fgTie("/steam/slip-skid", FGSteam::get_TC_rad);
|
|
|
|
|
fgTie("/steam/vertical-speed", FGSteam::get_VSI_fps);
|
|
|
|
|
fgTie("/steam/gyro-compass", FGSteam::get_DG_deg);
|
|
|
|
|
fgTie("/steam/vor1", FGSteam::get_HackVOR1_deg);
|
|
|
|
|
fgTie("/steam/vor2", FGSteam::get_HackVOR2_deg);
|
|
|
|
|
fgTie("/steam/glidescope1", FGSteam::get_HackGS_deg);
|
|
|
|
|
fgTie("/steam/adf", FGSteam::get_HackADF_deg);
|
|
|
|
|
fgTie("/steam/gyro-compass-error",
|
|
|
|
|
FGSteam::get_DG_err,
|
|
|
|
|
FGSteam::set_DG_err);
|
|
|
|
|
fgTie("/steam/mag-compass", FGSteam::get_MH_deg);
|
2000-09-06 00:07:48 +00:00
|
|
|
|
}
|
2000-03-21 20:51:03 +00:00
|
|
|
|
_UpdatesPending += timesteps;
|
|
|
|
|
}
|
|
|
|
|
|
2000-12-19 23:29:16 +00:00
|
|
|
|
#undef DF1
|
|
|
|
|
#undef DF2
|
|
|
|
|
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
2001-01-23 07:17:47 +00:00
|
|
|
|
/* tc should be (elapsed_time_between_updates / desired_smoothing_time) */
|
2000-03-21 20:51:03 +00:00
|
|
|
|
void FGSteam::set_lowpass ( double *outthe, double inthe, double tc )
|
|
|
|
|
{
|
|
|
|
|
if ( tc < 0.0 )
|
|
|
|
|
{ if ( tc < -1.0 )
|
|
|
|
|
{ /* time went backwards; kill the filter */
|
|
|
|
|
(*outthe) = inthe;
|
|
|
|
|
} else
|
|
|
|
|
{ /* ignore mildly negative time */
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
if ( tc < 0.2 )
|
2001-01-23 07:17:47 +00:00
|
|
|
|
{ /* Normal mode of operation; fast approximation to exp(-tc) */
|
2000-03-21 20:51:03 +00:00
|
|
|
|
(*outthe) = (*outthe) * ( 1.0 - tc )
|
|
|
|
|
+ inthe * tc;
|
|
|
|
|
} else
|
2000-03-22 21:59:59 +00:00
|
|
|
|
if ( tc > 5.0 )
|
2000-03-21 20:51:03 +00:00
|
|
|
|
{ /* Huge time step; assume filter has settled */
|
|
|
|
|
(*outthe) = inthe;
|
|
|
|
|
} else
|
|
|
|
|
{ /* Moderate time step; non linear response */
|
2000-03-22 21:59:59 +00:00
|
|
|
|
double keep = exp ( -tc );
|
2000-04-11 20:38:45 +00:00
|
|
|
|
// printf ( "ARP: Keep is %f\n", keep );
|
2000-03-22 21:59:59 +00:00
|
|
|
|
(*outthe) = (*outthe) * keep
|
|
|
|
|
+ inthe * ( 1.0 - keep );
|
2000-03-21 20:51:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-01-23 07:17:47 +00:00
|
|
|
|
#define INHG_TO_MB 33.86388 /* Inches_of_mercury * INHG_TO_MB == millibars. */
|
|
|
|
|
|
|
|
|
|
// Convert air pressure to altitude by ICAO Standard Atmosphere
|
|
|
|
|
double pressInHgToAltFt(double p_inhg)
|
|
|
|
|
{
|
|
|
|
|
// Ref. Aviation Formulary, Ed Williams, www.best.com/~williams/avform.htm
|
|
|
|
|
const double P_0 = 29.92126; // Std. MSL pressure, inHg. (=10135.25 mb)
|
|
|
|
|
const double p_Tr = 0.2233609 * P_0; // Pressure at tropopause, same units.
|
|
|
|
|
const double h_Tr = 36089.24; // Alt of tropopause, ft. (=11.0 km)
|
|
|
|
|
|
|
|
|
|
// return (P_0 - p_inhg) * 1000.0; // ### crude approx. for low alt's
|
|
|
|
|
if (p_inhg > p_Tr) // 0.0 to 11.0 km
|
|
|
|
|
return (1.0 - pow((p_inhg / P_0), 1.0 / 5.2558797)) / 6.8755856e-6;
|
|
|
|
|
return h_Tr + log10(p_inhg / p_Tr) / -4.806346e-5; // 11.0 to 20.0 km
|
|
|
|
|
// We could put more code for higher altitudes here.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Here the fun really begins
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FGSteam::_CatchUp()
|
|
|
|
|
{ if ( _UpdatesPending != 0 )
|
2000-10-19 21:24:43 +00:00
|
|
|
|
{ double dt = _UpdatesPending * 1.0 /
|
2001-01-13 22:06:39 +00:00
|
|
|
|
fgGetInt("/sim/model-hz"); // FIXME: inefficient
|
2000-05-02 19:41:35 +00:00
|
|
|
|
double AccN, AccE, AccU;
|
2000-05-12 20:07:51 +00:00
|
|
|
|
int i /*,j*/;
|
2000-03-22 21:59:59 +00:00
|
|
|
|
double d, the_ENGINE_rpm;
|
2000-05-02 19:41:35 +00:00
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/**************************
|
|
|
|
|
There is the possibility that this is the first call.
|
|
|
|
|
If this is the case, we will emit the feature registrations
|
|
|
|
|
just to be on the safe side. Doing it more than once will
|
|
|
|
|
waste CPU time but doesn't hurt anything really.
|
|
|
|
|
*/
|
2000-07-20 04:16:59 +00:00
|
|
|
|
if ( _UpdatesPending > 999999 )
|
2000-05-02 19:41:35 +00:00
|
|
|
|
{ FGFeature::register_int ( "Avionics/NAV1/Localizer", &NAV1_LOC );
|
|
|
|
|
FGFeature::register_double ( "Avionics/NAV1/Latitude", &NAV1_Lat );
|
|
|
|
|
FGFeature::register_double ( "Avionics/NAV1/Longitude", &NAV1_Lon );
|
|
|
|
|
FGFeature::register_double ( "Avionics/NAV1/Radial", &NAV1_Rad );
|
|
|
|
|
FGFeature::register_double ( "Avionics/NAV1/Altitude", &NAV1_Alt );
|
|
|
|
|
FGFeature::register_int ( "Avionics/NAV2/Localizer", &NAV2_LOC );
|
|
|
|
|
FGFeature::register_double ( "Avionics/NAV2/Latitude", &NAV2_Lat );
|
|
|
|
|
FGFeature::register_double ( "Avionics/NAV2/Longitude", &NAV2_Lon );
|
|
|
|
|
FGFeature::register_double ( "Avionics/NAV2/Radial", &NAV2_Rad );
|
|
|
|
|
FGFeature::register_double ( "Avionics/NAV2/Altitude", &NAV2_Alt );
|
|
|
|
|
FGFeature::register_double ( "Avionics/ADF/Latitude", &ADF_Lat );
|
|
|
|
|
FGFeature::register_double ( "Avionics/ADF/Longitude", &ADF_Lon );
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**************************
|
2000-03-22 21:59:59 +00:00
|
|
|
|
Someone has called our update function and
|
|
|
|
|
it turns out that we are running somewhat behind.
|
|
|
|
|
Here, we recalculate everything for a 'dt' second step.
|
|
|
|
|
*/
|
|
|
|
|
|
2000-05-02 19:41:35 +00:00
|
|
|
|
/**************************
|
|
|
|
|
The ball responds to the acceleration vector in the body
|
|
|
|
|
frame, only the components perpendicular to the longitudinal
|
|
|
|
|
axis of the aircraft. This is only related to actual
|
|
|
|
|
side slip for a symmetrical aircraft which is not touching
|
|
|
|
|
the ground and not changing its attitude. Math simplifies
|
|
|
|
|
by assuming (for small angles) arctan(x)=x in radians.
|
|
|
|
|
Obvious failure mode is the absence of liquid in the
|
|
|
|
|
tube, which is there to damp the motion, so that instead
|
|
|
|
|
the ball will bounce around, hitting the tube ends.
|
|
|
|
|
More subtle flaw is having it not move or a travel limit
|
|
|
|
|
occasionally due to some dirt in the tube or on the ball.
|
|
|
|
|
*/
|
|
|
|
|
// the_TC_rad = - ( FGBFI::getSideSlip () ); /* incorrect */
|
|
|
|
|
d = - current_aircraft.fdm_state->get_A_Z_pilot();
|
|
|
|
|
if ( d < 1 ) d = 1;
|
|
|
|
|
set_lowpass ( & the_TC_rad,
|
|
|
|
|
current_aircraft.fdm_state->get_A_Y_pilot () / d,
|
|
|
|
|
dt );
|
|
|
|
|
|
|
|
|
|
/**************************
|
|
|
|
|
The rate of turn indication is from an electric gyro.
|
|
|
|
|
We should have it spin up with the master switch.
|
|
|
|
|
It is mounted at a funny angle so that it detects
|
|
|
|
|
both rate of bank (i.e. rolling into and out of turns)
|
|
|
|
|
and the rate of turn (i.e. how fast heading is changing).
|
|
|
|
|
*/
|
|
|
|
|
set_lowpass ( & the_TC_std,
|
|
|
|
|
current_aircraft.fdm_state->get_Phi_dot ()
|
|
|
|
|
* RAD_TO_DEG / 20.0 +
|
|
|
|
|
current_aircraft.fdm_state->get_Psi_dot ()
|
|
|
|
|
* RAD_TO_DEG / 3.0 , dt );
|
|
|
|
|
|
|
|
|
|
/**************************
|
|
|
|
|
We want to know the pilot accelerations,
|
|
|
|
|
to compute the magnetic compass errors.
|
|
|
|
|
*/
|
|
|
|
|
AccN = current_aircraft.fdm_state->get_V_dot_north();
|
|
|
|
|
AccE = current_aircraft.fdm_state->get_V_dot_east();
|
|
|
|
|
AccU = current_aircraft.fdm_state->get_V_dot_down()
|
|
|
|
|
- 9.81 / 0.3;
|
|
|
|
|
if ( fabs(the_TC_rad) > 0.2 )
|
|
|
|
|
{ /* Massive sideslip jams it; it stops turning */
|
|
|
|
|
the_MH_degps = 0.0;
|
|
|
|
|
the_MH_err = FGBFI::getHeading () - the_MH_deg;
|
|
|
|
|
} else
|
|
|
|
|
{ double MagDip, MagVar, CosDip;
|
|
|
|
|
double FrcN, FrcE, FrcU, AccTot;
|
|
|
|
|
double EdgN, EdgE, EdgU;
|
|
|
|
|
double TrqN, TrqE, TrqU, Torque;
|
|
|
|
|
/* Find a force vector towards exact magnetic north */
|
|
|
|
|
MagVar = FGBFI::getMagVar() / RAD_TO_DEG;
|
|
|
|
|
MagDip = FGBFI::getMagDip() / RAD_TO_DEG;
|
|
|
|
|
CosDip = cos ( MagDip );
|
|
|
|
|
FrcN = CosDip * cos ( MagVar );
|
|
|
|
|
FrcE = CosDip * sin ( MagVar );
|
|
|
|
|
FrcU = sin ( MagDip );
|
|
|
|
|
/* Rotation occurs around acceleration axis,
|
|
|
|
|
but axis magnitude is irrelevant. So compute it. */
|
|
|
|
|
AccTot = AccN*AccN + AccE*AccE + AccU*AccU;
|
|
|
|
|
if ( AccTot > 1.0 ) AccTot = sqrt ( AccTot );
|
|
|
|
|
else AccTot = 1.0;
|
|
|
|
|
/* Force applies to north marking on compass card */
|
|
|
|
|
EdgN = cos ( the_MH_err / RAD_TO_DEG );
|
|
|
|
|
EdgE = sin ( the_MH_err / RAD_TO_DEG );
|
|
|
|
|
EdgU = 0.0;
|
|
|
|
|
/* Apply the force to the edge to get torques */
|
|
|
|
|
TrqN = EdgE * FrcU - EdgU * FrcE;
|
|
|
|
|
TrqE = EdgU * FrcN - EdgN * FrcU;
|
|
|
|
|
TrqU = EdgN * FrcE - EdgE * FrcN;
|
|
|
|
|
/* Select the component parallel to the axis */
|
|
|
|
|
Torque = ( TrqN * AccN +
|
|
|
|
|
TrqE * AccE +
|
|
|
|
|
TrqU * AccU ) * 5.0 / AccTot;
|
|
|
|
|
/* The magnetic compass has angular momentum,
|
|
|
|
|
so we apply a torque to it and wait */
|
|
|
|
|
if ( dt < 1.0 )
|
|
|
|
|
{ the_MH_degps= the_MH_degps * (1.0 - dt) - Torque;
|
|
|
|
|
the_MH_err += dt * the_MH_degps;
|
|
|
|
|
}
|
|
|
|
|
if ( the_MH_err > 180.0 ) the_MH_err -= 360.0; else
|
|
|
|
|
if ( the_MH_err < -180.0 ) the_MH_err += 360.0;
|
|
|
|
|
the_MH_deg = FGBFI::getHeading () - the_MH_err;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-22 21:59:59 +00:00
|
|
|
|
/**************************
|
|
|
|
|
This is not actually correct, but provides a
|
|
|
|
|
scaling capability for the vacuum pump later on.
|
|
|
|
|
When we have a real engine model, we can ask it.
|
2000-03-21 20:51:03 +00:00
|
|
|
|
*/
|
2001-01-11 22:44:18 +00:00
|
|
|
|
the_ENGINE_rpm = controls.get_throttle(0) * 26.0;
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
|
|
|
|
/**************************
|
|
|
|
|
First, we need to know what the static line is reporting,
|
|
|
|
|
which is a whole simulation area in itself. For now, we cheat.
|
2001-01-23 07:17:47 +00:00
|
|
|
|
We filter the actual value by one second to
|
|
|
|
|
account for the line impedance of the plumbing.
|
2000-03-21 20:51:03 +00:00
|
|
|
|
*/
|
2001-01-23 07:17:47 +00:00
|
|
|
|
double static_inhg = 29.92;
|
|
|
|
|
i = (int) FGBFI::getAltitude();
|
2000-03-22 21:59:59 +00:00
|
|
|
|
while ( i > 9000 )
|
2001-01-23 07:17:47 +00:00
|
|
|
|
{ static_inhg *= 0.707;
|
2000-03-22 21:59:59 +00:00
|
|
|
|
i -= 9000;
|
2000-03-21 20:51:03 +00:00
|
|
|
|
}
|
2001-01-23 07:17:47 +00:00
|
|
|
|
static_inhg *= ( 1.0 - 0.293 * i / 9000.0 );
|
|
|
|
|
set_lowpass ( & the_STATIC_inhg, static_inhg, dt );
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
NO alternate static source error (student feature),
|
|
|
|
|
NO possibility of blockage (instructor feature),
|
|
|
|
|
NO slip-induced error, important for C172 for example.
|
|
|
|
|
*/
|
|
|
|
|
|
2001-01-23 07:17:47 +00:00
|
|
|
|
/**************************
|
|
|
|
|
Altimeter.
|
|
|
|
|
ICAO standard atmosphere MSL pressure is 1013.25 mb, and pressure
|
|
|
|
|
gradient is about 28 ft per mb at MSL increasing to about 32 at
|
|
|
|
|
5000 and 38 at 10000 ft.
|
|
|
|
|
Standard altimeters apply the subscale offset to the output altitude,
|
|
|
|
|
not to the input pressure; I don't know exactly what pressure gradient
|
|
|
|
|
they assume for this. I choose to make it accurate at low altitudes.
|
|
|
|
|
Remember, we are trying to simulate a real altimeter, not an ideal one.
|
|
|
|
|
*/
|
|
|
|
|
set_lowpass ( & the_ALT_ft,
|
|
|
|
|
pressInHgToAltFt(the_STATIC_inhg) +
|
|
|
|
|
(the_ALT_datum_mb - 1013.25) * 28.0, /* accurate at low alt. */
|
|
|
|
|
dt * 10 ); /* smoothing time 0.1 s */
|
|
|
|
|
|
2000-03-21 20:51:03 +00:00
|
|
|
|
/**************************
|
|
|
|
|
The VSI case is a low-pass filter of the static line pressure.
|
|
|
|
|
The instrument reports the difference, scaled to approx ft.
|
|
|
|
|
NO option for student to break glass when static source fails.
|
|
|
|
|
NO capability for a fixed non-zero reading when level.
|
|
|
|
|
NO capability to have a scaling error of maybe a factor of two.
|
|
|
|
|
*/
|
|
|
|
|
the_VSI_fps = ( the_VSI_case - the_STATIC_inhg )
|
NAV1 is now the ILS-28R on airport KMYF,
NAV2 is now the VOR radial 068 from MZB,
ADF is now the Compass locator on the outer marker.
This combination is more than the legally required to
fly any of KMYF-ILS-28R, KMYF-LOC-28R KMYF-NDB28.
If you don't have access to the approach plates
and would like them, let me know and I'll scan them
(and put them on the webpage area).
The approaches do work; I've checked them all out in
terms of altitude profile, centerlines and other stuff.
In real life, the radar vectoring will basically abandon you
overhead KSEE airport at 4000 ft heading 210 or so. Sometime
later you'll be turned to a heading of 260 if the controller
doesn't have too much else to do, just before you hit the
extended centerline. You can't rely on that though.
Maintain 3500ft until established, 2100 ft until the outer marker,
If non-precision, maintain 1340 until crossing the radial,
then 900 thereafter until you miss, based on time from the NDB.
The miss takes you heading 270 to intercept a radial which this
hacky implementation will not let you set up the computer for.
The hacky math implementation does not take range and/or signal
strength into account, so you can fly to San Diego from England
by following the needle indication on the ADF. It is also
fairly inaccurate math; about as accurate as the real-life signals.
When we have a _real_ radio module, I will be very happy to
throw all that code away. For now, it makes it demonstratable.
Please notice the nastiness involving the "VARY_E" constant.
This is _not_ something that will go away with the radio module.
As far as I know, we don't have a routine that calculates
magnetic variation as a function of global position.
We will need one, probably within the next two months.
2000-03-26 16:52:36 +00:00
|
|
|
|
* 10000.0; /* manual scaling factor */
|
|
|
|
|
set_lowpass ( & the_VSI_case, the_STATIC_inhg, dt/6.0 );
|
2000-03-22 21:59:59 +00:00
|
|
|
|
|
|
|
|
|
/**************************
|
|
|
|
|
The engine driven vacuum pump is directly attached
|
|
|
|
|
to the engine shaft, so each engine rotation pumps
|
|
|
|
|
a fixed volume. The amount of air in that volume
|
|
|
|
|
is determined by the vacuum line's internal pressure.
|
|
|
|
|
The instruments are essentially leaking air like
|
|
|
|
|
a fixed source impedance from atmospheric pressure.
|
|
|
|
|
The regulator provides a digital limit setting,
|
|
|
|
|
which is open circuit unless the pressure drop is big.
|
|
|
|
|
Thus, we can compute the vacuum line pressure directly.
|
|
|
|
|
We assume that there is negligible reservoir space.
|
|
|
|
|
NO failure of the pump supported (yet)
|
|
|
|
|
*/
|
|
|
|
|
the_VACUUM_inhg = the_STATIC_inhg *
|
|
|
|
|
the_ENGINE_rpm / ( the_ENGINE_rpm + 10000.0 );
|
|
|
|
|
if ( the_VACUUM_inhg > 5.0 )
|
|
|
|
|
the_VACUUM_inhg = 5.0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
> I was merely going to do the engine rpm driven vacuum pump for both
|
|
|
|
|
> the AI and DG, have the gyros spin down down in power off descents,
|
|
|
|
|
> have it tumble when you exceed the usual pitch or bank limits,
|
|
|
|
|
> put in those insidious turning errors ... for now anyway.
|
|
|
|
|
*/
|
2000-07-20 04:16:59 +00:00
|
|
|
|
if ( _UpdatesPending > 999999 )
|
2000-06-15 18:36:13 +00:00
|
|
|
|
the_DG_err = FGBFI::getMagVar();
|
2000-07-22 23:25:49 +00:00
|
|
|
|
the_DG_degps = 0.01; /* HACK! */
|
2000-06-15 18:36:13 +00:00
|
|
|
|
if (dt<1.0) the_DG_err += dt * the_DG_degps;
|
|
|
|
|
the_DG_deg = FGBFI::getHeading () - the_DG_err;
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
|
|
|
|
/**************************
|
|
|
|
|
Finished updates, now clear the timer
|
|
|
|
|
*/
|
|
|
|
|
_UpdatesPending = 0;
|
2000-06-15 18:36:13 +00:00
|
|
|
|
} else {
|
|
|
|
|
// cout << "0 Updates pending" << endl;
|
2000-03-21 20:51:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
NAV1 is now the ILS-28R on airport KMYF,
NAV2 is now the VOR radial 068 from MZB,
ADF is now the Compass locator on the outer marker.
This combination is more than the legally required to
fly any of KMYF-ILS-28R, KMYF-LOC-28R KMYF-NDB28.
If you don't have access to the approach plates
and would like them, let me know and I'll scan them
(and put them on the webpage area).
The approaches do work; I've checked them all out in
terms of altitude profile, centerlines and other stuff.
In real life, the radar vectoring will basically abandon you
overhead KSEE airport at 4000 ft heading 210 or so. Sometime
later you'll be turned to a heading of 260 if the controller
doesn't have too much else to do, just before you hit the
extended centerline. You can't rely on that though.
Maintain 3500ft until established, 2100 ft until the outer marker,
If non-precision, maintain 1340 until crossing the radial,
then 900 thereafter until you miss, based on time from the NDB.
The miss takes you heading 270 to intercept a radial which this
hacky implementation will not let you set up the computer for.
The hacky math implementation does not take range and/or signal
strength into account, so you can fly to San Diego from England
by following the needle indication on the ADF. It is also
fairly inaccurate math; about as accurate as the real-life signals.
When we have a _real_ radio module, I will be very happy to
throw all that code away. For now, it makes it demonstratable.
Please notice the nastiness involving the "VARY_E" constant.
This is _not_ something that will go away with the radio module.
As far as I know, we don't have a routine that calculates
magnetic variation as a function of global position.
We will need one, probably within the next two months.
2000-03-26 16:52:36 +00:00
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Everything below is a transient hack; expect it to disappear
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
2000-04-25 04:58:25 +00:00
|
|
|
|
double FGSteam::get_HackGS_deg () {
|
User-visible
- knobs now continue to rotate when you hold down the mouse
- the middle mouse button makes knobs rotate much faster
- there are NAV1, NAV2, and ADF radios that can be tuned using the mouse
- there are standby frequencies for NAV1 and NAV2, and buttons to swap
- there is a crude, rather silly-looking DME, hard-wired to NAV1
- there is a crude, rather silly-looking autopilot that can lock
the heading (to the bug on the gyro), can lock to NAV1, and can lock
the current altitude
- the knobs for changing the radials on NAV1 and NAV2 look much better
and are in the right place
- tuning into an ILS frequency doesn't change the displayed radial for
NAV1
Code
- I've created a new module, sp_panel.[ch]xx, that constructs the
default single-prop panel; this works entirely outside of FGPanel,
so it is possible to construct similar modules for other sorts of
panels; all code specific to the default panel has been removed from
panel.cxx
- current_panel is now a pointer
- radiostack.[ch]xx keeps track both of the actual radial and of the
selected radial (they will differ with ILS); the NAV gauges should
not spin around automatically to show the actual radial (we need to
do something similar with the autopilot)
- the panel is initialized fairly early
- make sure that standby frequencies also get initialized
- I've started combining and clipping small textures to save texture
memory; there's a lot more to do, but at least I've made a start
2000-05-02 18:26:00 +00:00
|
|
|
|
if ( current_radiostack->get_nav1_inrange() &&
|
2000-05-12 22:17:09 +00:00
|
|
|
|
current_radiostack->get_nav1_has_gs() )
|
User-visible
- knobs now continue to rotate when you hold down the mouse
- the middle mouse button makes knobs rotate much faster
- there are NAV1, NAV2, and ADF radios that can be tuned using the mouse
- there are standby frequencies for NAV1 and NAV2, and buttons to swap
- there is a crude, rather silly-looking DME, hard-wired to NAV1
- there is a crude, rather silly-looking autopilot that can lock
the heading (to the bug on the gyro), can lock to NAV1, and can lock
the current altitude
- the knobs for changing the radials on NAV1 and NAV2 look much better
and are in the right place
- tuning into an ILS frequency doesn't change the displayed radial for
NAV1
Code
- I've created a new module, sp_panel.[ch]xx, that constructs the
default single-prop panel; this works entirely outside of FGPanel,
so it is possible to construct similar modules for other sorts of
panels; all code specific to the default panel has been removed from
panel.cxx
- current_panel is now a pointer
- radiostack.[ch]xx keeps track both of the actual radial and of the
selected radial (they will differ with ILS); the NAV gauges should
not spin around automatically to show the actual radial (we need to
do something similar with the autopilot)
- the panel is initialized fairly early
- make sure that standby frequencies also get initialized
- I've started combining and clipping small textures to save texture
memory; there's a lot more to do, but at least I've made a start
2000-05-02 18:26:00 +00:00
|
|
|
|
{
|
2000-05-12 20:07:51 +00:00
|
|
|
|
double x = current_radiostack->get_nav1_gs_dist();
|
2000-04-27 03:26:36 +00:00
|
|
|
|
double y = (FGBFI::getAltitude() - current_radiostack->get_nav1_elev())
|
|
|
|
|
* FEET_TO_METER;
|
|
|
|
|
double angle = atan2( y, x ) * RAD_TO_DEG;
|
2000-05-12 13:41:12 +00:00
|
|
|
|
return (current_radiostack->get_nav1_target_gs() - angle) * 5.0;
|
2000-04-27 03:26:36 +00:00
|
|
|
|
} else {
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
NAV1 is now the ILS-28R on airport KMYF,
NAV2 is now the VOR radial 068 from MZB,
ADF is now the Compass locator on the outer marker.
This combination is more than the legally required to
fly any of KMYF-ILS-28R, KMYF-LOC-28R KMYF-NDB28.
If you don't have access to the approach plates
and would like them, let me know and I'll scan them
(and put them on the webpage area).
The approaches do work; I've checked them all out in
terms of altitude profile, centerlines and other stuff.
In real life, the radar vectoring will basically abandon you
overhead KSEE airport at 4000 ft heading 210 or so. Sometime
later you'll be turned to a heading of 260 if the controller
doesn't have too much else to do, just before you hit the
extended centerline. You can't rely on that though.
Maintain 3500ft until established, 2100 ft until the outer marker,
If non-precision, maintain 1340 until crossing the radial,
then 900 thereafter until you miss, based on time from the NDB.
The miss takes you heading 270 to intercept a radial which this
hacky implementation will not let you set up the computer for.
The hacky math implementation does not take range and/or signal
strength into account, so you can fly to San Diego from England
by following the needle indication on the ADF. It is also
fairly inaccurate math; about as accurate as the real-life signals.
When we have a _real_ radio module, I will be very happy to
throw all that code away. For now, it makes it demonstratable.
Please notice the nastiness involving the "VARY_E" constant.
This is _not_ something that will go away with the radio module.
As far as I know, we don't have a routine that calculates
magnetic variation as a function of global position.
We will need one, probably within the next two months.
2000-03-26 16:52:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-04-25 04:58:25 +00:00
|
|
|
|
double FGSteam::get_HackVOR1_deg () {
|
|
|
|
|
double r;
|
|
|
|
|
|
2000-04-27 03:26:36 +00:00
|
|
|
|
if ( current_radiostack->get_nav1_inrange() ) {
|
2001-01-05 17:38:58 +00:00
|
|
|
|
r = current_radiostack->get_nav1_heading()
|
|
|
|
|
- current_radiostack->get_nav1_radial();
|
2001-02-02 02:55:07 +00:00
|
|
|
|
cout << "Radial = " << current_radiostack->get_nav1_radial()
|
|
|
|
|
<< " Bearing = " << current_radiostack->get_nav1_heading()
|
|
|
|
|
<< endl;
|
2000-04-25 04:58:25 +00:00
|
|
|
|
|
2000-04-27 03:26:36 +00:00
|
|
|
|
if (r> 180.0) r-=360.0; else
|
|
|
|
|
if (r<-180.0) r+=360.0;
|
|
|
|
|
if ( fabs(r) > 90.0 )
|
|
|
|
|
r = ( r<0.0 ? -r-180.0 : -r+180.0 );
|
2000-05-12 20:07:51 +00:00
|
|
|
|
// According to Robin Peel, the ILS is 4x more sensitive than a vor
|
|
|
|
|
if ( current_radiostack->get_nav1_loc() ) r *= 4.0;
|
2000-04-27 03:26:36 +00:00
|
|
|
|
} else {
|
|
|
|
|
r = 0.0;
|
|
|
|
|
}
|
2000-04-25 04:58:25 +00:00
|
|
|
|
|
|
|
|
|
return r;
|
NAV1 is now the ILS-28R on airport KMYF,
NAV2 is now the VOR radial 068 from MZB,
ADF is now the Compass locator on the outer marker.
This combination is more than the legally required to
fly any of KMYF-ILS-28R, KMYF-LOC-28R KMYF-NDB28.
If you don't have access to the approach plates
and would like them, let me know and I'll scan them
(and put them on the webpage area).
The approaches do work; I've checked them all out in
terms of altitude profile, centerlines and other stuff.
In real life, the radar vectoring will basically abandon you
overhead KSEE airport at 4000 ft heading 210 or so. Sometime
later you'll be turned to a heading of 260 if the controller
doesn't have too much else to do, just before you hit the
extended centerline. You can't rely on that though.
Maintain 3500ft until established, 2100 ft until the outer marker,
If non-precision, maintain 1340 until crossing the radial,
then 900 thereafter until you miss, based on time from the NDB.
The miss takes you heading 270 to intercept a radial which this
hacky implementation will not let you set up the computer for.
The hacky math implementation does not take range and/or signal
strength into account, so you can fly to San Diego from England
by following the needle indication on the ADF. It is also
fairly inaccurate math; about as accurate as the real-life signals.
When we have a _real_ radio module, I will be very happy to
throw all that code away. For now, it makes it demonstratable.
Please notice the nastiness involving the "VARY_E" constant.
This is _not_ something that will go away with the radio module.
As far as I know, we don't have a routine that calculates
magnetic variation as a function of global position.
We will need one, probably within the next two months.
2000-03-26 16:52:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-04-25 04:58:25 +00:00
|
|
|
|
double FGSteam::get_HackVOR2_deg () {
|
|
|
|
|
double r;
|
|
|
|
|
|
2000-04-27 03:26:36 +00:00
|
|
|
|
if ( current_radiostack->get_nav2_inrange() ) {
|
2001-01-05 17:38:58 +00:00
|
|
|
|
r = current_radiostack->get_nav2_heading()
|
|
|
|
|
- current_radiostack->get_nav2_radial();
|
2000-04-27 03:26:36 +00:00
|
|
|
|
// cout << "Radial = " << current_radiostack->get_nav1_radial()
|
|
|
|
|
// << " Bearing = " << current_radiostack->get_nav1_heading() << endl;
|
2000-04-25 04:58:25 +00:00
|
|
|
|
|
2000-04-27 03:26:36 +00:00
|
|
|
|
if (r> 180.0) r-=360.0; else
|
|
|
|
|
if (r<-180.0) r+=360.0;
|
|
|
|
|
if ( fabs(r) > 90.0 )
|
|
|
|
|
r = ( r<0.0 ? -r-180.0 : -r+180.0 );
|
|
|
|
|
} else {
|
|
|
|
|
r = 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-25 04:58:25 +00:00
|
|
|
|
return r;
|
NAV1 is now the ILS-28R on airport KMYF,
NAV2 is now the VOR radial 068 from MZB,
ADF is now the Compass locator on the outer marker.
This combination is more than the legally required to
fly any of KMYF-ILS-28R, KMYF-LOC-28R KMYF-NDB28.
If you don't have access to the approach plates
and would like them, let me know and I'll scan them
(and put them on the webpage area).
The approaches do work; I've checked them all out in
terms of altitude profile, centerlines and other stuff.
In real life, the radar vectoring will basically abandon you
overhead KSEE airport at 4000 ft heading 210 or so. Sometime
later you'll be turned to a heading of 260 if the controller
doesn't have too much else to do, just before you hit the
extended centerline. You can't rely on that though.
Maintain 3500ft until established, 2100 ft until the outer marker,
If non-precision, maintain 1340 until crossing the radial,
then 900 thereafter until you miss, based on time from the NDB.
The miss takes you heading 270 to intercept a radial which this
hacky implementation will not let you set up the computer for.
The hacky math implementation does not take range and/or signal
strength into account, so you can fly to San Diego from England
by following the needle indication on the ADF. It is also
fairly inaccurate math; about as accurate as the real-life signals.
When we have a _real_ radio module, I will be very happy to
throw all that code away. For now, it makes it demonstratable.
Please notice the nastiness involving the "VARY_E" constant.
This is _not_ something that will go away with the radio module.
As far as I know, we don't have a routine that calculates
magnetic variation as a function of global position.
We will need one, probably within the next two months.
2000-03-26 16:52:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-04-27 03:26:36 +00:00
|
|
|
|
double FGSteam::get_HackOBS1_deg () {
|
|
|
|
|
return current_radiostack->get_nav1_radial();
|
NAV1 is now the ILS-28R on airport KMYF,
NAV2 is now the VOR radial 068 from MZB,
ADF is now the Compass locator on the outer marker.
This combination is more than the legally required to
fly any of KMYF-ILS-28R, KMYF-LOC-28R KMYF-NDB28.
If you don't have access to the approach plates
and would like them, let me know and I'll scan them
(and put them on the webpage area).
The approaches do work; I've checked them all out in
terms of altitude profile, centerlines and other stuff.
In real life, the radar vectoring will basically abandon you
overhead KSEE airport at 4000 ft heading 210 or so. Sometime
later you'll be turned to a heading of 260 if the controller
doesn't have too much else to do, just before you hit the
extended centerline. You can't rely on that though.
Maintain 3500ft until established, 2100 ft until the outer marker,
If non-precision, maintain 1340 until crossing the radial,
then 900 thereafter until you miss, based on time from the NDB.
The miss takes you heading 270 to intercept a radial which this
hacky implementation will not let you set up the computer for.
The hacky math implementation does not take range and/or signal
strength into account, so you can fly to San Diego from England
by following the needle indication on the ADF. It is also
fairly inaccurate math; about as accurate as the real-life signals.
When we have a _real_ radio module, I will be very happy to
throw all that code away. For now, it makes it demonstratable.
Please notice the nastiness involving the "VARY_E" constant.
This is _not_ something that will go away with the radio module.
As far as I know, we don't have a routine that calculates
magnetic variation as a function of global position.
We will need one, probably within the next two months.
2000-03-26 16:52:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-04-27 03:26:36 +00:00
|
|
|
|
double FGSteam::get_HackOBS2_deg () {
|
|
|
|
|
return current_radiostack->get_nav2_radial();
|
NAV1 is now the ILS-28R on airport KMYF,
NAV2 is now the VOR radial 068 from MZB,
ADF is now the Compass locator on the outer marker.
This combination is more than the legally required to
fly any of KMYF-ILS-28R, KMYF-LOC-28R KMYF-NDB28.
If you don't have access to the approach plates
and would like them, let me know and I'll scan them
(and put them on the webpage area).
The approaches do work; I've checked them all out in
terms of altitude profile, centerlines and other stuff.
In real life, the radar vectoring will basically abandon you
overhead KSEE airport at 4000 ft heading 210 or so. Sometime
later you'll be turned to a heading of 260 if the controller
doesn't have too much else to do, just before you hit the
extended centerline. You can't rely on that though.
Maintain 3500ft until established, 2100 ft until the outer marker,
If non-precision, maintain 1340 until crossing the radial,
then 900 thereafter until you miss, based on time from the NDB.
The miss takes you heading 270 to intercept a radial which this
hacky implementation will not let you set up the computer for.
The hacky math implementation does not take range and/or signal
strength into account, so you can fly to San Diego from England
by following the needle indication on the ADF. It is also
fairly inaccurate math; about as accurate as the real-life signals.
When we have a _real_ radio module, I will be very happy to
throw all that code away. For now, it makes it demonstratable.
Please notice the nastiness involving the "VARY_E" constant.
This is _not_ something that will go away with the radio module.
As far as I know, we don't have a routine that calculates
magnetic variation as a function of global position.
We will need one, probably within the next two months.
2000-03-26 16:52:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-04-27 03:26:36 +00:00
|
|
|
|
double FGSteam::get_HackADF_deg () {
|
|
|
|
|
double r;
|
|
|
|
|
|
|
|
|
|
if ( current_radiostack->get_adf_inrange() ) {
|
2000-05-12 13:41:12 +00:00
|
|
|
|
r = current_radiostack->get_adf_heading() - FGBFI::getHeading();
|
2000-04-27 03:26:36 +00:00
|
|
|
|
|
|
|
|
|
// cout << "Radial = " << current_radiostack->get_adf_heading()
|
|
|
|
|
// << " Heading = " << FGBFI::getHeading() << endl;
|
|
|
|
|
} else {
|
|
|
|
|
r = 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r;
|
NAV1 is now the ILS-28R on airport KMYF,
NAV2 is now the VOR radial 068 from MZB,
ADF is now the Compass locator on the outer marker.
This combination is more than the legally required to
fly any of KMYF-ILS-28R, KMYF-LOC-28R KMYF-NDB28.
If you don't have access to the approach plates
and would like them, let me know and I'll scan them
(and put them on the webpage area).
The approaches do work; I've checked them all out in
terms of altitude profile, centerlines and other stuff.
In real life, the radar vectoring will basically abandon you
overhead KSEE airport at 4000 ft heading 210 or so. Sometime
later you'll be turned to a heading of 260 if the controller
doesn't have too much else to do, just before you hit the
extended centerline. You can't rely on that though.
Maintain 3500ft until established, 2100 ft until the outer marker,
If non-precision, maintain 1340 until crossing the radial,
then 900 thereafter until you miss, based on time from the NDB.
The miss takes you heading 270 to intercept a radial which this
hacky implementation will not let you set up the computer for.
The hacky math implementation does not take range and/or signal
strength into account, so you can fly to San Diego from England
by following the needle indication on the ADF. It is also
fairly inaccurate math; about as accurate as the real-life signals.
When we have a _real_ radio module, I will be very happy to
throw all that code away. For now, it makes it demonstratable.
Please notice the nastiness involving the "VARY_E" constant.
This is _not_ something that will go away with the radio module.
As far as I know, we don't have a routine that calculates
magnetic variation as a function of global position.
We will need one, probably within the next two months.
2000-03-26 16:52:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-21 20:51:03 +00:00
|
|
|
|
|
|
|
|
|
// end of steam.cxx
|