| | |
| | | using HslCommunication; |
| | | using HslCommunication.Core; |
| | | using HslCommunication.LogNet; |
| | | using HslCommunication.Profinet.Omron; |
| | | using HslCommunication.Profinet.Siemens; |
| | | using Newtonsoft.Json; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.ComponentModel; |
| | |
| | | using System.Linq; |
| | | using System.Net; |
| | | using System.Net.NetworkInformation; |
| | | using System.Reflection; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace WIDESEAWCS_Communicator |
| | | { |
| | | /// <summary> |
| | | /// 西门子S7通讯类 |
| | | /// 欧姆龙EtherNet/IP(CIP) |
| | | /// </summary> |
| | | [Description("欧姆龙EtherNet/IP(CIP)")] |
| | | public class OmronEtherNetCommunicator : BaseCommunicator |
| | |
| | | #endregion |
| | | |
| | | #region Private Method |
| | | /// <summary> |
| | | /// 从OperateResult对象中获取读取的数据。 |
| | | /// </summary> |
| | | /// <typeparam name="T">读取的数据类型。</typeparam> |
| | | /// <param name="operateResult">HSLCommunication读取的OperateResult<T>对象</param> |
| | | /// <returns>如果读取成功,返回读取结果,读取失败,抛出自定义通讯异常</returns> |
| | | /// <exception cref="CommunicationException">自定义通讯异常类</exception> |
| | | private object GetContent<T>(OperateResult<T> operateResult, string address) |
| | | { |
| | | try |
| | | { |
| | | if (!operateResult.IsSuccess) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.ReadFailedException, typeof(T).Name, address, operateResult.Message), CommunicationErrorType.ReadFailed); |
| | | } |
| | | return operateResult.Content ?? throw new CommunicationException(string.Format(CommunicationExceptionMessage.ReadDataIsNull, address), CommunicationErrorType.ReadFailed); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogNet.WriteException(Name, ex.Message, ex); |
| | | throw new CommunicationException(ex.Message, CommunicationErrorType.ReadFailed, innerException: ex); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | /// <typeparam name="T"></typeparam> |
| | | /// <param name="operateResult"></param> |
| | | /// <param name="address"></param> |
| | | /// <param name="value"></param> |
| | | /// <returns></returns> |
| | | /// <exception cref="CommunicationException"></exception> |
| | | private bool GetResult<T>(OperateResult operateResult, string address, T value) where T : notnull |
| | | { |
| | | StringBuilder stringBuilder = new StringBuilder(); |
| | | try |
| | | { |
| | | stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteData, address, value)); |
| | | if (!operateResult.IsSuccess) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.WriteFailedException, typeof(T).Name, address, value, operateResult.Message), CommunicationErrorType.WriteFailed); |
| | | } |
| | | else |
| | | { |
| | | object? obj = null; |
| | | for (int i = 0; i < 5; i++) |
| | | { |
| | | T readValue = Read<T>(address); |
| | | stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteAfterRead, readValue, value)); |
| | | obj = readValue; |
| | | if (readValue.Equals(value)) |
| | | { |
| | | stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteAndReadCheckSuccess, address, value, readValue)); |
| | | return true; |
| | | } |
| | | else if (i < 4) |
| | | { |
| | | Write(address, value); |
| | | } |
| | | } |
| | | stringBuilder.AppendLine(string.Format(CommunicationExceptionMessage.WriteAndReadCheckFaild, address, value, obj)); |
| | | throw new CommunicationException(stringBuilder.ToString(), CommunicationErrorType.WriteFailed); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogNet.WriteException(Name, ex.Message, ex); |
| | | throw new CommunicationException(ex.Message, CommunicationErrorType.WriteFailed, innerException: ex); |
| | | } |
| | | finally |
| | | { |
| | | LogNet.WriteInfo(Name, stringBuilder.ToString()); |
| | | } |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 写入数据 |
| | | /// </summary> |
| | | /// <param name="address"></param> |
| | | /// <param name="value"></param> |
| | | /// <returns></returns> |
| | | /// <exception cref="CommunicationException"></exception> |
| | | private OperateResult Write(string address, object value) |
| | | { |
| | | try |
| | | { |
| | | Type type = value.GetType(); |
| | | |
| | | switch (Type.GetTypeCode(type)) |
| | | { |
| | | case TypeCode.Int32: |
| | | return plc.Write(address, Convert.ToInt32(value)); |
| | | case TypeCode.UInt32: |
| | | return plc.Write(address, Convert.ToUInt32(value)); |
| | | case TypeCode.Int16: |
| | | return plc.Write(address, Convert.ToInt16(value)); |
| | | case TypeCode.UInt16: |
| | | return plc.Write(address, Convert.ToUInt16(value)); |
| | | case TypeCode.Single: |
| | | return plc.Write(address, Convert.ToSingle(value)); |
| | | case TypeCode.Boolean: |
| | | return plc.Write(address, Convert.ToBoolean(value)); |
| | | case TypeCode.Byte: |
| | | return plc.Write(address, Convert.ToByte(value)); |
| | | case TypeCode.String: |
| | | return plc.Write(address, Convert.ToString(value)); |
| | | case TypeCode.Char: |
| | | return plc.Write(address, Convert.ToChar(value)); |
| | | default: |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, type.Name, address), CommunicationErrorType.TypeError); |
| | | } |
| | | } |
| | | catch (CommunicationException ex) |
| | | { |
| | | throw new CommunicationException(ex.Message, ex.ErrorType); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | //读取异常时抛出自定义通讯异常类 |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, address, value), CommunicationErrorType.TypeError, innerException: ex); |
| | | } |
| | | } |
| | | |
| | | private object Read(string address, TypeCode typeCode) |
| | | { |
| | | try |
| | | { |
| | | switch (typeCode) |
| | | { |
| | | case TypeCode.Int32: |
| | | return (int)GetContent(plc.ReadInt32(address), address); |
| | | case TypeCode.UInt32: |
| | | return (uint)GetContent(plc.ReadUInt32(address), address); |
| | | case TypeCode.Int16: |
| | | return (short)GetContent(plc.ReadInt16(address), address); |
| | | case TypeCode.UInt16: |
| | | return (ushort)GetContent(plc.ReadUInt16(address), address); |
| | | case TypeCode.Single: |
| | | return (float)GetContent(plc.ReadFloat(address), address); |
| | | case TypeCode.Boolean: |
| | | return (bool)GetContent(plc.ReadBool(address), address); |
| | | case TypeCode.Byte: |
| | | return (byte)GetContent(plc.ReadByte(address), address); |
| | | case TypeCode.String: |
| | | return (string)GetContent(plc.ReadString(address), address); |
| | | case TypeCode.Char: |
| | | return (char)GetContent(plc.ReadByte(address), address); |
| | | default: |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, typeCode.ToString(), address), CommunicationErrorType.TypeError); |
| | | } |
| | | } |
| | | catch (CommunicationException ex) |
| | | { |
| | | //读取异常时抛出自定义通讯异常类 |
| | | throw new CommunicationException(ex.Message, ex.ErrorType); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | //读取异常时抛出自定义通讯异常类 |
| | | throw new CommunicationException($"读取数据异常,错误信息:{ex.Message}", CommunicationErrorType.ReadException, innerException: ex); |
| | | } |
| | | } |
| | | |
| | | private void Ping() |
| | | { |
| | | Task.Run(() => |
| | |
| | | |
| | | public override bool Disconnect() |
| | | { |
| | | throw new NotImplementedException(); |
| | | try |
| | | { |
| | | if (plc != null) |
| | | { |
| | | OperateResult operateResult = plc.ConnectClose();//断开与PLC的连接 |
| | | return operateResult.IsSuccess; |
| | | } |
| | | return false; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return false; |
| | | } |
| | | finally |
| | | { |
| | | _connected = false; |
| | | } |
| | | } |
| | | |
| | | public override void Dispose() |
| | | { |
| | | throw new NotImplementedException(); |
| | | _isPing = false; |
| | | Disconnect(); |
| | | plc.Dispose(); |
| | | GC.SuppressFinalize(this); |
| | | } |
| | | |
| | | public override byte[] Read(string address, int length) |
| | | { |
| | | throw new NotImplementedException(); |
| | | return (byte[])GetContent(plc.Read(address, (ushort)length), address); |
| | | } |
| | | |
| | | public override T Read<T>(string address) |
| | | { |
| | | throw new NotImplementedException(); |
| | | Type type = typeof(T); |
| | | return (T)Read(address, Type.GetTypeCode(type)); |
| | | } |
| | | |
| | | public override object ReadAsObj(string address, string dataType) |
| | | { |
| | | throw new NotImplementedException(); |
| | | return Read(address, SiemensDBDataType.GetTypeCode(dataType)); |
| | | } |
| | | |
| | | public override T ReadCustomer<T>(string address) |
| | | { |
| | | throw new NotImplementedException(); |
| | | try |
| | | { |
| | | return plc.ReadCustomer<T>(address).Content; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogNet.WriteException(Name, $"【{Name}】PLC读取异常,地址:【{address}】,错误信息:【{ex.Message}】", ex); |
| | | throw new CommunicationException(ex.Message, CommunicationErrorType.ReadException, innerException: ex); |
| | | } |
| | | } |
| | | |
| | | public override OperateResult<TimeSpan> Wait<T>(string address, int readInterval, int waitTimeout, T value) |
| | | { |
| | | throw new NotImplementedException(); |
| | | TypeCode typeCode = Type.GetTypeCode(typeof(T)); |
| | | switch (typeCode) |
| | | { |
| | | case TypeCode.Byte: |
| | | DateTime start = DateTime.Now; |
| | | while (true) |
| | | { |
| | | OperateResult<byte> read = plc.ReadByte(address); |
| | | if (!read.IsSuccess) return OperateResult.CreateFailedResult<TimeSpan>(read); |
| | | |
| | | if (read.Content == Convert.ToByte(value)) return OperateResult.CreateSuccessResult(DateTime.Now - start); |
| | | if (waitTimeout > 0 && (DateTime.Now - start).TotalMilliseconds > waitTimeout) |
| | | { |
| | | return new OperateResult<TimeSpan>(StringResources.Language.CheckDataTimeout + waitTimeout); |
| | | } |
| | | HslHelper.ThreadSleep(readInterval); |
| | | } |
| | | case TypeCode.Int16: |
| | | OperateResult<TimeSpan> operateResultShort = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout); |
| | | return operateResultShort; |
| | | case TypeCode.Int32: |
| | | OperateResult<TimeSpan> operateResultInt = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout); |
| | | return operateResultInt; |
| | | case TypeCode.UInt16: |
| | | OperateResult<TimeSpan> operateResultUShort = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout); |
| | | return operateResultUShort; |
| | | case TypeCode.UInt32: |
| | | OperateResult<TimeSpan> operateResultUInt = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout); |
| | | return operateResultUInt; |
| | | default: |
| | | throw new NotSupportedException(); |
| | | } |
| | | } |
| | | |
| | | public override bool Write(string address, byte[] data) |
| | | { |
| | | throw new NotImplementedException(); |
| | | try |
| | | { |
| | | OperateResult result = plc.Write(address, data); |
| | | if (result.IsSuccess) |
| | | { |
| | | return result.IsSuccess; |
| | | } |
| | | else |
| | | { |
| | | //todo 写入失败 |
| | | return false; |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | //写入异常时抛出自定义通讯异常类 |
| | | throw new CommunicationException($"写入数据异常,地址:【{address}】,错误信息: {ex.Message}", CommunicationErrorType.ReadFailed, innerException: ex); |
| | | } |
| | | } |
| | | |
| | | public override bool Write<T>(string address, T value) |
| | | { |
| | | throw new NotImplementedException(); |
| | | return GetResult(Write(address, value), address, value); |
| | | } |
| | | |
| | | public override bool WriteCustomer<T>(string address, [NotNull] T value) |
| | | { |
| | | throw new NotImplementedException(); |
| | | StringBuilder stringBuilder = new StringBuilder(); |
| | | try |
| | | { |
| | | OperateResult operateResult = plc.WriteCustomer(address, value); |
| | | stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteData, address, JsonConvert.SerializeObject(value))); |
| | | if (operateResult.IsSuccess) |
| | | { |
| | | object? obj = null; |
| | | for (int i = 0; i < 5; i++) |
| | | { |
| | | T readValue = ReadCustomer<T>(address); |
| | | stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteAfterRead, address, JsonConvert.SerializeObject(readValue))); |
| | | obj = readValue; |
| | | PropertyInfo[] propertyInfos = typeof(T).GetProperties(); |
| | | for (int j = 0; j < propertyInfos.Length; j++) |
| | | { |
| | | object? writeValueItem = propertyInfos[j].GetValue(value); |
| | | object? readValueItem = propertyInfos[j].GetValue(readValue); |
| | | if (writeValueItem.Equals(readValueItem)) |
| | | { |
| | | stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteAndReadCheckSuccess, address, JsonConvert.SerializeObject(value), JsonConvert.SerializeObject(readValue))); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | if (j == propertyInfos.Length - 1) |
| | | return true; |
| | | } |
| | | |
| | | plc.WriteCustomer(address, value); |
| | | } |
| | | stringBuilder.AppendLine(string.Format(CommunicationExceptionMessage.WriteAndReadCheckFaild, address, JsonConvert.SerializeObject(value), JsonConvert.SerializeObject(obj))); |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.WriteAndReadCheckFaild, address, JsonConvert.SerializeObject(value), JsonConvert.SerializeObject(obj)), CommunicationErrorType.WriteFailed); |
| | | } |
| | | else |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.WriteFailedException, typeof(T).Name, address, JsonConvert.SerializeObject(value), operateResult.Message), CommunicationErrorType.WriteFailed); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogNet.WriteException(Name, ex.Message, ex); |
| | | throw new CommunicationException(ex.Message, CommunicationErrorType.WriteFailed, innerException: ex); |
| | | } |
| | | finally |
| | | { |
| | | LogNet.WriteInfo(Name, stringBuilder.ToString()); |
| | | } |
| | | } |
| | | |
| | | public override bool WriteObj(string address, string dataType, object value) |
| | | { |
| | | throw new NotImplementedException(); |
| | | bool obj = false; |
| | | switch (dataType.ToLower()) |
| | | { |
| | | case SiemensDBDataType.DataType_DInt: |
| | | { |
| | | int writeVal; |
| | | try |
| | | { |
| | | writeVal = Convert.ToInt32(value); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex); |
| | | } |
| | | obj = GetResult(Write(address, writeVal), address, writeVal); |
| | | } |
| | | break; |
| | | case SiemensDBDataType.DataType_DW: |
| | | { |
| | | uint writeVal; |
| | | try |
| | | { |
| | | writeVal = Convert.ToUInt32(value); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex); |
| | | } |
| | | obj = GetResult(Write(address, writeVal), address, writeVal); |
| | | } |
| | | break; |
| | | case SiemensDBDataType.DataType_Int: |
| | | { |
| | | short writeVal; |
| | | try |
| | | { |
| | | writeVal = Convert.ToInt16(value); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex); |
| | | } |
| | | obj = GetResult(Write(address, writeVal), address, writeVal); |
| | | } |
| | | break; |
| | | case SiemensDBDataType.DataType_W: |
| | | { |
| | | ushort writeVal; |
| | | try |
| | | { |
| | | writeVal = Convert.ToUInt16(value); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex); |
| | | } |
| | | obj = GetResult(Write(address, writeVal), address, writeVal); |
| | | } |
| | | break; |
| | | case SiemensDBDataType.DataType_Float: |
| | | { |
| | | float writeVal; |
| | | try |
| | | { |
| | | writeVal = Convert.ToSingle(value); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex); |
| | | } |
| | | obj = GetResult(Write(address, writeVal), address, writeVal); |
| | | } |
| | | break; |
| | | case SiemensDBDataType.DataType_Bool: |
| | | { |
| | | bool writeVal; |
| | | try |
| | | { |
| | | writeVal = Convert.ToBoolean(value); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex); |
| | | } |
| | | obj = GetResult(Write(address, writeVal), address, writeVal); |
| | | } |
| | | break; |
| | | case SiemensDBDataType.DataType_Byte: |
| | | { |
| | | byte writeVal; |
| | | try |
| | | { |
| | | writeVal = Convert.ToByte(value); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex); |
| | | } |
| | | obj = GetResult(Write(address, writeVal), address, writeVal); |
| | | } |
| | | break; |
| | | case SiemensDBDataType.DataType_String: |
| | | { |
| | | string writeVal; |
| | | try |
| | | { |
| | | writeVal = value.ToString(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex); |
| | | } |
| | | obj = GetResult(Write(address, writeVal), address, writeVal); |
| | | } |
| | | |
| | | break; |
| | | case SiemensDBDataType.DataType_Char: |
| | | |
| | | break; |
| | | default: |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, dataType, address), CommunicationErrorType.TypeError); |
| | | } |
| | | return obj; |
| | | } |
| | | #endregion |
| | | |
| | | #region Destruction Function |
| | | /// <summary> |
| | | /// 析构函数,确保在不再需要时关闭连接 |
| | | /// </summary> |
| | | ~OmronEtherNetCommunicator() |
| | | { |
| | | Dispose(); |
| | | } |
| | | #endregion |
| | | } |