private ArgosFix[] GetFixes(DateTime transmissionDateTime, ICollection<byte> message) { if (message == null) return new ArgosFix[0]; //Get the message header bool messageHasSensorData = message.BooleanAt(0); //ignore sensor or error messages if (messageHasSensorData) return new ArgosFix[0]; if (message.Count < 9) //72 bits (9 bytes) required for a full absolute fix return new[] { new ArgosFix { ConditionCode = ArgosConditionCode.Invalid } }; //Get the absolute Fix byte reportedCrc = message.ByteAt(1, 6); byte fixBufferType = message.ByteAt(7, 2); uint longitudeBits = message.UInt32At(9, 22); double longitude = longitudeBits.TwosComplement(22, 4); uint latitudeBits = message.UInt32At(31, 21); double latitude = latitudeBits.TwosComplement(21, 4); ushort julian = message.UInt16At(52, 9); byte hour = message.ByteAt(61, 5); byte minute = message.ByteAt(66, 6); DateTime fixDate = CalculateFixDate(transmissionDateTime, julian, hour, minute); // Cyclical Redundancy Check var crc = new Crc(); crc.Update(fixBufferType, 2); crc.Update((int)longitudeBits, 22); crc.Update((int)latitudeBits, 21); crc.Update(julian, 9); crc.Update(hour, 5); crc.Update(minute, 6); ArgosConditionCode cCode = crc.Value == reportedCrc ? ArgosConditionCode.Good : ArgosConditionCode.Bad; var fixes = new List<ArgosFix> { new ArgosFix { ConditionCode = cCode, Longitude = longitude, Latitude = latitude, DateTime = fixDate } }; //Setup for the relative fixes if (fixBufferType > 3) throw new InvalidDataException("Argos Message has invalid Fix Buffer Type."); int numberOfRelativeFixes = new[] { 0, 3, 4, 5 }[fixBufferType]; int doubleLength = new[] { 0, 17, 12, 9 }[fixBufferType]; int relativeFixLength = new[] { 0, 46, 36, 30 }[fixBufferType]; //Get the relative fixes for (var i = 0; i < numberOfRelativeFixes; i++) { int firstBit = 72 + i * relativeFixLength; int bytesRequired = (firstBit + relativeFixLength + 7) / 8; //+7 to round up if (message.Count < bytesRequired) break; reportedCrc = message.ByteAt(firstBit, 6); firstBit += 6; longitudeBits = message.UInt32At(firstBit, doubleLength); double longitudeDelta = longitudeBits.TwosComplement(doubleLength, 4); firstBit += doubleLength; latitudeBits = message.UInt32At(firstBit, doubleLength); double latitudeDelta = latitudeBits.TwosComplement(doubleLength, 4); firstBit += doubleLength; //Get the time of the relative fixes byte delay = message.ByteAt(firstBit, 6); TimeSpan timeOffset = TimeSpan.FromMinutes((i + 1) * Period.TotalMinutes); fixDate = fixDate.AddMinutes(-fixDate.Minute); //Round down to the hour // Cyclical Redundancy Check crc = new Crc(); crc.Update((int)longitudeBits, doubleLength); crc.Update((int)latitudeBits, doubleLength); crc.Update(delay, 6); cCode = crc.Value == reportedCrc ? ArgosConditionCode.Good : ArgosConditionCode.Bad; //If the CRC is good we still need to check for values out of range if (cCode == ArgosConditionCode.Good) { //if the 6 bits of delay are all ones the fix could not be acquired if ((delay & 0x3F) == 0x3F) cCode = ArgosConditionCode.Unavailable; } if (delay > 59) //59 min is max delay delay = 0; //NOTE: In some cases Unavailable is reported when CRC was bad, but usually not. DateTime relFixDate; if (fixDate == default(DateTime)) relFixDate = new DateTime(); // use default value else relFixDate = fixDate - timeOffset + TimeSpan.FromMinutes(delay); fixes.Add( new ArgosFix { ConditionCode = cCode, Longitude = longitude + longitudeDelta, Latitude = latitude + latitudeDelta, DateTime = relFixDate } ); } return fixes.ToArray(); }
private ArgosFix[] GetFixes(DateTime transmissionDateTime, ICollection <byte> message) { if (message == null) { return(new ArgosFix[0]); } //Get the message header bool messageHasSensorData = message.BooleanAt(0); //ignore sensor or error messages if (messageHasSensorData) { return(new ArgosFix[0]); } if (message.Count < 9) //72 bits (9 bytes) required for a full absolute fix { return new[] { new ArgosFix { ConditionCode = ArgosConditionCode.Invalid } } } ; //Get the absolute Fix byte reportedCrc = message.ByteAt(1, 6); byte fixBufferType = message.ByteAt(7, 2); uint longitudeBits = message.UInt32At(9, 22); double longitude = longitudeBits.TwosComplement(22, 4); uint latitudeBits = message.UInt32At(31, 21); double latitude = latitudeBits.TwosComplement(21, 4); ushort julian = message.UInt16At(52, 9); byte hour = message.ByteAt(61, 5); byte minute = message.ByteAt(66, 6); DateTime fixDate = CalculateFixDate(transmissionDateTime, julian, hour, minute); // Cyclical Redundancy Check var crc = new Crc(); crc.Update(fixBufferType, 2); crc.Update((int)longitudeBits, 22); crc.Update((int)latitudeBits, 21); crc.Update(julian, 9); crc.Update(hour, 5); crc.Update(minute, 6); ArgosConditionCode cCode = crc.Value == reportedCrc ? ArgosConditionCode.Good : ArgosConditionCode.Bad; var fixes = new List <ArgosFix> { new ArgosFix { ConditionCode = cCode, Longitude = longitude, Latitude = latitude, DateTime = fixDate } }; //Setup for the relative fixes if (fixBufferType > 3) { throw new InvalidDataException("Argos Message has invalid Fix Buffer Type."); } int numberOfRelativeFixes = new[] { 0, 3, 4, 5 }[fixBufferType]; int doubleLength = new[] { 0, 17, 12, 9 }[fixBufferType]; int relativeFixLength = new[] { 0, 46, 36, 30 }[fixBufferType]; //Get the relative fixes for (var i = 0; i < numberOfRelativeFixes; i++) { int firstBit = 72 + i * relativeFixLength; int bytesRequired = (firstBit + relativeFixLength + 7) / 8; //+7 to round up if (message.Count < bytesRequired) { break; } reportedCrc = message.ByteAt(firstBit, 6); firstBit += 6; longitudeBits = message.UInt32At(firstBit, doubleLength); double longitudeDelta = longitudeBits.TwosComplement(doubleLength, 4); firstBit += doubleLength; latitudeBits = message.UInt32At(firstBit, doubleLength); double latitudeDelta = latitudeBits.TwosComplement(doubleLength, 4); firstBit += doubleLength; //Get the time of the relative fixes byte delay = message.ByteAt(firstBit, 6); TimeSpan timeOffset = TimeSpan.FromMinutes((i + 1) * Period.TotalMinutes); fixDate = fixDate.AddMinutes(-fixDate.Minute); //Round down to the hour // Cyclical Redundancy Check crc = new Crc(); crc.Update((int)longitudeBits, doubleLength); crc.Update((int)latitudeBits, doubleLength); crc.Update(delay, 6); cCode = crc.Value == reportedCrc ? ArgosConditionCode.Good : ArgosConditionCode.Bad; //If the CRC is good we still need to check for values out of range if (cCode == ArgosConditionCode.Good) { //if the 6 bits of delay are all ones the fix could not be acquired if ((delay & 0x3F) == 0x3F) { cCode = ArgosConditionCode.Unavailable; } } if (delay > 59) //59 min is max delay { delay = 0; } //NOTE: In some cases Unavailable is reported when CRC was bad, but usually not. DateTime relFixDate; if (fixDate == default(DateTime)) { relFixDate = new DateTime(); // use default value } else { relFixDate = fixDate - timeOffset + TimeSpan.FromMinutes(delay); } fixes.Add( new ArgosFix { ConditionCode = cCode, Longitude = longitude + longitudeDelta, Latitude = latitude + latitudeDelta, DateTime = relFixDate } ); } return(fixes.ToArray()); }