]> git.mxchange.org Git - simgear.git/commitdiff
Melchior FRANZ:
authorehofman <ehofman>
Thu, 20 Jan 2005 09:28:04 +0000 (09:28 +0000)
committerehofman <ehofman>
Thu, 20 Jan 2005 09:28:04 +0000 (09:28 +0000)
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)

simgear/environment/metar.cxx
simgear/environment/metar.hxx

index 124fa3f2701a768753ca929a397290a8eed6fc10..09ccbb7ab4881b6a51ae78602cb3976687c07c5a 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include <string>
+#include <time.h>
 
 #include <simgear/io/sg_socket.hxx>
 #include <simgear/debug/logstream.hxx>
  * 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
index f6e0b6b08deb39d536d66b6073182f420c8bb650..631d3e31dc323b5b9f8e6184423ea329918efff6 100644 (file)
@@ -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<SGMetarCloud>& 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();
 };