init
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10.Packets
|
||||
{
|
||||
public class AnalogDataFormat1Packet : AbstractDataPacket, IDataPacket
|
||||
{
|
||||
|
||||
public DateTime LocalTimeOfFirstSample
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
//bit 28
|
||||
public bool Same
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
return bits[28];
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
b[28] = value;
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
//bits 27-24
|
||||
public int Factor
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
return Utils.Utils.BitArrayToInt32(bits, 24, 27);
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
Utils.Utils.SetBits(b, (uint)value, 24, 27);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
//bits 23-16
|
||||
public int TotChan
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
return Utils.Utils.BitArrayToInt32(bits, 16, 23);
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
Utils.Utils.SetBits(b, (uint)value, 16, 23);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
//bits 15-8
|
||||
public long Subchan
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
return Utils.Utils.BitArrayToInt32(bits, 8, 15);
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
Utils.Utils.SetBits(b, (uint)value, 8, 15);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
//bits 7-2
|
||||
public long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
return Utils.Utils.BitArrayToInt32(bits, 2, 7);
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
Utils.Utils.SetBits(b, (uint)value, 2, 7);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
public enum Modes
|
||||
{
|
||||
DataIsPacked,
|
||||
DataIsUnpackedLSBPadded,
|
||||
Reserved,
|
||||
DataIsUnpackedMSBPadded
|
||||
}
|
||||
//bits 1-0
|
||||
public Modes Mode
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
var mode = Utils.Utils.BitArrayToInt32(bits, 0, 1);
|
||||
switch (mode)
|
||||
{
|
||||
case 0: return Modes.DataIsPacked;
|
||||
case 1: return Modes.DataIsUnpackedLSBPadded;
|
||||
case 3: return Modes.DataIsUnpackedMSBPadded;
|
||||
case 2:
|
||||
default: return Modes.Reserved;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
Utils.Utils.SetBits(b, (uint)value, 0, 1);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
public SampleData[] Samples = new SampleData[0];
|
||||
public class SampleData
|
||||
{
|
||||
public short[] ChannelData { private set; get; }
|
||||
protected SampleData() { }
|
||||
public SampleData(short[] channels)
|
||||
{
|
||||
ChannelData = channels;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// it seems the EMC ch10 validation tool only supports CH10 106v5, so use this header value for the analog packet when in this mode
|
||||
/// whether to include secondary time header or not
|
||||
/// 33199 Add Time format 1 as an export option for CH 10 export
|
||||
/// </summary>
|
||||
private const byte DATA_VERSION_V105 = 0x01;
|
||||
|
||||
|
||||
private const byte DATA_VERSION_DASSAULT = 0x06;
|
||||
public AnalogDataFormat1Packet(int nanoseconds, int seconds,
|
||||
Chapter10File.GetNextSampleDelegate getNextSample, int totalChannels, long channelLength, long rtc, long numSamples, long currentSample, byte sequenceNumber,
|
||||
ushort channelId, bool includeSecondaryHeader) : base(Enums.DataFileDataTypes.AnalogDataFormat1, includeSecondaryHeader)
|
||||
{
|
||||
TotChan = totalChannels;
|
||||
Subchan = 0;
|
||||
Same = true;
|
||||
Factor = 0;
|
||||
Length = 16;
|
||||
Mode = Modes.DataIsUnpackedMSBPadded;
|
||||
|
||||
var dataLength = Convert.ToUInt32(4 + sizeof(ushort) * totalChannels * numSamples); ;
|
||||
var offset = CommonHeaderWork(channelId, includeSecondaryHeader ? DATA_VERSION_DASSAULT : DATA_VERSION_V105, sequenceNumber, rtc, dataLength, nanoseconds, seconds);
|
||||
|
||||
for (var sampleIdx = 0; sampleIdx < numSamples; sampleIdx++)
|
||||
{
|
||||
for (var chIdx = 0; chIdx < totalChannels; chIdx++)
|
||||
{
|
||||
var signed = getNextSample(chIdx);
|
||||
var unsigned = (ushort)(((signed - 0x8000 & 0x00FF) << 8) | ((signed - 0x8000 >> 8) & 0x00FF));
|
||||
var bytes = BitConverter.GetBytes(unsigned).Reverse().ToArray();
|
||||
Buffer.BlockCopy(bytes, 0, _dataBytes, offset, 2);
|
||||
offset += 2;
|
||||
}
|
||||
currentSample++;
|
||||
}
|
||||
}
|
||||
public AnalogDataFormat1Packet() : base(Enums.DataFileDataTypes.AnalogDataFormat1, true)
|
||||
{
|
||||
}
|
||||
public AnalogDataFormat1Packet(byte[] bytes) : base(bytes)
|
||||
{
|
||||
var offset = IRIGCH10.PacketHeader.PACKET_HEADER_LENGTH;
|
||||
|
||||
if (PacketHeader.SecondaryHeaderPresent)
|
||||
{
|
||||
var secondaryHeaderBytes = new byte[SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH];
|
||||
Buffer.BlockCopy(bytes, offset,
|
||||
secondaryHeaderBytes, 0, SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH);
|
||||
var secondaryHeader = new SecondaryTimeFormatHeader(secondaryHeaderBytes);
|
||||
LocalTimeOfFirstSample = secondaryHeader.LocalTime;
|
||||
offset += SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(bytes, offset);
|
||||
offset += sizeof(uint);
|
||||
var numChannels = TotChan;
|
||||
var sizeOf1SampleForAllChannels = sizeof(ushort) * numChannels;
|
||||
//There's a CSDW in the data section, then all ADC data. CSDW is uint, 4 bytes
|
||||
var numSamples = (PacketHeader.DataLength - 4) / sizeOf1SampleForAllChannels;
|
||||
|
||||
Samples = new SampleData[numSamples];
|
||||
for (var i = 0; i < Samples.Length; i++)
|
||||
{
|
||||
var channels = GetChannels(bytes, offset, numChannels);
|
||||
Samples[i] = new SampleData(channels);
|
||||
offset += sizeOf1SampleForAllChannels;
|
||||
}
|
||||
}
|
||||
|
||||
private short[] GetChannels(byte[] bytes, int sampleStart, int numChannels)
|
||||
{
|
||||
var ret = new short[numChannels];
|
||||
for (var i = 0; i < numChannels; i++)
|
||||
{
|
||||
var unsignedBytes = new byte[2];
|
||||
Buffer.BlockCopy(bytes, sampleStart + i * 2, unsignedBytes, 0, 2);
|
||||
//we have to change the byte order here
|
||||
var unsigned = BitConverter.ToUInt16(new[] { unsignedBytes[1], unsignedBytes[0] }, 0);
|
||||
//go from unsigned to signed
|
||||
var adc = (short)((((unsigned & 0x00FF) << 8) | ((unsigned >> 8) & 0x00FF)) + 0x8000);
|
||||
ret[i] = adc;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
211
Common/DTS.Common.Serialization/IRIGCH10/Packets/IDataPacket.cs
Normal file
211
Common/DTS.Common.Serialization/IRIGCH10/Packets/IDataPacket.cs
Normal file
@@ -0,0 +1,211 @@
|
||||
using DTS.Serialization.IRIGCH10.Enums;
|
||||
using DTS.Serialization.IRIGCH10.Packets;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10
|
||||
{
|
||||
/// <summary>
|
||||
/// this is the interface that all datapackets implement, it defines how packets can be interacted with in general
|
||||
/// </summary>
|
||||
public interface IDataPacket
|
||||
{
|
||||
/// <summary>
|
||||
/// all chapter 10 packets have a packet header
|
||||
/// </summary>
|
||||
IPacketHeader PacketHeader { get; }
|
||||
/// <summary>
|
||||
/// computes the checksum for the datapacket data
|
||||
/// </summary>
|
||||
uint ComputeCheckSum();
|
||||
/// <summary>
|
||||
/// returns all bytes for the packet
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
byte[] GetBytes();
|
||||
/// <summary>
|
||||
/// sets the Realtime Counter (10 MHZ) for the packet
|
||||
/// </summary>
|
||||
/// <param name="rtc"></param>
|
||||
void SetRTC(long rtc);
|
||||
/// <summary>
|
||||
/// sets the DataVersion of the packet
|
||||
/// (part of the packet header)
|
||||
/// </summary>
|
||||
/// <param name="version"></param>
|
||||
void SetDataVersion(DataTypeVersion version);
|
||||
|
||||
/// <summary>
|
||||
/// sets the channel id for the packet (part of packet header)
|
||||
/// </summary>
|
||||
/// <param name="channelID"></param>
|
||||
void SetChannelID(ushort channelID);
|
||||
/// <summary>
|
||||
/// sets the sequence number for the packet,
|
||||
/// in general should be increasing and flip back to 0
|
||||
/// after max value
|
||||
/// </summary>
|
||||
/// <param name="seq"></param>
|
||||
void SetSequenceNumber(ushort seq);
|
||||
}
|
||||
/// <summary>
|
||||
/// this is the general base class all packets extend, it
|
||||
/// has common features like computing the checksum, setting the
|
||||
/// packet specific Channel Data Word, etc
|
||||
/// </summary>
|
||||
public abstract class AbstractDataPacket
|
||||
{
|
||||
protected void SetCSDWBit(int bit, bool value)
|
||||
{
|
||||
if (bit <0 || bit > 31)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!value)
|
||||
{
|
||||
//and with all ones except for the bit in question
|
||||
ChannelSpecificDataWord &= ~(1u << bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
//or with all 0s except for bit in question
|
||||
ChannelSpecificDataWord |= (1u << bit);
|
||||
}
|
||||
}
|
||||
protected bool GetCSDWBit(int bit)
|
||||
{
|
||||
if (bit < 0 || bit > 31) { return false; }
|
||||
return (ChannelSpecificDataWord & (1u << bit)) != 0;
|
||||
}
|
||||
protected int CommonHeaderWork(ushort channelId, byte dataVersion,
|
||||
byte sequenceNumber, long rtc, uint dataLength, int nanoseconds, int seconds)
|
||||
{
|
||||
PacketHeader.ChannelId = channelId;
|
||||
PacketHeader.DataVersion = dataVersion;
|
||||
PacketHeader.SequenceNum = sequenceNumber;
|
||||
PacketHeader.IPTSTimeSource = PacketHeader.SecondaryHeaderPresent;
|
||||
PacketHeader.RTCSyncError = false;
|
||||
PacketHeader.SecondaryHeaderTimeFormat = IRIGCH10.PacketHeader.SecondaryHeaderTimeFormats.IEEE1588;
|
||||
PacketHeader.DataOverflowError = false;
|
||||
PacketHeader.CheckSumPresence = IRIGCH10.PacketHeader.DataCheckSumPresences.NotPresent;
|
||||
PacketHeader.SetRTC(rtc);
|
||||
PacketHeader.DataLength = dataLength;
|
||||
|
||||
PacketHeader.PacketLength = PacketHeader.DataLength + IRIGCH10.PacketHeader.PACKET_HEADER_LENGTH;
|
||||
if (PacketHeader.SecondaryHeaderPresent)
|
||||
{
|
||||
PacketHeader.PacketLength += SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH;
|
||||
}
|
||||
if (0 != PacketHeader.PacketLength % 4)
|
||||
{
|
||||
var pad = 4 - PacketHeader.PacketLength % 4;
|
||||
//pad out packet length to a multiple of 4 ...
|
||||
PacketHeader.PacketLength += pad;
|
||||
}
|
||||
_dataBytes = new byte[PacketHeader.PacketLength - IRIGCH10.PacketHeader.PACKET_HEADER_LENGTH];
|
||||
|
||||
var offset = 0;
|
||||
|
||||
if (PacketHeader.SecondaryHeaderPresent)
|
||||
{
|
||||
var secondaryHeader = SecondaryTimeFormatHeader.GetBytes(nanoseconds, seconds);
|
||||
|
||||
Buffer.BlockCopy(secondaryHeader, 0, _dataBytes, offset, secondaryHeader.Length);
|
||||
offset += secondaryHeader.Length;
|
||||
}
|
||||
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
Buffer.BlockCopy(channelSpecificDataWord, 0, _dataBytes, offset, channelSpecificDataWord.Length);
|
||||
offset += channelSpecificDataWord.Length;
|
||||
return offset;
|
||||
}
|
||||
private uint _ChannelSpecificDataWork = 0;
|
||||
[Browsable(false)]
|
||||
public uint ChannelSpecificDataWord
|
||||
{
|
||||
get => _ChannelSpecificDataWork;
|
||||
protected set => _ChannelSpecificDataWork = value;
|
||||
}
|
||||
[Browsable(false)]
|
||||
public IPacketHeader PacketHeader { get; protected set; }
|
||||
public uint ComputeCheckSum()
|
||||
{
|
||||
return Utils.Utils.GetCheckSum32(_dataBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sets the sequence number for the packet
|
||||
/// </summary>
|
||||
/// <param name="seq"></param>
|
||||
public void SetSequenceNumber(ushort seq)
|
||||
{
|
||||
PacketHeader.SequenceNum = BitConverter.GetBytes(seq)[0];
|
||||
}
|
||||
|
||||
private long _rtc;
|
||||
/// <summary>
|
||||
/// returns the Realtime Counter (10Mhz) value for the packet
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public long GetRTC() { return _rtc; }
|
||||
/// <summary>
|
||||
/// sets the Realtime Counter (10Mhz) value for the packet
|
||||
/// </summary>
|
||||
/// <param name="rtc"></param>
|
||||
public void SetRTC(long rtc)
|
||||
{
|
||||
_rtc = rtc;
|
||||
PacketHeader.SetRTC(rtc);
|
||||
|
||||
}
|
||||
|
||||
public const long BASE_RTC = 141989612500056L;
|
||||
/// <summary>
|
||||
/// returns all bytes for the packet
|
||||
/// is virtual so extending classes can define their own behavior as needed
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual byte[] GetBytes()
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
using (var bw = new BinaryWriter(ms))
|
||||
{
|
||||
bw.Write(PacketHeader.GetBytes());
|
||||
bw.Write(_dataBytes);
|
||||
}
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
protected AbstractDataPacket(DataFileDataTypes dataType, bool secondaryHeaderPresent)
|
||||
{
|
||||
PacketHeader = new PacketHeader(dataType);
|
||||
PacketHeader.SecondaryHeaderPresent = secondaryHeaderPresent;
|
||||
}
|
||||
protected AbstractDataPacket(byte[] bytes)
|
||||
{
|
||||
var header = new byte[24];
|
||||
Buffer.BlockCopy(bytes, 0, header, 0, 24);
|
||||
PacketHeader = new PacketHeader(header);
|
||||
_dataBytes = new byte[PacketHeader.DataLength];
|
||||
var length = _dataBytes.Length;
|
||||
var length2 = bytes.Length - 24;
|
||||
if (length2 < length) { length = length2; }
|
||||
Buffer.BlockCopy(bytes, 24, _dataBytes, 0, length);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(_dataBytes, 0);
|
||||
}
|
||||
|
||||
protected byte[] _dataBytes;
|
||||
public void SetDataVersion(DataTypeVersion version)
|
||||
{
|
||||
PacketHeader.SetDataVersion(version);
|
||||
}
|
||||
|
||||
public void SetChannelID(ushort channelID)
|
||||
{
|
||||
PacketHeader.ChannelId = channelID;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10.Packets
|
||||
{
|
||||
public interface ISecondaryTimeFormatHeader
|
||||
{
|
||||
int NanoSeconds { get; }
|
||||
int Seconds { get; }
|
||||
ushort Reserved { get; }
|
||||
ushort CheckSum { get; }
|
||||
DateTime LocalTime { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10.Packets
|
||||
{
|
||||
public interface ITransportStreamHeader
|
||||
{
|
||||
int MessageFormat { get; }
|
||||
int MessageType { get; }
|
||||
int SequenceNumber { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10.Packets
|
||||
{
|
||||
public class PCMDataPacket : AbstractDataPacket, IDataPacket
|
||||
{
|
||||
//Bit 30 Intra packet headers
|
||||
public bool HasIntraPacketHeader
|
||||
{
|
||||
get => GetCSDWBit(30);
|
||||
set => SetCSDWBit(30, value);
|
||||
}
|
||||
//Bit29 Major Frame Indicator
|
||||
//not applicable in throughput mode
|
||||
public bool IsMajorFrame
|
||||
{
|
||||
get => GetCSDWBit(29);
|
||||
set => SetCSDWBit(29, value);
|
||||
}
|
||||
//Bit28 IsMinorFrame
|
||||
//not applicable in throughput mode
|
||||
public bool IsMinorFrame
|
||||
{
|
||||
get => GetCSDWBit(28);
|
||||
set => SetCSDWBit(28, value);
|
||||
}
|
||||
public enum MinorFrameStatus
|
||||
{
|
||||
Reserved0 = 0, //00
|
||||
Reserved1 = 1, //01
|
||||
MinorFrameCheck = 2, //10
|
||||
MinorFrameLock = 3 //11
|
||||
}
|
||||
public enum MajorFrameStatus
|
||||
{
|
||||
MajorFrameNotLocked = 0, //00
|
||||
Reserved1 = 1, //01
|
||||
MajorFrameCheck = 2, //10
|
||||
MajorFrameLock = 3 //11
|
||||
}
|
||||
//bits 27-24
|
||||
//not applicable for throughput mode
|
||||
public MinorFrameStatus LockStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
var csdw = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(csdw);
|
||||
return (MinorFrameStatus)Utils.Utils.BitArrayToInt32(bits, 24, 27);
|
||||
}
|
||||
set
|
||||
{
|
||||
var iValue = (int)value;
|
||||
var csdw = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(csdw);
|
||||
Utils.Utils.SetBits(bits, (uint)iValue, 24, 27);
|
||||
var ret = new Byte[sizeof(uint)];
|
||||
bits.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
//bit 21
|
||||
public bool Is32BitAligned
|
||||
{
|
||||
get => GetCSDWBit(21);
|
||||
set => SetCSDWBit(21, value);
|
||||
}
|
||||
//bit 20
|
||||
public bool IsThroughputMode
|
||||
{
|
||||
get => GetCSDWBit(20);
|
||||
set => SetCSDWBit(20, value);
|
||||
}
|
||||
|
||||
//bit 19 packed mode
|
||||
public bool IsPackedMode
|
||||
{
|
||||
get => GetCSDWBit(19);
|
||||
set => SetCSDWBit(19, value);
|
||||
}
|
||||
//bit 18 unpacked mode
|
||||
public bool IsUnpackedMode
|
||||
{
|
||||
get => GetCSDWBit(18);
|
||||
set => SetCSDWBit(18, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// it seems the EMC ch10 validation tool only supports CH10 106v5, so use this header value for the analog packet when in this mode
|
||||
/// whether to include secondary time header or not
|
||||
/// 33199 Add Time format 1 as an export option for CH 10 export
|
||||
/// </summary>
|
||||
private const byte DATA_VERSION = 0x06;
|
||||
public PCMDataPacket(int nanoseconds, int seconds,
|
||||
Chapter10File.GetNextSampleDelegate getNextSample, int totalChannels, long channelLength, long rtc, long numSamples, long currentSample, byte sequenceNumber,
|
||||
ushort channelId, bool includeSecondaryHeader) : base(Enums.DataFileDataTypes.PCMDataFormat1, includeSecondaryHeader)
|
||||
{
|
||||
HasIntraPacketHeader = includeSecondaryHeader;
|
||||
IsMajorFrame = false;
|
||||
IsMinorFrame = false;
|
||||
LockStatus = MinorFrameStatus.Reserved0;
|
||||
IsThroughputMode = true;
|
||||
Is32BitAligned = false;
|
||||
IsPackedMode = false;
|
||||
IsUnpackedMode = false;
|
||||
|
||||
//4 bytes for CSDW, then 4 bytes for a PCM FRAMESYNC??? this isn't in the spec but f/w is using it
|
||||
var dataLength = Convert.ToUInt32(4 + 2 * totalChannels * numSamples + 4*numSamples);
|
||||
|
||||
var offset = CommonHeaderWork(channelId, DATA_VERSION, sequenceNumber, rtc, dataLength, nanoseconds, seconds);
|
||||
for (var sampleIdx = 0; sampleIdx < numSamples; sampleIdx++)
|
||||
{
|
||||
Buffer.BlockCopy(new byte[] { 0x6B, 0xFE, 0x40, 0x28 }, 0, _dataBytes, offset, 4);
|
||||
offset += 4;
|
||||
for (var chIdx = 0; chIdx < totalChannels; chIdx++)
|
||||
{
|
||||
var signed = getNextSample(chIdx);
|
||||
var unsigned = (ushort)(((signed - 0x8000 & 0x00FF) << 8) | ((signed - 0x8000 >> 8) & 0x00FF));
|
||||
var bytes = BitConverter.GetBytes(unsigned).Reverse().ToArray();
|
||||
Buffer.BlockCopy(bytes, 0, _dataBytes, offset, 2);
|
||||
offset += 2;
|
||||
}
|
||||
currentSample++;
|
||||
}
|
||||
}
|
||||
public PCMDataPacket() : base(Enums.DataFileDataTypes.PCMDataFormat1, true)
|
||||
{
|
||||
}
|
||||
public PCMDataPacket(byte[] bytes) : base (bytes)
|
||||
{
|
||||
|
||||
}
|
||||
public PCMDataPacket(bool _) : base(UDP_DATA)
|
||||
{
|
||||
}
|
||||
|
||||
private static readonly byte[] UDP_DATA = { 0x25, 0xeb, 0x03, 0x00, 0x98, 0x05, 0x00, 0x00, 0x74, 0x05, 0x00, 0x00,
|
||||
0x06, 0x65, 0xc4, 0x09, 0x21, 0xe5, 0x5d, 0xed, 0x07, 0x00, 0x83, 0x37, 0x42, 0x89, 0x77, 0x2a,
|
||||
0x4c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00, 0x10, 0x00, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x04, 0x80, 0xe3, 0x7f, 0xcf, 0x7f, 0xe1, 0x7f, 0xee, 0x7f, 0xea, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x07, 0x80, 0xe7, 0x7f, 0xcf, 0x7f, 0xe7, 0x7f, 0xf3, 0x7f, 0xee, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x04, 0x80, 0xe5, 0x7f, 0xcd, 0x7f, 0xe2, 0x7f, 0xf1, 0x7f, 0xed, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x05, 0x80, 0xe9, 0x7f, 0xcd, 0x7f, 0xe2, 0x7f, 0xf1, 0x7f, 0xeb, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x07, 0x80, 0xe9, 0x7f, 0xcd, 0x7f, 0xec, 0x7f, 0xf3, 0x7f, 0xf1, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x06, 0x80, 0xe3, 0x7f, 0xce, 0x7f, 0xe6, 0x7f, 0xee, 0x7f, 0xee, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x02, 0x80, 0xe1, 0x7f, 0xc9, 0x7f, 0xdc, 0x7f, 0xec, 0x7f, 0xea, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x04, 0x80, 0xe7, 0x7f, 0xc5, 0x7f, 0xe7, 0x7f, 0xef, 0x7f, 0xed, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x05, 0x80, 0xed, 0x7f, 0xca, 0x7f, 0xe3, 0x7f, 0xf0, 0x7f, 0xf2, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x04, 0x80, 0xe5, 0x7f, 0xca, 0x7f, 0xe2, 0x7f, 0xec, 0x7f, 0xec, 0x7f, 0x6b, 0xfe, 0x40, 0x28,
|
||||
0x04, 0x80, 0xe6, 0x7f, 0xcc, 0x7f, 0xe5, 0x7f, 0xec, 0x7f, 0xed, 0x7f, 0x6b, 0xfe, 0x40, 0x28 };/*,
|
||||
0x06, 80, e7, 7f, cc, 7f, e6, 7f, f0, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e7, 7f, d2, 7f, e4, 7f, f0, 7f, f2, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, eb, 7f, cc, 7f, e7, 7f, e9, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, e7, 7f, d1, 7f, ed, 7f, ef, 7f, f1, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, ec, 7f, d7, 7f, e9, 7f, f2, 7f, ee, 7f, 6b, fe, 40, 28,
|
||||
0x07, 80, ed, 7f, cf, 7f, e7, 7f, f1, 7f, f0, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e7, 7f, d0, 7f, e6, 7f, f0, 7f, f0, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, e7, 7f, cf, 7f, e2, 7f, f0, 7f, ee, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e6, 7f, c8, 7f, dc, 7f, ef, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, ec, 7f, cc, 7f, e4, 7f, f2, 7f, f0, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, eb, 7f, c9, 7f, e8, 7f, f1, 7f, ec, 7f, 6b, fe, 40, 28,
|
||||
0x02, 80, e9, 7f, c6, 7f, e6, 7f, ed, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, e1, 7f, c9, 7f, e2, 7f, e9, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0xff, 7f, e2, 7f, c8, 7f, de, 7f, ea, 7f, eb, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, e6, 7f, ca, 7f, df, 7f, f0, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x00, 80, e7, 7f, cb, 7f, e2, 7f, f0, 7f, ec, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e7, 7f, d1, 7f, df, 7f, ef, 7f, f0, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, eb, 7f, d0, 7f, e5, 7f, ed, 7f, f0, 7f, 6b, fe, 40, 28,
|
||||
0x07, 80, e9, 7f, d3, 7f, ee, 7f, ef, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, eb, 7f, ca, 7f, e1, 7f, ef, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, e9, 7f, d0, 7f, e6, 7f, f2, 7f, f3, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, e3, 7f, d2, 7f, e6, 7f, f2, 7f, f1, 7f, 6b, fe, 40, 28,
|
||||
0x05, 80, ed, 7f, cf, 7f, e9, 7f, ed, 7f, f5, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, ed, 7f, d0, 7f, e6, 7f, ed, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, e8, 7f, cf, 7f, ec, 7f, ed, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, ea, 7f, cc, 7f, e8, 7f, ec, 7f, ec, 7f, 6b, fe, 40, 28,
|
||||
0x00, 80, eb, 7f, c9, 7f, e5, 7f, ef, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, de, 7f, ce, 7f, e7, 7f, eb, 7f, f1, 7f, 6b, fe, 40, 28,
|
||||
0x05, 80, e1, 7f, c6, 7f, e0, 7f, f0, 7f, ec, 7f, 6b, fe, 40, 28,
|
||||
0x01, 80, df, 7f, c7, 7f, df, 7f, e9, 7f, e9, 7f, 6b, fe, 40, 28,
|
||||
0x05, 80, e4, 7f, cd, 7f, e0, 7f, ea, 7f, eb, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, ea, 7f, ca, 7f, de, 7f, ed, 7f, ee, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, e7, 7f, c9, 7f, de, 7f, ef, 7f, ec, 7f, 6b, fe, 40, 28,
|
||||
0x05, 80, e5, 7f, c9, 7f, df, 7f, ed, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e3, 7f, d0, 7f, e2, 7f, ed, 7f, f0, 7f, 6b, fe, 40, 28,
|
||||
0x02, 80, e3, 7f, ce, 7f, e0, 7f, ed, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, f0, 7f, cc, 7f, e3, 7f, ee, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, ed, 7f, d0, 7f, e4, 7f, f3, 7f, ea, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, eb, 7f, c8, 7f, e6, 7f, ec, 7f, ea, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e9, 7f, ce, 7f, e3, 7f, ee, 7f, f0, 7f, 6b, fe, 40, 28,
|
||||
0x09, 80, e9, 7f, d1, 7f, e5, 7f, ea, 7f, eb, 7f, 6b, fe, 40, 28,
|
||||
0x07, 80, eb, 7f, ce, 7f, e6, 7f, f0, 7f, ec, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, ea, 7f, ce, 7f, e4, 7f, eb, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x08, 80, ed, 7f, ce, 7f, e8, 7f, ef, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x08, 80, ee, 7f, ce, 7f, e7, 7f, ef, 7f, ee, 7f, 6b, fe, 40, 28,
|
||||
0x05, 80, e3, 7f, cb, 7f, e0, 7f, ed, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x02, 80, e4, 7f, d0, 7f, e0, 7f, ed, 7f, ee, 7f, 6b, fe, 40, 28,
|
||||
0x00, 80, e7, 7f, cb, 7f, e5, 7f, e9, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x02, 80, df, 7f, cb, 7f, e3, 7f, ed, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0xff, 7f, e3, 7f, cf, 7f, ea, 7f, f0, 7f, eb, 7f, 6b, fe, 40, 28,
|
||||
0x02, 80, e3, 7f, cc, 7f, e2, 7f, ef, 7f, f0, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, e5, 7f, d3, 7f, e4, 7f, f1, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x07, 80, e9, 7f, ce, 7f, e6, 7f, f2, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, ed, 7f, cf, 7f, e6, 7f, ec, 7f, f1, 7f, 6b, fe, 40, 28,
|
||||
0x05, 80, ef, 7f, d5, 7f, e6, 7f, ec, 7f, f1, 7f, 6b, fe, 40, 28,
|
||||
0x07, 80, e7, 7f, d1, 7f, e8, 7f, f1, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, e7, 7f, cc, 7f, e1, 7f, ed, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x02, 80, e6, 7f, cb, 7f, e7, 7f, f1, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e5, 7f, ce, 7f, e9, 7f, ed, 7f, ee, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e3, 7f, cd, 7f, e6, 7f, ec, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x00, 80, ea, 7f, cd, 7f, e8, 7f, ed, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, e7, 7f, c8, 7f, e9, 7f, f3, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, e5, 7f, cb, 7f, e3, 7f, f1, 7f, f0, 7f, 6b, fe, 40, 28,
|
||||
0x02, 80, e3, 7f, ce, 7f, df, 7f, f0, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e7, 7f, ca, 7f, e0, 7f, ef, 7f, ee, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, e7, 7f, d3, 7f, e5, 7f, f0, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x01, 80, e9, 7f, c9, 7f, e2, 7f, ef, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x02, 80, df, 7f, c8, 7f, e1, 7f, ed, 7f, eb, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e7, 7f, ca, 7f, e4, 7f, ee, 7f, ea, 7f, 6b, fe, 40, 28,
|
||||
0x04, 80, e7, 7f, d1, 7f, e6, 7f, f0, 7f, ec, 7f, 6b, fe, 40, 28,
|
||||
0x02, 80, df, 7f, cc, 7f, e6, 7f, eb, 7f, ef, 7f, 6b, fe, 40, 28,
|
||||
0x05, 80, e7, 7f, d1, 7f, e4, 7f, ee, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x07, 80, e9, 7f, cf, 7f, e9, 7f, ec, 7f, ec, 7f, 6b, fe, 40, 28,
|
||||
0x03, 80, e7, 7f, cb, 7f, e7, 7f, ed, 7f, ed, 7f, 6b, fe, 40, 28,
|
||||
0x06, 80, e3, 7f, cf, 7f, e4, 7f, f1, 7f, ec, 7f, 6b, fe, 40, 28,
|
||||
0x07, 80, e8, 7f, cc, 7f, e9, 7f, f2, 7f, ed, 7f
|
||||
}*/
|
||||
//public AnalogDataFormat1Packet(byte[] bytes) : base(bytes)
|
||||
//{
|
||||
// var offset = IRIGCH10.PacketHeader.PACKET_HEADER_LENGTH;
|
||||
|
||||
// if (PacketHeader.SecondaryHeaderPresent)
|
||||
// {
|
||||
// var secondaryHeaderBytes = new byte[SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH];
|
||||
// Buffer.BlockCopy(bytes, offset,
|
||||
// secondaryHeaderBytes, 0, SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH);
|
||||
// var secondaryHeader = new SecondaryTimeFormatHeader(secondaryHeaderBytes);
|
||||
// LocalTimeOfFirstSample = secondaryHeader.LocalTime;
|
||||
// offset += SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH;
|
||||
// }
|
||||
|
||||
// ChannelSpecificDataWord = BitConverter.ToUInt32(bytes, offset);
|
||||
// offset += sizeof(uint);
|
||||
// var numChannels = TotChan;
|
||||
// var sizeOf1SampleForAllChannels = sizeof(ushort) * numChannels;
|
||||
// //There's a CSDW in the data section, then all ADC data. CSDW is uint, 4 bytes
|
||||
// var numSamples = (PacketHeader.DataLength - 4) / sizeOf1SampleForAllChannels;
|
||||
|
||||
// Samples = new SampleData[numSamples];
|
||||
// for (var i = 0; i < Samples.Length; i++)
|
||||
// {
|
||||
// var channels = GetChannels(bytes, offset, numChannels);
|
||||
// Samples[i] = new SampleData(channels);
|
||||
// offset += sizeOf1SampleForAllChannels;
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
367
Common/DTS.Common.Serialization/IRIGCH10/Packets/PCMPacket.cs
Normal file
367
Common/DTS.Common.Serialization/IRIGCH10/Packets/PCMPacket.cs
Normal file
@@ -0,0 +1,367 @@
|
||||
using DTS.Serialization.IRIGCH10.Enums;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10
|
||||
{
|
||||
/// <summary>
|
||||
/// implements the PCM/Pulse Control Modulation packet for CH 10
|
||||
/// </summary>
|
||||
public class PCMPacket : AbstractDataPacket, IDataPacket
|
||||
{
|
||||
private byte [] ChannelSpecificData;
|
||||
|
||||
public PCMPacket()
|
||||
: base(DataFileDataTypes.PCMDataFormat1)
|
||||
{
|
||||
ChannelSpecificData = new byte[4];
|
||||
_dataBytes = new byte[ChannelSpecificData.Length];
|
||||
}
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Indicate Minor Frame Status
|
||||
/// true = Minor Frame Lock
|
||||
/// false = Minor Frame Check (after losing lock)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// true - Major Frame Lock
|
||||
/// false - Major Frame Check (after losing Lock)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// true = 32Bit Alignment Mode
|
||||
/// false = 16Bit Alignment Mode
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Throughput DataMode enabled or not
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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 };
|
||||
|
||||
/// <summary>
|
||||
/// adds data in unpacked 16 bit alignment into the data buffer, resizing as needed
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// adds data in unpacked 16 bit alignment into the data buffer, resizing as needed
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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]
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
//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);
|
||||
}
|
||||
}
|
||||
}
|
||||
355
Common/DTS.Common.Serialization/IRIGCH10/Packets/PacketHeader.cs
Normal file
355
Common/DTS.Common.Serialization/IRIGCH10/Packets/PacketHeader.cs
Normal file
@@ -0,0 +1,355 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// implements the packet header portion of a packet
|
||||
/// </summary>
|
||||
public class PacketHeader : IPacketHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// used to indicate the start of a packet, is defined to 0x25, 0xEB by chapter10.pdf
|
||||
/// </summary>
|
||||
public ushort PacketSyncPattern { get; set; } = BitConverter.ToUInt16(new byte[] { 0x25, 0xEB }, 0);
|
||||
/// <summary>
|
||||
/// this is just a shortcut to avoid calculating the ushort value for 0x25,0xEB
|
||||
/// this is the ushort pattern expected for pattern sync
|
||||
/// </summary>
|
||||
public const ushort EXPECTED_SYNC_PATTERN = 60197;
|
||||
/// <summary>
|
||||
/// channel id, default to 0
|
||||
/// </summary>
|
||||
public ushort ChannelId { get; set; } = BitConverter.ToUInt16(new byte[] { 0x00, 0x00 }, 0);
|
||||
/// <summary>
|
||||
/// total length of the packet including header, data, and filler, and any checksums
|
||||
/// </summary>
|
||||
public uint PacketLength { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// length of the data portion of the packet, so sans filler and checksums
|
||||
/// </summary>
|
||||
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<DataFileDataTypes>().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; }
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="rtc"></param>
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
using DTS.Serialization.IRIGCH10.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10
|
||||
{
|
||||
/// <summary>
|
||||
/// this packet just points to specific time data packets as part of an indexing system
|
||||
/// </summary>
|
||||
public class RecorderIndexPacket : AbstractDataPacket, IDataPacket
|
||||
{
|
||||
//not confident on breaking out the individual properties of this dataword yet
|
||||
//(root index, file size, presence of data header, etc, so just use a
|
||||
//prefilled one for now ...
|
||||
private readonly byte [] ChannelSpecificDataWord = new byte[] {0x8D, 0x02, 0x00, 0xE0};
|
||||
private readonly byte [] RootPacketAddress = new byte [8];
|
||||
public void SetRootPacketAddress(long address)
|
||||
{
|
||||
var bits = BitConverter.GetBytes(address);
|
||||
Buffer.BlockCopy(bits, 0, RootPacketAddress, 0, bits.Length);
|
||||
}
|
||||
|
||||
private List<RecordingIndex> _indices = new List<RecordingIndex>();
|
||||
|
||||
public DateTime GetDateTime()
|
||||
{
|
||||
return _indices.First().GetDateTime();
|
||||
}
|
||||
public int NumberOfEntries => _indices.Count;
|
||||
public void AddRecordingIndex(RecordingIndex index)
|
||||
{
|
||||
_indices.Add(index);
|
||||
}
|
||||
|
||||
public RecorderIndexPacket()
|
||||
: base(DataFileDataTypes.ComputerGeneratedDataFormat3)
|
||||
{
|
||||
_CheckSum = new byte[4];
|
||||
}
|
||||
public override byte[] GetBytes()
|
||||
{
|
||||
//we just need to make sure data bytes is populated then we can let the base class do it's thing
|
||||
_dataBytes = new byte[_indices.Count * RecordingIndex.SIZE + RootPacketAddress.Length +
|
||||
ChannelSpecificDataWord.Length];
|
||||
Buffer.BlockCopy(ChannelSpecificDataWord, 0, _dataBytes, 0, ChannelSpecificDataWord.Length);
|
||||
Buffer.BlockCopy(RootPacketAddress, 0, _dataBytes, ChannelSpecificDataWord.Length, RootPacketAddress.Length);
|
||||
var offset = ChannelSpecificDataWord.Length + RootPacketAddress.Length;
|
||||
foreach (var index in _indices)
|
||||
{
|
||||
var bytes = index.GetBytes();
|
||||
Buffer.BlockCopy(bytes, 0, _dataBytes, offset, bytes.Length);
|
||||
offset += bytes.Length;
|
||||
}
|
||||
return base.GetBytes();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// here's a structure for the recording indicies in the recording index packet
|
||||
/// </summary>
|
||||
public class RecordingIndex
|
||||
{
|
||||
public const int SIZE = 8+8+2+1+1+8;
|
||||
private byte [] RTC = new byte [8];
|
||||
private byte [] TimeDate = new byte[8];
|
||||
private DateTime _dt;
|
||||
private readonly ushort ChannelId = ushort.MaxValue;
|
||||
private readonly byte DataType = 0x11;
|
||||
private readonly byte Reserved = 0x00;
|
||||
private byte[] DataPacketOffset = new byte[8];
|
||||
|
||||
private void SetRTC(long rtc)
|
||||
{
|
||||
var bits = BitConverter.GetBytes(rtc);
|
||||
Buffer.BlockCopy(bits, 0, RTC, 0, bits.Length);
|
||||
}
|
||||
|
||||
private void SetDataPacketOffset(long offset)
|
||||
{
|
||||
var bits = BitConverter.GetBytes(offset);
|
||||
Buffer.BlockCopy(bits, 0, DataPacketOffset, 0, bits.Length);
|
||||
}
|
||||
public DateTime GetDateTime(){ return _dt; }
|
||||
private void SetDateTime(DateTime dt)
|
||||
{
|
||||
_dt = dt;
|
||||
TimeDate[0] = Utils.Utils.GetBCDBytes(dt.Millisecond/10)[0];
|
||||
TimeDate[1] = Utils.Utils.GetBCDBytes(dt.Second)[0];
|
||||
TimeDate[2] = Utils.Utils.GetBCDBytes(dt.Minute)[0];
|
||||
TimeDate[3] = Utils.Utils.GetBCDBytes(dt.Hour)[0];
|
||||
TimeDate[4] = Utils.Utils.GetBCDBytes(dt.Day)[0];
|
||||
TimeDate[5] = Utils.Utils.GetBCDBytes(dt.Month)[0];
|
||||
TimeDate[6] = Utils.Utils.GetBCDBytes(dt.Year)[0];
|
||||
TimeDate[7] = Utils.Utils.GetBCDBytes(dt.Year)[1];
|
||||
}
|
||||
|
||||
public RecordingIndex(long rtc, long offset, DateTime dt)
|
||||
{
|
||||
SetDataPacketOffset(offset);
|
||||
SetRTC(rtc);
|
||||
SetDateTime(dt);
|
||||
}
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
var data = new byte[8 + 8 + 2 + 1 + 1 + 8];
|
||||
var curOffset = 0;
|
||||
Buffer.BlockCopy(RTC, 0, data, 0, RTC.Length);
|
||||
curOffset += RTC.Length;
|
||||
Buffer.BlockCopy(TimeDate, 0, data, curOffset, TimeDate.Length);
|
||||
curOffset += TimeDate.Length;
|
||||
var bytes = BitConverter.GetBytes(ChannelId);
|
||||
Buffer.BlockCopy(bytes, 0, data, curOffset, 2);
|
||||
curOffset += 2;
|
||||
data[curOffset++] = DataType;
|
||||
data[curOffset++] = Reserved;
|
||||
Buffer.BlockCopy(DataPacketOffset, 0, data, curOffset, DataPacketOffset.Length);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using DTS.Serialization.IRIGCH10.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10
|
||||
{
|
||||
/// <summary>
|
||||
/// this class handles the root recorder index packet,
|
||||
/// it points to recorder index packets, it's the last packet in a ch10 file
|
||||
/// (but can be broken over multiple packets)
|
||||
/// </summary>
|
||||
public class RootRecorderIndexPacket : AbstractDataPacket, IDataPacket
|
||||
{
|
||||
//not confident on breaking out the individual properties of this dataword yet
|
||||
//(root index, file size, presence of data header, etc, so just use a
|
||||
//prefilled one for now ...
|
||||
private readonly byte [] ChannelSpecificDataWord = new byte[] {0x8D, 0x00, 0x00, 0x60};
|
||||
private long _rootPacketAddressLong;
|
||||
private readonly byte [] RootPacketAddress = new byte [8];
|
||||
public void SetRootPacketAddress(long address)
|
||||
{
|
||||
_rootPacketAddressLong = address;
|
||||
var bits = BitConverter.GetBytes(address);
|
||||
Buffer.BlockCopy(bits, 0, RootPacketAddress, 0, bits.Length);
|
||||
}
|
||||
|
||||
private List<RecordingIndexIndex> _indices = new List<RecordingIndexIndex>();
|
||||
|
||||
public void AddRecordingIndex(RecordingIndexIndex index)
|
||||
{
|
||||
_indices.Add(index);
|
||||
}
|
||||
private readonly DateTime _dt;
|
||||
public RootRecorderIndexPacket(DateTime dt)
|
||||
: base(DataFileDataTypes.ComputerGeneratedDataFormat3)
|
||||
{
|
||||
_dt = dt;
|
||||
_CheckSum = new byte[4];
|
||||
}
|
||||
public override byte[] GetBytes()
|
||||
{
|
||||
//the last index should apparently point back to this entry...
|
||||
_indices.Add(new RecordingIndexIndex(GetRTC(), _rootPacketAddressLong, _dt));
|
||||
//we just need to make sure data bytes is populated then we can let the base class do it's thing
|
||||
_dataBytes = new byte[_indices.Count * RecordingIndexIndex.SIZE + RootPacketAddress.Length +
|
||||
ChannelSpecificDataWord.Length];
|
||||
|
||||
Buffer.BlockCopy(ChannelSpecificDataWord, 0, _dataBytes, 0, ChannelSpecificDataWord.Length);
|
||||
Buffer.BlockCopy(RootPacketAddress, 0, _dataBytes, ChannelSpecificDataWord.Length, RootPacketAddress.Length);
|
||||
var offset = ChannelSpecificDataWord.Length + RootPacketAddress.Length;
|
||||
foreach (var index in _indices)
|
||||
{
|
||||
var bytes = index.GetBytes();
|
||||
Buffer.BlockCopy(bytes, 0, _dataBytes, offset, bytes.Length);
|
||||
offset += bytes.Length;
|
||||
}
|
||||
return base.GetBytes();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// here is a root recording index entry, it points at other recording indicies
|
||||
/// </summary>
|
||||
public class RecordingIndexIndex
|
||||
{
|
||||
public const int SIZE = 8+8+8;
|
||||
private byte [] RTC = new byte [8];
|
||||
private byte [] TimeDate = new byte[8];
|
||||
private byte[] DataPacketOffset = new byte[8];
|
||||
|
||||
private void SetRTC(long rtc)
|
||||
{
|
||||
var bits = BitConverter.GetBytes(rtc);
|
||||
Buffer.BlockCopy(bits, 0, RTC, 0, bits.Length);
|
||||
}
|
||||
|
||||
private void SetDataPacketOffset(long offset)
|
||||
{
|
||||
var bits = BitConverter.GetBytes(offset);
|
||||
Buffer.BlockCopy(bits, 0, DataPacketOffset, 0, bits.Length);
|
||||
}
|
||||
|
||||
private void SetDateTime(DateTime dt)
|
||||
{
|
||||
TimeDate[0] = Utils.Utils.GetBCDBytes(dt.Millisecond/10)[0];
|
||||
TimeDate[1] = Utils.Utils.GetBCDBytes(dt.Second)[0];
|
||||
TimeDate[2] = Utils.Utils.GetBCDBytes(dt.Minute)[0];
|
||||
TimeDate[3] = Utils.Utils.GetBCDBytes(dt.Hour)[0];
|
||||
TimeDate[4] = Utils.Utils.GetBCDBytes(dt.Day)[0];
|
||||
TimeDate[5] = Utils.Utils.GetBCDBytes(dt.Month)[0];
|
||||
TimeDate[6] = Utils.Utils.GetBCDBytes(dt.Year)[0];
|
||||
TimeDate[7] = Utils.Utils.GetBCDBytes(dt.Year)[1];
|
||||
}
|
||||
|
||||
public RecordingIndexIndex(long rtc, long offset, DateTime dt)
|
||||
{
|
||||
SetDataPacketOffset(offset);
|
||||
SetRTC(rtc);
|
||||
SetDateTime(dt);
|
||||
}
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
var data = new byte[SIZE];
|
||||
var curOffset = 0;
|
||||
Buffer.BlockCopy(RTC, 0, data, 0, RTC.Length);
|
||||
curOffset += RTC.Length;
|
||||
Buffer.BlockCopy(TimeDate, 0, data, curOffset, TimeDate.Length);
|
||||
curOffset += TimeDate.Length;
|
||||
Buffer.BlockCopy(DataPacketOffset, 0, data, curOffset, DataPacketOffset.Length);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10.Packets
|
||||
{
|
||||
/// <summary>
|
||||
/// this class helps encapsulate a secondary time format header, but it's really
|
||||
/// only designed for one type of format currently
|
||||
/// </summary>
|
||||
public class SecondaryTimeFormatHeader : ISecondaryTimeFormatHeader
|
||||
{
|
||||
private byte[] _bytes = new byte[SECONDARY_TIME_HEADER_LENGTH];
|
||||
public int NanoSeconds { get; }
|
||||
public int Seconds { get; }
|
||||
public ushort Reserved { get; }
|
||||
public ushort CheckSum { get; }
|
||||
|
||||
public DateTime LocalTime
|
||||
{
|
||||
get => (new DateTime(1970, 1, 1)).AddSeconds(Seconds).AddTicks(NanoSeconds / 100).ToLocalTime();
|
||||
}
|
||||
public SecondaryTimeFormatHeader(byte[] input)
|
||||
{
|
||||
Array.Copy(input, 0, _bytes, 0, SECONDARY_TIME_HEADER_LENGTH);
|
||||
NanoSeconds = BitConverter.ToInt32(_bytes, 0);
|
||||
Seconds = BitConverter.ToInt32(_bytes, 4);
|
||||
Reserved = BitConverter.ToUInt16(_bytes, 8);
|
||||
CheckSum = BitConverter.ToUInt16(_bytes, 10);
|
||||
byte[] bytesToCompute;
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
using (var bw = new BinaryWriter(ms))
|
||||
{
|
||||
bw.Write(BitConverter.GetBytes(NanoSeconds));
|
||||
bw.Write(BitConverter.GetBytes(Seconds));
|
||||
bw.Write(Reserved);
|
||||
}
|
||||
bytesToCompute = ms.ToArray();
|
||||
}
|
||||
var computedChecksum = Utils.Utils.GetCheckSum8(bytesToCompute);
|
||||
if (computedChecksum != CheckSum)
|
||||
{
|
||||
System.Diagnostics.Trace.WriteLine("Secondary time header CRC does not match expectations");
|
||||
}
|
||||
}
|
||||
public static byte[] GetBytes(int nanoseconds, int seconds)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
using (var bw = new BinaryWriter(ms))
|
||||
{
|
||||
bw.Write(BitConverter.GetBytes(nanoseconds));
|
||||
bw.Write(BitConverter.GetBytes(seconds));
|
||||
bw.Write((ushort)0);
|
||||
|
||||
bw.Write(Utils.Utils.GetCheckSum8(ms.ToArray()));
|
||||
}
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
public const int SECONDARY_TIME_HEADER_LENGTH = 12;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using DTS.Serialization.IRIGCH10.Enums;
|
||||
using DTS.Serialization.IRIGCH10.Packets;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10
|
||||
{
|
||||
/// <summary>
|
||||
/// the TMATS packet in the ch10 file is
|
||||
/// a packet containing the setup file, a description of
|
||||
/// what channels, das, time formats, etc are used in the file
|
||||
/// </summary>
|
||||
public class TMATSPacket : AbstractDataPacket, IDataPacket
|
||||
{
|
||||
/// <summary>
|
||||
/// whether the TMATS is in XML or ASCII format
|
||||
/// </summary>
|
||||
public bool XMLFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
var b = new BitArray(BitConverter.GetBytes(ChannelSpecificDataWord));
|
||||
return b.Get(9);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// whether the setup record has changed or not
|
||||
/// </summary>
|
||||
public bool SetupRecordConfigurationChange
|
||||
{
|
||||
get
|
||||
{
|
||||
var b = new BitArray(BitConverter.GetBytes(ChannelSpecificDataWord));
|
||||
return b.Get(8);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// the chapter 10 version of the TMATS file
|
||||
/// </summary>
|
||||
public RCCChapter10Versions Chapter10Version
|
||||
{
|
||||
get
|
||||
{
|
||||
var b = new BitArray(BitConverter.GetBytes(ChannelSpecificDataWord));
|
||||
var ver = Utils.Utils.BitArrayToInt32(b, 0, 7);
|
||||
switch (ver)
|
||||
{
|
||||
case 0x07: return RCCChapter10Versions.RCC_106_07;
|
||||
case 0x08: return RCCChapter10Versions.RCC_106_09;
|
||||
case 0x09: return RCCChapter10Versions.RCC_106_11;
|
||||
case 0x0A: return RCCChapter10Versions.RCC_106_13;
|
||||
case 0x0B: return RCCChapter10Versions.RCC_106_15;
|
||||
default: return RCCChapter10Versions.RESERVED;
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum RCCChapter10Versions
|
||||
{
|
||||
RESERVED,
|
||||
RCC_106_07,
|
||||
RCC_106_09,
|
||||
RCC_106_11,
|
||||
RCC_106_13,
|
||||
RCC_106_15
|
||||
}
|
||||
private const byte DataVersionNoSecondaryHeader = 0x01;
|
||||
private const byte DataVersionSecondaryHeader = 0x09;
|
||||
public TMATSPacket(int nanoseconds, int seconds, string tmatsDoc, bool secondaryHeaderPresent)
|
||||
: base(DataFileDataTypes.ComputerGeneratedDataFormat1, secondaryHeaderPresent)
|
||||
{
|
||||
var tmatsBytes = Encoding.ASCII.GetBytes(tmatsDoc);
|
||||
var dataLength = Convert.ToUInt32(4 + tmatsBytes.Length); ;
|
||||
var offset = CommonHeaderWork(0, secondaryHeaderPresent ? DataVersionSecondaryHeader : DataVersionNoSecondaryHeader,
|
||||
1, BASE_RTC, dataLength, nanoseconds, seconds);
|
||||
Buffer.BlockCopy(tmatsBytes, 0, _dataBytes, offset, tmatsBytes.Length);
|
||||
}
|
||||
|
||||
public TMATSPacket(byte[] bytes) : base(bytes)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// the TMATS document
|
||||
/// </summary>
|
||||
public string TMATSDocument
|
||||
{
|
||||
get
|
||||
{
|
||||
//the document is prepended by a ChannelSpecificDataWord and potentially a time header
|
||||
var prepend = 4; //CSDW
|
||||
if (PacketHeader.SecondaryHeaderPresent) { prepend += SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH; }
|
||||
var length = PacketHeader.DataLength - prepend;
|
||||
var bytes = new byte[length];
|
||||
Buffer.BlockCopy(_dataBytes, prepend, bytes, 0, bytes.Length);
|
||||
return Encoding.ASCII.GetString(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using DTS.Serialization.IRIGCh10.Attributes;
|
||||
using DTS.Serialization.IRIGCH10.Enums;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10
|
||||
{
|
||||
/// <summary>
|
||||
/// implements a time data packet, allowing time data packets to be put into a ch 10 file
|
||||
/// </summary>
|
||||
public class TimeDataPacket : AbstractDataPacket, IDataPacket
|
||||
{
|
||||
public TimeDataPacket()
|
||||
: base(DataFileDataTypes.TimeDataFormat1)
|
||||
{
|
||||
_dataBytes = new byte[12];
|
||||
|
||||
}
|
||||
private DateTime _dt;
|
||||
public DateTime GetDateTime()
|
||||
{
|
||||
return _dt;
|
||||
}
|
||||
public void SetTime(DateTime dt)
|
||||
{
|
||||
_dt = dt;
|
||||
_dataBytes[4] = Utils.Utils.GetBCDBytes(dt.Millisecond/10)[0];
|
||||
_dataBytes[5] = Utils.Utils.GetBCDBytes(dt.Second)[0];
|
||||
_dataBytes[6] = Utils.Utils.GetBCDBytes(dt.Minute)[0];
|
||||
_dataBytes[7] = Utils.Utils.GetBCDBytes(dt.Hour)[0];
|
||||
_dataBytes[8] = Utils.Utils.GetBCDBytes(dt.Day)[0];
|
||||
_dataBytes[9] = Utils.Utils.GetBCDBytes(dt.Month)[0];
|
||||
_dataBytes[10] = Utils.Utils.GetBCDBytes(dt.Year)[0];
|
||||
_dataBytes[11] = Utils.Utils.GetBCDBytes(dt.Year)[1];
|
||||
}
|
||||
|
||||
public void SetTimeSource(byte b)
|
||||
{
|
||||
var bitArray = new BitArray(new[] {_dataBytes[0]});
|
||||
var bitArray2 = new BitArray(new[] {b});
|
||||
bitArray[0] = bitArray2[0];
|
||||
bitArray[1] = bitArray2[1];
|
||||
bitArray[2] = bitArray2[2];
|
||||
bitArray[3] = bitArray2[3];
|
||||
|
||||
bitArray.CopyTo(_dataBytes, 0);
|
||||
}
|
||||
public void SetTimeSource(TimeSource src)
|
||||
{
|
||||
var bitArray = new BitArray(new[] {_dataBytes[0], _dataBytes[1], _dataBytes[2], _dataBytes[3]});
|
||||
var bytevalue = new BitArray(new[] {PacketHeaderValueAttribute.GetPacketHeaderValue(src)});
|
||||
//ref Chapter 10, 10-47
|
||||
|
||||
bitArray[0] = bytevalue[3];
|
||||
bitArray[1] = bytevalue[2];
|
||||
bitArray[2] = bytevalue[1];
|
||||
bitArray[3] = bytevalue[0];
|
||||
|
||||
bitArray.CopyTo(_dataBytes, 0);
|
||||
}
|
||||
|
||||
public void SetTimeFormat(TimeFormats fmt)
|
||||
{
|
||||
var bitArray = new BitArray(new[] {_dataBytes[0], _dataBytes[1], _dataBytes[2], _dataBytes[3]});
|
||||
var bytevalue = new BitArray(new[] {PacketHeaderValueAttribute.GetPacketHeaderValue(fmt)});
|
||||
//ref Chapter 10, 10-47
|
||||
bitArray[4] = bytevalue[3];
|
||||
bitArray[5] = bytevalue[2];
|
||||
bitArray[6] = bytevalue[1];
|
||||
bitArray[7] = bytevalue[0];
|
||||
|
||||
bitArray.CopyTo(_dataBytes, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10.Packets
|
||||
{
|
||||
/// <summary>
|
||||
/// added an analog time format 1 packet for validating exports with EMC
|
||||
/// </summary>
|
||||
public class TimePacketFormat1 : AbstractDataPacket, IDataPacket
|
||||
{
|
||||
public enum IRIGTimeSource
|
||||
{
|
||||
IRIG_TCG_freewheeling,
|
||||
IRIG_TCG_freewheeling_from_TIME,
|
||||
IRIG_TCG_freewheeling_from_RMM,
|
||||
IRIG_TCG_locked_to_external_IRIG,
|
||||
IRIG_TCG_locked_to_external_GPS,
|
||||
IRIG_TCG_locked_to_external_NetworkTimeProtocol,
|
||||
IRIG_TCG_locked_to_external_Precision_Time_Protocol,
|
||||
IRIG_TCG_locked_to_external_Embedded,
|
||||
RESERVED
|
||||
};
|
||||
//bits 15-12
|
||||
//this is currently not serialized to the CSDW as the EMC validation tool will return errors if the
|
||||
//field is filled in.
|
||||
//DTM 2023-10-27
|
||||
public IRIGTimeSource ITS
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public enum TimeFormats
|
||||
{
|
||||
IRIG_B = 0x00,
|
||||
IRIG_A = 0x01,
|
||||
IRIG_G = 0x02,
|
||||
RTC = 0x03,
|
||||
UTC = 0x04,
|
||||
NativeGPS = 0x05,
|
||||
RESERVED = 0x06,
|
||||
NONE = 0x0F
|
||||
}
|
||||
//bits 7-4
|
||||
public TimeFormats TimeFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
var ntf = Utils.Utils.BitArrayToInt32(bits, 4, 7);
|
||||
return (TimeFormats)ntf;
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
Utils.Utils.SetBits(b, (uint)value, 4, 7);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
//bits 3-0
|
||||
public enum TimeSources
|
||||
{
|
||||
Internal = 0x00,
|
||||
External = 0x01,
|
||||
InternalFromRMM = 0x02,
|
||||
Reserved = 0x03,
|
||||
None = 0x0F
|
||||
}
|
||||
public TimeSources TimeSource
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
var ntf = Utils.Utils.BitArrayToInt32(bits, 0, 3);
|
||||
return (TimeSources)ntf;
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
Utils.Utils.SetBits(b, (uint)value, 0, 3);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public enum DateFormats
|
||||
{
|
||||
IRIGDayAvailable = 0x00,
|
||||
MonthAndYearAvailable = 0x01
|
||||
}
|
||||
//bit 9
|
||||
public DateFormats DateFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
var csdw = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(csdw);
|
||||
return bits[9] ? DateFormats.MonthAndYearAvailable : DateFormats.IRIGDayAvailable;
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
b.Set(9, value == DateFormats.MonthAndYearAvailable);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// the time represented by this packet
|
||||
/// </summary>
|
||||
public DateTime TimePacketTime { get; set; }
|
||||
//bit 8
|
||||
public bool IsLeapYear
|
||||
{
|
||||
get
|
||||
{
|
||||
var csdw = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(csdw);
|
||||
return bits[8];
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
b.Set(8, value);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public TimePacketFormat1(byte sequenceNumber, DateTime packetTime, long rtc, int nanoseconds, int seconds)
|
||||
: base(Enums.DataFileDataTypes.TimeDataFormat1, false)
|
||||
{
|
||||
SetDataVersion(Enums.DataTypeVersion.TG78);
|
||||
TimePacketTime = packetTime;
|
||||
IsLeapYear = DateTime.IsLeapYear(packetTime.Year);
|
||||
DateFormat = DateFormats.MonthAndYearAvailable;
|
||||
TimeSource = TimeSources.External;
|
||||
ITS = IRIGTimeSource.IRIG_TCG_locked_to_external_Embedded;
|
||||
var dataLength = Convert.ToUInt32(4 + sizeof(ushort) + 4);
|
||||
var offset = CommonHeaderWork(1, PacketHeader.DataVersion, sequenceNumber, rtc, dataLength, nanoseconds, seconds);
|
||||
|
||||
WriteMonthDayPayload(offset);
|
||||
}
|
||||
/// <summary>
|
||||
/// writes the month day payload portion of the timepacket
|
||||
/// </summary>
|
||||
/// <param name="offset"></param>
|
||||
private void WriteMonthDayPayload(int offset)
|
||||
{
|
||||
var Line1 = new BitArray(16);
|
||||
var digits = GetDigits(TimePacketTime.Second, 2);
|
||||
//tens of seconds
|
||||
var TSn = digits[0];
|
||||
Utils.Utils.SetBits(Line1, (uint)TSn, 12, 14);
|
||||
//units of seconds
|
||||
var Sn = digits[1];
|
||||
Utils.Utils.SetBits(Line1, (uint)Sn, 8, 11);
|
||||
digits = GetDigits(TimePacketTime.Millisecond, 3);
|
||||
//hundreds of ms
|
||||
var Hmn = digits[0];
|
||||
Utils.Utils.SetBits(Line1, (uint)Hmn, 4, 7);
|
||||
//tens of ms
|
||||
var Tmn = digits[1];
|
||||
Utils.Utils.SetBits(Line1, (uint)Tmn, 0, 3);
|
||||
|
||||
var temp = new byte[sizeof(ushort)];
|
||||
Line1.CopyTo(temp, 0);
|
||||
Buffer.BlockCopy(temp, 0, _dataBytes, offset, 2);
|
||||
offset += 2;
|
||||
|
||||
var Line2 = new BitArray(16);
|
||||
digits = GetDigits(TimePacketTime.Hour, 2);
|
||||
//tens of hours
|
||||
var THn = digits[0];
|
||||
Utils.Utils.SetBits(Line2, (uint)THn, 12, 13);
|
||||
//Units of hours
|
||||
var Hn = digits[1];
|
||||
Utils.Utils.SetBits(Line2, (uint)Hn, 8, 11);
|
||||
digits = GetDigits(TimePacketTime.Minute, 2);
|
||||
//tens of minutes
|
||||
var TMn = digits[0];
|
||||
Utils.Utils.SetBits(Line2, (uint)TMn, 4, 6);
|
||||
//units of minutes
|
||||
var Mn = digits[1];
|
||||
Utils.Utils.SetBits(Line2, (uint)Mn, 0, 3);
|
||||
temp = new byte[sizeof(ushort)];
|
||||
Line2.CopyTo(temp, 0);
|
||||
Buffer.BlockCopy(temp, 0, _dataBytes, offset, 2);
|
||||
offset += 2;
|
||||
|
||||
var Line3 = new BitArray(16);
|
||||
digits = GetDigits(TimePacketTime.Month, 2);
|
||||
//tens of months
|
||||
var Ton = digits[0];
|
||||
Utils.Utils.SetBits(Line3, (uint)Ton, 12, 13);
|
||||
//units of months
|
||||
var On = digits[1];
|
||||
Utils.Utils.SetBits(Line3, (uint)On, 8, 11);
|
||||
digits = GetDigits(TimePacketTime.Day, 2);
|
||||
//Tens of days
|
||||
var TDn = digits[0];
|
||||
Utils.Utils.SetBits(Line3, (uint)TDn, 4, 7);
|
||||
//units of days
|
||||
var Dn = digits[1];
|
||||
Utils.Utils.SetBits(Line3, (uint)Dn, 0, 3);
|
||||
temp = new byte[sizeof(ushort)];
|
||||
Line3.CopyTo(temp, 0);
|
||||
Buffer.BlockCopy(temp, 0, _dataBytes, offset, 2);
|
||||
offset += 2;
|
||||
|
||||
var line4 = new BitArray(16);
|
||||
digits = GetDigits(TimePacketTime.Year, 4);
|
||||
var OYn = digits[0];
|
||||
//thousands of years
|
||||
Utils.Utils.SetBits(line4, (uint)OYn, 12, 13);
|
||||
var HYn = digits[1];
|
||||
//hundreds of years
|
||||
Utils.Utils.SetBits(line4, (uint)HYn, 8, 11);
|
||||
var TYn = digits[2];
|
||||
//tens of years
|
||||
Utils.Utils.SetBits(line4, (uint)TYn, 4, 7);
|
||||
var Yn = digits[3];
|
||||
//units of years
|
||||
Utils.Utils.SetBits(line4, (uint)Yn, 0, 3);
|
||||
temp = new byte[sizeof(ushort)];
|
||||
line4.CopyTo(temp, 0);
|
||||
Buffer.BlockCopy(temp, 0, _dataBytes, offset, 2);
|
||||
offset += 2;
|
||||
}
|
||||
private int[] GetDigits(int number, int expectedDigits)
|
||||
{
|
||||
var list = new List<int>();
|
||||
var res = number;
|
||||
while (0 != res)
|
||||
{
|
||||
var digit = res % 10;
|
||||
res /= 10;
|
||||
list.Add(digit);
|
||||
}
|
||||
while (list.Count < expectedDigits)
|
||||
{
|
||||
list.Add(0);
|
||||
}
|
||||
list.Reverse();
|
||||
return list.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using DTS.Common.Utilities;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10.Packets
|
||||
{
|
||||
public class TimePacketFormat2 : AbstractDataPacket, IDataPacket
|
||||
{
|
||||
public DateTime LocalTimeOfFirstSample
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public enum NetworkTimeFormats
|
||||
{
|
||||
NetworkTimeProtocolVersion3 = 0x00,
|
||||
IEEE1588_2002 = 0x01,
|
||||
IEEE1588_2008 = 0x02,
|
||||
RESERVED
|
||||
}
|
||||
//bits 7-4
|
||||
public NetworkTimeFormats NetworkTimeFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
var ntf = Utils.Utils.BitArrayToInt32(bits, 4, 7);
|
||||
switch (ntf)
|
||||
{
|
||||
case 0: return NetworkTimeFormats.NetworkTimeProtocolVersion3;
|
||||
case 1: return NetworkTimeFormats.IEEE1588_2002;
|
||||
case 2: return NetworkTimeFormats.IEEE1588_2008;
|
||||
default: return NetworkTimeFormats.RESERVED;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
Utils.Utils.SetBits(b, (uint)value, 4, 7);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum TimeStatuses
|
||||
{
|
||||
TimeNotValid,
|
||||
TimeValid,
|
||||
Reserved
|
||||
}
|
||||
//bits 3-0
|
||||
|
||||
public TimeStatuses TimeStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
var ts = Utils.Utils.BitArrayToInt32(bits, 0, 3);
|
||||
switch (ts)
|
||||
{
|
||||
case 0: return TimeStatuses.TimeNotValid;
|
||||
case 1: return TimeStatuses.TimeValid;
|
||||
default: return TimeStatuses.Reserved;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var b = new BitArray(channelSpecificDataWord);
|
||||
Utils.Utils.SetBits(b, (uint)value, 0, 3);
|
||||
var ret = new byte[sizeof(uint)];
|
||||
b.CopyTo(ret, 0);
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(ret, 0);
|
||||
}
|
||||
}
|
||||
public uint UnsignedSeconds
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public uint UnsignedNanoSeconds
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string PTPTime
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
private const byte DATA_VERSION_TIME_FORMAT2 = 0x08;
|
||||
public TimePacketFormat2(byte sequenceNumber, bool rtcSyncError, int nanoseconds, int seconds, long rtc,
|
||||
bool includeSecondaryHeader) : base(Enums.DataFileDataTypes.TimeDataFormat2, includeSecondaryHeader)
|
||||
{
|
||||
NetworkTimeFormat = NetworkTimeFormats.IEEE1588_2008;
|
||||
TimeStatus = rtcSyncError ? TimeStatuses.TimeNotValid : TimeStatuses.TimeValid;
|
||||
//CSDW+CRC+TimeData (32 bitsx2)
|
||||
var dataLength = Convert.ToUInt32(4 + sizeof(uint) * 2);
|
||||
var offset = CommonHeaderWork(1, DATA_VERSION_TIME_FORMAT2, sequenceNumber, rtc, dataLength, nanoseconds, seconds);
|
||||
var bytes = BitConverter.GetBytes(seconds);
|
||||
Buffer.BlockCopy(bytes, 0, _dataBytes, offset, bytes.Length);
|
||||
offset += bytes.Length;
|
||||
bytes = BitConverter.GetBytes(nanoseconds);
|
||||
Buffer.BlockCopy(bytes, 0, _dataBytes, offset, bytes.Length);
|
||||
}
|
||||
public TimePacketFormat2(byte[] bytes) : base(bytes)
|
||||
{
|
||||
var offset = IRIGCH10.PacketHeader.PACKET_HEADER_LENGTH;
|
||||
|
||||
if (PacketHeader.SecondaryHeaderPresent)
|
||||
{
|
||||
var secondaryHeaderBytes = new byte[SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH];
|
||||
Buffer.BlockCopy(bytes, offset,
|
||||
secondaryHeaderBytes, 0, SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH);
|
||||
var secondaryHeader = new SecondaryTimeFormatHeader(secondaryHeaderBytes);
|
||||
LocalTimeOfFirstSample = secondaryHeader.LocalTime;
|
||||
offset += SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
ChannelSpecificDataWord = BitConverter.ToUInt32(bytes, offset);
|
||||
offset += sizeof(uint);
|
||||
var channelSpecificDataWord = BitConverter.GetBytes(ChannelSpecificDataWord);
|
||||
var bits = new BitArray(channelSpecificDataWord);
|
||||
var ntf = Utils.Utils.BitArrayToInt32(bits, 4, 7);
|
||||
switch (ntf)
|
||||
{
|
||||
case 0: NetworkTimeFormat = NetworkTimeFormats.NetworkTimeProtocolVersion3; break;
|
||||
case 1: NetworkTimeFormat = NetworkTimeFormats.IEEE1588_2002; break;
|
||||
case 2: NetworkTimeFormat = NetworkTimeFormats.IEEE1588_2008; break;
|
||||
default: NetworkTimeFormat = NetworkTimeFormats.RESERVED; break;
|
||||
}
|
||||
var ts = Utils.Utils.BitArrayToInt32(bits, 0, 3);
|
||||
switch (ts)
|
||||
{
|
||||
case 0: TimeStatus = TimeStatuses.TimeNotValid; break;
|
||||
case 1: TimeStatus = TimeStatuses.TimeValid; break;
|
||||
case 2: TimeStatus = TimeStatuses.Reserved; break;
|
||||
}
|
||||
|
||||
UnsignedSeconds = BitConverter.ToUInt32(bytes, offset);
|
||||
offset += sizeof(uint);
|
||||
UnsignedNanoSeconds = BitConverter.ToUInt32(bytes, offset);
|
||||
offset += sizeof(uint);
|
||||
PTPTime = PTP1588Timestamps.ToDateTimeString((decimal)UnsignedSeconds, (decimal)UnsignedNanoSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTS.Serialization.IRIGCH10.Packets
|
||||
{
|
||||
public class TransportStreamHeader : ITransportStreamHeader
|
||||
{
|
||||
/*• Transport Stream: 4-byte or 32-bit value. (Byteswap to PC format.)
|
||||
o Bit [3:0] 4-bit Message Format is set to 1.
|
||||
o Bit [7:4] 4-bit Message Type is set to 0.
|
||||
o Bit [31:8] 24-bit UDP message sequence number. It is incremented by 1 for each packet sent out in stream including Time data packet, CGPD (TMATS), and Analog data packets.
|
||||
*/
|
||||
private byte[] _bytes = new byte[4];
|
||||
public int MessageFormat { get; }
|
||||
public int MessageType { get; }
|
||||
public int SequenceNumber { get; }
|
||||
|
||||
public TransportStreamHeader()
|
||||
{
|
||||
|
||||
}
|
||||
public TransportStreamHeader(byte[] input)
|
||||
{
|
||||
if (null == input) { throw new NullReferenceException($"input is null"); }
|
||||
if (TRANSPORT_HEADER_LENGTH != input.Length) { throw new Exception($"Expected {TRANSPORT_HEADER_LENGTH} bytes, received {input.Length}"); }
|
||||
Buffer.BlockCopy(input, 0, _bytes, 0, TRANSPORT_HEADER_LENGTH);
|
||||
var int32 = BitConverter.ToInt32(input, 0);
|
||||
var bits = new BitArray(BitConverter.GetBytes(int32));
|
||||
MessageFormat = Utils.Utils.BitArrayToInt32(bits, 0, 3);
|
||||
MessageType = Utils.Utils.BitArrayToInt32(bits, 4, 7);
|
||||
SequenceNumber = Utils.Utils.BitArrayToInt32(bits, 8, 31);
|
||||
_bytes = input;
|
||||
}
|
||||
public const int TRANSPORT_HEADER_LENGTH = 4;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user