init
This commit is contained in:
452
Common/DTS.Common.DataModel/DASFactory.cs
Normal file
452
Common/DTS.Common.DataModel/DASFactory.cs
Normal file
@@ -0,0 +1,452 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using DTS.Common.Utilities;
|
||||
using DTS.DASLib.DASFactory;
|
||||
using DTS.DASLib.Service;
|
||||
using DTS.Common.Utilities.Logging;
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using DTS.Common.Enums.DASFactory;
|
||||
using DTS.Common.DataModel;
|
||||
|
||||
namespace DataPROWin7.DataModel
|
||||
{
|
||||
public class DASFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// starts the auto discovery process if it's not running yet
|
||||
/// </summary>
|
||||
public void StartMulticastAutoDiscovery()
|
||||
{
|
||||
_dasFactory.StartMulticastAutoDiscovery();
|
||||
}
|
||||
/// <summary>
|
||||
/// stops the auto discovery process if it is running
|
||||
/// </summary>
|
||||
public void StopMulticastAutoDiscovery()
|
||||
{
|
||||
_dasFactory.StopMulticastAutoDiscovery();
|
||||
}
|
||||
/// <summary>
|
||||
/// returns any discovered devices
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IDiscoveredDevice [] GetDiscoveredDevices()
|
||||
{
|
||||
return _dasFactory.GetDiscoveredDevices();
|
||||
}
|
||||
private DTS.DASLib.DASFactory.DASFactory _dasFactory;
|
||||
public IDASFactory GetDASFactory() { return _dasFactory; }
|
||||
public DASFactory()
|
||||
{
|
||||
//10285 Unhandled exception during diagnostics.
|
||||
//this initializes the interval value used in CheckUnitsAvailable to make the sleep time configurable.
|
||||
DTS.DASLib.Service.ServiceBase.InitializeCheckUnitsInterval(DataModelSettings.CheckUnitsIntervalMillisecond);
|
||||
//10843 TDAS communication needs to be throttled
|
||||
//this initializes the throttling of TDAS devices
|
||||
DTS.DASLib.Command.TDAS.CommandBase.InitializeSemaphore(
|
||||
DataModelSettings.SemaphoreDelay,
|
||||
DataModelSettings.SemaphoreSpots);
|
||||
//initialize SLICESemaphore before any communication starts
|
||||
//10852 Add semaphore to SLICE communication to improve SLICE 6 multiple IP performance
|
||||
DTS.DASLib.Command.SliceCommandBase.Initialize(DataModelSettings.SLICEConcurrentSpots,
|
||||
DataModelSettings.SLICEConcurrentDelayMs);
|
||||
_dasFactory = new DTS.DASLib.DASFactory.DASFactory(false, false);
|
||||
_dasFactory.DetachAllDevices();
|
||||
var mre = new ManualResetEvent(false);
|
||||
_dasFactory.Refresh(delegate { mre.Set(); });
|
||||
mre.WaitOne();
|
||||
_dasFactory.MultiCastAutoDiscoveryDefaultTimeoutMS = DataModelSettings.MulticastAutoDiscoveryReceiveTimeoutMS;
|
||||
|
||||
//16053 Implement KeepAliveSeconds and KeepAliveRetrySeconds in the .config file
|
||||
DFConstantsAndEnums.LocalKeepAliveRetryIntervalMS = DataModelSettings.LocalKeepAliveRetryIntervalMS;
|
||||
DFConstantsAndEnums.LocalKeepAliveTimeOutMS = DataModelSettings.LocalKeepAliveTimeOutMS;
|
||||
DFConstantsAndEnums.RemoteKeepAliveRetryIntervalSeconds = DataModelSettings.RemoteKeepAliveRetryIntervalSeconds;
|
||||
DFConstantsAndEnums.RemoteKeepAliveSeconds = DataModelSettings.RemoteKeepAliveSeconds;
|
||||
|
||||
DFConstantsAndEnums.ReceiveBufferSizeBytes = DataModelSettings.ReceiveBufferSizeBytes;
|
||||
DFConstantsAndEnums.SendBufferSizeBytes = DataModelSettings.SendBufferSizeBytes;
|
||||
|
||||
DFConstantsAndEnums.HeartbeatAsyncConnectTimeoutMS = DataModelSettings.HeartbeatAsyncConnectTimeoutMS;
|
||||
|
||||
_dasFactory.DeviceArrived += _dasFactory_DeviceArrived;
|
||||
_dasFactory.DeviceFailed += _dasFactory_DeviceFailed;
|
||||
_dasFactory.DeviceRemoved += _dasFactory_DeviceRemoved;
|
||||
}
|
||||
|
||||
public event DASFactoryEventHandler OnDeviceArrived;
|
||||
public event DASFactoryEventHandler OnFactoryChanged;
|
||||
|
||||
public void TakeOwnership()
|
||||
{
|
||||
try
|
||||
{
|
||||
_dasFactory.TakeOwnership();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void _dasFactory_DeviceRemoved(object sender, DASFactoryEventArgs e)
|
||||
{
|
||||
OnFactoryChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
|
||||
private void _dasFactory_DeviceFailed(object sender, DASFactoryEventArgs e)
|
||||
{
|
||||
OnFactoryChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void _dasFactory_DeviceArrived(object sender, DASFactoryEventArgs e)
|
||||
{
|
||||
OnDeviceArrived?.Invoke(sender, e);
|
||||
OnFactoryChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
public void DetachAllDevices(bool detachUSB = false)
|
||||
{
|
||||
// FB14290: make USB detaching conditional
|
||||
_dasFactory.DetachAllDevices(detachUSB);
|
||||
}
|
||||
|
||||
public void DisposeFactory()
|
||||
{
|
||||
_dasFactory.Dispose();
|
||||
_dasFactory = null;
|
||||
}
|
||||
//#define LOG_DEBUG_REFRESH
|
||||
public string[] TDASHostNames
|
||||
{
|
||||
get { return _dasFactory.TDASHostNames; }
|
||||
set
|
||||
{
|
||||
if (_bInRefresh)
|
||||
{
|
||||
#if LOG_DEBUG_REFRESH
|
||||
var st = new StackTrace(true);
|
||||
APILogger.Log("TDASHostNames SET WHILE WE ARE IN REFRESH\n", st.ToString());
|
||||
#endif
|
||||
}
|
||||
if (null == value || null == _dasFactory.TDASHostNames)
|
||||
{
|
||||
_dasFactory.TDASHostNames = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var val = value.Distinct().OrderBy(a => a);
|
||||
// this has side effects, so only change if needed
|
||||
var isEqual = _dasFactory.TDASHostNames.OrderBy(a => a).SequenceEqual(val);
|
||||
if (!isEqual)
|
||||
{
|
||||
_dasFactory.TDASHostNames = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string[] SPFDHostNames
|
||||
{
|
||||
get => _dasFactory.SPFDHostNames;
|
||||
set
|
||||
{
|
||||
if (null == value || null == _dasFactory.SPFDHostNames)
|
||||
{
|
||||
_dasFactory.SPFDHostNames = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var val = value.Distinct().OrderBy(a => a);
|
||||
// this has side effects, so only change if needed
|
||||
var isEqual = _dasFactory.SPFDHostNames.OrderBy(a => a).SequenceEqual(val);
|
||||
if (!isEqual)
|
||||
{
|
||||
_dasFactory.SPFDHostNames = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// http://fogbugz/fogbugz/default.asp?2903
|
||||
/// could also be called SliceDbHostNames
|
||||
/// </summary>
|
||||
public string[] SDBHostNames
|
||||
{
|
||||
get { return _dasFactory.SliceDBHostNames; }
|
||||
set
|
||||
{
|
||||
if (_bInRefresh)
|
||||
{
|
||||
#if LOG_DEBUG_REFRESH
|
||||
var st = new StackTrace(true);
|
||||
APILogger.Log("SDBHostNames SET WHILE WE ARE IN REFRESH\n", st.ToString());
|
||||
#endif
|
||||
}
|
||||
if (null == value || null == _dasFactory.SliceDBHostNames)
|
||||
{
|
||||
_dasFactory.SliceDBHostNames = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this has side effects, so only change if needed
|
||||
var equals = _dasFactory.SliceDBHostNames.OrderBy(a => a).SequenceEqual(value.OrderBy(a => a));
|
||||
if (false == equals)
|
||||
{
|
||||
_dasFactory.SliceDBHostNames = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SortableBindingList<IDiscoveredDevice> AutoDiscoverMulticast()
|
||||
{
|
||||
CancellationToken ct = new CancellationToken();
|
||||
return _dasFactory.AutoDiscoverMulticast(ct);
|
||||
}
|
||||
public delegate void DiscoveredDASEventHandler(object sender, IEnumerable<IDiscoveredDevice> newDevices);
|
||||
public event DiscoveredDASEventHandler DiscoveredDAS;
|
||||
public void DiscoveryThread(DFConstantsAndEnums.MultiCastDeviceClasses[] deviceFilter, CancellationToken ct, bool discoverParents = true)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
var discoveries = _dasFactory.AutoDiscoverMulticast(ct, discoverParents).ToList();
|
||||
var filteredDiscoveries = deviceFilter?.Count() > 0 ? discoveries.Where(idd => deviceFilter.Contains(idd.DevClass)).ToList() : discoveries;
|
||||
|
||||
DiscoveredDAS.Invoke(this, filteredDiscoveries);
|
||||
|
||||
ct.WaitHandle.WaitOne(1000);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// starts qats listening
|
||||
/// </summary>
|
||||
public void StartQATSListening()
|
||||
{
|
||||
_dasFactory.StartQATSListening();
|
||||
}
|
||||
/// <summary>
|
||||
/// stops any QATS listening
|
||||
/// </summary>
|
||||
public void StopQATSListening()
|
||||
{
|
||||
_dasFactory.StopQATSListening();
|
||||
}
|
||||
/// <summary>
|
||||
/// sends the request to send UDP QATS messages
|
||||
/// </summary>
|
||||
public void SendQATSRequest()
|
||||
{
|
||||
_dasFactory.SendQATSRequest();
|
||||
}
|
||||
/// <summary>
|
||||
/// returns any QueryArmTriggerStatus that are waiting and clears the list of waiting QATS
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IUDPQATSEntry[] GetQATS()
|
||||
{
|
||||
return _dasFactory.GetQATS();
|
||||
}
|
||||
/// <summary>
|
||||
/// configures the default timeout for multicast autodiscovery receive timeout
|
||||
/// in ms
|
||||
/// </summary>
|
||||
public int MulticastAutoDiscoveryReceiveTimeoutMS
|
||||
{
|
||||
get => _dasFactory.MultiCastAutoDiscoveryDefaultTimeoutMS;
|
||||
set => _dasFactory.MultiCastAutoDiscoveryDefaultTimeoutMS = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// configures the trasmit address for multicast autodiscovery
|
||||
/// in ms
|
||||
/// </summary>
|
||||
public string MulticastAutoDiscoveryAddress
|
||||
{
|
||||
get => _dasFactory.MulticastAutoDiscoveryAddress;
|
||||
set => _dasFactory.MulticastAutoDiscoveryAddress = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// configures the trasmit port for multicast autodiscovery
|
||||
/// in ms
|
||||
/// </summary>
|
||||
public int MulticastAutoDiscoveryPort
|
||||
{
|
||||
get => _dasFactory.MulticastAutoDiscoveryPort;
|
||||
set => _dasFactory.MulticastAutoDiscoveryPort = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// configures the receive port for multicast autodiscovery
|
||||
/// in ms
|
||||
/// </summary>
|
||||
public int MulticastAutoDiscoveryResponsePort
|
||||
{
|
||||
get => _dasFactory.MulticastAutoDiscoveryResponsePort;
|
||||
set => _dasFactory.MulticastAutoDiscoveryResponsePort = value;
|
||||
}
|
||||
|
||||
public double S6ConnectNewTimeout
|
||||
{
|
||||
get => _dasFactory.S6ConnectNewTimeout;
|
||||
set => _dasFactory.S6ConnectNewTimeout = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// I noticed in some logs - only one refresh at a time
|
||||
/// refresh is getting called multiple times for some reason.
|
||||
/// This gets a bit sticky, there's no reason for Refresh to be called more than once while refresh is still running,
|
||||
/// however one of the options for refresh is to not wait for it to finish, which means you could get into this situation.
|
||||
/// I haven't been able to duplicate this problem myself, so I'm going to add some logging to help find out how we got there if we
|
||||
/// get there again, and also some code to address when we do find ourselves there
|
||||
///
|
||||
/// </summary>
|
||||
private volatile bool _bInRefresh;
|
||||
|
||||
public void Refresh(bool wait)
|
||||
{
|
||||
|
||||
APILogger.Log(APILogger.GetCurrentMethod());
|
||||
if (_bInRefresh)
|
||||
{
|
||||
#if LOG_DEBUG_REFRESH
|
||||
var st = new StackTrace(true);
|
||||
APILogger.Log(string.Format("Warning - OVERLAPPING REFRESH CALL!\nStackTrace:\n{0}", st));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
var mre = new ManualResetEvent(false);
|
||||
try
|
||||
{
|
||||
_bInRefresh = true;
|
||||
_dasFactory.Refresh(delegate
|
||||
{
|
||||
mre.Set();
|
||||
_bInRefresh = false;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log("Exception refreshing ", ex.Message);
|
||||
return;
|
||||
}
|
||||
if (wait)
|
||||
{
|
||||
mre.WaitOne();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<IDASCommunication> GetActiveDevices()
|
||||
{
|
||||
return _dasFactory.GetDASList();
|
||||
}
|
||||
/// <summary>
|
||||
/// 14157 Refresh/Stability Issue in Data Acquisition Tile
|
||||
/// returns the list of all devices known connectable via ECM/SDB/S6DB
|
||||
/// these distributors have a HELLO SLICEBASE x.x.x.x:yyyy format, so
|
||||
/// we keep track of what the db told us
|
||||
/// this returns all the reported connections
|
||||
/// </summary>
|
||||
public string[] GetReportedConnections()
|
||||
{
|
||||
return _dasFactory.GetConnectedDevices();
|
||||
}
|
||||
/// <summary>
|
||||
/// runs auto discovery if needed, populating the downstream mac addresses for all attached SLICE6/SLICE6Db devices
|
||||
/// completes immediately if there are no attached SLICE6/SLICE6Db devices
|
||||
/// </summary>
|
||||
public void AutoDiscoverIfNecessary()
|
||||
{
|
||||
var foundDas = ApplicationProperties.DASFactory.GetActiveDevices();
|
||||
var bNeedToRun = foundDas.OfType<EthernetSlice6DB>().Any();
|
||||
if (!bNeedToRun) return;
|
||||
var ipAddressToIdas = new Dictionary<string, IDASCommunication>();
|
||||
foreach (var das in foundDas)
|
||||
{
|
||||
var h = new DASHardware(das);
|
||||
var connection = h.ConnectionUSBAware.ToLower();
|
||||
if (connection.Contains("usb"))
|
||||
{
|
||||
connection = h.SerialNumber;
|
||||
}
|
||||
ipAddressToIdas[connection] = das;
|
||||
}
|
||||
try
|
||||
{
|
||||
var units = ApplicationProperties.DASFactory.AutoDiscoverMulticast();
|
||||
var macAddresToDevice = new Dictionary<string, IDiscoveredDevice>();
|
||||
foreach (var unit in units)
|
||||
{
|
||||
var mac = unit.Mac.Replace('-', ':').ToUpper();
|
||||
macAddresToDevice[mac] = unit;
|
||||
}
|
||||
foreach (var unit in units)
|
||||
{
|
||||
if (!ipAddressToIdas.ContainsKey(unit.Ip))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ipAddressToIdas[unit.Ip].MACAddress = unit.Mac;
|
||||
ipAddressToIdas[unit.Ip].DownstreamMACAddresses = (from c in unit.Connections
|
||||
select c.MACAddress.Replace('-', ':').ToUpper()
|
||||
into childMac
|
||||
where macAddresToDevice.ContainsKey(childMac)
|
||||
select macAddresToDevice[childMac]
|
||||
into childDevice
|
||||
select childDevice.Mac).ToArray();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log(ex);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// returns true if the DAS is streaming
|
||||
/// </summary>
|
||||
/// <param name="das"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsStreaming(IDASCommunication das)
|
||||
{
|
||||
if (!(das is EthernetSlice6Air)) { return false; }
|
||||
|
||||
if (null == das.DASArmStatus)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//15932 Error when performing test when S6A is streaming
|
||||
//don't currently know of a better way to determine if the unit is streaming or not
|
||||
//when attaching to a stream device some attributes can't be read and because of timing
|
||||
//some status may not be populated, but if we aren't armed or in realtime and we are a S6A and
|
||||
//we responded with Invalid mode during setup, we are _probably_ streaming
|
||||
return !das.DASArmStatus.IsArmed && !das.DASArmStatus.IsInRealtime &&
|
||||
das.DASArmStatus.ReceivedInvalidModeDuringSetup;
|
||||
}
|
||||
/// <summary>
|
||||
/// returns true if the unit is in realtime
|
||||
/// uses DASArmStatus, but this isn't always populated on time, so if the unit is streaming it will also
|
||||
/// return true, which seems to be consistent with what was intended in the old code
|
||||
/// 15932 Error when performing test when S6A is streaming
|
||||
/// </summary>
|
||||
/// <param name="das"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsInRealtime(IDASCommunication das)
|
||||
{
|
||||
if (null == das.DASArmStatus) { return false; }
|
||||
return das.DASArmStatus.IsInRealtime || IsStreaming(das);
|
||||
}
|
||||
/// <summary>
|
||||
/// returns true if any of the units in the input parameters are in realtime or are streaming
|
||||
/// </summary>
|
||||
/// <param name="das"></param>
|
||||
/// <returns></returns>
|
||||
public static bool AnyInRealtime(List<IDASCommunication> das)
|
||||
{
|
||||
return das.Exists(unit => IsInRealtime(unit));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user