public List <SessionMessages> ParseSessions()
    {
        if (!IsActivityFile)
        {
            throw new Exception($"Expected FIT File Type: Activity, recieved File Type: {_messages?.FileId?.GetType()}");
        }

        // When there are no Sessions but there are Records create a Session message to recover as much data as possible
        if (_messages.Sessions.Count == 0 && _messages.Records.Count > 0)
        {
            Dynastream.Fit.DateTime startTime = _messages.Records[0].GetTimestamp();
            Dynastream.Fit.DateTime timestamp = _messages.Records[_messages.Records.Count - 1].GetTimestamp();

            var session = new SessionMesg();
            session.SetStartTime(startTime);
            session.SetTimestamp(timestamp);
            session.SetTotalElapsedTime(timestamp.GetTimeStamp() - startTime.GetTimeStamp());
            session.SetTotalTimerTime(timestamp.GetTimeStamp() - startTime.GetTimeStamp());

            _messages.Sessions.Add(session);
        }

        int recordsTaken = 0;

        var sessions = new List <SessionMessages>(_messages.Sessions.Count);

        foreach (SessionMesg sessionMesg in _messages.Sessions)
        {
            var session = new SessionMessages(sessionMesg)
            {
                Laps = _messages.Laps.Skip(sessionMesg.GetFirstLapIndex() ?? 0).Take(sessionMesg.GetNumLaps() ?? 0).ToList(),

                ClimbPros   = _messages.ClimbPros.Where(climb => climb.Within(sessionMesg)).ToList(),
                Events      = _messages.Events.Where(evt => evt.Within(sessionMesg)).ToList(),
                DeviceInfos = _messages.DeviceInfos.Where(deviceInfo => deviceInfo.Within(sessionMesg)).ToList(),
                Lengths     = _messages.Lengths.Where(length => length.Overlaps(sessionMesg)).ToList(),
                Records     = _messages.Records.Skip(recordsTaken).Where(record => record.Within(sessionMesg)).ToList(),
                SegmentLaps = _messages.SegmentLaps.Where(segmentLap => segmentLap.Overlaps(sessionMesg)).ToList(),

                TimerEvents               = _messages.Events.Where(evt => evt.GetEvent() == Event.Timer && evt.Within(sessionMesg)).ToList(),
                FrontGearChangeEvents     = _messages.Events.Where(evt => evt.GetEvent() == Event.FrontGearChange && evt.Within(sessionMesg)).ToList(),
                RearGearChangeEvents      = _messages.Events.Where(evt => evt.GetEvent() == Event.RearGearChange && evt.Within(sessionMesg)).ToList(),
                RiderPositionChangeEvents = _messages.Events.Where(evt => evt.GetEvent() == Event.RiderPositionChange && evt.Within(sessionMesg)).ToList(),

                Activity                  = _messages.Activity,
                FileId                    = _messages.FileId,
                RecordFieldNames          = _messages.RecordFieldNames,
                RecordDeveloperFieldNames = _messages.RecordDeveloperFieldNames,
                UserProfile               = _messages.UserProfile,
                Workout                   = _messages.Workout,
                WorkoutSteps              = _messages.WorkoutSteps,
                ZonesTarget               = _messages.ZonesTarget,
            };

            recordsTaken += session.Records.Count;
            sessions.Add(session);
        }

        return(sessions);
    }
示例#2
0
        public static void Stop()
        {
            var now = new DateTime(System.DateTime.Now);

            TerminateLap();

            sessionMesg.SetTimestamp(now);
            sessionMesg.SetSport(Sport.Cycling);
            sessionMesg.SetSubSport(SubSport.VirtualActivity);
            sessionMesg.SetTotalDistance(State.TripTotalKm * 1000);
            sessionMesg.SetTotalElapsedTime(State.TripTotalTime);
            sessionMesg.SetFirstLapIndex(0);
            sessionMesg.SetNumLaps(numLaps);
            sessionMesg.SetEvent(Event.Session);
            sessionMesg.SetEventType(EventType.Stop);
            sessionMesg.SetEventGroup(0);

            activityMesg = new ActivityMesg();
            activityMesg.SetTimestamp(now);
            activityMesg.SetTotalTimerTime(State.TripTotalTime);
            activityMesg.SetNumSessions(1);
            activityMesg.SetType(Activity.Manual);
            activityMesg.SetEvent(Event.Activity);
            activityMesg.SetEventType(EventType.Stop);
            activityMesg.SetEventGroup(0);

            encoder.Write(sessionMesg);
            encoder.Write(activityMesg);

            encoder.Close();
            fitDest.Close();
        }
示例#3
0
        public static void AddRecord()
        {
            var now = new DateTime(System.DateTime.Now);

            if (lastRecordTimeStamp == now.GetTimeStamp())
            {
                return; // do not record twice with same timestamp
            }

            try
            {
                var newRecord = new RecordMesg();
                var hr        = State.CyclistHeartRate > 0 ? (byte?)State.CyclistHeartRate : null;
                var cad       = State.BikeCadence > 0 ? (byte?)State.BikeCadence : null;

                newRecord.SetTimestamp(now);

                newRecord.SetHeartRate(hr);
                newRecord.SetCadence(cad);
                newRecord.SetPower((ushort)State.CyclistPower);
                newRecord.SetGrade(State.BikeIncline);
                newRecord.SetDistance(State.TripTotalKm * 1000);
                newRecord.SetSpeed(State.BikeSpeedKmh / 3.6f);
                newRecord.SetAltitude(RaceState.Instance.CarPositions[0].Y);

                encoder.Write(newRecord);

                lastRecordTimeStamp = now.GetTimeStamp();
            } catch (Exception e)
            {
                Console.Write("Failed to write record.");
                Console.WriteLine(e.Message);
            }
        }
示例#4
0
        static void OnFileIDMesg(object sender, MesgEventArgs e)
        {
            Console.WriteLine("FileIdHandler: Received {1} Mesg with global ID#{0}", e.mesg.Num, e.mesg.Name);
            FileIdMesg myFileId = (FileIdMesg)e.mesg;

            try
            {
                Console.WriteLine("\tType: {0}", myFileId.GetType());
                Console.WriteLine("\tManufacturer: {0}", myFileId.GetManufacturer());
                Console.WriteLine("\tProduct: {0}", myFileId.GetProduct());
                Console.WriteLine("\tSerialNumber {0}", myFileId.GetSerialNumber());
                Console.WriteLine("\tNumber {0}", myFileId.GetNumber());
                Console.WriteLine("\tTimeCreated {0}", myFileId.GetTimeCreated());

                //Make sure properties with sub properties arent null before trying to create objects based on them
                if (myFileId.GetTimeCreated() != null)
                {
                    Dynastream.Fit.DateTime dtTime = new Dynastream.Fit.DateTime(myFileId.GetTimeCreated().GetTimeStamp());
                }
            }
            catch (FitException exception)
            {
                Console.WriteLine("\tOnFileIDMesg Error {0}", exception.Message);
                Console.WriteLine("\t{0}", exception.InnerException);
            }
        }
        protected DeviceInfoMesg GetDeviceInfoMesg(GarminDeviceInfo deviceInfo, Dynastream.Fit.DateTime startTime)
        {
            var deviceInfoMesg = new DeviceInfoMesg();

            deviceInfoMesg.SetTimestamp(startTime);
            deviceInfoMesg.SetSerialNumber(deviceInfo.UnitId);
            deviceInfoMesg.SetManufacturer(deviceInfo.ManufacturerId);
            deviceInfoMesg.SetProduct(deviceInfo.ProductID);
            deviceInfoMesg.SetDeviceIndex(0);
            deviceInfoMesg.SetSourceType(SourceType.Local);
            deviceInfoMesg.SetProductName(deviceInfo.Name);

            if (deviceInfo.Version.VersionMinor <= 0)
            {
                deviceInfoMesg.SetSoftwareVersion(deviceInfo.Version.VersionMajor);
            }
            else
            {
                var adjustedMinor = deviceInfo.Version.VersionMinor < 10 ? deviceInfo.Version.VersionMinor * 10 : deviceInfo.Version.VersionMinor;
                var minor         = adjustedMinor / 100;
                deviceInfoMesg.SetSoftwareVersion((float)(deviceInfo.Version.VersionMajor + minor));
            }

            return(deviceInfoMesg);
        }
示例#6
0
 /// <summary>
 /// Gets a system date/time from a Dynastream date/time.
 /// </summary>
 /// <param name="dateTime">Dynastream date/time.</param>
 /// <returns>System date/time.</returns>
 public static System.DateTime?GetDateTime(Dynastream.Fit.DateTime dateTime)
 {
     if (dateTime != null)
     {
         return(dateTime.GetDateTime().ToLocalTime());
     }
     return(null);
 }
示例#7
0
        static void CreateActivityFile(List <Mesg> messages, String filename, Dynastream.Fit.DateTime startTime)
        {
            // The combination of file type, manufacturer id, product id, and serial number should be unique.
            // When available, a non-random serial number should be used.
            Dynastream.Fit.File fileType = Dynastream.Fit.File.Activity;
            ushort manufacturerId        = Manufacturer.Development;
            ushort productId             = 0;
            float  softwareVersion       = 1.0f;

            Random random       = new Random();
            uint   serialNumber = (uint)random.Next();

            // Every FIT file MUST contain a File ID message
            var fileIdMesg = new FileIdMesg();

            fileIdMesg.SetType(fileType);
            fileIdMesg.SetManufacturer(manufacturerId);
            fileIdMesg.SetProduct(productId);
            fileIdMesg.SetTimeCreated(startTime);
            fileIdMesg.SetSerialNumber(serialNumber);

            // A Device Info message is a BEST PRACTICE for FIT ACTIVITY files
            var deviceInfoMesg = new DeviceInfoMesg();

            deviceInfoMesg.SetDeviceIndex(DeviceIndex.Creator);
            deviceInfoMesg.SetManufacturer(Manufacturer.Development);
            deviceInfoMesg.SetProduct(productId);
            deviceInfoMesg.SetProductName("FIT Cookbook"); // Max 20 Chars
            deviceInfoMesg.SetSerialNumber(serialNumber);
            deviceInfoMesg.SetSoftwareVersion(softwareVersion);
            deviceInfoMesg.SetTimestamp(startTime);

            // Create the output stream, this can be any type of stream, including a file or memory stream. Must have read/write access
            FileStream fitDest = new FileStream(filename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);

            // Create a FIT Encode object
            Encode encoder = new Encode(ProtocolVersion.V20);

            // Write the FIT header to the output stream
            encoder.Open(fitDest);

            // Write the messages to the file, in the proper sequence
            encoder.Write(fileIdMesg);
            encoder.Write(deviceInfoMesg);

            foreach (Mesg message in messages)
            {
                encoder.Write(message);
            }

            // Update the data size in the header and calculate the CRC
            encoder.Close();

            // Close the output stream
            fitDest.Close();

            Console.WriteLine($"Encoded FIT file {fitDest.Name}");
        }
        public ICollection <LapMesg> GetLapsBasedOnSegments(WorkoutSamples workoutSamples, Dynastream.Fit.DateTime startTime, Sport sport, SubSport subSport)
        {
            using var tracing = Tracing.Trace($"{nameof(FitConverter)}.{nameof(GetLapsBasedOnSegments)}")
                                .WithTag(TagKey.Format, FileFormat.Fit.ToString());

            var stepsAndLaps = new List <LapMesg>();

            if (workoutSamples is null)
            {
                return(stepsAndLaps);
            }

            ushort stepIndex    = 0;
            var    speedMetrics = GetSpeedSummary(workoutSamples);

            if (workoutSamples.Segment_List.Any())
            {
                var totalElapsedTime = 0;
                foreach (var segment in workoutSamples.Segment_List)
                {
                    var lapStartTime = new Dynastream.Fit.DateTime(startTime);
                    lapStartTime.Add(segment.Start_Time_Offset);

                    totalElapsedTime += segment.Length;

                    var lapMesg = new LapMesg();
                    lapMesg.SetStartTime(lapStartTime);
                    lapMesg.SetMessageIndex(stepIndex);
                    lapMesg.SetEvent(Event.Lap);
                    lapMesg.SetLapTrigger(LapTrigger.Time);
                    lapMesg.SetSport(sport);
                    lapMesg.SetSubSport(subSport);

                    lapMesg.SetTotalElapsedTime(segment.Length);
                    lapMesg.SetTotalTimerTime(segment.Length);

                    var startIndex          = segment.Start_Time_Offset;
                    var endIndex            = segment.Start_Time_Offset + segment.Length;
                    var lapDistanceInMeters = 0f;
                    for (int i = startIndex; i < endIndex; i++)
                    {
                        if (speedMetrics is object && i < speedMetrics.Values.Length)
                        {
                            var currentSpeedInMPS = ConvertToMetersPerSecond(speedMetrics.GetValue(i), workoutSamples);
                            lapDistanceInMeters += 1 * currentSpeedInMPS;
                        }
                    }

                    lapMesg.SetTotalDistance(lapDistanceInMeters);
                    stepsAndLaps.Add(lapMesg);

                    stepIndex++;
                }
            }

            return(stepsAndLaps);
        }
示例#9
0
        void OnFileIDMesg(object sender, MesgEventArgs e)
        {
            FileIdMesg myFileId = (FileIdMesg)e.mesg;

            try
            {
                Dynastream.Fit.DateTime dtTime = new Dynastream.Fit.DateTime(myFileId.GetTimeCreated().GetTimeStamp());

                tDevice.Text       = getGarminProduct(myFileId.GetProduct());
                tSerialNumber.Text = myFileId.GetSerialNumber().ToString();
            }
            catch (FitException exception)
            {
                Debug.WriteLine(string.Format("\tOnFileIDMesg Error {0}", exception.Message));
                Debug.WriteLine(string.Format("\t{0}", exception.InnerException));
            }
        }
示例#10
0
文件: Fit.cs 项目: eitanbehar/gpx
        static void OnFileIDMesg(object sender, MesgEventArgs e)
        {
            Console.WriteLine("FileIdHandler: Received {1} Mesg with global ID#{0}", e.mesg.Num, e.mesg.Name);
            FileIdMesg myFileId = (FileIdMesg)e.mesg;

            try
            {
                Console.WriteLine("\tType: {0}", myFileId.GetType());
                Console.WriteLine("\tManufacturer: {0}", myFileId.GetManufacturer());
                Console.WriteLine("\tProduct: {0}", myFileId.GetProduct());
                Console.WriteLine("\tSerialNumber {0}", myFileId.GetSerialNumber());
                Console.WriteLine("\tNumber {0}", myFileId.GetNumber());
                Dynastream.Fit.DateTime dtTime = new Dynastream.Fit.DateTime(myFileId.GetTimeCreated().GetTimeStamp());
            }
            catch (FitException exception)
            {
                Console.WriteLine("\tOnFileIDMesg Error {0}", exception.Message);
                Console.WriteLine("\t{0}", exception.InnerException);
            }
        }
示例#11
0
        /// <summary>
        /// Terminates the current lap in the FIT recording.
        /// Use cases : ingame lap (if no workout in progress), start/end of workout, end of activity.
        /// </summary>
        public static void TerminateLap()
        {
            var now = new DateTime(System.DateTime.Now);

            currentLapMesg.SetTimestamp(now);
            currentLapMesg.SetSport(Sport.Cycling);
            currentLapMesg.SetTotalElapsedTime(now.GetTimeStamp() - currentLapMesg.GetStartTime().GetTimeStamp());
            currentLapMesg.SetTotalTimerTime(now.GetTimeStamp() - currentLapMesg.GetStartTime().GetTimeStamp());
            currentLapMesg.SetTotalDistance(State.TripTotalKm * 1000 - alreadyLappedDistance);
            currentLapMesg.SetEvent(Event.Lap);
            currentLapMesg.SetEventType(EventType.Stop);
            currentLapMesg.SetEventGroup(0);

            encoder.Write(currentLapMesg);

            numLaps++;
            currentLapMesg        = new LapMesg();
            alreadyLappedDistance = State.TripTotalKm * 1000;

            currentLapMesg.SetStartTime(now);
        }
示例#12
0
        static public void Start()
        {
            var assettoFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\Assetto Corsa\\SimCyclingActivities";

            if (!Directory.Exists(assettoFolder))
            {
                Directory.CreateDirectory(assettoFolder);
            }

            var filepath = assettoFolder + "\\" + System.DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss") + ".fit";

            var now = new DateTime(System.DateTime.Now);

            // Create file encode object
            encoder = new Encode(ProtocolVersion.V20);

            fitDest = new FileStream(filepath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
            encoder.Open(fitDest);

            var fileIdMesg = new FileIdMesg(); // Every FIT file MUST contain a 'File ID' message as the first message

            fileIdMesg.SetType(Dynastream.Fit.File.Activity);
            fileIdMesg.SetManufacturer(Manufacturer.Dynastream);  // Types defined in the profile are available
            fileIdMesg.SetProduct(22);
            fileIdMesg.SetSerialNumber(1234);
            fileIdMesg.SetTimeCreated(now);

            // Encode each message, a definition message is automatically generated and output if necessary
            encoder.Write(fileIdMesg);

            sessionMesg = new SessionMesg();
            sessionMesg.SetStartTime(now);

            currentLapMesg = new LapMesg();
            currentLapMesg.SetStartTime(now);
        }
示例#13
0
        public static void EncodeCourse()
        {
            const string filename = "CourseEncodeRecipe.fit";

            // Example Record Data Defining a Course
            var courseData = new List <Dictionary <string, object> >()
            {
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262849U }, { "position_lat", 463583114 }, { "position_long", -1131028903 }, { "altitude", 329f }, { "distance", 0f }, { "speed", 0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262855U }, { "position_lat", 463583127 }, { "position_long", -1131031938 }, { "altitude", 328.6f }, { "distance", 22.03f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262869U }, { "position_lat", 463583152 }, { "position_long", -1131038159 }, { "altitude", 327.6f }, { "distance", 67.29f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262876U }, { "position_lat", 463583164 }, { "position_long", -1131041346 }, { "altitude", 327f }, { "distance", 90.52f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262876U }, { "position_lat", 463583164 }, { "position_long", -1131041319 }, { "altitude", 327f }, { "distance", 90.72f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262891U }, { "position_lat", 463588537 }, { "position_long", -1131041383 }, { "altitude", 327f }, { "distance", 140.72f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262891U }, { "position_lat", 463588549 }, { "position_long", -1131041383 }, { "altitude", 327f }, { "distance", 140.82f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262897U }, { "position_lat", 463588537 }, { "position_long", -1131038293 }, { "altitude", 327.6f }, { "distance", 163.26f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262911U }, { "position_lat", 463588512 }, { "position_long", -1131032041 }, { "altitude", 328.4f }, { "distance", 208.75f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262918U }, { "position_lat", 463588499 }, { "position_long", -1131028879 }, { "altitude", 329f }, { "distance", 231.8f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262918U }, { "position_lat", 463588499 }, { "position_long", -1131028903 }, { "altitude", 329f }, { "distance", 231.97f }, { "speed", 3.0f }
                },
                new Dictionary <string, object>()
                {
                    { "timestamp", 961262933U }, { "position_lat", 463583127 }, { "position_long", -1131028903 }, { "altitude", 329f }, { "distance", 281.96f }, { "speed", 3.0f }
                },
            };

            // Create the output stream, this can be any type of stream, including a file or memory stream. Must have read/write access.
            FileStream fitDest = new FileStream(filename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);

            // Create a FIT Encode object
            Encode encoder = new Encode(ProtocolVersion.V10);

            // Write the FIT header to the output stream
            encoder.Open(fitDest);

            // Reference points for the course
            var firstRecord    = courseData[0];
            var lastRecord     = courseData[courseData.Count - 1];
            var halfwayRecord  = courseData[courseData.Count / 2];
            var startTimestamp = (uint)firstRecord["timestamp"];
            var endTimestamp   = (uint)lastRecord["timestamp"];
            var startDateTime  = new Dynastream.Fit.DateTime(startTimestamp);
            var endDateTime    = new Dynastream.Fit.DateTime(endTimestamp);

            // Every FIT file MUST contain a File ID message
            var fileIdMesg = new FileIdMesg();

            fileIdMesg.SetType(Dynastream.Fit.File.Course);
            fileIdMesg.SetManufacturer(Manufacturer.Development);
            fileIdMesg.SetProduct(ProductId);
            fileIdMesg.SetTimeCreated(startDateTime);
            fileIdMesg.SetSerialNumber(startDateTime.GetTimeStamp());
            encoder.Write(fileIdMesg);

            // Every FIT file MUST contain a Course message
            var courseMesg = new CourseMesg();

            courseMesg.SetName("Garmin Field Day");
            courseMesg.SetSport(Sport.Cycling);
            encoder.Write(courseMesg);

            // Every FIT COURSE file MUST contain a Lap message
            var lapMesg = new LapMesg();

            lapMesg.SetStartTime(startDateTime);
            lapMesg.SetTimestamp(startDateTime);
            lapMesg.SetTotalElapsedTime(endTimestamp - startTimestamp);
            lapMesg.SetTotalTimerTime(endTimestamp - startTimestamp);
            lapMesg.SetStartPositionLat((int)firstRecord["position_lat"]);
            lapMesg.SetStartPositionLong((int)firstRecord["position_long"]);
            lapMesg.SetEndPositionLat((int)lastRecord["position_lat"]);
            lapMesg.SetEndPositionLong((int)lastRecord["position_long"]);
            lapMesg.SetTotalDistance((float)lastRecord["distance"]);
            encoder.Write(lapMesg);

            // Timer Events are REQUIRED for FIT COURSE files
            var eventMesgStart = new EventMesg();

            eventMesgStart.SetTimestamp(startDateTime);
            eventMesgStart.SetEvent(Event.Timer);
            eventMesgStart.SetEventType(EventType.Start);
            encoder.Write(eventMesgStart);

            // Every FIT COURSE file MUST contain Record messages
            foreach (var record in courseData)
            {
                var timestamp = (uint)record["timestamp"];
                var latitude  = (int)record["position_lat"];
                var longitude = (int)record["position_long"];
                var distance  = (float)record["distance"];
                var speed     = (float)record["speed"];
                var altitude  = (float)record["altitude"];

                var recordMesg = new RecordMesg();
                recordMesg.SetTimestamp(new Dynastream.Fit.DateTime(timestamp));
                recordMesg.SetPositionLat(latitude);
                recordMesg.SetPositionLong(longitude);
                recordMesg.SetDistance(distance);
                recordMesg.SetSpeed(speed);
                recordMesg.SetAltitude(altitude);
                encoder.Write(recordMesg);

                // Add a Course Point at the halfway point of the route
                if (record == halfwayRecord)
                {
                    var coursePointMesg = new CoursePointMesg();
                    coursePointMesg.SetTimestamp(new Dynastream.Fit.DateTime(timestamp));
                    coursePointMesg.SetName("Halfway");
                    coursePointMesg.SetType(CoursePoint.Generic);
                    coursePointMesg.SetPositionLat(latitude);
                    coursePointMesg.SetPositionLong(longitude);
                    coursePointMesg.SetDistance(distance);
                    encoder.Write(coursePointMesg);
                }
            }

            // Timer Events are REQUIRED for FIT COURSE files
            var eventMesgStop = new EventMesg();

            eventMesgStop.SetTimestamp(endDateTime);
            eventMesgStop.SetEvent(Event.Timer);
            eventMesgStop.SetEventType(EventType.StopAll);
            encoder.Write(eventMesgStop);

            // Update the data size in the header and calculate the CRC
            encoder.Close();

            // Close the output stream
            fitDest.Close();

            Console.WriteLine($"Encoded FIT file {fitDest.Name}");
        }
示例#14
0
 public DeviceInfoMesg GetDeviceInfo(GarminDeviceInfo deviceInfo, Dynastream.Fit.DateTime startTime)
 {
     return(this.GetDeviceInfoMesg(deviceInfo, startTime));
 }
示例#15
0
        private SessionMesg GetSessionMesg(Workout workout, WorkoutSamples workoutSamples, Dynastream.Fit.DateTime startTime, Dynastream.Fit.DateTime endTime, ushort numLaps)
        {
            var sessionMesg = new SessionMesg();

            sessionMesg.SetTimestamp(endTime);
            sessionMesg.SetStartTime(startTime);
            var totalTime = workoutSamples.Duration;

            sessionMesg.SetTotalElapsedTime(totalTime);
            sessionMesg.SetTotalTimerTime(totalTime);
            sessionMesg.SetTotalDistance(GetTotalDistance(workoutSamples));
            sessionMesg.SetTotalWork((uint)workout.Total_Work);
            sessionMesg.SetTotalCalories((ushort)GetCalorieSummary(workoutSamples)?.Value);

            var outputSummary = GetOutputSummary(workoutSamples);

            sessionMesg.SetAvgPower((ushort?)outputSummary?.Average_Value);
            sessionMesg.SetMaxPower((ushort?)outputSummary?.Max_Value);

            sessionMesg.SetFirstLapIndex(0);
            sessionMesg.SetNumLaps(numLaps);
            sessionMesg.SetThresholdPower((ushort)workout.Ftp_Info.Ftp);
            sessionMesg.SetEvent(Event.Lap);
            sessionMesg.SetEventType(EventType.Stop);
            sessionMesg.SetSport(GetGarminSport(workout));
            sessionMesg.SetSubSport(GetGarminSubSport(workout));

            var hrSummary = GetHeartRateSummary(workoutSamples);

            sessionMesg.SetAvgHeartRate((byte?)hrSummary?.Average_Value);
            sessionMesg.SetMaxHeartRate((byte?)hrSummary?.Max_Value);

            var cadenceSummary = GetCadenceSummary(workoutSamples);

            sessionMesg.SetAvgCadence((byte?)cadenceSummary?.Average_Value);
            sessionMesg.SetMaxCadence((byte?)cadenceSummary?.Max_Value);

            sessionMesg.SetMaxSpeed(GetMaxSpeedMetersPerSecond(workoutSamples));
            sessionMesg.SetAvgSpeed(GetAvgSpeedMetersPerSecond(workoutSamples));
            sessionMesg.SetAvgGrade(GetAvgGrade(workoutSamples));
            sessionMesg.SetMaxPosGrade(GetMaxGrade(workoutSamples));
            sessionMesg.SetMaxNegGrade(0.0f);

            // HR zones
            if (_config.Format.IncludeTimeInHRZones && workoutSamples.Metrics.Any())
            {
                var hrz1 = GetHeartRateZone(1, workoutSamples);
                if (hrz1 is object)
                {
                    sessionMesg.SetTimeInHrZone(1, hrz1?.Duration);
                }

                var hrz2 = GetHeartRateZone(2, workoutSamples);
                if (hrz2 is object)
                {
                    sessionMesg.SetTimeInHrZone(2, hrz2?.Duration);
                }

                var hrz3 = GetHeartRateZone(3, workoutSamples);
                if (hrz3 is object)
                {
                    sessionMesg.SetTimeInHrZone(3, hrz3?.Duration);
                }

                var hrz4 = GetHeartRateZone(4, workoutSamples);
                if (hrz4 is object)
                {
                    sessionMesg.SetTimeInHrZone(4, hrz4?.Duration);
                }

                var hrz5 = GetHeartRateZone(5, workoutSamples);
                if (hrz5 is object)
                {
                    sessionMesg.SetTimeInHrZone(5, hrz5?.Duration);
                }
            }

            // Power Zones
            if (_config.Format.IncludeTimeInPowerZones && workoutSamples.Metrics.Any())
            {
                var zones = GetTimeInPowerZones(workout, workoutSamples);
                if (zones is object)
                {
                    sessionMesg.SetTimeInPowerZone(1, zones.Zone1.Duration);
                    sessionMesg.SetTimeInPowerZone(2, zones.Zone2.Duration);
                    sessionMesg.SetTimeInPowerZone(3, zones.Zone3.Duration);
                    sessionMesg.SetTimeInPowerZone(4, zones.Zone4.Duration);
                    sessionMesg.SetTimeInPowerZone(5, zones.Zone5.Duration);
                    sessionMesg.SetTimeInPowerZone(6, zones.Zone6.Duration);
                    sessionMesg.SetTimeInPowerZone(7, zones.Zone7.Duration);
                }
            }

            return(sessionMesg);
        }
        public ICollection <LapMesg> GetLaps(PreferredLapType preferredLapType, WorkoutSamples workoutSamples, Dynastream.Fit.DateTime startTime, Sport sport, SubSport subSport)
        {
            using var tracing = Tracing.Trace($"{nameof(FitConverter)}.{nameof(GetLaps)}")
                                .WithTag(TagKey.Format, FileFormat.Fit.ToString());

            if ((preferredLapType == PreferredLapType.Default || preferredLapType == PreferredLapType.Class_Segments) &&
                workoutSamples.Segment_List.Any())
            {
                return(GetLapsBasedOnSegments(workoutSamples, startTime, sport, subSport));
            }

            return(GetLapsBasedOnDistance(workoutSamples, startTime, sport, subSport));
        }
示例#17
0
文件: Fit.cs 项目: eitanbehar/gpx
        static void OnMesg(object sender, MesgEventArgs e)
        {
            string activityType = e.mesg.Name;

            Console.WriteLine("OnMesg: Received Mesg with global ID#{0}, its name is {1}", e.mesg.Num, activityType);

            Trackpoint tp = new Trackpoint();

            for (byte i = 0; i < e.mesg.GetNumFields(); i++)
            {
                foreach (var field in e.mesg.fields)
                {
                    string fieldValue = field.GetValue().ToString();
                    string fieldName  = field.GetName().ToString();
                    string recordType = e.mesg.fields[i].Num.ToString();
                    Console.WriteLine("\tField{0} Index{1} (\"{2}\" Field#{4}) Value: {3}", i, 0, fieldName, fieldValue, recordType);

                    if (activityType == "FileId")
                    {
                        switch (fieldName)
                        {
                        case "TimeCreated":
                            Dynastream.Fit.DateTime dt = new Dynastream.Fit.DateTime(uint.Parse(fieldValue));
                            tcx.Id        = Trackpoint.ConvertDate(dt.GetDateTime());
                            tcx.StartTime = dt.GetDateTime();
                            break;

                        default:
                            break;
                        }
                    }

                    if (activityType == "Record")
                    {
                        switch (fieldName)
                        {
                        case "Timestamp":
                            Dynastream.Fit.DateTime dt = new Dynastream.Fit.DateTime(uint.Parse(fieldValue));
                            tp.Time = dt.GetDateTime();
                            break;

                        case "HeartRate":
                            tp.HeartRateBpm = int.Parse(fieldValue);
                            break;

                        case "PositionLat":
                            tp.LatitudeDegrees = double.Parse(fieldValue);
                            break;

                        case "PositionLong":
                            tp.LongitudeDegrees = double.Parse(fieldValue);
                            break;

                        case "Altitude":
                            tp.AltitudeMeters = 300;    //double.Parse(fieldValue);
                            break;

                        default:
                            break;
                        }
                    }
                }
            }

            if (activityType == "Record")
            {
                tcx.TrackpointList.Add(tp);
            }
        }
        public ICollection <LapMesg> GetLapsBasedOnDistance(WorkoutSamples workoutSamples, Dynastream.Fit.DateTime startTime, Sport sport, SubSport subSport)
        {
            using var tracing = Tracing.Trace($"{nameof(FitConverter)}.{nameof(GetLapsBasedOnDistance)}")
                                .WithTag(TagKey.Format, FileFormat.Fit.ToString());

            var stepsAndLaps = new List <LapMesg>();

            if (workoutSamples is null)
            {
                return(stepsAndLaps);
            }

            var speedMetrics = GetSpeedSummary(workoutSamples);

            if (speedMetrics is null)
            {
                return(stepsAndLaps);
            }

            var speedUnit = GetDistanceUnit(speedMetrics?.Display_Unit);
            var lapMeters = 0;

            switch (speedUnit)
            {
            case DistanceUnit.Kilometers: lapMeters = 1000; break;

            default: lapMeters = 1600; break;
            }

            LapMesg lap                 = null;
            ushort  stepIndex           = 0;
            var     lapDistanceInMeters = 0f;
            float   lapLengthSeconds    = 0;

            for (var secondsSinceStart = 0; secondsSinceStart < speedMetrics.Values.Length; secondsSinceStart++)
            {
                if (lap is null || lap.GetTotalElapsedTime() is not null)
                {
                    // Start new Lap
                    var lapStartTime = new Dynastream.Fit.DateTime(startTime);
                    lapStartTime.Add(secondsSinceStart);

                    lap = new LapMesg();
                    lap.SetStartTime(lapStartTime);
                    lap.SetMessageIndex(stepIndex);
                    lap.SetEvent(Event.Lap);
                    lap.SetLapTrigger(LapTrigger.Time);
                    lap.SetSport(sport);
                    lap.SetSubSport(subSport);

                    lapLengthSeconds    = 0;
                    lapDistanceInMeters = 0f;
                }

                var currentSpeedInMPS = ConvertToMetersPerSecond(speedMetrics.GetValue(secondsSinceStart), workoutSamples);
                lapDistanceInMeters += 1 * currentSpeedInMPS;
                lapLengthSeconds++;

                if (lapDistanceInMeters >= lapMeters || secondsSinceStart == speedMetrics.Values.Length - 1)
                {
                    lap.SetTotalElapsedTime(lapLengthSeconds);
                    lap.SetTotalTimerTime(lapLengthSeconds);
                    lap.SetTotalDistance(lapDistanceInMeters);
                    stepsAndLaps.Add(lap);
                    stepIndex++;
                }
            }

            return(stepsAndLaps);
        }
示例#19
0
        static void OnFileIDMesg(object sender, MesgEventArgs e)
        {
            Console.WriteLine("FileIdHandler: Received {1} Mesg with global ID#{0}", e.mesg.Num, e.mesg.Name);
             FileIdMesg myFileId = (FileIdMesg)e.mesg;
             try
             {
            Console.WriteLine("\tType: {0}", myFileId.GetType());
            Console.WriteLine("\tManufacturer: {0}", myFileId.GetManufacturer());
            Console.WriteLine("\tProduct: {0}", myFileId.GetProduct());
            Console.WriteLine("\tSerialNumber {0}", myFileId.GetSerialNumber());
            Console.WriteLine("\tNumber {0}", myFileId.GetNumber());
            Console.WriteLine("\tTimeCreated {0}", myFileId.GetTimeCreated());
            Dynastream.Fit.DateTime dtTime = new Dynastream.Fit.DateTime(myFileId.GetTimeCreated().GetTimeStamp());

             }
             catch (FitException exception)
             {
            Console.WriteLine("\tOnFileIDMesg Error {0}", exception.Message);
            Console.WriteLine("\t{0}", exception.InnerException);
             }
        }
示例#20
0
        static public void CreateLapSwimActivity()
        {
            // Example Swim Data representing a 500 yard pool swim using different strokes and drills.
            var swimData = new List <Dictionary <string, object> >()
            {
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 20U }, { "stroke", "Freestyle" }, { "strokes", 30U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 25U }, { "stroke", "Freestyle" }, { "strokes", 20U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 30U }, { "stroke", "Freestyle" }, { "strokes", 10U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 35U }, { "stroke", "Freestyle" }, { "strokes", 20U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Lap" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Idle" }, { "duration", 60U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Lap" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 20U }, { "stroke", "Backstroke" }, { "strokes", 30U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 25U }, { "stroke", "Backstroke" }, { "strokes", 20U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 30U }, { "stroke", "Backstroke" }, { "strokes", 10U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 35U }, { "stroke", "Backstroke" }, { "strokes", 20U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Lap" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Idle" }, { "duration", 60U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Lap" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 20U }, { "stroke", "Breaststroke" }, { "strokes", 30U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 25U }, { "stroke", "Breaststroke" }, { "strokes", 20U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 30U }, { "stroke", "Breaststroke" }, { "strokes", 10U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 35U }, { "stroke", "Breaststroke" }, { "strokes", 20U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Lap" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Idle" }, { "duration", 60U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Lap" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 20U }, { "stroke", "Butterfly" }, { "strokes", 30U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 25U }, { "stroke", "Butterfly" }, { "strokes", 20U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 30U }, { "stroke", "Butterfly" }, { "strokes", 10U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 35U }, { "stroke", "Butterfly" }, { "strokes", 20U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Lap" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Idle" }, { "duration", 60U }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Lap" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 40U }, { "stroke", "Drill" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 40U }, { "stroke", "Drill" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 40U }, { "stroke", "Drill" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Active" }, { "duration", 40U }, { "stroke", "Drill" }
                },
                new Dictionary <string, object>()
                {
                    { "type", "Lap" }
                },
            };

            const string FileName = "ActivityEncodeRecipeLapSwim.fit";
            var          messages = new List <Mesg>();

            // The starting timestamp for the activity
            var startTime = new Dynastream.Fit.DateTime(System.DateTime.UtcNow);


            // Timer Events are a BEST PRACTICE for FIT ACTIVITY files
            var eventMesgStart = new EventMesg();

            eventMesgStart.SetTimestamp(startTime);
            eventMesgStart.SetEvent(Event.Timer);
            eventMesgStart.SetEventType(EventType.Start);
            messages.Add(eventMesgStart);

            //
            // Create a Length or Lap message for each item in the sample swim data. Calculate
            // distance, duration, and stroke count for each lap and the overall session.
            //

            // Session Accumulators
            uint   sessionTotalElapsedTime = 0;
            float  sessionDistance         = 0;
            ushort sessionNumLengths       = 0;
            ushort sessionNumActiveLengths = 0;
            ushort sessionTotalStrokes     = 0;
            ushort sessionNumLaps          = 0;

            // Lap accumulators
            uint   lapTotalElapsedTime = 0;
            float  lapDistance         = 0;
            ushort lapNumActiveLengths = 0;
            ushort lapNumLengths       = 0;
            ushort lapFirstLengthIndex = 0;
            ushort lapTotalStrokes     = 0;
            var    lapStartTime        = new Dynastream.Fit.DateTime(startTime);

            var    poolLength     = 22.86f;
            var    poolLengthUnit = DisplayMeasure.Statute;
            var    timestamp      = new Dynastream.Fit.DateTime(startTime);
            ushort messageIndex   = 0;

            foreach (var swimLength in swimData)
            {
                string type = (string)swimLength["type"];

                if (type.Equals("Lap"))
                {
                    // Create a Lap message, set its fields, and write it to the file
                    var lapMesg = new LapMesg();
                    lapMesg.SetMessageIndex(sessionNumLaps);
                    lapMesg.SetTimestamp(timestamp);
                    lapMesg.SetStartTime(lapStartTime);
                    lapMesg.SetTotalElapsedTime(lapTotalElapsedTime);
                    lapMesg.SetTotalTimerTime(lapTotalElapsedTime);
                    lapMesg.SetTotalDistance(lapDistance);
                    lapMesg.SetFirstLengthIndex(lapFirstLengthIndex);
                    lapMesg.SetNumActiveLengths(lapNumActiveLengths);
                    lapMesg.SetNumLengths(lapNumLengths);
                    lapMesg.SetTotalStrokes(lapTotalStrokes);
                    lapMesg.SetAvgStrokeDistance(lapDistance / lapTotalStrokes);
                    lapMesg.SetSport(Sport.Swimming);
                    lapMesg.SetSubSport(SubSport.LapSwimming);
                    messages.Add(lapMesg);

                    sessionNumLaps++;

                    // Reset the Lap accumulators
                    lapFirstLengthIndex = messageIndex;
                    lapNumActiveLengths = 0;
                    lapNumLengths       = 0;
                    lapTotalElapsedTime = 0;
                    lapDistance         = 0;
                    lapTotalStrokes     = 0;
                    lapStartTime        = new Dynastream.Fit.DateTime(timestamp);
                }
                else
                {
                    uint duration   = (uint)swimLength["duration"];
                    var  lengthType = (LengthType)Enum.Parse(typeof(LengthType), type);

                    // Create a Length message and its fields
                    var lengthMesg = new LengthMesg();
                    lengthMesg.SetMessageIndex(messageIndex++);
                    lengthMesg.SetStartTime(timestamp);
                    lengthMesg.SetTotalElapsedTime(duration);
                    lengthMesg.SetTotalTimerTime(duration);
                    lengthMesg.SetLengthType(lengthType);

                    timestamp.Add(duration);
                    lengthMesg.SetTimestamp(timestamp);

                    // Create the Record message that pairs with the Length Message
                    var recordMesg = new RecordMesg();
                    recordMesg.SetTimestamp(timestamp);
                    recordMesg.SetDistance(sessionDistance + poolLength);

                    // Is this an Active Length?
                    if (lengthType == LengthType.Active)
                    {
                        // Get the Active data from the model
                        string     stroke     = swimLength.ContainsKey("stroke") ? (String)swimLength["stroke"] : "Freestyle";
                        uint       strokes    = swimLength.ContainsKey("strokes") ? (uint)swimLength["strokes"] : 0;
                        SwimStroke swimStroke = (SwimStroke)Enum.Parse(typeof(SwimStroke), stroke);

                        // Set the Active data on the Length Message
                        lengthMesg.SetAvgSpeed(poolLength / (float)duration);
                        lengthMesg.SetSwimStroke(swimStroke);

                        if (strokes > 0)
                        {
                            lengthMesg.SetTotalStrokes((ushort)strokes);
                            lengthMesg.SetAvgSwimmingCadence((byte)(strokes * 60U / duration));
                        }

                        // Set the Active data on the Record Message
                        recordMesg.SetSpeed(poolLength / (float)duration);
                        if (strokes > 0)
                        {
                            recordMesg.SetCadence((byte)((strokes * 60U) / duration));
                        }

                        // Increment the "Active" accumulators
                        sessionNumActiveLengths++;
                        lapNumActiveLengths++;
                        sessionDistance     += poolLength;
                        lapDistance         += poolLength;
                        sessionTotalStrokes += (ushort)strokes;
                        lapTotalStrokes     += (ushort)strokes;
                    }

                    // Write the messages to the file
                    messages.Add(recordMesg);
                    messages.Add(lengthMesg);

                    // Increment the "Total" accumulators
                    sessionTotalElapsedTime += duration;
                    lapTotalElapsedTime     += duration;
                    sessionNumLengths++;
                    lapNumLengths++;
                }
            }

            // Timer Events are a BEST PRACTICE for FIT ACTIVITY files
            var eventMesgStop = new EventMesg();

            eventMesgStop.SetTimestamp(timestamp);
            eventMesgStop.SetEvent(Event.Timer);
            eventMesgStop.SetEventType(EventType.StopAll);
            messages.Add(eventMesgStop);

            // Every FIT ACTIVITY file MUST contain at least one Session message
            var sessionMesg = new SessionMesg();

            sessionMesg.SetMessageIndex(0);
            sessionMesg.SetTimestamp(timestamp);
            sessionMesg.SetStartTime(startTime);
            sessionMesg.SetTotalElapsedTime(sessionTotalElapsedTime);
            sessionMesg.SetTotalTimerTime(sessionTotalElapsedTime);
            sessionMesg.SetTotalDistance(sessionDistance);
            sessionMesg.SetSport(Sport.Swimming);
            sessionMesg.SetSubSport(SubSport.LapSwimming);
            sessionMesg.SetFirstLapIndex(0);
            sessionMesg.SetNumLaps(sessionNumLaps);
            sessionMesg.SetPoolLength(poolLength);
            sessionMesg.SetPoolLengthUnit(poolLengthUnit);
            sessionMesg.SetNumLengths(sessionNumLengths);
            sessionMesg.SetNumActiveLengths(sessionNumActiveLengths);
            sessionMesg.SetTotalStrokes(sessionTotalStrokes);
            sessionMesg.SetAvgStrokeDistance(sessionDistance / sessionTotalStrokes);
            messages.Add(sessionMesg);

            // Every FIT ACTIVITY file MUST contain EXACTLY one Activity message
            var activityMesg = new ActivityMesg();

            activityMesg.SetTimestamp(timestamp);
            activityMesg.SetNumSessions(1);
            var timezoneOffset = (int)TimeZoneInfo.Local.BaseUtcOffset.TotalSeconds;

            activityMesg.SetLocalTimestamp((uint)((int)timestamp.GetTimeStamp() + timezoneOffset));
            activityMesg.SetTotalTimerTime(sessionTotalElapsedTime);
            messages.Add(activityMesg);

            CreateActivityFile(messages, FileName, startTime);
        }
示例#21
0
        private Dynastream.Fit.DateTime AddMetrics(ICollection <Mesg> messages, WorkoutSamples workoutSamples, Dynastream.Fit.DateTime startTime)
        {
            var allMetrics        = workoutSamples.Metrics;
            var hrMetrics         = allMetrics.FirstOrDefault(m => m.Slug == "heart_rate");
            var outputMetrics     = allMetrics.FirstOrDefault(m => m.Slug == "output");
            var cadenceMetrics    = allMetrics.FirstOrDefault(m => m.Slug == "cadence");
            var speedMetrics      = GetSpeedSummary(workoutSamples);
            var resistanceMetrics = allMetrics.FirstOrDefault(m => m.Slug == "resistance");
            var inclineMetrics    = GetGradeSummary(workoutSamples);
            var locationMetrics   = workoutSamples.Location_Data?.SelectMany(x => x.Coordinates).ToArray();
            var altitudeMetrics   = allMetrics.FirstOrDefault(m => m.Slug == "altitude");

            var recordsTimeStamp = new Dynastream.Fit.DateTime(startTime);

            if (workoutSamples.Seconds_Since_Pedaling_Start is object)
            {
                for (var i = 0; i < workoutSamples.Seconds_Since_Pedaling_Start.Count; i++)
                {
                    var record = new RecordMesg();
                    record.SetTimestamp(recordsTimeStamp);

                    if (speedMetrics is object && i < speedMetrics.Values.Length)
                    {
                        record.SetSpeed(ConvertToMetersPerSecond(speedMetrics.GetValue(i), workoutSamples));
                    }

                    if (hrMetrics is object && i < hrMetrics.Values.Length)
                    {
                        record.SetHeartRate((byte)hrMetrics.Values[i]);
                    }

                    if (cadenceMetrics is object && i < cadenceMetrics.Values.Length)
                    {
                        record.SetCadence((byte)cadenceMetrics.Values[i]);
                    }

                    if (outputMetrics is object && i < outputMetrics.Values.Length)
                    {
                        record.SetPower((ushort)outputMetrics.Values[i]);
                    }

                    if (resistanceMetrics is object && i < resistanceMetrics.Values.Length)
                    {
                        var resistancePercent = resistanceMetrics.Values[i] / 1;
                        record.SetResistance((byte)(254 * resistancePercent));
                    }

                    if (altitudeMetrics is object && i < altitudeMetrics.Values.Length)
                    {
                        var altitude = ConvertDistanceToMeters(altitudeMetrics.GetValue(i), altitudeMetrics.Display_Unit);
                        record.SetAltitude(altitude);
                    }

                    if (inclineMetrics is object && i < inclineMetrics.Values.Length)
                    {
                        record.SetGrade((float)inclineMetrics.GetValue(i));
                    }

                    if (locationMetrics is object && i < locationMetrics.Length)
                    {
                        // unit is semicircles
                        record.SetPositionLat(ConvertDegreesToSemicircles(locationMetrics[i].Latitude));
                        record.SetPositionLong(ConvertDegreesToSemicircles(locationMetrics[i].Longitude));
                    }

                    messages.Add(record);
                    recordsTimeStamp.Add(1);
                }
            }

            return(recordsTimeStamp);
        }
示例#22
0
        static public void CreateTimeBasedActivity()
        {
            const double TwoPI = Math.PI * 2.0;
            const double SemicirclesPerMeter = 107.173;
            const string FileName            = "ActivityEncodeRecipe.fit";

            var messages = new List <Mesg>();

            // The starting timestamp for the activity
            var startTime = new Dynastream.Fit.DateTime(System.DateTime.UtcNow);

            // Timer Events are a BEST PRACTICE for FIT ACTIVITY files
            var eventMesgStart = new EventMesg();

            eventMesgStart.SetTimestamp(startTime);
            eventMesgStart.SetEvent(Event.Timer);
            eventMesgStart.SetEventType(EventType.Start);
            messages.Add(eventMesgStart);

            // Create the Developer Id message for the developer data fields.
            var developerIdMesg = new DeveloperDataIdMesg();

            // It is a BEST PRACTICE to reuse the same Guid for all FIT files created by your platform
            byte[] appId = new Guid("00010203-0405-0607-0809-0A0B0C0D0E0F").ToByteArray();
            for (int i = 0; i < appId.Length; i++)
            {
                developerIdMesg.SetApplicationId(i, appId[i]);
            }
            developerIdMesg.SetDeveloperDataIndex(0);
            developerIdMesg.SetApplicationVersion(110);
            messages.Add(developerIdMesg);

            // Create the Developer Data Field Descriptions
            var doughnutsFieldDescMesg = new FieldDescriptionMesg();

            doughnutsFieldDescMesg.SetDeveloperDataIndex(0);
            doughnutsFieldDescMesg.SetFieldDefinitionNumber(0);
            doughnutsFieldDescMesg.SetFitBaseTypeId(FitBaseType.Float32);
            doughnutsFieldDescMesg.SetFieldName(0, "Doughnuts Earned");
            doughnutsFieldDescMesg.SetUnits(0, "doughnuts");
            doughnutsFieldDescMesg.SetNativeMesgNum(MesgNum.Session);
            messages.Add(doughnutsFieldDescMesg);

            FieldDescriptionMesg hrFieldDescMesg = new FieldDescriptionMesg();

            hrFieldDescMesg.SetDeveloperDataIndex(0);
            hrFieldDescMesg.SetFieldDefinitionNumber(1);
            hrFieldDescMesg.SetFitBaseTypeId(FitBaseType.Uint8);
            hrFieldDescMesg.SetFieldName(0, "Heart Rate");
            hrFieldDescMesg.SetUnits(0, "bpm");
            hrFieldDescMesg.SetNativeFieldNum(RecordMesg.FieldDefNum.HeartRate);
            hrFieldDescMesg.SetNativeMesgNum(MesgNum.Record);
            messages.Add(hrFieldDescMesg);

            // Every FIT ACTIVITY file MUST contain Record messages
            var timestamp = new Dynastream.Fit.DateTime(startTime);

            // Create one hour (3600 seconds) of Record data
            for (uint i = 0; i <= 3600; i++)
            {
                // Create a new Record message and set the timestamp
                var recordMesg = new RecordMesg();
                recordMesg.SetTimestamp(timestamp);

                // Fake Record Data of Various Signal Patterns
                recordMesg.SetDistance(i);                                                          // Ramp
                recordMesg.SetSpeed(1);                                                             // Flatline
                recordMesg.SetHeartRate((byte)((Math.Sin(TwoPI * (0.01 * i + 10)) + 1.0) * 127.0)); // Sine
                recordMesg.SetCadence((byte)(i % 255));                                             // Sawtooth
                recordMesg.SetPower((ushort)((i % 255) < 127 ? 150 : 250));                         // Square
                recordMesg.SetAltitude((float)Math.Abs(((double)i % 255.0) - 127.0));               // Triangle
                recordMesg.SetPositionLat(0);
                recordMesg.SetPositionLong((int)Math.Round(i * SemicirclesPerMeter));

                // Add a Developer Field to the Record Message
                var hrDevField = new DeveloperField(hrFieldDescMesg, developerIdMesg);
                recordMesg.SetDeveloperField(hrDevField);
                hrDevField.SetValue((byte)((Math.Sin(TwoPI * (0.01 * i + 10)) + 1.0) * 127.0)); // Sine

                // Write the Rercord message to the output stream
                messages.Add(recordMesg);

                // Increment the timestamp by one second
                timestamp.Add(1);
            }

            // Timer Events are a BEST PRACTICE for FIT ACTIVITY files
            var eventMesgStop = new EventMesg();

            eventMesgStop.SetTimestamp(timestamp);
            eventMesgStop.SetEvent(Event.Timer);
            eventMesgStop.SetEventType(EventType.StopAll);
            messages.Add(eventMesgStop);

            // Every FIT ACTIVITY file MUST contain at least one Lap message
            var lapMesg = new LapMesg();

            lapMesg.SetMessageIndex(0);
            lapMesg.SetTimestamp(timestamp);
            lapMesg.SetStartTime(startTime);
            lapMesg.SetTotalElapsedTime(timestamp.GetTimeStamp() - startTime.GetTimeStamp());
            lapMesg.SetTotalTimerTime(timestamp.GetTimeStamp() - startTime.GetTimeStamp());
            messages.Add(lapMesg);

            // Every FIT ACTIVITY file MUST contain at least one Session message
            var sessionMesg = new SessionMesg();

            sessionMesg.SetMessageIndex(0);
            sessionMesg.SetTimestamp(timestamp);
            sessionMesg.SetStartTime(startTime);
            sessionMesg.SetTotalElapsedTime(timestamp.GetTimeStamp() - startTime.GetTimeStamp());
            sessionMesg.SetTotalTimerTime(timestamp.GetTimeStamp() - startTime.GetTimeStamp());
            sessionMesg.SetSport(Sport.StandUpPaddleboarding);
            sessionMesg.SetSubSport(SubSport.Generic);
            sessionMesg.SetFirstLapIndex(0);
            sessionMesg.SetNumLaps(1);

            // Add a Developer Field to the Session message
            var doughnutsEarnedDevField = new DeveloperField(doughnutsFieldDescMesg, developerIdMesg);

            doughnutsEarnedDevField.SetValue(sessionMesg.GetTotalElapsedTime() / 1200.0f);
            sessionMesg.SetDeveloperField(doughnutsEarnedDevField);
            messages.Add(sessionMesg);

            // Every FIT ACTIVITY file MUST contain EXACTLY one Activity message
            var activityMesg = new ActivityMesg();

            activityMesg.SetTimestamp(timestamp);
            activityMesg.SetNumSessions(1);
            var timezoneOffset = (int)TimeZoneInfo.Local.BaseUtcOffset.TotalSeconds;

            activityMesg.SetLocalTimestamp((uint)((int)timestamp.GetTimeStamp() + timezoneOffset));
            activityMesg.SetTotalTimerTime(timestamp.GetTimeStamp() - startTime.GetTimeStamp());
            messages.Add(activityMesg);

            CreateActivityFile(messages, FileName, startTime);
        }
示例#23
0
        private Dictionary <int, Tuple <WorkoutStepMesg, LapMesg> > GetWorkoutStepsAndLaps(WorkoutSamples workoutSamples, Dynastream.Fit.DateTime startTime, Sport sport, SubSport subSport)
        {
            var stepsAndLaps = new Dictionary <int, Tuple <WorkoutStepMesg, LapMesg> >();

            if (workoutSamples is null)
            {
                return(stepsAndLaps);
            }

            var cadenceTargets = workoutSamples.Target_Performance_Metrics?.Target_Graph_Metrics?.FirstOrDefault(w => w.Type == "cadence")?.Graph_Data;

            if (cadenceTargets is null)
            {
                return(stepsAndLaps);
            }

            uint            previousCadenceLower = 0;
            uint            previousCadenceUpper = 0;
            ushort          stepIndex            = 0;
            var             duration             = 0;
            float           lapDistanceInMeters  = 0;
            WorkoutStepMesg workoutStep          = null;
            LapMesg         lapMesg      = null;
            var             speedMetrics = GetSpeedSummary(workoutSamples);

            foreach (var secondSinceStart in workoutSamples.Seconds_Since_Pedaling_Start)
            {
                var index = secondSinceStart <= 0 ? 0 : secondSinceStart - 1;
                duration++;

                if (speedMetrics is object && index < speedMetrics.Values.Length)
                {
                    var currentSpeedInMPS = ConvertToMetersPerSecond(speedMetrics.GetValue(index), workoutSamples);
                    lapDistanceInMeters += 1 * currentSpeedInMPS;
                }

                var currentCadenceLower = index < cadenceTargets.Lower.Length ? (uint)cadenceTargets.Lower[index] : 0;
                var currentCadenceUpper = index < cadenceTargets.Upper.Length ? (uint)cadenceTargets.Upper[index] : 0;

                if (currentCadenceLower != previousCadenceLower ||
                    currentCadenceUpper != previousCadenceUpper)
                {
                    if (workoutStep != null && lapMesg != null)
                    {
                        workoutStep.SetDurationValue((uint)duration * 1000);                         // milliseconds

                        var lapEndTime = new Dynastream.Fit.DateTime(startTime);
                        lapEndTime.Add(secondSinceStart);
                        lapMesg.SetTotalElapsedTime(duration);
                        lapMesg.SetTotalTimerTime(duration);
                        lapMesg.SetTimestamp(lapEndTime);
                        lapMesg.SetEventType(EventType.Stop);
                        lapMesg.SetTotalDistance(lapDistanceInMeters);

                        stepsAndLaps.Add(stepIndex, new Tuple <WorkoutStepMesg, LapMesg>(workoutStep, lapMesg));
                        stepIndex++;
                        duration            = 0;
                        lapDistanceInMeters = 0;
                    }

                    workoutStep = new WorkoutStepMesg();
                    workoutStep.SetDurationType(WktStepDuration.Time);
                    workoutStep.SetMessageIndex(stepIndex);
                    workoutStep.SetTargetType(WktStepTarget.Cadence);
                    workoutStep.SetCustomTargetValueHigh(currentCadenceUpper);
                    workoutStep.SetCustomTargetValueLow(currentCadenceLower);
                    workoutStep.SetIntensity(currentCadenceUpper > 60 ? Intensity.Active : Intensity.Rest);

                    lapMesg = new LapMesg();
                    var lapStartTime = new Dynastream.Fit.DateTime(startTime);
                    lapStartTime.Add(secondSinceStart);
                    lapMesg.SetStartTime(lapStartTime);
                    lapMesg.SetWktStepIndex(stepIndex);
                    lapMesg.SetMessageIndex(stepIndex);
                    lapMesg.SetEvent(Event.Lap);
                    lapMesg.SetLapTrigger(LapTrigger.Time);
                    lapMesg.SetSport(sport);
                    lapMesg.SetSubSport(subSport);

                    previousCadenceLower = currentCadenceLower;
                    previousCadenceUpper = currentCadenceUpper;
                }
            }

            return(stepsAndLaps);
        }
示例#24
0
        void BtnSaveFitClick(object sender, EventArgs e)
        {
            if (saveFileDlg.ShowDialog() == DialogResult.OK)
            {
                FileIdMesg fileIdMesg = new FileIdMesg();
                fileIdMesg.SetManufacturer(Manufacturer.Dynastream);
                fileIdMesg.SetProduct(1000);
                fileIdMesg.SetSerialNumber(12345);

                FileStream fitDest = new FileStream(saveFileDlg.FileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);

                // create file encode object
                Encode encode = new Encode();
                // write out header
                encode.Open(fitDest);
                // encode each message, a definition message is automatically generated and output if necessary
                encode.Write(fileIdMesg);

                SQLiteCommand cmd = new SQLiteCommand(_db);
                string        sql;
                // TODO: write FIT File Summary Information here, suspect that's why GarminConnect
                // is rejecting it because the summary data isn't there.
                sql             = string.Format("select fs.*, f.fileActivityDateTime from FileSummary fs join File f on f.idFile = fs.idFile where fs.idFile = {0}", _file);
                cmd.CommandText = sql;
                SQLiteDataReader rdr_summary = cmd.ExecuteReader();
                if (rdr_summary.HasRows)
                {
                    rdr_summary.Read();
                    SessionMesg sess = new SessionMesg();
                    //"fsMaxHeartRate" INTEGER,"fsMaxCadence" INTEGER,"fsMaxSpeed" FLOAT, "fsAvgPower" FLOAT, "fsMaxPower" FLOAT)
                    sess.SetTotalElapsedTime((float)Convert.ToDouble(rdr_summary["fsDuration"]));
                    sess.SetTotalMovingTime((float)Convert.ToDouble(rdr_summary["fsMovingTime"]));
                    sess.SetTotalTimerTime((float)Convert.ToDouble(rdr_summary["fsMovingTime"]));
                    sess.SetTotalDistance((float)(Convert.ToDouble(rdr_summary["fsDistance"]) * 1609.344));                     // convert miles back to metres
                    sess.SetTotalCalories(Convert.ToUInt16(rdr_summary["fsCalories"]));
                    sess.SetAvgHeartRate(Convert.ToByte(Convert.ToInt32(rdr_summary["fsAvgHeart"])));
                    sess.SetAvgCadence(Convert.ToByte(Convert.ToInt32(rdr_summary["fsAvgCadence"])));
                    sess.SetAvgSpeed((float)(Convert.ToDouble(rdr_summary["fsAvgSpeed"]) / 2.23693629));
                    sess.SetTotalAscent(Convert.ToUInt16(Convert.ToDouble(rdr_summary["fsTotalAscent"]) / 3.2808399));
                    sess.SetTotalDescent(Convert.ToUInt16(Convert.ToDouble(rdr_summary["fsTotalDescent"]) / 3.2808399));
                    sess.SetMaxHeartRate(Convert.ToByte(Convert.ToInt32(rdr_summary["fsMaxHeartRate"])));
                    sess.SetMaxCadence(Convert.ToByte(Convert.ToInt32(rdr_summary["fsMaxCadence"])));
                    sess.SetMaxSpeed(Convert.ToByte(Convert.ToInt32(rdr_summary["fsMaxSpeed"]) / 2.23693629));

                    Dynastream.Fit.DateTime dt_start = new Dynastream.Fit.DateTime(Convert.ToDateTime(rdr_summary["fileActivityDateTime"]));
                    sess.SetStartTime(dt_start);
                    encode.Write(sess);
                }
                rdr_summary.Close();

                // load and process the archived trackpoints for file

                sql             = string.Format("select * from FileTrackpoints where idFile = {0}", _file);
                cmd.CommandText = sql;
                SQLiteDataReader rdr = cmd.ExecuteReader();
                if (rdr.HasRows)
                {
                    while (rdr.Read())
                    {
                        // TODO: need to handle `0` lng/lat coordinates so that we're not mapped
                        // as being in the middle of the atlantic ! :-)
                        RecordMesg rec             = new RecordMesg();
                        Dynastream.Fit.DateTime dt = new Dynastream.Fit.DateTime(System.DateTime.Parse((string)rdr["tpTime"]));
                        rec.SetTimestamp(dt);
                        rec.SetDistance((float)Convert.ToDouble(rdr["tpDistance"]));
                        rec.SetHeartRate(Convert.ToByte(Convert.ToInt32(rdr["tpHeart"])));
                        rec.SetCadence(Convert.ToByte(Convert.ToInt32(rdr["tpCadence"])));
                        rec.SetTemperature(Convert.ToSByte(Convert.ToInt32(rdr["tpTemperature"])));
                        rec.SetAltitude((float)(Convert.ToDouble(rdr["tpAltitude"]) / 3.2808399));                         // converted back to metres from ft in db
                        rec.SetPositionLong((int)GeoMath.degrees_to_semicircle(Convert.ToDouble(rdr["tpLongitude"])));
                        rec.SetPositionLat((int)GeoMath.degrees_to_semicircle(Convert.ToDouble(rdr["tpLatitude"])));
                        rec.SetSpeed((float)Convert.ToDouble(rdr["tpSpeed"]));
                        encode.Write(rec);
                    }
                }

                encode.Close();
                fitDest.Close();

                MessageBox.Show("File Saved Successfully");

                System.Diagnostics.Process.Start(saveFileDlg.FileName);
            }
            else
            {
            }
        }