using DTS.Serialization.IRIGCh10.Attributes; using DTS.Serialization.IRIGCH10.Enums; using System; using System.Collections; using System.ComponentModel; using System.IO; using System.Linq; namespace DTS.Serialization.IRIGCH10 { /// /// implements the packet header portion of a packet /// public class PacketHeader : IPacketHeader { /// /// used to indicate the start of a packet, is defined to 0x25, 0xEB by chapter10.pdf /// public ushort PacketSyncPattern { get; set; } = BitConverter.ToUInt16(new byte[] { 0x25, 0xEB }, 0); /// /// this is just a shortcut to avoid calculating the ushort value for 0x25,0xEB /// this is the ushort pattern expected for pattern sync /// public const ushort EXPECTED_SYNC_PATTERN = 60197; /// /// channel id, default to 0 /// public ushort ChannelId { get; set; } = BitConverter.ToUInt16(new byte[] { 0x00, 0x00 }, 0); /// /// total length of the packet including header, data, and filler, and any checksums /// public uint PacketLength { get; set; } = 0; /// /// length of the data portion of the packet, so sans filler and checksums /// public uint DataLength { get; set; } = 0; public byte DataVersion { get; set; } = 0; public byte SequenceNum { get; set; } = 0; [Browsable(false)] public byte PacketFlags { get; private set; } = 0; public bool SecondaryHeaderPresent { get { var b = new BitArray(new[] { PacketFlags }); return b.Get(7); } set { PacketFlags = SetBit(PacketFlags, 7, value); } } public bool IPTSTimeSource { get { var b = new BitArray(new[] { PacketFlags }); return b.Get(6); } set { PacketFlags = SetBit(PacketFlags, 6, value); } } public bool RTCSyncError { get { var b = new BitArray(new[] { PacketFlags }); return b.Get(5); } set { PacketFlags = SetBit(PacketFlags, 5, value); } } public enum SecondaryHeaderTimeFormats { Chapter4 = 0, IEEE1588 = 1, ExtendedRelativeTimeCounter = 2, Reserved = 3 } public SecondaryHeaderTimeFormats SecondaryHeaderTimeFormat { get { var b = new BitArray(new[] { PacketFlags }); return (SecondaryHeaderTimeFormats)Utils.Utils.BitArrayToInt32(b, 2, 3); } set { var b = new BitArray(new[] { PacketFlags }); Utils.Utils.SetBits(b, (uint)value, 2, 3); var ret = new byte[1]; b.CopyTo(ret, 0); PacketFlags = ret[0]; } } public bool DataOverflowError { get { var b = new BitArray(new[] { PacketFlags }); return b.Get(4); } set { PacketFlags = SetBit(PacketFlags, 4, value); } } private byte SetBit(byte input, int bit, bool bVal) { var b = new BitArray(new[] { input }); b.Set(bit, bVal); var ret = new byte[1]; b.CopyTo(ret, 0); return ret[0]; } public enum DataCheckSumPresences { NotPresent = 0, EightBit = 1, SixteenBit = 2, ThirtyTwoBit = 3 } public DataCheckSumPresences CheckSumPresence { get { var b = new BitArray(new[] { PacketFlags }); return (DataCheckSumPresences)Utils.Utils.BitArrayToInt32(b, 0, 1); } set { var b = new BitArray(new[] { PacketFlags }); Utils.Utils.SetBits(b, (uint)value, 0, 1); var ret = new byte[1]; b.CopyTo(ret, 0); PacketFlags = ret[0]; } } [Browsable(false)] public byte DataType { get; set; } = 0; public DataFileDataTypes DataFileType { get { var all = Enum.GetValues(typeof(DataFileDataTypes)).Cast().ToArray(); foreach (var datatype in all) { var b = PacketHeaderValueAttribute.GetPacketHeaderValue(datatype); if (b == DataType) { return datatype; } } return DataFileDataTypes.ComputerGeneratedDataFormat0; } } //10 MHz Relative Time Counter [Browsable(false)] public byte[] RTC { get; set; } = new byte[6]; public long RTCLong { get { var bytes = new byte[8]; Buffer.BlockCopy(RTC, 0, bytes, 0, 6); return BitConverter.ToInt64(bytes, 0); } } public ushort CheckSum { get; set; } /// /// the RealtimeCounter in the packet header is a 6 byte field /// for convenience we'll use a long to interact with it /// even though we are only using 6 bytes /// /// public void SetRTC(long rtc) { var bytes = GetRTCBytes(rtc); Buffer.BlockCopy(bytes, 0, RTC, 0, RTC.Length); } private const int RTC_SIZE_BYTES = 6; public static byte[] GetRTCBytes(long rtc) { var s = rtc.ToString("X"); var buffer = new byte[RTC_SIZE_BYTES]; for (int i = 0; i < RTC_SIZE_BYTES; i++) { string sVal = s.Substring(i * 2, 2); var val = Convert.ToInt16(sVal, 16); buffer[buffer.Length - 1 - i] = BitConverter.GetBytes(val)[0]; } return buffer; } public PacketHeader(DataFileDataTypes dataType) { DataType = PacketHeaderValueAttribute.GetPacketHeaderValue(dataType); } public PacketHeader(byte[] bytes) { if (null == bytes) { throw new NullReferenceException("no bytes received"); } if (PACKET_HEADER_LENGTH != bytes.Length) { throw new Exception($"Expected {PACKET_HEADER_LENGTH} bytes, received: {bytes.Length}"); } PacketSyncPattern = BitConverter.ToUInt16(bytes, 0); if (PacketSyncPattern != EXPECTED_SYNC_PATTERN) { System.Diagnostics.Trace.WriteLine("Expected sync pattern not found"); } ChannelId = BitConverter.ToUInt16(bytes, 2); PacketLength = BitConverter.ToUInt32(bytes, 4); DataLength = BitConverter.ToUInt32(bytes, 8); DataVersion = bytes[12]; SequenceNum = bytes[13]; PacketFlags = bytes[14]; DataType = bytes[15]; RTC = new byte[6]; Array.Copy(bytes, 16, RTC, 0, 6); CheckSum = BitConverter.ToUInt16(bytes, 22); var computedCRC = ComputeCheckSum(); if (CheckSum != computedCRC) { System.Diagnostics.Trace.WriteLine("Checksum doesn't match"); } } public byte[] GetBytes() { using (var sw = new MemoryStream()) { using (var bw = new BinaryWriter(sw)) { bw.Write(PacketSyncPattern); bw.Write(ChannelId); bw.Write(PacketLength); bw.Write(DataLength); bw.Write(DataVersion); bw.Write(SequenceNum); bw.Write(PacketFlags); bw.Write(DataType); bw.Write(RTC); bw.Write(ComputeCheckSum()); } return sw.ToArray(); } } public void SetDataVersion(DataTypeVersion version) { DataVersion = PacketHeaderValueAttribute.GetPacketHeaderValue(version); } public void SetPacketFlags(bool SecondaryHeaderPresent, bool SecondaryHeaderTime, bool RTCSyncerror, bool DataOverflow, SecondaryHeaderTimeFormat fmt, DataCheckSumType checkSum ) { var bitArray = new BitArray(new[] { PacketFlags }); bitArray[7] = SecondaryHeaderPresent; bitArray[6] = SecondaryHeaderTime; bitArray[5] = RTCSyncerror; bitArray[4] = DataOverflow; var byteValue = new BitArray(new[] { PacketHeaderValueAttribute.GetPacketHeaderValue(fmt) }); bitArray[3] = byteValue[0]; bitArray[2] = byteValue[1]; byteValue = new BitArray(new[] { PacketHeaderValueAttribute.GetPacketHeaderValue(checkSum) }); bitArray[1] = byteValue[0]; bitArray[0] = byteValue[1]; var bytes = new byte[1]; bitArray.CopyTo(bytes, 0); PacketFlags = bytes[0]; } public ushort ComputeCheckSum() { byte[] bytesToCompute; using (var ms = new MemoryStream()) { using (var bw = new BinaryWriter(ms)) { bw.Write(PacketSyncPattern); bw.Write(ChannelId); bw.Write(PacketLength); bw.Write(DataLength); bw.Write(DataVersion); bw.Write(SequenceNum); bw.Write(PacketFlags); bw.Write(DataType); bw.Write(RTC); } bytesToCompute = ms.ToArray(); } return Utils.Utils.GetCheckSum16(bytesToCompute); } public const int PACKET_HEADER_LENGTH = 24; } public interface IPacketHeader { ushort PacketSyncPattern { get; set; } ushort ChannelId { get; set; } uint PacketLength { get; set; } uint DataLength { get; set; } byte DataVersion { get; set; } byte SequenceNum { get; set; } [Browsable(false)] byte PacketFlags { get; } bool SecondaryHeaderPresent { get; set; } bool IPTSTimeSource { get; set; } bool RTCSyncError { get; set; } PacketHeader.SecondaryHeaderTimeFormats SecondaryHeaderTimeFormat { get; set; } bool DataOverflowError { get; set; } PacketHeader.DataCheckSumPresences CheckSumPresence { get; set; } [Browsable(false)] byte DataType { get; set; } DataFileDataTypes DataFileType { get; } [Browsable(false)] byte[] RTC { get; set; } long RTCLong { get; } ushort CheckSum { get; set; } void SetRTC(long rtc); void SetDataVersion(DataTypeVersion version); void SetPacketFlags(bool SecondaryHeaderPresent, bool SecondaryHeaderTime, bool RTCSyncerror, bool DataOverflow, SecondaryHeaderTimeFormat fmt, DataCheckSumType checkSum ); byte[] GetBytes(); ushort ComputeCheckSum(); } }