This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -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;
}
}
}

View 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;
}
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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;
// }
//}
}
}

View 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);
}
}
}

View 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();
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}