/// <summary> /// Validate if a MessageDefinition is compatible with a protocol version /// </summary> /// <param name="defn">Definition to validate</param> /// <returns>true if definition is compatible. false otherwise</returns> public bool ValidateMessageDefn(MessageDefinition defn) { if (m_validator == null) { return(true); } return(m_validator.ValidateMessageDefn(defn)); }
public bool Supports(MessageDefinition mesgDef) { if (mesgDef == null) { return(false); } if (GlobalMessageNum != mesgDef.GlobalMessageNum) { return(false); } if (LocalMessageNum != mesgDef.LocalMessageNum) { return(false); } foreach (FieldDefinition fieldDef in mesgDef.GetFields()) { FieldDefinition supportedFieldDef = GetField(fieldDef.Num); if (supportedFieldDef == null) { return(false); } if (fieldDef.Size > supportedFieldDef.Size) { return(false); } } foreach (DeveloperFieldDefinition fieldDef in mesgDef.DeveloperFieldDefinitions) { var supportedFieldDef = GetDeveloperFieldDefinition(fieldDef.FieldNum, fieldDef.DeveloperDataIndex); if (supportedFieldDef == null) { return(false); } if (fieldDef.Size > supportedFieldDef.Size) { return(false); } } return(true); }
public MessageDefinition(MessageDefinition mesgDef) { LocalMessageNum = mesgDef.LocalMessageNum; GlobalMessageNum = mesgDef.GlobalMessageNum; architecture = mesgDef.IsBigEndian ? Fit.BigEndian : Fit.LittleEndian; NumFields = mesgDef.NumFields; foreach (FieldDefinition fieldDef in mesgDef.fieldDefs) { fieldDefs.Add(new FieldDefinition(fieldDef)); } m_devFieldDefs.AddRange(mesgDef.m_devFieldDefs); }
public void Write(MessageDefinition mesgDefinition) { if (open == false) { throw new FitException("Encode:Write - Encode not opened yet, must call Encode:Open()"); } if (!validator.ValidateMessageDefn(mesgDefinition)) { throw new FitException("Encode:Write - mesgDefinition contains incompatible protocol Features"); } mesgDefinition.Write(fitDest); lastMessageDef[mesgDefinition.LocalMessageNum] = mesgDefinition; }
public void Write(Stream outStream, MessageDefinition mesgDef) { if (mesgDef == null) { mesgDef = new MessageDefinition(this); } EndianBinaryWriter bw = new EndianBinaryWriter(outStream, mesgDef.IsBigEndian); bw.Write(LocalNum); foreach (FieldDefinition fieldDef in mesgDef.GetFields()) { Field field = GetField(fieldDef.Num); if (null == field) { field = Profile.GetField(this.MessageNumber, fieldDef.Num); if (null != field) { FieldsList.Add(field); } else { field = new Field(fieldDef.Num, fieldDef.Type); } } WriteField(field, fieldDef.Size, bw); } foreach (DeveloperFieldDefinition fieldDef in mesgDef.DeveloperFieldDefinitions) { DeveloperField field = GetDeveloperField(fieldDef.FieldNum, fieldDef.DeveloperDataIndex); if (field == null) { field = new DeveloperField(fieldDef); SetDeveloperField(field); } WriteField(field, fieldDef.Size, bw); } }
/// <summary> /// Validate if a MessageDefinition is compatible with a protocol version /// </summary> /// <param name="defn">Definition to validate</param> /// <returns>true if definition is compatible. false otherwise</returns> public bool ValidateMessageDefn(MessageDefinition defn) { if (defn.DeveloperFieldDefinitions.Any()) { return(false); } foreach (var fld in defn.GetFields()) { int typeNum = fld.Type & Fit.BaseTypeNumMask; if (typeNum > Fit.Byte) { return(false); } } return(true); }
public void Read(Stream inStream, MessageDefinition defnMessage) { inStream.Position = 1; EndianBinaryReader mesgReader = new EndianBinaryReader(inStream, defnMessage.IsBigEndian); LocalNum = defnMessage.LocalMessageNum; foreach (FieldDefinition fieldDef in defnMessage.GetFields()) { bool read = true; // It's possible the field type found in the field definition may // not agree with the type defined in the profile. The profile // type will be preferred for decode. Field field = GetField(fieldDef.Num); if (field == null) { // We normally won't have fields attached to our skeleton message, // as we add values we need to add the fields too based on the mesg,field // combo in the profile. Must derive from the profile so the scale etc // is correct field = new Field(Profile.GetMessage(this.MessageNumber).GetField(fieldDef.Num)); if (field.Num == Fit.FieldNumInvalid) { // If there was no info in the profile the FieldNum will get set to invalid // so preserve the unknown fields info while we know it field.Num = fieldDef.Num; field.SetType(fieldDef.Type); } SetField(field); } if (field.Type != fieldDef.Type) { int fieldSize = Fit.BaseType[field.Type & Fit.BaseTypeNumMask].size; int defSize = Fit.BaseType[fieldDef.Type & Fit.BaseTypeNumMask].size; if (defSize < fieldSize) { field.SetType(fieldDef.Type); } else if (defSize != fieldSize) { // Demotion is hard. Don't read the field if the // sizes are different. Use the profile type if the // signedness of the field has changed. read = false; } } if (read) { ReadFieldValue(field, fieldDef.Size, mesgReader); } else { // Skip the bytes for the field if we aren't going to bother reading them mesgReader.ReadBytes(fieldDef.Size); } } foreach (DeveloperFieldDefinition fldDef in defnMessage.DeveloperFieldDefinitions) { DeveloperField fld = GetDeveloperField(fldDef.FieldNum, fldDef.DeveloperDataIndex); if (ReferenceEquals(fld, null)) { fld = new DeveloperField(fldDef); SetDeveloperField(fld); } ReadFieldValue(fld, fldDef.Size, mesgReader); } }
public Message(Stream fitStream, MessageDefinition defnMessage) : this(defnMessage.GlobalMessageNum) { Read(fitStream, defnMessage); }
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.GetMessage(MessageNum.Record).GetField("Timestamp")); timestampField.SetValue(timestamp); byte localMessageNum = (byte)((nextByte & Fit.CompressedLocalMessageNumMask) >> 5); mesgBuffer.WriteByte(localMessageNum); if (localMessageDefs[localMessageNum] == null) { throw new FitException("Decode:DecodeNextMessage - FIT decode error: Missing message definition for local message number " + localMessageNum + " at stream position " + fitStream.Position); } int fieldsSize = localMessageDefs[localMessageNum].GetMessageSize() - 1; try { byte[] read = br.ReadBytes(fieldsSize); if (read.Length < fieldsSize) { throw new Exception("Field size mismatch, expected: " + fieldsSize + "received: " + read.Length); } mesgBuffer.Write(read, 0, fieldsSize); } catch (Exception e) { throw new FitException("Decode:DecodeNextMessage - Compressed Data Message unexpected end of file. Wanted " + fieldsSize + " bytes at stream position " + fitStream.Position, e); } Message newMessage = new Message(mesgBuffer, localMessageDefs[localMessageNum]); newMessage.InsertField(0, timestampField); RaiseMessageEvent(newMessage); } // Is it a mesg def? else if ((nextByte & Fit.MessageDefinitionMask) == Fit.MessageDefinitionMask) { 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); int numBytes = numFields * 3; //3 Bytes per field try { byte[] read = br.ReadBytes(numBytes); if (read.Length < numBytes) { throw new Exception("Message Definition size mismatch, expected: " + numBytes + "received: " + read.Length); } mesgDefBuffer.Write(read, 0, numBytes); if ((nextByte & Fit.DevDataMask) == Fit.DevDataMask) { // Definition Contains Dev Data byte numDevFields = br.ReadByte(); mesgDefBuffer.WriteByte(numDevFields); numBytes = numDevFields * 3; read = br.ReadBytes(numBytes); if (read.Length < numBytes) { throw new Exception("Message Definition size mismatch, expected: " + numBytes + "received: " + read.Length); } // Read Dev Data mesgDefBuffer.Write(read, 0, numBytes); } } catch (Exception e) { throw new FitException("Decode:DecodeNextMessage - Defn Message unexpected end of file. Wanted " + numBytes + " bytes at stream position " + fitStream.Position, e); } MessageDefinition newMessageDef = new MessageDefinition(mesgDefBuffer, m_lookup); localMessageDefs[newMessageDef.LocalMessageNum] = newMessageDef; if (MessageDefinitionEvent != null) { MessageDefinitionEvent(this, new MessageDefinitionEventArgs(newMessageDef)); } } // Is it a data mesg? else if ((nextByte & Fit.MessageDefinitionMask) == Fit.MessageHeaderMask) { MemoryStream mesgBuffer = new MemoryStream(); byte localMessageNum = (byte)(nextByte & Fit.LocalMessageNumMask); mesgBuffer.WriteByte(localMessageNum); if (localMessageDefs[localMessageNum] == null) { throw new FitException("Decode:DecodeNextMessage - FIT decode error: Missing message definition for local message number " + localMessageNum + " at stream position " + fitStream.Position); } int fieldsSize = localMessageDefs[localMessageNum].GetMessageSize() - 1; try { byte[] read = br.ReadBytes(fieldsSize); if (read.Length < fieldsSize) { throw new Exception("Field size mismatch, expected: " + fieldsSize + "received: " + read.Length); } mesgBuffer.Write(read, 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); } Message newMessage = new Message(mesgBuffer, localMessageDefs[localMessageNum]); // If the new message contains a timestamp field, record the value to use as // a reference for compressed timestamp headers Field timestampField = newMessage.GetField("Timestamp"); if (timestampField != null) { object tsValue = timestampField.GetValue(); if (tsValue != null) { timestamp = (uint)tsValue; lastTimeOffset = (int)timestamp & Fit.CompressedTimeMask; } } foreach (Field field in newMessage.FieldsList) { if (field.IsAccumulated) { int i; for (i = 0; i < field.GetNumValues(); i++) { long value = Convert.ToInt64(field.GetRawValue(i)); foreach (Field fieldIn in newMessage.FieldsList) { foreach (FieldComponent fc in fieldIn.components) { if ((fc.fieldNum == field.Num) && (fc.accumulate)) { value = (long)((((value / field.Scale) - field.Offset) + fc.offset) * fc.scale); } } } accumulator.Set(newMessage.MessageNumber, field.Num, value); } } } // Now that the entire message is decoded we can evaluate subfields and expand any components newMessage.ExpandComponents(accumulator); RaiseMessageEvent(newMessage); } else { throw new FitException("Decode:Read - FIT decode error: Unexpected Object Header Byte 0x" + nextByte.ToString("X") + " at stream position: " + fitStream.Position); } }
public MessageDefinitionEventArgs(MessageDefinition newDefn) { messageDefinition = new MessageDefinition(newDefn); }
public void OnMessageDefinition(MessageDefinition newMessageDefinition) { Write(newMessageDefinition); }