Files
DP44/DataPRO/DASFactory/DASFactory.AutoDiscovery.cs
2026-04-17 14:55:32 -04:00

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;
}
}
}