279 lines
8.5 KiB
C#
279 lines
8.5 KiB
C#
using System;
|
|||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using SimpleCore.Library;
|
||
|
|
|
||
|
|
namespace StandardScene.ExtendDevice.Door
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 门状态枚举
|
||
|
|
/// </summary>
|
||
|
|
public enum DoorState
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 关闭
|
||
|
|
/// </summary>
|
||
|
|
Closed = 0,
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 打开
|
||
|
|
/// </summary>
|
||
|
|
Open = 1,
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 未知状态
|
||
|
|
/// </summary>
|
||
|
|
Unknown = 2
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 门控制器状态枚举
|
||
|
|
/// </summary>
|
||
|
|
public enum DoorControllerState
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 离线
|
||
|
|
/// </summary>
|
||
|
|
Offline = 0,
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 在线
|
||
|
|
/// </summary>
|
||
|
|
Online = 1,
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 连接中
|
||
|
|
/// </summary>
|
||
|
|
Connecting = 2,
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 错误
|
||
|
|
/// </summary>
|
||
|
|
Error = 3
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 基础门控制器类
|
||
|
|
/// </summary>
|
||
|
|
public abstract class BasicDoorController
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 控制器索引
|
||
|
|
/// </summary>
|
||
|
|
public int Index { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// IP地址
|
||
|
|
/// </summary>
|
||
|
|
public string Ip { get; set; } = string.Empty;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 端口
|
||
|
|
/// </summary>
|
||
|
|
public int Port { get; set; } = 502;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 控制器状态
|
||
|
|
/// </summary>
|
||
|
|
public DoorControllerState State { get; protected set; } = DoorControllerState.Offline;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 是否在线
|
||
|
|
/// </summary>
|
||
|
|
public bool IsOnline => State == DoorControllerState.Online;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 门状态字典,键为门索引
|
||
|
|
/// </summary>
|
||
|
|
public Dictionary<int, DoorState> DoorStates { get; protected set; } = new Dictionary<int, DoorState>();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 门目标控制字典,键为门索引,值为期望的开关状态(true=打开,false=关闭)
|
||
|
|
/// 仅作为指令缓存,实际通信由具体门控制器内部线程完成
|
||
|
|
/// </summary>
|
||
|
|
public Dictionary<int, bool> DoorControlTargets { get; protected set; } = new Dictionary<int, bool>();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 门配置信息字典,键为门索引
|
||
|
|
/// </summary>
|
||
|
|
public Dictionary<int, DoorModel> DoorConfigs { get; protected set; } = new Dictionary<int, DoorModel>();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 最后更新时间
|
||
|
|
/// </summary>
|
||
|
|
public DateTime LastUpdateTime { get; protected set; } = DateTime.Now;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 错误信息
|
||
|
|
/// </summary>
|
||
|
|
public string ErrorMessage { get; protected set; } = string.Empty;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 更新控制器状态
|
||
|
|
/// </summary>
|
||
|
|
public virtual void UpdateState(DoorControllerState newState, string errorMessage = "")
|
||
|
|
{
|
||
|
|
State = newState;
|
||
|
|
ErrorMessage = errorMessage;
|
||
|
|
LastUpdateTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 更新门状态
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="doorIndex">门索引</param>
|
||
|
|
/// <param name="state">门状态</param>
|
||
|
|
public virtual void UpdateDoorState(int doorIndex, DoorState state)
|
||
|
|
{
|
||
|
|
if (!DoorStates.ContainsKey(doorIndex))
|
||
|
|
{
|
||
|
|
Diagnosis.Post($"门控制器{Index}不存在门{doorIndex}");
|
||
|
|
}
|
||
|
|
DoorStates[doorIndex] = state;
|
||
|
|
LastUpdateTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取门状态
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="doorIndex">门索引</param>
|
||
|
|
/// <returns>门状态,如果不存在则返回Unknown</returns>
|
||
|
|
public virtual DoorState GetDoorState(int doorIndex)
|
||
|
|
{
|
||
|
|
return DoorStates.TryGetValue(doorIndex, out var state) ? state : DoorState.Unknown;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 初始化门状态
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="doorIndices">门索引列表</param>
|
||
|
|
public virtual void InitializeDoors(List<int> doorIndices)
|
||
|
|
{
|
||
|
|
DoorStates.Clear();
|
||
|
|
DoorControlTargets.Clear();
|
||
|
|
foreach (var index in doorIndices)
|
||
|
|
{
|
||
|
|
DoorStates[index] = DoorState.Closed;
|
||
|
|
DoorControlTargets[index] = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 初始化门配置信息
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="doorConfigs">门配置列表</param>
|
||
|
|
public virtual void InitializeDoorConfigs(List<DoorModel> doorConfigs)
|
||
|
|
{
|
||
|
|
DoorConfigs.Clear();
|
||
|
|
if (doorConfigs != null)
|
||
|
|
{
|
||
|
|
foreach (var config in doorConfigs)
|
||
|
|
{
|
||
|
|
DoorConfigs[config.Index] = new DoorModel
|
||
|
|
{
|
||
|
|
Index = config.Index,
|
||
|
|
ControlAddress = config.ControlAddress,
|
||
|
|
OpenStatusAddress = config.OpenStatusAddress,
|
||
|
|
NoControl = config.NoControl
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 更新门配置信息
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="doorConfigs">门配置列表</param>
|
||
|
|
public virtual void UpdateDoorConfigs(List<DoorModel> doorConfigs)
|
||
|
|
{
|
||
|
|
if (doorConfigs == null)
|
||
|
|
{
|
||
|
|
DoorConfigs.Clear();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建配置字典
|
||
|
|
var configDict = doorConfigs.ToDictionary(d => d.Index);
|
||
|
|
|
||
|
|
// 删除配置中不存在的门
|
||
|
|
var toRemove = DoorConfigs.Keys.Where(k => !configDict.ContainsKey(k)).ToList();
|
||
|
|
foreach (var key in toRemove)
|
||
|
|
{
|
||
|
|
DoorConfigs.Remove(key);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 添加或更新门配置
|
||
|
|
foreach (var config in doorConfigs)
|
||
|
|
{
|
||
|
|
DoorConfigs[config.Index] = new DoorModel
|
||
|
|
{
|
||
|
|
Index = config.Index,
|
||
|
|
ControlAddress = config.ControlAddress,
|
||
|
|
OpenStatusAddress = config.OpenStatusAddress,
|
||
|
|
NoControl = config.NoControl
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取门配置信息
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="doorIndex">门索引</param>
|
||
|
|
/// <returns>门配置信息,如果不存在则返回null</returns>
|
||
|
|
public virtual DoorModel GetDoorConfig(int doorIndex)
|
||
|
|
{
|
||
|
|
return DoorConfigs.TryGetValue(doorIndex, out var config) ? config : null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 设置门的目标控制状态(仅修改内存字段,不直接进行通信)
|
||
|
|
/// 实际的通信写入由具体门控制器在内部线程中根据该目标状态执行
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="doorIndex">门索引</param>
|
||
|
|
/// <param name="open">true=打开,false=关闭</param>
|
||
|
|
public virtual void SetDoorControlTarget(int doorIndex, bool open)
|
||
|
|
{
|
||
|
|
// 统一支持 NoControl:当门被配置为不允许发送任何控制指令时,
|
||
|
|
// 强制将目标置为 false,并避免为其它控制器留下“需要开门”的目标。
|
||
|
|
if (DoorConfigs.TryGetValue(doorIndex, out var cfg) && cfg != null && cfg.NoControl)
|
||
|
|
{
|
||
|
|
DoorControlTargets[doorIndex] = false;
|
||
|
|
LastUpdateTime = DateTime.Now;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
DoorControlTargets[doorIndex] = open;
|
||
|
|
LastUpdateTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 连接门控制器
|
||
|
|
/// </summary>
|
||
|
|
public virtual void Connect()
|
||
|
|
{
|
||
|
|
UpdateState(DoorControllerState.Connecting);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 断开连接
|
||
|
|
/// </summary>
|
||
|
|
public virtual void Disconnect()
|
||
|
|
{
|
||
|
|
UpdateState(DoorControllerState.Offline);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 读取门状态(开到位信号)
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="doorIndex">门索引</param>
|
||
|
|
/// <returns>门状态</returns>
|
||
|
|
public abstract bool ReadDoorState(int doorIndex);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入门控制信号(开关控制)
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="doorIndex">门索引</param>
|
||
|
|
/// <param name="open">true=打开,false=关闭</param>
|
||
|
|
public abstract void WriteDoorControl(int doorIndex, bool open);
|
||
|
|
}
|
||
|
|
}
|