/* If all waypoints are with a 20m radius of their centre consider there to be no movement */
        private bool HaveWaypointsMoved()
        {
            float averageLat = Waypoints.Average(info => info.Lat);
            float averageLng = Waypoints.Average(info => info.Lng);

            foreach (var waypoint in Waypoints)
            {
                if (GPRMCInfo.Haversine(averageLat, averageLng, waypoint.Lat, waypoint.Lng) > 20)
                {
                    return(true);
                }
            }

            return(false);
        }
        /* Attempt to parse te NMEA message using regular expressions */
        public static GPRMCInfo Parse(string gprmc)
        {
            Regex regex = new Regex(@"\$GPRMC,(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*)");
            Match match = regex.Match(gprmc);

            if (match.Success)
            {
                if (match.Groups.Count < 11)
                {
                    return(null);
                }
                var time              = match.Groups[1].Value;
                var status            = match.Groups[2].Value;
                var lat               = match.Groups[3].Value;
                var latDirection      = match.Groups[4].Value;
                var lng               = match.Groups[5].Value;
                var lngDirection      = match.Groups[6].Value;
                var speed             = match.Groups[7].Value;
                var trackAngle        = match.Groups[8].Value;
                var date              = match.Groups[9].Value;
                var magneticVariation = match.Groups[10].Value;
                var checksum          = match.Groups[11].Value;

                GPRMCInfo result = new GPRMCInfo();

                try {
                    result.Date  = DateTime.ParseExact(date + time, "ddMMyyHHmmss.ff", CultureInfo.InvariantCulture);
                    result.Lat   = ParseCoord(lat) * (latDirection == "N" ? 1 : -1);
                    result.Lng   = ParseCoord(lng) * (lngDirection == "E" ? 1 : -1);
                    result.Speed = float.Parse(speed) * 0.514444f;
                } catch {
                    return(null);
                }
                return(result);
            }

            return(null);
        }
        public async void Run(IBackgroundTaskInstance taskInstance)
        {
            BackgroundTaskDeferral deferral = taskInstance.GetDeferral();

            /* Look for the serial and create a data reader using it's input stream */
            string deviceSelector = SerialDevice.GetDeviceSelector("UART0");
            var    devices        = await DeviceInformation.FindAllAsync(deviceSelector);

            SerialDevice serialPort = await SerialDevice.FromIdAsync(devices[0].Id);

            var DataReader = new DataReader(serialPort.InputStream)
            {
                InputStreamOptions = InputStreamOptions.Partial
            };

            bool quit = false;

            LineQueue lineQueue = new LineQueue();

            while (!quit)
            {
                /* Read the GPS data from the serial device (the GPS model continously sends NMEA hence only reading is required) */
                string gpsData = await ReadAsync(DataReader);

                lineQueue.AddChunk(gpsData);

                while (lineQueue.HasMore())
                {
                    string nmeaSentence = lineQueue.Next();
                    Debug.Write(nmeaSentence);

                    /* Attempt to parse the NMEA sentence if valid add to waypoint list */
                    if (nmeaSentence.StartsWith("$GPRMC"))
                    {
                        GPRMCInfo info = GPRMCInfo.Parse(nmeaSentence);
                        if (info != null)
                        {
                            TimeOfLastValidWaypoint = DateTime.Now;
                            Waypoints.Add(info);
                        }
                    }

                    /* If the waypoint list is full then check whether there has been any movement and start/end trip as appropriate */
                    if (Waypoints.Count == Waypoints.Capacity)
                    {
                        if (!HaveWaypointsMoved())
                        {
                            EndTrip();
                        }
                        else
                        {
                            if (!InTrip)
                            {
                                StartTrip();
                            }
                            WriteWaypointsToFile();
                        }
                        Waypoints.Clear();
                    }

                    /* If there haven't been any valid GPRMC messages for 2min end the trip */
                    if ((TimeOfLastValidWaypoint - DateTime.Now).Minutes >= 2)
                    {
                        EndTrip();
                    }
                }
            }

            deferral.Complete();
        }