SiemensS7Communication.cs 6.2 KB
using HHECS.BllModel;
using HHECS.EquipmentModel;
using HslCommunication;
using HslCommunication.Core.Address;
using HslCommunication.Profinet.Siemens;
using System.Text;

namespace HHECS.DAQClient.Communications
{
    /// <summary>
    /// 西门子通信
    /// </summary>
    public class SiemensS7Communication : ICommunication
    {
        public readonly SiemensS7Net Siemens = null!;

        public string IpAddress => Siemens.IpAddress;

        public int CommunicationId { get; set; }

        private SiemensS7Communication() { }

        public SiemensS7Communication(int communicationId, SiemensPLCS siemens, string ipAddress)
        {
            CommunicationId = communicationId;
            Siemens = new SiemensS7Net(siemens, ipAddress);
            Siemens.SetPersistentConnection();
        }

        public BllResult ConnectServer()
        {
            var result = Siemens.ConnectServer();
            if (!result.IsSuccess)
            {
                return BllResultFactory.Error(result.Message);
            }
            return BllResultFactory.Success();
        }

        public BllResult ConnectClose()
        {
            Siemens.ConnectClose();
            return BllResultFactory.Success();
        }

        public BllResult Read(IEnumerable<DataItem> dataItems)
        {
            try
            {
                var addressDatas = new List<S7AddressData>();
                foreach (var item in dataItems)
                {
                    ushort byteLength = GetByteLength(item);
                    var i = item.DataAddress.IndexOf(',');
                    var address = i > 0 ? item.DataAddress[..i] : item.DataAddress;
                    var parseResult = S7AddressData.ParseFrom(address, byteLength);
                    if (!parseResult.IsSuccess)
                    {
                        return BllResultFactory.Error(parseResult.Message);
                    }
                    addressDatas.Add(parseResult.Content);
                }
                var result = Siemens.Read(addressDatas.ToArray());
                if (!result.IsSuccess)
                {
                    return BllResultFactory.Error(result.Message);
                }
                var buffer = result.Content;
                var byteIndex = 0;
                foreach (var item in dataItems)
                {
                    _ = ushort.TryParse(item.DataAddress.Split('.').LastOrDefault(), out var bitIndex);
                    item.Value = item.DataType switch
                    {
                        EquipmentDataType.BYTE => Siemens.ByteTransform.TransByte(buffer, byteIndex).ToString(),
                        EquipmentDataType.BOOL => Convert.ToBoolean(buffer[byteIndex] & 1 << bitIndex).ToString(),
                        EquipmentDataType.DINT => Siemens.ByteTransform.TransInt32(buffer, byteIndex).ToString(),
                        EquipmentDataType.DWORD => Siemens.ByteTransform.TransUInt32(buffer, byteIndex).ToString(),
                        EquipmentDataType.WORD => Siemens.ByteTransform.TransUInt16(buffer, byteIndex).ToString(),
                        EquipmentDataType.INT => Siemens.ByteTransform.TransInt16(buffer, byteIndex).ToString(),
                        EquipmentDataType.CHAR => Siemens.ByteTransform.TransString(buffer, byteIndex, item.Length, Encoding.ASCII).Replace("\u0003", "").Trim(),
                        EquipmentDataType.REAL => Siemens.ByteTransform.TransSingle(buffer, byteIndex).ToString(),
                        _ => string.Empty,
                    };
                    byteIndex += GetByteLength(item);
                }
                return BllResultFactory.Success();
            }
            catch (Exception ex)
            {
                return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]数据出现异常:{ex.Message}");
            }
        }

        public BllResult Read(DataItem dataItem)
        {
            return Read([dataItem]);
        }

        public BllResult Write(IEnumerable<DataItem> dataItems)
        {
            try
            {
                var result = new OperateResult();
                foreach (var item in dataItems)
                {
                    if (item.DataType == EquipmentDataType.BOOL)
                    {
                        _ = bool.TryParse(item.Value, out bool val);
                        result = Siemens.Write(item.DataAddress, val);
                    }
                    else if (item.DataType == EquipmentDataType.INT)
                    {
                        _ = ushort.TryParse(item.Value, out ushort val);
                        result = Siemens.Write(item.DataAddress, val);
                    }
                    else if (item.DataType == EquipmentDataType.REAL)
                    {
                        _ = float.TryParse(item.Value, out var val);
                        result = Siemens.Write(item.DataAddress, val);
                    }
                    else
                    {
                        var bytes = Encoding.Default.GetBytes(item.Value ?? string.Empty);
                        result = Siemens.Write(item.DataAddress, bytes);
                    }
                    if (!result.IsSuccess)
                    {
                        return BllResultFactory.Error($"写入PLC[{Siemens.IpAddress}]_{item.DataAddress}地址数据失败:{result.Message}");
                    }
                }
                return BllResultFactory.Success();
            }
            catch (Exception ex)
            {
                return BllResultFactory.Error($"写入PLC[{Siemens.IpAddress}]数据出现异常:{ex.Message}");
            }
        }

        public BllResult Write(DataItem dataItem)
        {
            return Write([dataItem]);
        }

        private static ushort GetByteLength(DataItem data) => data.DataType switch
        {
            EquipmentDataType.BOOL => 1,
            EquipmentDataType.WORD => 2,//UInt16
            EquipmentDataType.DWORD => 4,//UInt32
            EquipmentDataType.INT => 2,//Int16
            EquipmentDataType.DINT => 4,//Int32
            EquipmentDataType.CHAR or
            EquipmentDataType.BYTE => data.Length,
            EquipmentDataType.REAL => 4,//Float
            _ => data.Length
        };
    }
}