public static void ExportSchedulesFITFile(Stream exportStream, MemoryStream dataStream) { MemoryStream tempDataStream = new MemoryStream(); // Reserve size for header tempDataStream.Write(new Byte[12], 0, 12); // File id message FITMessage fileIdMessage = new FITMessage(FITGlobalMessageIds.FileId); FITMessageField fileType = new FITMessageField((Byte)FITFileIdFieldsIds.FileType); FITMessageField manufacturerId = new FITMessageField((Byte)FITFileIdFieldsIds.ManufacturerId); FITMessageField productId = new FITMessageField((Byte)FITFileIdFieldsIds.ProductId); FITMessageField serialNumber = new FITMessageField((Byte)FITFileIdFieldsIds.SerialNumber); FITMessageField exportDate = new FITMessageField((Byte)FITFileIdFieldsIds.ExportDate); FITMessageField number = new FITMessageField((Byte)FITFileIdFieldsIds.Number); manufacturerId.SetUInt16(1); fileType.SetEnum((Byte)FITFileTypes.Schedules); // Invalid fields productId.SetUInt16(0xFFFF); serialNumber.SetUInt32z(0); exportDate.SetUInt32(0xFFFFFFFF); number.SetUInt16(0xFFFF); fileIdMessage.AddField(serialNumber); fileIdMessage.AddField(exportDate); fileIdMessage.AddField(manufacturerId); fileIdMessage.AddField(productId); fileIdMessage.AddField(number); fileIdMessage.AddField(fileType); fileIdMessage.Serialize(tempDataStream); // Write all passed in data to output stream tempDataStream.Write(dataStream.GetBuffer(), 0, (int)dataStream.Length); // Write FIT header at the start of the stream GarminFitnessByteRange headerSize = new GarminFitnessByteRange(12); GarminFitnessByteRange protocolVersion = new GarminFitnessByteRange((Byte)((FITConstants.FITProtocolMajorVersion << 4) | FITConstants.FITProtocolMinorVersion)); GarminFitnessUInt16Range profileVersion = new GarminFitnessUInt16Range((UInt16)((FITConstants.FITProfileMajorVersion * FITConstants.FITProfileMajorVersionMultiplier) + FITConstants.FITProfileMinorVersion)); GarminFitnessInt32Range dataSize = new GarminFitnessInt32Range(0); tempDataStream.Seek(0, SeekOrigin.Begin); dataSize.Value = (int)tempDataStream.Length - 12; headerSize.Serialize(tempDataStream); protocolVersion.Serialize(tempDataStream); profileVersion.Serialize(tempDataStream); dataSize.Serialize(tempDataStream); tempDataStream.Write(Encoding.UTF8.GetBytes(FITConstants.FITFileDescriptor), 0, 4); // Write CRC GarminFitnessUInt16Range crc = new GarminFitnessUInt16Range(FITUtils.ComputeStreamCRC(tempDataStream)); tempDataStream.Seek(0, SeekOrigin.End); crc.Serialize(tempDataStream); // Write all data to output stream exportStream.Write(tempDataStream.GetBuffer(), 0, (int)tempDataStream.Length); }
public override void FillFITStepMessage(FITMessage message) { FITMessageField durationType = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.DurationType); FITMessageField durationValue = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.DurationValue); durationType.SetEnum((Byte)FITWorkoutStepDurationTypes.Calories); durationValue.SetUInt32((UInt32)CaloriesToSpend); }
public override void FillFITStepMessage(FITMessage message) { FITMessageField durationType = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.DurationType); FITMessageField repeatCount = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetValue); durationType.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatCount); repeatCount.SetUInt32((UInt32)RepetitionCount); }
public override void FillFITStepMessage(FITMessage message) { FITMessageField powerZone = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetValue); FITMessageField minPower = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); FITMessageField maxPower = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); powerZone.SetUInt32(0); if (IsPercentFTP) { minPower.SetUInt32((UInt32)MinPower); maxPower.SetUInt32((UInt32)MaxPower); } else { minPower.SetUInt32((UInt32)MinPower + 1000); maxPower.SetUInt32((UInt32)MaxPower + 1000); } }
public override void FillFITStepMessage(FITMessage message) { FITMessageField HRZone = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetValue); FITMessageField minHR = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); FITMessageField maxHR = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); bool exportAsPercentMax = Options.Instance.ExportSportTracksHeartRateAsPercentMax; float lastMaxHR = GarminProfileManager.Instance.UserProfile.GetProfileForActivity(Options.Instance.GetGarminCategory(BaseTarget.ParentStep.ParentWorkout.Category)).MaximumHeartRate; HRZone.SetUInt32(0); if (float.IsNaN(lastMaxHR)) { exportAsPercentMax = false; } if (exportAsPercentMax) { float baseMultiplier = Constants.MaxHRInPercentMax / lastMaxHR; minHR.SetUInt32((UInt32)Math.Max(Constants.MinHRInPercentMax, Math.Round(Zone.Low * baseMultiplier, 0, MidpointRounding.AwayFromZero))); maxHR.SetUInt32((UInt32)Math.Min(Constants.MaxHRInPercentMax, Math.Round(Zone.High * baseMultiplier, 0, MidpointRounding.AwayFromZero))); } else { minHR.SetUInt32((UInt32)Utils.Clamp(Zone.Low, Constants.MinHRInBPM, Constants.MaxHRInBPM) + 100); maxHR.SetUInt32((UInt32)Utils.Clamp(Zone.High, Constants.MinHRInBPM, Constants.MaxHRInBPM) + 100); } }
public void FillFITMessage(FITMessage workoutMessage) { FITMessageField capabilities = new FITMessageField((Byte)FITWorkoutFieldIds.Capabilities); FITMessageField sportType = new FITMessageField((Byte)FITWorkoutFieldIds.SportType); FITMessageField numValidSteps = new FITMessageField((Byte)FITWorkoutFieldIds.NumSteps); FITMessageField unknown = new FITMessageField((Byte)FITWorkoutFieldIds.Unknown); FITMessageField workoutName = new FITMessageField((Byte)FITWorkoutFieldIds.WorkoutName); sportType.SetEnum((Byte)Options.Instance.GetFITSport(Category)); capabilities.SetUInt32z(32); numValidSteps.SetUInt16(StepCount); unknown.SetUInt16(0xFFFF); workoutMessage.AddField(capabilities); if (!String.IsNullOrEmpty(Name)) { workoutName.SetString(Name, (Byte)(Constants.MaxNameLength + 1)); workoutMessage.AddField(workoutName); } workoutMessage.AddField(numValidSteps); workoutMessage.AddField(unknown); workoutMessage.AddField(sportType); }
public virtual void SerializeToFIT(Stream stream) { Debug.Assert(GetSplitPartsCount() == 1); FITMessage workoutMessage = new FITMessage(FITGlobalMessageIds.Workout); FillFITMessage(workoutMessage); workoutMessage.Serialize(stream); bool serializeDefinition = true; foreach (IStep step in Steps) { step.SerializeToFIT(stream, serializeDefinition); serializeDefinition = false; } }
public override void DeserializeFromFIT(FITMessage stepMessage) { Debug.Assert(false); }
public override void FillFITStepMessage(FITMessage message) { FITMessageField powerZone = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetValue); FITMessageField minPower = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); FITMessageField maxPower = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); bool exportAsPercentFTP = Options.Instance.ExportSportTracksPowerAsPercentFTP; GarminCategories category = Options.Instance.GetGarminCategory(BaseTarget.ParentStep.ParentWorkout.Category); float lastFTP = 0; if (category == GarminCategories.Biking) { GarminBikingActivityProfile profile = (GarminBikingActivityProfile)GarminProfileManager.Instance.UserProfile.GetProfileForActivity(category); lastFTP = profile.FTP; } else { exportAsPercentFTP = false; } powerZone.SetUInt32(0); if (exportAsPercentFTP) { float baseMultiplier = 100.0f / lastFTP; minPower.SetUInt32((UInt32)Utils.Clamp(Math.Round(Zone.Low * baseMultiplier, 0, MidpointRounding.AwayFromZero), Constants.MinPowerInPercentFTP, Constants.MaxPowerInPercentFTP)); maxPower.SetUInt32((UInt32)Utils.Clamp(Math.Round(Zone.High * baseMultiplier, 0, MidpointRounding.AwayFromZero), Constants.MinPowerInPercentFTP, Constants.MaxPowerInPercentFTP)); } else { minPower.SetUInt32((UInt32)Utils.Clamp(Zone.Low, Constants.MinPowerInWatts, Constants.MaxPowerWorkoutInWatts) + 1000); maxPower.SetUInt32((UInt32)Utils.Clamp(Zone.High, Constants.MinPowerInWatts, Constants.MaxPowerWorkoutInWatts) + 1000); } }
public void TestFITScheduleDeserialization() { FITMessage serializedMessage = new FITMessage(FITGlobalMessageIds.WorkoutSchedules); FITMessageField dateField = new FITMessageField((Byte)FITScheduleFieldIds.ScheduledDate); DateTime referenceDate = new DateTime(1989, 12, 31); DateTime resultDate; serializedMessage.AddField(dateField); DateTime currentDate = DateTime.Today; dateField.SetUInt32((UInt32)(currentDate - referenceDate).TotalSeconds); resultDate = WorkoutImporter.ImportWorkoutScheduleMessage(serializedMessage); Assert.AreEqual(currentDate, resultDate, "Deserialized date invalid for FIT format"); currentDate = currentDate.AddDays(1); dateField.SetUInt32((UInt32)(currentDate - referenceDate).TotalSeconds); resultDate = WorkoutImporter.ImportWorkoutScheduleMessage(serializedMessage); Assert.AreEqual(currentDate, resultDate, "Deserialized date invalid for FIT format"); dateField.SetUInt32(315576000); resultDate = WorkoutImporter.ImportWorkoutScheduleMessage(serializedMessage); Assert.AreEqual(new DateTime(1999, 12, 31, 12, 0, 0), resultDate, "Deserialized date invalid for FIT format"); // New Zealand time (UST+12H) is a case where we had problems because the offset changes the day String currentZoneName = Time.CurrentTimeZone.standardName; bool res = Time.SetTimeZone("New Zealand Standard Time"); dateField.SetUInt32(315576000); resultDate = WorkoutImporter.ImportWorkoutScheduleMessage(serializedMessage); res = Time.SetTimeZone(currentZoneName); Assert.AreEqual(new DateTime(1999, 12, 31, 12, 0, 0), resultDate, "Deserialized date invalid for FIT format"); }
public override void FillFITStepMessage(FITMessage message) { FITMessageField targetType = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetType); targetType.SetEnum((Byte)FITWorkoutStepTargetTypes.Cadence); ConcreteTarget.FillFITStepMessage(message); }
public void TestFITSerialization() { Workout placeholderWorkout = new Workout("Test", PluginMain.GetApplication().Logbook.ActivityCategories[0]); RegularStep placeholderStep = new RegularStep(placeholderWorkout); ILogbook logbook = PluginMain.GetApplication().Logbook; bool exportHRAsMax = Options.Instance.ExportSportTracksHeartRateAsPercentMax; bool exportPowerAsFTP = Options.Instance.ExportSportTracksPowerAsPercentFTP; FITMessage serializedMessage = new FITMessage(FITGlobalMessageIds.WorkoutStep); FITMessageField messageField; // This is required to determine the step's id in the workout during serialization placeholderWorkout.Steps.AddStepToRoot(placeholderStep); // No target NullTarget noTarget = new NullTarget(placeholderStep); noTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid no target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.NoTarget, messageField.GetEnum(), "Invalid target type in field for target"); serializedMessage.Clear(); // Cadence targets BaseCadenceTarget cadenceTarget = new BaseCadenceTarget(placeholderStep); // Cadence range cadenceTarget.ConcreteTarget = new CadenceRangeTarget(80, 90, cadenceTarget); cadenceTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Cadence, messageField.GetEnum(), "Invalid target type in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(80, messageField.GetUInt32(), "Invalid lower value in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(90, messageField.GetUInt32(), "Invalid upper value in field for CadenceRange target"); serializedMessage.Clear(); cadenceTarget.ConcreteTarget = new CadenceRangeTarget(60, 120, cadenceTarget); cadenceTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Cadence, messageField.GetEnum(), "Invalid target type in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(60, messageField.GetUInt32(), "Invalid lower value in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(120, messageField.GetUInt32(), "Invalid upper value in field for CadenceRange target"); serializedMessage.Clear(); // Cadence ST zone cadenceTarget.ConcreteTarget = new CadenceZoneSTTarget(logbook.CadenceZones[0].Zones[2], cadenceTarget); cadenceTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid CadenceST target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Cadence, messageField.GetEnum(), "Invalid target type in field for CadenceST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(70, messageField.GetUInt32(), "Invalid lower value in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(85, messageField.GetUInt32(), "Invalid upper value in field for CadenceRange target"); serializedMessage.Clear(); cadenceTarget.ConcreteTarget = new CadenceZoneSTTarget(logbook.CadenceZones[0].Zones[4], cadenceTarget); cadenceTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid CadenceST target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Cadence, messageField.GetEnum(), "Invalid target type in field for CadenceST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(100, messageField.GetUInt32(), "Invalid lower value in field for CadenceRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid CadenceRange target FIT serialization"); Assert.AreEqual(120, messageField.GetUInt32(), "Invalid upper value in field for CadenceRange target"); serializedMessage.Clear(); // Speed targets BaseSpeedTarget speedTarget = new BaseSpeedTarget(placeholderStep); // Speed range placeholderWorkout.Category = logbook.ActivityCategories[0].SubCategories[3]; speedTarget.ConcreteTarget = new SpeedRangeTarget(20, 30, Length.Units.Kilometer, Speed.Units.Speed, speedTarget); speedTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Speed, messageField.GetEnum(), "Invalid target type in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(5555, messageField.GetUInt32(), "Invalid lower value in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(8333, messageField.GetUInt32(), "Invalid upper value in field for SpeedRange target"); serializedMessage.Clear(); speedTarget.ConcreteTarget = new SpeedRangeTarget(20, 30, Length.Units.Mile, Speed.Units.Speed, speedTarget); speedTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Speed, messageField.GetEnum(), "Invalid target type in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(8940, messageField.GetUInt32(), "Invalid lower value in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(13411, messageField.GetUInt32(), "Invalid upper value in field for SpeedRange target"); serializedMessage.Clear(); // Pace shouldn't change the values saved placeholderWorkout.Category = logbook.ActivityCategories[0].SubCategories[2]; speedTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid SpeedRange pace target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Speed, messageField.GetEnum(), "Invalid target type in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid SpeedRange pace target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for SpeedRange pace target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid SpeedRange pace target FIT serialization"); Assert.AreEqual(8940, messageField.GetUInt32(), "Invalid lower value in field for SpeedRange pace target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid SpeedRange pace target FIT serialization"); Assert.AreEqual(13411, messageField.GetUInt32(), "Invalid upper value in field for SpeedRange pace target"); serializedMessage.Clear(); // Speed Garmin zone speedTarget.ConcreteTarget = new SpeedZoneGTCTarget(1, speedTarget); speedTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid SpeedGTC target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Speed, messageField.GetEnum(), "Invalid target type in field for SpeedGTC target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid SpeedGTC target FIT serialization"); Assert.AreEqual(1, messageField.GetUInt32(), "Invalid zone value in field for SpeedGTC target"); serializedMessage.Clear(); speedTarget.ConcreteTarget = new SpeedZoneGTCTarget(3, speedTarget); speedTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid SpeedGTC target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Speed, messageField.GetEnum(), "Invalid target type in field for SpeedGTC target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid SpeedGTC target FIT serialization"); Assert.AreEqual(3, messageField.GetUInt32(), "Invalid zone value in field for SpeedGTC target"); serializedMessage.Clear(); // Speed ST zone Options.Instance.ExportSportTracksHeartRateAsPercentMax = false; placeholderWorkout.Category = logbook.ActivityCategories[0].SubCategories[3]; speedTarget.ConcreteTarget = new SpeedZoneSTTarget(logbook.SpeedZones[0].Zones[1], speedTarget); speedTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid SpeedST target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Speed, messageField.GetEnum(), "Invalid target type in field for target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(2777, messageField.GetUInt32(), "Invalid lower value in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(5555, messageField.GetUInt32(), "Invalid upper value in field for SpeedRange target"); serializedMessage.Clear(); speedTarget.ConcreteTarget = new SpeedZoneSTTarget(logbook.SpeedZones[0].Zones[2], speedTarget); speedTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid SpeedST target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Speed, messageField.GetEnum(), "Invalid target type in field for target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(5555, messageField.GetUInt32(), "Invalid lower value in field for SpeedRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid SpeedRange target FIT serialization"); Assert.AreEqual(8333, messageField.GetUInt32(), "Invalid upper value in field for SpeedRange target"); serializedMessage.Clear(); // Pace shouldn't change the values saved placeholderWorkout.Category = logbook.ActivityCategories[0].SubCategories[2]; speedTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid SpeedST target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Speed, messageField.GetEnum(), "Invalid target type in field for target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid SpeedRange pace target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for SpeedRange pace target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid SpeedRange pace target FIT serialization"); Assert.AreEqual(5555, messageField.GetUInt32(), "Invalid lower value in field for SpeedRange pace target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid SpeedRange pace target FIT serialization"); Assert.AreEqual(8333, messageField.GetUInt32(), "Invalid upper value in field for SpeedRange pace target"); serializedMessage.Clear(); // Heart rate targets BaseHeartRateTarget hrTarget = new BaseHeartRateTarget(placeholderStep); // HR range hrTarget.ConcreteTarget = new HeartRateRangeTarget(130, 170, false, hrTarget); hrTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid HRRange target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.HeartRate, messageField.GetEnum(), "Invalid target type in field for HRRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid HRRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for HRRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid HRRange target FIT serialization"); Assert.AreEqual(230, messageField.GetUInt32(), "Invalid lower value in field for HRRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid HRRange target FIT serialization"); Assert.AreEqual(270, messageField.GetUInt32(), "Invalid upper value in field for HRRange target"); serializedMessage.Clear(); hrTarget.ConcreteTarget = new HeartRateRangeTarget(100, 190, false, hrTarget); hrTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid HRRange target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.HeartRate, messageField.GetEnum(), "Invalid target type in field for HRRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid HRRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for HRRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid HRRange target FIT serialization"); Assert.AreEqual(200, messageField.GetUInt32(), "Invalid lower value in field for HRRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid HRRange target FIT serialization"); Assert.AreEqual(290, messageField.GetUInt32(), "Invalid upper value in field for HRRange target"); serializedMessage.Clear(); hrTarget.ConcreteTarget = new HeartRateRangeTarget(50, 70, true, hrTarget); hrTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid HRRange %Max target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.HeartRate, messageField.GetEnum(), "Invalid target type in field for HRRange %Max target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid HRRange %Max target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for HRRange %Max target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid HRRange %Max target FIT serialization"); Assert.AreEqual(50, messageField.GetUInt32(), "Invalid lower value in field for HRRange %Max target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid HRRange %Max target FIT serialization"); Assert.AreEqual(70, messageField.GetUInt32(), "Invalid upper value in field for HRRange %Max target"); serializedMessage.Clear(); // HR Garmin zone hrTarget.ConcreteTarget = new HeartRateZoneGTCTarget(1, hrTarget); hrTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid HRGTC target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.HeartRate, messageField.GetEnum(), "Invalid target type in field for HRGTC target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid HRGTC target FIT serialization"); Assert.AreEqual(1, messageField.GetUInt32(), "Invalid zone value in field for HRGTC target"); serializedMessage.Clear(); hrTarget.ConcreteTarget = new HeartRateZoneGTCTarget(3, hrTarget); hrTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid HRGTC target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.HeartRate, messageField.GetEnum(), "Invalid target type in field for HRGTC target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid HRGTC target FIT serialization"); Assert.AreEqual(3, messageField.GetUInt32(), "Invalid zone value in field for HRGTC target"); serializedMessage.Clear(); // HR ST zone Options.Instance.ExportSportTracksHeartRateAsPercentMax = false; hrTarget.ConcreteTarget = new HeartRateZoneSTTarget(logbook.HeartRateZones[0].Zones[2], hrTarget); hrTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid HRST target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.HeartRate, messageField.GetEnum(), "Invalid target type in field for HRST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid HRST target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for HRST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid HRST target FIT serialization"); Assert.AreEqual(240, messageField.GetUInt32(), "Invalid lower value in field for HRST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid HRST target FIT serialization"); Assert.AreEqual(260, messageField.GetUInt32(), "Invalid upper value in field for HRST target"); serializedMessage.Clear(); hrTarget.ConcreteTarget = new HeartRateZoneSTTarget(logbook.HeartRateZones[0].Zones[4], hrTarget); hrTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid HRST target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.HeartRate, messageField.GetEnum(), "Invalid target type in field for HRST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid HRST target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for HRST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid HRST target FIT serialization"); Assert.AreEqual(280, messageField.GetUInt32(), "Invalid lower value in field for HRST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid HRST target FIT serialization"); Assert.AreEqual(340, messageField.GetUInt32(), "Invalid upper value in field for HRST target"); serializedMessage.Clear(); placeholderWorkout.Category = logbook.ActivityCategories[0].SubCategories[1]; Options.Instance.ExportSportTracksHeartRateAsPercentMax = true; hrTarget.ConcreteTarget = new HeartRateZoneSTTarget(logbook.HeartRateZones[1].Zones[2], hrTarget); hrTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid HRST %Max target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.HeartRate, messageField.GetEnum(), "Invalid target type in field for HRST %Max target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid HRST %Max target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for HRST %Max target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid HRST %Max target FIT serialization"); Assert.AreEqual(68, messageField.GetUInt32(), "Invalid lower value in field for HRST %Max target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid HRST %Max target FIT serialization"); Assert.AreEqual(82, messageField.GetUInt32(), "Invalid upper value in field for HRST %Max target"); serializedMessage.Clear(); // Power targets BasePowerTarget powerTarget = new BasePowerTarget(placeholderStep); // Power range powerTarget.ConcreteTarget = new PowerRangeTarget(150, 200, false, powerTarget); powerTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid PowerRange target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Power, messageField.GetEnum(), "Invalid target type in field for PowerRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid PowerRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for PowerRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid PowerRange target FIT serialization"); Assert.AreEqual(1150, messageField.GetUInt32(), "Invalid lower value in field for PowerRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid PowerRange target FIT serialization"); Assert.AreEqual(1200, messageField.GetUInt32(), "Invalid upper value in field for PowerRange target"); serializedMessage.Clear(); powerTarget.ConcreteTarget = new PowerRangeTarget(300, 400, false, powerTarget); powerTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid PowerRange target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Power, messageField.GetEnum(), "Invalid target type in field for target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid PowerRange target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for PowerRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid PowerRange target FIT serialization"); Assert.AreEqual(1300, messageField.GetUInt32(), "Invalid lower value in field for PowerRange target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid PowerRange target FIT serialization"); Assert.AreEqual(1400, messageField.GetUInt32(), "Invalid upper value in field for PowerRange target"); serializedMessage.Clear(); powerTarget.ConcreteTarget = new PowerRangeTarget(67, 80, true, powerTarget); powerTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid PowerRange %FTP target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Power, messageField.GetEnum(), "Invalid target type in field for PowerRange %FTP target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid PowerRange %FTP target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for PowerRange %FTP target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid PowerRange %FTP target FIT serialization"); Assert.AreEqual(67, messageField.GetUInt32(), "Invalid lower value in field for PowerRange %FTP target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid PowerRange %FTP target FIT serialization"); Assert.AreEqual(80, messageField.GetUInt32(), "Invalid upper value in field for PowerRange %FTP target"); serializedMessage.Clear(); // Power Garmin zone powerTarget.ConcreteTarget = new PowerZoneGTCTarget(1, powerTarget); powerTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid PowerGTC target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Power, messageField.GetEnum(), "Invalid target type in field for PowerGTC target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid PowerGTC target FIT serialization"); Assert.AreEqual(1, messageField.GetUInt32(), "Invalid zone value in field for PowerGTC target"); serializedMessage.Clear(); powerTarget.ConcreteTarget = new PowerZoneGTCTarget(3, powerTarget); powerTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid PowerGTC target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Power, messageField.GetEnum(), "Invalid target type in field for target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid PowerGTC target FIT serialization"); Assert.AreEqual(3, messageField.GetUInt32(), "Invalid zone value in field for PowerGTC target"); serializedMessage.Clear(); // Power ST zone placeholderWorkout.Category = logbook.ActivityCategories[0].SubCategories[4]; Options.Instance.ExportSportTracksPowerAsPercentFTP = false; powerTarget.ConcreteTarget = new PowerZoneSTTarget(logbook.PowerZones[0].Zones[1], powerTarget); powerTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid PowerST target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Power, messageField.GetEnum(), "Invalid target type in field for PowerST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid PowerST target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for PowerST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid PowerST target FIT serialization"); Assert.AreEqual(1150, messageField.GetUInt32(), "Invalid lower value in field for PowerST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid PowerSTFTP target FIT serialization"); Assert.AreEqual(1200, messageField.GetUInt32(), "Invalid upper value in field for PowerST target"); serializedMessage.Clear(); powerTarget.ConcreteTarget = new PowerZoneSTTarget(logbook.PowerZones[0].Zones[3], powerTarget); powerTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid PowerST target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Power, messageField.GetEnum(), "Invalid target type in field for PowerST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid PowerST target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for PowerST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid PowerST target FIT serialization"); Assert.AreEqual(1300, messageField.GetUInt32(), "Invalid lower value in field for PowerST target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid PowerSTFTP target FIT serialization"); Assert.AreEqual(1400, messageField.GetUInt32(), "Invalid upper value in field for PowerST target"); serializedMessage.Clear(); Options.Instance.ExportSportTracksPowerAsPercentFTP = true; powerTarget.FillFITStepMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetType); Assert.IsNotNull(messageField, "Invalid PowerST %FTP target FIT serialization"); Assert.AreEqual((Byte)FITWorkoutStepTargetTypes.Power, messageField.GetEnum(), "Invalid target type in field for PowerST %FTP target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetValue); Assert.IsNotNull(messageField, "Invalid PowerST %FTP target FIT serialization"); Assert.AreEqual(0, messageField.GetUInt32(), "Invalid zone value in field for PowerST %FTP target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); Assert.IsNotNull(messageField, "Invalid PowerST %FTP target FIT serialization"); Assert.AreEqual(120, messageField.GetUInt32(), "Invalid lower value in field for PowerST %FTP target"); messageField = serializedMessage.GetField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); Assert.IsNotNull(messageField, "Invalid PowerST %FTP target FIT serialization"); Assert.AreEqual(160, messageField.GetUInt32(), "Invalid upper value in field for PowerST %FTP target"); serializedMessage.Clear(); // Make sure to reset options to previous values Options.Instance.ExportSportTracksHeartRateAsPercentMax = exportHRAsMax; Options.Instance.ExportSportTracksPowerAsPercentFTP = exportPowerAsFTP; }
public void TestFITDeserialization() { ILogbook logbook = PluginMain.GetApplication().Logbook; Workout placeholderWorkout = null; FITMessage serializedMessage = new FITMessage(FITGlobalMessageIds.Workout); FITMessageField nameField = new FITMessageField((Byte)FITWorkoutFieldIds.WorkoutName); FITMessageField numStepsField = new FITMessageField((Byte)FITWorkoutFieldIds.NumSteps); FITMessageField categoryField = new FITMessageField((Byte)FITWorkoutFieldIds.SportType); try { placeholderWorkout = WorkoutImporter.ImportWorkoutFromMessage(serializedMessage, logbook.ActivityCategories[0]); Assert.Fail("Workout without name was FIT deserialized"); } catch (FITParserException) { } nameField.SetString(String.Empty); serializedMessage.AddField(nameField); try { placeholderWorkout = WorkoutImporter.ImportWorkoutFromMessage(serializedMessage, logbook.ActivityCategories[0]); Assert.Fail("Workout without step count was FIT deserialized"); } catch (FITParserException) { } numStepsField.SetUInt16(0); serializedMessage.AddField(numStepsField); // Name nameField.SetString("TestName"); placeholderWorkout = WorkoutImporter.ImportWorkoutFromMessage(serializedMessage, logbook.ActivityCategories[0]); Assert.AreEqual("TestName", placeholderWorkout.Name, "Workout name not properly FIT deserialized"); GarminWorkoutManager.Instance.RemoveWorkout(placeholderWorkout); nameField.SetString("Workout2"); placeholderWorkout = WorkoutImporter.ImportWorkoutFromMessage(serializedMessage, logbook.ActivityCategories[0]); Assert.AreEqual("Workout2", placeholderWorkout.Name, "Workout name not properly FIT deserialized"); GarminWorkoutManager.Instance.RemoveWorkout(placeholderWorkout); // No need to test category, we ignore them in the application at this time (TODO) // Number of steps is tested in the steps list test since it requires multiple messages // Do not test steps deserialization here, it has it's own test }
public void TestFITDeserialization() { Workout placeholderWorkout = new Workout("Test", PluginMain.GetApplication().Logbook.ActivityCategories[0]); RegularStep placeholderStep = new RegularStep(placeholderWorkout); FITMessage serializedMessage = new FITMessage(FITGlobalMessageIds.WorkoutStep); FITMessageField typeField = new FITMessageField((Byte)FITWorkoutStepFieldIds.TargetType); FITMessageField valueField = new FITMessageField((Byte)FITWorkoutStepFieldIds.TargetValue); FITMessageField lowRangeField = new FITMessageField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); FITMessageField highRangeField = new FITMessageField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); ITarget loadedTarget = null; serializedMessage.AddField(typeField); // No target typeField.SetEnum((Byte)FITWorkoutStepTargetTypes.NoTarget); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(loadedTarget is NullTarget, "No target not properly FIT deserialized without value fields"); serializedMessage.AddField(valueField); serializedMessage.AddField(lowRangeField); serializedMessage.AddField(highRangeField); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(loadedTarget is NullTarget, "No target not properly FIT deserialized with unset value fields"); valueField.SetUInt32(1); lowRangeField.SetUInt32(1); highRangeField.SetUInt32(1); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(loadedTarget is NullTarget, "No target not properly FIT deserialized with value fields"); // Cadence targets BaseCadenceTarget cadenceTarget; // Cadence range CadenceRangeTarget cadenceRangeTarget; typeField.SetEnum((Byte)FITWorkoutStepTargetTypes.Cadence); valueField.SetUInt32(0); lowRangeField.SetUInt32(80); highRangeField.SetUInt32(90); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "CadenceRange target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseCadenceTarget, "CadenceRange target wasn't deserialized as proper type"); cadenceTarget = loadedTarget as BaseCadenceTarget; Assert.IsTrue(cadenceTarget.ConcreteTarget is CadenceRangeTarget, "CadenceRange target wasn't deserialized as proper concrete type"); cadenceRangeTarget = cadenceTarget.ConcreteTarget as CadenceRangeTarget; Assert.AreEqual(80, cadenceRangeTarget.MinCadence, "CadenceRange min value wasn't properly deserialized"); Assert.AreEqual(90, cadenceRangeTarget.MaxCadence, "CadenceRange max value wasn't properly deserialized"); lowRangeField.SetUInt32(60); highRangeField.SetUInt32(120); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "CadenceRange target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseCadenceTarget, "CadenceRange target wasn't deserialized as proper type"); cadenceTarget = loadedTarget as BaseCadenceTarget; Assert.IsTrue(cadenceTarget.ConcreteTarget is CadenceRangeTarget, "CadenceRange target wasn't deserialized as proper concrete type"); cadenceRangeTarget = cadenceTarget.ConcreteTarget as CadenceRangeTarget; Assert.AreEqual(60, cadenceRangeTarget.MinCadence, "CadenceRange min value wasn't properly deserialized"); Assert.AreEqual(120, cadenceRangeTarget.MaxCadence, "CadenceRange max value wasn't properly deserialized"); // Speed targets BaseSpeedTarget speedTarget; // Speed range SpeedRangeTarget speedRangeTarget; double speed; typeField.SetEnum((Byte)FITWorkoutStepTargetTypes.Speed); valueField.SetUInt32(0); lowRangeField.SetUInt32(5555); highRangeField.SetUInt32(8333); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "SpeedRange target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseSpeedTarget, "SpeedRange target wasn't deserialized as proper type"); speedTarget = loadedTarget as BaseSpeedTarget; Assert.IsTrue(speedTarget.ConcreteTarget is SpeedRangeTarget, "SpeedRange target wasn't deserialized as proper concrete type"); speedRangeTarget = speedTarget.ConcreteTarget as SpeedRangeTarget; speed = Length.Convert(speedRangeTarget.GetMinSpeedInBaseUnitsPerHour(), speedRangeTarget.BaseUnit, Length.Units.Kilometer); Assert.AreEqual(20, speed, 0.01, "SpeedRange min value wasn't properly deserialized"); speed = Length.Convert(speedRangeTarget.GetMaxSpeedInBaseUnitsPerHour(), speedRangeTarget.BaseUnit, Length.Units.Kilometer); Assert.AreEqual(30, speed, 0.01, "SpeedRange max value wasn't properly deserialized"); lowRangeField.SetUInt32(1788); highRangeField.SetUInt32(3576); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "SpeedRange target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseSpeedTarget, "SpeedRange target wasn't deserialized as proper type"); speedTarget = loadedTarget as BaseSpeedTarget; Assert.IsTrue(speedTarget.ConcreteTarget is SpeedRangeTarget, "SpeedRange target wasn't deserialized as proper concrete type"); speedRangeTarget = speedTarget.ConcreteTarget as SpeedRangeTarget; speed = Length.Convert(speedRangeTarget.GetMinSpeedInBaseUnitsPerHour(), speedRangeTarget.BaseUnit, Length.Units.Mile); Assert.AreEqual(4, speed, 0.01, "SpeedRange min value wasn't properly deserialized"); speed = Length.Convert(speedRangeTarget.GetMaxSpeedInBaseUnitsPerHour(), speedRangeTarget.BaseUnit, Length.Units.Mile); Assert.AreEqual(8, speed, 0.01, "SpeedRange max value wasn't properly deserialized"); // Speed Garmin zone SpeedZoneGTCTarget speedGTCTarget; valueField.SetUInt32(1); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "SpeedGTC target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseSpeedTarget, "SpeedGTC target wasn't deserialized as proper type"); speedTarget = loadedTarget as BaseSpeedTarget; Assert.IsTrue(speedTarget.ConcreteTarget is SpeedZoneGTCTarget, "SpeedGTC target wasn't deserialized as proper concrete type"); speedGTCTarget = speedTarget.ConcreteTarget as SpeedZoneGTCTarget; Assert.AreEqual(1, speedGTCTarget.Zone, "SpeedGTC zone value wasn't properly deserialized"); valueField.SetUInt32(3); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "SpeedGTC target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseSpeedTarget, "SpeedGTC target wasn't deserialized as proper type"); speedTarget = loadedTarget as BaseSpeedTarget; Assert.IsTrue(speedTarget.ConcreteTarget is SpeedZoneGTCTarget, "SpeedGTC target wasn't deserialized as proper concrete type"); speedGTCTarget = speedTarget.ConcreteTarget as SpeedZoneGTCTarget; Assert.AreEqual(3, speedGTCTarget.Zone, "SpeedGTC zone value wasn't properly deserialized"); // Heart rate targets BaseHeartRateTarget hrTarget; // Heart rate range HeartRateRangeTarget hrRangeTarget; typeField.SetEnum((Byte)FITWorkoutStepTargetTypes.HeartRate); valueField.SetUInt32(0); lowRangeField.SetUInt32(230); highRangeField.SetUInt32(270); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "HRRange target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseHeartRateTarget, "HRRange target wasn't deserialized as proper type"); hrTarget = loadedTarget as BaseHeartRateTarget; Assert.IsTrue(hrTarget.ConcreteTarget is HeartRateRangeTarget, "HRRange target wasn't deserialized as proper concrete type"); hrRangeTarget = hrTarget.ConcreteTarget as HeartRateRangeTarget; Assert.AreEqual(false, hrRangeTarget.IsPercentMaxHeartRate, "HRRange %Max wasn't properly deserialized"); Assert.AreEqual(130, hrRangeTarget.MinHeartRate, "HRRange min value wasn't properly deserialized"); Assert.AreEqual(170, hrRangeTarget.MaxHeartRate, "HRRange max value wasn't properly deserialized"); lowRangeField.SetUInt32(50); highRangeField.SetUInt32(70); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "HRRange target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseHeartRateTarget, "HRRange target wasn't deserialized as proper type"); hrTarget = loadedTarget as BaseHeartRateTarget; Assert.IsTrue(hrTarget.ConcreteTarget is HeartRateRangeTarget, "HRRange target wasn't deserialized as proper concrete type"); hrRangeTarget = hrTarget.ConcreteTarget as HeartRateRangeTarget; Assert.AreEqual(true, hrRangeTarget.IsPercentMaxHeartRate, "HRRange %Max wasn't properly deserialized"); Assert.AreEqual(50, hrRangeTarget.MinHeartRate, "HRRange min value wasn't properly deserialized"); Assert.AreEqual(70, hrRangeTarget.MaxHeartRate, "HRRange max value wasn't properly deserialized"); // Heart rate Garmin zone HeartRateZoneGTCTarget hrGTCTarget; valueField.SetUInt32(2); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "HRGTC target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseHeartRateTarget, "HRGTC target wasn't deserialized as proper type"); hrTarget = loadedTarget as BaseHeartRateTarget; Assert.IsTrue(hrTarget.ConcreteTarget is HeartRateZoneGTCTarget, "HRGTC target wasn't deserialized as proper concrete type"); hrGTCTarget = hrTarget.ConcreteTarget as HeartRateZoneGTCTarget; Assert.AreEqual(2, hrGTCTarget.Zone, "HRGTC zone value wasn't properly deserialized"); valueField.SetUInt32(4); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "HRGTC target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BaseHeartRateTarget, "HRGTC target wasn't deserialized as proper type"); hrTarget = loadedTarget as BaseHeartRateTarget; Assert.IsTrue(hrTarget.ConcreteTarget is HeartRateZoneGTCTarget, "HRGTC target wasn't deserialized as proper concrete type"); hrGTCTarget = hrTarget.ConcreteTarget as HeartRateZoneGTCTarget; Assert.AreEqual(4, hrGTCTarget.Zone, "HRGTC zone value wasn't properly deserialized"); // Power targets BasePowerTarget powerTarget; // Power range PowerRangeTarget powerRangeTarget; typeField.SetEnum((Byte)FITWorkoutStepTargetTypes.Power); valueField.SetUInt32(0); lowRangeField.SetUInt32(1150); highRangeField.SetUInt32(1200); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "PowerRange target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BasePowerTarget, "PowerRange target wasn't deserialized as proper type"); powerTarget = loadedTarget as BasePowerTarget; Assert.IsTrue(powerTarget.ConcreteTarget is PowerRangeTarget, "PowerRange target wasn't deserialized as proper concrete type"); powerRangeTarget = powerTarget.ConcreteTarget as PowerRangeTarget; Assert.AreEqual(false, powerRangeTarget.IsPercentFTP, "PowerRange %FTP wasn't properly deserialized"); Assert.AreEqual(150, powerRangeTarget.MinPower, "PowerRange min value wasn't properly deserialized"); Assert.AreEqual(200, powerRangeTarget.MaxPower, "PowerRange max value wasn't properly deserialized"); lowRangeField.SetUInt32(67); highRangeField.SetUInt32(200); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "PowerRange target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BasePowerTarget, "PowerRange target wasn't deserialized as proper type"); powerTarget = loadedTarget as BasePowerTarget; Assert.IsTrue(powerTarget.ConcreteTarget is PowerRangeTarget, "PowerRange target wasn't deserialized as proper concrete type"); powerRangeTarget = powerTarget.ConcreteTarget as PowerRangeTarget; Assert.AreEqual(true, powerRangeTarget.IsPercentFTP, "PowerRange %FTP wasn't properly deserialized"); Assert.AreEqual(67, powerRangeTarget.MinPower, "PowerRange min value wasn't properly deserialized"); Assert.AreEqual(200, powerRangeTarget.MaxPower, "PowerRange max value wasn't properly deserialized"); // Power Garmin zone PowerZoneGTCTarget powerGTCTarget; valueField.SetUInt32(1); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "PowerGTC target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BasePowerTarget, "PowerGTC target wasn't deserialized as proper type"); powerTarget = loadedTarget as BasePowerTarget; Assert.IsTrue(powerTarget.ConcreteTarget is PowerZoneGTCTarget, "PowerGTC target wasn't deserialized as proper concrete type"); powerGTCTarget = powerTarget.ConcreteTarget as PowerZoneGTCTarget; Assert.AreEqual(1, powerGTCTarget.Zone, "PowerGTC zone value wasn't properly deserialized"); valueField.SetUInt32(7); loadedTarget = TargetFactory.Create(serializedMessage, placeholderStep); Assert.IsNotNull(loadedTarget, "PowerGTC target wasn't properly deserialized"); Assert.IsTrue(loadedTarget is BasePowerTarget, "PowerGTC target wasn't deserialized as proper type"); powerTarget = loadedTarget as BasePowerTarget; Assert.IsTrue(powerTarget.ConcreteTarget is PowerZoneGTCTarget, "PowerGTC target wasn't deserialized as proper concrete type"); powerGTCTarget = powerTarget.ConcreteTarget as PowerZoneGTCTarget; Assert.AreEqual(7, powerGTCTarget.Zone, "PowerGTC zone value wasn't properly deserialized"); }
public override void FillFITStepMessage(FITMessage message) { FITMessageField speedZone = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetValue); FITMessageField minSpeed = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetCustomValueLow); FITMessageField maxSpeed = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetCustomValueHigh); speedZone.SetUInt32(0); minSpeed.SetUInt32((UInt32)(MinMetersPerSecond * 1000)); maxSpeed.SetUInt32((UInt32)(MaxMetersPerSecond * 1000)); }
public override void FillFITStepMessage(FITMessage message) { Debug.Assert(false); }
public static void ExportWorkoutToFIT(IWorkout workout, Stream exportStream, bool updateExportDate) { MemoryStream dataStream = new MemoryStream(); // Reserve size for header dataStream.Write(new Byte[12], 0, 12); // File id message FITMessage fileIdMessage = new FITMessage(FITGlobalMessageIds.FileId); FITMessageField fileType = new FITMessageField((Byte)FITFileIdFieldsIds.FileType); FITMessageField manufacturerId = new FITMessageField((Byte)FITFileIdFieldsIds.ManufacturerId); FITMessageField productId = new FITMessageField((Byte)FITFileIdFieldsIds.ProductId); FITMessageField serialNumber = new FITMessageField((Byte)FITFileIdFieldsIds.SerialNumber); FITMessageField exportDate = new FITMessageField((Byte)FITFileIdFieldsIds.ExportDate); FITMessageField number = new FITMessageField((Byte)FITFileIdFieldsIds.Number); fileType.SetEnum((Byte)FITFileTypes.Workout); manufacturerId.SetUInt16(1); productId.SetUInt16(20119); serialNumber.SetUInt32z(0); exportDate.SetUInt32(workout.CreationTimestamp); number.SetUInt16(0xFFFF); fileIdMessage.AddField(serialNumber); fileIdMessage.AddField(exportDate); fileIdMessage.AddField(manufacturerId); fileIdMessage.AddField(productId); fileIdMessage.AddField(number); fileIdMessage.AddField(fileType); fileIdMessage.Serialize(dataStream); // File creator message FITMessage fileCreatorMessage = new FITMessage(FITGlobalMessageIds.FileCreator); FITMessageField software = new FITMessageField((Byte)FITFileCreatorFieldsIds.SoftwareVersion); FITMessageField hardware = new FITMessageField((Byte)FITFileCreatorFieldsIds.HardwareVersion); software.SetUInt16(3605); hardware.SetUInt8(0); fileCreatorMessage.AddField(software); fileCreatorMessage.AddField(hardware); fileCreatorMessage.Serialize(dataStream); // Write workout workout.SerializeToFIT(dataStream); // Write FIT header at the start of the stream GarminFitnessByteRange headerSize = new GarminFitnessByteRange(12); GarminFitnessByteRange protocolVersion = new GarminFitnessByteRange((Byte)((FITConstants.FITProtocolMajorVersion << 4) | FITConstants.FITProtocolMinorVersion)); GarminFitnessUInt16Range profileVersion = new GarminFitnessUInt16Range((UInt16)((FITConstants.FITProfileMajorVersion * FITConstants.FITProfileMajorVersionMultiplier) + FITConstants.FITProfileMinorVersion)); GarminFitnessInt32Range dataSize = new GarminFitnessInt32Range(0); dataStream.Seek(0, SeekOrigin.Begin); dataSize.Value = (int)dataStream.Length - 12; headerSize.Serialize(dataStream); protocolVersion.Serialize(dataStream); profileVersion.Serialize(dataStream); dataSize.Serialize(dataStream); dataStream.Write(Encoding.UTF8.GetBytes(FITConstants.FITFileDescriptor), 0, 4); // Write CRC GarminFitnessUInt16Range crc = new GarminFitnessUInt16Range(FITUtils.ComputeStreamCRC(dataStream)); dataStream.Seek(0, SeekOrigin.End); crc.Serialize(dataStream); // Write all data to output stream exportStream.Write(dataStream.GetBuffer(), 0, (int)dataStream.Length); if (updateExportDate) { workout.LastExportDate = DateTime.Now; } }
public override void FillFITStepMessage(FITMessage message) { FITMessageField durationType = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.DurationType); FITMessageField durationValue = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.DurationValue); durationType.SetEnum((Byte)FITWorkoutStepDurationTypes.Distance); durationValue.SetUInt32((UInt32)GetDistanceInUnits(Length.Units.Centimeter)); }
public void TestFITScheduleSerialization() { Workout placeholderWorkout = new Workout("Test", PluginMain.GetApplication().Logbook.ActivityCategories[0]); RegularStep placeholderStep = new RegularStep(placeholderWorkout); ILogbook logbook = PluginMain.GetApplication().Logbook; bool exportHRAsMax = Options.Instance.ExportSportTracksHeartRateAsPercentMax; bool exportPowerAsFTP = Options.Instance.ExportSportTracksPowerAsPercentFTP; FITMessage serializedMessage = new FITMessage(FITGlobalMessageIds.Workout); FITMessageField messageField; DateTime serializedDate; DateTime referenceDate = new DateTime(1989, 12, 31); // Scheduled dates placeholderWorkout.Name = "WorkoutTest5"; serializedDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 12, 0, 0); placeholderWorkout.FillFITMessageForScheduledDate(serializedMessage, serializedDate); messageField = serializedMessage.GetField((Byte)FITScheduleFieldIds.ScheduledDate); Assert.IsNotNull(messageField, "Schedule date field not serialized for step"); Assert.AreEqual((UInt32)(serializedDate - referenceDate).TotalSeconds, messageField.GetUInt32(), "Invalid Schedule date FIT serialization"); serializedMessage.Clear(); placeholderWorkout.Name = "WorkoutTest6"; serializedDate.AddDays(1); placeholderWorkout.FillFITMessageForScheduledDate(serializedMessage, serializedDate); messageField = serializedMessage.GetField((Byte)FITScheduleFieldIds.ScheduledDate); Assert.IsNotNull(messageField, "Schedule date field not serialized for step"); Assert.AreEqual((UInt32)(serializedDate - referenceDate).TotalSeconds, messageField.GetUInt32(), "Invalid Schedule date FIT serialization"); serializedMessage.Clear(); // Test specific date with hardcoded result placeholderWorkout.Name = "WorkoutTest6b"; serializedDate = new DateTime(1999, 12, 31, 12, 0, 0); placeholderWorkout.FillFITMessageForScheduledDate(serializedMessage, serializedDate); messageField = serializedMessage.GetField((Byte)FITScheduleFieldIds.ScheduledDate); Assert.IsNotNull(messageField, "Schedule date field not serialized for step"); Assert.AreEqual(315576000, messageField.GetUInt32(), "Invalid Schedule date FIT serialization"); serializedMessage.Clear(); // New Zealand time (UST+12H) is a case where we had problems because the offset changes the day String currentZoneName = Time.CurrentTimeZone.standardName; placeholderWorkout.Name = "WorkoutTest7"; bool res = Time.SetTimeZone("New Zealand Standard Time"); serializedDate = new DateTime(1999, 12, 31, 0, 0, 0); placeholderWorkout.FillFITMessageForScheduledDate(serializedMessage, serializedDate); res = Time.SetTimeZone(currentZoneName); messageField = serializedMessage.GetField((Byte)FITScheduleFieldIds.ScheduledDate); Assert.IsNotNull(messageField, "Schedule date field not serialized for step"); Assert.AreEqual(315576000, messageField.GetUInt32(), "Invalid Schedule date FIT serialization"); serializedMessage.Clear(); }
public void TestFITDeserialization() { Workout placeholderWorkout = new Workout("Test", PluginMain.GetApplication().Logbook.ActivityCategories[0]); RepeatStep placeholderStep = new RepeatStep(placeholderWorkout); FITMessage serializedMessage = new FITMessage(FITGlobalMessageIds.WorkoutStep); FITMessageField typeField = new FITMessageField((Byte)FITWorkoutStepFieldIds.DurationType); FITMessageField valueField = new FITMessageField((Byte)FITWorkoutStepFieldIds.TargetValue); IRepeatDuration deserializedDuration; serializedMessage.AddField(typeField); serializedMessage.AddField(valueField); // Repeat count typeField.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatCount); valueField.SetUInt32(6); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatCountDuration, "Repeat count duration not properly FIT deserialized"); RepeatCountDuration repeatDuration = deserializedDuration as RepeatCountDuration; Assert.AreEqual(6, repeatDuration.RepetitionCount, "Invalid value deserialized for FIT repeat count duration"); valueField.SetUInt32(2); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatCountDuration, "Repeat count duration not properly FIT deserialized"); repeatDuration = deserializedDuration as RepeatCountDuration; Assert.AreEqual(2, repeatDuration.RepetitionCount, "Invalid value deserialized for FIT repeat count duration"); // Repeat until calories typeField.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatUntilCalories); valueField.SetUInt32(666); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilCaloriesDuration, "Repeat until calories duration not properly FIT deserialized"); RepeatUntilCaloriesDuration caloriesDuration = deserializedDuration as RepeatUntilCaloriesDuration; Assert.AreEqual(666, caloriesDuration.CaloriesToSpend, "Invalid value deserialized for FIT repeat until calories duration"); valueField.SetUInt32(150); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilCaloriesDuration, "Repeat until calories duration not properly FIT deserialized"); caloriesDuration = deserializedDuration as RepeatUntilCaloriesDuration; Assert.AreEqual(150, caloriesDuration.CaloriesToSpend, "Invalid value deserialized for FIT repeat until calories duration"); // Repeat until distance typeField.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatUntilDistance); valueField.SetUInt32(100000); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilDistanceDuration, "Repeat until distance duration not properly FIT deserialized"); RepeatUntilDistanceDuration distanceDuration = deserializedDuration as RepeatUntilDistanceDuration; Assert.AreEqual(1, Length.Convert(distanceDuration.GetDistanceInBaseUnit(), distanceDuration.BaseUnit, Length.Units.Kilometer), STCommon.Data.Constants.Delta, "Invalid value deserialized for FIT repeat until distance duration"); valueField.SetUInt32(160934); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilDistanceDuration, "Repeat until distance duration not properly FIT deserialized"); distanceDuration = deserializedDuration as RepeatUntilDistanceDuration; Assert.AreEqual(1, Length.Convert(distanceDuration.GetDistanceInBaseUnit(), distanceDuration.BaseUnit, Length.Units.Mile), STCommon.Data.Constants.Delta, "Invalid value deserialized for FIT repeat until distance duration"); // Repeat until HR Above typeField.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatUntilHeartRateGreaterThan); valueField.SetUInt32(220); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilHeartRateAboveDuration, "Repeat until HRAbove duration not properly FIT deserialized"); RepeatUntilHeartRateAboveDuration hrAboveDuration = deserializedDuration as RepeatUntilHeartRateAboveDuration; Assert.IsFalse(hrAboveDuration.IsPercentageMaxHeartRate, "Invalid value deserialized for FIT repeat until HRAbove duration"); Assert.AreEqual(120, hrAboveDuration.MaxHeartRate, "Invalid value deserialized for FIT repeat until HRAbove duration"); valueField.SetUInt32(80); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilHeartRateAboveDuration, "Repeat until HRAbove duration not properly FIT deserialized"); hrAboveDuration = deserializedDuration as RepeatUntilHeartRateAboveDuration; Assert.IsTrue(hrAboveDuration.IsPercentageMaxHeartRate, "Invalid value deserialized for FIT repeat until HRAbove duration"); Assert.AreEqual(80, hrAboveDuration.MaxHeartRate, "Invalid value deserialized for FIT repeat until HRAbove duration"); // Repeat until HR Below typeField.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatUntilHeartRateLessThan); valueField.SetUInt32(230); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilHeartRateBelowDuration, "Repeat until HRBelow duration not properly FIT deserialized"); RepeatUntilHeartRateBelowDuration hrBelowDuration = deserializedDuration as RepeatUntilHeartRateBelowDuration; Assert.IsFalse(hrBelowDuration.IsPercentageMaxHeartRate, "Invalid value deserialized for FIT repeat until HRBelow duration"); Assert.AreEqual(130, hrBelowDuration.MinHeartRate, "Invalid value deserialized for FIT repeat until HRBelow duration"); valueField.SetUInt32(65); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilHeartRateBelowDuration, "Repeat until HRBelow duration not properly FIT deserialized"); hrBelowDuration = deserializedDuration as RepeatUntilHeartRateBelowDuration; Assert.IsTrue(hrBelowDuration.IsPercentageMaxHeartRate, "Invalid value deserialized for FIT repeat until HRBelow duration"); Assert.AreEqual(65, hrBelowDuration.MinHeartRate, "Invalid value deserialized for FIT repeat until HRBelow duration"); // Repeat until Power Above typeField.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatUntilPowerGreaterThan); valueField.SetUInt32(1220); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilPowerAboveDuration, "Repeat until PowerAbove duration not properly FIT deserialized"); RepeatUntilPowerAboveDuration powerAboveDuration = deserializedDuration as RepeatUntilPowerAboveDuration; Assert.IsFalse(powerAboveDuration.IsPercentFTP, "Invalid value deserialized for FIT repeat until PowerAbove duration"); Assert.AreEqual(220, powerAboveDuration.MaxPower, "Invalid value deserialized for FIT repeat until PowerAbove duration"); valueField.SetUInt32(80); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilPowerAboveDuration, "Repeat until PowerAbove duration not properly FIT deserialized"); powerAboveDuration = deserializedDuration as RepeatUntilPowerAboveDuration; Assert.IsTrue(powerAboveDuration.IsPercentFTP, "Invalid value deserialized for FIT repeat until PowerAbove duration"); Assert.AreEqual(80, powerAboveDuration.MaxPower, "Invalid value deserialized for FIT repeat until PowerAbove duration"); // Repeat until Power Below typeField.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatUntilPowerLessThan); valueField.SetUInt32(1400); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilPowerBelowDuration, "Repeat until PowerBelow duration not properly FIT deserialized"); RepeatUntilPowerBelowDuration powerBelowDuration = deserializedDuration as RepeatUntilPowerBelowDuration; Assert.IsFalse(powerBelowDuration.IsPercentFTP, "Invalid value deserialized for FIT repeat until PowerBelow duration"); Assert.AreEqual(400, powerBelowDuration.MinPower, "Invalid value deserialized for FIT repeat until PowerBelow duration"); valueField.SetUInt32(125); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilPowerBelowDuration, "Repeat until PowerBelow duration not properly FIT deserialized"); powerBelowDuration = deserializedDuration as RepeatUntilPowerBelowDuration; Assert.IsTrue(powerBelowDuration.IsPercentFTP, "Invalid value deserialized for FIT repeat until PowerBelow duration"); Assert.AreEqual(125, powerBelowDuration.MinPower, "Invalid value deserialized for FIT repeat until PowerBelow duration"); // Repeat until time typeField.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatUntilTime); valueField.SetUInt32(60000); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilTimeDuration, "Repeat until time duration not properly FIT deserialized"); RepeatUntilTimeDuration timeDuration = deserializedDuration as RepeatUntilTimeDuration; Assert.AreEqual(60, timeDuration.TimeInSeconds, "Invalid value deserialized for FIT repeat until time duration"); valueField.SetUInt32(600000); deserializedDuration = DurationFactory.Create(serializedMessage, placeholderStep); Assert.IsTrue(deserializedDuration is RepeatUntilTimeDuration, "Repeat until time duration not properly FIT deserialized"); timeDuration = deserializedDuration as RepeatUntilTimeDuration; Assert.AreEqual(600, timeDuration.TimeInSeconds, "Invalid value deserialized for FIT repeat until time duration"); }
public override void FillFITStepMessage(FITMessage message) { FITMessageField durationType = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.DurationType); FITMessageField repeatPower = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.TargetValue); durationType.SetEnum((Byte)FITWorkoutStepDurationTypes.RepeatUntilHeartRateGreaterThan); if (IsPercentageMaxHeartRate) { repeatPower.SetUInt32((UInt32)MaxHeartRate); } else { repeatPower.SetUInt32((UInt32)MaxHeartRate + 100); } }
public void TestFITSerialization() { Workout placeholderWorkout = new Workout("Test", PluginMain.GetApplication().Logbook.ActivityCategories[0]); RegularStep placeholderStep = new RegularStep(placeholderWorkout); ILogbook logbook = PluginMain.GetApplication().Logbook; bool exportHRAsMax = Options.Instance.ExportSportTracksHeartRateAsPercentMax; bool exportPowerAsFTP = Options.Instance.ExportSportTracksPowerAsPercentFTP; FITMessage serializedMessage = new FITMessage(FITGlobalMessageIds.Workout); FITMessageField messageField; // Name placeholderWorkout.Name = "WorkoutTest1"; placeholderWorkout.FillFITMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutFieldIds.WorkoutName); Assert.IsNotNull(messageField, "Workout name field not serialized for step"); Assert.AreEqual("WorkoutTest1", messageField.GetString(), "Invalid workout name FIT serialization"); serializedMessage.Clear(); placeholderWorkout.Name = "WorkoutTest2"; placeholderWorkout.FillFITMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutFieldIds.WorkoutName); Assert.IsNotNull(messageField, "Workout name field not serialized for step"); Assert.AreEqual("WorkoutTest2", messageField.GetString(), "Invalid workout name FIT serialization"); serializedMessage.Clear(); // Category/Sport placeholderWorkout.Name = "WorkoutTest3"; placeholderWorkout.Category = logbook.ActivityCategories[0].SubCategories[5]; placeholderWorkout.FillFITMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutFieldIds.SportType); Assert.IsNotNull(messageField, "Workout sport field not serialized for step"); Assert.AreEqual(FITSports.Cycling, (FITSports)messageField.GetEnum(), "Invalid workout sport FIT serialization"); serializedMessage.Clear(); placeholderWorkout.Name = "WorkoutTest4"; placeholderWorkout.Category = logbook.ActivityCategories[0].SubCategories[6]; placeholderWorkout.FillFITMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutFieldIds.SportType); Assert.IsNotNull(messageField, "Workout sport field not serialized for step"); Assert.AreEqual(FITSports.Running, (FITSports)messageField.GetEnum(), "Invalid workout sport FIT serialization"); serializedMessage.Clear(); // Number of steps placeholderWorkout.Name = "WorkoutTest5"; placeholderWorkout.FillFITMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutFieldIds.NumSteps); Assert.IsNotNull(messageField, "Workout sport field not serialized for step"); Assert.AreEqual(1, messageField.GetUInt16(), "Invalid workout step count FIT serialization"); serializedMessage.Clear(); placeholderWorkout.Name = "WorkoutTest6"; placeholderWorkout.Steps.AddStepToRoot(new RepeatStep(placeholderWorkout)); placeholderWorkout.FillFITMessage(serializedMessage); messageField = serializedMessage.GetField((Byte)FITWorkoutFieldIds.NumSteps); Assert.IsNotNull(messageField, "Workout sport field not serialized for step"); Assert.AreEqual(3, messageField.GetUInt16(), "Invalid workout step count FIT serialization"); serializedMessage.Clear(); // Do not test steps serialization here, it has it's own test }
public abstract void FillFITStepMessage(FITMessage message);
public override void FillFITStepMessage(FITMessage message) { FITMessageField durationType = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.DurationType); FITMessageField durationValue = message.GetExistingOrAddField((Byte)FITWorkoutStepFieldIds.DurationValue); durationType.SetEnum((Byte)FITWorkoutStepDurationTypes.PowerLessThan); if (IsPercentFTP) { durationValue.SetUInt32((UInt32)MinPower); } else { durationValue.SetUInt32((UInt32)MinPower + 1000); } }
public abstract void DeserializeFromFIT(FITMessage workoutMessage);
public static Workout ImportWorkoutFromMessage(FITMessage workoutMessage) { return ImportWorkoutFromMessage(workoutMessage, null); }
public virtual void FillFITMessageForScheduledDate(FITMessage scheduleMessage, DateTime scheduledDate) { FITMessageField workoutManufacturer = new FITMessageField((Byte)FITScheduleFieldIds.WorkoutManufacturer); FITMessageField workoutProduct = new FITMessageField((Byte)FITScheduleFieldIds.WorkoutProduct); FITMessageField workoutSN = new FITMessageField((Byte)FITScheduleFieldIds.WorkoutSN); FITMessageField scheduleType = new FITMessageField((Byte)FITScheduleFieldIds.ScheduleType); FITMessageField workoutCompleted = new FITMessageField((Byte)FITScheduleFieldIds.WorkoutCompleted); FITMessageField workoutId = new FITMessageField((Byte)FITScheduleFieldIds.WorkoutId); FITMessageField scheduledField = new FITMessageField((Byte)FITScheduleFieldIds.ScheduledDate); DateTime midDaySchedule = new DateTime(scheduledDate.Date.Year, scheduledDate.Date.Month, scheduledDate.Day, 12, 0, 0); TimeSpan timeSinceReference = midDaySchedule - new DateTime(1989, 12, 31); // Hardcoded fields from the schedule file workoutManufacturer.SetUInt16(1); // Always 1 workoutProduct.SetUInt16(20119); // Always 20119 workoutSN.SetUInt32z(0); // Invalid workoutCompleted.SetEnum((Byte)0xFF); // Invalid/Not completed // Real data scheduleType.SetEnum((Byte)FITScheduleType.Workout); workoutId.SetUInt32(CreationTimestamp); scheduleMessage.AddField(workoutSN); scheduleMessage.AddField(workoutId); scheduleMessage.AddField(scheduledField); scheduleMessage.AddField(workoutManufacturer); scheduleMessage.AddField(workoutProduct); scheduleMessage.AddField(workoutCompleted); scheduleMessage.AddField(scheduleType); scheduledField.SetUInt32((UInt32)timeSinceReference.TotalSeconds); }
public static Workout ImportWorkoutFromMessage(FITMessage workoutMessage, IActivityCategory category) { // Peek name FITMessageField nameField = workoutMessage.GetField((Byte)FITWorkoutFieldIds.WorkoutName); if (nameField != null) { GarminFitnessView pluginView = PluginMain.GetApplication().ActiveView as GarminFitnessView; String workoutName = nameField.GetString(); if (category == null && pluginView != null) { GarminWorkoutControl workoutControl = pluginView.GetCurrentView() as GarminWorkoutControl; if (workoutControl != null) { workoutControl.GetNewWorkoutNameAndCategory(ref workoutName, ref category); } } return GarminWorkoutManager.Instance.CreateWorkout(workoutName, workoutMessage, category); } else { throw new FITParserException("No name for workout"); } }
public virtual void SerializeToFITSchedule(Stream stream, bool serializeDefiniton) { Debug.Assert(GetSplitPartsCount() == 1); FITMessage scheduleMessage = new FITMessage(FITGlobalMessageIds.WorkoutSchedules); foreach (DateTime scheduledDate in ScheduledDates) { FillFITMessageForScheduledDate(scheduleMessage, scheduledDate); scheduleMessage.Serialize(stream, serializeDefiniton); serializeDefiniton = false; } }
public static DateTime ImportWorkoutScheduleMessage(FITMessage scheduleMessage) { // Make sure we have a workout file FITMessageField scheduledDate = scheduleMessage.GetField((Byte)FITScheduleFieldIds.ScheduledDate); UInt32 secondsSinceReference = scheduledDate.GetUInt32(); return new DateTime(1989, 12, 31) + new TimeSpan(0, 0, (int)secondsSinceReference); }