From: ehofman Date: Thu, 20 Jan 2005 09:28:04 +0000 (+0000) Subject: Melchior FRANZ: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=1e87dd790344ccbe9078dc506652cfebf09b9ac1;p=simgear.git Melchior FRANZ: The following patches to SimGear & FlightGear ... - create an FGMetar abstraction layer, whose purpose is: * provide defaults for unset values * interpolate/randomize data (GREATER_THAN) * derive additional values (time, age, snow cover) * consider minimum identifier (CAVOK, mil. color codes) - add rain/hail/snow/snowcover support on the METAR side - add max age of METAR data handling (currently set to - add support for an external METAR cache proxy server - add CAVOK handling - set missing year/month in regular METAR messages - fix a small bug in metar.cxx (wrong return value) --- diff --git a/simgear/environment/metar.cxx b/simgear/environment/metar.cxx index 124fa3f2..09ccbb7a 100644 --- a/simgear/environment/metar.cxx +++ b/simgear/environment/metar.cxx @@ -26,6 +26,7 @@ */ #include +#include #include #include @@ -59,8 +60,10 @@ * double d = n.getDewpoint_C(); * @endcode */ -SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const string& auth) : +SGMetar::SGMetar(const string& m, const string& proxy, const string& port, + const string& auth, const time_t time) : _grpcount(0), + _x_proxy(false), _year(-1), _month(-1), _day(-1), @@ -74,13 +77,17 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const _wind_range_to(-1), _temp(NaN), _dewp(NaN), - _pressure(NaN) + _pressure(NaN), + _rain(false), + _hail(false), + _snow(false), + _cavok(false) { if (m.length() == 4 && isalnum(m[0]) && isalnum(m[1]) && isalnum(m[2]) && isalnum(m[3])) { for (int i = 0; i < 4; i++) _icao[i] = toupper(m[i]); _icao[4] = '\0'; - _data = loadData(_icao, proxy, port, auth); + _data = loadData(_icao, proxy, port, auth, time); } else { _data = new char[m.length() + 2]; // make room for " \0" strcpy(_data, m.c_str()); @@ -92,7 +99,8 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const _icao[0] = '\0'; // NOAA preample - scanPreambleDate(); + if (!scanPreambleDate()) + useCurrentDate(); scanPreambleTime(); // METAR header @@ -127,6 +135,7 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const delete[] _data; throw sg_io_exception("metar data incomplete (" + _url + ')'); } + _url = ""; } @@ -143,6 +152,16 @@ SGMetar::~SGMetar() } +void SGMetar::useCurrentDate() +{ + struct tm now; + time_t now_sec = time(0); + gmtime_r(&now_sec, &now); + _year = now.tm_year + 1900; + _month = now.tm_mon + 1; +} + + /** * If called with "KSFO" loads data from * @code @@ -157,10 +176,15 @@ SGMetar::~SGMetar() * @return pointer to Metar data string, allocated by new char[]. * @see rfc2068.txt for proxy spec ("Proxy-Authorization") */ -char *SGMetar::loadData(const char *id, const string& proxy, const string& port, const string& auth) +char *SGMetar::loadData(const char *id, const string& proxy, const string& port, + const string& auth, time_t time) { + const int buflen = 512; + char buf[2 * buflen]; + string host = proxy.empty() ? "weather.noaa.gov" : proxy; string path = "/pub/data/observations/metar/stations/"; + path += string(id) + ".TXT"; _url = "http://weather.noaa.gov" + path; @@ -174,24 +198,25 @@ char *SGMetar::loadData(const char *id, const string& proxy, const string& port, string get = "GET "; if (!proxy.empty()) get += "http://weather.noaa.gov"; - get += path + " HTTP/1.0\r\n"; - sock->writestring(get.c_str()); - if (!auth.empty()) { - get = "Proxy-Authorization: " + auth + "\r\n"; - sock->writestring(get.c_str()); - } + sprintf(buf, "%ld", time); + get += path + " HTTP/1.0\015\012X-Time: " + buf + "\015\012"; - sock->writestring("\r\n"); + if (!auth.empty()) + get += "Proxy-Authorization: " + auth + "\015\012"; + + get += "\015\012"; + sock->writestring(get.c_str()); int i; - const int buflen = 512; - char buf[2 * buflen]; // skip HTTP header - while ((i = sock->readline(buf, buflen))) + while ((i = sock->readline(buf, buflen))) { if (i <= 2 && isspace(buf[0]) && (!buf[1] || isspace(buf[1]))) break; + if (!strncmp(buf, "X-MetarProxy: ", 9)) + _x_proxy = true; + } if (i) { i = sock->readline(buf, buflen); if (i) @@ -392,7 +417,7 @@ bool SGMetar::scanWind() if (gust != NaN) _gust_speed = gust * factor; _grpcount++; - return false; + return true; } @@ -643,14 +668,15 @@ bool SGMetar::scanWeather() } string pre, post; + int intensity = 0; if (*m == '-') - m++, pre = "light "; + m++, pre = "light ", intensity = 1; else if (*m == '+') - m++, pre = "heavy "; + m++, pre = "heavy ", intensity = 3; else if (!strncmp(m, "VC", 2)) m += 2, post = "in the vicinity "; else - pre = "moderate "; + pre = "moderate ", intensity = 2; int i; for (i = 0; i < 3; i++) { @@ -662,6 +688,12 @@ bool SGMetar::scanWeather() if (!(a = scanToken(&m, phenomenon))) break; weather += string(a->text) + " "; + if (!strcmp(a->id, "RA")) + _rain = intensity; + else if (!strcmp(a->id, "HA")) + _hail = intensity; + else if (!strcmp(a->id, "SN")) + _snow = intensity; } if (!weather.length()) return false; @@ -714,8 +746,13 @@ bool SGMetar::scanSkyCondition() m += i; if (!scanBoundary(&m)) return false; - cl._coverage = 0; - _clouds.push_back(cl); + + if (i == 3) { + cl._coverage = 0; + _clouds.push_back(cl); + } else { + _cavok = true; + } _m = m; return true; } @@ -907,10 +944,11 @@ bool SGMetar::scanRunwayReport() if (!strncmp(m, "CLRD", 4)) { m += 4; // runway cleared - r._deposit = "cleared"; + r._deposit_string = "cleared"; } else { if (scanNumber(&m, &i, 1)) { - r._deposit = runway_deposit[i]; + r._deposit = i; + r._deposit_string = runway_deposit[i]; } else if (*m == '/') m++; else @@ -1137,4 +1175,24 @@ const struct Token *SGMetar::scanToken(char **str, const struct Token *list) return longest; } + +void SGMetarCloud::set(double alt, int cov) +{ + _altitude = alt; + if (cov != -1) + _coverage = cov; +} + + +void SGMetarVisibility::set(double dist, int dir, int mod, int tend) +{ + _distance = dist; + if (dir != -1) + _direction = dir; + if (mod != -1) + _modifier = mod; + if (tend != 1) + _tendency = tend; +} + #undef NaN diff --git a/simgear/environment/metar.hxx b/simgear/environment/metar.hxx index f6e0b6b0..631d3e31 100644 --- a/simgear/environment/metar.hxx +++ b/simgear/environment/metar.hxx @@ -67,6 +67,8 @@ public: DECREASING }; + void set(double dist, int dir = -1, int mod = -1, int tend = -1); + inline double getVisibility_m() const { return _distance; } inline double getVisibility_ft() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_FEET; } inline double getVisibility_sm() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_SM; } @@ -87,7 +89,8 @@ class SGMetarRunway { friend class SGMetar; public: SGMetarRunway() : - _deposit(0), + _deposit(-1), + _deposit_string(0), _extent(-1), _extent_string(0), _depth(NaN), @@ -96,7 +99,8 @@ public: _comment(0), _wind_shear(false) {} - inline const char *getDeposit() const { return _deposit; } + inline int getDeposit() const { return _deposit; } + inline const char *getDepositString() const { return _deposit_string; } inline double getExtent() const { return _extent; } inline const char *getExtentString() const { return _extent_string; } inline double getDepth() const { return _depth; } @@ -110,7 +114,8 @@ public: protected: SGMetarVisibility _min_visibility; SGMetarVisibility _max_visibility; - const char *_deposit; + int _deposit; + const char *_deposit_string; int _extent; const char *_extent_string; double _depth; @@ -131,6 +136,8 @@ public: _type(0), _type_long(0) {} + void set(double alt, int cov = -1); + inline int getCoverage() const { return _coverage; } inline double getAltitude_m() const { return _altitude; } inline double getAltitude_ft() const { return _altitude == NaN ? NaN : _altitude * SG_METER_TO_FEET; } @@ -147,7 +154,8 @@ protected: class SGMetar { public: - SGMetar(const string& m, const string& proxy = "", const string& port = "", const string &auth = ""); + SGMetar(const string& m, const string& proxy = "", const string& port = "", + const string &auth = "", const time_t time = 0); ~SGMetar(); enum ReportType { @@ -159,6 +167,7 @@ public: inline const char *getData() const { return _data; } inline const char *getUnusedData() const { return _m; } + inline const bool getProxy() const { return _x_proxy; } inline const char *getId() const { return _icao; } inline int getYear() const { return _year; } inline int getMonth() const { return _month; } @@ -193,6 +202,11 @@ public: inline double getPressure_hPa() const { return _pressure == NaN ? NaN : _pressure / 100; } inline double getPressure_inHg() const { return _pressure == NaN ? NaN : _pressure * SG_PA_TO_INHG; } + inline int getRain() const { return _rain; } + inline int getHail() const { return _hail; } + inline int getSnow() const { return _snow; } + inline bool getCAVOK() const { return _cavok; } + double getRelHumidity() const; inline vector& getClouds() { return _clouds; } @@ -202,6 +216,7 @@ public: protected: string _url; int _grpcount; + bool _x_proxy; char *_data; char *_m; char _icao[5]; @@ -219,6 +234,10 @@ protected: double _temp; double _dewp; double _pressure; + int _rain; + int _hail; + int _snow; + bool _cavok; SGMetarVisibility _min_visibility; SGMetarVisibility _max_visibility; @@ -230,6 +249,7 @@ protected: bool scanPreambleDate(); bool scanPreambleTime(); + void useCurrentDate(); bool scanType(); bool scanId(); @@ -253,7 +273,8 @@ protected: int scanNumber(char **str, int *num, int min, int max = 0); bool scanBoundary(char **str); const struct Token *scanToken(char **str, const struct Token *list); - char *loadData(const char *id, const string& proxy, const string& port, const string &auth); + char *loadData(const char *id, const string& proxy, const string& port, + const string &auth, time_t time); void normalizeData(); };