using System; using System.Collections.Generic; namespace DTS.DASLib.Command.SLICE.RealtimeCommands { /// /// this class was ported from FWTU RealtimeCommands, it appears almost verbatim to there /// public class UDPRealtimeByteConverter { public enum UDP_BYTE_INDEX { PKT_PATTERN = 0, // u16 CHANNEL_ID = 2, // u16 PKT_LEN = 4, // u32 DATA_LEN = 8, // u32 DATA_TYPE_VER = 12, // u8 SEQ_NUMBER = 13, // u8 PKT_FLAGS = 14, // u8 DATA_TYPE = 15, // u8 REL_TIME32 = 16, // u32 of 48 REL_TIME16 = 20, // u16 HDR_CRC16 = 22, // u16 PTP_U32_LSW = 24, // u32 PTP_U32_MSW = 28, // u32 RSV_U16 = 32, // u32 HDR2CRC16 = 34, // u16 CSDW = 36, // u32 DATA_START = 40, // data start address } // This is list of data type for UDP to support public enum UDP_DATA_TYPE { // 0x21 for analog format 1. 0x01 = CGDP format 1 (setup record). 0x12 = Time Data, Format 2 (PTP time) CGDP_TYPE = 0x01, // Setup XML record. 1. Setup Record, periodic message sent out. TIME_DATA_PTP = 0x12, // Time data, format 2. Periodic message. ANALOG_DATA_FORMAT_1 = 0x21, // Analog data format 3. Periodic message. } public ushort PacketPattern { get; private set; } public ushort DataChannelID { get; private set; } public uint PacketLength { get; private set; } /// /// careful if you use this, it's not the same as /// RtData.Length ... /// public uint DataLength { get; private set; } public byte DataTypeVersion { get; private set; } public byte SequenceNumber { get; private set; } public byte PacketFlags { get; private set; } public byte DataType { get; private set; } public uint RelativeTime32 { get; private set; } public ushort RelativeTime16 { get; private set; } public ushort HdrCrc16 { get; private set; } public uint PtpTimeStampSec { get; private set; } public uint PtpTimeStampNsec { get; private set; } public uint Hdr2Crc16 { get; private set; } public uint ChannelMask { get; private set; } public ulong UdpSampleCount { get; private set; } public ushort[] RtData { get; private set; } public uint[] Channels { get; private set; } public byte SequenceNumberPrev { get; private set; } public UDPRealtimeByteConverter(byte[] bytes) { // TBD: Currently expect 36byte header. If simplified version with 24Byte, // we have to account for the right offset. RTC will be used then. PacketPattern = GetUShort(bytes, (int)UDP_BYTE_INDEX.PKT_PATTERN); DataChannelID = GetUShort(bytes, (int)UDP_BYTE_INDEX.CHANNEL_ID); PacketLength = GetUInt(bytes, (int)UDP_BYTE_INDEX.PKT_LEN); DataLength = GetUInt(bytes, (int)UDP_BYTE_INDEX.DATA_LEN); DataTypeVersion = GetByte(bytes, (int)UDP_BYTE_INDEX.DATA_TYPE_VER); SequenceNumber = GetByte(bytes, (int)UDP_BYTE_INDEX.SEQ_NUMBER); PacketFlags = GetByte(bytes, (int)UDP_BYTE_INDEX.PKT_FLAGS); DataType = GetByte(bytes, (int)UDP_BYTE_INDEX.DATA_TYPE); // 0x21 for analog format 1. 0x01 = CGDP format 1 (setup record). 0x12 = Time Data, Format 2 (PTP time) RelativeTime32 = GetUInt(bytes, (int)UDP_BYTE_INDEX.REL_TIME32); RelativeTime16 = GetUShort(bytes, (int)UDP_BYTE_INDEX.REL_TIME16); HdrCrc16 = GetUShort(bytes, (int)UDP_BYTE_INDEX.HDR_CRC16); PtpTimeStampSec = GetUInt(bytes, (int)UDP_BYTE_INDEX.PTP_U32_MSW); PtpTimeStampNsec = GetUInt(bytes, (int)UDP_BYTE_INDEX.PTP_U32_LSW); Hdr2Crc16 = GetUShort(bytes, (int)UDP_BYTE_INDEX.HDR2CRC16); if (DataType == (int)UDP_DATA_TYPE.ANALOG_DATA_FORMAT_1) { RtData = new ushort[(DataLength - 4) / 2]; // ushort[(bytes.Length - (int)UDP_BYTE_INDEX.DATA_START) / 2]; var mychannels = new List(); for (var i = 0; i < 6; i++) // var length = dataLength; { //if (ba.Get(i)) assume all 6 channels if UDP. { mychannels.Add(Convert.ToUInt32(i)); } } Channels = mychannels.ToArray(); UdpSampleCount = Convert.ToUInt64(RtData.Length / Channels.Length); SequenceNumberPrev = SequenceNumber; // TBD: check for pktFlag if the optional 2nd header is being used or not. If not, // we can start the data from UDP_BYTE_INDEX.PTP_U32_LSW for (var idx = 0; idx < RtData.Length; idx++) { RtData[idx] = GetRTUShort(bytes, (int)(UDP_BYTE_INDEX.DATA_START + idx * 2)); RtData[idx] ^= 0x8000; } } else { // TBD for other packet types. RtData = null; } } private static ulong GetULong(byte[] bytes, int offset) { return (ulong)bytes[offset + 7] << 0 | (ulong)bytes[offset + 6] << 8 | (ulong)bytes[offset + 5] << 16 | (ulong)bytes[offset + 4] << 24 | (ulong)bytes[offset + 3] << 32 | (ulong)bytes[offset + 2] << 40 | (ulong)bytes[offset + 1] << 48 | (ulong)bytes[offset + 0] << 56; } private static ushort GetUShort(byte[] bytes, int offset) { return (ushort)(bytes[offset + 1] | bytes[offset + 0] << 8); } private static byte GetByte(byte[] bytes, int offset) { return bytes[offset]; } private static uint GetUInt(byte[] bytes, int offset) { return (uint)bytes[offset + 3] << 0 | (uint)bytes[offset + 2] << 8 | (uint)bytes[offset + 1] << 16 | (uint)bytes[offset + 0] << 24; } /// /// data apparently has a different byte order than parameters, so we have to /// rearrange byte order for parameters but not data. /// /// /// /// private static ushort GetRTUShort(byte[] bytes, int offset) { return (ushort)(bytes[offset + 0] | bytes[offset + 1] << 8); } } }