update_interval_sec( 60.0 ),
elapsed( 60.0 )
{
+#ifdef ENABLE_THREADS
+ thread = new MetarThread(this);
+ thread->start();
+#endif // ENABLE_THREADS
}
FGMetarEnvironmentCtrl::~FGMetarEnvironmentCtrl ()
{
+#ifdef ENABLE_THREADS
+ thread->cancel();
+ thread->join();
+#endif // ENABLE_THREADS
+
delete env;
env = NULL;
}
void
FGMetarEnvironmentCtrl::update(double delta_time_sec)
{
- const SGPropertyNode *longitude
+ static const SGPropertyNode *longitude
= fgGetNode( "/position/longitude-deg", true );
- const SGPropertyNode *latitude
+ static const SGPropertyNode *latitude
= fgGetNode( "/position/latitude-deg", true );
elapsed += delta_time_sec;
if ( elapsed > update_interval_sec ) {
globals->get_airports()->no_metar( a.id );
}
}
+
env->update(delta_time_sec);
}
station_elevation_ft = a.elevation;
// fetch current metar data
- SGMetar *m;
+ SGMetar *m = NULL;
+#ifdef ENABLE_THREADS
+
+ bool valid_data = false;
+ if (!metar_queue.empty())
+ {
+ m = metar_queue.pop();
+
+ if (m != NULL)
+ valid_data = true;
+ }
+
+ if ( valid_data == false ) {
+ mutex.lock();
+ metar_cond.signal();
+ mutex.unlock();
+
+ return false;
+ }
+#else
try {
m = new SGMetar( _icao.c_str() );
} catch (const sg_io_exception& e) {
<< e.getFormattedMessage().c_str() );
return false;
}
+#endif // ENABLE_THREADS
d = m->getMinVisibility().getVisibility_m();
d = (d != SGMetarNaN) ? d : 10000;
delete m;
+#ifdef ENABLE_THREADS
+ mutex.lock();
+ metar_cond.signal();
+ mutex.unlock();
+#endif // ENABLE_THREADS
+
return true;
}
+#ifdef ENABLE_THREADS
+/**
+ *
+ */
+void
+FGMetarEnvironmentCtrl::MetarThread::run()
+{
+ SGMetar *m = NULL;
+
+ // pthread_cleanup_push( metar_cleanup_handler, fetcher );
+ while ( true )
+ {
+ set_cancel( SGThread::CANCEL_DISABLE );
+ try
+ {
+ cout << "Fetching ..." << endl;
+ // if (m != NULL) m = NULL;
+ m = new SGMetar( fetcher->_icao.c_str() );
+
+ } catch (const sg_io_exception& e) {
+ // SG_LOG( SG_GENERAL, SG_WARN, "Error fetching live weather data: "
+ // << e.getFormattedMessage().c_str() );
+ m = NULL;
+ }
+ set_cancel( SGThread::CANCEL_DEFERRED );
+
+ fetcher->metar_queue.push( m );
+
+ // Wait for the next frame signal before we fetch the next metar data
+ fetcher->mutex.lock();
+ fetcher->metar_cond.wait( fetcher->mutex );
+ fetcher->mutex.unlock();
+ }
+ // pthread_cleanup_pop(1);
+}
+
+/**
+ * Ensure mutex is unlocked.
+ */
+void
+metar_cleanup_handler( void* arg )
+{
+ FGMetarEnvironmentCtrl* fetcher = (FGMetarEnvironmentCtrl*) arg;
+ fetcher->mutex.unlock();
+}
+#endif // ENABLE_THREADS
+
// end of environment_ctrl.cxx
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/environment/metar.hxx>
+#ifdef ENABLE_THREADS
+# include <simgear/threads/SGThread.hxx>
+# include <simgear/threads/SGQueue.hxx>
+#endif
+
#ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
#else
float elapsed;
bool fetch_data (const string &icao);
void update_env_config();
+
+private:
+
+#ifdef ENABLE_THREADS
+ /**
+ * FIFO queue which holds a pointer to the fetched metar data.
+ */
+ SGBlockingQueue< SGMetar * > metar_queue;
+
+ /**
+ * This class represents the thread of execution responsible for
+ * fetching the metar data.
+ */
+ class MetarThread : public SGThread
+ {
+ public:
+ MetarThread( FGMetarEnvironmentCtrl* f ) : fetcher(f) {}
+ ~MetarThread() {}
+
+ /**
+ * Reads the tile from disk.
+ */
+ void run();
+
+ private:
+ FGMetarEnvironmentCtrl *fetcher;
+
+ private:
+ // not implemented.
+ MetarThread();
+ MetarThread( const MetarThread& );
+ MetarThread& operator=( const MetarThread& );
+ };
+
+ friend class MetarThread;
+
+ /**
+ * Metar data fetching thread.
+ */
+ MetarThread* thread;
+
+ /**
+ * Lock and synchronize access to metar queue.
+ */
+ SGMutex mutex;
+ SGPthreadCond metar_cond;
+
+ /**
+ * Thread cleanup handler.
+ */
+ friend void metar_cleanup_handler( void* );
+#endif // ENABLE_THREADS
};
#endif // _ENVIRONMENT_CTRL_HXX