2026-01-06 08:49:12 +08:00
|
|
|
|
using Infrastructure.Helper;
|
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2026-01-08 10:57:12 +08:00
|
|
|
|
using System.Linq;
|
2026-01-06 08:49:12 +08:00
|
|
|
|
using System.Threading;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
|
|
namespace ZR.Service.Utils.MyAlarmLigth
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 调漆房IO端口监听+灯控类(X1-X8监听 → 触发对应灯控方法)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class TiaoQiFangLight : IDisposable
|
|
|
|
|
|
{
|
|
|
|
|
|
// 核心配置(仅保留必要参数,对齐测试代码风格)
|
|
|
|
|
|
private const byte MODBUS_SLAVE_ID = 0x01;
|
|
|
|
|
|
private const ushort DI_START_ADDR = 0x0000;
|
|
|
|
|
|
private const int POLLING_INTERVAL_MS = 200;
|
|
|
|
|
|
private const int DI_COUNT = 8;
|
|
|
|
|
|
|
|
|
|
|
|
// 依赖注入(仅保留核心依赖)
|
2026-01-08 10:57:12 +08:00
|
|
|
|
private readonly AlarmLightModbus _modbusClient;
|
2026-01-06 08:49:12 +08:00
|
|
|
|
private readonly ILogger<TiaoQiFangLight> _logger;
|
|
|
|
|
|
|
|
|
|
|
|
// 状态缓存+监听控制(精简命名)
|
|
|
|
|
|
private readonly bool[] _lastDiState = new bool[DI_COUNT];
|
|
|
|
|
|
private CancellationTokenSource _cts;
|
|
|
|
|
|
private Task _listenTask;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构造函数(精简参数,日志可选)
|
|
|
|
|
|
/// </summary>
|
2026-01-08 10:57:12 +08:00
|
|
|
|
public TiaoQiFangLight(AlarmLightModbus modbusClient, ILogger<TiaoQiFangLight> logger = null)
|
2026-01-06 08:49:12 +08:00
|
|
|
|
{
|
|
|
|
|
|
_modbusClient = modbusClient;
|
|
|
|
|
|
_logger = logger;
|
|
|
|
|
|
Array.Fill(_lastDiState, false); // 初始化未按下
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 启动监听(精简逻辑,无冗余判断)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void StartListen()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_listenTask?.IsCompleted == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger?.LogWarning("调漆房IO监听已启动,无需重复执行");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_cts = new CancellationTokenSource();
|
|
|
|
|
|
_listenTask = Task.Run(() => ListenDiLoop(_cts.Token), _cts.Token);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 停止监听(精简释放逻辑)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void StopListen()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_cts == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
_cts.Cancel();
|
|
|
|
|
|
_listenTask?.Wait(1000);
|
|
|
|
|
|
_logger?.LogInformation("❌ 停止X1-X8监听");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 核心:轮询监听DI状态(精简循环逻辑,对齐测试代码异常处理)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private async Task ListenDiLoop(CancellationToken cancellationToken)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (!cancellationToken.IsCancellationRequested)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-01-08 10:57:12 +08:00
|
|
|
|
// ====== 关键修改:用ReadDiscreteInputs读取DI端口 ======
|
|
|
|
|
|
List<bool> diStates = _modbusClient.ReadDiscreteInputs(
|
|
|
|
|
|
MODBUS_SLAVE_ID,
|
|
|
|
|
|
DI_START_ADDR,
|
|
|
|
|
|
(ushort)DI_COUNT // 转为ushort匹配方法参数
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 结果校验
|
|
|
|
|
|
if (diStates == null || diStates.Count != DI_COUNT)
|
2026-01-06 08:49:12 +08:00
|
|
|
|
{
|
|
|
|
|
|
await Task.Delay(POLLING_INTERVAL_MS, cancellationToken);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < DI_COUNT; i++)
|
|
|
|
|
|
{
|
2026-01-08 10:57:12 +08:00
|
|
|
|
bool isPressed = diStates[i]; // true=按下,false=未按下
|
2026-01-06 08:49:12 +08:00
|
|
|
|
string portName = $"X{i + 1}";
|
|
|
|
|
|
|
2026-01-08 10:57:12 +08:00
|
|
|
|
// 仅“从未按下→按下”时触发
|
2026-01-06 08:49:12 +08:00
|
|
|
|
if (isPressed && !_lastDiState[i])
|
|
|
|
|
|
{
|
2026-01-08 10:57:12 +08:00
|
|
|
|
TriggerLightMethod(i + 1);
|
2026-01-06 08:49:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
_lastDiState[i] = isPressed; // 更新缓存
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-08 10:57:12 +08:00
|
|
|
|
catch (OperationCanceledException)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger?.LogInformation("监听循环被取消,正常退出");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2026-01-06 08:49:12 +08:00
|
|
|
|
catch (Exception cmdEx)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await Task.Delay(POLLING_INTERVAL_MS, cancellationToken);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 触发灯控方法(精简逻辑,仅保留核心映射)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void TriggerLightMethod(int portNumber)
|
|
|
|
|
|
{
|
|
|
|
|
|
byte lightUnitId = 0x01; // 警灯站号(可按需替换为ReadAlarmlightNumber)
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (portNumber)
|
|
|
|
|
|
{
|
|
|
|
|
|
// X1-X4 → 红灯
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
_logger?.LogInformation($"✅ X{portNumber}触发:红灯闪烁");
|
2026-01-08 10:57:12 +08:00
|
|
|
|
_modbusClient.WriteSingleCoil(lightUnitId, 0, true); //0-Y1地址
|
2026-01-06 08:49:12 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
_logger?.LogInformation($"✅ X{portNumber}触发:红灯闪烁");
|
2026-01-08 10:57:12 +08:00
|
|
|
|
_modbusClient.WriteSingleCoil(lightUnitId, 1, false);
|
2026-01-06 08:49:12 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
_logger?.LogInformation($"✅ X{portNumber}触发:红灯闪烁");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 4:
|
|
|
|
|
|
_logger?.LogInformation($"✅ X{portNumber}触发:红灯闪烁");
|
|
|
|
|
|
break;
|
|
|
|
|
|
// X5 → 绿灯
|
|
|
|
|
|
case 5:
|
|
|
|
|
|
_logger?.LogInformation($"✅ X{portNumber}触发:绿灯常亮");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger?.LogError(ex, $"❌ X{portNumber}触发灯控方法失败");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 释放资源(精简Dispose)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
|
{
|
|
|
|
|
|
StopListen();
|
|
|
|
|
|
_cts?.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|