예제 #1
0
        private void OnPacketSmoothingTimerCallback(object state)
        {
            RiderStateEventArgs riderState = null;

            lock (this)
            {
                if (m_latestPlayerStateEventArgs != null)
                {
                    riderState = new RiderStateEventArgs(m_latestPlayerStateEventArgs);
                    m_latestPlayerStateEventArgs = null;
                }
            }

            if (riderState != null)
            {
                if (m_debugMode)
                {
                    Logger.LogInformation($"TRACING-INCOMING: PlayerId: {riderState.Id}, Power: {riderState.Power}, HeartRate: {riderState.Heartrate}, Distance: {riderState.Distance}, Time: {riderState.Time}, Course: {riderState.Course}, RoadId: {riderState.RoadId}, IsForward: {riderState.IsForward}, RoadTime: {riderState.RoadTime}");
                }
                else
                {
                    Logger.LogInformation($"TRACING-OUTGOING: Power: {riderState.Power}, HeartRate: {riderState.Heartrate}, Distance: {riderState.Distance}, Time: {riderState.Time}, Course: {riderState.Course}, RoadId: {riderState.RoadId}, IsForward: {riderState.IsForward}, RoadTime: {riderState.RoadTime}");
                }

                m_eventsProcessed++;

                OnRiderStateEvent(riderState);
            }
        }
예제 #2
0
        private void OnHighResRiderStateEvent(RiderStateEventArgs e)
        {
            EventHandler <RiderStateEventArgs> handler = HighResRiderStateEvent;

            if (handler != null)
            {
                try
                {
                    handler(this, e);
                }
                catch
                {
                    // Don't let downstream exceptions bubble up
                }
            }
        }
예제 #3
0
        private void ProcessedRiderStateEventHandler(object sender, RiderStateEventArgs e)
        {
            if (!m_dispatcher.CheckAccess()) // are we currently on the UI thread?
            {
                // We're not in the UI thread, ask the dispatcher to call this same method in the UI thread, then exit
                m_dispatcher.BeginInvoke(new ProcessedRiderStateEventHandlerDelegate(ProcessedRiderStateEventHandler), new object[] { sender, e });
                return;
            }

            lblEventsProcessed.Text = m_zpMonitorService.EventsProcessed.ToString();

            string[] row = { e.Id.ToString(), e.Power.ToString(), e.Heartrate.ToString(), DateTime.Now.ToString() };

            lvTrace.Items.Insert(0, new ListViewItem(row));

            if (lvTrace.Items.Count > 10)
            {
                lvTrace.Items.RemoveAt(10);
            }
        }
예제 #4
0
            public Waypoint CheckWaypointCrossings(RiderStateEventArgs e)
            {
                Waypoint searchWp;

                Logger.LogInformation($"CheckWaypointCrossings - Waypoints: {WaypointList.Count}");

                if (e.IsForward) // RoadTime values are increasing
                {
                    searchWp = WaypointList.Find(item => item.Course == e.Course && item.IsForward == e.IsForward && item.RoadId == e.RoadId &&
                                                 item.LastRiderRoadTime < item.RoadTime && // Last check was behind Waypoint line (values going up)
                                                 e.RoadTime >= item.RoadTime               // Current check is at or past Waypoint line
                                                 );
                }
                else // RoadTime values are decreasing
                {
                    searchWp = WaypointList.Find(item => item.Course == e.Course && item.IsForward == e.IsForward && item.RoadId == e.RoadId &&
                                                 item.LastRiderRoadTime > item.RoadTime && // Last check was past Waypoint line (values going down)
                                                 e.RoadTime <= item.RoadTime               // Current check is at or behind Waypoint line
                                                 );
                }

                return(searchWp);
            }
예제 #5
0
        /// <summary>
        /// Handle player state changes.
        /// Event distance is given in meters.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RiderStateEventHandler(object sender, RiderStateEventArgs e)
        {
            if (!m_started || !m_splits.ShowSplits)
            {
                return;
            }

            SplitV2 split = null;

            if (m_splits.CalculateGoal)
            {
                if (m_splitCount >= m_splits.Splits.Count)
                {
                    return;
                }

                // get the in-progress split
                split = m_splits.Splits[m_splitCount];
            }

            DateTime now = DateTime.Now;

            TimeSpan runningTime = (now - m_startTime);
            TimeSpan splitTime   = (now - m_splitStartTime);

            if (m_eventCount++ == 0)
            {
                // Capture the current distance traveled value to use as an offset to each successive distance value.
                m_distanceSeedValue = e.Distance;
            }

            // Calculate total distance travelled
            int totalMeters = e.Distance - m_distanceSeedValue;

            double kmsTravelled   = totalMeters / 1000.0;
            double milesTravelled = kmsTravelled / 1.609;

            double totalDistance = Math.Round(m_splits.SplitsInKm ? kmsTravelled : milesTravelled, 1);

            // Calculate how deep into the current split the rider is.
            int splitMetersTravelled = totalMeters - m_lastSplitMeters;

            // How long is current split?
            int splitLengthMeters = split == null ? m_splits.SplitDistanceAsMeters : split.SplitDistanceAsMeters;

            // How much of the split is completed (expressed as percentage)
            double splitCompletedPct = splitMetersTravelled / (double)splitLengthMeters;

            // Compute distance, leave unrounded
            double splitKmTravelled = splitMetersTravelled / 1000.0;
            double splitMiTravelled = splitKmTravelled / 1.609;

            double splitDistance = m_splits.SplitsInKm ? splitKmTravelled : splitMiTravelled;
            double splitSpeed    = Math.Round((splitDistance / splitTime.TotalSeconds) * 3600, 1);

            // Now round the distance
            splitDistance = Math.Round(splitDistance, 1);

            if (split != null)
            {
                if (splitMetersTravelled >= splitLengthMeters)
                {
                    // Calculate the deltaTime, positive number is bad, negative good.
                    TimeSpan deltaTime = new TimeSpan(0, 0, (int)Math.Round(runningTime.Subtract(split.TotalTime).TotalSeconds, 0));

                    // This completes the split.  TotalDistance travelled and Delta is included.
                    SplitEventArgs args = new SplitEventArgs(m_splitCount + 1, splitTime, splitSpeed, totalDistance, runningTime, m_splits.SplitsInKm, deltaTime);
                    OnSplitGoalCompletedEvent(args);

                    // Reset time and begin next split
                    m_splitStartTime = now;
                    m_splitCount++;

                    m_lastSplitMeters = split.TotalDistanceAsMeters;
                }
                else
                {
                    // Goal time of split start
                    TimeSpan splitStartTime = split.TotalTime.Subtract(split.SplitTime);

                    // Goal time to get to this point in the split
                    TimeSpan splitWaypointTime = splitStartTime.Add(split.SplitTime.Multiply(splitCompletedPct));

                    // Calculate the deltaTime, positive number is bad, negative good.
                    TimeSpan deltaTime = new TimeSpan(0, 0, (int)Math.Round(runningTime.Subtract(splitWaypointTime).TotalSeconds, 0));

                    // This is an update to the split in-progress.  SplitDistance travelled is included.
                    SplitEventArgs args = new SplitEventArgs(m_splitCount + 1, splitTime, splitSpeed, splitDistance, runningTime, m_splits.SplitsInKm, deltaTime);
                    OnSplitUpdatedEvent(args);

                    Logger.LogInformation($"%Complete: {splitCompletedPct} Start: {splitStartTime.ToString("m'm 's's'")} Waypoint: {splitWaypointTime.ToString("m'm 's's'")} Delta: {deltaTime.ToString("m'm 's's'")}");
                }
            }
            else
            {
                if (splitMetersTravelled >= splitLengthMeters)
                {
                    // This completes the split.  TotalDistance traveled is included.
                    SplitEventArgs args = new SplitEventArgs(m_splitCount + 1, splitTime, splitSpeed, totalDistance, runningTime, m_splits.SplitsInKm);
                    OnSplitCompletedEvent(args);

                    // Reset time and begin next split
                    m_splitStartTime = now;
                    m_splitCount++;

                    m_lastSplitMeters = totalMeters;
                }
                else
                {
                    // This is an update to the split in-progress.  SplitDistance traveled is included.
                    SplitEventArgs args = new SplitEventArgs(m_splitCount + 1, splitTime, splitSpeed, splitDistance, runningTime, m_splits.SplitsInKm);
                    OnSplitUpdatedEvent(args);
                }
            }
        }
        /// <summary>
        /// Handle player state changes.  Calculates moving averages.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RiderStateEventHandler(object sender, RiderStateEventArgs e)
        {
            DateTime now    = DateTime.Now;  // fixed current time
            TimeSpan oldest = TimeSpan.Zero; // oldest item in queue
            DateTime start  = now;           // for duration timing
            int      curAvgPower;
            int      curAvgHR;
            int      maxAvgPower;
            int      maxAvgHR;
            bool     calculateMax = false;
            bool     triggerMax   = false;

            if (!m_started)
            {
                return;
            }

            // the Statistics class captures the values we want to measure
            var stats = new Statistics(e.Power, e.Heartrate);

            if (m_countOverallPowerSamples == 0)
            {
                // Capture the current distance traveled value to use as an offset to each successive distance value.
                m_distanceSeedValue = e.Distance;
            }

            // To keep track of overall average power.  Performing here as zeros count.
            m_sumOverallPower          += (long)stats.Power;
            m_countOverallPowerSamples += 1;

            if (MetricsCalculatedEvent != null)
            {
                int overallPower = (int)Math.Round(m_sumOverallPower / (double)m_countOverallPowerSamples, 0);

                // Calculate average speed, distance is given in meters.
                TimeSpan runningTime    = (DateTime.Now - m_collectionStart);
                double   kmsTravelled   = (e.Distance - m_distanceSeedValue) / 1000.0;
                double   milesTravelled = kmsTravelled / 1.609;
                double   averageKph     = Math.Round((kmsTravelled / runningTime.TotalSeconds) * 3600, 1);
                double   averageMph     = Math.Round((milesTravelled / runningTime.TotalSeconds) * 3600, 1);

                OnMetricsCalculatedEvent(new MetricsCalculatedEventArgs(overallPower, averageKph, averageMph));
            }

            // For calculating normalized power zeros are ignored.
            if (m_excludeZeroPowerValues && stats.Power == 0)
            {
                return;
            }

            // Initialize with current max values.  This is so we know if a new max has occurred.
            maxAvgPower = m_maxAvgPower;
            maxAvgHR    = m_maxAvgHR;

            // Remove any queue items which are older than the set time duration
            while (m_statsQueue.Count > 0)
            {
                // look at front of queue
                var peekStats = m_statsQueue.Peek();

                // determine time difference between the newest item and this oldest item
                oldest = stats.Timestamp - peekStats.Timestamp;

                // if queue isn't at capacity yet, exit loop
                if (oldest.TotalSeconds <= m_duration)
                {
                    break;
                }

                // subtract oldest entry from values and dequeue
                m_sumPower -= (long)peekStats.Power;
                m_sumHR    -= (long)peekStats.HeartRate;
                m_statsQueue.Dequeue();

                calculateMax = true;  // we have a full sample, calculate maximums
            }

            // add this new item to the queue
            m_statsQueue.Enqueue(stats);
            m_sumPower += (long)stats.Power;
            m_sumHR    += (long)stats.HeartRate;

            // calculate averages
            curAvgPower = (int)Math.Round(m_sumPower / (double)m_statsQueue.Count, 0);
            curAvgHR    = (int)Math.Round(m_sumHR / (double)m_statsQueue.Count, 0);

            // if queue was full, check to see if we have any new max values
            if (calculateMax)
            {
                if (curAvgPower > m_maxAvgPower)
                {
                    m_maxAvgPower = curAvgPower;
                    triggerMax    = true;
                }
                if (curAvgHR > m_maxAvgHR)
                {
                    m_maxAvgHR = curAvgHR;
                    triggerMax = true;
                }

                // Since buffer was full trigger an event so consumer can use this new average (without waiting for a change).  Used by NormalizedPower
                OnMovingAverageCalculatedEvent(new MovingAverageCalculatedEventArgs(curAvgPower, m_durationType));
            }

            // if either average power or average HR changed, trigger event
            if (curAvgPower != m_curAvgPower || curAvgHR != m_curAvgHR)
            {
                m_curAvgPower = curAvgPower;
                m_curAvgHR    = curAvgHR;

                OnMovingAverageChangedEvent(new MovingAverageChangedEventArgs(curAvgPower, curAvgHR, m_durationType));
            }

            // if either max average power or max HR changed, trigger event
            if (triggerMax)
            {
                OnMovingAverageMaxChangedEvent(new MovingAverageMaxChangedEventArgs(m_maxAvgPower, m_maxAvgHR, m_durationType));
            }

            //Logger.LogInformation($"id: {e.PlayerState.Id} watch: {e.PlayerState.WatchingRiderId} power: {stats.Power} HR: {stats.HeartRate} Count: {m_statsQueue.Count} Sum: {m_sumTotal} Avg: {PowerAvg} Oldest: {oldest.TotalSeconds} TTP: {(DateTime.Now - start).TotalMilliseconds} WorldTime: {e.PlayerState.WorldTime} ");
            //Logger.LogInformation($"id: {e.PlayerState.Id} power: {stats.Power} HR: {stats.HeartRate} Count: {m_statsQueue.Count} PowerAvg: {curAvgPower} HRAvg: {curAvgHR} PowerMax: {m_maxAvgPower} HRMax: {m_maxAvgHR} Oldest: {oldest.TotalSeconds} TTP: {(DateTime.Now - start).TotalMilliseconds} WorldTime: {e.PlayerState.WorldTime} ");
        }
예제 #7
0
 public void Add(RiderStateEventArgs e)
 {
     this.Add(new Waypoint(e.RoadId, e.IsForward, e.Course, e.RoadTime));
 }
예제 #8
0
        /// <summary>
        /// Handle player state changes.
        /// Event distance is given in meters.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RiderStateEventHandler(object sender, RiderStateEventArgs e)
        {
            if (!m_started || !m_splits.ShowSplits)
            {
                return;
            }

            SplitGoal goal = null;

            if (m_splitGoals != null)
            {
                if (m_splitCount >= m_splitGoals.Goals.Count)
                {
                    return;
                }

                // get the in-progress goal
                goal = m_splitGoals.Goals[m_splitCount];
            }

            DateTime now = DateTime.Now;

            TimeSpan runningTime = (now - m_startTime);
            TimeSpan splitTime   = (now - m_splitStartTime);

            if (m_eventCount++ == 0)
            {
                // Capture the current distance traveled value to use as an offset to each successive distance value.
                m_distanceSeedValue = e.Distance;
            }

            // Calculate total distance travelled
            int totalMeters = e.Distance - m_distanceSeedValue;


            double kmsTravelled   = totalMeters / 1000.0;
            double milesTravelled = kmsTravelled / 1.609;

            double totalDistance = Math.Round(m_splits.SplitsInKm ? kmsTravelled : milesTravelled, 1);

            //double averageKph = Math.Round((kmsTravelled / runningTime.TotalSeconds) * 3600, 1);
            //double averageMph = Math.Round((milesTravelled / runningTime.TotalSeconds) * 3600, 1);

            // Calculate how deep into the split distance the rider is.
            int splitMeters = totalMeters - (m_splits.SplitDistanceAsMeters * m_splitCount);

            double splitKmTravelled = Math.Round(splitMeters / 1000.0, 1);
            double splitMiTravelled = Math.Round(splitKmTravelled / 1.609, 1);

            double splitDistance = m_splits.SplitsInKm ? splitKmTravelled : splitMiTravelled;
            double splitSpeed    = Math.Round((splitDistance / splitTime.TotalSeconds) * 3600, 1);

            //double splitAverageKph = Math.Round((splitKmTravelled / splitTime.TotalSeconds) * 3600, 1);
            //double splitAverageMph = Math.Round((splitMiTravelled / splitTime.TotalSeconds) * 3600, 1);

            if (goal != null)
            {
                if (splitKmTravelled >= goal.SplitDistanceKm)
                {
                    // Calculate the deltaTime, positive number is good, negative bad.
                    TimeSpan deltaTime = goal.TotalTime.Subtract(runningTime);

                    // This completes the split.  TotalDistance travelled and Delta is included.
                    SplitGoalCompletedEventArgs args = new SplitGoalCompletedEventArgs(m_splitCount + 1, splitTime, splitSpeed, totalDistance, runningTime, m_splits.SplitsInKm, deltaTime);
                    OnSplitGoalCompletedEvent(args);

                    // Reset time and begin next split
                    m_splitStartTime = now;
                    m_splitCount++;

                    m_lastSplitMeters = 0;
                }
                else
                {
                    if (splitMeters - m_lastSplitMeters >= 100) // only raise update event every 100 meters or so
                    {
                        // This is an update to the split in-progress.  SplitDistance travelled is included.
                        SplitEventArgs args = new SplitEventArgs(m_splitCount + 1, splitTime, splitSpeed, splitDistance, runningTime, m_splits.SplitsInKm);
                        OnSplitUpdatedEvent(args);

                        m_lastSplitMeters = splitMeters;
                    }
                }
            }
            else
            {
                if (splitKmTravelled >= m_splits.SplitDistanceAsKm)
                {
                    // This completes the split.  TotalDistance traveled is included.
                    SplitEventArgs args = new SplitEventArgs(m_splitCount + 1, splitTime, splitSpeed, totalDistance, runningTime, m_splits.SplitsInKm);
                    OnSplitCompletedEvent(args);

                    // Reset time and begin next split
                    m_splitStartTime = now;
                    m_splitCount++;

                    m_lastSplitMeters = 0;
                }
                else
                {
                    if (splitMeters - m_lastSplitMeters >= 100) // only raise update event every 100 meters or so
                    {
                        // This is an update to the split in-progress.  SplitDistance traveled is included.
                        SplitEventArgs args = new SplitEventArgs(m_splitCount + 1, splitTime, splitSpeed, splitDistance, runningTime, m_splits.SplitsInKm);
                        OnSplitUpdatedEvent(args);

                        m_lastSplitMeters = splitMeters;
                    }
                }
            }
        }