*/
#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),
_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());
_icao[0] = '\0';
// NOAA preample
- scanPreambleDate();
+ if (!scanPreambleDate())
+ useCurrentDate();
scanPreambleTime();
// METAR header
delete[] _data;
throw sg_io_exception("metar data incomplete (" + _url + ')');
}
+
_url = "";
}
}
+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
* @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;
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)
if (gust != NaN)
_gust_speed = gust * factor;
_grpcount++;
- return false;
+ return true;
}
}
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++) {
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;
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;
}
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
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
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; }
friend class SGMetar;
public:
SGMetarRunway() :
- _deposit(0),
+ _deposit(-1),
+ _deposit_string(0),
_extent(-1),
_extent_string(0),
_depth(NaN),
_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; }
protected:
SGMetarVisibility _min_visibility;
SGMetarVisibility _max_visibility;
- const char *_deposit;
+ int _deposit;
+ const char *_deposit_string;
int _extent;
const char *_extent_string;
double _depth;
_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; }
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 {
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; }
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; }
protected:
string _url;
int _grpcount;
+ bool _x_proxy;
char *_data;
char *_m;
char _icao[5];
double _temp;
double _dewp;
double _pressure;
+ int _rain;
+ int _hail;
+ int _snow;
+ bool _cavok;
SGMetarVisibility _min_visibility;
SGMetarVisibility _max_visibility;
bool scanPreambleDate();
bool scanPreambleTime();
+ void useCurrentDate();
bool scanType();
bool scanId();
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();
};