using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using StandardScene.Utils; using SimpleCore.Library; namespace StandardScene.ExtendDevice.Door { /// /// Modbus 门控制器实现 /// [DoorType("ModbusDoorController")] public class ModbusDoorController : BasicDoorController { /// /// Modbus TCP 客户端 /// private ModbusRtu _modbusClient; /// /// 同步锁 /// private readonly object _syncLock = new object(); /// /// 是否已启动 /// private bool _isStarted = false; /// /// 最近一次已下发的门控制状态,键为门索引 /// private readonly Dictionary _lastSentControl = new Dictionary(); /// /// 定时读取任务取消令牌 /// private CancellationTokenSource _cancellationTokenSource; /// /// 定时读取任务 /// private Task _readTask; /// /// 读取间隔(毫秒),默认1000ms /// public int ReadInterval { get; set; } = 1000; /// /// 重连间隔(毫秒),默认3000ms /// public int ReconnectInterval { get; set; } = 3000; /// /// 上次重连尝试时间 /// private DateTime _lastReconnectAttempt = DateTime.MinValue; /// /// Modbus 从站地址,默认1 /// public byte SlaveAddress { get; set; } = 1; /// /// 设置门的目标控制状态(线程安全实现) /// 仅修改内存字段,不直接进行通信,实际通信在内部线程中完成 /// /// 门索引 /// true=打开,false=关闭 public override void SetDoorControlTarget(int doorIndex, bool open) { lock (_syncLock) { base.SetDoorControlTarget(doorIndex, open); } } /// /// 连接门控制器 /// public override void Connect() { lock (_syncLock) { if (_isStarted) { return; } try { UpdateState(DoorControllerState.Connecting); // 根据配置的门初始化门状态 var doorIndices = DoorConfigs.Keys.OrderBy(k => k).ToList(); InitializeDoors(doorIndices); // 初始化最近一次已下发的控制状态 _lastSentControl.Clear(); foreach (var index in doorIndices) { _lastSentControl[index] = false; if (!DoorControlTargets.ContainsKey(index)) { DoorControlTargets[index] = false; } } // 尝试连接 Modbus TCP 客户端 try { _modbusClient = new ModbusRtu(); _modbusClient.StartTcpRtu(Ip, Port); UpdateState(DoorControllerState.Online); } catch (Exception connectEx) { UpdateState(DoorControllerState.Connecting); Diagnosis.Log($"ModbusDoorController[{Index}] 初次连接失败,将在后台持续重连: {ExceptionFormatter.FormatEx(connectEx)}", "ModbusDoorController", true); } // 启动定时读取任务 _cancellationTokenSource = new CancellationTokenSource(); _readTask = Task.Run(() => ReadDoorStatesLoop(_cancellationTokenSource.Token)); _isStarted = true; } catch (Exception ex) { UpdateState(DoorControllerState.Error, $"初始化失败: {ex.Message}"); _isStarted = false; Diagnosis.Log($"ModbusDoorController[{Index}] 初始化失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", true); } } } /// /// 断开连接 /// public override void Disconnect() { lock (_syncLock) { if (!_isStarted) { return; } try { // 停止读取任务 _cancellationTokenSource?.Cancel(); _readTask?.Wait(1000); // 关闭 Modbus 连接 _modbusClient?.Close(); _modbusClient = null; _isStarted = false; UpdateState(DoorControllerState.Offline); } catch (Exception ex) { UpdateState(DoorControllerState.Error, $"断开连接失败: {ex.Message}"); Diagnosis.Log($"ModbusDoorController[{Index}] 断开连接失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", true); } } } /// /// 定时读取门状态循环 /// private void ReadDoorStatesLoop(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { try { if (!_isStarted) { break; } // 检查连接状态 bool isConnected = _modbusClient?.modbusRtu?.Connected ?? false; if (_modbusClient == null || !isConnected) { UpdateState(DoorControllerState.Connecting); // 控制重连频率 var timeSinceLastReconnect = (DateTime.Now - _lastReconnectAttempt).TotalMilliseconds; if (timeSinceLastReconnect >= ReconnectInterval) { _lastReconnectAttempt = DateTime.Now; TryReconnect(); } isConnected = _modbusClient?.modbusRtu?.Connected ?? false; if (_modbusClient == null || !isConnected) { Thread.Sleep(ReadInterval); continue; } } // 读取所有门的状态 ReadAllDoorStates(); // 根据目标控制状态下发控制指令 ApplyDoorControlTargets(); // 更新在线状态 UpdateState(DoorControllerState.Online); } catch (Exception ex) { Diagnosis.Log($"ModbusDoorController[{Index}] 读取状态失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", true); UpdateState(DoorControllerState.Error, $"读取状态失败: {ex.Message}"); // 如果连接失败,尝试重连 TryReconnect(); } // 等待指定间隔 Thread.Sleep(ReadInterval); } } /// /// 尝试重连 Modbus TCP 连接 /// private void TryReconnect() { ModbusRtu oldClient = null; try { // 安全关闭旧连接 if (_modbusClient != null) { oldClient = _modbusClient; _modbusClient = null; try { oldClient.Close(); } catch { // 忽略关闭时的异常 } finally { oldClient = null; } } // 创建新连接 _modbusClient = new ModbusRtu(); _modbusClient.StartTcpRtu(Ip, Port); Diagnosis.Log($"ModbusDoorController[{Index}] 重连成功", "ModbusDoorController", false); } catch (Exception ex) { // 重连失败,确保资源释放 if (_modbusClient != null) { try { _modbusClient.Close(); } catch { // 忽略关闭异常 } _modbusClient = null; } Diagnosis.Log($"ModbusDoorController[{Index}] 重连失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", false); } } /// /// 读取所有门的状态 /// private void ReadAllDoorStates() { lock (_syncLock) { foreach (var doorConfig in DoorConfigs.Values) { try { var state = ReadDoorState(doorConfig.Index); UpdateDoorState(doorConfig.Index, state ? DoorState.Open : DoorState.Closed); } catch (Exception ex) { Diagnosis.Log($"ModbusDoorController[{Index}] 读取门{doorConfig.Index}状态失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", true); } } } } /// /// 根据 DoorControlTargets 中的目标状态,下发门控制指令 /// private void ApplyDoorControlTargets() { lock (_syncLock) { foreach (var doorConfig in DoorConfigs.Values) { var doorIndex = doorConfig.Index; // 获取目标控制状态,默认false bool target = false; DoorControlTargets.TryGetValue(doorIndex, out target); // 如果门配置为不允许发送任何控制指令,则跳过(既不打开也不关闭) if (doorConfig.NoControl) { continue; } // 获取上一次已下发的状态 bool last; var hasLast = _lastSentControl.TryGetValue(doorIndex, out last); // 如果没有记录或状态发生变化,则下发控制 if (!hasLast || last != target) { try { WriteDoorControl(doorIndex, target); _lastSentControl[doorIndex] = target; } catch (Exception ex) { Diagnosis.Log($"ModbusDoorController[{Index}] 下发门{doorIndex}控制指令失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", true); } } } } } /// /// 读取门状态(开到位信号) /// /// 门索引 /// true=打开,false=关闭 public override bool ReadDoorState(int doorIndex) { lock (_syncLock) { if (!DoorConfigs.TryGetValue(doorIndex, out var doorConfig)) { throw new ArgumentException($"门{doorIndex}不存在"); } if (_modbusClient == null || !_modbusClient.modbusRtu.Connected) { throw new InvalidOperationException("Modbus连接未建立"); } // 读取开到位信号 var data = _modbusClient.ReadDiscreteInputs_02(SlaveAddress, doorConfig.OpenStatusAddress, 1); return data != null && data.Length > 0 && data[0]; } } /// /// 写入门控制信号(开关控制) /// /// 门索引 /// true=打开,false=关闭 public override void WriteDoorControl(int doorIndex, bool open) { lock (_syncLock) { if (!DoorConfigs.TryGetValue(doorIndex, out var doorConfig)) { throw new ArgumentException($"门{doorIndex}不存在"); } if (_modbusClient == null || !_modbusClient.modbusRtu.Connected) { // 尝试重连 TryReconnect(); if (_modbusClient == null || !_modbusClient.modbusRtu.Connected) { throw new InvalidOperationException("Modbus连接未建立"); } } // 写入开关控制信号(线圈) _modbusClient.WriteMultipleCoils_15(SlaveAddress, doorConfig.ControlAddress, [open]); } } /// /// 析构函数,确保资源释放 /// ~ModbusDoorController() { Disconnect(); } } }