#endif
#include "realwx_ctrl.hxx"
-#include "metarproperties.hxx"
-#include "metarairportfilter.hxx"
-#include "fgmetar.hxx"
-
-#include <Main/fg_props.hxx>
+#include <algorithm>
#include <boost/foreach.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/props/tiedpropertylist.hxx>
-#include <simgear/io/HTTPClient.hxx>
#include <simgear/io/HTTPRequest.hxx>
#include <simgear/timing/sg_time.hxx>
#include <simgear/structure/event_mgr.hxx>
+#include <simgear/structure/commands.hxx>
-#include <algorithm>
+#include "metarproperties.hxx"
+#include "metarairportfilter.hxx"
+#include "fgmetar.hxx"
+#include <Network/HTTPClient.hxx>
+#include <Main/fg_props.hxx>
namespace Environment {
-/* -------------------------------------------------------------------------------- */
-
-class FGHTTPClient : public simgear::HTTP::Client {
-public:
- FGHTTPClient();
-};
-FGHTTPClient::FGHTTPClient()
-{
- string proxyHost(fgGetString("/sim/presets/proxy/host"));
- int proxyPort(fgGetInt("/sim/presets/proxy/port"));
- string proxyAuth(fgGetString("/sim/presets/proxy/auth"));
-
- if (!proxyHost.empty()) {
- setProxy(proxyHost, proxyPort, proxyAuth);
- }
-}
/* -------------------------------------------------------------------------------- */
class LiveMetarProperties : public MetarProperties, MetarDataHandler {
public:
- LiveMetarProperties( SGPropertyNode_ptr rootNode, MetarRequester * metarRequester );
+ LiveMetarProperties( SGPropertyNode_ptr rootNode, MetarRequester * metarRequester, int maxAge );
virtual ~LiveMetarProperties();
virtual void update( double dt );
virtual double getTimeToLive() const { return _timeToLive; }
- virtual void setTimeToLive( double value ) { _timeToLive = value; }
+ virtual void resetTimeToLive()
+ { _timeToLive = 0.00; _pollingTimer = 0.0; }
// implementation of MetarDataHandler
virtual void handleMetarData( const std::string & data );
double _timeToLive;
double _pollingTimer;
MetarRequester * _metarRequester;
+ int _maxAge;
};
typedef SGSharedPtr<LiveMetarProperties> LiveMetarProperties_ptr;
-LiveMetarProperties::LiveMetarProperties( SGPropertyNode_ptr rootNode, MetarRequester * metarRequester ) :
+LiveMetarProperties::LiveMetarProperties( SGPropertyNode_ptr rootNode, MetarRequester * metarRequester, int maxAge ) :
MetarProperties( rootNode ),
_timeToLive(0.0),
_pollingTimer(0.0),
- _metarRequester(metarRequester)
+ _metarRequester(metarRequester),
+ _maxAge(maxAge)
{
_tiedProperties.Tie("time-to-live", &_timeToLive );
}
{
_timeToLive -= dt;
_pollingTimer -= dt;
- if( _timeToLive < 0.0 ) {
+ if( _timeToLive <= 0.0 ) {
_timeToLive = 0.0;
std::string stationId = getStationId();
if( stationId.empty() ) return;
void LiveMetarProperties::handleMetarData( const std::string & data )
{
- SG_LOG( SG_ENVIRONMENT, SG_INFO, "LiveMetarProperties::handleMetarData() received METAR for " << getStationId() << ": " << data );
+ SG_LOG( SG_ENVIRONMENT, SG_DEBUG, "LiveMetarProperties::handleMetarData() received METAR for " << getStationId() << ": " << data );
_timeToLive = DEFAULT_TIME_TO_LIVE_SECONDS;
- setMetar( data );
+
+ SGSharedPtr<FGMetar> m;
+ try {
+ m = new FGMetar(data.c_str());
+ }
+ catch( sg_io_exception ) {
+ SG_LOG( SG_ENVIRONMENT, SG_WARN, "Can't parse metar: " << data );
+ return;
+ }
+
+ if (_maxAge && (m->getAge_min() > _maxAge)) {
+ // METAR is older than max-age, ignore
+ SG_LOG( SG_ENVIRONMENT, SG_DEBUG, "Ignoring outdated METAR for " << getStationId());
+ return;
+ }
+
+ setMetar( m );
}
/* -------------------------------------------------------------------------------- */
virtual void reinit ();
virtual void shutdown ();
+ /**
+ * Create a metar-property binding at the specified property path,
+ * and initiate a request for the specified station-ID (which may be
+ * empty). If the property path is already mapped, the station ID
+ * will be updated.
+ */
+ void addMetarAtPath(const string& propPath, const string& icao);
+
+ void removeMetarAtPath(const string& propPath);
protected:
void bind();
void unbind();
SGPropertyNode_ptr _max_age_n;
bool _enabled;
- bool __enabled;
+ bool _wasEnabled;
simgear::TiedPropertyList _tiedProperties;
typedef std::vector<LiveMetarProperties_ptr> MetarPropertiesList;
MetarPropertiesList _metarProperties;
+ MetarRequester* _requester;
};
+static bool commandRequestMetar(const SGPropertyNode* arg)
+{
+ SGSubsystemGroup* envMgr = (SGSubsystemGroup*) globals->get_subsystem("environment");
+ if (!envMgr) {
+ return false;
+ }
+
+ BasicRealWxController* self = (BasicRealWxController*) envMgr->get_subsystem("realwx");
+ if (!self) {
+ return false;
+ }
+
+ string icao(arg->getStringValue("station"));
+ boost::to_upper(icao);
+ string path = arg->getStringValue("path");
+ self->addMetarAtPath(path, icao);
+ return true;
+}
+
+static bool commandClearMetar(const SGPropertyNode* arg)
+{
+ SGSubsystemGroup* envMgr = (SGSubsystemGroup*) globals->get_subsystem("environment");
+ if (!envMgr) {
+ return false;
+ }
+
+ BasicRealWxController* self = (BasicRealWxController*) envMgr->get_subsystem("realwx");
+ if (!self) {
+ return false;
+ }
+
+ string path = arg->getStringValue("path");
+ self->removeMetarAtPath(path);
+ return true;
+}
+
/* -------------------------------------------------------------------------------- */
/*
Properties
_ground_elevation_n( fgGetNode( "/position/ground-elev-m", true )),
_max_age_n( fgGetNode( "/environment/params/metar-max-age-min", false ) ),
_enabled(true),
- __enabled(false)
+ _wasEnabled(false),
+ _requester(metarRequester)
{
// at least instantiate MetarProperties for /environment/metar
_metarProperties.push_back( new LiveMetarProperties(
- fgGetNode( rootNode->getStringValue("metar", "/environment/metar"), true ), metarRequester ));
+ fgGetNode( rootNode->getStringValue("metar", "/environment/metar"), true ),
+ metarRequester,
+ getMetarMaxAgeMin()));
BOOST_FOREACH( SGPropertyNode_ptr n, rootNode->getChildren("metar") ) {
- SGPropertyNode_ptr metarNode = fgGetNode( n->getStringValue(), true );
-
- // check for duplicate entries
- bool existingElement = false;
- BOOST_FOREACH( LiveMetarProperties_ptr p, _metarProperties ) {
- if( p->get_root_node()->getPath() == metarNode->getPath() ) {
- existingElement = true;
- break;
- }
- }
-
- if( existingElement )
- continue;
-
- SG_LOG( SG_ENVIRONMENT, SG_INFO, "Adding metar properties at " << metarNode->getPath() );
- _metarProperties.push_back( new LiveMetarProperties( metarNode, metarRequester ));
+ SGPropertyNode_ptr metarNode = fgGetNode( n->getStringValue(), true );
+ addMetarAtPath(metarNode->getPath(), "");
}
+
+ SGCommandMgr::instance()->addCommand("request-metar", commandRequestMetar);
+ SGCommandMgr::instance()->addCommand("clear-metar", commandClearMetar);
}
BasicRealWxController::~BasicRealWxController()
{
+ //SGCommandMgr::instance()->removeCommand("request-metar");
}
void BasicRealWxController::init()
{
- __enabled = false;
+ _wasEnabled = false;
+
+ checkNearbyMetar();
update(0); // fetch data ASAP
globals->get_event_mgr()->addTask("checkNearbyMetar", this,
void BasicRealWxController::reinit()
{
- __enabled = false;
+ _wasEnabled = false;
+ checkNearbyMetar();
+ update(0); // fetch data ASAP
}
void BasicRealWxController::shutdown()
}
void BasicRealWxController::update( double dt )
-{
+{
if( _enabled ) {
- bool firstIteration = !__enabled; // first iteration after being enabled?
-
+ bool firstIteration = !_wasEnabled;
// clock tick for every METAR in stock
BOOST_FOREACH(LiveMetarProperties* p, _metarProperties) {
// first round? All received METARs are outdated
- if( firstIteration ) p->setTimeToLive( 0.0 );
+ if( firstIteration ) p->resetTimeToLive();
p->update(dt);
}
- __enabled = true;
+ _wasEnabled = true;
} else {
- __enabled = false;
+ _wasEnabled = false;
}
}
+void BasicRealWxController::addMetarAtPath(const string& propPath, const string& icao)
+{
+ // check for duplicate entries
+ BOOST_FOREACH( LiveMetarProperties_ptr p, _metarProperties ) {
+ if( p->get_root_node()->getPath() == propPath ) {
+ // already exists
+ if (p->getStationId() != icao) {
+ p->setStationId(icao);
+ p->resetTimeToLive();
+ }
+
+ return;
+ }
+ } // of exitsing metar properties iteration
+
+ SGPropertyNode_ptr metarNode = fgGetNode(propPath, true);
+ SG_LOG( SG_ENVIRONMENT, SG_INFO, "Adding metar properties at " << propPath );
+ LiveMetarProperties_ptr p(new LiveMetarProperties( metarNode, _requester, getMetarMaxAgeMin() ));
+ _metarProperties.push_back(p);
+ p->setStationId(icao);
+}
+
+void BasicRealWxController::removeMetarAtPath(const string &propPath)
+{
+ MetarPropertiesList::iterator it = _metarProperties.begin();
+ for (; it != _metarProperties.end(); ++it) {
+ LiveMetarProperties_ptr p(*it);
+ if( p->get_root_node()->getPath() == propPath ) {
+ _metarProperties.erase(it);
+ // final ref will drop, and delete the MetarProperties, when we return
+ return;
+ }
+ }
+
+ SG_LOG(SG_ENVIRONMENT, SG_WARN, "no metar properties at " << propPath);
+}
+
void BasicRealWxController::checkNearbyMetar()
{
try {
_metarProperties[0]->getStationId() <<
"', new: '" << nearestAirport->ident() << "'" );
_metarProperties[0]->setStationId( nearestAirport->ident() );
- _metarProperties[0]->setTimeToLive( 0.0 );
+ _metarProperties[0]->resetTimeToLive();
}
}
catch( sg_exception & ) {
class NoaaMetarRealWxController : public BasicRealWxController, MetarRequester {
public:
NoaaMetarRealWxController( SGPropertyNode_ptr rootNode );
- virtual ~NoaaMetarRealWxController();
- virtual void update( double dt );
// implementation of MetarRequester
virtual void requestMetar( MetarDataHandler * metarDataHandler, const std::string & id );
private:
- FGHTTPClient _http;
+
};
NoaaMetarRealWxController::NoaaMetarRealWxController( SGPropertyNode_ptr rootNode ) :
{
}
-NoaaMetarRealWxController::~NoaaMetarRealWxController()
-{
-}
-
-void NoaaMetarRealWxController::update( double dt )
-{
- _http.update();
- BasicRealWxController::update( dt );
-}
-
void NoaaMetarRealWxController::requestMetar( MetarDataHandler * metarDataHandler, const std::string & id )
{
class NoaaMetarGetRequest : public simgear::HTTP::Request
virtual void responseComplete()
{
if (responseCode() == 200) {
- _metarDataHandler->handleMetarData( _metar);
+ _metarDataHandler->handleMetarData( simgear::strutils::simplify(_metar) );
} else {
SG_LOG(SG_ENVIRONMENT, SG_WARN, "metar download failed:" << url() << ": reason:" << responseReason());
}
}
-
- bool fromMetarProxy() const
- { return _fromProxy; }
+
+ virtual void failed()
+ {
+ SG_LOG(SG_ENVIRONMENT, SG_INFO, "metar download failure");
+ }
+
+// bool fromMetarProxy() const
+// { return _fromProxy; }
private:
string _metar;
bool _fromProxy;
MetarDataHandler * _metarDataHandler;
};
+ string upperId = boost::to_upper_copy(id);
- SG_LOG(SG_ENVIRONMENT, SG_INFO,
- "NoaaMetarRealWxController::update(): spawning load request for station-id '" << id << "'" );
- _http.makeRequest(new NoaaMetarGetRequest(metarDataHandler, id));
+ SG_LOG(SG_ENVIRONMENT, SG_INFO,
+ "NoaaMetarRealWxController::update(): spawning load request for station-id '" << upperId << "'" );
+ FGHTTPClient* http = static_cast<FGHTTPClient*>(globals->get_subsystem("http"));
+ if (http) {
+ http->makeRequest(new NoaaMetarGetRequest(metarDataHandler, upperId));
+ }
}
/* -------------------------------------------------------------------------------- */
RealWxController * RealWxController::createInstance( SGPropertyNode_ptr rootNode )
{
-// string dataSource = rootNode->getStringValue("data-source", "noaa" );
-// if( dataSource == "nwx" ) {
-// return new NwxMetarRealWxController( rootNode );
-// } else {
- return new NoaaMetarRealWxController( rootNode );
-// }
+ return new NoaaMetarRealWxController( rootNode );
}
/* -------------------------------------------------------------------------------- */