init
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user