Files

368 lines
14 KiB
C#
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
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);
}
}
}