Example #1
0
        /// <summary>
        /// Gets a summary of the data for all the laps.
        /// </summary>
        /// <param name="lap">List of laps to get the summary for.</param>
        /// <returns>The new summary.</returns>
        private static Summary GetSessionSummary(LapsList laps)
        {
            Summary summary = new Summary();

            foreach (Lap lap in laps)
            {
                foreach (Record record in lap.Records)
                {
                    summary.AveSpeed     += record.Speed;
                    summary.AvePower     += record.Power;
                    summary.AveHeartRate += record.HeartRate;
                    summary.AveCadence   += record.Cadence;
                    if (record.Speed > summary.MaxSpeed)
                    {
                        summary.MaxSpeed = record.Speed;
                    }
                    if (record.Power > summary.MaxPower)
                    {
                        summary.MaxPower = record.Power;
                    }
                    if (record.HeartRate > summary.MaxHeartRate)
                    {
                        summary.MaxHeartRate = record.HeartRate;
                    }
                    if (record.Cadence > summary.MaxCadence)
                    {
                        summary.MaxCadence = record.Cadence;
                    }
                }
                summary.NumRecords += lap.Records.Count;
            }
            if (summary.NumRecords != 0)
            {
                summary.AveSpeed     = summary.AveSpeed / summary.NumRecords;
                summary.AvePower     = summary.AvePower / summary.NumRecords;
                summary.AveHeartRate = summary.AveHeartRate / summary.NumRecords;
                summary.AveCadence   = summary.AveCadence / summary.NumRecords;
            }
            return(summary);
        }
Example #2
0
        /// <summary>
        /// Opens a FIT file.
        /// </summary>
        private void OpenFileButton_Click(object sender, RoutedEventArgs e)
        {
            // set the initial directory from Settings.OpenFilePath
            string path = (string)Properties.Settings.Default["OpenFilePath"];

            if (path.Length == 0)
            {
                path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            }
            openFileDialog.InitialDirectory = path;

            // prompt the user for a file name
            bool?result = openFileDialog.ShowDialog(this);

            if (result == true)
            {
                // update Settings.OpenFilePath from the file name
                path = System.IO.Path.GetDirectoryName(openFileDialog.FileName);
                Properties.Settings.Default["OpenFilePath"] = path;
                Properties.Settings.Default.Save();
                string fileName = openFileDialog.FileName;

                // get the CSV and FIT file names
                string csvFileName = openFileDialog.FileName;
                string fitFileName = Path.ChangeExtension(csvFileName, "fit");
                FileNameTextBox.Text = csvFileName;

                // get the start time
                string[]        parts = Path.GetFileNameWithoutExtension(csvFileName).Split(new char[] { '-' });
                System.DateTime start = System.IO.File.GetCreationTime(csvFileName);
                if (parts.Length == 5)
                {
                    try
                    {
                        start = new System.DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]), int.Parse(parts[4]), 0, DateTimeKind.Local);
                    }
                    catch { }
                }

                // read the lines from the CSV file
                laps = new LapsList();
                Lap lap = new Lap();
                laps.Add(lap);
                string[] textLines = System.IO.File.ReadAllLines(csvFileName);

                // convert the CSV lines into FIT records and laps
                int  skipped      = 0;
                int  removed      = 0;
                bool gotTotals    = false;
                int  rideCalories = 0;
                uint rideWork     = 0;
                for (int i = 0; i < textLines.Length; i++)
                {
                    string line = textLines[i];
                    if (!Char.IsDigit(line[0]))
                    {
                        if (line.StartsWith("Stage_"))
                        {
                            lap = new Lap();
                            laps.Add(lap);
                        }
                        else if (line.StartsWith("Ride_Totals"))
                        {
                            gotTotals = true;
                        }
                        else if (line.StartsWith("KCal,"))
                        {
                            if (int.TryParse(line.Substring(5), out int calories))
                            {
                                if (gotTotals)
                                {
                                    rideCalories = calories;
                                }
                                else if (laps.Count > 1)
                                {
                                    laps[laps.Count - 2].Calories = calories;
                                }
                            }
                        }
                        else if (line.StartsWith("KJ,"))
                        {
                            if (uint.TryParse(line.Substring(3), out uint work))
                            {
                                if (gotTotals)
                                {
                                    rideWork = work;
                                }
                                else if (laps.Count > 1)
                                {
                                    laps[laps.Count - 2].Work = work;
                                }
                            }
                        }
                        continue;
                    }
                    Record record = new Record(line, start);
                    if (record.Speed != 0 || record.Power != 0 || record.HeartRate != 0 || record.Cadence != 0)
                    {
                        lap.Records.Add(record);
                    }
                    else
                    {
                        skipped++;
                    }
                }

                // remove the last lap if it's empty
                Lap lastLap = laps[laps.Count - 1];
                if (lastLap.Records.Count == 0 && laps.Count > 1)
                {
                    laps.Remove(lastLap);
                    lastLap = laps[laps.Count - 1];
                }

                // fix up the calorie values
                int  sumCalories = 0;
                uint sumWork     = 0;
                foreach (Lap l in laps)
                {
                    sumCalories += l.Calories;
                    sumWork     += l.Work;
                }
                if (rideCalories == 0)
                {
                    rideCalories = sumCalories;
                }
                if (lastLap.Calories == 0)
                {
                    lastLap.Calories = rideCalories - sumCalories;
                }
                if (rideWork == 0)
                {
                    rideWork = sumWork;
                }
                if (lastLap.Work == 0)
                {
                    lastLap.Work = rideWork - sumWork;
                }

                // remove trailing rundown records from the last lap
                Record  lastRecord     = lastLap.Records[lastLap.Records.Count - 1];
                Summary lapSummary     = GetLapSummary(lastLap);
                double  speedThreshold = lapSummary.AveSpeed * 0.6;
                int     j = lastLap.Records.Count - 1;
                while (j >= 0 && lastLap.Records[j].Speed < speedThreshold)
                {
                    j--;
                }
                if (j != lastLap.Records.Count - 1)
                {
                    int count = lastLap.Records.Count - j - 1;
                    lastLap.Records.RemoveRange(j + 1, count);
                    removed += count;
                }

                // display a summary of the file
                Record  firstRecord    = laps[0].Records[0];
                Summary sessionSummary = GetSessionSummary(laps);
                NumRecordsLabel.Content = sessionSummary.NumRecords.ToString();
                NumSkippedLabel.Content = skipped.ToString();
                NumRemovedLabel.Content = removed.ToString();
                NumLapsLabel.Content    = laps.Count.ToString();
                System.DateTime startTime = firstRecord.Time.ToLocalTime();
                StartDateLabel.Content    = startTime.ToString("yyyy/MM/dd");
                StartTimeLabel.Content    = startTime.ToString("HH:mm:ss");
                ElapsedTimeLabel.Content  = (lastRecord.Time - firstRecord.Time).ToString();
                AveCadenceLabel.Content   = sessionSummary.AveCadence.ToString("0");
                MaxCadenceLabel.Content   = sessionSummary.MaxCadence.ToString();
                AvePowerLabel.Content     = sessionSummary.AvePower.ToString("0");
                MaxPowerLabel.Content     = sessionSummary.MaxPower.ToString();
                AveHeartRateLabel.Content = sessionSummary.AveHeartRate.ToString("0");
                MaxHeartRateLabel.Content = sessionSummary.MaxHeartRate.ToString();
                AveSpeedLabel.Content     = sessionSummary.AveSpeed.ToString("0.##");
                MaxSpeedLabel.Content     = sessionSummary.MaxSpeed.ToString("0.##");

                // write the data to a FIT file
                WriteFitFile(fitFileName, start, laps, rideCalories, rideWork);
            }
        }
Example #3
0
        /// <summary>
        /// Writes the data to a FIT file.
        /// </summary>
        /// <param name="fileName">Name of the FIT file to write to.</param>
        /// <param name="start">Start date/time of the activity.</param>
        /// <param name="laps">Lap and record data to be written.</param>
        /// <param name="calories">Calories used for the activity.</param>
        /// <param name="work">Work done for the activity.</param>
        static void WriteFitFile(string fileName, System.DateTime start, LapsList laps, int calories, uint work)
        {
            // open the encoder and stream
            Encode     encoder   = new Encode(ProtocolVersion.V20);
            FileStream fitStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);

            encoder.Open(fitStream);

            // write the file ID message
            FileIdMesg fileIdMsg = new FileIdMesg();

            fileIdMsg.SetType(Dynastream.Fit.File.Activity);
            fileIdMsg.SetManufacturer(Manufacturer.StagesCycling);
            fileIdMsg.SetProduct(3);
            fileIdMsg.SetSerialNumber(1);
            fileIdMsg.SetTimeCreated(new Dynastream.Fit.DateTime(start));
            encoder.Write(fileIdMsg);

            // write the record and lap messages
            foreach (Lap lap in laps)
            {
                // write the record messages
                foreach (Record record in lap.Records)
                {
                    RecordMesg recordMsg = new RecordMesg();
                    recordMsg.SetTimestamp(new Dynastream.Fit.DateTime(record.Time.ToUniversalTime()));
                    recordMsg.SetHeartRate((byte)record.HeartRate);
                    recordMsg.SetCadence((byte)record.Cadence);
                    recordMsg.SetDistance((float)record.Distance * 1000);
                    recordMsg.SetSpeed((float)(record.Speed / 3.6));
                    recordMsg.SetPower((ushort)record.Power);
                    encoder.Write(recordMsg);
                }

                // write the lap message
                Record   first  = lap.Records[0];
                Record   last   = lap.Records[lap.Records.Count - 1];
                TimeSpan time   = last.Time - first.Time;
                LapMesg  lapMsg = new LapMesg();
                lapMsg.SetTimestamp(new Dynastream.Fit.DateTime(last.Time.ToUniversalTime()));
                lapMsg.SetStartTime(new Dynastream.Fit.DateTime(first.Time.ToUniversalTime()));
                lapMsg.SetTotalElapsedTime((int)time.TotalSeconds);
                lapMsg.SetTotalTimerTime((int)time.TotalSeconds);
                lapMsg.SetTotalDistance((float)(last.Distance - first.Distance) * 1000);
                lapMsg.SetTotalCalories((ushort)lap.Calories);
                lapMsg.SetTotalWork(lap.Work * 1000);
                lapMsg.SetEvent(Event.Lap);
                lapMsg.SetEventType(EventType.Stop);
                lapMsg.SetIntensity(Intensity.Active);
                lapMsg.SetLapTrigger(LapTrigger.Manual);
                lapMsg.SetSport(Sport.Cycling);
                Summary lapSummary = GetLapSummary(lap);
                lapMsg.SetAvgCadence((byte)lapSummary.AveCadence);
                lapMsg.SetMaxCadence((byte)lapSummary.MaxCadence);
                lapMsg.SetAvgHeartRate((byte)lapSummary.AveHeartRate);
                lapMsg.SetMaxHeartRate((byte)lapSummary.MaxHeartRate);
                lapMsg.SetAvgPower((ushort)lapSummary.AvePower);
                lapMsg.SetMaxPower((ushort)lapSummary.MaxPower);
                lapMsg.SetAvgSpeed((float)lapSummary.AveSpeed / 3.6f);
                lapMsg.SetMaxSpeed((float)lapSummary.MaxSpeed / 3.6f);
                encoder.Write(lapMsg);
            }

            // get the first and last records
            Record   firstRecord = laps[0].Records[0];
            Lap      lastLap     = laps[laps.Count - 1];
            Record   lastRecord  = lastLap.Records[lastLap.Records.Count - 1];
            TimeSpan totalTime   = lastRecord.Time - firstRecord.Time;

            // write the session message
            SessionMesg sessionMsg = new SessionMesg();

            sessionMsg.SetTimestamp(new Dynastream.Fit.DateTime(lastRecord.Time.ToUniversalTime()));
            sessionMsg.SetStartTime(new Dynastream.Fit.DateTime(firstRecord.Time.ToUniversalTime()));
            sessionMsg.SetTotalElapsedTime((int)totalTime.TotalSeconds);
            sessionMsg.SetTotalTimerTime((int)totalTime.TotalSeconds);
            sessionMsg.SetTotalDistance((float)(lastRecord.Distance - firstRecord.Distance) * 1000);
            sessionMsg.SetTotalCalories((ushort)calories);
            sessionMsg.SetTotalWork(work * 1000);
            sessionMsg.SetFirstLapIndex(0);
            sessionMsg.SetNumLaps((ushort)laps.Count);
            sessionMsg.SetEvent(Event.Session);
            sessionMsg.SetEventType(EventType.Stop);
            sessionMsg.SetSport(Sport.Cycling);
            sessionMsg.SetSubSport(SubSport.Spin);
            Summary sessionSummary = GetSessionSummary(laps);

            sessionMsg.SetAvgCadence((byte)sessionSummary.AveCadence);
            sessionMsg.SetMaxCadence((byte)sessionSummary.MaxCadence);
            sessionMsg.SetAvgHeartRate((byte)sessionSummary.AveHeartRate);
            sessionMsg.SetMaxHeartRate((byte)sessionSummary.MaxHeartRate);
            sessionMsg.SetAvgPower((ushort)sessionSummary.AvePower);
            sessionMsg.SetMaxPower((ushort)sessionSummary.MaxPower);
            sessionMsg.SetAvgSpeed((float)sessionSummary.AveSpeed / 3.6f);
            sessionMsg.SetMaxSpeed((float)sessionSummary.MaxSpeed / 3.6f);
            encoder.Write(sessionMsg);

            // write the activity message
            ActivityMesg activityMsg = new ActivityMesg();

            activityMsg.SetTimestamp(new Dynastream.Fit.DateTime(lastRecord.Time.ToUniversalTime()));
            activityMsg.SetTotalTimerTime((int)totalTime.TotalSeconds);
            activityMsg.SetNumSessions(1);
            activityMsg.SetType(Activity.Manual);
            activityMsg.SetEvent(Event.Activity);
            activityMsg.SetEventType(EventType.Stop);
            encoder.Write(activityMsg);

            // close the encoder and stream
            encoder.Close();
            fitStream.Close();
        }