init
This commit is contained in:
39
DataPRO/IService/StateMachine/DASState.cs
Normal file
39
DataPRO/IService/StateMachine/DASState.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public abstract class DASStateSelector : DASState, IDASStateWithSelector
|
||||
{
|
||||
public abstract IDASState StateSelector();
|
||||
}
|
||||
public abstract class DASState : IDASState
|
||||
{
|
||||
public IDASFactory DASFactory { get; set; }
|
||||
public abstract State State { get; }
|
||||
public virtual Action OnEntry { get => OnEnterState; }
|
||||
public virtual Action OnExit { get => OnExitState; }
|
||||
|
||||
public virtual void OnEnterState()
|
||||
{
|
||||
Console.WriteLine($"Enter {State.ToString()} State");
|
||||
}
|
||||
|
||||
public virtual void OnExitState()
|
||||
{
|
||||
Console.WriteLine($"Exit {State.ToString()} State");
|
||||
}
|
||||
/// <summary>
|
||||
/// for now we enforce that there is just one status object
|
||||
/// we'll probably want to refactor this at some point how
|
||||
/// this information is stored and passed, but this will prevent
|
||||
/// accidents from happening in the short term
|
||||
/// </summary>
|
||||
private static readonly Status _status = new Status();
|
||||
|
||||
public Status Status
|
||||
{
|
||||
get => _status;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
DataPRO/IService/StateMachine/IDASState.cs
Normal file
21
DataPRO/IService/StateMachine/IDASState.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public interface IDASState
|
||||
{
|
||||
Status Status { get; }
|
||||
IDASFactory DASFactory { get; set; }
|
||||
Action OnEntry { get; }
|
||||
Action OnExit { get; }
|
||||
State State { get; }
|
||||
void OnEnterState();
|
||||
void OnExitState();
|
||||
}
|
||||
|
||||
public interface IDASStateWithSelector : IDASState
|
||||
{
|
||||
IDASState StateSelector();
|
||||
}
|
||||
}
|
||||
1073
DataPRO/IService/StateMachine/StateMachineBootstrap.cs
Normal file
1073
DataPRO/IService/StateMachine/StateMachineBootstrap.cs
Normal file
File diff suppressed because it is too large
Load Diff
109
DataPRO/IService/StateMachine/States.cs
Normal file
109
DataPRO/IService/StateMachine/States.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public enum State
|
||||
{
|
||||
Prepare,
|
||||
HardwareDiscovery,
|
||||
HardwareDiscoveryStart,
|
||||
Configure,
|
||||
ConfigureStart,
|
||||
Diagnose,
|
||||
Realtime,
|
||||
Arming,
|
||||
Arm,
|
||||
Download,
|
||||
RealtimeStart,
|
||||
DownloadStart
|
||||
}
|
||||
|
||||
public class States
|
||||
{
|
||||
private static readonly States instance = new States();
|
||||
private Dictionary<State, IDASState> _statesDict = new Dictionary<State, IDASState>();
|
||||
private Dictionary<State, IDASStateWithSelector> _statesSelectableDict = new Dictionary<State, IDASStateWithSelector>();
|
||||
|
||||
// Explicit static constructor to tell C# compiler
|
||||
// not to mark type as beforefieldinit
|
||||
// https://csharpindepth.com/articles/singleton
|
||||
static States()
|
||||
{
|
||||
}
|
||||
|
||||
public IDASState Prepare { get => _statesDict[State.Prepare]; }
|
||||
public IDASState HardwareDiscovery { get => _statesDict[State.HardwareDiscovery]; }
|
||||
public IDASStateWithSelector HardwareDiscoveryStart { get => _statesSelectableDict[State.HardwareDiscoveryStart]; }
|
||||
public IDASState Download { get => _statesDict[State.Download]; }
|
||||
public IDASStateWithSelector DownloadStart { get => _statesSelectableDict[State.DownloadStart]; }
|
||||
public IDASStateWithSelector Diagnose { get => _statesSelectableDict[State.Diagnose]; }
|
||||
public IDASStateWithSelector Configure { get => _statesSelectableDict[State.Configure]; }
|
||||
public IDASState Arming { get => _statesDict[State.Arming]; }
|
||||
public IDASState Arm { get => _statesDict[State.Arm]; }
|
||||
public IDASState Realtime { get => _statesDict[State.Realtime]; }
|
||||
public IDASStateWithSelector RealtimeStart { get => _statesSelectableDict[State.RealtimeStart]; }
|
||||
public IDASStateWithSelector ConfigureStart
|
||||
{
|
||||
get => _statesSelectableDict[State.ConfigureStart];
|
||||
}
|
||||
|
||||
public static void SetDASFactory(IDASFactory dasFactory)
|
||||
{
|
||||
foreach (var enumState in Instance._statesDict)
|
||||
{
|
||||
enumState.Value.DASFactory = dasFactory;
|
||||
}
|
||||
|
||||
foreach (var enumState in Instance._statesSelectableDict)
|
||||
{
|
||||
enumState.Value.DASFactory = dasFactory;
|
||||
}
|
||||
}
|
||||
private States()
|
||||
{
|
||||
AddState(State.Prepare, new Prepare());
|
||||
AddState(State.HardwareDiscovery, new HardwareDiscovery());
|
||||
AddState(State.HardwareDiscoveryStart, new HardwareDiscoveryStart());
|
||||
AddState(State.Configure, new Configure());
|
||||
AddState(State.Download, new Download());
|
||||
AddState(State.Diagnose, new Diagnose());
|
||||
AddState(State.Arming, new Arming());
|
||||
AddState(State.Arm, new Arm());
|
||||
AddState(State.Realtime, new Realtime());
|
||||
AddState(State.ConfigureStart, new ConfigureStart());
|
||||
AddState(State.RealtimeStart, new RealtimeStart());
|
||||
AddState(State.DownloadStart, new DownloadStart());
|
||||
}
|
||||
private void AddState<T>(State state, T dasState)
|
||||
{
|
||||
if (dasState is IDASStateWithSelector)
|
||||
{
|
||||
_statesSelectableDict.Add(state, (IDASStateWithSelector)dasState);
|
||||
return;
|
||||
}
|
||||
_statesDict.Add(state, (IDASState)dasState);
|
||||
}
|
||||
public IDASState GetIDASState(State state)
|
||||
{
|
||||
if (_statesDict.ContainsKey(state))
|
||||
{
|
||||
return _statesDict[state];
|
||||
}
|
||||
if (_statesSelectableDict.ContainsKey(state))
|
||||
{
|
||||
return _statesSelectableDict[state];
|
||||
}
|
||||
throw new InvalidOperationException("Undefined State");
|
||||
}
|
||||
|
||||
public static States Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
DataPRO/IService/StateMachine/States/Arm.cs
Normal file
9
DataPRO/IService/StateMachine/States/Arm.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
internal class Arm : DASState
|
||||
{
|
||||
public override State State => State.Arm;
|
||||
}
|
||||
}
|
||||
9
DataPRO/IService/StateMachine/States/Arming.cs
Normal file
9
DataPRO/IService/StateMachine/States/Arming.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
internal class Arming : DASState
|
||||
{
|
||||
public override State State => State.Arming;
|
||||
}
|
||||
}
|
||||
26
DataPRO/IService/StateMachine/States/Configure.cs
Normal file
26
DataPRO/IService/StateMachine/States/Configure.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class Configure : DASStateSelector
|
||||
{
|
||||
public override IDASState StateSelector()
|
||||
{
|
||||
if (AllowApplyConfig())
|
||||
{
|
||||
return States.Instance.ConfigureStart;
|
||||
}
|
||||
return States.Instance.Configure;
|
||||
}
|
||||
|
||||
public override State State => State.Configure;
|
||||
|
||||
public bool AllowApplyConfig()
|
||||
{
|
||||
//needs to decide based on 1) are all channels resolved (or do we even require that?) 2) are there channels out of place
|
||||
//(or do we even care about that?) 3) are there any channels resolved?
|
||||
//for now we'll just return true till there's some logic ready to be put in place
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
DataPRO/IService/StateMachine/States/ConfigureStart.cs
Normal file
30
DataPRO/IService/StateMachine/States/ConfigureStart.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class ConfigureStart : DASStateSelector
|
||||
{
|
||||
public override State State => State.ConfigureStart;
|
||||
|
||||
public override IDASState StateSelector()
|
||||
{
|
||||
//more work needs to go in here ...
|
||||
return States.Instance.Diagnose;
|
||||
}
|
||||
|
||||
public override Action OnEntry
|
||||
{
|
||||
get
|
||||
{
|
||||
return ApplyConfig;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyConfig()
|
||||
{
|
||||
OnEnterState();
|
||||
Status.ConfigureStatus.ApplyConfig();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
29
DataPRO/IService/StateMachine/States/Diagnose.cs
Normal file
29
DataPRO/IService/StateMachine/States/Diagnose.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class Diagnose : DASStateSelector
|
||||
{
|
||||
public override State State => State.Diagnose;
|
||||
|
||||
public override IDASState StateSelector()
|
||||
{
|
||||
if (CanTransitToRealtimeStart())
|
||||
{
|
||||
return States.Instance.RealtimeStart;
|
||||
}
|
||||
|
||||
return States.Instance.Diagnose;
|
||||
}
|
||||
private bool CanTransitToRealtimeStart()
|
||||
{
|
||||
if (Status.DiagnoseParams.ProceedToRealtimeWhenDone && Status.DiagnoseParams.AllUnitsPassedDiagnostic)
|
||||
return true;
|
||||
|
||||
if (Status.DiagnoseParams.ProceedToRealtimeWhenDone && !Status.DiagnoseParams.RequireAllUnitsPassDiagnostic)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
DataPRO/IService/StateMachine/States/Download.cs
Normal file
9
DataPRO/IService/StateMachine/States/Download.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
internal class Download : DASState
|
||||
{
|
||||
public override State State => State.Download;
|
||||
}
|
||||
}
|
||||
39
DataPRO/IService/StateMachine/States/DownloadStart.cs
Normal file
39
DataPRO/IService/StateMachine/States/DownloadStart.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class DownloadStart : DASStateSelector
|
||||
{
|
||||
private void Start()
|
||||
{
|
||||
OnEnterState();
|
||||
Status.DownloadStatusInfo.Download();
|
||||
}
|
||||
|
||||
private bool CanTransitToPrepare()
|
||||
{
|
||||
return Status.DownloadParams.ProceedWhenDone && (Status.DownloadStatusInfo.AllDASFinished || !Status.DownloadParams.RequireAllDASFinish);
|
||||
}
|
||||
|
||||
public override IDASState StateSelector()
|
||||
{
|
||||
if (CanTransitToPrepare())
|
||||
{
|
||||
return States.Instance.Prepare;
|
||||
}
|
||||
return States.Instance.Download;
|
||||
}
|
||||
|
||||
public override Action OnEntry
|
||||
{
|
||||
get => Start;
|
||||
}
|
||||
|
||||
public override State State => State.DownloadStart;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
internal class HardwareDiscovery : DASState
|
||||
{
|
||||
public override State State => State.HardwareDiscovery;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class HardwareDiscoveryStart : DASStateSelector
|
||||
{
|
||||
private void Start()
|
||||
{
|
||||
OnEnterState();
|
||||
if (null != Status.HardwareDiscoveryParams.RequeryDevice)
|
||||
{
|
||||
Status.HardwareDiscoveryStatusInfo.RequeryDevice();
|
||||
}
|
||||
else { Status.HardwareDiscoveryStatusInfo.Ping(); }
|
||||
}
|
||||
|
||||
private bool CanTransitToDownload()
|
||||
{
|
||||
return CanTransitToConfigure() && Status.HardwareDiscoveryParams.GoToDownload;
|
||||
}
|
||||
|
||||
private bool CanTransitToConfigure()
|
||||
{
|
||||
return Status.HardwareDiscoveryParams.ProceedWhenDone && (Status.HardwareDiscoveryStatusInfo.AllDASFound || !Status.HardwareDiscoveryParams.RequireAllDASFound);
|
||||
}
|
||||
private bool CanTransitToArm()
|
||||
{
|
||||
return Status.HardwareDiscoveryParams.ProceedWhenDone && Status.HardwareDiscoveryStatusInfo.SomeUnitsInArmState;
|
||||
}
|
||||
|
||||
public override IDASState StateSelector()
|
||||
{
|
||||
if (CanTransitToDownload())
|
||||
return States.Instance.Download;
|
||||
|
||||
if (CanTransitToConfigure())
|
||||
return States.Instance.Configure;
|
||||
|
||||
if (CanTransitToArm())
|
||||
return States.Instance.Arm;
|
||||
|
||||
return States.Instance.HardwareDiscovery;
|
||||
}
|
||||
public override Action OnEntry
|
||||
{
|
||||
get => Start;
|
||||
}
|
||||
|
||||
public override State State => State.HardwareDiscoveryStart;
|
||||
}
|
||||
}
|
||||
23
DataPRO/IService/StateMachine/States/Prepare.cs
Normal file
23
DataPRO/IService/StateMachine/States/Prepare.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
internal class Prepare : DASState
|
||||
{
|
||||
private void PrepareDASFactory()
|
||||
{
|
||||
OnEnterState();
|
||||
if (null != DASFactory)
|
||||
{
|
||||
DASFactory.DetachAllDevices();
|
||||
DASFactory.TDASHostNames = new string[0];
|
||||
DASFactory.SliceDBHostNames = new string[0];
|
||||
}
|
||||
}
|
||||
public override State State => State.Prepare;
|
||||
public override Action OnEntry
|
||||
{
|
||||
get => PrepareDASFactory;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
DataPRO/IService/StateMachine/States/Realtime.cs
Normal file
9
DataPRO/IService/StateMachine/States/Realtime.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class Realtime : DASState
|
||||
{
|
||||
public override State State => State.Realtime;
|
||||
}
|
||||
}
|
||||
32
DataPRO/IService/StateMachine/States/RealtimeStart.cs
Normal file
32
DataPRO/IService/StateMachine/States/RealtimeStart.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class RealtimeStart : DASStateSelector
|
||||
{
|
||||
public override State State => State.RealtimeStart;
|
||||
public override Action OnEntry => Start;
|
||||
|
||||
public override IDASState StateSelector()
|
||||
{
|
||||
if (Status.RealtimeStatus.CouldNotStartRealtime)
|
||||
{
|
||||
return States.Instance.RealtimeStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
return States.Instance.Realtime;
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
OnEnterState();
|
||||
Status.RealtimeStatus.StartRealtime();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,721 @@
|
||||
using DTS.Common.Interface.Channels;
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using DTS.Common.Interface.DASFactory.Config;
|
||||
using DTS.Common.Interface.Sensors;
|
||||
using DTS.Common.Interface.StatusAndProgressBar;
|
||||
using DTS.Common.Utilities.Logging;
|
||||
using DTS.DASLib.Service.StateMachine.StatusAndParameters.Configure;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class ConfigureStatusInformation : IStatusInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// all possible status that can be relayed to consumers
|
||||
/// </summary>
|
||||
public enum StatusValues
|
||||
{
|
||||
ApplyingConfiguration,
|
||||
AutoResolvingChannels,
|
||||
ManuallyResolvedChannels,
|
||||
Completed,
|
||||
Cancelling,
|
||||
Cancelled,
|
||||
ChannelOutOfPosition,
|
||||
NoChannelsAssigned,
|
||||
AllChannelsResolved,
|
||||
EIDNotFound,
|
||||
ApplyConfigFailed,
|
||||
AppliedConfiguration,
|
||||
PrepareForDiagnostics,
|
||||
PrepareForDiagnosticsFailed,
|
||||
PrepareForDiagnosticsSuccess,
|
||||
LowPower,
|
||||
LowPowerSuccess,
|
||||
LowPowerFailure
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// no channels are currently assigned
|
||||
/// </summary>
|
||||
public bool NoChannelsAssigned { get; internal set; } = true;
|
||||
/// <summary>
|
||||
/// all channels to be resolved are resolved
|
||||
/// </summary>
|
||||
public bool AllChannelsResolved { get; internal set; } = false;
|
||||
/// <summary>
|
||||
/// one or more channels are out of position with respect to how
|
||||
/// they requested to be positioned (they are on a different channel than they were specified to be on)
|
||||
/// </summary>
|
||||
public bool ChannelsOutOfPosition { get; internal set; } = false;
|
||||
/// <summary>
|
||||
/// all units that were to be configured were configured
|
||||
/// </summary>
|
||||
public bool HaveAppliedConfigAllUnits { get; set; } = false;
|
||||
/// <summary>
|
||||
/// signals a cancel request
|
||||
/// </summary>
|
||||
public ManualResetEvent CancelEvent = new ManualResetEvent(false);
|
||||
/// <summary>
|
||||
/// signals when work is finished
|
||||
/// </summary>
|
||||
public ManualResetEvent DoneEvent = new ManualResetEvent(false);
|
||||
/// <summary>
|
||||
/// action to take on completion of work
|
||||
/// </summary>
|
||||
public ActionCompleteDelegate CompleteAction { get; set; }
|
||||
/// <summary>
|
||||
/// action to take on progress notification
|
||||
/// </summary>
|
||||
public SetProgressValueDelegate ProgressAction { get; set; }
|
||||
/// <summary>
|
||||
/// action to take on a status notification
|
||||
/// </summary>
|
||||
public StatusIntDelegate StatusAction { get; set; }
|
||||
/// <summary>
|
||||
/// action to take on extended status notification
|
||||
/// </summary>
|
||||
public StatusExIntDelegate StatusExAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// holds references to all units which were successfully configured
|
||||
/// </summary>
|
||||
public IDASCommunication[] UnitsConfigured { get; set; } = new IDASCommunication[0];
|
||||
/// <summary>
|
||||
/// task for turning excitation on/off, used for monitoring task or interrupting
|
||||
/// </summary>
|
||||
private Task _ExcitationTask = null;
|
||||
/// <summary>
|
||||
/// task for applying configuration, used for monitoring task or interrupting
|
||||
/// </summary>
|
||||
private Task _ApplyConfigTask = null;
|
||||
/// <summary>
|
||||
/// used to canel running task
|
||||
/// returns when task is cancelled or completed
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task Cancel()
|
||||
{
|
||||
CancelEvent.Set();
|
||||
StatusAction?.Invoke((int)StatusValues.Cancelling);
|
||||
//simulate time spent waiting for cancel to be acknowledged
|
||||
Thread.Sleep(100);
|
||||
DoneEvent.WaitOne();
|
||||
StatusAction?.Invoke((int)StatusValues.Cancelled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// turns on power (if requested and appropriate)
|
||||
/// </summary>
|
||||
private void PrepareForDiagnostics()
|
||||
{
|
||||
var param = States.Instance.Configure.Status.ConfigureParameters;
|
||||
var status = States.Instance.Configure.Status.ConfigureStatus;
|
||||
var global = States.Instance.Configure.Status.GlobalStatusInformation;
|
||||
var dasFactory = States.Instance.Configure.DASFactory;
|
||||
|
||||
//make sure we have some units to turn on, if not fail task
|
||||
if (!status.UnitsConfigured.Any())
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.PrepareForDiagnosticsFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
ProgressAction?.Invoke(0D);
|
||||
StatusAction?.Invoke((int)StatusValues.PrepareForDiagnostics);
|
||||
|
||||
//record if any units fail to turn on excitation
|
||||
var bPassed = true;
|
||||
var mre = new ManualResetEvent(false);
|
||||
try
|
||||
{
|
||||
using (var diagnosticsService = new DiagnosticsService())
|
||||
{
|
||||
var units = status.UnitsConfigured.ToList();
|
||||
diagnosticsService.PrepareForDiagnostics(units,
|
||||
PrePostResults.PreEventDiagnosticsResult,
|
||||
param.SampleRateLookup,
|
||||
param.AAFRateLookup,
|
||||
(ServiceBase.CallbackData data) =>
|
||||
{
|
||||
switch (data.Status)
|
||||
{
|
||||
case ServiceBase.CallbackData.CallbackStatus.Success:
|
||||
StatusExAction?.Invoke((int)StatusValues.PrepareForDiagnosticsSuccess, data.Target);
|
||||
global.AddUnitAtHighPower(data.Target);
|
||||
break;
|
||||
case ServiceBase.CallbackData.CallbackStatus.Failure:
|
||||
bPassed = false;
|
||||
StatusExAction?.Invoke((int)StatusValues.PrepareForDiagnosticsFailed, data.Target);
|
||||
break;
|
||||
case ServiceBase.CallbackData.CallbackStatus.AllFinished:
|
||||
mre.Set();
|
||||
break;
|
||||
}
|
||||
},
|
||||
units);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
bPassed = false;
|
||||
throw ex;
|
||||
}
|
||||
|
||||
var timeWaited = 0;
|
||||
while (!mre.WaitOne(PREPARE_SPIN_TIME, false))
|
||||
{
|
||||
timeWaited += PREPARE_SPIN_TIME;
|
||||
ProgressAction?.Invoke(100D * timeWaited / EXPECTED_PREPARE_TIME);
|
||||
}
|
||||
if (bPassed)
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.PrepareForDiagnosticsSuccess);
|
||||
States.Instance.ConfigureStart.Status.GlobalStatusInformation.ExcitationOn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.PrepareForDiagnosticsFailed);
|
||||
}
|
||||
}
|
||||
|
||||
private const int PREPARE_SPIN_TIME = 200;
|
||||
private const int EXPECTED_PREPARE_TIME = 8000;
|
||||
/// <summary>
|
||||
/// lock used to control thread access to shared resources
|
||||
/// [like UnitsConfigured]
|
||||
/// </summary>
|
||||
private static readonly object MyLock = new object();
|
||||
private void AddConfiguredDevice(IDASCommunication device)
|
||||
{
|
||||
lock (MyLock)
|
||||
{
|
||||
if (UnitsConfigured.Contains(device)) { return; }
|
||||
var list = new List<IDASCommunication>();
|
||||
list.AddRange(UnitsConfigured);
|
||||
list.Add(device);
|
||||
UnitsConfigured = list.ToArray();
|
||||
}
|
||||
StatusExAction?.Invoke((int)StatusValues.AppliedConfiguration, device);
|
||||
}
|
||||
/// <summary>
|
||||
/// Turns off excitation, returns immediately
|
||||
/// </summary>
|
||||
public void TurnOffExcitation()
|
||||
{
|
||||
var param = States.Instance.ConfigureStart.Status.ConfigureParameters;
|
||||
//reset the flag that got us here
|
||||
param.TurnOffExcitation = false;
|
||||
var status = States.Instance.ConfigureStart.Status.ConfigureStatus;
|
||||
var dasFactory = States.Instance.ConfigureStart.DASFactory;
|
||||
|
||||
_ExcitationTask = Task.Run(() =>
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.LowPower);
|
||||
var units = dasFactory.GetDASList();
|
||||
var anyFailed = false;
|
||||
try
|
||||
{
|
||||
var mre = new ManualResetEvent(false);
|
||||
using (var service = new ArmingService())
|
||||
{
|
||||
service.EnterLowPowerMode(units, (ServiceBase.CallbackData data) =>
|
||||
{
|
||||
switch (data.Status)
|
||||
{
|
||||
case ServiceBase.CallbackData.CallbackStatus.Success:
|
||||
StatusExAction?.Invoke((int)StatusValues.LowPowerSuccess, data.Target);
|
||||
break;
|
||||
case ServiceBase.CallbackData.CallbackStatus.AllFinished:
|
||||
mre.Set();
|
||||
break;
|
||||
case ServiceBase.CallbackData.CallbackStatus.Failure:
|
||||
anyFailed = true;
|
||||
StatusExAction?.Invoke((int)StatusValues.LowPowerFailure, data.Target);
|
||||
break;
|
||||
}
|
||||
}, units);
|
||||
}
|
||||
|
||||
mre.WaitOne();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log(ex);
|
||||
}
|
||||
|
||||
//if any failed to turn off record the error
|
||||
//if all turned off, then set the global status param that excitation is now known off
|
||||
if (anyFailed)
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.LowPowerFailure);
|
||||
}
|
||||
else
|
||||
{
|
||||
States.Instance.ConfigureStart.Status.GlobalStatusInformation.ExcitationOn = false;
|
||||
StatusAction?.Invoke((int)StatusValues.LowPowerSuccess);
|
||||
}
|
||||
|
||||
StatusAction?.Invoke((int)StatusValues.Completed);
|
||||
CompleteAction?.Invoke();
|
||||
DoneEvent.Set();
|
||||
});
|
||||
}
|
||||
/// <summary>
|
||||
/// starts ApplyConfig process, returns immediately
|
||||
/// </summary>
|
||||
public void ApplyConfig()
|
||||
{
|
||||
DoneEvent.Reset();
|
||||
var param = States.Instance.ConfigureStart.Status.ConfigureParameters;
|
||||
if (param.TurnOffExcitation)
|
||||
{
|
||||
TurnOffExcitation();
|
||||
return;
|
||||
}
|
||||
var unitsToConfigure = param.UnitsToConfigure.ToList();
|
||||
var dasFactory = States.Instance.ConfigureStart.DASFactory;
|
||||
|
||||
_ApplyConfigTask = Task.Run(() =>
|
||||
{
|
||||
//the user could just be turning on power, in which case the configuration is already set
|
||||
//if the flag for set configuration is set, then set the configuration, otherwise don't
|
||||
if (param.SetConfiguration)
|
||||
{
|
||||
HaveAppliedConfigAllUnits = false;
|
||||
StatusAction?.Invoke((int)StatusValues.ApplyingConfiguration);
|
||||
|
||||
//check if we are supposed to configure a unit, but it's not available
|
||||
//mark it failed if the unit is not available
|
||||
var units = dasFactory.GetDASList();
|
||||
foreach (var unit in unitsToConfigure)
|
||||
{
|
||||
if (!units.Contains(unit))
|
||||
{
|
||||
unitsToConfigure.Remove(unit);
|
||||
StatusExAction?.Invoke((int)StatusValues.ApplyConfigFailed, unit);
|
||||
}
|
||||
}
|
||||
|
||||
var mre = new ManualResetEvent(false);
|
||||
if (unitsToConfigure.Any())
|
||||
{
|
||||
using (var configService = new ConfigurationService())
|
||||
{
|
||||
configService.SetConfiguration(unitsToConfigure, param.DoStrictCheck, param.EventConfig,
|
||||
(data) =>
|
||||
{
|
||||
switch (data.Status)
|
||||
{
|
||||
case ServiceBase.CallbackData.CallbackStatus.AllFinished:
|
||||
mre.Set();
|
||||
break;
|
||||
case ServiceBase.CallbackData.CallbackStatus.Progress:
|
||||
ProgressAction?.Invoke(data.ProgressValue);
|
||||
break;
|
||||
case ServiceBase.CallbackData.CallbackStatus.Failure:
|
||||
StatusExAction?.Invoke((int)StatusValues.ApplyConfigFailed, data.Target,
|
||||
data.ErrorMessage, data.ErrorException);
|
||||
break;
|
||||
case ServiceBase.CallbackData.CallbackStatus.Success:
|
||||
AddConfiguredDevice(data.Target);
|
||||
break;
|
||||
}
|
||||
}, unitsToConfigure,
|
||||
param.ErrorRequiringActionAction,
|
||||
param.DummyConfig,
|
||||
param.MaxAAF,
|
||||
param.ConfigureDigitalOutputs,
|
||||
param.TurnOffAAFRealtime,
|
||||
param.DSPFilterType,
|
||||
param.DiscardDiagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
mre.WaitOne();
|
||||
//check that all the units that should have been configured were
|
||||
var allConfigured = Array.TrueForAll(param.UnitsToConfigure, d => UnitsConfigured.Contains(d));
|
||||
HaveAppliedConfigAllUnits = allConfigured;
|
||||
}
|
||||
//finally turn on power UNLESS the user has specified not to (most likely by pressing "Low Power" button)
|
||||
//but also potentially by a property setting
|
||||
if (!CancelEvent.WaitOne(1, false))
|
||||
{
|
||||
if (param.PrepareForDiagnostics && !param.SkipTurnOnPower)
|
||||
{
|
||||
PrepareForDiagnostics();
|
||||
}
|
||||
CompleteAction?.Invoke();
|
||||
}
|
||||
|
||||
StatusAction?.Invoke((int)StatusValues.Completed);
|
||||
DoneEvent.Set();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// holds channels that are not resolved for one reason or another
|
||||
/// </summary>
|
||||
private readonly List<GroupChannelWithMeta> _unresolvedChannels = new List<GroupChannelWithMeta>();
|
||||
/// <summary>
|
||||
/// holds channels that are now resolved/assigned
|
||||
/// </summary>
|
||||
private readonly List<GroupChannelWithMeta> _resolvedChannels = new List<GroupChannelWithMeta>();
|
||||
|
||||
private bool IsUnresolved(IGroupChannel ch)
|
||||
{
|
||||
return _unresolvedChannels.Exists(channel => channel.Channel == ch);
|
||||
}
|
||||
|
||||
private bool IsResolved(IGroupChannel ch)
|
||||
{
|
||||
return _resolvedChannels.Exists(channel => channel.Channel == ch);
|
||||
}
|
||||
private void AddResolvedChannel(IGroupChannel channel,
|
||||
IDASChannel hwChannel,
|
||||
bool eidOutOfPlace,
|
||||
ConfigureStatusParameters param,
|
||||
IDictionary<IDASChannel, IDASCommunication> lookupChannelToDAS,
|
||||
ISensorData sd,
|
||||
bool missingEID)
|
||||
{
|
||||
//remove any possible duplicates
|
||||
_resolvedChannels.RemoveAll(ch => ch.Channel == channel);
|
||||
_unresolvedChannels.RemoveAll(ch => ch.Channel == channel);
|
||||
|
||||
var meta = new GroupChannelWithMeta()
|
||||
{
|
||||
Channel = channel,
|
||||
ChannelConflict = false,
|
||||
ConflictingChannel = null,
|
||||
DASChannel = hwChannel,
|
||||
EIDOutOfPlace = eidOutOfPlace,
|
||||
HWChannelIncompatible = false,
|
||||
MissingID = missingEID,
|
||||
MissingSensor = false
|
||||
};
|
||||
_resolvedChannels.Add(meta);
|
||||
|
||||
//set the hardware in the group if needed
|
||||
var includedHardware = channel.Group.IncludedHardware.ToList();
|
||||
var hwId = param.GetDatabaseIdAction(lookupChannelToDAS[hwChannel]);
|
||||
if (!includedHardware.Contains(hwId))
|
||||
{
|
||||
includedHardware.Add(hwId);
|
||||
}
|
||||
channel.Group.SetIncludedHardware(includedHardware.ToArray());
|
||||
|
||||
//set the calibration
|
||||
if (hwChannel is AnalogInputDASChannel aic)
|
||||
{
|
||||
foreach (var e in sd.SupportedExcitation)
|
||||
{
|
||||
if (!aic.IsSupported(e))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var sc = param.GetCalibrationAction(sd, e);
|
||||
if (null == sc) { continue; }
|
||||
param.SetSensorCalibrationAction(sd, sc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void AddUnresolvedChannel(IGroupChannel ch,
|
||||
bool bChannelConflict,
|
||||
IGroupChannel conflictingChannel,
|
||||
bool EIDOutOfPlace,
|
||||
bool hwChannelIncompatible,
|
||||
bool hwNotFound,
|
||||
bool missingId,
|
||||
bool missingSensor)
|
||||
{
|
||||
//remove any possible duplicates
|
||||
_resolvedChannels.RemoveAll(channel => channel.Channel == ch);
|
||||
_unresolvedChannels.RemoveAll(channel => channel.Channel == ch);
|
||||
|
||||
var meta = new GroupChannelWithMeta()
|
||||
{
|
||||
Channel = ch,
|
||||
ChannelConflict = bChannelConflict,
|
||||
ConflictingChannel = conflictingChannel,
|
||||
DASChannel = null,
|
||||
EIDOutOfPlace = EIDOutOfPlace,
|
||||
HWChannelIncompatible = hwChannelIncompatible,
|
||||
HWNotFound = hwNotFound,
|
||||
MissingID = missingId,
|
||||
MissingSensor = missingSensor
|
||||
};
|
||||
_unresolvedChannels.Add(meta);
|
||||
}
|
||||
|
||||
private bool IsHWChannelResolved(IDASChannel channel)
|
||||
{
|
||||
return _resolvedChannels.Exists(ch => ch.DASChannel == channel);
|
||||
}
|
||||
|
||||
public void ManuallyUnresolveChannel(IGroupChannel channel)
|
||||
{
|
||||
if (!IsResolved(channel))
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.ChannelNotAssigned);
|
||||
}
|
||||
|
||||
var resolvedChannel = _resolvedChannels.First(ch => ch.Channel == channel);
|
||||
if (resolvedChannel.AssignedByEID)
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.EID_Locked);
|
||||
}
|
||||
|
||||
AddUnresolvedChannel(channel, false, null, false, false, resolvedChannel.HWNotFound, resolvedChannel.MissingID,
|
||||
false);
|
||||
}
|
||||
public void ManuallyResolveChannel(IGroupChannel channel, IDASChannel hardwareChannel)
|
||||
{
|
||||
var param = States.Instance.ConfigureStart.Status.ConfigureParameters;
|
||||
GetIdToHardwareLookup(param, out var lookupIDToHardware, out var lookupChannelToDAS,
|
||||
out var lookupDAStoChannel);
|
||||
if (channel.IsBlank())
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.BlankChannel);
|
||||
}
|
||||
if (channel.IsDisabled)
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.ChannelDisabled);
|
||||
}
|
||||
if (channel.SensorId < 0)
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.NoSensor);
|
||||
}
|
||||
|
||||
var sd = param.GetSensorAction(channel);
|
||||
if (null == sd)
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.SensorNotFound);
|
||||
}
|
||||
|
||||
var compatible = IsSensorHwCompatible(hardwareChannel, sd);
|
||||
if (SensorCompatiblilityResponse.Compatible != compatible)
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.IncompatibleHardware);
|
||||
}
|
||||
//alright, looks ok ... unless there's something on that channel already ...
|
||||
if (IsHWChannelResolved(hardwareChannel))
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.ChannelAlreadyAssigned);
|
||||
}
|
||||
//ok, well make sure it's we didn't find the EID for the channel already on a channel, if so ... it's locked on
|
||||
//that channel
|
||||
bool bFoundEID = false;
|
||||
if (IsResolved(channel))
|
||||
{
|
||||
var resolvedChannel = _resolvedChannels.First(ch => ch.Channel == channel);
|
||||
if (resolvedChannel.AssignedByEID)
|
||||
{
|
||||
if (resolvedChannel.DASChannel != hardwareChannel)
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.EID_Locked);
|
||||
}
|
||||
//nothing to do ...
|
||||
bFoundEID = true;
|
||||
}
|
||||
}
|
||||
|
||||
//determine if we should have found an EID and didn't
|
||||
var bMissingEID = !string.IsNullOrWhiteSpace(sd.EID) && !bFoundEID;
|
||||
//if we are missing an ID, and aren't allowed to assign to a channel without an id, then don't allow it
|
||||
if (bMissingEID && !param.AllowSensorIdToBlankChannel)
|
||||
{
|
||||
throw new InvalidAssignmentException(channel, InvalidAssignmentException.Reasons.EIDRequiredAndMissing);
|
||||
}
|
||||
//add as a resolved channel
|
||||
AddResolvedChannel(channel, hardwareChannel, false, param, lookupChannelToDAS, sd, bMissingEID);
|
||||
AllChannelsResolved = _unresolvedChannels.Any();
|
||||
}
|
||||
/// <summary>
|
||||
/// thrown by manually resolve/unresolve functions
|
||||
/// </summary>
|
||||
public class InvalidAssignmentException : Exception
|
||||
{
|
||||
public enum Reasons
|
||||
{
|
||||
BlankChannel,
|
||||
NoSensor,
|
||||
ChannelDisabled,
|
||||
SensorNotFound,
|
||||
IncompatibleHardware,
|
||||
ChannelAlreadyAssigned,
|
||||
EID_Locked, //sensor is already locked by EID to a different channel
|
||||
EIDRequiredAndMissing,
|
||||
ChannelNotAssigned
|
||||
}
|
||||
public IGroupChannel GroupChannel { get; private set; }
|
||||
public Reasons Reason { get; private set; }
|
||||
|
||||
public InvalidAssignmentException(IGroupChannel channel, Reasons reason)
|
||||
: base($"{reason.ToString()} - {channel}")
|
||||
{
|
||||
Reason = reason;
|
||||
GroupChannel = channel;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// sensor is not compatible with hardware, but maybe in the future we'll want to know why
|
||||
/// even though right now it's just "hw incompatible"
|
||||
/// </summary>
|
||||
internal enum SensorCompatiblilityResponse
|
||||
{
|
||||
Compatible,
|
||||
DigitalInputNotSupportedOnHWChannel,
|
||||
DigitalInputModeNotSupportedOnHWChannel,
|
||||
BridgeModeNotSupportedOnHWChannel,
|
||||
SquibFireModeNotSupportedOnHWChannel,
|
||||
NoSupportedExcitationOnHWChannel
|
||||
}
|
||||
/// <summary>
|
||||
/// check if sensor can run on the channel in question
|
||||
/// checks excitation, bridge, sensor type, etc
|
||||
/// </summary>
|
||||
/// <param name="hwid"></param>
|
||||
/// <param name="sd"></param>
|
||||
/// <returns></returns>
|
||||
private SensorCompatiblilityResponse IsSensorHwCompatible(IDASChannel hwChannel, ISensorData sd)
|
||||
{
|
||||
switch (hwChannel)
|
||||
{
|
||||
case AnalogInputDASChannel aic:
|
||||
if (aic.SupportedBridges.Contains(sd.Bridge))
|
||||
{
|
||||
if (aic.DigitalInputChannel)
|
||||
{
|
||||
if (!sd.IsDigitalInput())
|
||||
{
|
||||
//hardware is digital, sensor is not, it's not compatible
|
||||
return SensorCompatiblilityResponse.DigitalInputNotSupportedOnHWChannel;
|
||||
}
|
||||
else if (!aic.SupportedDigitalInputModes.Contains(sd.InputMode))
|
||||
{
|
||||
//sensor and hardware are digital, but the input mode is not supported
|
||||
return SensorCompatiblilityResponse.DigitalInputModeNotSupportedOnHWChannel;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var param = States.Instance.ConfigureStart.Status.ConfigureParameters;
|
||||
var excitationPassed = (from e in sd.SupportedExcitation
|
||||
where aic.SupportedExcitation.Contains(e)
|
||||
select param.GetCalibrationAction(sd, e)).Any(sc => null != sc);
|
||||
if (!excitationPassed)
|
||||
{
|
||||
//there's no supported excitation match
|
||||
return SensorCompatiblilityResponse.NoSupportedExcitationOnHWChannel;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//the hardware does not support the bridge mode of the sensor ...
|
||||
return SensorCompatiblilityResponse.BridgeModeNotSupportedOnHWChannel;
|
||||
}
|
||||
|
||||
break;
|
||||
case OutputSquibChannel _:
|
||||
var squibChannel = (OutputSquibChannel)hwChannel;
|
||||
if (!sd.IsSquib())
|
||||
{
|
||||
//hardware channel is squib, sensor is not
|
||||
return SensorCompatiblilityResponse.BridgeModeNotSupportedOnHWChannel;
|
||||
}
|
||||
else if (!squibChannel.SupportedSquibFireModes.Contains(sd.SquibFireMode))
|
||||
{
|
||||
//hardware and sensor are squib, but fire mode not supported by hardware
|
||||
return SensorCompatiblilityResponse.SquibFireModeNotSupportedOnHWChannel;
|
||||
}
|
||||
|
||||
break;
|
||||
case OutputTOMDigitalChannel _:
|
||||
if (!sd.IsDigitalOutput())
|
||||
{
|
||||
//hardware channel is digital output, sensor is not
|
||||
return SensorCompatiblilityResponse.BridgeModeNotSupportedOnHWChannel;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return SensorCompatiblilityResponse.Compatible;
|
||||
}
|
||||
/// <summary>
|
||||
/// returns sensor EID to hardware channel mapping as determined from connected units
|
||||
/// </summary>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="lookupChannelToDAS">hardware channel to IDASCommunication</param>
|
||||
/// <param name="lookupIDToHardware">eid to hardware channel</param>
|
||||
/// <returns></returns>
|
||||
private void GetIdToHardwareLookup(ConfigureStatusParameters param,
|
||||
out IDictionary<string, IDASChannel> lookupIDToHardware,
|
||||
out IDictionary<IDASChannel, IDASCommunication> lookupChannelToDAS,
|
||||
out IDictionary<int, IDictionary<int, IDASChannel>> lookupDASToChannel
|
||||
)
|
||||
{
|
||||
lookupIDToHardware = new Dictionary<string, IDASChannel>();
|
||||
lookupChannelToDAS = new Dictionary<IDASChannel, IDASCommunication>();
|
||||
lookupDASToChannel = new Dictionary<int, IDictionary<int, IDASChannel>>();
|
||||
|
||||
foreach (var unit in param.UnitsToConfigure)
|
||||
{
|
||||
//why is there no config data?
|
||||
if (null == unit.ConfigData)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var dasid = param.GetDatabaseIdAction(unit);
|
||||
if (!lookupDASToChannel.ContainsKey(dasid))
|
||||
{
|
||||
lookupDASToChannel.Add(dasid, new Dictionary<int, IDASChannel>());
|
||||
}
|
||||
|
||||
foreach (var module in unit.ConfigData.Modules)
|
||||
{
|
||||
foreach (var channel in module.Channels)
|
||||
{
|
||||
lookupChannelToDAS[channel] = unit;
|
||||
lookupDASToChannel[dasid][channel.Number] = channel;
|
||||
if (null != channel.IDs && channel.IDs.Length > 0)
|
||||
{
|
||||
var id = channel.IDs[0].ID;
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
lookupIDToHardware[id] = channel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// resets all status to defaults
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
NoChannelsAssigned = true;
|
||||
AllChannelsResolved = false;
|
||||
ChannelsOutOfPosition = false;
|
||||
HaveAppliedConfigAllUnits = false;
|
||||
StatusAction = null;
|
||||
CompleteAction = null;
|
||||
ProgressAction = null;
|
||||
UnitsConfigured = new IDASCommunication[0];
|
||||
_unresolvedChannels.Clear();
|
||||
_resolvedChannels.Clear();
|
||||
_ExcitationTask = null;
|
||||
_ApplyConfigTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
using DTS.Common.Classes.DSP;
|
||||
using DTS.Common.Enums;
|
||||
using DTS.Common.Interface.Channels;
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using DTS.Common.Interface.Sensors;
|
||||
using DTS.Common.Interface.StatusAndProgressBar;
|
||||
using DTS.Common.Interface.TestSetups.TestSetupsList;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class ConfigureStatusParameters : IStatusParameters
|
||||
{
|
||||
#region ResolveChannels
|
||||
public bool RequireIdFoundForSensorsWithIds { get; set; } = true;
|
||||
public bool AllowMissingSensors { get; set; } = false;
|
||||
public bool AllowSensorsOutOfPosition { get; set; } = true;
|
||||
|
||||
public ITestSetup TestSetupConfiguration { get; set; }
|
||||
public delegate ISensorData GetSensorDelegate(IGroupChannel groupChannel);
|
||||
|
||||
public delegate ISensorCalibration GetSensorCalibrationDelegate(ISensorData sensor,
|
||||
ExcitationVoltageOptions.ExcitationVoltageOption excitation);
|
||||
/// <summary>
|
||||
/// delegate allowing us to retrieve the latest sensor calibration given a sensor and an excitation
|
||||
/// </summary>
|
||||
public GetSensorCalibrationDelegate GetCalibrationAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// retrieves a sensor given a group channel
|
||||
/// this is handled in DataPRO by DataModel.TestTemplate
|
||||
/// but since that exists in UI land, we'll just define a delegate
|
||||
/// and allow it to be provided by the consumer by whatever mechanism it chooses
|
||||
/// for run test this should be testtemplate, but for testing it could equally
|
||||
/// just come from the db or directly provided
|
||||
/// </summary>
|
||||
public GetSensorDelegate GetSensorAction { get; set; }
|
||||
public bool AllowSensorIdToBlankChannel { get; set; }
|
||||
|
||||
public delegate int GetDatabaseIdDelegate(IDASCommunication das);
|
||||
public GetDatabaseIdDelegate GetDatabaseIdAction { get; set; }
|
||||
|
||||
public delegate void SetSensorCalibrationDelegate(ISensorData sd, ISensorCalibration sc);
|
||||
public SetSensorCalibrationDelegate SetSensorCalibrationAction { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Configure
|
||||
/// <summary>
|
||||
/// Excitation should be turned off, this flag is reverted as soon as the process to turn off excitation starts
|
||||
/// </summary>
|
||||
public bool TurnOffExcitation { get; set; } = false;
|
||||
/// <summary>
|
||||
/// defines an array of units which configuration should be applied to
|
||||
/// </summary>
|
||||
public IDASCommunication[] UnitsToConfigure { get; set; } = new IDASCommunication[0];
|
||||
/// <summary>
|
||||
/// whether strict check should be used when applying configuration
|
||||
/// </summary>
|
||||
public bool DoStrictCheck { get; set; } = true;
|
||||
/// <summary>
|
||||
/// whether configuration should be written to even or diagnostic file stores
|
||||
/// (this is a legacy feature of sliceware, not all units support it, but SLICE units have multiple file stores
|
||||
/// so configuration could be written to different ones (diagnostic/event)
|
||||
/// </summary>
|
||||
public bool EventConfig { get; set; } = true;
|
||||
/// <summary>
|
||||
/// whether we are configuring units for data collection or just dummy collection (not collecting data)
|
||||
/// </summary>
|
||||
public bool DummyConfig { get; set; } = false;
|
||||
/// <summary>
|
||||
/// the MAX AAF for SLICE and TDAS
|
||||
/// </summary>
|
||||
public double[] MaxAAF { get; set; } = new double[0];
|
||||
/// <summary>
|
||||
/// whether digital outputs should be applied or not when applying configuration
|
||||
/// this allows digital outputs to not be configured for say trigger check
|
||||
/// </summary>
|
||||
public bool ConfigureDigitalOutputs { get; set; } = true;
|
||||
/// <summary>
|
||||
/// the current configure process can occasionally require user input
|
||||
/// [probably to acknowledge AAF errors?] this allows a method of interacting
|
||||
/// during this process
|
||||
/// </summary>
|
||||
public ErrorCallback ErrorRequiringActionAction { get; set; }
|
||||
/// <summary>
|
||||
/// whether AAF should be turned off for realtime or not
|
||||
/// AAF takes up a lot of time for slice realtime, so it's usually desirable to turn off
|
||||
/// </summary>
|
||||
public bool TurnOffAAFRealtime { get; set; } = true;
|
||||
/// <summary>
|
||||
/// whether to reset the hardware event lines before setting the config
|
||||
/// </summary>
|
||||
public bool ResetHardwareEventLines { get; set; } = false;
|
||||
/// <summary>
|
||||
/// whether to prepare for diagnostics (turn on excitation, switches)
|
||||
/// </summary>
|
||||
public bool PrepareForDiagnostics { get; set; } = false;
|
||||
/// <summary>
|
||||
/// lookup serial number to data collection rate
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, double> SampleRateLookup { get; set; } = new Dictionary<string, double>();
|
||||
/// <summary>
|
||||
/// lookup serial number to Anti Alias Filter rate
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, float> AAFRateLookup { get; set; } = new Dictionary<string, float>();
|
||||
/// <summary>
|
||||
/// whether turning on power should be skipped or not
|
||||
/// this can allow excitation to remain off which is sometimes used to keep the units in low power state
|
||||
/// until the user explicitly turns on power
|
||||
/// </summary>
|
||||
public bool SkipTurnOnPower { get; set; } = false;
|
||||
/// <summary>
|
||||
/// whether to apply configuration or not
|
||||
/// </summary>
|
||||
public bool SetConfiguration { get; set; } = true;
|
||||
public DSPFilterType DSPFilterType { get; set; }
|
||||
/// <summary>
|
||||
/// whether to discard diagnostics when setting configuration
|
||||
/// </summary>
|
||||
public bool DiscardDiagnostics { get; set; } = true;
|
||||
#endregion
|
||||
|
||||
public ConfigureStatusParameters()
|
||||
{
|
||||
ResetDSPFilterType();
|
||||
}
|
||||
private void ResetDSPFilterType()
|
||||
{
|
||||
var dsp = DSPFilterCollection.GetDSPFilterCollection();
|
||||
DSPFilterType = dsp.GetFilter(string.Empty);
|
||||
}
|
||||
/// <summary>
|
||||
/// resets all parameters back to defaults
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
RequireIdFoundForSensorsWithIds = true;
|
||||
AllowMissingSensors = false;
|
||||
AllowSensorsOutOfPosition = true;
|
||||
DoStrictCheck = true;
|
||||
EventConfig = true;
|
||||
DummyConfig = false;
|
||||
MaxAAF = new double[0];
|
||||
ConfigureDigitalOutputs = true;
|
||||
ErrorRequiringActionAction = null;
|
||||
TestSetupConfiguration = null;
|
||||
GetSensorAction = null;
|
||||
AllowSensorIdToBlankChannel = false;
|
||||
ResetHardwareEventLines = false;
|
||||
PrepareForDiagnostics = false;
|
||||
UnitsToConfigure = new IDASCommunication[0];
|
||||
SampleRateLookup = new Dictionary<string, double>();
|
||||
AAFRateLookup = new Dictionary<string, float>();
|
||||
SkipTurnOnPower = false;
|
||||
SetConfiguration = true;
|
||||
TurnOffExcitation = false;
|
||||
DiscardDiagnostics = true;
|
||||
ResetDSPFilterType();
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"RequireIdFoundForSensorsWithIds={RequireIdFoundForSensorsWithIds.ToString()}");
|
||||
sb.AppendLine($"AllowMissingSensors={AllowMissingSensors.ToString()}");
|
||||
sb.AppendLine($"AllowSensorsOutOfPosition={AllowSensorsOutOfPosition.ToString()}");
|
||||
sb.AppendLine($"DoStrictCheck={DoStrictCheck.ToString()}");
|
||||
sb.AppendLine($"EventConfig={EventConfig.ToString()}");
|
||||
sb.AppendLine($"DummyConfig={DummyConfig.ToString()}");
|
||||
sb.Append("MaxAAF=");
|
||||
for (int i = 0; i < MaxAAF.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(", ");
|
||||
}
|
||||
sb.Append(MaxAAF[i].ToString());
|
||||
}
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"ConfigureDigitalOutputs={ConfigureDigitalOutputs.ToString()}");
|
||||
sb.AppendLine($"AllowSensorIdToBlankChannel={AllowSensorIdToBlankChannel.ToString()}");
|
||||
sb.AppendLine($"ResetHardwareEventLines={ResetHardwareEventLines.ToString()}");
|
||||
sb.AppendLine($"PrepareForDiagnostics={PrepareForDiagnostics.ToString()}");
|
||||
sb.Append("UnitsToConfigure=");
|
||||
for (var i = 0; i < UnitsToConfigure.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(", ");
|
||||
}
|
||||
sb.Append(UnitsToConfigure[i].SerialNumber);
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
sb.Append("SampleRateLookup=");
|
||||
var first = true;
|
||||
using (var enumSampleRate = SampleRateLookup.GetEnumerator())
|
||||
{
|
||||
while (enumSampleRate.MoveNext())
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
sb.Append(", ");
|
||||
}
|
||||
sb.Append($"{enumSampleRate.Current.Key}={enumSampleRate.Current.Value.ToString()}");
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
sb.AppendLine();
|
||||
|
||||
sb.Append("AAFLookup=");
|
||||
first = true;
|
||||
using (var enumAAF = AAFRateLookup.GetEnumerator())
|
||||
{
|
||||
while (enumAAF.MoveNext())
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append($"{enumAAF.Current.Key}={enumAAF.Current.Value.ToString()}");
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendLine($"SkipTurnOnPower={SkipTurnOnPower.ToString()}");
|
||||
|
||||
sb.Append("ErrorRequiringActionAction=");
|
||||
sb.AppendLine(null == ErrorRequiringActionAction ? "[null]" : "[defined]");
|
||||
sb.AppendLine($"SetConfiguration={SetConfiguration.ToString()}");
|
||||
sb.AppendLine($"TurnOffExcitation={TurnOffExcitation.ToString()}");
|
||||
sb.AppendLine($"DiscardDiagnostics={DiscardDiagnostics.ToString()}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using DTS.Common.Interface.Channels;
|
||||
using DTS.Common.Interface.DASFactory.Config;
|
||||
using DTS.Common.Interface.Groups.GroupList;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine.StatusAndParameters.Configure
|
||||
{
|
||||
/// <summary>
|
||||
/// helper class for use when resolving channels
|
||||
/// </summary>
|
||||
internal class GroupChannelWithMeta
|
||||
{
|
||||
public bool ChannelConflict { get; set; }
|
||||
public IGroupChannel ConflictingChannel { get; set; }
|
||||
public IGroupChannel Channel { get; set; }
|
||||
public IGroup Group { get; set; }
|
||||
public bool MissingID { get; set; }
|
||||
public bool MissingSensor { get; set; }
|
||||
public bool EIDOutOfPlace { get; set; }
|
||||
public bool HWNotFound { get; set; }
|
||||
public bool HWChannelIncompatible { get; set; }
|
||||
public IDASChannel DASChannel { get; set; }
|
||||
public bool AssignedByEID { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class DiagnoseParameters : IStatusParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// controls whether we should remain in state or not
|
||||
/// </summary>
|
||||
public bool ProceedToRealtimeWhenDone { get; set; }
|
||||
public bool RequireAllUnitsPassDiagnostic { get; set; }
|
||||
|
||||
public bool AllUnitsPassedDiagnostic { get; set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ProceedToRealtimeWhenDone = true;
|
||||
RequireAllUnitsPassDiagnostic = false;
|
||||
AllUnitsPassedDiagnostic = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using DTS.Common.Interface.StatusAndProgressBar;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class DownloadParameters : IStatusParameters
|
||||
{
|
||||
#region general parameters
|
||||
/// <summary>
|
||||
/// controls whether we should remain in state or not
|
||||
/// </summary>
|
||||
public bool ProceedWhenDone { get; set; } = false;
|
||||
/// <summary>
|
||||
/// whether all das are required to finish their download
|
||||
/// </summary>
|
||||
public bool RequireAllDASFinish { get; set; } = false;
|
||||
#endregion
|
||||
|
||||
#region config file parameters
|
||||
/// <summary>
|
||||
/// holds the Download Folder setting from our config file
|
||||
/// </summary>
|
||||
public string DefaultDownloadFolder { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// holds the upload binaries setting from our config file
|
||||
/// </summary>
|
||||
public bool DefaultUploadBinaries { get; set; } = false;
|
||||
/// <summary>
|
||||
/// holds the upload exports setting from our config file
|
||||
/// </summary>
|
||||
public bool DefaultUploadExports { get; set; } = false;
|
||||
/// <summary>
|
||||
/// holds the upload logs setting from our config file
|
||||
/// </summary>
|
||||
public bool DefaultUploadLogs { get; set; } = false;
|
||||
/// <summary>
|
||||
/// holds the upload reports setting from our config file
|
||||
/// </summary>
|
||||
public bool DefaultUploadReports { get; set; } = false;
|
||||
/// <summary>
|
||||
/// holds the upload test setups setting from our config file
|
||||
/// </summary>
|
||||
public bool DefaultUploadSetups { get; set; } = false;
|
||||
#endregion
|
||||
|
||||
#region download function parameters
|
||||
/// <summary>
|
||||
/// defines an array of DAS which should be downloaded from
|
||||
/// </summary>
|
||||
public IDASCommunication[] DASList { get; set; } = new IDASCommunication[0];
|
||||
|
||||
/// <summary>
|
||||
/// holds the test id of our current test
|
||||
/// </summary>
|
||||
public string CurrentTestTestId { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// holds the test id node of our current test
|
||||
/// </summary>
|
||||
public string CurrentTestTestIdNode { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// holds the test directory location of our current test
|
||||
/// </summary>
|
||||
public string CurrentTestTestDirectory { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// holds the original test directory location of our current test
|
||||
/// </summary>
|
||||
public string CurrentTestOriginalTestDirectory { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// holds whether we're in ROI mode or not
|
||||
/// </summary>
|
||||
public bool ROI { get; set; } = false;
|
||||
/// <summary>
|
||||
/// holds whether we're in Recovery mode or not
|
||||
/// </summary>
|
||||
public bool Recovery { get; set; } = false;
|
||||
/// <summary>
|
||||
/// Used to prevent unnecessarily re-copying the folders in the Test Id folder
|
||||
/// (DASConfigs, SETUP, etc.) when running from the Download tile.
|
||||
/// </summary>
|
||||
public bool FoldersCopied { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public ErrorCallback ErrorCallback { get; set; }
|
||||
/// <summary>
|
||||
/// resets all parameters back to defaults
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
DASList = new IDASCommunication[0];
|
||||
CurrentTestTestId = string.Empty;
|
||||
CurrentTestTestIdNode = string.Empty;
|
||||
DefaultDownloadFolder = string.Empty;
|
||||
DefaultUploadBinaries = false;
|
||||
DefaultUploadExports = false;
|
||||
DefaultUploadLogs = false;
|
||||
DefaultUploadReports = false;
|
||||
DefaultUploadSetups = false;
|
||||
ErrorCallback = null;
|
||||
Recovery = false;
|
||||
ROI = false;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using DTS.Common.Interface.DASFactory.Download;
|
||||
using DTS.Common.Interface.StatusAndProgressBar;
|
||||
using DTS.Common.Utilities.Logging;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class DownloadStatusInformation : IStatusInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// all possible status that can be relayed to consumers
|
||||
/// </summary>
|
||||
public enum StatusValues
|
||||
{
|
||||
Preparing,
|
||||
Downloading,
|
||||
CaptureAttributes,
|
||||
Failed,
|
||||
ROIFailed,
|
||||
Completed,
|
||||
Cancelling,
|
||||
Cancelled,
|
||||
CancelledPartial,
|
||||
DownloadDirectory,
|
||||
MissingHardware,
|
||||
NoDataToDownload,
|
||||
NotAllChannelsDownloaded,
|
||||
ExistingFiles,
|
||||
CleaningUp,
|
||||
QueryEventData
|
||||
}
|
||||
/// <summary>
|
||||
/// signals cancel was requested
|
||||
/// </summary>
|
||||
public ManualResetEvent CancelEvent = new ManualResetEvent(false);
|
||||
/// <summary>
|
||||
/// signals when ping and connect is finished
|
||||
/// </summary>
|
||||
public ManualResetEvent DoneEvent = new ManualResetEvent(false);
|
||||
/// <summary>
|
||||
/// action to take on completion of ping and connect
|
||||
/// </summary>
|
||||
public ActionCompleteDelegate CompleteAction { get; set; }
|
||||
/// <summary>
|
||||
/// action to take on progress notification
|
||||
/// </summary>
|
||||
public SetProgressValueDelegate ProgressAction { get; set; }
|
||||
/// <summary>
|
||||
/// action to take on a status notification
|
||||
/// </summary>
|
||||
public StatusIntDelegate StatusAction { get; set; }
|
||||
/// <summary>
|
||||
/// action to take on extended status notification
|
||||
/// </summary>
|
||||
public StatusExIntDelegate StatusExAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// if we were told of DAS to download from,
|
||||
/// this will be true if all the das were downloaded
|
||||
/// </summary>
|
||||
public bool AllDASFinished { get; set; } = false;
|
||||
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
AllDASFinished = false;
|
||||
CompleteAction = null;
|
||||
StatusAction = null;
|
||||
StatusExAction = null;
|
||||
ProgressAction = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// starts Downloading, returns immediately
|
||||
/// </summary>
|
||||
public void Download()
|
||||
{
|
||||
_DownloadTask = Task.Run(() =>
|
||||
{
|
||||
AllDASFinished = false;
|
||||
var param = States.Instance.DownloadStart.Status.DownloadParams;
|
||||
var global = States.Instance.DownloadStart.Status.GlobalStatusParameters;
|
||||
var dasFactory = States.Instance.DownloadStart.DASFactory;
|
||||
var errorCallback = param.ErrorCallback;
|
||||
|
||||
//get a list of all the das to download from
|
||||
var dasList = param.DASList.ToList();
|
||||
|
||||
|
||||
StatusAction?.Invoke((int)StatusValues.Preparing);
|
||||
|
||||
//check if we are supposed to download from a unit, but it's not available
|
||||
var activeDASList = dasFactory.GetDASList();
|
||||
if (dasList.Exists(das => !activeDASList.Contains(das)))
|
||||
{
|
||||
var missingList = dasList.Where(das => !activeDASList.Contains(das)).ToList();
|
||||
var dr = errorCallback?.Invoke(StatusValues.MissingHardware.ToString(), string.Join(Environment.NewLine, missingList.Select(das => das.SerialNumber).ToList()));
|
||||
if (DialogResult.OK != dr)
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.Failed);
|
||||
}
|
||||
}
|
||||
|
||||
//check if we have any das left to download from
|
||||
if (!dasList.Any())
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.Failed);
|
||||
}
|
||||
|
||||
//check that all units have config data
|
||||
if (dasList.Exists(das => das.ConfigData == null))
|
||||
{
|
||||
//throw error. by state machine definition we should have gone through Config first
|
||||
StatusExAction?.Invoke((int)StatusValues.NoDataToDownload, dasList.Where(das => das.ConfigData == null).ToArray());
|
||||
}
|
||||
|
||||
//we have das, they have config data. get the event
|
||||
var oneEvent = GetOneEvent(dasList);
|
||||
if (null == oneEvent)
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.Failed);
|
||||
}
|
||||
|
||||
//create folder environment
|
||||
var eventId = oneEvent.EventId;
|
||||
|
||||
|
||||
var currentTestTestId = param.CurrentTestTestId;
|
||||
var currentTestTestIdNode = param.CurrentTestTestIdNode;
|
||||
var currentTestTestDirectory = param.CurrentTestTestDirectory;
|
||||
var currentTestOriginalTestDirectory = param.CurrentTestOriginalTestDirectory;
|
||||
var defaultDownloadFolder = param.DefaultDownloadFolder;
|
||||
var DownloadFolder = Path.Combine(Environment.CurrentDirectory, defaultDownloadFolder);
|
||||
var ROI = param.ROI;
|
||||
var recovery = param.Recovery;
|
||||
var foldersCopied = param.FoldersCopied;
|
||||
|
||||
var directory = Path.Combine(DownloadFolder, eventId, currentTestTestId, "Binary");
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.Failed);
|
||||
}
|
||||
}
|
||||
|
||||
StatusAction?.Invoke((int)StatusValues.DownloadDirectory);
|
||||
var DownloadDirectory = Path.Combine(directory, ROI ? "ROI" : "ALL");
|
||||
var TestItem = $"{defaultDownloadFolder}\\{eventId}\\{currentTestTestId}\\Binary\\{(ROI ? "ROI" : "ALL")}"; //optimize this
|
||||
|
||||
if (recovery && Directory.Exists(directory))
|
||||
{
|
||||
if (currentTestTestId != currentTestTestIdNode)
|
||||
{
|
||||
//We want to keep ROI and ALL "recovery" downloads in the same path, so use the same "Test Id" node in the path
|
||||
//Since the .../Binary folder exists, we know that this test has downloaded before, so create a recovery folder
|
||||
DownloadDirectory = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, "Binary", ROI ? "ROI" : "ALL");
|
||||
}
|
||||
|
||||
if ((currentTestTestId != currentTestTestIdNode || currentTestTestDirectory != currentTestOriginalTestDirectory) &&
|
||||
!foldersCopied)
|
||||
{
|
||||
//Either this is a "recovery" folder or the Test Id field was changed in Basic info.
|
||||
//Either way, the following files need to be copied from the original folder
|
||||
var copied = false;
|
||||
var originalTestIdNode = Path.GetFileName(currentTestOriginalTestDirectory);
|
||||
|
||||
var sourceDir = Path.Combine(DownloadFolder, eventId, originalTestIdNode, Common.Constants.DAS_CONFIGS);
|
||||
var destDir = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, Common.Constants.DAS_CONFIGS);
|
||||
DirectoryCopy(sourceDir, destDir, true, param, ref copied, false);
|
||||
|
||||
sourceDir = Path.Combine(DownloadFolder, eventId, originalTestIdNode, "Logs");
|
||||
destDir = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, "Logs");
|
||||
DirectoryCopy(sourceDir, destDir, true, param, ref copied, false);
|
||||
|
||||
sourceDir = Path.Combine(DownloadFolder, eventId, originalTestIdNode, Common.Constants.REPORT_DIR_NAME);
|
||||
destDir = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, Common.Constants.REPORT_DIR_NAME);
|
||||
DirectoryCopy(sourceDir, destDir, true, param, ref copied, false);
|
||||
|
||||
sourceDir = Path.Combine(DownloadFolder, eventId, originalTestIdNode, "SETUP");
|
||||
destDir = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, "SETUP");
|
||||
DirectoryCopy(sourceDir, destDir, true, param, ref copied, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var mre = new ManualResetEvent(false);
|
||||
mre.WaitOne();
|
||||
|
||||
if (!CancelEvent.WaitOne(1, false))
|
||||
{
|
||||
//check that all the units that should have been configured were
|
||||
var allDownloaded = Array.TrueForAll(param.DASList, d => dasList.Contains(d));
|
||||
AllDASFinished = allDownloaded;
|
||||
|
||||
CompleteAction?.Invoke();
|
||||
}
|
||||
|
||||
StatusAction?.Invoke((int)StatusValues.Completed);
|
||||
DoneEvent.Set();
|
||||
});
|
||||
}
|
||||
|
||||
private Task _DownloadTask = null;
|
||||
public async Task Cancel()
|
||||
{
|
||||
CancelEvent.Set();
|
||||
StatusAction?.Invoke((int)StatusValues.Cancelling);
|
||||
//simulate time spent waiting for cancel to be acknowledged
|
||||
Thread.Sleep(100);
|
||||
DoneEvent.WaitOne();
|
||||
StatusAction?.Invoke((int)StatusValues.Cancelled);
|
||||
}
|
||||
|
||||
#region helpers
|
||||
private static string GetHash(DownloadReport.EventInfo myEvent)
|
||||
{
|
||||
return $"{myEvent.TestID}_{myEvent.EventNumber:00}".ToUpper();
|
||||
}
|
||||
private IEventInfoAggregate GetOneEvent(List<IDASCommunication> dasList)
|
||||
{
|
||||
var eventInfo = new DownloadReport.EventInfo();
|
||||
var eventIds = new List<string>();
|
||||
var events = new Dictionary<string, IEventInfoAggregate>();
|
||||
foreach (var das in dasList)
|
||||
{
|
||||
if (null == das.EventInfo || !das.EventInfo.Events.Any()) { continue; }
|
||||
eventInfo = (DownloadReport.EventInfo)das.EventInfo.Events[0];
|
||||
var key = GetHash(eventInfo);
|
||||
if (!eventIds.Contains(key))
|
||||
{
|
||||
eventIds.Add(key);
|
||||
//TODO: Add Events, etc to
|
||||
//events.Add(key, new IEventInfoAggregate(eventInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
events[key].Add(eventInfo);
|
||||
}
|
||||
}
|
||||
IEventInfoAggregate oneEvent = null;
|
||||
if (events.Count > 0)
|
||||
{
|
||||
oneEvent = events[GetHash(eventInfo)];
|
||||
}
|
||||
return oneEvent;
|
||||
}
|
||||
/// <summary>
|
||||
/// we don't use move as we don't want to necessarily disturb directories already in the target location, and any files that are already there
|
||||
/// [but we will overwrite if a source file exists in the destination]
|
||||
/// </summary>
|
||||
/// <param name="sourceDirName"></param>
|
||||
/// <param name="destDirName"></param>
|
||||
/// <param name="copySubDirs"></param>
|
||||
/// <param name="param"></param>
|
||||
/// /// <param name="copied"></param>
|
||||
/// /// <param name="uploadingData"></param>
|
||||
public bool DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs, DownloadParameters param, ref bool copied, bool uploadingData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileLocations = new List<string>();
|
||||
var destFileLocations = new List<string>();
|
||||
|
||||
var dirs = new List<string>();
|
||||
dirs.Add(sourceDirName);
|
||||
while (dirs.Count > 0)
|
||||
{
|
||||
var currentDir = dirs[0];
|
||||
dirs.RemoveAt(0);
|
||||
|
||||
var dir = new System.IO.DirectoryInfo(currentDir);
|
||||
if (!dir.Exists) { continue; }
|
||||
var files = dir.GetFiles();
|
||||
fileLocations.AddRange(files.Select(file => file.FullName));
|
||||
|
||||
var subDirs = dir.GetDirectories();
|
||||
dirs.AddRange(subDirs.Select(thisdir => thisdir.FullName));
|
||||
}
|
||||
|
||||
//uri requires folders end with \\
|
||||
if (!sourceDirName.EndsWith("\\")) { sourceDirName += "\\"; }
|
||||
var diSourceDir = new System.IO.DirectoryInfo(sourceDirName);
|
||||
if (!destDirName.EndsWith("\\")) { destDirName += "\\"; }
|
||||
|
||||
var curFileUndex = 1;
|
||||
var existingFiles = new List<string>();
|
||||
|
||||
for (var i = fileLocations.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var curFile = fileLocations[i];
|
||||
if (uploadingData)
|
||||
{
|
||||
var tokens = curFile.Split('\\');
|
||||
if (tokens.Contains("Binary"))
|
||||
{
|
||||
if (!param.DefaultUploadBinaries)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("DASConfigs"))
|
||||
{
|
||||
if (!param.DefaultUploadSetups)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("SETUP"))
|
||||
{
|
||||
if (!param.DefaultUploadSetups)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("Reports"))
|
||||
{
|
||||
if (!param.DefaultUploadReports)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("Logs"))
|
||||
{
|
||||
if (!param.DefaultUploadLogs)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("Exports"))
|
||||
{
|
||||
if (!param.DefaultUploadExports)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
var fiCurFile = new System.IO.FileInfo(curFile);
|
||||
|
||||
var path1 = new Uri("file:\\\\" + diSourceDir.FullName);
|
||||
var path2 = new Uri("file:\\\\" + fiCurFile.FullName);
|
||||
var diff = path1.MakeRelativeUri(path2);
|
||||
var relPath = diff.OriginalString;
|
||||
path2 = new Uri("file:\\\\" + destDirName);
|
||||
|
||||
path2 = new Uri(path2, relPath);
|
||||
|
||||
destFileLocations.Add(path2.LocalPath);
|
||||
if (System.IO.File.Exists(path2.LocalPath))
|
||||
{
|
||||
existingFiles.Add(path2.LocalPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (existingFiles.Count > 0)
|
||||
{
|
||||
var temp = new Uri("file:\\\\" + destDirName);
|
||||
var dr = param.ErrorCallback?.Invoke(StatusValues.ExistingFiles.ToString(), string.Format(Resources.UploadData_Files_Exist, temp.LocalPath, "\n\n"));
|
||||
|
||||
if (DialogResult.OK != dr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < fileLocations.Count && i < destFileLocations.Count; i++)
|
||||
{
|
||||
var fiSource = new System.IO.FileInfo(fileLocations[i]);
|
||||
var fiDest = new System.IO.FileInfo(destFileLocations[destFileLocations.Count - 1 - i]);
|
||||
|
||||
if (!System.IO.Directory.Exists(fiDest.Directory.FullName)) { System.IO.Directory.CreateDirectory(fiDest.Directory.FullName); }
|
||||
|
||||
System.IO.File.Copy(fiSource.FullName, fiDest.FullName, true);
|
||||
var percent = 100D * curFileUndex++ / fileLocations.Count;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log("Upload Failure from ", sourceDirName, " to ", destDirName, ex);
|
||||
return false;
|
||||
}
|
||||
if (!uploadingData) return false;
|
||||
APILogger.Log("Upload Success from ", sourceDirName, " to ", destDirName);
|
||||
copied = true;
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log("Upload Failure from ", sourceDirName, " to ", destDirName, ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class GlobalStatusInformation : IStatusInfo
|
||||
{
|
||||
private static readonly object MyLock = new object();
|
||||
|
||||
private List<IDASCommunication> _unitsInRealtime = new List<IDASCommunication>();
|
||||
/// <summary>
|
||||
/// returns an array of all devices that are known to be in realtime
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IDASCommunication[] GetUnitsInRealtime()
|
||||
{
|
||||
lock (MyLock)
|
||||
{
|
||||
return _unitsInRealtime.ToArray();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// adds a device to the list of units known to be in realtime
|
||||
/// </summary>
|
||||
/// <param name="device"></param>
|
||||
public void AddUnitInRealtime(IDASCommunication device)
|
||||
{
|
||||
lock (MyLock)
|
||||
{
|
||||
if (_unitsInRealtime.Contains(device)) { return; }
|
||||
|
||||
_unitsInRealtime.Add(device);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IDASCommunication> _unitsInArm = new List<IDASCommunication>();
|
||||
/// <summary>
|
||||
/// returns an array of units known to be in arm
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IDASCommunication[] GetUnitsInArm()
|
||||
{
|
||||
lock (MyLock)
|
||||
{
|
||||
return _unitsInArm.ToArray();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// adds a device to the list of devices known to be in arm
|
||||
/// </summary>
|
||||
/// <param name="device"></param>
|
||||
public void AddUnitInArm(IDASCommunication device)
|
||||
{
|
||||
lock (MyLock)
|
||||
{
|
||||
if (_unitsInArm.Contains(device))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_unitsInArm.Add(device);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IDASCommunication> _unitsAtLowPower = new List<IDASCommunication>();
|
||||
/// <summary>
|
||||
/// returns an array of all known devices that are at low power
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IDASCommunication[] GetUnitsAtLowPower()
|
||||
{
|
||||
lock (MyLock)
|
||||
{
|
||||
return _unitsAtLowPower.ToArray();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// adds a unit to the list of units currently at low power
|
||||
/// removes from high power list if present in it
|
||||
/// </summary>
|
||||
/// <param name="das"></param>
|
||||
public void AddUnitAtLowPower(IDASCommunication das)
|
||||
{
|
||||
lock (MyLock)
|
||||
{
|
||||
if (_unitsAtLowPower.Contains(das)) { return; }
|
||||
_unitsAtLowPower.Add(das);
|
||||
if (!_unitsAtHighPower.Contains(das)) { return; }
|
||||
|
||||
_unitsAtHighPower.Remove(das);
|
||||
}
|
||||
}
|
||||
private List<IDASCommunication> _unitsAtHighPower = new List<IDASCommunication>();
|
||||
/// <summary>
|
||||
/// returns an array of all units that are known to be at high power
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IDASCommunication[] GetUnitsAtHighPower()
|
||||
{
|
||||
lock (MyLock)
|
||||
{
|
||||
return _unitsAtHighPower.ToArray();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// adds unit to the list of devices known to be at high power
|
||||
/// removes from the low power list if present
|
||||
/// </summary>
|
||||
/// <param name="das"></param>
|
||||
public void AddUnitAtHighPower(IDASCommunication das)
|
||||
{
|
||||
lock (MyLock)
|
||||
{
|
||||
if (_unitsAtHighPower.Contains(das)) { return; }
|
||||
_unitsAtHighPower.Add(das);
|
||||
if (!_unitsAtLowPower.Contains(das)) { return; }
|
||||
_unitsAtLowPower.Remove(das);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// whether excitation is on or off, currently this is just
|
||||
/// controlled by Configure->TurnOffExcitation and Configure->PrepareForDiagnostics
|
||||
/// the status is only changed currently if all units successfully switch to low power or vice versa
|
||||
/// </summary>
|
||||
public bool ExcitationOn { get; set; } = false;
|
||||
/// <summary>
|
||||
/// resets all status back to defaults
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
ExcitationOn = false;
|
||||
lock (MyLock)
|
||||
{
|
||||
_unitsAtHighPower.Clear();
|
||||
_unitsAtLowPower.Clear();
|
||||
_unitsInRealtime.Clear();
|
||||
_unitsInArm.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using DTS.Common.Enums.Sensors;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class GlobalStatusParameters : IStatusParameters
|
||||
{
|
||||
public bool AllowUDPMulticast { get; set; } = true;
|
||||
public bool DisableAutoSense { get; set; } = SensorConstants.DisableAutoSense;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
AllowUDPMulticast = true;
|
||||
DisableAutoSense = SensorConstants.DisableAutoSense;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using DTS.Common.Interface.DataRecorders;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class HardwareDiscoveryParameters
|
||||
{
|
||||
public bool ReadIds { get; set; } = false;
|
||||
/// <summary>
|
||||
/// ip addresses that we expliticly want to connect to
|
||||
/// if not specified in known tdas or known slice ip addresses will try connecting as both slice and tdas
|
||||
/// </summary>
|
||||
public string[] Addresses { get; set; } = new string[0];
|
||||
/// <summary>
|
||||
/// range of address to ping
|
||||
/// items must be in the form of aaa.bbb.ccc.ddd
|
||||
/// will ping all addresses iterating from item1 upto the 4th byte on item 2
|
||||
/// any ip that responds will be added to ips to connect to
|
||||
/// if it's not known whether it's a SLICE or TDAS then will be added to both lists to connect to
|
||||
/// </summary>
|
||||
public Tuple<string, string>[] AddressRanges { get; set; } = new Tuple<string, string>[0];
|
||||
/// <summary>
|
||||
/// ip address that are known to be TDAS, so we don't have to try connecting to as a slice
|
||||
/// </summary>
|
||||
public string[] KnownTDASIPAddresses { get; set; } = new string[0];
|
||||
/// <summary>
|
||||
/// ip addresses that are known to be SLICE, so we don't have to try connecting to as a TDAS
|
||||
/// </summary>
|
||||
public string[] KnownSLICEIPAddresses { get; set; } = new string[0];
|
||||
/// <summary>
|
||||
/// controls whether we should remain in state or not
|
||||
/// sometimes the user just wants to see the hardware detected and not go onto resolve channels or any additional
|
||||
/// actions
|
||||
/// </summary>
|
||||
public bool ProceedWhenDone { get; set; } = false;
|
||||
/// <summary>
|
||||
/// whether all das are required to be found
|
||||
/// </summary>
|
||||
public bool RequireAllDASFound { get; set; } = false;
|
||||
/// <summary>
|
||||
/// whether to proceed to download state after completion
|
||||
/// </summary>
|
||||
public bool GoToDownload { get; set; } = false;
|
||||
/// <summary>
|
||||
/// controls whether we are ping and connecting or just pinging ...
|
||||
/// </summary>
|
||||
public bool Connect { get; set; } = false;
|
||||
/// <summary>
|
||||
/// controls whether UDP/Multicast discovery should be performed
|
||||
/// </summary>
|
||||
public bool UseMulticastDiscover { get; set; } = false;
|
||||
public int ConnectTimeoutMS { get; set; } = 30000; //30 seconds
|
||||
/// <summary>
|
||||
/// whether to run auto-sense or not
|
||||
/// note that DisableAutoSense overrules this setting
|
||||
/// </summary>
|
||||
public bool RunAutoSense { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// specific device to query, when present
|
||||
/// this is used to signal that there's a device already attached that
|
||||
/// we want to requery
|
||||
/// this is done when the device configuration is changed
|
||||
/// </summary>
|
||||
public IDASCommunication RequeryDevice { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// serial numbers that are required to connect
|
||||
/// </summary>
|
||||
public string[] RequiredSerials { get; set; } = new string[0];
|
||||
/// <summary>
|
||||
/// controls whether to perform hardware checks (voltage/memory/firmware/etc)
|
||||
/// after connecting to hardware
|
||||
/// </summary>
|
||||
public bool DoHardwareChecks { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// hardware that we expect to be connected once ping and connect completes
|
||||
/// used as part of DoHardwareChecks
|
||||
/// </summary>
|
||||
public IDASHardware[] ExpectedHardware { get; set; } = new IDASHardware[0];
|
||||
|
||||
public delegate bool UnitIsInDbDelegate(IDASCommunication das);
|
||||
public UnitIsInDbDelegate UnitIsInDbQuery { get; set; } = null;
|
||||
|
||||
public delegate string FirmwareExpectedVersionDelegate(IDASCommunication das);
|
||||
public FirmwareExpectedVersionDelegate UnitExpectedFirmwareQuery { get; set; } = null;
|
||||
|
||||
public delegate bool IsCalDateExpiredDelegate(IDASCommunication das);
|
||||
public IsCalDateExpiredDelegate CalDateExpiredQuery { get; set; } = null;
|
||||
|
||||
public delegate long UnitExpectedMaxMemoryDelegate(IDASCommunication das);
|
||||
public UnitExpectedMaxMemoryDelegate UnitExpectedMaxMemoryQuery { get; set; } = null;
|
||||
|
||||
public delegate void UpdateMaxMemoryDelegate(IDASCommunication das);
|
||||
public UpdateMaxMemoryDelegate UpdateMaxMemoryAction { get; set; } = null;
|
||||
/// <summary>
|
||||
/// whether to check the input/battery voltage for units or not
|
||||
/// </summary>
|
||||
public bool DoVoltageChecks { get; set; } = true;
|
||||
public void Reset()
|
||||
{
|
||||
ReadIds = false;
|
||||
Addresses = new string[0];
|
||||
AddressRanges = new Tuple<string, string>[0];
|
||||
ProceedWhenDone = false;
|
||||
RequireAllDASFound = false;
|
||||
KnownSLICEIPAddresses = new string[0];
|
||||
KnownTDASIPAddresses = new string[0];
|
||||
RequeryDevice = null;
|
||||
RequiredSerials = new string[0];
|
||||
DoHardwareChecks = false;
|
||||
ExpectedHardware = new IDASHardware[0];
|
||||
UnitIsInDbQuery = null;
|
||||
UnitExpectedFirmwareQuery = null;
|
||||
CalDateExpiredQuery = null;
|
||||
UnitExpectedMaxMemoryQuery = null;
|
||||
UpdateMaxMemoryAction = null;
|
||||
DoVoltageChecks = true;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"ReadIds={ReadIds.ToString()}");
|
||||
sb.AppendLine($"Addresses={string.Join(",", Addresses)}");
|
||||
sb.Append("AddressRanges=");
|
||||
for (int i = 0; i < AddressRanges.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(", ");
|
||||
}
|
||||
sb.Append($"({AddressRanges[i].Item1},{AddressRanges[i].Item2})");
|
||||
}
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"ProceedWhenDone={ProceedWhenDone.ToString()}");
|
||||
sb.AppendLine($"RequireAllDASFound={RequireAllDASFound.ToString()}");
|
||||
sb.AppendLine($"KnownSLICEIPAddresses={string.Join(",", KnownSLICEIPAddresses)}");
|
||||
sb.AppendLine($"KnownTDASIPAddresses={string.Join(",", KnownTDASIPAddresses)}");
|
||||
sb.Append("RequiryDevice=");
|
||||
if (null == RequeryDevice)
|
||||
{
|
||||
sb.AppendLine("null");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine(RequeryDevice.SerialNumber);
|
||||
}
|
||||
|
||||
sb.AppendLine($"RequiredSerials={string.Join(",", RequiredSerials)}");
|
||||
sb.AppendLine($"DoHardwareChecks={DoHardwareChecks.ToString()}");
|
||||
sb.Append("ExpectedHardware=");
|
||||
for (var i = 0; i < ExpectedHardware.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(", ");
|
||||
}
|
||||
sb.Append(ExpectedHardware[i].SerialNumber);
|
||||
}
|
||||
sb.AppendLine();
|
||||
|
||||
sb.Append("UnitIsInDbQuery=");
|
||||
sb.AppendLine(null == UnitIsInDbQuery ? "[null]" : "[defined]");
|
||||
|
||||
sb.Append("UnitExpectedFirmwareQuery=");
|
||||
sb.AppendLine(null == UnitExpectedFirmwareQuery ? "[null]" : "[defined]");
|
||||
|
||||
sb.Append("CalDateExpiredQuery=");
|
||||
sb.AppendLine(null == CalDateExpiredQuery ? "[null]" : "[defined]");
|
||||
|
||||
sb.Append("UnitExpectedMaxMemoryQuery=");
|
||||
sb.AppendLine(null == UnitExpectedMaxMemoryQuery ? "[null]" : "[defined]");
|
||||
|
||||
sb.Append("UpdateMaxMemoryAction=");
|
||||
sb.AppendLine(null == UpdateMaxMemoryAction ? "[null]" : "[defined]");
|
||||
|
||||
sb.Append("DoVoltageChecks=");
|
||||
sb.AppendLine(DoVoltageChecks.ToString());
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public interface IStatusInfo
|
||||
{
|
||||
void Reset();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public interface IStatusParameters
|
||||
{
|
||||
void Reset();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static DTS.DASLib.Service.ServiceBase;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class RealtimeParameters : IStatusParameters
|
||||
{
|
||||
public List<IDASCommunication> UnitsToStartRealtime { get; set; }
|
||||
public int RealtimeDelayBetweenPollsInMilliSecond { get; set; }
|
||||
public bool AllowMultipleSampleRealtime { get; set; }
|
||||
public bool UseSingleSampleMode { get; set; }
|
||||
public List<int> ModuleIndices { get; set; }
|
||||
public Dictionary<IDASCommunication, byte[]> IdasToActiveChannels { get; set; }
|
||||
public double RealtimeSampleRate { get; set; }
|
||||
public byte RealtimeSampleRateAAFilterRatio { get; set; }
|
||||
public bool SliceTurnOffAAFRealtime { get; set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
UnitsToStartRealtime = new List<IDASCommunication>();
|
||||
RealtimeDelayBetweenPollsInMilliSecond = 0;
|
||||
AllowMultipleSampleRealtime = false;
|
||||
UseSingleSampleMode = false;
|
||||
ModuleIndices = new List<int>();
|
||||
IdasToActiveChannels = new Dictionary<IDASCommunication, byte[]>();
|
||||
RealtimeSampleRate = 0.0;
|
||||
RealtimeSampleRateAAFilterRatio = 0;
|
||||
SliceTurnOffAAFRealtime = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
using DTS.Common.Enums.DASFactory;
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using DTS.Common.Interface.StatusAndProgressBar;
|
||||
using DTS.Common.Utilities.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static DTS.DASLib.Service.ServiceBase;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class RealtimeStatusInformation : IStatusInfo
|
||||
{
|
||||
private readonly ManualResetEvent stopRealtimeEvent = new ManualResetEvent(true);
|
||||
|
||||
//this is a wait handle that is set when we get a callback from realtime service saying it's done
|
||||
private readonly ManualResetEvent realtimeDoneFromService = new ManualResetEvent(false);
|
||||
|
||||
/// <summary>
|
||||
/// action to take on completion of Realtime start
|
||||
/// </summary>
|
||||
public Action CompleteAction { get; set; }
|
||||
public void Reset()
|
||||
{
|
||||
CompleteAction = null;
|
||||
realtimeDoneFromService.Reset();
|
||||
stopRealtimeEvent.Set();
|
||||
CouldNotStartRealtime = false;
|
||||
}
|
||||
|
||||
public Action<double, double> SetRealtimeSampleRateAAF { get; set; }
|
||||
public bool CouldNotStartRealtime { get; set; }
|
||||
public Callback StartRealtimeCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// returns the Anti-Alias Filter (AAF) for the DAS in question
|
||||
/// this is dependent on the sample rate for the hardware and a ratio in the config file
|
||||
/// (RealtimeSampleRateAAFilterRatio)
|
||||
/// </summary>
|
||||
/// <param name="das"></param>
|
||||
/// <returns></returns>
|
||||
private float GetRealtimeAAFForHardware(IDASCommunication idas, double samplerate)
|
||||
{
|
||||
var param = States.Instance.Realtime.Status.RealtimeParams;
|
||||
if (param.SliceTurnOffAAFRealtime && DFConstantsAndEnums.SupportsTurnOffAAFRealtime(idas))
|
||||
{
|
||||
return Common.Constants.SLICE2_NO_AAF_REALTIME_RATE;
|
||||
}
|
||||
//for now there is no additional work done
|
||||
if (0 == param.RealtimeSampleRateAAFilterRatio) { return Convert.ToSingle(samplerate); }
|
||||
return (float)samplerate / param.RealtimeSampleRateAAFilterRatio;
|
||||
}
|
||||
|
||||
public bool IsInRealtime
|
||||
{
|
||||
get { return !stopRealtimeEvent.WaitOne(2, false); }
|
||||
}
|
||||
|
||||
public void StopRealtime()
|
||||
{
|
||||
stopRealtimeEvent.Set();
|
||||
}
|
||||
|
||||
Task _realtimeTask;
|
||||
public void StartRealtime()
|
||||
{
|
||||
_realtimeTask = Task.Run(() =>
|
||||
{
|
||||
var param = States.Instance.Realtime.Status.RealtimeParams;
|
||||
var status = States.Instance.Realtime.Status.RealtimeStatus;
|
||||
var global = States.Instance.Realtime.Status.GlobalStatusParameters;
|
||||
StartRealtime(param.UnitsToStartRealtime, param.ModuleIndices, param.UseSingleSampleMode,
|
||||
param.RealtimeSampleRate, param.RealtimeDelayBetweenPollsInMilliSecond, param.AllowMultipleSampleRealtime, status.SetRealtimeSampleRateAAF, status.CompleteAction,
|
||||
param.IdasToActiveChannels, status.StartRealtimeCallback);
|
||||
});
|
||||
}
|
||||
|
||||
public void StartRealtime(List<IDASCommunication> ldas, List<int> moduleArrayIndicies, bool useSingleSampleMode,
|
||||
double realtimeSampleRate, int realtimeDelayBetweenPolls, bool allowMultipleSampleRealtime, Action<double, double> SetRealtimeSampleRateAAF, Action CompleteAction,
|
||||
Dictionary<IDASCommunication, byte[]> idasToActiveChannels, Callback StartRealtimeCallback
|
||||
)
|
||||
{
|
||||
var startRealtimeCallback = new Callback(StartRealtimeCallback);
|
||||
startRealtimeCallback += (data) =>
|
||||
{
|
||||
if (data.Status == CallbackData.CallbackStatus.AllFinished)
|
||||
{
|
||||
//service is done, mark it
|
||||
realtimeDoneFromService.Set();
|
||||
}
|
||||
if (data.Status == CallbackData.CallbackStatus.Failure)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
stopRealtimeEvent.Reset();
|
||||
using (var realtimeService = new RealtimeService())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ldas.Count > 0)
|
||||
{
|
||||
|
||||
if (useSingleSampleMode)
|
||||
{
|
||||
realtimeDoneFromService.Reset();
|
||||
realtimeService.StartActivePolling(ldas, startRealtimeCallback, ldas,
|
||||
stopRealtimeEvent, idasToActiveChannels);
|
||||
SetRealtimeSampleRateAAF(double.NaN, double.NaN);
|
||||
}
|
||||
else
|
||||
{
|
||||
realtimeDoneFromService.Reset();
|
||||
realtimeService.Start(ldas,
|
||||
Convert.ToInt32(realtimeSampleRate),
|
||||
realtimeDelayBetweenPolls,
|
||||
startRealtimeCallback,
|
||||
ldas,
|
||||
allowMultipleSampleRealtime,
|
||||
moduleArrayIndicies.ToArray(),
|
||||
stopRealtimeEvent,
|
||||
idasToActiveChannels,
|
||||
GetRealtimeAAFForHardware);
|
||||
if (ldas.Any())
|
||||
{
|
||||
SetRealtimeSampleRateAAF(realtimeSampleRate,
|
||||
GetRealtimeAAFForHardware(ldas[0], realtimeSampleRate));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRealtimeSampleRateAAF(double.NaN, double.NaN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log(ex);
|
||||
CouldNotStartRealtime = true;
|
||||
//there was an exception , stop the realtime and service
|
||||
stopRealtimeEvent.Set();
|
||||
realtimeDoneFromService.Set();
|
||||
}
|
||||
finally
|
||||
{
|
||||
CompleteAction();
|
||||
}
|
||||
|
||||
var mr = new ManualResetEvent(false);
|
||||
realtimeService.ServiceAvailable += delegate
|
||||
{
|
||||
realtimeService.ServiceAvailable -= delegate { };
|
||||
mr.Set();
|
||||
};
|
||||
|
||||
while (!stopRealtimeEvent.WaitOne(30, false) && !mr.WaitOne(1, false))
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
//either realtime event was signalled to stop (datapro) or the service actually did already stop
|
||||
//go and set the event handle to stopped to notify service in case it's running
|
||||
stopRealtimeEvent.Set();
|
||||
//now wait for the event from the service saying it's stopped
|
||||
realtimeDoneFromService.WaitOne();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
DataPRO/IService/StateMachine/StatusAndParameters/Status.cs
Normal file
30
DataPRO/IService/StateMachine/StatusAndParameters/Status.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class Status
|
||||
{
|
||||
public HardwareDiscoveryParameters HardwareDiscoveryParams = new HardwareDiscoveryParameters();
|
||||
public HardwareDiscoveryStatusInfo HardwareDiscoveryStatusInfo = new HardwareDiscoveryStatusInfo();
|
||||
public GlobalStatusInformation GlobalStatusInformation = new GlobalStatusInformation();
|
||||
public GlobalStatusParameters GlobalStatusParameters = new GlobalStatusParameters();
|
||||
public ConfigureStatusInformation ConfigureStatus = new ConfigureStatusInformation();
|
||||
public ConfigureStatusParameters ConfigureParameters = new ConfigureStatusParameters();
|
||||
public RealtimeStatusInformation RealtimeStatus = new RealtimeStatusInformation();
|
||||
public RealtimeParameters RealtimeParams = new RealtimeParameters();
|
||||
public DiagnoseParameters DiagnoseParams = new DiagnoseParameters();
|
||||
public DownloadParameters DownloadParams = new DownloadParameters();
|
||||
public DownloadStatusInformation DownloadStatusInfo = new DownloadStatusInformation();
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
GlobalStatusParameters.Reset();
|
||||
GlobalStatusInformation.Reset();
|
||||
HardwareDiscoveryParams.Reset();
|
||||
HardwareDiscoveryStatusInfo.Reset();
|
||||
ConfigureStatus.Reset();
|
||||
ConfigureParameters.Reset();
|
||||
RealtimeStatus.Reset();
|
||||
RealtimeParams.Reset();
|
||||
DiagnoseParams.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
18
DataPRO/IService/StateMachine/Triggers.cs
Normal file
18
DataPRO/IService/StateMachine/Triggers.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
enum Trigger
|
||||
{
|
||||
PingAndConnect,
|
||||
Reset,
|
||||
ResolveChannelsAuto,
|
||||
ResolveChannelsManual,
|
||||
ApplyConfiguration,
|
||||
TurnOffExcitation,
|
||||
Cancel,
|
||||
Finish,
|
||||
Arm,
|
||||
StartRealtime,
|
||||
RequeryDevice,
|
||||
Download
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user