Skip to content

Commit

Permalink
Feat/RT/Weather: Initial parsing of METAR report
Browse files Browse the repository at this point in the history
  • Loading branch information
TwinFan committed Jul 20, 2024
1 parent 942d2c5 commit bd9623f
Show file tree
Hide file tree
Showing 16 changed files with 474 additions and 72 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@
[submodule "Lib/parson"]
path = Lib/parson
url = https://github.com/kgabis/parson
[submodule "Lib/metaf"]
path = Lib/metaf
url = https://github.com/TwinFan/metaf
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}/Lib/ImGui")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/Lib/ImGui/misc/cpp")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/Lib/ImgWindow")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/Lib/Font")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/Lib/metaf/include")

################################################################################
# Source groups
Expand Down Expand Up @@ -184,6 +185,7 @@ set(Header_Files
Lib/ImgWindow/SystemGL.h
Lib/Font/IconsFontAwesome5.h
Lib/Font/fa-solid-900.inc
Lib/metaf/include/metaf.hpp
Lib/XPMP2/inc/XPCAircraft.h
Lib/XPMP2/inc/XPMPMultiplayer.h
Lib/XPMP2/lib/fmod/logo/FMOD_Logo.h
Expand Down
Binary file modified Data/RealTraffic/RealTraffic API.pdf
Binary file not shown.
53 changes: 39 additions & 14 deletions Include/LTWeather.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#ifndef LTWeather_h
#define LTWeather_h

class LTWeather;

/// Initialize Weather module, dataRefs
bool WeatherInit ();
/// Shutdown Weather module
Expand All @@ -30,14 +32,19 @@ void WeatherStop ();
bool WeatherCanSet ();
/// Shall we actuall set the weather as per ability and user's configuration?
bool WeatherShallSet ();

/// Indicate that we are taking control now
void WeatherTakeControl ();
/// Are we controlling weather?
bool WeatherInControl ();

/// Thread-safely store weather information to be set in X-Plane in the main thread later
void WeatherSet (const LTWeather& w);
/// Actually update X-Plane's weather if there is anything to do (called from main thread)
void WeatherUpdate ();
/// Reset weather settings to what they were before X-Plane took over
void WeatherReset ();

/// Log current weather
void WeatherLogCurrent (const std::string& msg);

/// Return a human readable string on the weather source, is "LiveTraffic" if WeatherInControl()
std::string WeatherGetSource ();

Expand All @@ -46,18 +53,25 @@ std::string WeatherGetSource ();
//

/// Distance when next weather is set to update immediately instead of gradually
constexpr double WEATHER_MAX_DIST = 50 * M_per_NM;
constexpr double WEATHER_MAX_DIST_M = 50 * M_per_NM;
/// Minimum thickness of a METAR cloud layer [m]
constexpr float WEATHER_MIN_CLOUD_HEIGHT_M = 300;
/// May height AGL up to which we weigh METAR higher than other weather data
constexpr double PREFER_METAR_MAX_AGL_M = 5000.0 * M_per_FT;

/// @brief Weather data to be set in X-Plane
/// @details A value of `NAN` means: don't set.
struct LTWeather
class LTWeather
{
public:
/// Interpolation settings: indexes and weights to take over values from a differently sized float array
struct InterpolSet {
size_t i = 0; ///< lower index, other is i+1
float w = 1.0f; ///< weight on lower index' value, other weight is 1.0f-w
};

positionTy pos; ///< position the weather refers to

float visibility_reported_sm = NAN; ///< float y statute_miles = 0. The reported visibility (e.g. what the METAR/weather window says).
float sealevel_pressure_pas = NAN; ///< float y pascals Pressure at sea level, current planet
float sealevel_temperature_c = NAN; ///< float y degreesC The temperature at sea level.
Expand All @@ -83,17 +97,14 @@ struct LTWeather
float thermal_rate_ms = NAN; ///< float y m/s >= 0 The climb rate for thermals.
float wave_amplitude = NAN; ///< float y meters Amplitude of waves in the water (height of waves)
float wave_dir = NAN; ///< float y degrees Direction of waves.
float runway_friction = NAN; ///< float y enum The friction constant for runways (how wet they are). Dry = 0, wet(1-3), puddly(4-6), snowy(7-9), icy(10-12), snowy/icy(13-15)
int runway_friction = 0; ///< int y enum The friction constant for runways (how wet they are). Dry = 0, wet(1-3), puddly(4-6), snowy(7-9), icy(10-12), snowy/icy(13-15)
float variability_pct = 0; ///< float y ratio How randomly variable the weather is over distance. Range 0 - 1.

static positionTy lastPos; ///< last position for which weather was set (to check if next one is "far" awar and deserves to be updated immedlately

bool update_immediately = false; ///< int y bool If this is true, any weather region changes EXCEPT CLOUDS will take place immediately instead of at the next update interval (currently 60 seconds).
std::string metar; ///< METAR, if filled combine METAR data into weather generation

public:
LTWeather(); ///< Constructor sets all arrays to all `NAN`

void Set (bool bForceImmediately = false); ///< Set the given weather in X-Plane
void Get (const std::string& logMsg = ""); ///< Read weather from X-Plane
void Log (const std::string& msg) const; ///< Log values to Log.txt

/// @brief Compute interpolation settings to fill one array from a differently sized one
/// @details: Both arrays are supposed to be sorted ascending.
/// They hold e.g. altimeter values of weather layers.
Expand All @@ -109,14 +120,28 @@ struct LTWeather
void InterpolateDir (const std::array<InterpolSet,13>& aInterpol,
const std::vector<float>& from,
std::array<float,13>& to);

protected:
static positionTy lastPos; ///< last position for which weather was set (to check if next one is "far" awar and deserves to be updated immedlately

protected:
void Set () const; ///< Set the given weather in X-Plane
void Get (const std::string& logMsg = ""); ///< Read weather from X-Plane, if `logMsg` non-empty then log immediately (mith `logMsg` appearing on top)
void Log (const std::string& msg) const; ///< Log values to Log.txt

void IncorporateMETAR (); ///< add information from the METAR into the data (run from XP's main thread, so can use XP SDK, just before LTWeather::Set())

// Some global functions require access
friend void WeatherSet (const LTWeather& w);
friend void WeatherUpdate ();
friend void WeatherLogCurrent (const std::string& msg);
};

//
// MARK: Fetch METAR
//

/// Asynchronously, fetch fresh weather information
bool WeatherUpdate (const positionTy& pos, float radius_nm);
bool WeatherFetchUpdate (const positionTy& pos, float radius_nm);

#endif /* LTWeather_h */
3 changes: 3 additions & 0 deletions Include/LiveTraffic.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ std::string GetNearestAirportId (const positionTy& _pos, positionTy* outApPos =
inline std::string GetNearestAirportId (float lat, float lon)
{ return GetNearestAirportId(positionTy((double)lat,(double)lon)); }

/// Fetch specific airport location/altitude
positionTy GetAirportLoc (const std::string sICAO);

/// Convert ADS-B Emitter Category to text
const char* GetADSBEmitterCat (const std::string& cat);

Expand Down
1 change: 1 addition & 0 deletions Lib/metaf
Submodule metaf added at 21f23a
4 changes: 4 additions & 0 deletions LiveTraffic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@
25EF90052B497C7900D7C805 /* LTSynthetic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LTSynthetic.h; sourceTree = "<group>"; };
25EFC76B249567BF005DB0A6 /* IconsFontAwesome5.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IconsFontAwesome5.h; sourceTree = "<group>"; };
25EFC76C249567BF005DB0A6 /* fa-solid-900.inc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.pascal; path = "fa-solid-900.inc"; sourceTree = "<group>"; };
25F108C22C49A79A0021EDD6 /* metaf */ = {isa = PBXFileReference; lastKnownFileType = folder; path = metaf; sourceTree = "<group>"; };
25F3471A24D2C7DE004574E7 /* parson.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parson.h; sourceTree = "<group>"; };
25F3471B24D2C7DE004574E7 /* parson.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = parson.c; sourceTree = "<group>"; };
25F3471D24D2CB15004574E7 /* ACTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ACTable.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -451,6 +452,7 @@
25A095CA2203B0C500658AA8 /* Lib */ = {
isa = PBXGroup;
children = (
25F108C22C49A79A0021EDD6 /* metaf */,
25BF009E290DCBF400317CAE /* XPMP2.xcodeproj */,
258117B5291AF24D00D05428 /* FMOD_Logo.cpp */,
251284AC274D829500B0F51A /* base64 */,
Expand Down Expand Up @@ -787,6 +789,7 @@
"Lib/ImGui/**",
Lib/ImgWindow,
Lib/Font,
Lib/metaf/include,
"$(HEADER_SEARCH_PATHS)",
);
LIBRARY_SEARCH_PATHS = Lib/fmod;
Expand Down Expand Up @@ -895,6 +898,7 @@
"Lib/ImGui/**",
Lib/ImgWindow,
Lib/Font,
Lib/metaf/include,
"$(HEADER_SEARCH_PATHS)",
);
LIBRARY_SEARCH_PATHS = Lib/fmod;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@
contextName = "Apt::FindEdgesForHeading(double, double, std::__1::vector&lt;unsigned long, std::__1::allocator&lt;unsigned long&gt; &gt;&amp;, TaxiEdge::edgeTy) const:LTApt.cpp">
<PersistentStrings>
<PersistentString
value = "lst[1385]">
value = "vecTaxiEdges[222]">
</PersistentString>
<PersistentString
value = "vecTaxiEdgesIdxHead[3321]">
value = "lst[1385]">
</PersistentString>
<PersistentString
value = "vecTaxiEdges[222]">
value = "vecTaxiEdgesIdxHead[3321]">
</PersistentString>
</PersistentStrings>
</ContextState>
Expand Down Expand Up @@ -129,10 +129,10 @@
contextName = "LTFlightData::AddDynData(LTFlightData::FDDynamicData const&amp;, int, int, positionTy*):LTFlightData.cpp">
<PersistentStrings>
<PersistentString
value = "dynDataDeque">
value = "posDeque">
</PersistentString>
<PersistentString
value = "posDeque">
value = "dynDataDeque">
</PersistentString>
<PersistentString
value = "currCycle">
Expand Down Expand Up @@ -258,6 +258,9 @@
</PersistentString>
</PersistentStrings>
</ContextState>
<ContextState
contextName = "XDR_float::set(float):LTWeather.cpp">
</ContextState>
<ContextState
contextName = "LTFlightDataRemoveOutdatedAc():LTFlightData.cpp">
</ContextState>
Expand All @@ -268,10 +271,10 @@
value = "cull">
</PersistentString>
<PersistentString
value = "tcas">
value = "iter-&gt;second">
</PersistentString>
<PersistentString
value = "iter-&gt;second">
value = "tcas">
</PersistentString>
</PersistentStrings>
</ContextState>
Expand Down Expand Up @@ -476,7 +479,7 @@
contextName = "LTAircraft::CalcPPos():LTAircraft.cpp">
<PersistentStrings>
<PersistentString
value = "turn">
value = "from">
</PersistentString>
<PersistentString
value = "to">
Expand All @@ -488,7 +491,7 @@
value = "ppos">
</PersistentString>
<PersistentString
value = "from">
value = "turn">
</PersistentString>
</PersistentStrings>
</ContextState>
Expand Down Expand Up @@ -586,10 +589,10 @@
value = "mapFd">
</PersistentString>
<PersistentString
value = "dataRefs">
value = "sizeof(bool)">
</PersistentString>
<PersistentString
value = "sizeof(bool)">
value = "dataRefs">
</PersistentString>
<PersistentString
value = "(int*)p">
Expand Down Expand Up @@ -1109,6 +1112,14 @@
</PersistentString>
</PersistentStrings>
</ContextState>
<ContextState
contextName = "LTWeather::FillFromMETAR(std::__1::basic_string&lt;char, std::__1::char_traits&lt;char&gt;, std::__1::allocator&lt;char&gt;&gt; const&amp;):LTWeather.cpp">
<PersistentStrings>
<PersistentString
value = "nextWeather">
</PersistentString>
</PersistentStrings>
</ContextState>
<ContextState
contextName = "BezierCurve::GetPos(positionTy&amp;, double, double, double, double) const:LTAircraft.cpp">
</ContextState>
Expand Down Expand Up @@ -1171,10 +1182,10 @@
value = "_startTime">
</PersistentString>
<PersistentString
value = "_deltaDist">
value = "_targetTime">
</PersistentString>
<PersistentString
value = "_targetTime">
value = "_deltaDist">
</PersistentString>
</PersistentStrings>
</ContextState>
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ LiveTraffic is based on a number of other great libraries and APIs, most notably
- [XPMP2](https://github.com/TwinFan/XPMP2) for CSL model processing
- [CURL](https://curl.haxx.se/libcurl/) for network protocol support
- [parson](https://github.com/kgabis/parson) as JSON parser
- [metaf](https://github.com/nnaumenko/metaf) as METAR parser
- [libz/zlib](https://zlib.net) as compression library (used by CURL)
- [ImGui](https://github.com/ocornut/imgui) for user interfaces
- [ImgWindow](https://github.com/xsquawkbox/xsb_public) for integrating ImGui into X-Plane windows
Expand All @@ -40,8 +41,8 @@ Thanks go to

## Build

Please note that LiveTraffic includes the XPMP2 lib as a GitHub submodule.
To properly build, you need to also checkout the XPMP2 submodule,
Please note that LiveTraffic includes XPMP2, parson, and metaf libs as a GitHub submodules.
To properly build, you need to also checkout the submodules,
e.g. on the command line by doing
```
git clone --recurse-submodules https://github.com/TwinFan/LiveTraffic
Expand Down
2 changes: 1 addition & 1 deletion Src/DataRefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2703,7 +2703,7 @@ bool DataRefs::WeatherUpdate ()
{
// Trigger a weather update; this is an asynch operation
lastWeatherAttempt = GetMiscNetwTime();
return ::WeatherUpdate(camPos, WEATHER_SEARCH_RADIUS_NM); // travel distances [m] doubles as weather search distance [nm]
return ::WeatherFetchUpdate(camPos, WEATHER_SEARCH_RADIUS_NM); // travel distances [m] doubles as weather search distance [nm]
}
return false;
}
Expand Down
20 changes: 19 additions & 1 deletion Src/LTMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,14 +760,29 @@ std::string GetNearestAirportId (const positionTy& _pos,
if (outApPos) {
outApPos->lat() = lat;
outApPos->lon() = lon;
outApPos->SetAltFt((double)alt);
outApPos->alt_m() = alt;
}
}

// return the id
return airportId;
}

// Fetch specific airport location/altitude
positionTy GetAirportLoc (const std::string sICAO)
{
XPLMNavRef navRef = XPLMFindNavAid(nullptr, sICAO.c_str(),
nullptr, nullptr, nullptr,
xplm_Nav_Airport);
if (!navRef) return positionTy();
float lat=NAN, lon=NAN, alt=NAN;
XPLMGetNavAidInfo(navRef, nullptr,
&lat, &lon, &alt,
nullptr, nullptr, nullptr, nullptr, nullptr);
return positionTy(lat, lon, alt);
}


// Convert ADS-B Emitter Category to text
const char* GetADSBEmitterCat (const std::string& cat)
{
Expand Down Expand Up @@ -929,6 +944,9 @@ void LTRegularUpdates()
// Update cached values
dataRefs.UpdateCachedValues();

// Update the weather (short-cuts if nothing to do)
WeatherUpdate();

// Check if some msg window needs to show
CheckThenShowMsgWindow();

Expand Down
Loading

0 comments on commit bd9623f

Please sign in to comment.