public void ExpandComponents() { // We can't modify the fields collection as we are traversing it, save new fields // to add after we complete expansion List<Field> newFields = new List<Field>(); foreach (Field myField in fields) { List<FieldComponent> compsToExpand = null; Field containingField = null; // Determine the active subfield and expand if it has any components ushort activeSubfield = GetActiveSubFieldIndex(myField.Num); if (activeSubfield == Fit.SubfieldIndexMainField) { // There are main field components, expand if (myField.components.Count > 0) { compsToExpand = myField.components; containingField = myField; } } else { // There are subfield components, expand if (myField.GetSubfield(activeSubfield).Components.Count > 0) { compsToExpand = myField.GetSubfield(activeSubfield).Components; containingField = myField; } } if (compsToExpand != null) { // Comp Decode if (containingField.values.Count > 0) { int offset = 0; foreach (FieldComponent component in compsToExpand) { if (component.fieldNum != Fit.FieldNumInvalid) { Field destinationField = new Field(Profile.GetMesg(this.Num).GetField(component.fieldNum)); // GetBitsValue will not return more bits than the componentField type can hold. // This means strings are built one letter at a time when using components // which is a bad idea to start with) long? bitsValue = containingField.GetBitsValue(offset, component.bits, destinationField.Type); if (bitsValue == null) { break; } if (component.accumulate == true) { bitsValue = component.Accumulate(bitsValue.Value); } if (destinationField.IsNumeric()) { float fbitsValue = Convert.ToSingle(bitsValue); fbitsValue = ((float)fbitsValue / component.scale) - component.offset; if (this.HasField(destinationField.Num) == true) { this.GetField(destinationField.Num).SetValue(this.GetField(destinationField.Num).values.Count, fbitsValue); } else { destinationField.SetValue(fbitsValue); newFields.Add(destinationField); } } // Shouldn't apply scale/offset to string or enum else { object nonNumericBitsValue; // Ensure strings are added as byte[] if ((destinationField.Type & Fit.BaseTypeNumMask) == Fit.String) { nonNumericBitsValue = new byte[] { (byte)bitsValue }; } else { nonNumericBitsValue = bitsValue; } if (this.HasField(destinationField.Num) == true) { this.GetField(destinationField.Num).SetValue(this.GetField(destinationField.Num).values.Count, nonNumericBitsValue); } else { destinationField.SetValue(nonNumericBitsValue); newFields.Add(destinationField); } } } offset += component.bits; } } } } foreach (Field newField in newFields) { // Another component added this field during expansion, append the additional values if (this.HasField(newField.Num) == true) { foreach (object newValue in newField.values) { this.GetField(newField.Num).SetValue(this.GetField(newField.Num).values.Count, newValue); } } // Add the new field else { this.SetField(newField); } } }
public void ExpandComponents() { // We can't modify the fields collection as we are traversing it, save new fields // to add after we complete expansion List <Field> newFields = new List <Field>(); foreach (Field myField in fields) { List <FieldComponent> compsToExpand = null; Field containingField = null; // Determine the active subfield and expand if it has any components ushort activeSubfield = GetActiveSubFieldIndex(myField.Num); if (activeSubfield == Fit.SubfieldIndexMainField) { // There are main field components, expand if (myField.components.Count > 0) { compsToExpand = myField.components; containingField = myField; } } else { // There are subfield components, expand if (myField.GetSubfield(activeSubfield).Components.Count > 0) { compsToExpand = myField.GetSubfield(activeSubfield).Components; containingField = myField; } } if (compsToExpand != null) { // Comp Decode if (containingField.values.Count > 0) { int offset = 0; foreach (FieldComponent component in compsToExpand) { if (component.fieldNum != Fit.FieldNumInvalid) { Field destinationField = new Field(Profile.GetMesg(this.Num).GetField(component.fieldNum)); // GetBitsValue will not return more bits than the componentField type can hold. // This means strings are built one letter at a time when using components // which is a bad idea to start with) long?bitsValue = containingField.GetBitsValue(offset, component.bits, destinationField.Type); if (bitsValue == null) { break; } if (component.accumulate == true) { bitsValue = component.Accumulate(bitsValue.Value); } if (destinationField.IsNumeric()) { float fbitsValue = Convert.ToSingle(bitsValue); fbitsValue = ((float)fbitsValue / component.scale) - component.offset; if (this.HasField(destinationField.Num) == true) { this.GetField(destinationField.Num).SetValue(this.GetField(destinationField.Num).values.Count, fbitsValue); } else { destinationField.SetValue(fbitsValue); newFields.Add(destinationField); } } // Shouldn't apply scale/offset to string or enum else { object nonNumericBitsValue; // Ensure strings are added as byte[] if ((destinationField.Type & Fit.BaseTypeNumMask) == Fit.String) { nonNumericBitsValue = new byte[] { (byte)bitsValue }; } else { nonNumericBitsValue = bitsValue; } if (this.HasField(destinationField.Num) == true) { this.GetField(destinationField.Num).SetValue(this.GetField(destinationField.Num).values.Count, nonNumericBitsValue); } else { destinationField.SetValue(nonNumericBitsValue); newFields.Add(destinationField); } } } offset += component.bits; } } } } foreach (Field newField in newFields) { // Another component added this field during expansion, append the additional values if (this.HasField(newField.Num) == true) { foreach (object newValue in newField.values) { this.GetField(newField.Num).SetValue(this.GetField(newField.Num).values.Count, newValue); } } // Add the new field else { this.SetField(newField); } } }
public void DecodeNextMessage(Stream fitStream) { BinaryReader br = new BinaryReader(fitStream); byte nextByte = br.ReadByte(); // Is it a compressed timestamp mesg? if ((nextByte & Fit.CompressedHeaderMask) == Fit.CompressedHeaderMask) { MemoryStream mesgBuffer = new MemoryStream(); int timeOffset = nextByte & Fit.CompressedTimeMask; timestamp += (uint)((timeOffset - lastTimeOffset) & Fit.CompressedTimeMask); lastTimeOffset = timeOffset; Field timestampField = new Field(Profile.mesgs[Profile.RecordIndex].GetField("Timestamp")); timestampField.SetValue(timestamp); byte localMesgNum = (byte)((nextByte & Fit.CompressedLocalMesgNumMask) >> 5); mesgBuffer.WriteByte(localMesgNum); if (localMesgDefs[localMesgNum] == null) { throw new FitException("Decode:DecodeNextMessage - FIT decode error: Missing message definition for local message number " + localMesgNum + "."); } int fieldsSize = localMesgDefs[localMesgNum].GetMesgSize() - 1; try { mesgBuffer.Write(br.ReadBytes(fieldsSize), 0, fieldsSize); } catch (IOException e) { throw new FitException("Decode:DecodeNextMessage - Compressed Data Message unexpected end of file. Wanted " + fieldsSize + " bytes at stream position " + fitStream.Position, e); } Mesg newMesg = new Mesg(mesgBuffer, localMesgDefs[localMesgNum]); newMesg.InsertField(0, timestampField); if (MesgEvent != null) { MesgEvent(this, new MesgEventArgs(newMesg)); } } // Is it a mesg def? else if ((nextByte & Fit.HeaderTypeMask) == Fit.MesgDefinitionMask) { MemoryStream mesgDefBuffer = new MemoryStream(); // Figure out number of fields (length) of our defn and build buffer mesgDefBuffer.WriteByte(nextByte); mesgDefBuffer.Write(br.ReadBytes(4), 0, 4); byte numfields = br.ReadByte(); mesgDefBuffer.WriteByte(numfields); try { mesgDefBuffer.Write(br.ReadBytes(numfields * 3), 0, numfields * 3); } catch (IOException e) { throw new FitException("Decode:DecodeNextMessage - Defn Message unexpected end of file. Wanted " + (numfields * 3) + " bytes at stream position " + fitStream.Position, e); } MesgDefinition newMesgDef = new MesgDefinition(mesgDefBuffer); localMesgDefs[newMesgDef.LocalMesgNum] = newMesgDef; if (MesgDefinitionEvent != null) { MesgDefinitionEvent(this, new MesgDefinitionEventArgs(newMesgDef)); } } // Is it a data mesg? else if ((nextByte & Fit.HeaderTypeMask) == Fit.MesgHeaderMask) { MemoryStream mesgBuffer = new MemoryStream(); byte localMesgNum = (byte)(nextByte & Fit.LocalMesgNumMask); mesgBuffer.WriteByte(localMesgNum); if (localMesgDefs[localMesgNum] == null) { throw new FitException("Decode:DecodeNextMessage - FIT decode error: Missing message definition for local message number " + localMesgNum + "."); } int fieldsSize = localMesgDefs[localMesgNum].GetMesgSize() - 1; try { mesgBuffer.Write(br.ReadBytes(fieldsSize), 0, fieldsSize); } catch (Exception e) { throw new FitException("Decode:DecodeNextMessage - Data Message unexpected end of file. Wanted " + fieldsSize + " bytes at stream position " + fitStream.Position, e); } Mesg newMesg = new Mesg(mesgBuffer, localMesgDefs[localMesgNum]); // If the new message contains a timestamp field, record the value to use as // a reference for compressed timestamp headers Field timestampField = newMesg.GetField("Timestamp"); if (timestampField != null) { timestamp = (uint)timestampField.GetValue(); lastTimeOffset = (int)timestamp & Fit.CompressedTimeMask; } // Now that the entire message is decoded we can evaluate subfields and expand any components newMesg.ExpandComponents(); if (MesgEvent != null) { MesgEvent(this, new MesgEventArgs(newMesg)); } } else { throw new FitException("Decode:Read - FIT decode error: Unexpected Record Header Byte 0x" + nextByte.ToString("X")); } }
public void DecodeNextMessage(Stream fitStream) { BinaryReader br = new BinaryReader(fitStream); byte nextByte = br.ReadByte(); // Is it a compressed timestamp mesg? if ((nextByte & Fit.CompressedHeaderMask) == Fit.CompressedHeaderMask) { MemoryStream mesgBuffer = new MemoryStream(); int timeOffset = nextByte & Fit.CompressedTimeMask; timestamp += (uint)((timeOffset - lastTimeOffset) & Fit.CompressedTimeMask); lastTimeOffset = timeOffset; Field timestampField = new Field(Profile.mesgs[Profile.RecordIndex].GetField("Timestamp")); timestampField.SetValue(timestamp); byte localMesgNum = (byte)((nextByte & Fit.CompressedLocalMesgNumMask) >> 5); mesgBuffer.WriteByte(localMesgNum); if (localMesgDefs[localMesgNum] == null) { throw new FitException("Decode:DecodeNextMessage - FIT decode error: Missing message definition for local message number " + localMesgNum + "."); } int fieldsSize = localMesgDefs[localMesgNum].GetMesgSize() - 1; try { mesgBuffer.Write(br.ReadBytes(fieldsSize), 0, fieldsSize); } catch (IOException e) { throw new FitException("Decode:DecodeNextMessage - Compressed Data Message unexpected end of file. Wanted " + fieldsSize + " bytes at stream position " + fitStream.Position, e); } Mesg newMesg = new Mesg(mesgBuffer, localMesgDefs[localMesgNum]); newMesg.InsertField(0, timestampField); if (MesgEvent != null) { MesgEvent(this, new MesgEventArgs(newMesg)); } } // Is it a mesg def? else if ((nextByte & Fit.HeaderTypeMask) == Fit.MesgDefinitionMask) { MemoryStream mesgDefBuffer = new MemoryStream(); // Figure out number of fields (length) of our defn and build buffer mesgDefBuffer.WriteByte(nextByte); mesgDefBuffer.Write(br.ReadBytes(4), 0, 4); byte numfields = br.ReadByte(); mesgDefBuffer.WriteByte(numfields); try { mesgDefBuffer.Write(br.ReadBytes(numfields * 3), 0, numfields * 3); } catch (IOException e) { throw new FitException("Decode:DecodeNextMessage - Defn Message unexpected end of file. Wanted " + (numfields * 3) + " bytes at stream position " + fitStream.Position, e); } MesgDefinition newMesgDef = new MesgDefinition(mesgDefBuffer); localMesgDefs[newMesgDef.LocalMesgNum] = newMesgDef; if (MesgDefinitionEvent != null) { MesgDefinitionEvent(this, new MesgDefinitionEventArgs(newMesgDef)); } } // Is it a data mesg? else if ((nextByte & Fit.HeaderTypeMask) == Fit.MesgHeaderMask) { MemoryStream mesgBuffer = new MemoryStream(); byte localMesgNum = (byte)(nextByte & Fit.LocalMesgNumMask); mesgBuffer.WriteByte(localMesgNum); if (localMesgDefs[localMesgNum] == null) { throw new FitException("Decode:DecodeNextMessage - FIT decode error: Missing message definition for local message number " + localMesgNum + "."); } int fieldsSize = localMesgDefs[localMesgNum].GetMesgSize() - 1; try { mesgBuffer.Write(br.ReadBytes(fieldsSize), 0, fieldsSize); } catch (Exception e) { throw new FitException("Decode:DecodeNextMessage - Data Message unexpected end of file. Wanted " + fieldsSize + " bytes at stream position " + fitStream.Position, e); } Mesg newMesg = new Mesg(mesgBuffer, localMesgDefs[localMesgNum]); // If the new message contains a timestamp field, record the value to use as // a reference for compressed timestamp headers Field timestampField = newMesg.GetField("Timestamp"); if (timestampField != null) { timestamp = (uint)timestampField.GetValue(); lastTimeOffset = (int)timestamp & Fit.CompressedTimeMask; } // Now that the entire message is decoded we can evaluate subfields and expand any components newMesg.ExpandComponents(); if (MesgEvent != null) { MesgEvent(this, new MesgEventArgs(newMesg)); } } else { throw new FitException("Decode:Read - FIT decode error: Unexpected Record Header Byte 0x" + nextByte.ToString("X")); } }