Files
DP44/DataPRO/IService/Classes/Ribeye Service.cs
2026-04-17 14:55:32 -04:00

2624 lines
108 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Xml.Serialization;
using System.IO;
using DTS.Common;
using DTS.Common.DASResource;
using DTS.Common.Enums;
using DTS.Common.Interface.DASFactory;
using DTS.DASLib.Command.Ribeye;
using DTS.Common.Utilities.Logging;
using DTS.Common.Enums.Sensors;
using DTS.Common.Classes.Connection;
using DTS.Common.Interface.Connection;
using DTS.Common.Interface.DASFactory.Diagnostics;
using DTS.DASLib.Service.Classes.Diagnostics;
using DTS.Common.Enums.DASFactory;
using DTS.Common.Interface.DASFactory.ARM;
using DTS.Common.Interface.DASFactory.Download;
using DTS.Common.Interface.DASFactory.Config;
using DTS.Common.ICommunication;
using DTS.Common.Interface.StatusAndProgressBar;
using DTS.Common.Enums.Hardware;
using static DTS.Common.Enums.DASFactory.DFConstantsAndEnums;
using System.IO.Ports;
using DTS.Common.Classes.DSP;
namespace DTS.DASLib.Service
{
/// <summary>
/// The Ribeye class implements the required services for a Ribeye device
/// </summary>
/// <typeparam>Type of connection (e.g. Ethernet)</typeparam>
public partial class Ribeye<T> : Communication<T>,
IDASCommunication,
IConfigurationActions,
IDiagnosticsActions,
IRealTimeActions,
IArmActions,
IDownloadActions
where T : IConnection, new()
{
public ExcitationStatus ExcitationStatus { get; set; } = ExcitationStatus.Unknown;
/// <summary>
/// <inheritdoc cref="IConfiguration"/>
/// </summary>
public string TestDirectory { get; set; }
public IOptimizationValues OptimizationValues { get; set; }
/// <summary>
/// returns true if the unit is capable of reading arm status
/// 17800 Trigger status is "waiting" but PPRO has indeed triggered
/// </summary>
/// <returns></returns>
bool IDASCommunication.GetCanCheckArmStatus() { return true; }
void IDASCommunication.SetIsStreamingSupported(bool supported = false)
{
IsStreamingSupported = false;
}
void IDASCommunication.ReadFirstUseDate()
{
IsFirstUseDateSupported = false;
FirstUseDate = null;
}
/// <summary>
/// indicates date of first use
/// null indicates the hardware has not been used since calibration
/// only valid when IsFirstUseDateSupported is true
/// 15524 DAS "First Use Date"
/// </summary>
public DateTime? FirstUseDate { get; set; } = null;
/// <summary>
/// returns whether the hardware supports first use or not
/// for hardware to support first use the hardware must support
/// storage for user attributes in firmware and also have been
/// calibrated by software support hardware first use
/// 15524 DAS "First Use Date"
/// </summary>
public bool IsFirstUseDateSupported { get; set; } = false;
/// <summary>
/// returns whether or not the hardware and firmware support streaming
/// </summary>
public bool IsStreamingSupported { get; set; } = false;
public bool ConnectionCheck()
{
try
{
var querySerialNumber = new QuerySerialNumber(this);
querySerialNumber.SyncExecute();
return true;
}
catch (Exception ex)
{
APILogger.Log(ex);
}
return false;
}
public HardwareTypes GetHardwareType() => HardwareTypes.Ribeye;
public int[] GetStackChannelConfigTypes() => new int[] { 0 };
public int RecordId { get; set; } = HardwareConstants.INVALID_IDASCOMMUNICATION_RECORD_ID;
void IDiagnosticsActions.ClearTriggerOut(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
void IConfigurationActions.SetFirstUseDate(DateTime firstUseDate, ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Error("Not supported");
}
void IDiagnosticsActions.ClearLatches(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
/// <summary>
/// clears any das trigger lines (N/A to ribeye)
/// </summary>
void IDiagnosticsActions.ClearDASTriggerLine(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
bool IConfiguration.SupportsAutoDetect => false;
void IConfigurationActions.AutoDetect(bool QueryConfiguration, ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
/// <summary>
/// queries for any connected devices
/// currently Ribeye can not discover devices
/// </summary>
public void QueryConnectedDevices() { }
public string MACAddress { get; set; }
public string[] DownstreamMACAddresses { get; set; }
public bool IsEthernetDistributor() { return false; }
public bool IsSlice6Distributor() { return false; }
public bool IsBattery() { return false; }
public bool IsTSRAIR() { return false; }
public bool IsSlice6Air() { return false; }
public bool IsSlice6AirTc() { return false; }
public bool IsScheduleEventCountSupported() { return false; }
public double[] GetNominalRanges(SensorConstants.BridgeType bridge)
{
throw new NotImplementedException();
}
public int MaxModules
{
get => 1;
set {; }
}
/// <summary>
/// phase shift information not known for ribeye, so assume 0 for now
/// </summary>
/// <param name="ModuleIndex"></param>
/// <param name="ActualSampleRate"></param>
/// <param name="HardwareAAF"></param>
/// <returns></returns>
public ulong GetPhaseShiftSamples(uint ModuleIndex, double ActualSampleRate, uint HardwareAAF, ulong originalT0) { return 0; }
/// <summary>
/// initiates background flash erase for units that support it
/// will return immediately after flash erase begins
/// </summary>
/// <param name="callbck"></param>
/// <param name="userData"></param>
void IArmActions.BeginBackgroundFlashErase(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
/// <summary>
/// returns whether unit is capable of flash erase
/// </summary>
bool IArmActions.SupportsBackgroundFlashErase => false;
/// <summary>
/// returns whether unit has started background flash erase
/// </summary>
bool IArmActions.BackgroundFlashEraseStarted => false;
DateTime? IArmActions.BackgroundFlashEraseStartTime => null;
int IConfiguration.GetDASDisplayOrder() { return -1; }
int[] IConfiguration.GetChannelDisplayOrder() { return new int[] { -1 }; }
void IConfiguration.SetDASDisplayOrder(int order) { throw new NotSupportedException("Not supported for Ribeye"); }
void IConfiguration.SetChannelDisplayOrder(int[] order) { throw new NotSupportedException("Not supported for Ribeye"); }
public bool RequireDiagnosticRateMatchSampleRate() { return false; }
public DateTime SystemBaseTime => DateTime.MinValue;
public bool SupportsTimeSynchronization => false;
public bool RangeBandwidthLimited => false;
void IArmActions.ReadyForArming(ServiceCallback callback, object userData, Guid eventGuid, int armNowTimeout, bool testingMode,
int maxNumberEvents, bool DummyArm, bool SysMode)
{
var info = new RibeyeArmNowPacket(callback, userData, armNowTimeout);
LaunchAsyncWorker("Ribeye.ReadyArming", new WaitCallback(AsyncReadyArming), info);
}
private void AsyncReadyArming(object asyncInfo)
{
var info = asyncInfo as RibeyeArmNowPacket;
info.Success();
return;
}
public bool CheckAAF(float rate) { return true; }
long IDASCommunication.MaxMemory() { return long.MaxValue; }
//don't know the actual max rate, but hopefully it doesn't run by itself and is controlled by the
//max rate of other hardware
uint IDASCommunication.MaxSampleRate(int numberOfConfiguredChannels) { return uint.MaxValue; }
uint IDASCommunication.MinSampleRate() { return uint.MinValue; }
public uint MaxAAFilterRate() { return uint.MaxValue; }
public float InputLowVoltage { get; set; }
public float InputMediumVoltage { get; set; }
public float InputHighVoltage { get; set; }
public float BatteryLowVoltage { get; set; }
public float BatteryMediumVoltage { get; set; }
public float BatteryHighVoltage { get; set; }
public double MinimumValidInputVoltage { get; set; }
public double MaximumValidInputVoltage { get; set; }
public double MinimumValidBatteryVoltage { get; set; }
public double MaximumValidBatteryVoltage { get; set; }
public bool AutoArmed { get => false; set { } }
/// <summary>
/// the UDP settings to broadcast auto arm status to on auto arm boot
/// 17583 Monitor Test UI
/// </summary>
public string AutoArmUDPSetting { get; set; } = "239.1.2.3:8504";
/// <summary>
/// Auto Arm a single DAS now
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
/// <param name="eventGuid">A unique GUID that this event will be tagged
/// with</param>
void IArmActions.AutoArmNow(ServiceCallback callback, object userData, Guid eventGuid, int
armNowTimeout, bool testingMode, uint diagnosticsDelayMs, int maxNumberEvents, bool repeatEnable, bool preserveDiagnostics)
{
throw new NotSupportedException("AutoArmNow not supported for Ribeye");
}
private Dictionary<DFConstantsAndEnums.ProtocolLimitedCommands, byte> Ribeye_MinimumProtocols = new Dictionary<DFConstantsAndEnums.ProtocolLimitedCommands, byte>();
public override void InitMinProto()
{
// Ribeye Protocol Limitations
MinimumProtocols = Ribeye_MinimumProtocols;
}
private const float RibeyeSampleRate = 10000.0F;
private const string RIBEYE_CONFIGURATION_FILE = "ribeye.xml";
#region Configuration
/// <summary>
/// ConfigData contains all configuration information about the Ribeye
/// </summary>
public IConfigurationData ConfigData { get; set; }
/// <summary>
/// Verify that the ConfigData property is correctly constructed
/// </summary>
/// <param name="DoStrictCheck">Set to true if your're arming</param>
void IConfigurationActions.VerifyConfig(bool DoStrictCheck)
{
VerifyConfig(DoStrictCheck, null);
}
void IConfigurationActions.StoreTestSetupXML(ServiceCallback callback, object userData, string testSetupXML)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
void IConfigurationActions.ResetHardwareLines(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
void IConfigurationActions.CheckAAFilterRate(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
void IConfigurationActions.VerifyConfig(bool DoStrictCheck, ErrorCallback failedChallengeFunc)
{
VerifyConfig(DoStrictCheck, failedChallengeFunc);
}
void VerifyConfig(bool DoStrictCheck, ErrorCallback failedChallengeFunc)
{
// look thru all the config data and make sure it's fit to be used
// our caller have already checked for null, but...
if (ConfigData == null)
{
// "Slice.VerifyConfig: ConfigData is null"
throw new ArgumentException(Strings.Slice_VerifyConfig_Err1);
}
if (string.IsNullOrEmpty(ConfigData.Description))
{
// "Slice.VerifyConfig: ConfigData.Description is null"
//throw new ArgumentException(Strings.Slice_VerifyConfig_Err2);
ConfigData.Description = "";
}
if (DoStrictCheck && string.IsNullOrEmpty(ConfigData.TestID))
{
// "Slice.VerifyConfig: ConfigData.TestID is null"
throw new ArgumentException(Strings.Slice_VerifyConfig_Err3);
//ConfigData.TestID = "Default Test ID";
}
// we don't care about EID's here
if (ConfigData.Modules == null || ConfigData.Modules.Length == 0 || ConfigData.Modules.Length > DASInfo.Modules.Length)
{
// "Slice.VerifyConfig: ConfigData.Modules is null, empty or too long"
throw new ArgumentException(Strings.Slice_VerifyConfig_Err4);
}
for (int moduleIdx = 0; moduleIdx < ConfigData.Modules.Length; moduleIdx++)
{
var module = ConfigData.Modules[moduleIdx];
if (module.ModuleArrayIndex != moduleIdx)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].ModuleNumber doesn't mach index"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err5, moduleIdx));
}
if (module.RecordingMode != DFConstantsAndEnums.RecordingMode.CircularBuffer &&
module.RecordingMode != DFConstantsAndEnums.RecordingMode.RecorderMode)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Mode has incorrect value"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err7, moduleIdx));
}
if (module.SampleRateHz != RibeyeSampleRate)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].SampleRateHz must be below {1}"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err8, moduleIdx, RibeyeSampleRate));
}
if ((uint)((module.PreTriggerSeconds + module.PostTriggerSeconds) * module.SampleRateHz) > DASInfo.Modules[moduleIdx].MaxRecordingSamples)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}] total number of samples must be below {1}"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err9, moduleIdx, DASInfo.Modules[moduleIdx].MaxRecordingSamples));
}
if (module.Channels == null || module.Channels.Length == 0 || module.Channels.Length > DASInfo.Modules[moduleIdx].NumberOfChannels)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels is null, empty or too long"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err10, moduleIdx));
}
for (int channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
{
var channel = (DASChannel)module.Channels[channelIdx];
if (channel.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Disabled)
continue;
if (channel.OwningModule != module)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].OwningModule doesn't mach owner"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err11, moduleIdx, channelIdx));
}
if (channel.ModuleChannelNumber != channelIdx)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].ChannelNumber doesn't mach index"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err12, moduleIdx, channelIdx));
}
if (channel.DiagnosticsMode) { throw new ArgumentException("no Diagnostics Mode support for Ribeye"); }
if (channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Normal &&
channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.DummyArm &&
channel.ConfigurationMode != DFConstantsAndEnums.ConfigMode.Disabled)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].mode has incorrect value"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err13, moduleIdx, channelIdx));
}
if (!(channel is AnalogInputDASChannel))
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}] is not an analog input channel"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err14, moduleIdx, channelIdx));
}
var analog = channel as AnalogInputDASChannel;
if (analog.TypeOfBridge != SensorConstants.BridgeType.FullBridge)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].Bridge has incorrect value"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err15, moduleIdx, channelIdx));
}
if (analog.ShuntIsEnabled)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].BridgeResistanceOhms is outside the allowed range({2}-{3})"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err16, moduleIdx, channelIdx, 0, 0));
}
if (analog.VoltageInsertionCheckEnabled)
{
throw new NotSupportedException("No voltage insertion supported for Ribeye");
}
if (analog.IsProportionalToExcitation)
{
throw new ArgumentException(string.Format(Strings.Ribeye_VerifyConfig_ProportionalNotSupported, moduleIdx * 3 + channelIdx));
}
if (analog.BypassAAFilter)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}], bypassing AA filter is not supported"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err17, moduleIdx, channelIdx));
}
if (analog.DesiredRangeWithHeadroomEU < 0)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].DesiredRange must be positive"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err18, moduleIdx, channelIdx));
}
if (DoStrictCheck && string.IsNullOrEmpty(analog.EngineeringUnits))
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].EngineeringUnits can't be null or empty"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err19, moduleIdx, channelIdx));
}
if (analog.Excitation != ExcitationVoltageOptions.ExcitationVoltageOption.Volt5)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].Excitation only 5 volts is supported"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err20, moduleIdx, channelIdx));
}
if (analog.ZeroMethod != ZeroMethodType.AverageOverTime &&
analog.ZeroMethod != ZeroMethodType.UsePreEventDiagnosticsZero)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}].ZeroMethod has invalid value"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err22, moduleIdx, channelIdx));
}
if (DoStrictCheck && analog.ZeroMethod == ZeroMethodType.AverageOverTime)
{
if (analog.ZeroAverageStartSeconds >= analog.ZeroAverageStopSeconds)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}] zero average start must be less than zero average stop"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err23, moduleIdx, channelIdx));
}
if (analog.ZeroAverageStopSeconds > module.PostTriggerSeconds)
{
// "Slice.VerifyConfig: ConfigData.Module[{0}].Channels[{1}] zero average stop must be less than post-trigger"
throw new ArgumentException(string.Format(Strings.Slice_VerifyConfig_Err25, moduleIdx, channelIdx));
}
}
}
}
}
/// <summary>
/// Apply the data in the ConfigData property to the DAS
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IConfigurationActions.CheckSafetyState(bool bArmed, ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.CheckSafetyState", new WaitCallback(AsyncCheckSafetyState), info);
}
void IConfigurationActions.QueryTestSetup(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
/// <summary>
/// Apply the data in the ConfigData property to the DAS
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IConfigurationActions.Configure(ServiceCallback callback, object userData, bool EventConfig, bool DummyConfig, double [] maxAAF, bool configureDigitalOutputs, uint crc, bool turnOffAAFRealtime,
IStreamingFilterProfile dspFilterType, bool discardDiagnostics, Dictionary<IDASCommunication, ushort> timeChannelIds, Dictionary<IDASCommunication, ushort> dataChannelIds,
Dictionary<IDASCommunication, UDPStreamProfile> streamProfiles, Dictionary<IDASCommunication, int> streamADCPerPacket, Dictionary<IDASCommunication, ushort> irigTDPIntervals,
Dictionary<IDASCommunication, string> addresses, Dictionary<IDASCommunication, uint[]> tmnsConfigs,
Dictionary<IDASCommunication, uint> baudRates, Dictionary<IDASCommunication, uint> dataBits, Dictionary<IDASCommunication, StopBits> stopBits,
Dictionary<IDASCommunication, Parity> parities, Dictionary<IDASCommunication, Handshake> flowControls, Dictionary<IDASCommunication, UartDataFormat> dataFormats,
Dictionary<IDASCommunication, ushort> tmatsIntervals
)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.DiscardDiagnostics = discardDiagnostics;
LaunchAsyncWorker("Ribeye.Configure", new WaitCallback(AsyncConfigure), info);
}
void IConfigurationActions.ApplyLevelTriggers(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.ApplyLevelTriggers", AsyncApplyLevelTriggers, info);
}
private void AsyncApplyLevelTriggers(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
info.Success();
}
private const string KEY_TESTID = "TestID";
private const string KEY_TEST_DESCRIPTION = "TestDescription";
private const string KEY_TEST_GUID = "TestGUID";
private const string KEY_FAULT_FLAGS = "FaultFlags";
private const string KEY_SAMPLE_RATE = "SampleRate";
private const string KEY_RECORDING_MODE = "RecordingMode";
private const string KEY_PRETRIGGER_SECONDS = "PretriggerSeconds";
private const string KEY_POSTTRIGGER_SECONDS = "PosttriggerSeconds";
private const string KEY_CONFIGDATA = "ConfigData";
private void AsyncConfigure(object configAsyncInfo)
{
var info = configAsyncInfo as RibeyeServiceAsyncInfo;
var Configuration = new Utility.XmlDictionary(); ;
var serializer = new XmlSerializer(Configuration.GetType());
if (File.Exists(RIBEYE_CONFIGURATION_FILE))
{
try
{
using (var sr = new StreamReader(RIBEYE_CONFIGURATION_FILE))
{
Configuration = (Utility.XmlDictionary)serializer.Deserialize(sr);
}
}
catch (Exception)
{
}
}
Configuration.Dictionary[KEY_TESTID] = ConfigData.TestID;
Configuration.Dictionary[KEY_TEST_DESCRIPTION] = ConfigData.Description;
Configuration.Dictionary[KEY_SAMPLE_RATE] = ConfigData.Modules.FirstOrDefault().SampleRateHz;
Configuration.Dictionary[KEY_RECORDING_MODE] = ConfigData.Modules.FirstOrDefault().RecordingMode;
Configuration.Dictionary[KEY_PRETRIGGER_SECONDS] = ConfigData.Modules.FirstOrDefault().PreTriggerSeconds;
Configuration.Dictionary[KEY_POSTTRIGGER_SECONDS] = ConfigData.Modules.FirstOrDefault().PostTriggerSeconds;
Configuration.Dictionary[KEY_CONFIGDATA] = ConfigurationData.Serialize((ConfigurationData)ConfigData);
using (var writer = new StreamWriter(RIBEYE_CONFIGURATION_FILE))
{
serializer.Serialize(writer, Configuration);
writer.Close();
}
ConfigurationData.SetConfiguration(this, File.ReadAllText(RIBEYE_CONFIGURATION_FILE), ConfigurationData.DIAGNOSTIC_FILESTORE);
ConfigureHasBeenRun = true;
if (info.DiscardDiagnostics) { DiagnosticsHasBeenRun = false; }
info.Success();
}
private void AsyncCheckSafetyState(object configAsyncInfo)
{
// ribeye doesn't have safety switch info, so might as well return right away.
var info = configAsyncInfo as RibeyeServiceAsyncInfo;
info.Success();
}
/// <summary>
/// Retrieve configuration from DAS and store it in the ConfigData property
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IConfigurationActions.QueryConfiguration(ServiceCallback callback, object userData, uint crc, string strConfig, bool bReadIds, bool bDeviceScaleFactors,
bool differentModuleCountsAreOK)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.QueryConfiguration", new WaitCallback(AsyncQueryConfiguration), info);
}
void IConfigurationActions.UpdateConfigurationFromFile(ServiceCallback callback, object userData,
string filePath)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.UpdateConfigurationFromFile", new WaitCallback(AsyncUpdateConfigurationFromFile),
info);
}
private void AsyncUpdateConfigurationFromFile(object asyncInfo)
{
var info = asyncInfo as RibeyeServiceAsyncInfo;
info.Error("Not supported yet");
return;
}
private void AsyncQueryConfiguration(object configAsyncInfo)
{
var info = configAsyncInfo as RibeyeServiceAsyncInfo;
try
{
var Configuration = new Utility.XmlDictionary(); ;
var serializer = new XmlSerializer(Configuration.GetType());
if (File.Exists(RIBEYE_CONFIGURATION_FILE))
{
try
{
using (var sr = new StreamReader(RIBEYE_CONFIGURATION_FILE))
{
Configuration = (Utility.XmlDictionary)serializer.Deserialize(sr);
}
}
catch (Exception)
{
}
}
if (Configuration.Dictionary.ContainsKey(KEY_CONFIGDATA))
{
ConfigData = ConfigurationData.DeserializeFromString((string)Configuration.Dictionary[KEY_CONFIGDATA]);
}
else
{
ConfigData = MakeDefaultConfigFromInfo();
}
if (Configuration.Dictionary.ContainsKey(KEY_TESTID))
{
ConfigData.TestID = Configuration.Dictionary[KEY_TESTID] as string;
}
if (Configuration.Dictionary.ContainsKey(KEY_TEST_DESCRIPTION))
{
ConfigData.Description = Configuration.Dictionary[KEY_TEST_DESCRIPTION] as string;
}
else
{
ConfigData.Description = "";
}
if (Configuration.Dictionary.ContainsKey(KEY_SAMPLE_RATE))
{
ConfigData.Modules.FirstOrDefault().SampleRateHz = (uint)Configuration.Dictionary[KEY_SAMPLE_RATE];
}
if (Configuration.Dictionary.ContainsKey(KEY_PRETRIGGER_SECONDS))
{
ConfigData.Modules.FirstOrDefault().PreTriggerSeconds = (double)Configuration.Dictionary[KEY_PRETRIGGER_SECONDS];
}
if (Configuration.Dictionary.ContainsKey(KEY_POSTTRIGGER_SECONDS))
{
ConfigData.Modules.FirstOrDefault().PostTriggerSeconds = (double)Configuration.Dictionary[KEY_POSTTRIGGER_SECONDS];
}
// get scale factors
try
{
var scaleFactors = GetScaleFactors();
// set the OwningDAS and OwningModule since it was skipped during serialization
foreach (var iDASModule in ConfigData.Modules)
{
var module = (DASModule)iDASModule;
module.OwningDAS = this;
foreach (var iDASchannel in module.Channels)
{
var channel = (DASChannel)iDASchannel;
channel.OwningModule = module;
// pick up the scalefactor for this channel
if (channel is AnalogInputDASChannel analog)
{
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(module.ModuleArrayIndex, analog.ModuleChannelNumber);
analog.ScalefactorMilliVoltsPerADC = scaleFactors[dasChannelNumber];
analog.IDs = RetriveEIDs(dasChannelNumber);
}
}
}
}
catch
{
// we don't need no stinking scale factors
}
// get sensor ID's
if (ConfigData.Modules != null)
{
foreach (var iDASModule in ConfigData.Modules)
{
var module = (DASModule)iDASModule;
module.OwningDAS = this; // in case bailed out above
foreach (var iDASChannel in module.Channels)
{
var channel = (DASChannel)iDASChannel;
channel.OwningModule = module; // in case bailed out above
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(module.ModuleArrayIndex, channel.ModuleChannelNumber);
channel.IDs = RetriveEIDs(dasChannelNumber);
}
}
}
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
private DASModule MakeConfigModuleFromInfoModule(InfoResult.Module infoModule)
{
var configModule = new DASModule(infoModule.ModuleArrayIndex, this);
if (infoModule.TypeOfModule != DFConstantsAndEnums.ModuleType.RibeyeLED)
{
throw new Exception("Ribeye.MakeConfigModuleFromInfoModule: Unsupported slice type " + infoModule.TypeOfModule.ToString());
}
configModule.Channels = new AnalogInputDASChannel[infoModule.NumberOfChannels];
for (var channelIdx = 0; channelIdx < infoModule.NumberOfChannels; channelIdx++)
{
configModule.Channels[channelIdx] = new AnalogInputDASChannel(configModule, channelIdx);
}
return configModule;
}
private ConfigurationData MakeDefaultConfigFromInfo()
{
var conf = new ConfigurationData();
if (DASInfo != null && DASInfo.Modules != null && DASInfo.Modules.Length > 0)
{
conf.Modules = new DASModule[DASInfo.Modules.Length];
for (var moduleIdx = 0; moduleIdx < DASInfo.Modules.Length; moduleIdx++)
{
conf.Modules[moduleIdx] = MakeConfigModuleFromInfoModule((InfoResult.Module)DASInfo.Modules[moduleIdx]);
}
}
return conf;
}
void IConfigurationActions.Reboot(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
/// <summary>
/// Retrieve the EID's and store it in the ConfigData property
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IConfigurationActions.UpdateIDs(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.UpdateIDs", new WaitCallback(AsyncUpdateIDs), info);
}
void IConfigurationActions.UpdateId(ServiceCallback callback, object userData, DASModule module, DASChannel channel)
{
var info = new UpdateIdsInfo(callback, userData, module, channel);
LaunchAsyncWorker("Ribeye.UpdateId", new WaitCallback(AsyncUpdateId), info);
}
private class UpdateIdsInfo : RibeyeServiceAsyncInfo
{
public DASModule Module { get; set; }
public DASChannel Channel { get; set; }
public UpdateIdsInfo(ServiceCallback callback, object userData, DASModule module, DASChannel channel)
: base(callback, userData)
{
Module = module;
Channel = channel;
}
}
private void AsyncUpdateIDs(object configAsyncInfo)
{
var info = configAsyncInfo as RibeyeServiceAsyncInfo;
if (ConfigData == null)
{
info.Error("DAS doesn't have any ConfigData");
return;
}
try
{
// get sensor ID's
if (ConfigData.Modules != null)
{
foreach (var module in ConfigData.Modules)
{
foreach (var channel in module.Channels)
{
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(module.ModuleArrayIndex, channel.ModuleChannelNumber);
channel.IDs = RetriveEIDs(dasChannelNumber);
}
}
}
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
private void AsyncUpdateId(object configAsyncInfo)
{
var info = configAsyncInfo as UpdateIdsInfo;
try
{
// get sensor ID's
var dasChannelNumber = DASInfo.MapModuleArrayIndexAndChannelNum2DASChannel(info.Module.ModuleArrayIndex, info.Channel.ModuleChannelNumber);
info.Channel.IDs = RetriveEIDs(dasChannelNumber);
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
private float[] GetScaleFactors()
{
var LEDQuery = new QueryNumberOfLEDs(this);
LEDQuery.SyncExecute();
var ScaleFactors = new float[LEDQuery.NumberOfLEDs * 3];
for (var Index = 0; Index < ScaleFactors.Length; Index++)
{
ScaleFactors[Index] = (float)(1.0 / 100.0);
}
return ScaleFactors;
}
private EID[] RetriveEIDs(byte DASChannelNumber)
{
if (RunTestVariables.BypassEIDRead) { return new EID[0]; }
var idList = new List<EID>();
uint LEDNumber = (uint)DASChannelNumber / 3;
uint AxisNumber = (uint)DASChannelNumber % 3;
var EID = "E" + SerialNumber + LEDNumber.ToString("00") + AxisNumber.ToString("0");
idList.Add(new EID(EID));
return idList.ToArray();
}
#endregion
#region Diagnostics
// our public diagnostics member
/// <summary>
/// ChannelDiagnostics is used to indicate which diagnostics are requested
/// </summary>
public IDiagnosticActions[] ChannelDiagnostics { get; set; }
public IArmCheckActions ArmCheckActions { get; set; }
public IArmCheckResults ArmCheckResults { get; set; }
/// <summary>
/// ChannelDiagnosticsResults contains the results of a diagnostics service.
/// </summary>
public IDiagnosticResult[] ChannelDiagnosticsResults { get; set; }
public void SetChannelDiagnosticActions(IDiagnosticActions[] actions, bool setInDb = true)
{
DiagnosticsActions.SetChannelDiagnosticActions(this, actions, setInDb);
}
public void ClearChannelDiagnosticsResults(bool bClearDb = true)
{
DiagnosticsResultActions.ClearChannelDiagnosticsResults(this, bClearDb);
}
public void SetChannelDiagnosticsResults(IDiagnosticResult[] results, bool setInDb)
{
DiagnosticsResultActions.SetChannelDiagnosticsResults(this, results, setInDb);
}
public IModuleDiagnosticsResult[] ModuleDiagnosticsResults { get; set; }
/// <summary>
/// BaseInput contains information about diagnostics for the module.
/// </summary>
public IBaseInputValues BaseInput { get; set; }
#region Clock Sync
public IDictionary<InputClockSource, bool> DASClockSyncStatus { get; set; } = null;
public bool ClockSyncInUTC { get; set; } = false;
public ClockSyncProfile DASClockSyncProfile { get; set; }
public byte PTPDomainID { get; set; }
#endregion
void IDiagnosticsActions.GetBridgeMeasurement(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.GetBridgeMeasurement", new WaitCallback(AsyncDiagnosAndGetResults), info);
}
void IDiagnosticsActions.MeasureTransferSpeed(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
#region Voltage Check
public void PerformVoltageCheck(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.PerformVoltageCheck", new WaitCallback(AsyncPerformVoltageCheck), info);
}
private void AsyncPerformVoltageCheck(object o)
{
RibeyeServiceAsyncInfo info = o as RibeyeServiceAsyncInfo;
info.Success();
}
public void PerformVoltageCheckTAOnly(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.PerformVoltageCheckTAOnly", new WaitCallback(AsyncPerformVoltageCheckTAOnly), info);
}
private void AsyncPerformVoltageCheckTAOnly(object o)
{
RibeyeServiceAsyncInfo info = o as RibeyeServiceAsyncInfo;
info.Success();
}
void IDiagnosticsActions.PerformArmChecks(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.PerformArmChecks", new WaitCallback(AsyncPerformArmChecks), info);
}
void IDiagnosticsActions.SaveTiltSensorDataPre(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.SaveTiltSensorDataPre", new WaitCallback(AsyncSaveTiltSensorDataPre), info);
}
void IDiagnosticsActions.SaveTemperaturesPre(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.SaveTemperaturesPre", new WaitCallback(AsyncSaveTemperaturesPre), info);
}
#endregion Voltage Check
private void AsyncPerformArmChecks(object o)
{
if (!(o is RibeyeServiceAsyncInfo info)) { return; }
info.Success();
}
private void AsyncSaveTiltSensorDataPre(object o)
{
if (!(o is RibeyeServiceAsyncInfo info)) { return; }
info.Success();
}
private void AsyncSaveTemperaturesPre(object o)
{
if (!(o is RibeyeServiceAsyncInfo info)) { return; }
info.Success();
}
/// <summary>
/// Perform diagnostics based on the property ChannelDiagnostics and stuff the
/// result in ChannelDiagnosticsResults
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
/// <param name="DiagnosticsAAFilterFrequencyHz">The AA filter frequency for diagnostics. Not used by Ribeye</param>
/// <param name="DiagnosticsSampleRateHz">The sample rate for diagnostics. Not used by Ribeye</param>
void IDiagnosticsActions.PrepareForDiagnostics(UInt32 DiagnosticsSampleRateHz,
float DiagnosticsAAFilterFrequencyHz,
PrePostResults WhichResult,
ServiceCallback callback,
object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.PrepareForDiagnostics", new WaitCallback(AsyncPrepareForDiagnostics), info);
}
/// <summary>
/// the working guts of PrepareForDiagnostics
/// </summary>
/// <param name="asyncInfo">our async data</param>
private void AsyncPrepareForDiagnostics(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
// we're done
info.Success();
}
catch (CanceledException)
{
// like most tv shows, we have been canceled
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
/// <summary>
/// Perform diagnostics based on the property ChannelDiagnostics and stuff the
/// result in ChannelDiagnosticsResults
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
/// <param name="DiagnosticsAAFilterFrequencyHz">The AA filter rate for
/// diagnostics. Not used by Ribeye</param>
/// <param name="DiagnosticsSampleRateHz">The sample rate for diagnostics. Not
/// used by Ribeye</param>
void IDiagnosticsActions.PrepareForBridgeResistanceMeasurement(UInt32 DiagnosticsSampleRateHz,
float DiagnosticsAAFilterFrequencyHz,
ServiceCallback callback,
object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.PrepareForBridgeResistanceMeasurement", new WaitCallback(AsyncPrepareForBridgeResistanceMeasurement), info);
}
/// <summary>
/// the working guts of PrepareForBridgeResistanceMeasurement
/// </summary>
/// <param name="asyncInfo">our async data</param>
private void AsyncPrepareForBridgeResistanceMeasurement(object asyncInfo)
{
var info = asyncInfo as RibeyeServiceAsyncInfo;
try
{
// we're done
info.Success();
}
catch (CanceledException)
{
// like most tv shows, we have been canceled
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
public void SetStatusIndicator(DiagnosticsStatusIndicatorState state, ServiceCallback callback, object userData)
{
}
public void TurnOffT0Lights(ServiceCallback callback, object userData)
{
}
/// <summary>
/// Perform diagnostics based on the property ChannelDiagnostics and stuff the
/// result in ChannelDiagnosticsResults
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IDiagnosticsActions.DiagnosAndGetResults(int EventNumber,
PrePostResults WhichResult,
ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.DiagnosAndGetResults", new WaitCallback(AsyncDiagnosAndGetResults), info);
}
/// <summary>
/// the working guts of DiagnosAndGetResults
/// </summary>
/// <param name="asyncInfo">our async data</param>
private void AsyncDiagnosAndGetResults(object asyncInfo)
{
var info = asyncInfo as RibeyeServiceAsyncInfo;
try
{
// prepare the result array
var results = new DiagnosticsResult[ChannelDiagnostics.Length];
for (var idx = 0; idx < ChannelDiagnostics.Length; idx++)
{
results[idx] = new DiagnosticsResult();
results[idx].DASChannelNumber = ChannelDiagnostics[idx].DASChannelNumber;
results[idx].EventNumber = DFConstantsAndEnums.EVENT_NUMBER_PRETEST_DIAG; // it's not really an event
}
// There's only one diagnostic, the current positions
var Query = new QueryCurrentPositions(this);
Query.SyncExecute();
var ScaleFactors = GetScaleFactors();
for (var idx = 0; idx < ChannelDiagnostics.Length; idx++)
{
results[idx].ExpectedExcitationMilliVolts = 5000;
results[idx].MeasuredOffsetMilliVolts = Query.Positions[ChannelDiagnostics[idx].DASChannelNumber];
// This is not the real scale factor. But it will make the diagnostics happy. It's OK
// do to this because the real scale factor is queried elsewhere for use with download
var ModuleIndex = ChannelDiagnostics[idx].DASChannelNumber / ConfigData.Modules[0].NumberOfChannels();
var ChannelIndex = ChannelDiagnostics[idx].DASChannelNumber % 3;
AnalogInputDASChannel channel = ConfigData.Modules[ModuleIndex].Channels[ChannelIndex] as AnalogInputDASChannel;
if (null == channel)
{
results[idx].ScalefactorMilliVoltsPerADC = ScaleFactors[ChannelDiagnostics[idx].DASChannelNumber];
}
else
{
results[idx].ScalefactorMilliVoltsPerADC = channel.SensorCapacityEU / Constants.ADC_MIDPOINT;
// Need to update this value for consistency
channel.ScalefactorMilliVoltsPerADC = results[idx].ScalefactorMilliVoltsPerADC;
channel.NoiseAsPercentOfFullScale = null != results[idx].NoisePercentFullScale ? (double)results[idx].NoisePercentFullScale : 0D;
}
results[idx].FinalOffsetADC = (short)(results[idx].MeasuredOffsetMilliVolts / results[idx].ScalefactorMilliVoltsPerADC);
if (channel.RemoveOffset)
{
var ADC = (double)results[idx].MeasuredOffsetMilliVolts / results[idx].ScalefactorMilliVoltsPerADC;
var devPercent = 100D * ADC / short.MaxValue;
results[idx].AutoZeroPercentDeviation = devPercent;
}
else { results[idx].AutoZeroPercentDeviation = null; }
}
SetChannelDiagnosticsResults(results, true);
info.Success();
}
catch (CanceledException)
{
// like most tv shows, we have been canceled
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
/// <summary>
/// Retrieve the results from the implicit pre and post event diagnostics
/// </summary>
/// <param name="EventNumber">Which event number to Retrieve from</param>
/// <param name="WhichResult">The pre or post test results?</param>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IDiagnosticsActions.GetEventDiagnosticsResults(int EventNumber,
PrePostResults WhichResult,
ServiceCallback callback,
object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.GetEventDiagnosticsResults", new WaitCallback(AsyncGetEventDiagnosticsResults), info);
}
private void AsyncGetEventDiagnosticsResults(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
DiagnosticsResult[] resultArray = null;
var scaleFactors = GetScaleFactors();
resultArray = new DiagnosticsResult[scaleFactors.Length];
for (int idx = 0; idx < scaleFactors.Length; idx++)
{
resultArray[idx] = new DiagnosticsResult();
resultArray[idx].DASChannelNumber = idx;
resultArray[idx].EventNumber = 1;
resultArray[idx].ScalefactorMilliVoltsPerADC = scaleFactors[idx];
}
SetChannelDiagnosticsResults(resultArray, true);
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
#endregion
#region Realtime
/// <summary>
/// indicates whether the DAS supports streaming
/// 10572 implement SW side for single command streaming realtime
/// </summary>
public bool SupportsIndividualChannelRealtimeStreaming => false;
public bool SupportsHardwareInputCheck() { return false; }
public bool ControlsDAQ() { return true; }
public bool SupportsAutoArm() { return false; }
public bool SupportsLevelTrigger() { return false; }
public bool SupportsMultipleEvents() { return false; }
public bool SupportsMultipleConfigurations() { return false; }
public bool SupportsRealtime() { return false; }
public bool SupportsStartInversion() => HardwareConstants.SupportsStartInversion(GetHardwareType(), ProtocolVersion);
public bool SupportsTriggerInversion() => HardwareConstants.SupportsTriggerInversion(GetHardwareType(), ProtocolVersion);
public bool InvertTrigger
{
get => false;
set { if (value) { throw new NotSupportedException("Ribeye doesn't support trigger inversion"); } }
}
public bool InvertStart
{
get => false;
set { if (value) { throw new NotSupportedException("Ribeye doesn't support start inversion"); } }
}
public bool IgnoreShortedStart
{
get => false;
set { if (value) { throw new NotSupportedException("Ribeye doesn't support ignore shorted start"); } }
}
public bool IgnoreShortedTrigger
{
get => false;
set { if (value) { throw new NotSupportedException("Ribeye doesn't support ignore shorted trigger"); } }
}
public bool SupportsMultipleSampleRealtime() { return false; }
/// <summary>
/// A list of channels to use with the Realtime service.
/// </summary>
public List<int> RealtimeDASChannels { get; set; }
public List<double> TiltAxisData { get; set; }
EventWaitHandle QuitRealtime;
private class RealTimeAsyncPacket
{
public RibeyeServiceAsyncInfo Info { get; set; }
public System.Threading.Timer Timer { get; set; }
public int SamplesPerSecond { get; set; }
public int MillisecBetweenSamples { get; set; }
public bool AllowMultipleSampleRealtime { get; set; }
}
void IRealTimeActions.RealTime(int samplesPerSecond,
int millisecBetweenSamples,
ServiceCallback callback,
object userData,
bool allowMultipleSampleRealtime,
int moduleIndex,
ManualResetEvent stopEvent,
byte[] channels,
double aaf,
int minCAllbackUpdateTimeMs,
bool UseUDPStreaming,
string hostIPAddress)
{
var packet = new RealTimeAsyncPacket();
packet.Info = new RibeyeServiceAsyncInfo(callback, userData);
packet.SamplesPerSecond = samplesPerSecond;
packet.MillisecBetweenSamples = millisecBetweenSamples;
packet.AllowMultipleSampleRealtime = allowMultipleSampleRealtime;
QuitRealtime = new EventWaitHandle(false, EventResetMode.ManualReset);
LaunchAsyncWorker("Ribeye.RealTime", new WaitCallback(AsyncRealTime), packet);
}
void IRealTimeActions.RealTimePolling(ServiceCallback callback,
object userData,
ManualResetEvent stopEvent,
byte[] channels
)
{
var packet = new RealTimeAsyncPacket();
packet.Info.Success();
}
void IRealTimeActions.RealTimeTiltPolling(ServiceCallback callback, object userData, ManualResetEvent stopEvent)
{
var packet = new RealTimeAsyncPacket();
packet.Info.Success();
}
private void AsyncRealTime(object asyncInfo)
{
var packet = (RealTimeAsyncPacket)asyncInfo;
packet.Info.Success();
}
void IRealTimeActions.ExitRealTimeMode(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.ExitRealTimeMode", new WaitCallback(AsyncExitRealTimeMode), info);
}
private void AsyncExitRealTimeMode(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
QuitRealtime.Set();
if (null != DASArmStatus) DASArmStatus.IsInRealtime = false;// FB15550: Update IsInRealtime flag if we exit RT so DataPRO is aware
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
public string UDPStreamAddress { get; }
void IRealTimeActions.SetUDPStreamProfile(ServiceCallback callback, object userData, UDPStreamProfile streamProfile, string udpAddress, ushort timeChannelId, ushort dataChannelId, uint[] tmnsConfig, ushort irigTimeDataPacketIntervalMs)
{
var packet = new RealTimeAsyncPacket();
packet.Info.Success();
}
void IRealTimeActions.GetUDPStreamProfile(ServiceCallback callback, object userData)
{
var packet = new RealTimeAsyncPacket();
packet.Info.Success();
}
#endregion
#region Arming
/// <summary>
/// The arm status information
/// </summary>
public IArmStatusData DASArmStatus { get; set; }
public bool GetIsInArm()
{
if (null == DASArmStatus) { return false; }
return DASArmStatus.IsArmed;
}
public bool GetIsInRealtime()
{
if (null == DASArmStatus) { return false; }
return DASArmStatus.IsInRealtime;
}
/// <summary>
/// returns true if the unit is known to be streaming
/// does not query the hardware, just returns a flag if it has been set
/// </summary>
/// <returns></returns>
public bool GetIsStreaming()
{
return false;
}
public void SetDASArmStatus(IArmStatusData status, bool bSetInDb)
{
ArmStatus.SetArmStatus(this, status, bSetInDb);
}
public void SetInArm(bool WriteToDb)
{
if (null == DASArmStatus)
{
var armStatus = new ArmStatus()
{
IsArmed = true
};
ArmStatus.SetArmStatus(this, armStatus, WriteToDb);
}
else
{
DASArmStatus.IsArmed = true;
if (WriteToDb)
{
SetDASArmStatus();
}
}
}
public void SetInRealtime(bool WriteToDb, bool ExitRealtimeIfPossible)
{
if (null == DASArmStatus)
{
var armStatus = new ArmStatus()
{
IsInRealtime = true
};
ArmStatus.SetArmStatus(this, armStatus, WriteToDb);
}
else
{
DASArmStatus.IsInRealtime = true;
if (WriteToDb)
{
SetDASArmStatus();
}
}
}
public void SetDASArmStatus()
{
ArmStatus.SetArmStatus(this, DASArmStatus, true);
}
public DFConstantsAndEnums.CommandStatus AutoArmStatus { get; set; } = DFConstantsAndEnums.CommandStatus.StatusNoError;
public FlashEraseStatus DASFlashEraseStatus { get; set; }
void IArmActions.BeginFlashErase(ServiceCallback callback, object userData, bool DummyArm)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
void IArmActions.QueryFlashEraseStatus(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
var eraseStatus = new FlashEraseStatus();
eraseStatus.PercentComplete = 100.0f;
eraseStatus.LastError = DFConstantsAndEnums.CommandStatus.StatusNoError;
DASFlashEraseStatus = eraseStatus;
info.Success();
}
/// <summary>
/// Arm a single DAS now
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
/// <param name="eventGuid">A unique GUID that this event will be tagged
/// with</param>
void IArmActions.ArmNow(ServiceCallback callback, object userData,
Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode)
{
var info = new RibeyeArmNowPacket(callback, userData, armNowTimeout);
LaunchAsyncWorker("Ribeye.ArmNow", new WaitCallback(AsyncArmNow), info);
var Configuration = new Utility.XmlDictionary(); ;
var serializer = new XmlSerializer(Configuration.GetType());
if (File.Exists(RIBEYE_CONFIGURATION_FILE))
{
try
{
using (var sr = new StreamReader(RIBEYE_CONFIGURATION_FILE))
{
Configuration = (Utility.XmlDictionary)serializer.Deserialize(sr);
}
}
catch (Exception)
{
}
}
Configuration.Dictionary[KEY_TEST_GUID] = eventGuid;
using (var writer = new StreamWriter(RIBEYE_CONFIGURATION_FILE))
{
serializer.Serialize(writer, Configuration);
writer.Close();
}
}
void IArmActions.PrepareForArmNow(ServiceCallback callback, object userData,
Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode)
{
var info = new RibeyeArmNowPacket(callback, userData, armNowTimeout);
LaunchAsyncWorker("Ribeye.PrepareForArmNow", new WaitCallback(AsyncPrepareForArmNow), info);
var Configuration = new Utility.XmlDictionary(); ;
var serializer = new XmlSerializer(Configuration.GetType());
if (File.Exists(RIBEYE_CONFIGURATION_FILE))
{
try
{
using (var sr = new StreamReader(RIBEYE_CONFIGURATION_FILE))
{
Configuration = (Utility.XmlDictionary)serializer.Deserialize(sr);
}
}
catch (Exception)
{
}
}
Configuration.Dictionary[KEY_TEST_GUID] = eventGuid;
using (var writer = new StreamWriter(RIBEYE_CONFIGURATION_FILE))
{
serializer.Serialize(writer, Configuration);
writer.Close();
}
}
void IArmActions.ReArm(ServiceCallback callback, object userData, bool autoArm, bool arm, bool repeatEnable)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Error("NotSupported");
}
void IArmActions.PreparedArmNow(ServiceCallback callback, object userData,
Guid eventGuid, int armNowTimeout, bool testingMode, int maxNumberEvents, bool SysMode)
{
var info = new RibeyeArmNowPacket(callback, userData, armNowTimeout);
LaunchAsyncWorker("Ribeye.PreparedArmNow", new WaitCallback(AsyncPreparedArmNow), info);
var Configuration = new Utility.XmlDictionary(); ;
var serializer = new XmlSerializer(Configuration.GetType());
if (File.Exists(RIBEYE_CONFIGURATION_FILE))
{
try
{
using (var sr = new StreamReader(RIBEYE_CONFIGURATION_FILE))
{
Configuration = (Utility.XmlDictionary)serializer.Deserialize(sr);
}
}
catch (Exception)
{
}
}
Configuration.Dictionary[KEY_TEST_GUID] = eventGuid;
using (var writer = new StreamWriter(RIBEYE_CONFIGURATION_FILE))
{
serializer.Serialize(writer, Configuration);
writer.Close();
}
}
private void AsyncArmNow(object asyncInfo)
{
var info = asyncInfo as RibeyeArmNowPacket;
try
{
var Prepare = new PrepareForDataCollection(this, 60000);
Prepare.SyncExecute();
// After we've reset the event list, our (the DAS) EventInfo property is now invalid
SetEventInfo(null);
var ArmNow = new Arm(this, info.ArmNowTimeout);
// Ribeye has different logic than we do. Map theirs to ours
if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBuffer)
{
ArmNow.TStopMS = 0;
ArmNow.TPostMS = (uint)(1000.0 * ConfigData.Modules[0].PostTriggerSeconds);
}
else
{
ArmNow.TStopMS = (uint)(1000.0 * (ConfigData.Modules[0].PostTriggerSeconds + ConfigData.Modules[0].PreTriggerSeconds));
ArmNow.TPostMS = (uint)(1000.0 * ConfigData.Modules[0].PostTriggerSeconds);
}
ArmNow.SyncExecute();
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
private void AsyncPrepareForArmNow(object asyncInfo)
{
var info = (RibeyeArmNowPacket)asyncInfo;
try
{
var Prepare = new PrepareForDataCollection(this, 60000);
Prepare.SyncExecute();
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
private void AsyncPreparedArmNow(object asyncInfo)
{
var info = (RibeyeArmNowPacket)asyncInfo;
try
{
// After we've reset the event list, our (the DAS) EventInfo property is now invalid
SetEventInfo(null);
var ArmNow = new Arm(this, info.ArmNowTimeout);
// Ribeye has different logic than we do. Map theirs to ours
if (ConfigData.Modules[0].RecordingMode == DFConstantsAndEnums.RecordingMode.CircularBuffer)
{
ArmNow.TStopMS = 0;
ArmNow.TPostMS = (uint)(1000.0 * ConfigData.Modules[0].PostTriggerSeconds);
}
else
{
ArmNow.TStopMS = (uint)(1000.0 * (ConfigData.Modules[0].PostTriggerSeconds + ConfigData.Modules[0].PreTriggerSeconds));
ArmNow.TPostMS = (uint)(1000.0 * ConfigData.Modules[0].PostTriggerSeconds);
}
ArmNow.SyncExecute();
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
/// <summary>
/// Arm multiple chained DAS now
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IArmActions.EnableFaultChecking(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.EnableFaultChecking", new WaitCallback(AsyncEnableFaultChecking), info);
}
void IArmActions.CheckAlreadyLevelTriggered(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.CheckAlreadyLevelTriggered", new WaitCallback(AsyncCheckAlreadyLevelTriggered), info);
}
private void AsyncCheckAlreadyLevelTriggered(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
foreach (var m in ConfigData.Modules)
{
foreach (var ch in m.Channels)
{
if (ch is AnalogInputDASChannel)
{
(ch as AnalogInputDASChannel).AlreadyLevelTriggered = false;
}
}
}
info.Success();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
private void AsyncEnableFaultChecking(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
/// <summary>
/// DisAutoArm the DAS
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IArmActions.DisAutoArm(ServiceCallback callback, object userData)
{
throw new NotSupportedException("DisAutoArm not supported for Ribeye");
}
/// <summary>
/// Disarm the DAS
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IArmActions.Disarm(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.EnableDisarm", new WaitCallback(AsyncDisarm), info);
}
private void AsyncDisarm(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
var DisarmCommand = new Disarm(this);
DisarmCommand.SyncExecute();
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
void IArmActions.GetExtendedFaultIds(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.GetExtendedFaultIds", new WaitCallback(RibeyeAsyncGetExtendedFaultIds), info);
}
private void RibeyeAsyncGetExtendedFaultIds(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
info.Success();
}
/// <summary>
/// Retrieve the current arm status from the DAS
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IArmActions.GetArmStatus(ServiceCallback callback, object userData, uint inputVoltageCutoff, int maxTimeout)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.GetArmStatus", new WaitCallback(RibeyeAsyncGetArmStatus), info);
}
private void RibeyeAsyncGetArmStatus(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
var armStatus = new ArmStatus();
var Status = new QueryArmAndTriggerStatus(this);
Status.IO_Timeout = 3000;
try
{
Status.SyncExecute();
}
catch (Exception)
{
Flush(500);
Status = new QueryArmAndTriggerStatus(this);
Status.IO_Timeout = 3000;
Status.SyncExecute();
}
armStatus.IsArmed = Status.IsArmed;
armStatus.IsFaulted = false;
armStatus.IsRecording = Status.IsRecording;
armStatus.IsTriggered = Status.IsTriggered;
armStatus.IsInRealtime = false;
armStatus.IsRearming = false;
// !!!! Do something better!!!!!
armStatus.TotalSamples = 300000;
armStatus.CurrentSample = 0;
armStatus.SampleRate = (uint)RibeyeSampleRate;
armStatus.TimeRemainingSeconds = 30;
armStatus.EventNumber = 0;
armStatus.RecordingMode = 0;
SetDASArmStatus(armStatus, true);
Thread.Sleep(50);
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
/// <summary>
/// Retrieve the current arm status from the DAS
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IArmActions.GetAutoArmStatus(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.GetAutoArmStatus", new WaitCallback(RibeyeAsyncGetAutoArmStatus), info);
}
private void RibeyeAsyncGetAutoArmStatus(object asyncInfo)
{
var info = asyncInfo as RibeyeServiceAsyncInfo;
AutoArmStatus = DFConstantsAndEnums.CommandStatus.StatusUnimplemented;
info.Success();
}
/// <summary>
/// Set the DAS to low power mode
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IArmActions.EnterLowPowerMode(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.LowPowerMode", new WaitCallback(RibeyeAsyncLowPowerMode), info);
}
private void RibeyeAsyncLowPowerMode(object asyncInfo)
{
var info = asyncInfo as RibeyeServiceAsyncInfo;
DiagnosticsHasBeenRun = false;
try
{
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
/// <summary>
/// Tells the DAS to start record
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IArmActions.StartRecord(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.StartRecord", new WaitCallback(RibeyeAsyncStartRecord), info);
}
private void RibeyeAsyncStartRecord(object asyncInfo)
{
// ribeye doesn't have software start. Trigger is the next best thing.
RibeyeAsyncTrigger(asyncInfo);
}
/// <summary>
/// Sends trigger signal to HW
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IArmActions.Trigger(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.Trigger", new WaitCallback(RibeyeAsyncTrigger), info);
}
private void RibeyeAsyncTrigger(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
Trigger Trigger = new Trigger(this);
Trigger.SyncExecute();
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
#endregion
#region Trigger check
// our public trigger check member
public ITriggerCheckResult TriggerResult { get; set; }
#endregion
#region Downloading
void IDownloadActions.SetEventInfo(int eventIndex,
string id,
Guid guid,
ulong totalSamples,
ulong[] triggerSamples,
ulong startRecordSample,
UInt32 eventHasDownloaded,
ServiceCallback callback,
object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Error("Setting event info not supported on Ribeye");
}
private class RibeyeDownloadState : RibeyeServiceAsyncInfo
{
public IDownloadRequest Request;
public ulong SamplesDownloaded; // how many samples have we downloaded so far
public DownloadTestData DownloadCommand;
public RibeyeDownloadState(ServiceCallback cb, object cbObj, IDownloadRequest _Request)
: base(cb, cbObj)
{
Request = _Request;
SamplesDownloaded = 0;
DownloadCommand = null;
}
}
public IDownloadRequest WhatToDownload { get; set; }
public void SetWhatToDownload(IDownloadRequest request, bool bSetInDb = true)
{
DownloadRequest.SetWhatToDownload(this, request, bSetInDb);
}
public IDownloadReport EventInfo { get; set; }
public void SetEventInfo(IDownloadReport eventInfo, bool bSetInDb = true)
{
DownloadReport.SetEventInfo(this, eventInfo, bSetInDb);
}
public bool[] EventDownloadedStatus { get; set; }
public void SetEventDownloadStatus(bool[] status, bool storeInDb = true)
{
DownloadReport.SetEventDownloadStatus(this, status, storeInDb);
}
public void SetEventGuids(Guid[] guids, bool storeInDb = true)
{
DownloadReport.SetEventGuids(this, guids, storeInDb);
}
public Guid[] EventGuids { get; set; }
public ushort[] FaultFlags { get; set; }
public void SetEventFaultFlags(ushort[] flags, bool storeInDb = true)
{
DownloadReport.SetEventFaultFlags(this, flags, storeInDb);
}
public byte[] ArmAttempts { get; set; }
uint[] IDownload.ExtendedFaultFlags1 { get; set; }
uint[] IDownload.ExtendedFaultFlags2 { get; set; }
uint[] IDownload.ExtendedFaultFlags3 { get; set; }
uint[] IDownload.ExtendedFaultFlags4 { get; set; }
void IDownload.SetExtendedFaultFlags(uint[][] flags)
{
DownloadExtendedFaultFunctions.SetExtendedFaultFlags(flags, this);
}
public void SetEventArmAttemps(byte[] armAttempts, bool storeInDb = true)
{
DownloadReport.SetEventArmAttempts(this, armAttempts, storeInDb);
}
/// <summary>
/// Download the data specified in the WhatToDownload property
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IDownloadActions.Download(ServiceCallback callback, object userData)
{
var state = new RibeyeDownloadState(callback, userData, WhatToDownload);
LaunchAsyncWorker("Ribeye.Download", new WaitCallback(Download), state);
}
private void Download(object asyncInfo)
{
var state = asyncInfo as RibeyeDownloadState;
try
{
var NumberOfChannels = EventInfo.Events[WhatToDownload.EventNumber].Modules.Sum(module => module.NumberOfChannels());
// these two are per channel of course
var TotalNumberOfSamples = WhatToDownload.EndSample - WhatToDownload.StartSample + 1;
// allocate array to return to user
var Data = new short[NumberOfChannels][];
for (var idx = 0; idx < NumberOfChannels; idx++)
{
Data[idx] = new short[TotalNumberOfSamples];
}
const uint DownloadChunkMS = 100;
for (uint CurrentMS = 0; CurrentMS < TotalNumberOfSamples / RibeyeSampleRate * 1000.0; CurrentMS += DownloadChunkMS)
{
const int MaximumRetries = 10;
var Sucess = false;
var Download = new DownloadTestData(this);
for (var CurrentRetryCount = 0; CurrentRetryCount < MaximumRetries && false == Sucess; CurrentRetryCount++)
{
Download = new DownloadTestData(this);
Download.IO_Timeout = 5000;
var StartTimeMS = (int)(WhatToDownload.StartSample / RibeyeSampleRate * 1000D + CurrentMS - EventInfo.Events[0].Modules[0].PreTriggerSeconds * 1000D);
Download.StartTimeMS = StartTimeMS;
Download.StopTimeMS = (int)Math.Min(StartTimeMS + DownloadChunkMS, (WhatToDownload.EndSample * 1000D / RibeyeSampleRate - EventInfo.Events[0].Modules[0].PreTriggerSeconds * 1000.0));
try
{
Download.SyncExecute();
Sucess = true;
}
catch (Exception)
{
APILogger.LogString("Ribeye download timed out. Retrying");
Flush(500);
}
}
// OK, we have our data block
var newData = new short[NumberOfChannels][];
for (var channelIdx = 0; channelIdx < NumberOfChannels; channelIdx++)
{
Download.GetChannelData(channelIdx, out newData[channelIdx]);
}
state.SamplesDownloaded = (ulong)(CurrentMS * RibeyeSampleRate / 1000);
state.NewData(newData, state.SamplesDownloaded, ulong.MinValue, ulong.MinValue);
var ratio = Math.Min(1D, state.SamplesDownloaded / (double)(state.Request.EndSample - state.Request.StartSample + 1));
state.Progress((int)(ratio * 100D));
}
state.Progress(100);
// send data to user
state.Success();
}
catch (CanceledException)
{
state.Cancel();
}
catch (Exception ex)
{
state.Error(ex.Message, ex);
}
}
/// <summary>
/// Retrieve info about available events to download
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IDownloadActions.QueryDownload(ServiceCallback callback, object userData, int eventIndex, TDASServiceSetupInfo setupInfo)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
if (eventIndex > 0) { info.Error("only single event support - RibEye"); }
else { LaunchAsyncWorker("Ribeye.QueryDownload", new WaitCallback(RibeyeAsyncQueryDownload), info); }
}
private void RibeyeAsyncQueryDownload(object asyncInfo)
{
var info = asyncInfo as RibeyeServiceAsyncInfo;
var Configuration = new Utility.XmlDictionary();
var serializer = new XmlSerializer(Configuration.GetType());
if (File.Exists(RIBEYE_CONFIGURATION_FILE))
{
try
{
using (var sr = new StreamReader(RIBEYE_CONFIGURATION_FILE))
{
Configuration = (Utility.XmlDictionary)serializer.Deserialize(sr);
}
}
catch (Exception)
{
}
}
try
{
uint EventCount = 1;
var dlReport = new DownloadReport();
// we'll also freshen up the cached event GUIDs
var eventGuids = new Guid[EventCount];
var faultFlags = new ushort[EventCount];
try
{
dlReport.Events = new DownloadReport.EventInfo[EventCount];
for (var eventIdx = 0; eventIdx < EventCount; eventIdx++)
{
// the object to store it all in
var eventInfo = new DownloadReport.EventInfo();
// get the event level values
if (Configuration.Dictionary.ContainsKey(KEY_TEST_DESCRIPTION))
{
eventInfo.Description = Configuration.Dictionary[KEY_TEST_DESCRIPTION] as string;
}
else
{
eventInfo.Description = "";
}
if (Configuration.Dictionary.ContainsKey(KEY_TESTID))
{
eventInfo.TestID = Configuration.Dictionary[KEY_TESTID] as string;
}
eventInfo.EventNumber = eventIdx;
if (Configuration.Dictionary.ContainsKey(KEY_TEST_GUID))
{
eventInfo.TestGUID = (Guid)Configuration.Dictionary[KEY_TEST_GUID];
eventInfo.FaultFlags = (UInt16)Configuration.Dictionary[KEY_FAULT_FLAGS];
eventInfo.ClearFaults();
}
eventGuids[eventIdx] = eventInfo.TestGUID;
faultFlags[eventIdx] = 0;
eventInfo.HasBeenDownloaded = false;
var LEDs = new QueryNumberOfLEDs(this);
LEDs.SyncExecute();
var Data = new QueryDataAvailable(this);
Data.SyncExecute();
eventInfo.Modules = new DASModule[LEDs.NumberOfLEDs];
var numberOfSamples = Data.TotalMS / 1000.0 * RibeyeSampleRate;
var triggerSampleNumber = Data.PreTriggerMS / 1000.0 * RibeyeSampleRate;
//this appears to be not be used, so I commented it out to reduce compiler warnings
// 6/10/2010 - dtm
//var eventStartRecordSampleNumber = 0;
var eventStartTime = DateTime.Now;
for (var moduleIdx = 0; moduleIdx < eventInfo.Modules.Length; moduleIdx++)
{
var module = new DASModule(moduleIdx, this);
// now update the module with dynamic data
module.NumberOfSamples = (ulong)(Data.TotalMS / 1000.0 * RibeyeSampleRate);
module.TriggerSampleNumbers = new UInt64[1]; // only one so far
module.TriggerSampleNumbers[0] = (ulong)(Data.PreTriggerMS / 1000.0 * RibeyeSampleRate);
var phaseshift = GetPhaseShiftSamples(Convert.ToUInt32(module.ModuleArrayIndex),
Convert.ToDouble(ConfigData.Modules[moduleIdx].SampleRateHz),
Convert.ToUInt32(ConfigData.Modules[moduleIdx].AAFilterRateHz),
module.TriggerSampleNumbers[0]);
module.TriggerSampleNumbers[0] += phaseshift;
module.StartRecordSampleNumber = 0;
module.PreTriggerSeconds = Data.PreTriggerMS / 1000.0;
module.PostTriggerSeconds = (Data.PreTriggerMS + Data.PostTriggerMS) / 1000.0;
module.Channels = new DASChannel[3];
module.AAFilterRateHz = ConfigData.Modules[moduleIdx].AAFilterRateHz;
module.SampleRateHz = ConfigData.Modules[moduleIdx].SampleRateHz;
module.Channels = (DASChannel[])ConfigData.Modules[moduleIdx].Channels.Clone();
// update the channel info
for (uint channelIdx = 0; channelIdx < module.Channels.Length; channelIdx++)
{
module.Channels[channelIdx].EventStartTime = eventStartTime;
}
// store it in the object
eventInfo.Modules[moduleIdx] = module;
}
// store it in the object
dlReport.Events[eventIdx] = eventInfo;
}
}
finally
{
SetEventGuids(eventGuids);
SetEventFaultFlags(faultFlags);
}
// now assigned the data to the public property
SetEventInfo(dlReport);
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
void CopyDownloadChannelDataFromConfigData(AnalogInputDASChannel SourceChannel, ref AnalogInputDASChannel DestinationChannel)
{
if (null == SourceChannel)
{
throw new ArgumentException("The internal representation of a source channel was expected to be an AnalogInputDASChannel, but it was null");
}
if (null == DestinationChannel)
{
throw new ArgumentException("The internal representation of a destination channel was expected to be an AnalogInputDASChannel, but it was null");
}
DestinationChannel.BridgeResistanceOhms = SourceChannel.BridgeResistanceOhms;
DestinationChannel.ZeroPoint = SourceChannel.ZeroPoint;
DestinationChannel.BypassAAFilter = SourceChannel.BypassAAFilter;
DestinationChannel.ConfigurationMode = SourceChannel.ConfigurationMode;
DestinationChannel.DiagnosticsMode = SourceChannel.DiagnosticsMode;
}
/// <summary>
/// Figure out if events have been downloaded
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IDownloadActions.QueryDownloadedStatus(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.QueryDownloadedStatus", new WaitCallback(AsyncQueryDownloadedStatus), info);
}
private void AsyncQueryDownloadedStatus(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
int EventCount = 1;
var eventDownloadedStatus = new bool[EventCount];
for (var eventIdx = 0; eventIdx < EventCount; eventIdx++)
{
eventDownloadedStatus[eventIdx] = true;
}
// now assigned the data to the public property
SetEventDownloadStatus(eventDownloadedStatus);
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
/// <summary>
/// Update the recorded trigger sample numbers in HW
/// </summary>
/// <param name="callback">The function to call with information</param>
/// <param name="userData">Whatever you want to pass along</param>
void IDownloadActions.SetTriggerSampleNumbers(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.SetTriggerSampleNumbers", new WaitCallback(AsyncSetTriggerSampleNumbers), info);
}
private void AsyncSetTriggerSampleNumbers(object asyncInfo)
{
var info = (RibeyeServiceAsyncInfo)asyncInfo;
try
{
info.Success();
}
catch (CanceledException)
{
info.Cancel();
}
catch (Exception ex)
{
info.Error(ex.Message, ex);
}
}
void IDownloadActions.SetDownloaded(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
info.Success();
}
#endregion
#region Information
/// <summary>
/// well, something interesting going on here
/// there are multiple definitions for DASInfo property in the inherited interfaces
/// the other one is Communication_DASInfo from ICommunication
/// but since that's a different type, I'm presuming this property was intended to hide that one
/// 6/29/10 - dtm
/// </summary>
public new IInfoResult DASInfo { get; set; }
public void SetDASInfo(IInfoResult dasInfo, bool bSetInDb = true)
{
InfoResult.SetDASInfo(this, dasInfo, bSetInDb);
}
public void SetDASInfo() { InfoResult.SetDASInfo(this); }
#endregion
#region Misc
/// <summary>
/// Provides a string representation of this object.
/// </summary>
/// <returns>a string representing this object</returns>
public override string ToString()
{
var sn = SerialNumber;
if (!string.IsNullOrEmpty(sn))
return sn;
return "Unknown DAS";
}
/// <summary>
/// The number of channels that have been configured. For a Ribeye all channels are always configured
/// </summary>
/// <returns>The number of channels configured</returns>
public int NumberOfConfiguredChannels()
{
if (ConfigData == null)
return 0;
return ConfigData.NumberOfConfiguredChannels();
}
/// <summary>
/// The number of channels in this ribeye
/// </summary>
/// <returns>The number of channels in this ribeye</returns>
public int NumberOfChannels()
{
if (ConfigData == null)
return 0;
return ConfigData.NumberOfChannels();
}
/// <summary>
/// CompareTo delegate for sorting, etc.
/// </summary>
/// <param name="das">The das to compare with this das</param>
/// <returns></returns>
public int CompareTo(IDASCommunication das)
{
if (das == null || string.IsNullOrEmpty(das.SerialNumber) || string.IsNullOrEmpty(SerialNumber))
return 0;
return SerialNumber.CompareTo(das.SerialNumber);
}
/// <summary>
/// Tracks if diagnostics have been run
/// </summary>
public bool DiagnosticsHasBeenRun { get; set; }
public bool ConfigureHasBeenRun { get; set; } = false;
private class RibeyeArmNowPacket : RibeyeServiceAsyncInfo
{
public int ArmNowTimeout { get; set; }
public RibeyeArmNowPacket(ServiceCallback callback, object userData, int armNowTimeout)
: base(callback, userData)
{
ArmNowTimeout = armNowTimeout;
}
}
private class RibeyeServiceAsyncInfo
{
public ServiceCallback Callback { get; set; }
public object UserData { get; set; }
public object FunctionData { get; set; }
public bool DiscardDiagnostics { get; set; } = true;
public RibeyeServiceAsyncInfo(ServiceCallback _callback, object _userData)
{
Callback = _callback;
UserData = _userData;
}
public void Error(string msg, Exception ex)
{
try
{
var cbData = new ServiceCallbackData();
cbData.Status = ServiceCallbackData.CallbackStatus.Failure;
cbData.ErrorMessage = msg;
cbData.ErrorException = ex;
cbData.UserData = UserData;
Callback(cbData);
}
catch (Exception eex)
{
APILogger.Log("MessageBox", Strings.RibeyeAsyncInfoError, eex);
}
}
public void Error(string msg)
{
Error(msg, null);
}
public void Progress(int value)
{
try
{
var progressData = new ServiceCallbackData();
progressData.Status = ServiceCallbackData.CallbackStatus.ProgressReport;
progressData.ProgressValue = value;
progressData.UserData = UserData;
Callback(progressData);
}
catch (Exception ex)
{
APILogger.Log("MessageBox", Strings.RibeyeAsyncInfoProgressError, ex);
}
}
public void NewData(short[][] data, ulong samplenumber, ulong timeStamp, ulong sequenceNumber)
{
try
{
var progressData = new ServiceCallbackData();
progressData.Status = ServiceCallbackData.CallbackStatus.NewData;
progressData.ProgressValue = 0;
progressData.UserData = UserData;
progressData.AddSampleData(data, samplenumber, timeStamp, sequenceNumber);
Callback(progressData);
}
catch (Exception ex)
{
APILogger.Log("MessageBox", Strings.RibeyeAsyncInfoNewDataError, ex);
}
}
public void Success()
{
try
{
var success = new ServiceCallbackData();
success.Status = ServiceCallbackData.CallbackStatus.Success;
success.UserData = UserData;
Callback(success);
}
catch (Exception ex)
{
APILogger.Log("MessageBox", Strings.RibeyeAsyncInfoSuccessError, ex);
}
}
public void Cancel()
{
try
{
var cancelReport = new ServiceCallbackData();
cancelReport.Status = ServiceCallbackData.CallbackStatus.Canceled;
cancelReport.ProgressValue = 0;
cancelReport.UserData = UserData;
Callback(cancelReport);
}
catch (Exception ex)
{
APILogger.Log("MessageBox", Strings.RibeyeAsyncInfoCancelError, ex);
}
}
}
private void LaunchAsyncWorker(string Invoker, WaitCallback cb, object asyncInfo)
{
if (!Connected)
{
// "{0}: Not currently connected"
throw new NotConnectedException(string.Format(Strings.Slice_LaunchAsyncWorker_Err1, Invoker));
}
if (!ThreadPool.QueueUserWorkItem(cb, asyncInfo))
{
// "{0}: Unable to enqueue function"
throw new Exception(string.Format(Strings.Slice_LaunchAsyncWorker_Err2, Invoker));
}
}
#endregion
void IDiagnosticsActions.SquibFireCheckArm(double delay, double duration, ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.SquibFireCheckArm", new WaitCallback(AsyncSquibFireCheckArm), info);
}
/// <summary>
/// the working guts of PrepareForDiagnostics
/// </summary>
/// <param name="asyncInfo">our async data</param>
private void AsyncSquibFireCheckArm(object asyncInfo)
{
var packet = (RibeyeServiceAsyncInfo)asyncInfo;
packet.Success();
}
void IDiagnosticsActions.TriggerCheckTrigger(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.TriggerCheckTrigger", new WaitCallback(AsyncTriggerCheckTrigger), info);
}
/// <summary>
/// the working guts of PrepareForDiagnostics
/// </summary>
/// <param name="asyncInfo">our async data</param>
private void AsyncTriggerCheckTrigger(object asyncInfo)
{
var packet = asyncInfo as RibeyeServiceAsyncInfo;
packet.Success();
}
void IDiagnosticsActions.TriggerCheckDownload(double delay, double duration, float dummyAAFilterFrequencyHz, uint dummySampleRateHz, ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.TriggerCheckDownload", new WaitCallback(AsyncTriggerCheckDownload), info);
}
/// <summary>
/// the working guts of PrepareForDiagnostics
/// </summary>
/// <param name="asyncInfo">our async data</param>
private void AsyncTriggerCheckDownload(object asyncInfo)
{
var packet = asyncInfo as RibeyeServiceAsyncInfo;
packet.Success();
}
public void CorrectT0s(ServiceCallback callback, object userData)
{
var info = new RibeyeServiceAsyncInfo(callback, userData);
LaunchAsyncWorker("Ribeye.CorrectT0s", new WaitCallback(AsyncCorrectT0s), info);
}
private void AsyncCorrectT0s(object asyncInfo)
{
var packet = asyncInfo as RibeyeServiceAsyncInfo;
packet.Error("Not supported");
return;
}
}
/// <summary>
/// EthernetRibeye is a empty wrapper for a Ribeye connected over ethernet
/// </summary>
public class EthernetRibeye : Ribeye<EthernetConnection>
{
}
}