Esempio n. 1
0
        /// <summary>
        /// Decode a METAR/TAF message
        /// </summary>
        /// <param name="msg">The message</param>
        /// <returns>A filled MTData object</returns>
        public static MTData Decode(string msg)
        {
            var mdata = new MTData {
                RAW = msg
            };                              // save reference

            if (string.IsNullOrWhiteSpace(msg))
            {
                return(mdata);
            }

            string raw = msg.Replace("\n", "") + " ";  // remove CRLF and we need a space at the end...

            raw = M_MsgTypeDecoder.Decode(raw, mdata); // defaults to METAR if not tagged with a Msg Type

            if (mdata.MsgType == MsgType.METAR)
            {
                DecodeMetar(raw, mdata);
            }
            else if (mdata.MsgType == MsgType.SPECI)
            {
                DecodeMetar(raw, mdata);
            }
            else if (mdata.MsgType == MsgType.TAF)
            {
                DecodeTaf(raw, mdata);
            }

            return(mdata);
        }
Esempio n. 2
0
        /// <summary>
        /// Decode a part into mData and return the rest
        /// </summary>
        /// <param name="raw">The raw METAR input string</param>
        /// <param name="mData">The MData record to fill in</param>
        /// <returns>The reminder of  the input string, (raw minus the processed part)</returns>
        public static string Decode(string raw, MTData mData)
        {
            try {
                Match match = RE_metar.Match(raw);
                if (match.Success)
                {
                    mData.MsgType = MsgType.METAR;
                    if (match.Groups["opt"].Success && match.Groups["opt"].Value == "COR")
                    {
                        mData.MsgModifier = MsgModifier.COR;
                    }
                    return(match.Groups["rest"].Value.TrimStart( ));
                }

                match = RE_speci.Match(raw);
                if (match.Success)
                {
                    mData.MsgType = MsgType.SPECI;
                    if (match.Groups["opt"].Success && match.Groups["opt"].Value == "COR")
                    {
                        mData.MsgModifier = MsgModifier.COR;
                    }
                    return(match.Groups["rest"].Value.TrimStart( ));
                }

                match = RE_taf.Match(raw);
                if (match.Success)
                {
                    mData.MsgType = MsgType.TAF;
                    if (match.Groups["opt"].Success && match.Groups["opt"].Value == "AMD")
                    {
                        mData.MsgModifier = MsgModifier.AMD;
                    }
                    else if (match.Groups["opt"].Success && match.Groups["opt"].Value == "COR")
                    {
                        mData.MsgModifier = MsgModifier.COR;
                    }
                    else
                    {
                        mData.MsgModifier = MsgModifier.NONE;
                    }
                    return(match.Groups["rest"].Value.TrimStart( ));
                }
            }
            catch {
                ; // DEBUG STOP
            }

            return(raw);
        }
Esempio n. 3
0
        // Static Decoder

        /// <summary>
        /// Decode a METAR Message
        /// </summary>
        /// <param name="raw">The raw message starting with the StationID</param>
        /// <param name="mdata">The MData record to fill</param>
        private static void DecodeMetar(string raw, MTData mdata)
        {
            raw = M_StationDecoder.Decode(raw, mdata.Station);
            if (!mdata.Station.Valid)
            {
                return;                   // ERROR must have
            }
            raw = M_ObsTimeDecoder.Decode(raw, mdata.ObsTime);
            if (!mdata.ObsTime.Valid)
            {
                return;                   // ERROR must have
            }
            raw = M_ModifierDecoder.Decode(raw, mdata.Modifier);
            if (mdata.Modifier.IsNil)
            {
                // cancelled - forget the rest and return
                return;
            }

            raw = M_WindDecoder.Decode(raw, mdata.Wind);
            raw = M_WindDecoder.Decode(raw, mdata.Wind); // optional variable part, will capture if there

            raw = M_VisibilityDecoder.Decode(raw, mdata.Visibility);

            while (M_RunwayVRDecoder.IsMatch(raw))// optional multiple
            {
                raw = M_RunwayVRDecoder.Decode(raw, mdata.RunwayVRs);
            }
            ;

            while (M_WeatherDecoder.IsMatch(raw))// optional multiple
            {
                raw = M_WeatherDecoder.Decode(raw, mdata.Weather);
            }

            while (M_SkyConditionDecoder.IsMatch(raw))// optional multiple
            {
                raw = M_SkyConditionDecoder.Decode(raw, mdata.SkyConditions);
            }
            ;

            raw = M_TempDecoder.Decode(raw, mdata.Temperature);
            raw = M_PressureDecoder.Decode(raw, mdata.Altimeter);

            // RMKs

            // Eval Category
            mdata.FlightCategory = M_CategoryDecoder.Decode(mdata);
        }
Esempio n. 4
0
        /// <summary>
        /// Decode a part into mData and return the rest
        /// </summary>
        /// <param name="raw">The raw METAR input string</param>
        /// <param name="mData">The MData record to fill in</param>
        /// <returns>The reminder of  the input string, (raw minus the processed part)</returns>
        public static string Decode(string raw, MTData mData)
        {
            try {
                Match match = RE_regular.Match(raw);
                if (match.Success)
                {
                    mData.CancelFlag = (match.Groups["rest"].Value == "CNL");
                    return(match.Groups["rest"].Value.TrimStart( ));
                }
            }
            catch {
                ; // DEBUG STOP
            }

            return(raw);
        }
Esempio n. 5
0
        /// <summary>
        /// Decode a TAF Message
        /// </summary>
        /// <param name="raw">The raw message starting with the StationID</param>
        /// <param name="mdata">The MData record to fill</param>
        private static void DecodeTaf(string raw, MTData mdata)
        {
            raw = M_StationDecoder.Decode(raw, mdata.Station);
            if (!mdata.Station.Valid)
            {
                return;                   // ERROR must have
            }
            raw = M_ObsTimeDecoder.Decode(raw, mdata.ObsTime);
            if (!mdata.ObsTime.Valid)
            {
                return;                   // ERROR must have
            }
            raw = T_PeriodDecoder.Decode(raw, mdata.TafPeriod);
            if (!mdata.TafPeriod.Valid)
            {
                return;                     // ERROR must have
            }
            if (T_CancelDecoder.IsMatch(raw))
            {
                // cancelled - collect the flag, forget the rest and return
                raw = T_CancelDecoder.Decode(raw, mdata);
                return;
            }

            // add the basic FC record here as we go and process further parts
            mdata.Forecasts.Add(new T_Forecast( )
            {
                Valid = true, From = mdata.TafPeriod.From, To = mdata.TafPeriod.To, IsTimeSpan = true
            });

            raw = M_WindDecoder.Decode(raw, mdata.Forecasts.First( ).Wind);
            raw = M_WindDecoder.Decode(raw, mdata.Forecasts.First( ).Wind); // optional variable part, will capture if there

            raw = M_VisibilityDecoder.Decode(raw, mdata.Forecasts.First( ).Visibility);

            while (M_WeatherDecoder.IsMatch(raw))// optional multiple
            {
                raw = M_WeatherDecoder.Decode(raw, mdata.Forecasts.First( ).Weather);
            }

            while (M_SkyConditionDecoder.IsMatch(raw))// optional multiple
            {
                raw = M_SkyConditionDecoder.Decode(raw, mdata.Forecasts.First( ).SkyConditions);
            }
            ;

            while (T_TempMinMaxDecoder.IsMatch(raw))// optional multiple
            {
                raw = T_TempMinMaxDecoder.Decode(raw, mdata.Forecasts.First( ).TempMinMax);
            }
            ;
            // Eval Category
            mdata.Forecasts.First( ).FlightCategory = M_CategoryDecoder.Decode(mdata.Forecasts.First( ));

            // We should get into the additional forecast records now..
            while (T_ForecastDecoder.IsMatch(raw))
            {
                raw = T_ForecastDecoder.Decode(raw, mdata.Forecasts);
                // collect the allowed forecast records
                raw = M_WindDecoder.Decode(raw, mdata.Forecasts.Last( ).Wind);
                raw = M_WindDecoder.Decode(raw, mdata.Forecasts.Last( ).Wind); // optional variable part, will capture if there

                raw = M_VisibilityDecoder.Decode(raw, mdata.Forecasts.Last( ).Visibility);

                while (M_WeatherDecoder.IsMatch(raw))// optional multiple
                {
                    raw = M_WeatherDecoder.Decode(raw, mdata.Forecasts.Last( ).Weather);
                }

                while (M_SkyConditionDecoder.IsMatch(raw))// optional multiple
                {
                    raw = M_SkyConditionDecoder.Decode(raw, mdata.Forecasts.Last( ).SkyConditions);
                }
                ;
                // Eval Category
                mdata.Forecasts.Last( ).FlightCategory = M_CategoryDecoder.Decode(mdata.Forecasts.Last( ));
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Evaluate the FlightCategory
        /// </summary>
        /// <param name="mdata">An MData record</param>
        /// <returns>A FlightCategory record</returns>
        public static M_Category Decode(MTData mdata)
        {
            var ret = new M_Category();

            // OFF_LIMIT Ceilings are less than 200 feet above ground level and/or visibility is less than 0.5 mile.
            bool trigger = false;

            trigger |= mdata.Visibility.Valid && mdata.Visibility.Distance_SM < 0.5;
            trigger |= mdata.SkyConditions.Count > 0 && mdata.SkyConditions[0].Height_ft < 200;
            if (trigger)
            {
                ret.FlightCategory = FLCat.LIFR;
                ret.Valid          = true;
                return(ret);
            }
            // LIFR Ceilings are less than 500 feet above ground level and/or visibility is less than 1 mile.
            trigger  = false;
            trigger |= mdata.Visibility.Valid && mdata.Visibility.Distance_SM < 1.0;
            trigger |= mdata.SkyConditions.Count > 0 && mdata.SkyConditions[0].Height_ft < 500;
            if (trigger)
            {
                ret.FlightCategory = FLCat.LIFR;
                ret.Valid          = true;
                return(ret);
            }
            // IFR  Ceilings 500 to less than 1,000 feet and/or visibility 1 to less than 3 miles.
            trigger  = false;
            trigger |= mdata.Visibility.Valid && mdata.Visibility.Distance_SM >= 1.0 && mdata.Visibility.Distance_SM < 3.0;
            trigger |= mdata.SkyConditions.Count > 0 && mdata.SkyConditions[0].Height_ft >= 500 && mdata.SkyConditions[0].Height_ft < 1000;
            if (trigger)
            {
                ret.FlightCategory = FLCat.IFR;
                ret.Valid          = true;
                return(ret);
            }
            // MVFR Ceilings 1,000 to 3,000 feet and/or visibility is 3-5 miles inclusive.
            trigger  = false;
            trigger |= mdata.Visibility.Valid && mdata.Visibility.Distance_SM >= 3.0 && mdata.Visibility.Distance_SM <= 5.0;
            trigger |= mdata.SkyConditions.Count > 0 && mdata.SkyConditions[0].Height_ft >= 1000 && mdata.SkyConditions[0].Height_ft <= 3000;
            if (trigger)
            {
                ret.FlightCategory = FLCat.MVFR;
                ret.Valid          = true;
                return(ret);
            }
            // VFR  Ceiling greater than 3000 feet and visibility greater than 5 miles (includes sky clear).
            trigger  = true;
            trigger &= mdata.Visibility.Valid && mdata.Visibility.Distance_SM > 5.0;
            trigger &= mdata.SkyConditions.Count > 0 && mdata.SkyConditions[0].Height_ft > 3000;
            trigger |= mdata.Visibility.CAVOK; // overrides
            if (trigger)
            {
                ret.FlightCategory = FLCat.VFR;
                ret.Valid          = true;
                return(ret);
            }
            // missing data
            ret.FlightCategory = FLCat.UNKOWN;
            ret.Valid          = true;

            return(ret);
        }