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,55 @@
/*
* Test.Module.IConvertable.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DTS.Serialization
{
// *** see Test.cs ***
public partial class Test
{
// *** see Test.Module.cs ***
public partial class Module
{
/// <summary>
/// An object that expresses this interface can convert itself to and from a
/// <see cref="DTS.Serialization.Test.Module"/> object.
/// </summary>
///
public interface IConvertable
{
/// <summary>
/// Convert this object to a <see cref="DTS.Serialization.Test.Module"/>.
/// </summary>
///
/// <param name="parentTest">
/// The <see cref="DTS.Serialization.ParentTest"/> that contains the afixed object.
/// </param>
///
/// <returns>
/// The <see cref="DTS.Serialization.Test.Module"/> equivalent of this object.
/// </returns>
///
Test.Module ToDtsSerializationTestModule( DTS.Serialization.Test parentTest );
/// <summary>
/// Initialize this object using the specified <see cref="DTS.Serialization.Test.Module"/>.
/// </summary>
///
/// <param name="test">
/// The <see cref="DTS.Serialization.Test.Module"/> with which this object will be initialized from.
/// </param>
///
void FromDtsSerializationTestModule( Test.Module testModule, DTS.Serialization.Test.ReportErrors reportErrors );
}
}
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DTS.Common.DAS.Concepts;
namespace DTS.Serialization
{
/// <summary>
/// A collection of a channel and associated metadata that will all be needed together when
/// this file format starts laying down bytes.
/// </summary>
public class ChannelWithMeta
{
/// <summary>
/// Get/set the <see cref="DTS.Serialization.Test.Module.Channel"/> to be serialized.
/// </summary>
public Test.Module.Channel Channel { get; }
/// <summary>
/// Get/set the <see cref="DataScaler"/> associated with the
/// specified channel.
/// </summary>
public DataScaler Scaler { get; }
/// <summary>
/// Get/set the <see cref="double"/> sample rate associated with the specified channel.
/// </summary>
public double SampleRate { get; }
/// <summary>
/// Get/set the <see cref="double"/> start time associated with the specified channel.
/// </summary>
public double StartTime { get; }
/// <summary>
/// Initialize an instance of the ChannelWithMeta class.
/// </summary>
///
/// <param name="channel">
/// A <see cref="DTS.Serialization.Test.Module.Channel"/> to be serialized.
/// </param>
///
/// <param name="scaler">
/// The <see cref="DataScaler"/> containing scaling information for
/// the specified channel.
/// </param>
///
/// <param name="samplerate">
/// The <see cref="double"/> sample rate of the associated channel.
/// </param>
///
/// <param name="starttime">
/// The <see cref="double"/> start time of the associated channel.
/// </param>
///
public ChannelWithMeta(DTS.Serialization.Test.Module.Channel channel, DataScaler scaler, double samplerate, double starttime)
{
Channel = channel;
Scaler = scaler;
SampleRate = samplerate;
StartTime = starttime;
}
public static double GetMinStartTime(double start, IList<ChannelWithMeta> channelsWithMeta)
{
// Start is a generally a negative value, so to get the value for the start time of the minimum common data set, run Max()
return Math.Max(start, channelsWithMeta.Min(cwm => cwm.StartTime));
}
public static double GetMinStopTime(double stop, IList<ChannelWithMeta> channelsWithMeta)
{
// To get the value for the stop time of the minimum common data set, run Min()
// LINQ statement will sometimes hand back float-rounding error numbers (4.999999999999995 v 5.0), so cast to decimals.
return (double)Math.Min((decimal)stop,
channelsWithMeta.Min(cwm =>
(decimal)cwm.StartTime + (cwm.Channel.PersistentChannelInfo.Length - 1) * 1m / (decimal)cwm.SampleRate));
}
}
}

View File

@@ -0,0 +1,208 @@
using DTS.Common.Utilities.Logging;
using DTS.Common.Utils;
using DTS.DASLib.Command.SLICE.MulticastCommands;
using DTS.Serialization.IRIGCH10.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace DTS.Serialization.IRIGCH10
{
public class CH10AnalogStreamDecode
{
private static object MyLock = new object();
private readonly ManualResetEvent _stopListening = new ManualResetEvent(false);
public string MulticastReceiveAddress { get; set; } = MulticastCommandBase.DEFAULT_RECEIVE_ADDRESS;
public int ResponsePort { get; set; } = (int)MulticastCommandBase.Ports.Response;
private Task _listeningTask = null;
public IPAddress BindToAdapterIPAddress { get; set; } = IPAddress.Any;
/// <summary>
/// starts listening for UDP stream packets
/// </summary>
public void StartListening()
{
lock (MyLock)
{
_stopListening.Set();
if (null != _listeningTask)
{
_listeningTask.Wait();
}
_stopListening.Reset();
_listeningTask = Task.Run(ListenThread);
}
}
public delegate void TimePacketDelegate(TimePacketFormat2 packet);
public delegate void AnalogDataPacketDelegate(AnalogDataFormat1Packet packet);
public delegate void TMATSPacketDelegate(TMATSPacket packet);
public delegate void BadCRCDelegate(IPacketHeader packet);
/// <summary>
/// action to perform when a packet is received but has a bad CRC
/// </summary>
public BadCRCDelegate OnBadCRC;
/// <summary>
/// action to perform when a time packet is received
/// </summary>
public TimePacketDelegate OnTimePacket;
/// <summary>
/// action to perform when an analog data packet is received
/// </summary>
public AnalogDataPacketDelegate OnAnalogPacket;
/// <summary>
/// action to perform when a tmats packet is received
/// </summary>
public TMATSPacketDelegate OnTMATSPacket;
private void ListenThread()
{
var rxGroupAddress = IPAddress.Parse(MulticastReceiveAddress);
var endPoint = new IPEndPoint(BindToAdapterIPAddress, ResponsePort);
var receiver = new UdpClient();
receiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
if (BindToAdapterIPAddress == IPAddress.Any) { receiver.ExclusiveAddressUse = false; }
try
{
receiver.Client.Bind(endPoint);
}
catch (Exception ex)
{
APILogger.Log(ex);
return;
}
try
{
if (BindToAdapterIPAddress == IPAddress.Any)
{
receiver.JoinMulticastGroup(rxGroupAddress);
}
else
{
receiver.JoinMulticastGroup(rxGroupAddress, BindToAdapterIPAddress);
}
}
catch (Exception ex)
{
APILogger.Log(ex);
}
var data = new byte[0];
IAsyncResult asyncResult = null;
do
{
if (BindToAdapterIPAddress != IPAddress.Any && !NetworkUtils.IsNetworkInterfaceUp(BindToAdapterIPAddress))
{
Thread.Sleep(100);
continue;
}
asyncResult = receiver.BeginReceive(null, null);
asyncResult.AsyncWaitHandle.WaitOne(100);
if (asyncResult.IsCompleted)
{
try
{
IPEndPoint remoteEP = null;
data = receiver.EndReceive(asyncResult, ref remoteEP);
data = CombineBytesIfNeeded(data);
ParseBytes(data);
}
catch (Exception ex)
{
APILogger.Log(ex);
}
}
} while (!_stopListening.WaitOne(0, false));
receiver.Close();
}
private byte[] _leftOvertBytes = new byte[0];
private static object LEFT_OVER_BYTES_LOCK = new object();
private void QueueBytes(byte[] bytes)
{
lock (LEFT_OVER_BYTES_LOCK)
{
var newBytes = new byte[bytes.Length + _leftOvertBytes.Length];
Buffer.BlockCopy(_leftOvertBytes, 0, newBytes, 0, _leftOvertBytes.Length);
Buffer.BlockCopy(bytes, 0, newBytes, _leftOvertBytes.Length, bytes.Length);
_leftOvertBytes = bytes;
}
}
private byte[] CombineBytesIfNeeded(byte[] newData)
{
lock (LEFT_OVER_BYTES_LOCK)
{
var newBytes = new byte[newData.Length + _leftOvertBytes.Length];
Buffer.BlockCopy(_leftOvertBytes, 0, newBytes, 0, _leftOvertBytes.Length);
Buffer.BlockCopy(newData, 0, newBytes, _leftOvertBytes.Length, newData.Length);
return newBytes;
}
}
private void ParseBytes(byte[] bytes)
{
var currentIndex = 0L;
while (currentIndex < bytes.Length)
{
var nextIndex = Chapter10File.ReadChapter10PacketHeader(bytes, currentIndex, out var header);
if (header.PacketSyncPattern != PacketHeader.EXPECTED_SYNC_PATTERN)
{
currentIndex = Chapter10File.GetIndexOfNextPacket(bytes, currentIndex);
}
else
{
if (header.CheckSum != header.ComputeCheckSum())
{
OnBadCRC?.Invoke(header);
continue;
}
if (header.PacketLength > bytes.Length)
{
QueueBytes(bytes);
return;
}
var buffer = new byte[header.PacketLength];
Buffer.BlockCopy(bytes, Convert.ToInt32(currentIndex), buffer, 0, Convert.ToInt32(header.PacketLength));
switch (header.DataFileType)
{
case Enums.DataFileDataTypes.ComputerGeneratedDataFormat0:
case Enums.DataFileDataTypes.ComputerGeneratedDataFormat1:
APILogger.Log("TMATS packet received");
var tmatsPacket = new TMATSPacket(buffer);
OnTMATSPacket?.Invoke(tmatsPacket);
break;
case Enums.DataFileDataTypes.AnalogDataFormat1:
var analog = new AnalogDataFormat1Packet(buffer);
OnAnalogPacket?.Invoke(analog);
break;
case Enums.DataFileDataTypes.TimeDataFormat2:
var timePacket = new TimePacketFormat2(buffer);
OnTimePacket?.Invoke(timePacket);
break;
default:
APILogger.Log($"unknown header file type: {header.DataFileType}, ");
break;
}
currentIndex = nextIndex;
}
}
}
/// <summary>
/// stops listening for stream packets
/// </summary>
public void StopListening()
{
lock (MyLock)
{
_stopListening.Set();
}
}
}
}