/// <summary> /// Generates actual data to send to the client. /// </summary> /// <remarks>Data is sent according to the behavior of a typical GPS device: $GPGGA, /// $GPGSA, $GPRMC, $GPGSV sentences are sent every second, and a $GPGSV sentence /// is sent every five seconds. /// Developers who want to emulate a specific model of GPS device should override this /// method and generate the sentences specific to that device.</remarks> protected override void OnEmulation() { // Update real-time position, speed, bearing, etc. base.OnEmulation(); if (Route.Count == 0) { CurrentPosition = EmulatePositionError(CurrentPosition); } /* NMEA devices will transmit "bursts" of NMEA sentences, followed by a one-second pause. * Other sentences (usually $GPGSV) are transmitted once every few seconds. This emulator, * by default, will transmit the most common NMEA sentences. */ // $GPGGA if (!_gpggaInterval.Equals(TimeSpan.Zero) // Has enough time elapsed to send the sentence? && UtcDateTime.Subtract(_gpggaLastSent) > _gpggaInterval) { // Get the tracked satellite count int trackedCount = Satellites.Count(item => item.SignalToNoiseRatio.Value > 0); // Yes _gpggaLastSent = UtcDateTime; // Queue the sentence to the read buffer WriteSentenceToClient(new GpggaSentence(UtcDateTime.TimeOfDay, CurrentPosition, _fixQuality, trackedCount, _horizontalDOP, Altitude.Add(EmulateError(_verticalDOP)), Distance.Empty, TimeSpan.Zero, -1)); //Add an error to the altitude written to the client but don't change the actual value (otherwise it will "walk") } // $GPRMC if (!_gprmcInterval.Equals(TimeSpan.Zero) // Has enough time elapsed to send the sentence? && UtcDateTime.Subtract(_gprmcLastSent) > _gprmcInterval) { // Yes _gprmcLastSent = UtcDateTime; // Queue the sentence to the read buffer WriteSentenceToClient(new GprmcSentence(UtcDateTime, _fixStatus == FixStatus.Fix, CurrentPosition, Speed, Bearing, _magneticVariation)); } // $GPGLL if (!_gpgllInterval.Equals(TimeSpan.Zero) // Has enough time elapsed to send the sentence? && UtcDateTime.Subtract(_gpgllLastSent) > _gpgllInterval) { // Yes _gpgllLastSent = UtcDateTime; // Write a $GPGLL to the client WriteSentenceToClient(new GpgllSentence(CurrentPosition, UtcDateTime.TimeOfDay, _fixStatus)); } // $GPGSA if (!_gpgsaInterval.Equals(TimeSpan.Zero) // Has enough time elapsed to send the sentence? && UtcDateTime.Subtract(_gpgsaLastSent) > _gpgsaInterval) { // Yes _gpgsaLastSent = UtcDateTime; // Queue the sentence to the read buffer WriteSentenceToClient(new GpgsaSentence(_fixMode, _fixMethod, Satellites, _meanDOP, _horizontalDOP, _verticalDOP)); } // $GPGSV if (!_gpgsvInterval.Equals(TimeSpan.Zero) // Has enough time elapsed to send the sentence? && UtcDateTime.Subtract(_gpgsvLastSent) > _gpgsvInterval) { // Build a list of sentences from our satellites IList <GpgsvSentence> sentences = GpgsvSentence.FromSatellites(Satellites); // Yes _gpgsvLastSent = UtcDateTime; // Write each sentence to the read buffer foreach (GpgsvSentence gpgsv in sentences) { WriteSentenceToClient(gpgsv); } } // And signal that we have data (or not) if (ReadBuffer.Count == 0) { ReadDataAvailableWaitHandle.Reset(); } else { ReadDataAvailableWaitHandle.Set(); } }