1
0
Fork 0

Issue #809, restructure position init code.

Modify startup sequence, so position can be modified late in the startup process, right before the scenery load starts. This allows two ugly hacks to move to a permanent, less hacky location. If other position init modes required similar late evaluation in the future, this can be accommodated now.

This is a somewhat high-risk change - I've tested both carrier starts and runway-selection based on realwx METAR, but please look out for other position-init issues and test before / after this patch.
This commit is contained in:
James Turner 2012-12-09 19:41:31 +00:00
parent 13cec7bd99
commit dc132ab475
5 changed files with 93 additions and 62 deletions

View file

@ -102,7 +102,7 @@ void LiveMetarProperties::update( double dt )
{ {
_timeToLive -= dt; _timeToLive -= dt;
_pollingTimer -= dt; _pollingTimer -= dt;
if( _timeToLive < 0.0 ) { if( _timeToLive <= 0.0 ) {
_timeToLive = 0.0; _timeToLive = 0.0;
std::string stationId = getStationId(); std::string stationId = getStationId();
if( stationId.empty() ) return; if( stationId.empty() ) return;
@ -234,6 +234,8 @@ BasicRealWxController::~BasicRealWxController()
void BasicRealWxController::init() void BasicRealWxController::init()
{ {
_wasEnabled = false; _wasEnabled = false;
checkNearbyMetar();
update(0); // fetch data ASAP update(0); // fetch data ASAP
globals->get_event_mgr()->addTask("checkNearbyMetar", this, globals->get_event_mgr()->addTask("checkNearbyMetar", this,
@ -420,6 +422,11 @@ void NoaaMetarRealWxController::requestMetar( MetarDataHandler * metarDataHandle
} }
} }
virtual void failed()
{
SG_LOG(SG_ENVIRONMENT, SG_INFO, "metar download failure");
}
// bool fromMetarProxy() const // bool fromMetarProxy() const
// { return _fromProxy; } // { return _fromProxy; }
private: private:

View file

@ -581,6 +581,7 @@ void fgCreateSubsystems() {
exit(-1); exit(-1);
} }
globals->add_subsystem( "http", new FGHTTPClient );
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Initialize the scenery management subsystem. // Initialize the scenery management subsystem.
@ -626,7 +627,6 @@ void fgCreateSubsystems() {
// Initialize the Input-Output subsystem // Initialize the Input-Output subsystem
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
globals->add_subsystem( "io", new FGIO ); globals->add_subsystem( "io", new FGIO );
globals->add_subsystem( "http", new FGHTTPClient );
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Create and register the logger. // Create and register the logger.
@ -756,29 +756,6 @@ void fgPostInitSubsystems()
globals->get_subsystem_mgr()->postinit(); globals->get_subsystem_mgr()->postinit();
SG_LOG(SG_GENERAL, SG_INFO, "Subsystems postinit took:" << st.elapsedMSec()); SG_LOG(SG_GENERAL, SG_INFO, "Subsystems postinit took:" << st.elapsedMSec());
////////////////////////////////////////////////////////////////////
// TODO FIXME! UGLY KLUDGE!
////////////////////////////////////////////////////////////////////
{
/* Scenarios require Nasal, so FGAIManager loads the scenarios,
* including its models such as a/c carriers, in its 'postinit',
* which is the very last thing we do.
* flightgear::initPosition is called very early in main.cxx/fgIdleFunction,
* one of the first things we do, long before scenarios/carriers are
* loaded. => When requested "initial preset position" relates to a
* carrier, recalculate the 'initial' position here (how have things
* ever worked before this hack - this init sequence has always been
* this way...?)*/
std::string carrier = fgGetString("/sim/presets/carrier","");
if (carrier != "")
{
// clear preset location and re-trigger position setup
fgSetDouble("/sim/presets/longitude-deg", 9999);
fgSetDouble("/sim/presets/latitude-deg", 9999);
flightgear::initPosition();
}
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// End of subsystem initialization. // End of subsystem initialization.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View file

@ -217,39 +217,15 @@ static void fgIdleFunction ( void ) {
} }
} else if ( idle_state == 10 ) { } else if ( idle_state == 10 ) {
idle_state = 900; idle_state = 800;
fgPostInitSubsystems(); fgPostInitSubsystems();
} else if ( idle_state == 800 ) {
// Torsten Dreyer: if (flightgear::finalizePosition()) {
// ugly hack for automatic runway selection on startup based on idle_state = 900;
// metar data. Makes startup.nas obsolete and guarantees the same
// runway selection as for AI traffic. However, this code belongs to
// somewhere(?) else - if I only new where...
if( true == fgGetBool( "/environment/metar/valid" ) ) {
SG_LOG(SG_ENVIRONMENT, SG_INFO,
"Using METAR for runway selection: '" << fgGetString("/environment/metar/data") << "'" );
// the realwx_ctrl fetches metar in the foreground on init,
// If it was able to fetch a metar or one was given on the commandline,
// the valid flag is set here, otherwise it is false
double hdg = fgGetDouble( "/environment/metar/base-wind-dir-deg", 9999.0 );
string apt = fgGetString( "/sim/startup/options/airport" );
string rwy = fgGetString( "/sim/startup/options/runway" );
double strthdg = fgGetDouble( "/sim/startup/options/heading-deg", 9999.0 );
string parkpos = fgGetString( "/sim/presets/parkpos" );
bool onground = fgGetBool( "/sim/presets/onground", false );
// don't check for wind-speed < 1kt, this belongs to the runway-selection code
// the other logic is taken from former startup.nas
if( hdg < 360.0 && apt.length() > 0 && strthdg > 360.0 && rwy.length() == 0 && onground && parkpos.length() == 0 ) {
extern bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg );
flightgear::setPosFromAirportIDandHdg( apt, hdg );
}
} else {
SG_LOG(SG_ENVIRONMENT, SG_INFO,
"No METAR available to pick active runway" );
}
fgSplashProgress("init-graphics"); fgSplashProgress("init-graphics");
} else {
fgSplashProgress("finalize-position");
}
} else if ( idle_state == 900 ) { } else if ( idle_state == 900 ) {
idle_state = 1000; idle_state = 1000;

View file

@ -40,6 +40,11 @@ using std::endl;
namespace flightgear namespace flightgear
{ {
/// to avoid blocking when metar-fetch is enabled, but the network is
/// unresponsive, we need a timeout value. This value is reset on initPosition,
/// and tracked through each call to finalizePosition.
static SGTimeStamp global_finalizeTime;
// Set current tower position lon/lat given an airport id // Set current tower position lon/lat given an airport id
static bool fgSetTowerPosFromAirportID( const string& id) { static bool fgSetTowerPosFromAirportID( const string& id) {
const FGAirport *a = fgFindAirportID( id); const FGAirport *a = fgFindAirportID( id);
@ -131,7 +136,7 @@ static void fgApplyStartOffset(const SGGeod& aStartPos, double aHeading, double
} }
// Set current_options lon/lat given an airport id and heading (degrees) // Set current_options lon/lat given an airport id and heading (degrees)
bool setPosFromAirportIDandHdg( const string& id, double tgt_hdg ) { static bool setPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
if ( id.empty() ) if ( id.empty() )
return false; return false;
@ -395,7 +400,8 @@ static bool fgSetPosFromFix( const string& id )
// Set the initial position based on presets (or defaults) // Set the initial position based on presets (or defaults)
bool initPosition() bool initPosition()
{ {
// cout << "initPosition()" << endl; global_finalizeTime = SGTimeStamp(); // reset to invalid
double gs = fgGetDouble("/sim/presets/glideslope-deg") double gs = fgGetDouble("/sim/presets/glideslope-deg")
* SG_DEGREES_TO_RADIANS ; * SG_DEGREES_TO_RADIANS ;
double od = fgGetDouble("/sim/presets/offset-distance-nm"); double od = fgGetDouble("/sim/presets/offset-distance-nm");
@ -541,4 +547,64 @@ bool initPosition()
return true; return true;
} }
bool finalizePosition()
{
// first call to finalize after an initPosition call
if (global_finalizeTime.get_usec() == 0) {
global_finalizeTime = SGTimeStamp::now();
}
/* Scenarios require Nasal, so FGAIManager loads the scenarios,
* including its models such as a/c carriers, in its 'postinit',
* which is the very last thing we do.
* flightgear::initPosition is called very early in main.cxx/fgIdleFunction,
* one of the first things we do, long before scenarios/carriers are
* loaded. => When requested "initial preset position" relates to a
* carrier, recalculate the 'initial' position here
*/
std::string carrier = fgGetString("/sim/presets/carrier","");
if (!carrier.empty())
{
SG_LOG(SG_GENERAL, SG_INFO, "finalizePositioned: re-init-ing position on carrier");
// clear preset location and re-trigger position setup
fgSetDouble("/sim/presets/longitude-deg", 9999);
fgSetDouble("/sim/presets/latitude-deg", 9999);
return initPosition();
}
double hdg = fgGetDouble( "/environment/metar/base-wind-dir-deg", 9999.0 );
string apt = fgGetString( "/sim/startup/options/airport" );
string rwy = fgGetString( "/sim/startup/options/runway" );
double strthdg = fgGetDouble( "/sim/startup/options/heading-deg", 9999.0 );
string parkpos = fgGetString( "/sim/presets/parkpos" );
bool onground = fgGetBool( "/sim/presets/onground", false );
// this logic is taken from former startup.nas
bool needMetar = (hdg < 360.0) && !apt.empty() && (strthdg > 360.0) &&
rwy.empty() && onground && parkpos.empty();
if (needMetar) {
// timeout so we don't spin forever if the network is down
if (global_finalizeTime.elapsedMSec() > fgGetInt("/sim/startup/metar-fetch-timeout-msec", 5000)) {
SG_LOG(SG_GENERAL, SG_WARN, "finalizePosition: timed out waiting for METAR fetch");
return true;
}
if (!fgGetBool( "/environment/metar/valid" )) {
// bit hacky - run these two subsystems. We can't run the whole
// lot since some view things aren't initialised and hence FGLight
// crashes.
globals->get_subsystem("http")->update(0.0);
globals->get_subsystem("environment")->update(0.0);
return false;
}
SG_LOG(SG_ENVIRONMENT, SG_INFO,
"Using METAR for runway selection: '" << fgGetString("/environment/metar/data") << "'" );
setPosFromAirportIDandHdg( apt, hdg );
// fall through to return true
} // of need-metar case
return true;
}
} // of namespace flightgear } // of namespace flightgear

View file

@ -28,13 +28,18 @@ namespace flightgear
// Set the initial position based on presets (or defaults) // Set the initial position based on presets (or defaults)
bool initPosition(); bool initPosition();
/**
* finalize the position once subsystems, Nasal and scenarios are loaded;
* all of which can potentially affect the position.
* returns true if the position is finally set, or false if more time
* is required to finalize the position (eg, awaiting METAR to set the
* active runway)
*/
bool finalizePosition();
// Listen to /sim/tower/airport-id and set tower view position accordingly // Listen to /sim/tower/airport-id and set tower view position accordingly
void initTowerLocationListener(); void initTowerLocationListener();
// FIXME - only public becuase of the evil runway-selection hack in main.cxx
bool setPosFromAirportIDandHdg( const std::string& id, double tgt_hdg );
} // of namespace flightgear } // of namespace flightgear
#endif // of FG_POSITION_INIT_HXX #endif // of FG_POSITION_INIT_HXX