Beispiel #1
0
        /// <summary>
        /// Parses a raw NMEA GSA (gps fix information) sentence.
        /// This is the prefered sentence to use for positions.
        /// It is only generated by NMEA 2.0 GPS units. All modern units should be version 2.0 complient.
        /// </summary>
        /// <remarks>
        /// GSA - essential fix data which provide 3D location and accuracy data.
        /// $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
        /// Where:
        ///		GSA         Satellite status
        //      A           Auto selection of 2D or 3D fix(M = manual)
        //      3           3D fix - values include: 1 = no fix
        //                                  2 = 2D fix
        //                                  3 = 3D fix
        //                  04,05... PRNs of satellites used for fix(space for 12)
        //                  2.5      PDOP(dilution of precision)
        //                  1.3      Horizontal dilution of precision(HDOP)
        //                  2.1      Vertical dilution of precision(VDOP)
        //                  *39      the checksum data, always begins with*
        /// </remarks>
        /// <param name="sentence">NMEA GGA Senetence.</param>
        /// <returns>True if the sentence is successfully parsed.</returns>
        public bool ParseGSA(string sentence)
        {
            bool success = true;

            // The sentence should be a comma seperated list of values
            // Some may be empty!
            // Start by stripping the leading and trailing data.
            Char[] splitChars = { ',' };
            //string[] words = sentence.Substring(1, sentence.IndexOf('*')).Split(splitChars, StringSplitOptions.None);
            string[] words = sentence.Split(splitChars, StringSplitOptions.None);

            // save the sentence type
            mTag = words[0];

            // Do we have enough words to parse the fix status?
            if (words.Length > 2 && words[2].Length != 0)
            {
                // Get the fix code
                mNMEAMode = words[2].Equals("1", StringComparison.OrdinalIgnoreCase) ? NMEAMODE.NO_FIX : (words[2].Equals("2", StringComparison.OrdinalIgnoreCase) ? NMEAMODE.TWO_DIMENSION : NMEAMODE.THREE_DIMENSION);
            }
            else
            {
                // The fix status is invalid
                mNMEAMode = NMEAMODE.NO_MODE;
                success   = false;
            }

            return(success);
        }
Beispiel #2
0
        /// <summary>
        /// Diseminates NMEA2000 Position, Rapid Update CAN frames.
        /// </summary>
        /// <remarks>
        /// Position, Rapid Update PGN 129025
        /// First two bytes of a NMEA2000 frame indicate the
        /// <field>
        /// name = "Latitude"
        /// type = "int"
        /// offset = "0"
        /// length = "32"
        /// signed = "yes"
        /// units = "deg"
        /// scaling = "0.0000001"
        /// </field>
        /// <field>
        /// name = "Longitude"
        /// type = "int"
        /// offset = "32"
        /// length = "32"
        /// signed = "yes"
        /// units = "deg"
        /// scaling = "0.0000001"
        /// </field>
        /// </remarks>
        public void ParsePositionRapidUpdate(byte[] data)
        {
            if (!BitConverter.IsLittleEndian)
            {
                Array.Reverse(data, 0, 4);
                Array.Reverse(data, 4, 4);
            }
            double lat = BitConverter.ToInt32(data, 0);

            lat *= 0.0000001;
            double lon = BitConverter.ToInt32(data, 4);

            lon *= 0.0000001;
            mPosition.Reset(lat, lon);
            mNMEAMode = NMEAMODE.TWO_DIMENSION;
            //Console.WriteLine("Position {0}", mPosition.ToString());
        }
Beispiel #3
0
        /// <summary>
        /// Parses a GPSD 'o' report.
        /// Attempts to return a complete time/position/velocity report as a unit.
        /// Any field for which data is not available being reported as ?.
        /// If there is no fix, the response is simply "O=?", otherwise a tag and timestamp are always reported.
        /// </summary>
        /// <param name="sentence">GPSD 'o' report.</param>
        /// <exception cref="System.Exception">Thrown if the sentence is not a GPSD report or sentence is not an 'O' report.</exception>
        public void Parse(string sentence)
        {
            // break up the sentence into fields
            Char[]   splitChars = { ' ' };
            string[] fields     = sentence.Split(splitChars);
            // validate the sentence
            if (!fields[0].StartsWith("O="))
            {
                throw new Exception("Invalid sentence, not an 'O' report.");
            }
            // make sure there is a complete report
            if (fields[0] == "O=?")
            {
                // need to invalidate all data
                fields = new string[] { "O=?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?" }
            }
            ;
            if (fields.Length != 15)
            {
                throw new Exception("Invalid sentence, invalid field count.");
            }

            // looks good to go
            mTag = fields[0].Substring(2);
            // check that this is a fresh update
            double newStamp = (fields[1] == "?")? Double.NaN : Double.Parse(fields[1]);

            mInvalid   = (newStamp == double.NaN);
            mTimeStamp = new DateTime((long)newStamp);
            mTimeError = (fields[2] == "?")? Double.NaN : Double.Parse(fields[2]);
            mPosition.Reset((fields[3] == "?")? Double.NaN : Double.Parse(fields[3]), (fields[4] == "?")? Double.NaN : Double.Parse(fields[4]));
            mAltitude = (fields[5] == "?")? Double.NaN : Double.Parse(fields[5]);
            mHorizontalErrorEstimate = (fields[6] == "?")? 0.0 : Double.Parse(fields[6]);
            mVerticalErrorEstimate   = (fields[7] == "?")? Double.NaN : Double.Parse(fields[7]);
            mCourseOverGround        = (fields[8] == "?")? Double.NaN : Double.Parse(fields[8]);
            mSpeedOverGround         = (fields[9] == "?")? Double.NaN : Double.Parse(fields[9]);
            mClimbSink = (fields[10] == "?")? Double.NaN : Double.Parse(fields[10]);
            mEstimatedErrorCourseOverGround = (fields[11] == "?")? Double.MaxValue : Double.Parse(fields[11]);
            mEstimatedErrorSpeedOverGround  = (fields[12] == "?")? Double.MaxValue : Double.Parse(fields[12]);
            mEstimatedErrorClimbSink        = (fields[13] == "?")? Double.MaxValue : Double.Parse(fields[13]);
            mNMEAMode = (NMEAMODE)((fields[14] == "?")? 0 : Int32.Parse(fields[14]));
        }
Beispiel #4
0
        /// <summary>
        /// Parses a raw NMEA RMC (recommended minimum data for gps) sentence.
        /// This provides the least information for positions but is guarenteed to be generated by all GPS units.
        /// </summary>
        /// <remarks>
        /// $GPRMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,ddmmyy,x.x,a*hh
        /// 1 = UTC of position fix
        /// 2 = Data status (Navigation receiver warning A = OK, V = warning)
        /// 3 = Latitude of fix
        /// 4 = N or S
        /// 5 = Longitude of fix
        /// 6 = E or W
        /// 7 = Speed over ground in knots
        /// 8 = Track made good in degrees True
        /// 9 = UT date
        /// 10 = Magnetic variation degrees (Easterly var. subtracts from true course)
        /// 11 = E or W
        /// 12 = Checksum
        /// </remarks>
        /// <param name="sentence">NMEA RMC Senetence.</param>
        /// <returns>True if the sentence is successfully parsed.</returns>
        public bool ParseRMC(string sentence)
        {
            bool success = true;

            // The sentence should be a comma seperated list of values
            // Some may be empty!
            // Start by stripping the leading and trailing data.
            Char[] splitChars = { ',' };
            //string[] words = sentence.Substring(1, sentence.IndexOf('*')).Split(splitChars, StringSplitOptions.None);
            string[] words = sentence.Split(splitChars, StringSplitOptions.None);

            // save the sentence type
            mTag = words[0];

            // Do we have enough words to parse the fix status?
            if (words.Length > 2 && words[2].Length != 0)
            {
                // Get the fix flag
                //if (words[2].Equals("A", StringComparison.OrdinalIgnoreCase))
                //    mNMEAMode = NMEAMODE.TWO_DIMENSION;
                //else
                //{
                //    mNMEAMode = NMEAMODE.NO_FIX;
                //    return false;
                //}

                if (!words[2].Equals("A", StringComparison.OrdinalIgnoreCase))
                {
                    mNMEAMode = NMEAMODE.NO_FIX;
                    return(false);
                }
            }
            else
            {
                // The fix status is invalid
                mNMEAMode = NMEAMODE.NO_MODE;
                success   = false;
            }

            // Do we have enough words to parse the UTC date/time?
            if (words.Length > 9)
            {
                if (words[1].Length != 0 && words[9].Length != 0)
                {
                    try
                    {
                        // time part
                        string utcTimeWord     = words[1];
                        int    utcHours        = int.Parse(utcTimeWord.Substring(0, 2), NMEAGPSClient.NMEACultureInfo);                               // AA
                        int    utcMinutes      = int.Parse(utcTimeWord.Substring(2, 2), NMEAGPSClient.NMEACultureInfo);                               // BB
                        int    utcSeconds      = int.Parse(utcTimeWord.Substring(4, 2), NMEAGPSClient.NMEACultureInfo);                               // CC
                        int    utcMilliseconds = 0;
                        if (utcTimeWord.Length > 6)
                        {
                            utcMilliseconds = Convert.ToInt32(float.Parse(utcTimeWord.Substring(6)) * 1000, NMEAGPSClient.NMEACultureInfo);                                // DDDD
                        }
                        // date part
                        string utcDateWord = words[9];
                        int    utcDay      = int.Parse(utcDateWord.Substring(0, 2), NMEAGPSClient.NMEACultureInfo);
                        int    utcMonth    = int.Parse(utcDateWord.Substring(2, 2), NMEAGPSClient.NMEACultureInfo);
                        int    utcYear     = int.Parse(utcDateWord.Substring(4, 2), NMEAGPSClient.NMEACultureInfo) + 2000;

                        // make the date/time
                        mTimeStamp = new DateTime(utcYear, utcMonth, utcDay, utcHours, utcMinutes, utcSeconds, utcMilliseconds, DateTimeKind.Utc);
                        //CNXLog.InfoFormat("ParseRMC DateTime {0} time word {1} date word {2}", mTimeStamp.ToString(), words[1], words[9]);
                    }
                    catch (Exception e)
                    {
                        // The UTC date/time is invalid
                        CNXLog.ErrorFormat("ParseRMC DateTime error {0} {1}", sentence, e);
                        mTimeStamp = DateTime.MaxValue;
                        success    = false;
                    }
                }
                else
                {
                    // The UTC date/time is invalid
                    CNXLog.ErrorFormat("ParseRMC DateTime sentence length error {0} {1}", sentence);
                    mTimeStamp = DateTime.MaxValue;
                    success    = false;
                }
            }
            else
            {
                // The UTC date/time is invalid
                CNXLog.ErrorFormat("ParseRMC DateTime sentence length error {0} {1}", sentence);
                mTimeStamp = DateTime.MaxValue;
                success    = false;
            }

            // Do we have enough data to parse the location?
            if (words.Length > 6 && words[3].Length != 0 && words[4].Length != 0 && words[5].Length != 0 && words[6].Length != 0)
            {
                mPosition = ParseNMEAPosition(words[3], words[4], words[5], words[6]);
            }

            // Do we have enough info to process speed?
            if (words.Length > 7 && words[7].Length != 0)
            {
                // The speed is the sixth word, expressed in knots
                // Conversion, 1,852 Knot to meter
                mSpeedOverGround = ParseVelocity(words[7]);
            }
            else
            {
                mSpeedOverGround = double.MinValue;
            }

            // do we have enough info to process the bearing?
            if (words.Length > 8 && words[8].Length != 0)
            {
                // The bearing is the seventh word
                if (!double.TryParse(words[8], out mCourseOverGround))
                {
                    mCourseOverGround = double.NaN;
                }
            }
            else
            {
                mCourseOverGround = double.NaN;
            }

            return(success);
        }