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);
                }
            }
        }
Exemple #3
0
        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"));
             }
        }