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); }
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}"); }
protected override Tuple <string, ICollection <Mesg> > Convert(Workout workout, WorkoutSamples workoutSamples) { // MESSAGE ORDER MATTERS var messages = new List <Mesg>(); var startTime = GetStartTimeUtc(workout); var endTime = GetEndTimeUtc(workout); var title = WorkoutHelper.GetTitle(workout); var sport = GetGarminSport(workout); var subSport = GetGarminSubSport(workout); if (sport == Sport.Invalid) { Log.Warning("Unsupported Sport Type - Skipping {@Sport}", workout.Fitness_Discipline); return(new Tuple <string, ICollection <Mesg> >(string.Empty, null)); } var fileIdMesg = new FileIdMesg(); fileIdMesg.SetSerialNumber(_serialNumber); fileIdMesg.SetTimeCreated(startTime); fileIdMesg.SetManufacturer(_manufacturerId); fileIdMesg.SetProduct(_productId); fileIdMesg.SetType(Dynastream.Fit.File.Activity); messages.Add(fileIdMesg); var eventMesg = new EventMesg(); eventMesg.SetTimestamp(startTime); eventMesg.SetData(0); eventMesg.SetEvent(Event.Timer); eventMesg.SetEventType(EventType.Start); eventMesg.SetEventGroup(0); messages.Add(eventMesg); var deviceInfoMesg = new DeviceInfoMesg(); deviceInfoMesg.SetTimestamp(startTime); deviceInfoMesg.SetSerialNumber(_serialNumber); deviceInfoMesg.SetManufacturer(_manufacturerId); deviceInfoMesg.SetProduct(_productId); deviceInfoMesg.SetSoftwareVersion(_softwareVersion); deviceInfoMesg.SetDeviceIndex(0); deviceInfoMesg.SetSourceType(SourceType.Local); deviceInfoMesg.SetProductName("PelotonToGarmin"); // Max 20 Chars messages.Add(deviceInfoMesg); var userProfileMesg = new UserProfileMesg(); userProfileMesg.SetPowerSetting(DisplayPower.PercentFtp); messages.Add(userProfileMesg); var sportMesg = new SportMesg(); sportMesg.SetSport(sport); sportMesg.SetSubSport(subSport); messages.Add(sportMesg); var zoneTargetMesg = new ZonesTargetMesg(); zoneTargetMesg.SetFunctionalThresholdPower((ushort)workout.Ftp_Info.Ftp); zoneTargetMesg.SetPwrCalcType(PwrZoneCalc.PercentFtp); var maxHr = GetUserMaxHeartRate(workoutSamples); if (maxHr is object) { zoneTargetMesg.SetMaxHeartRate(maxHr.Value); zoneTargetMesg.SetHrCalcType(HrZoneCalc.PercentMaxHr); } messages.Add(zoneTargetMesg); var trainingMesg = new TrainingFileMesg(); trainingMesg.SetTimestamp(startTime); trainingMesg.SetTimeCreated(startTime); trainingMesg.SetSerialNumber(_serialNumber); trainingMesg.SetManufacturer(_manufacturerId); trainingMesg.SetProduct(_productId); trainingMesg.SetType(Dynastream.Fit.File.Workout); messages.Add(trainingMesg); AddMetrics(messages, workoutSamples, startTime); var workoutSteps = new List <WorkoutStepMesg>(); var laps = new List <LapMesg>(); if (workoutSamples.Target_Performance_Metrics?.Target_Graph_Metrics?.FirstOrDefault(w => w.Type == "cadence")?.Graph_Data is object) { var stepsAndLaps = GetWorkoutStepsAndLaps(workoutSamples, startTime, sport, subSport); workoutSteps = stepsAndLaps.Values.Select(v => v.Item1).ToList(); laps = stepsAndLaps.Values.Select(v => v.Item2).ToList(); } else { laps = GetWorkoutLaps(workoutSamples, startTime, sport, subSport).ToList(); } var workoutMesg = new WorkoutMesg(); workoutMesg.SetWktName(title.Replace(_spaceSeparator, " ")); workoutMesg.SetCapabilities(32); workoutMesg.SetSport(sport); workoutMesg.SetSubSport(subSport); workoutMesg.SetNumValidSteps((ushort)workoutSteps.Count); messages.Add(workoutMesg); // add steps in order foreach (var step in workoutSteps) { messages.Add(step); } // Add laps in order foreach (var lap in laps) { messages.Add(lap); } messages.Add(GetSessionMesg(workout, workoutSamples, startTime, endTime, (ushort)laps.Count)); var activityMesg = new ActivityMesg(); activityMesg.SetTimestamp(endTime); activityMesg.SetTotalTimerTime(workoutSamples.Duration); activityMesg.SetNumSessions(1); activityMesg.SetType(Activity.Manual); activityMesg.SetEvent(Event.Activity); activityMesg.SetEventType(EventType.Stop); var timezoneOffset = (int)TimeZoneInfo.Local.GetUtcOffset(base.GetEndTimeUtc(workout)).TotalSeconds; var timeStamp = (uint)((int)endTime.GetTimeStamp() + timezoneOffset); activityMesg.SetLocalTimestamp(timeStamp); messages.Add(activityMesg); return(new Tuple <string, ICollection <Mesg> >(title, messages)); }