using HslCommunication; using System.ComponentModel; using System.Reflection; using WIDESEAWCS_Communicator; using WIDESEAWCS_QuartzJob.DeviceBase; using WIDESEAWCS_QuartzJob.DTO; using WIDESEAWCS_QuartzJob.StackerCrane; using WIDESEAWCS_QuartzJob.StackerCrane.Enum; using WIDESEAWCS_QuartzJob.StackerCrane.Common; namespace WIDESEAWCS_QuartzJob { /// /// 自定义堆垛机 /// [Description("高常温堆垛机")] public class SpeTemperatureStackerCrane : StackerCraneBase, IStackerCrane { #region Private Member /// /// 堆垛机通讯对象 /// private BaseCommunicator _communicator; /// /// 堆垛机协议信息 /// private readonly List _deviceProDTOs; /// /// 堆垛机协议明细信息 /// private readonly List _deviceProtocolDetailDTOs; /// /// 设备编号 /// public readonly string _deviceCode; /// /// 设备名称 /// public readonly string _deviceName; /// /// 上一次任务号 /// private int _lastTaskNum; private bool _isChecked = false; private bool _heartStart = true; private bool _isConnected = true; #endregion Private Member #region Public Member /// /// 通讯对象 /// public BaseCommunicator Communicator => _communicator; /// /// 通讯协议信息 /// public List DeviceProDTOs => _deviceProDTOs; /// /// 通讯协议明细信息 /// public List DeviceProtocolDetailDTOs => _deviceProtocolDetailDTOs; /// /// 堆垛机状态 /// public TemperatureStackerCraneStatus StackerCraneStatusValue => GetStackerCraneStatus(); /// /// 堆垛机状态中文说明 /// public string StackerCraneStatusDes => GetEnumDes(StackerCraneStatusValue); /// /// 手自动状态 /// public TemperatureStackerCraneAutoStatus StackerCraneAutoStatusValue => GetStackerCraneAutoStatus(); /// /// 作业状态 /// public TemperatureStackerCraneWorkStatus StackerCraneWorkStatusValue => GetStackerCraneWorkStatus(); /// /// 作业状态中文说明 /// public string StackerCraneWorkStatusDes => GetEnumDes(StackerCraneWorkStatusValue); /// /// 上一次执行的任务号 /// public int LastTaskNum => _lastTaskNum; /// /// 当前正在执行的任务号 /// public int CurrentTaskNum => GetCurrentTaskNum(); /// /// 上一次执行的任务类型 /// public int? LastTaskType { get; set; } = null; /// /// 设备编号 /// public string DeviceCode => _deviceCode; /// /// 设备名称 /// public string DeviceName => _deviceName; /// /// 设备是否已连接 /// public bool IsConnected => Communicator.IsConnected && _isConnected; /// /// 堆垛机任务命令 /// public object StackerCraneTaskCommand { get; set; } /// /// 堆垛机完成事件是否已订阅 /// public bool IsEventSubscribed => StackerCraneTaskCompletedEventHandler != null; /// /// 堆垛机任务完成事件 /// public event EventHandler StackerCraneTaskCompletedEventHandler; #endregion Public Member #region Constructor Function /// /// 构造函数 /// /// 堆垛机通讯对象 /// 堆垛机协议信息 /// 堆垛机协议明细信息 /// 设备编号 /// 设备名称 public SpeTemperatureStackerCrane(BaseCommunicator communicator, List deviceProDTOs, List deviceProtocolDetailDTOs, string deviceCode, string deviceName) { _communicator = communicator; _deviceProDTOs = deviceProDTOs; _deviceProtocolDetailDTOs = deviceProtocolDetailDTOs; _deviceCode = deviceCode; _deviceName = deviceName; CheckConnect(); } #endregion Constructor Function #region Private Method private object GetStatus(string protocolParamType) { if (!Communicator.IsConnected) { return StackerCraneStatus.Unkonw.ToString(); } List devicePros = _deviceProDTOs.Where(x => x.DeviceProParamType == protocolParamType).ToList(); if (devicePros.Count == 0) { throw new Exception($"未获取到协议信息,协议参数类型:{protocolParamType}"); } foreach (var devicePro in devicePros) { object readStatus = Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType); DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault( x => x.DeviceProParamName == devicePro.DeviceProParamType && x.ProtocalDetailValue.Equals(readStatus.ToString())); if (deviceProtocolDetail != null) { return Convert.ToInt32(readStatus); } } return StackerCraneStatus.Unkonw.ToString(); } /// /// 获取堆垛机设备状态 /// /// private TemperatureStackerCraneStatus GetStackerCraneStatus() { return (TemperatureStackerCraneStatus)GetStatus(nameof(TemperatureStackerCraneStatus)); } /// /// 获取堆垛机手自动状态 /// /// private TemperatureStackerCraneAutoStatus GetStackerCraneAutoStatus() { return (TemperatureStackerCraneAutoStatus)GetStatus(nameof(TemperatureStackerCraneWorkStatus)); } /// /// 获取堆垛机工作状态 /// /// private TemperatureStackerCraneWorkStatus GetStackerCraneWorkStatus() { return (TemperatureStackerCraneWorkStatus)GetStatus(nameof(TemperatureStackerCraneWorkStatus)); } /// /// 获取枚举说明 /// /// 枚举泛型 /// /// private string GetEnumDes(T value) where T : Enum { FieldInfo? fieldInfo = typeof(T).GetField(value.ToString()); if (fieldInfo != null) { DescriptionAttribute? descriptionAttribute = fieldInfo.GetCustomAttribute(); if (descriptionAttribute != null) { return descriptionAttribute.Description; } return "未定义"; } return "未知"; } private int GetCurrentTaskNum() { DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(CurrentTaskNum)); return devicePro == null ? throw new Exception($"读取当前任务号错误,未获取到协议信息,请检查配置参数名称是否配置,且配置为{nameof(CurrentTaskNum)}") : (int)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType); } private void CheckConnect() { Task.Run(() => { while (_heartStart) { try { DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(); if (devicePro == null) { _isConnected = false; } else { Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType); _isConnected = true; } } catch (Exception ex) { _isConnected = false; } Thread.Sleep(500); } }); } #endregion Private Method #region Public Method /// /// 获取堆垛机状态 /// public T GetStackerCraneStatus() where T : notnull, Enum { return (T)GetStatus(typeof(T).Name); } /// /// 释放对象 /// public void Dispose() { _heartStart = false; _communicator.Dispose(); GC.SuppressFinalize(this); } /// /// 根据参数名称读取堆垛机对应的数据。 /// /// 参数名称枚举类型。 /// 读取结果的返回值类型。 /// 参数名称。 /// 返回读取到的数据。 /// public TResult GetValue(TEnum value) where TEnum : Enum { if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络"); DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString()); return devicePro == null ? throw new Exception($"读取数据错误,未在协议信息里面找到参数{value.ToString()}") : (TResult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType); } /// /// 心跳 /// public void Heartbeat() { } /// /// 发送任务命令 /// /// 任务命令 /// public bool SendCommand(T command) where T : IDataTransfer, new() { if (Communicator is SiemensS7) { if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络"); DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == nameof(DeviceCommand)).OrderBy(x => x.DeviceProOffset).FirstOrDefault(); if (devicePro == null) { return false; } if (Communicator.WriteCustomer(devicePro.DeviceProAddress, command)) { StackerCraneTaskCommand = command; //CheckStackerCraneTaskCompleted(); return true; } return false; } else { throw new Exception("暂不支持除西门子之外的PLC"); } } /// /// 监测堆垛机任务是否完成(防止任务完成事件监测超时,定义手动触发功能) /// public void CheckStackerCraneTaskCompleted() { if (_isChecked) return; Task.Run(() => { _isChecked = true; try { DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(FormationStackerCraneTaskCompletionStatus)); if (devicePro == null) return; DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault( x => x.DeviceProParamName == devicePro.DeviceProParamName && x.ProtocolDetailType == FormationStackerCraneTaskCompletionStatus.NormalCompleted.ToString()); if (deviceProtocolDetail == null) return; OperateResult operateResult = WaitForCompletion(devicePro, deviceProtocolDetail); if (operateResult.IsSuccess) { int taskNum = CurrentTaskNum; StackerCraneTaskCompletedEventArgs args = new(taskNum); StackerCraneTaskCompletedEventHandler?.Invoke(this, args); _lastTaskNum = taskNum; } } catch (Exception ex) { // TODO: 添加日志记录 } finally { _isChecked = false; } }); } /// /// 等待任务完成信号 /// private OperateResult WaitForCompletion(DeviceProDTO devicePro, DeviceProtocolDetailDTO deviceProtocolDetail) { TypeCode typeCode = SiemensDBDataType.GetTypeCode(devicePro.DeviceDataType); return typeCode switch { TypeCode.Boolean => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000, Convert.ToBoolean(deviceProtocolDetail.ProtocalDetailValue)), TypeCode.Byte => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000, Convert.ToByte(deviceProtocolDetail.ProtocalDetailValue)), TypeCode.Int16 => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000, Convert.ToInt16(deviceProtocolDetail.ProtocalDetailValue)), TypeCode.Int32 => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000, Convert.ToInt32(deviceProtocolDetail.ProtocalDetailValue)), TypeCode.UInt16 => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000, Convert.ToUInt16(deviceProtocolDetail.ProtocalDetailValue)), TypeCode.UInt32 => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000, Convert.ToUInt32(deviceProtocolDetail.ProtocalDetailValue)), _ => new OperateResult() }; } /// /// 根据参数名称写入堆垛机对应的数据。 /// /// 参数名称枚举类型。 /// 要写入的数据类型。 /// 参数名称。 /// 要写入的数据。 /// 返回写入成功或失败 /// public bool SetValue(TEnum @enum, TValue value) where TEnum : Enum where TValue : notnull { if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络"); DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString()); return devicePro == null ? throw new Exception($"写入数据错误,未在协议信息里面找到参数{value.ToString()}") : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value); } #endregion Public Method } }