356 lines
12 KiB
C#
356 lines
12 KiB
C#
|
|
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();
|
|||
|
|
}
|
|||
|
|
}
|