using Cowain.Base.Helpers;
using Plugin.Cowain.Driver.ViewModels;
using Microsoft.Extensions.DependencyInjection;
using Plugin.Cowain.Driver.Abstractions;
using Plugin.Cowain.Driver.IServices;
using Microsoft.Extensions.Logging;
namespace Plugin.Cowain.Driver;
///
/// 设备数据采集,不注入到容器,一个设备一个线程
///
public class DeviceThread
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); // 初始化计数为1,最大计数也为1,实现互斥
private Task? _mainTask;
private Task? _consumeVariablesTask;
private readonly IDriver _driver;
private readonly DeviceViewModel _device;
private readonly IActionPluginService _actionPluginService;
private IServiceProvider _serviceProvider;
private IVariableChannelService? _variableChannelService;
private readonly ILogger _logger;
public DeviceViewModel Device { get => _device; }
public IDriver Driver { get => _driver; }
public DeviceThread(IDriver driver, IActionPluginService actionPluginService, IServiceProvider serviceProvider, DeviceViewModel device)
{
_serviceProvider = serviceProvider;
_driver = driver;
_actionPluginService = actionPluginService;
_device = device;
_variableChannelService = _serviceProvider.GetService();
_logger = ServiceLocator.GetRequiredService>();
}
public async Task StartReadAsync(CancellationToken cancellationToken)
{
if (!_device.Enable)
{
return;
}
_logger.LogInformation($"DeviceThread线程自动启动:{_device.DeviceName}");
await _semaphore.WaitAsync(cancellationToken);
_variableChannelService?.RegisterDeviceActions(_device);
//消费变量,但不等待结果
_consumeVariablesTask = _variableChannelService?.ConsumeVariablesAsync();
_mainTask = Task.Factory.StartNew(async () =>
{
_driver.SetParam(_device.Param);
_driver.SetDeviceModel(_device);
var connect = await _driver.OpenAsync();
if (!connect)
{
//建立过链接后就不用再连接了
_logger.LogInformation($"DeviceThread设备连接失败:{_device.DeviceName}");
}
await _driver.ReadThreadAsync(_device, cancellationToken);
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap();
//释放信号量,允许其他线程进入
_semaphore.Release();
}
public async Task StopReadAsync(CancellationToken cancellationToken)
{
_logger.LogInformation($"DeviceThread线程停止开始:{_device.DeviceName}");
_variableChannelService?.StopConsumeVariablesAsync(cancellationToken);
try
{
// 等待消费变量任务完成
_logger.LogInformation($"DeviceThread 消费变量任务判断:{_device.DeviceName}");
if (_consumeVariablesTask != null && !_consumeVariablesTask.IsCompleted)
{
_logger.LogInformation($"DeviceThread 消费变量任务await:{_device.DeviceName}");
await Task.WhenAny(_consumeVariablesTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
// 等待主任务完成
_logger.LogInformation($"DeviceThread 主任务判断:{_device.DeviceName}");
if (_mainTask != null && !_mainTask.IsCompleted)
{
_logger.LogInformation($"DeviceThread 主任务await:{_device.DeviceName}");
await Task.WhenAny(_mainTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
}
catch (OperationCanceledException ex)
{
_logger.LogInformation($"DeviceThread-StopReadAsync任务取消:{_device.DeviceName}->{ex.Message}");
}
catch (Exception ex)
{
_logger.LogError(ex, $"DeviceThread-StopReadAsync任务异常:{_device.DeviceName}");
}
finally
{
// 确保资源释放
_driver.Close();
_logger.LogInformation($"DeviceThread线程停止完成:{_device.DeviceName}");
}
}
}