127 lines
4.6 KiB
C#
127 lines
4.6 KiB
C#
using DTS.Common.Enums.DASFactory;
|
|
using DTS.Common.Interface.DASFactory;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace DTS.DASLib.DASFactory
|
|
{
|
|
internal class AutoDiscovery
|
|
{
|
|
private readonly IDASFactory _dasFactory;
|
|
/// <summary>
|
|
/// this is the task that is actively looking for UDP devices
|
|
/// </summary>
|
|
private Task _scanTask = null;
|
|
/// <summary>
|
|
/// this is the cancellation token source for the cancel token used by the scan task
|
|
/// </summary>
|
|
private CancellationTokenSource tokenSource = new CancellationTokenSource();
|
|
/// <summary>
|
|
/// this is a lock used to make start/stop and Get thread safe
|
|
/// </summary>
|
|
private static readonly object _multicastLock = new object();
|
|
|
|
/// <summary>
|
|
/// starts a background discovery process
|
|
/// </summary>
|
|
public void StartMulticastAutoDiscovery()
|
|
{
|
|
lock (_multicastLock)
|
|
{
|
|
//start scanning (unless we are already scanning)
|
|
if (null == _scanTask || _scanTask.IsCompleted)
|
|
{
|
|
if (tokenSource.IsCancellationRequested)
|
|
{
|
|
tokenSource.Dispose();
|
|
// token has been cancelled. no "reset" other than creating a new token source
|
|
tokenSource = new CancellationTokenSource();
|
|
}
|
|
_scanTask = Task.Run(() => DiscoveryWork(null, tokenSource.Token, false));
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// stops a background discovery process
|
|
/// </summary>
|
|
public void StopMulticastAutoDiscovery()
|
|
{
|
|
lock (_multicastLock)
|
|
{
|
|
//stop scanning (unless it's not currently scanning)
|
|
if (null == _scanTask || _scanTask.IsCompleted) { return; }
|
|
if (tokenSource.Token.CanBeCanceled)
|
|
{
|
|
tokenSource.Cancel();
|
|
}
|
|
}
|
|
_scanTask.Wait();
|
|
_scanTask = null;
|
|
}
|
|
/// <summary>
|
|
/// list of any discovered devices since discovery started
|
|
/// </summary>
|
|
private readonly List<IDiscoveredDevice> _discoveredDevices = new List<IDiscoveredDevice>();
|
|
/// <summary>
|
|
/// this is the actual discovery thread
|
|
/// </summary>
|
|
/// <param name="deviceFilter"></param>
|
|
/// <param name="ct"></param>
|
|
/// <param name="discoverParents"></param>
|
|
private void DiscoveryWork(DFConstantsAndEnums.MultiCastDeviceClasses[] deviceFilter, CancellationToken ct, bool discoverParents = true)
|
|
{
|
|
var keepGoing = !ct.IsCancellationRequested;
|
|
|
|
ClearDiscoveredDevices();
|
|
while (keepGoing)
|
|
{
|
|
var discoveries = _dasFactory.AutoDiscoverMulticast(ct, discoverParents).ToArray();
|
|
var filteredDiscoveries = deviceFilter?.Count() > 0 ? discoveries.Where(x => deviceFilter.Contains(x.DevClass)).ToArray() : discoveries;
|
|
UpdateDevices(filteredDiscoveries);
|
|
ct.WaitHandle.WaitOne(1000);
|
|
keepGoing = !ct.IsCancellationRequested;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// adds any new devices to list of devices
|
|
/// does not change any existing entries
|
|
/// </summary>
|
|
/// <param name="devices"></param>
|
|
private void UpdateDevices(IDiscoveredDevice[] devices)
|
|
{
|
|
lock (_multicastLock)
|
|
{
|
|
foreach (var device in devices)
|
|
{
|
|
if (!_discoveredDevices.Exists(x => x.Serial == device.Serial))
|
|
{
|
|
_discoveredDevices.Add(device);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// clears any discovered devices
|
|
/// </summary>
|
|
private void ClearDiscoveredDevices()
|
|
{
|
|
lock (_multicastLock) { _discoveredDevices.Clear(); }
|
|
}
|
|
/// <summary>
|
|
/// retrieves all discovered devices
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public IDiscoveredDevice[] GetDiscoveredDevices()
|
|
{
|
|
lock (_multicastLock) { return _discoveredDevices.ToArray(); }
|
|
}
|
|
|
|
public AutoDiscovery(IDASFactory dasFactory)
|
|
{
|
|
_dasFactory = dasFactory;
|
|
}
|
|
}
|
|
}
|