X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FEnvironment%2Fenvironment_ctrl.cxx;h=cf9c6505faefd68dff5f2cdfabb23f86666f19d2;hb=c6f88e5b9be767d93fd34f3b01c0e949fbd0044b;hp=21fb708e671a5315898b672ca1d380f6994150a1;hpb=5bc15d7a69813e97a7146742e3b2aa2d784eab73;p=flightgear.git diff --git a/src/Environment/environment_ctrl.cxx b/src/Environment/environment_ctrl.cxx index 21fb708e6..cf9c6505f 100644 --- a/src/Environment/environment_ctrl.cxx +++ b/src/Environment/environment_ctrl.cxx @@ -16,15 +16,17 @@ // // 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. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // $Id$ -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include #include +#include #include #include @@ -32,12 +34,20 @@ #include
#include
+#include "Environment/fgmetar.hxx" #include "environment_mgr.hxx" #include "environment_ctrl.hxx" -SG_USING_STD(sort); - +using std::sort; +class AirportWithMetar : public FGAirport::AirportFilter +{ +public: + virtual bool passAirport(FGAirport* aApt) const + { + return aApt->getMetar(); + } +}; //////////////////////////////////////////////////////////////////////// // Implementation of FGEnvironmentCtrl abstract base class. @@ -227,7 +237,7 @@ FGInterpolateEnvironmentCtrl::read_table (const SGPropertyNode * node, table.push_back(b); } } - sort(table.begin(), table.end()); + sort(table.begin(), table.end(), bucket::lessThan); } void @@ -308,6 +318,11 @@ FGInterpolateEnvironmentCtrl::bucket::operator< (const bucket &b) const return (altitude_ft < b.altitude_ft); } +bool +FGInterpolateEnvironmentCtrl::bucket::lessThan(bucket *a, bucket *b) +{ + return (a->altitude_ft) < (b->altitude_ft); +} //////////////////////////////////////////////////////////////////////// @@ -316,28 +331,43 @@ FGInterpolateEnvironmentCtrl::bucket::operator< (const bucket &b) const FGMetarEnvironmentCtrl::FGMetarEnvironmentCtrl () : env( new FGInterpolateEnvironmentCtrl ), - _icao( "" ), + metar_loaded( false ), search_interval_sec( 60.0 ), // 1 minute same_station_interval_sec( 900.0 ), // 15 minutes search_elapsed( 9999.0 ), fetch_elapsed( 9999.0 ), + last_apt( 0 ), proxy_host( fgGetNode("/sim/presets/proxy/host", true) ), proxy_port( fgGetNode("/sim/presets/proxy/port", true) ), proxy_auth( fgGetNode("/sim/presets/proxy/authentication", true) ), + metar_max_age( fgGetNode("/environment/params/metar-max-age-min", true) ), + + // Interpolation constant definitions. + EnvironmentUpdatePeriodSec( 0.2 ), + MaxWindChangeKtsSec( 0.2 ), + MaxVisChangePercentSec( 0.05 ), + MaxPressureChangeInHgSec( 0.0033 ), + MaxCloudAltitudeChangeFtSec( 20.0 ), + MaxCloudThicknessChangeFtSec( 50.0 ), + MaxCloudInterpolationHeightFt( 5000.0 ), + MaxCloudInterpolationDeltaFt( 4000.0 ), + _error_count( 0 ), + _stale_count( 0 ), + _dt( 0.0 ), _error_dt( 0.0 ) { -#if defined(ENABLE_THREADS) && ENABLE_THREADS +#if defined(ENABLE_THREADS) thread = new MetarThread(this); - thread->start( 1 ); + thread->setProcessorAffinity(1); + thread->start(); #endif // ENABLE_THREADS } FGMetarEnvironmentCtrl::~FGMetarEnvironmentCtrl () { -#if defined(ENABLE_THREADS) && ENABLE_THREADS - thread->cancel(); - thread->join(); +#if defined(ENABLE_THREADS) + thread_stop(); #endif // ENABLE_THREADS delete env; @@ -369,41 +399,282 @@ static void set_dewpoint_at_altitude( float dewpoint_degc, float altitude_ft ) { void FGMetarEnvironmentCtrl::update_env_config () { - fgSetupWind( fgGetDouble("/environment/metar/base-wind-range-from"), - fgGetDouble("/environment/metar/base-wind-range-to"), - fgGetDouble("/environment/metar/base-wind-speed-kt"), - fgGetDouble("/environment/metar/gust-wind-speed-kt") ); + double dir_from; + double dir_to; + double speed; + double gust; + double vis; + double pressure; + double temp; + double dewpoint; + + // If we aren't in the METAR scenario, don't attempt to interpolate. + if (strcmp(fgGetString("/environment/weather-scenario", "METAR"), "METAR")) return; + + if (metar_loaded) { + // Generate interpolated values between the METAR and the current + // configuration. + + // Pick up the METAR wind values and convert them into a vector. + double metar[2]; + double metar_speed = fgGetDouble("/environment/metar/base-wind-speed-kt"); + double metar_heading = fgGetDouble("/environment/metar/base-wind-range-from"); + + metar[0] = metar_speed * sin((metar_heading / 180.0) * M_PI); + metar[1] = metar_speed * cos((metar_heading / 180.0) * M_PI); + + // Convert the current wind values and convert them into a vector + double current[2]; + double current_speed = + fgGetDouble("/environment/config/boundary/entry/wind-speed-kt"); + double current_heading = fgGetDouble( + "/environment/config/boundary/entry/wind-from-heading-deg"); + + current[0] = current_speed * sin((current_heading / 180.0) * M_PI); + current[1] = current_speed * cos((current_heading / 180.0) * M_PI); + + // Determine the maximum component-wise value that the wind can change. + // First we determine the fraction in the X and Y component, then + // factor by the maximum wind change. + double x = fabs(current[0] - metar[0]); + double y = fabs(current[1] - metar[1]); + + // only interpolate if we have a difference + if (x + y > 0) { + double dx = x / (x + y); + double dy = 1 - dx; + + double maxdx = dx * MaxWindChangeKtsSec; + double maxdy = dy * MaxWindChangeKtsSec; + + // Interpolate each component separately. + current[0] = interpolate_val(current[0], metar[0], maxdx); + current[1] = interpolate_val(current[1], metar[1], maxdy); + } + + // Now convert back to polar coordinates. + if ((current[0] == 0.0) && (current[1] == 0.0)) { + // Special case where there is no wind (otherwise atan2 barfs) + speed = 0.0; + dir_from = current_heading; + + } else { + // Some real wind to convert back from. Work out the speed + // and direction value in degrees. + speed = sqrt((current[0] * current[0]) + (current[1] * current[1])); + dir_from = (atan2(current[0], current[1]) * 180.0 / M_PI); + + // Normalize the direction. + if (dir_from < 0.0) + dir_from += 360.0; + + SG_LOG( SG_GENERAL, SG_DEBUG, "Wind : " << dir_from << "@" << speed); + } + + // Now handle the visibility. We convert both visibility values + // to X-values, then interpolate from there, then back to real values. + // The length_scale is fixed to 1000m, so the visibility changes by + // by MaxVisChangePercentSec or 1000m X MaxVisChangePercentSec, + // whichever is more. + double currentvis = + fgGetDouble("/environment/config/boundary/entry/visibility-m"); + double metarvis = fgGetDouble("/environment/metar/min-visibility-m"); + double currentxval = log(1000.0 + currentvis); + double metarxval = log(1000.0 + metarvis); + + currentxval = interpolate_val(currentxval, metarxval, MaxVisChangePercentSec); + + // Now convert back from an X-value to a straightforward visibility. + vis = exp(currentxval) - 1000.0; + + pressure = interpolate_prop( + "/environment/config/boundary/entry/pressure-sea-level-inhg", + "/environment/metar/pressure-inhg", + MaxPressureChangeInHgSec); + + dir_to = fgGetDouble("/environment/metar/base-wind-range-to"); + gust = fgGetDouble("/environment/metar/gust-wind-speed-kt"); + temp = fgGetDouble("/environment/metar/temperature-degc"); + dewpoint = fgGetDouble("/environment/metar/dewpoint-degc"); + + // Set the cloud layers by interpolating over the METAR versions. + SGPropertyNode * clouds = fgGetNode("/environment/metar/clouds"); + + vector layers = clouds->getChildren("layer"); + vector::const_iterator layer; + vector::const_iterator layers_end = layers.end(); + + const char *cl = "/environment/clouds/layer[%i]"; + double aircraft_alt = fgGetDouble("/position/altitude-ft"); + char s[128]; + int i; + + for (i = 0, layer = layers.begin(); layer != layers_end; ++layer, i++) { + double currentval; + double requiredval; + + // In the case of clouds, we want to avoid writing if nothing has + // changed, as these properties are tied to the renderer and will + // cause the clouds to be updated, reseting the texture locations. + + // We don't interpolate the coverage values as no-matter how we + // do it, it will be quite a sudden change of texture. Better to + // have a single change than four or five. + snprintf(s, 128, cl, i); + strncat(s, "/coverage", 128); + const char* coverage = (*layer)->getStringValue("coverage", "clear"); + if (strncmp(fgGetString(s), coverage, 128) != 0) + fgSetString(s, coverage); + + snprintf(s, 128, cl, i); + strncat(s, "/elevation-ft", 128); + double current_alt = fgGetDouble(s); + double required_alt = (*layer)->getDoubleValue("elevation-ft"); + + if (current_alt < -9000 || required_alt < -9000 || + fabs(aircraft_alt - required_alt) > MaxCloudInterpolationHeightFt || + fabs(current_alt - required_alt) > MaxCloudInterpolationDeltaFt) { + // We don't interpolate any layers that are + // - too far above us to be visible + // - too far below us to be visible + // - with too large a difference to make interpolation sensible + // - to or from -9999 (used as a placeholder) + // - any values that are too high above us, + snprintf(s, 128, cl, i); + strncat(s, "/elevation-ft", 128); + if (current_alt != required_alt) + fgSetDouble(s, required_alt); + + snprintf(s, 128, cl, i); + strncat(s, "/thickness-ft", 128); + if (fgGetDouble(s) != (*layer)->getDoubleValue("thickness-ft")) + fgSetDouble(s, (*layer)->getDoubleValue("thickness-ft")); + + } else { + // Interpolate the other values in the usual way + if (current_alt != required_alt) { + current_alt = interpolate_val(current_alt, + required_alt, + MaxCloudAltitudeChangeFtSec); + fgSetDouble(s, current_alt); + } + + snprintf(s, 128, cl, i); + strncat(s, "/thickness-ft", 128); + currentval = fgGetDouble(s); + requiredval = (*layer)->getDoubleValue("thickness-ft"); + + if (currentval != requiredval) { + currentval = interpolate_val(currentval, + requiredval, + MaxCloudThicknessChangeFtSec); + fgSetDouble(s, currentval); + } + } + } + + } else { + // We haven't already loaded a METAR, so apply it immediately. + dir_from = fgGetDouble("/environment/metar/base-wind-range-from"); + dir_to = fgGetDouble("/environment/metar/base-wind-range-to"); + speed = fgGetDouble("/environment/metar/base-wind-speed-kt"); + gust = fgGetDouble("/environment/metar/gust-wind-speed-kt"); + vis = fgGetDouble("/environment/metar/min-visibility-m"); + pressure = fgGetDouble("/environment/metar/pressure-inhg"); + temp = fgGetDouble("/environment/metar/temperature-degc"); + dewpoint = fgGetDouble("/environment/metar/dewpoint-degc"); + + // Set the cloud layers by copying over the METAR versions. + SGPropertyNode * clouds = fgGetNode("/environment/metar/clouds", true); + + vector layers = clouds->getChildren("layer"); + vector::const_iterator layer; + vector::const_iterator layers_end = layers.end(); + + const char *cl = "/environment/clouds/layer[%i]"; + char s[128]; + int i; + + for (i = 0, layer = layers.begin(); layer != layers_end; ++layer, i++) { + snprintf(s, 128, cl, i); + strncat(s, "/coverage", 128); + fgSetString(s, (*layer)->getStringValue("coverage", "clear")); + + snprintf(s, 128, cl, i); + strncat(s, "/elevation-ft", 128); + fgSetDouble(s, (*layer)->getDoubleValue("elevation-ft")); + + snprintf(s, 128, cl, i); + strncat(s, "/thickness-ft", 128); + fgSetDouble(s, (*layer)->getDoubleValue("thickness-ft")); + + snprintf(s, 128, cl, i); + strncat(s, "/span-m", 128); + fgSetDouble(s, 40000.0); + } + + // Force an update of the 3D clouds + fgSetDouble("/environment/rebuild-layers", 1.0); + } + + fgSetupWind(dir_from, dir_to, speed, gust); + fgDefaultWeatherValue("visibility-m", vis); + set_temp_at_altitude(temp, station_elevation_ft); + set_dewpoint_at_altitude(dewpoint, station_elevation_ft); + fgDefaultWeatherValue("pressure-sea-level-inhg", pressure); + + // We've now successfully loaded a METAR into the configuration + metar_loaded = true; +} + +double FGMetarEnvironmentCtrl::interpolate_prop(const char * currentname, + const char * requiredname, + double dt) +{ + double currentval = fgGetDouble(currentname); + double requiredval = fgGetDouble(requiredname); + return interpolate_val(currentval, requiredval, dt); +} + +double FGMetarEnvironmentCtrl::interpolate_val(double currentval, + double requiredval, + double dt) +{ + double dval = EnvironmentUpdatePeriodSec * dt; - fgDefaultWeatherValue( "visibility-m", - fgGetDouble("/environment/metar/min-visibility-m") ); - set_temp_at_altitude( fgGetDouble("/environment/metar/temperature-degc"), - station_elevation_ft ); - set_dewpoint_at_altitude( fgGetDouble("/environment/metar/dewpoint-degc"), - station_elevation_ft ); - fgDefaultWeatherValue( "pressure-sea-level-inhg", - fgGetDouble("/environment/metar/pressure-inhg") ); + if (fabs(currentval - requiredval) < dval) return requiredval; + if (currentval < requiredval) return (currentval + dval); + if (currentval > requiredval) return (currentval - dval); + return requiredval; } void FGMetarEnvironmentCtrl::init () { - const SGPropertyNode *longitude - = fgGetNode( "/position/longitude-deg", true ); - const SGPropertyNode *latitude - = fgGetNode( "/position/latitude-deg", true ); + SGGeod pos = SGGeod::fromDeg( + fgGetDouble("/position/longitude-deg", true), + fgGetDouble( "/position/latitude-deg", true)); + metar_loaded = false; bool found_metar = false; + long max_age = metar_max_age->getLongValue(); + // Don't check max age during init so that we don't loop over a lot + // of airports metar if there is a problem. + // The update() calls will find a correct metar if things went wrong here + metar_max_age->setLongValue(0); while ( !found_metar && (_error_count < 3) ) { - FGAirport a = globals->get_airports() - ->search( longitude->getDoubleValue(), - latitude->getDoubleValue(), - true ); - FGMetarResult result = fetch_data( a.getId() ); + AirportWithMetar filter; + FGAirport* a = FGAirport::findClosest(pos, 10000.0, &filter); + if (!a) { + break; + } + + FGMetarResult result = fetch_data(a); if ( result.m != NULL ) { - SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.getId()); + SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " + << a->ident()); last_apt = a; - _icao = a.getId(); search_elapsed = 0.0; fetch_elapsed = 0.0; update_metar_properties( result.m ); @@ -413,10 +684,12 @@ FGMetarEnvironmentCtrl::init () } else { // mark as no metar so it doesn't show up in subsequent // searches. - SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a.getId() ); - globals->get_airports()->no_metar( a.getId() ); + SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a->ident() ); + a->setMetar(false); } - } + } // of airprot-with-metar search iteration + + metar_max_age->setLongValue(max_age); } void @@ -424,10 +697,7 @@ FGMetarEnvironmentCtrl::reinit () { _error_count = 0; _error_dt = 0.0; - -#if 0 - update_env_config(); -#endif + metar_loaded = false; env->reinit(); } @@ -435,7 +705,6 @@ FGMetarEnvironmentCtrl::reinit () void FGMetarEnvironmentCtrl::update(double delta_time_sec) { - _dt += delta_time_sec; if (_error_count >= 3) return; @@ -446,43 +715,56 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec) = fgGetNode( "/position/longitude-deg", true ); static const SGPropertyNode *latitude = fgGetNode( "/position/latitude-deg", true ); + SGGeod pos = SGGeod::fromDeg(longitude->getDoubleValue(), + latitude->getDoubleValue()); + search_elapsed += delta_time_sec; fetch_elapsed += delta_time_sec; + interpolate_elapsed += delta_time_sec; // if time for a new search request, push it onto the request // queue if ( search_elapsed > search_interval_sec ) { - FGAirport a = globals->get_airports() - ->search( longitude->getDoubleValue(), - latitude->getDoubleValue(), - true ); - if ( last_apt.getId() != a.getId() - || fetch_elapsed > same_station_interval_sec ) - { - SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.getId()); - request_queue.push( a.getId() ); - last_apt = a; - _icao = a.getId(); - search_elapsed = 0.0; - fetch_elapsed = 0.0; + AirportWithMetar filter; + FGAirport* a = FGAirport::findClosest(pos, 10000.0, &filter); + if (a) { + if ( !last_apt || last_apt->ident() != a->ident() + || fetch_elapsed > same_station_interval_sec ) + { + SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " + << a->ident()); + request_queue.push(a); + last_apt = a; + search_elapsed = 0.0; + fetch_elapsed = 0.0; + } else { + search_elapsed = 0.0; + SG_LOG( SG_GENERAL, SG_INFO, "same station, waiting = " + << same_station_interval_sec - fetch_elapsed ); + } + } else { - search_elapsed = 0.0; - SG_LOG( SG_GENERAL, SG_INFO, "same station, waiting = " - << same_station_interval_sec - fetch_elapsed ); + SG_LOG( SG_GENERAL, SG_WARN, + "Unable to find any airports with metar" ); } + } else if ( interpolate_elapsed > EnvironmentUpdatePeriodSec ) { + // Interpolate the current configuration closer to the actual METAR + update_env_config(); + env->reinit(); + interpolate_elapsed = 0.0; } -#if defined(ENABLE_THREADS) && ENABLE_THREADS +#if !defined(ENABLE_THREADS) // No loader thread running so manually fetch the data - string id = ""; + FGAirport* apt = NULL; while ( !request_queue.empty() ) { - id = request_queue.front(); + apt = request_queue.front(); request_queue.pop(); } - if ( !id.empty() ) { - SG_LOG( SG_GENERAL, SG_INFO, "inline fetching = " << id ); - result = fetch_data( id ); + if (apt) { + SG_LOG( SG_GENERAL, SG_INFO, "inline fetching = " << apt->ident() ); + result = fetch_data( apt ); result_queue.push( result ); } #endif // ENABLE_THREADS @@ -500,8 +782,8 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec) // mark as no metar so it doesn't show up in subsequent // searches, and signal an immediate re-search. SG_LOG( SG_GENERAL, SG_WARN, - "no metar at station = " << result.icao ); - globals->get_airports()->no_metar( result.icao ); + "no metar at station = " << result.airport->ident() ); + result.airport->setMetar(false); search_elapsed = 9999.0; } } @@ -517,10 +799,10 @@ FGMetarEnvironmentCtrl::setEnvironment (FGEnvironment * environment) } FGMetarResult -FGMetarEnvironmentCtrl::fetch_data( const string &icao ) +FGMetarEnvironmentCtrl::fetch_data(FGAirport* apt) { FGMetarResult result; - result.icao = icao; + result.airport = apt; // if the last error was more than three seconds ago, // then pretent nothing happened. @@ -532,31 +814,37 @@ FGMetarEnvironmentCtrl::fetch_data( const string &icao ) _error_count = 0; } - // fetch station elevation if exists - FGAirport a = globals->get_airports()->search( icao ); - station_elevation_ft = a.getElevation(); + station_elevation_ft = apt->getElevation(); // fetch current metar data try { string host = proxy_host->getStringValue(); string auth = proxy_auth->getStringValue(); string port = proxy_port->getStringValue(); - result.m = new FGMetar( icao, host, port, auth); + result.m = new FGMetar( apt->ident(), host, port, auth); - if (result.m->getAge_min() > 4 * 60) { - SG_LOG( SG_GENERAL, SG_WARN, "METAR data too old"); + long max_age = metar_max_age->getLongValue(); + long age = result.m->getAge_min(); + if (max_age && age > max_age) { + SG_LOG( SG_GENERAL, SG_WARN, "METAR data too old (" << age << " min)."); delete result.m; result.m = NULL; - } + + if (++_stale_count > 10) { + _error_count = 1000; + throw sg_io_exception("More than 10 stale METAR messages in a row." + " Check your system time!"); + } + } else + _stale_count = 0; } catch (const sg_io_exception& e) { SG_LOG( SG_GENERAL, SG_WARN, "Error fetching live weather data: " << e.getFormattedMessage().c_str() ); -#if defined(ENABLE_THREADS) && ENABLE_THREADS +#if defined(ENABLE_THREADS) if (_error_count++ >= 3) { SG_LOG( SG_GENERAL, SG_WARN, "Stop fetching data permanently."); - thread->cancel(); - thread->join(); + thread_stop(); } #endif @@ -570,19 +858,25 @@ FGMetarEnvironmentCtrl::fetch_data( const string &icao ) void -FGMetarEnvironmentCtrl::update_metar_properties( FGMetar *m ) +FGMetarEnvironmentCtrl::update_metar_properties( const FGMetar *m ) { int i; double d; char s[128]; + fgSetString("/environment/metar/real-metar", m->getData()); + // don't update with real weather when we use a custom weather scenario + const char *current_scenario = fgGetString("/environment/weather-scenario", "METAR"); + if( strcmp(current_scenario, "METAR") && strcmp(current_scenario, "none")) + return; + fgSetString("/environment/metar/last-metar", m->getData()); fgSetString("/environment/metar/station-id", m->getId()); fgSetDouble("/environment/metar/min-visibility-m", m->getMinVisibility().getVisibility_m() ); fgSetDouble("/environment/metar/max-visibility-m", m->getMaxVisibility().getVisibility_m() ); - SGMetarVisibility *dirvis = m->getDirVisibility(); + const SGMetarVisibility *dirvis = m->getDirVisibility(); for (i = 0; i < 8; i++, dirvis++) { const char *min = "/environment/metar/visibility[%d]/min-m"; const char *max = "/environment/metar/visibility[%d]/max-m"; @@ -613,9 +907,9 @@ FGMetarEnvironmentCtrl::update_metar_properties( FGMetar *m ) m->getPressure_inHg() ); vector cv = m->getClouds(); - vector::iterator cloud; + vector::const_iterator cloud; - const char *cl = "/environment/clouds/layer[%i]"; + const char *cl = "/environment/metar/clouds/layer[%i]"; for (i = 0, cloud = cv.begin(); cloud != cv.end(); cloud++, i++) { const char *coverage_string[5] = { "clear", "few", "scattered", "broken", "overcast" }; @@ -665,37 +959,26 @@ FGMetarEnvironmentCtrl::update_metar_properties( FGMetar *m ) } -#if defined(ENABLE_THREADS) && ENABLE_THREADS -/** - * - */ +#if defined(ENABLE_THREADS) +void +FGMetarEnvironmentCtrl::thread_stop() +{ + request_queue.push(NULL); // ask thread to terminate + thread->join(); +} + void FGMetarEnvironmentCtrl::MetarThread::run() { - pthread_cleanup_push( metar_cleanup_handler, fetcher ); while ( true ) { - set_cancel( SGThread::CANCEL_DISABLE ); - - string icao = fetcher->request_queue.pop(); - SG_LOG( SG_GENERAL, SG_INFO, "Thread: fetch metar data = " << icao ); - FGMetarResult result = fetcher->fetch_data( icao ); - - set_cancel( SGThread::CANCEL_DEFERRED ); - + FGAirport* apt = fetcher->request_queue.pop(); + if (!apt) + return; + SG_LOG( SG_GENERAL, SG_INFO, "Thread: fetch metar data = " << apt->ident() ); + FGMetarResult result = fetcher->fetch_data( apt ); fetcher->result_queue.push( result ); } - pthread_cleanup_pop(1); -} - -/** - * Ensure mutex is unlocked. - */ -void -metar_cleanup_handler( void* arg ) -{ - FGMetarEnvironmentCtrl* fetcher = (FGMetarEnvironmentCtrl*) arg; - fetcher->mutex.unlock(); } #endif // ENABLE_THREADS