using DTS.Serialization.IRIGCH10.Enums; using System; using System.Collections; namespace DTS.Serialization.IRIGCH10 { /// /// implements the PCM/Pulse Control Modulation packet for CH 10 /// public class PCMPacket : AbstractDataPacket, IDataPacket { private byte [] ChannelSpecificData; public PCMPacket() : base(DataFileDataTypes.PCMDataFormat1) { ChannelSpecificData = new byte[4]; _dataBytes = new byte[ChannelSpecificData.Length]; } /// /// Intra-Packet Header (IPH). (Bit 30) indicates if Intra-Packet Headers (IntraPacket Time Stamp and Intra-Packet Data Header) are inserted before each /// minor frame. Intra-Packet Headers are only optional because of the mode /// selection. This determines whether Intra-Packet Headers are included or /// omitted. /// false = Intra-Packet Headers are omitted for Throughput Mode. /// true = Intra-Packet Headers are required for Packed Data and Unpacked Data /// modes. /// public bool IntraPacketHeader { get { var bitArray = new BitArray(ChannelSpecificData); return bitArray[30]; } set { var bitArray = new BitArray(ChannelSpecificData); bitArray[30] = value; bitArray.CopyTo(ChannelSpecificData, 0); } } /// /// Major Frame Indicator (MA). (Bit 29) indicates if the first word in the packet is /// the beginning of a major frame. Not valid for Throughput Mode. /// false = First word is not the beginning of a major frame. /// true = First word is the beginning of a major frame. /// public bool MajorFrameIndicator { get { var bitArray = new BitArray(ChannelSpecificData); return bitArray[29]; } set { var bitArray = new BitArray(ChannelSpecificData); bitArray[29] = value; bitArray.CopyTo(ChannelSpecificData, 0); } } /// /// Minor Frame Indicator (MI). (Bit 28) indicates if the first word in the packet is /// the beginning of a minor frame. Not valid for Throughput Mode. /// false = First word is not the beginning of a minor frame. /// true = First word is the beginning of a minor frame. /// public bool MinorFrameIndicator { get { var bitArray = new BitArray(ChannelSpecificData); return bitArray[28]; } set { var bitArray = new BitArray(ChannelSpecificData); bitArray[28] = value; bitArray.CopyTo(ChannelSpecificData, 0); } } /// /// Indicate Minor Frame Status /// true = Minor Frame Lock /// false = Minor Frame Check (after losing lock) /// public bool MinorFrameLockStatus { get { var bitArray = new BitArray(ChannelSpecificData); return bitArray[27] && bitArray[26]; } set { var bitArray = new BitArray(ChannelSpecificData); bitArray[27] = true; bitArray[26] = value; bitArray.CopyTo(ChannelSpecificData, 0); } } /// /// true - Major Frame Lock /// false - Major Frame Check (after losing Lock) /// public bool MajorFrameStatus { get { var bitArray = new BitArray(ChannelSpecificData); return bitArray[25] && bitArray[24]; } set { var bitArray = new BitArray(ChannelSpecificData); bitArray[25] = true; bitArray[24] = value; bitArray.CopyTo(ChannelSpecificData, 0); } } /// /// true = 32Bit Alignment Mode /// false = 16Bit Alignment Mode /// public bool AlignmentMode { get { var bitArray = new BitArray(ChannelSpecificData); return bitArray[21]; } set { var bitArray = new BitArray(ChannelSpecificData); bitArray[21] = value; bitArray.CopyTo(ChannelSpecificData, 0); } } /// /// Throughput DataMode enabled or not /// public bool ThroughputDataMode { get { var bitArray = new BitArray(ChannelSpecificData); return bitArray[20]; } set { var bitArray = new BitArray(ChannelSpecificData); bitArray[20] = value; bitArray.CopyTo(ChannelSpecificData, 0); } } public bool PackedData { get { var bitArray = new BitArray(ChannelSpecificData); return bitArray[19]; } set { var bitArray = new BitArray(ChannelSpecificData); bitArray[19] = value; bitArray.CopyTo(ChannelSpecificData, 0); } } public bool UnpackedData { get { var bitArray = new BitArray(ChannelSpecificData); return bitArray[18]; } set { var bitArray = new BitArray(ChannelSpecificData); bitArray[18] = value; bitArray.CopyTo(ChannelSpecificData, 0); } } /// /// contains an 18-bit binary value /// representing the Word offset into the major frame for the first data word in the /// packet. Not valid for Packed or Throughput Mode. /// public byte[] SyncOffset { get { var output = new byte[2]; var bitArray = new BitArray(ChannelSpecificData); var bitArray2 = new BitArray(output); for (int i = 0; i <= 17; i++) { bitArray2[i] = bitArray[i]; } bitArray2.CopyTo(output, 0); return output; } set { var bitArray = new BitArray(ChannelSpecificData); var bitArray2 = new BitArray(value); for (int i = 0; i <= 17; i++) { bitArray[i] = bitArray2[i]; } bitArray.CopyTo(ChannelSpecificData, 0); } } public readonly byte[] FrameSync = new byte[] { 0x90, 0xEB }; //private readonly byte[] FrameSync = new byte[] { 0x90, 0xEB, 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x90, 0xEB }; /// /// adds data in unpacked 16 bit alignment into the data buffer, resizing as needed /// /// public void AddUnpacked16BitData(ushort[] data, long timeStamp, bool bFirst) { var intraPacketBytes = GetIntraPacketTimeStampBytes(timeStamp); var intraHeaderBytes = GetIntraPacketHeader(); var insertSpot = 0; //for some reason the spec seems to call out a different first order than all subsequent data sequences. //the first sequence has a timestamp at the front, while all subsequent do not, but have a trailer timestamp. if (bFirst) { var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + FrameSync.Length + intraPacketBytes.Length + intraHeaderBytes.Length]; Buffer.BlockCopy(_dataBytes, 0, newBuffer, insertSpot, _dataBytes.Length); insertSpot += _dataBytes.Length; Buffer.BlockCopy(intraPacketBytes, 0, newBuffer, insertSpot, intraPacketBytes.Length); insertSpot += intraPacketBytes.Length; Buffer.BlockCopy(intraHeaderBytes, 0, newBuffer, insertSpot, intraHeaderBytes.Length); insertSpot += intraHeaderBytes.Length; Buffer.BlockCopy(FrameSync, 0, newBuffer, insertSpot, FrameSync.Length); insertSpot += FrameSync.Length; Buffer.BlockCopy(data, 0, newBuffer, insertSpot, data.Length * 2); } else { var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + intraPacketBytes.Length + intraHeaderBytes.Length]; Buffer.BlockCopy(_dataBytes, 0, newBuffer, insertSpot, _dataBytes.Length); insertSpot += _dataBytes.Length; Buffer.BlockCopy(data, 0, newBuffer, insertSpot, data.Length * 2); insertSpot += data.Length * 2; Buffer.BlockCopy(intraPacketBytes, 0, newBuffer, insertSpot, intraPacketBytes.Length); insertSpot += intraPacketBytes.Length; Buffer.BlockCopy(intraHeaderBytes, 0, newBuffer, insertSpot, intraHeaderBytes.Length); } } /// /// adds data in unpacked 16 bit alignment into the data buffer, resizing as needed /// /// public void AddPacked16BitData(ushort[] data, long timeStamp, bool bFirst) { var intraPacketBytes = GetIntraPacketTimeStampBytes(timeStamp); var intraHeaderBytes = GetIntraPacketHeader(); var insertSpot = 0; //for some reason the spec seems to call out a different first order than all subsequent data sequences. //the first sequence has a timestamp at the front, while all subsequent do not, but have a trailer timestamp. if (bFirst) { var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + FrameSync.Length + intraPacketBytes.Length + intraHeaderBytes.Length]; Buffer.BlockCopy(_dataBytes, 0, newBuffer, insertSpot, _dataBytes.Length); insertSpot += _dataBytes.Length; Buffer.BlockCopy(intraPacketBytes, 0, newBuffer, insertSpot, intraPacketBytes.Length); insertSpot += intraPacketBytes.Length; Buffer.BlockCopy(intraHeaderBytes, 0, newBuffer, insertSpot, intraHeaderBytes.Length); insertSpot += intraHeaderBytes.Length; Buffer.BlockCopy(FrameSync, 0, newBuffer, insertSpot, FrameSync.Length); insertSpot += FrameSync.Length; Buffer.BlockCopy(data, 0, newBuffer, insertSpot, data.Length * 2); } else { var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + intraPacketBytes.Length + intraHeaderBytes.Length]; Buffer.BlockCopy(_dataBytes, 0, newBuffer, insertSpot, _dataBytes.Length); insertSpot += _dataBytes.Length; Buffer.BlockCopy(data, 0, newBuffer, insertSpot, data.Length * 2); insertSpot += data.Length * 2; Buffer.BlockCopy(intraPacketBytes, 0, newBuffer, insertSpot, intraPacketBytes.Length); insertSpot += intraPacketBytes.Length; Buffer.BlockCopy(intraHeaderBytes, 0, newBuffer, insertSpot, intraHeaderBytes.Length); } } private byte [] GetIntraPacketHeader() { var array = new BitArray(new byte[2]); //bits 15-14 minor frame status //00,01 reserved //10 minor frame check //11 minor frame lock //bits 13-12 major frame status // 00 - major frame not locked // 01 - reserved // 10 major frame check // 11 major frame lock array.Set(15, true); array.Set(14, true); array.Set(12, true); array.Set(13, true); var output = new byte[2]; array.CopyTo(output, 0); return output; } private byte [] GetIntraPacketTimeStampBytes(long timeStamp) { var output = new byte[8]; var stamp = IRIGCH10.PacketHeader.GetRTCBytes(timeStamp); Buffer.BlockCopy(output, 0, stamp, 0, stamp.Length); return output; } /// /// adds data in throughput mode to the packet, resizing the data buffer in the process /// [throughput mode as opposed to a packed/or aligned mode] /// /// //public void AddThroughputData(ushort[] data) //{ // var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + FrameSync.Length]; // Buffer.BlockCopy(_dataBytes, 0, newBuffer, 0, _dataBytes.Length); // Buffer.BlockCopy(FrameSync, 0, newBuffer, _dataBytes.Length, FrameSync.Length); // Buffer.BlockCopy(data, 0, newBuffer, _dataBytes.Length + FrameSync.Length, data.Length * 2); // _dataBytes = newBuffer; //} public override void ComputeCheckSum() { RefreshChannelSpecificDataInDataBytes(); base.ComputeCheckSum(); } public override byte[] GetBytes() { RefreshChannelSpecificDataInDataBytes(); return base.GetBytes(); } private void RefreshChannelSpecificDataInDataBytes() { //make sure ChannelSpecificData is set ... Buffer.BlockCopy(ChannelSpecificData, 0, _dataBytes, 0, ChannelSpecificData.Length); } } }