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); } }
private void OnHighResRiderStateEvent(RiderStateEventArgs e) { EventHandler <RiderStateEventArgs> handler = HighResRiderStateEvent; if (handler != null) { try { handler(this, e); } catch { // Don't let downstream exceptions bubble up } } }
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); } }
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); }
/// <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} "); }
public void Add(RiderStateEventArgs e) { this.Add(new Waypoint(e.RoadId, e.IsForward, e.Course, e.RoadTime)); }
/// <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; } } } }