SiemensS7Communication.cs 13 KB
using HHECS.BllModel;
using HHECS.EquipmentModel;
using HslCommunication;
using HslCommunication.Core;
using HslCommunication.Profinet.Siemens;
using System.Text;
using System.Text.RegularExpressions;

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

        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
            {
                //DB地址批量读取
                if (dataItems.All(x => x.DataAddress.StartsWith("DB", StringComparison.OrdinalIgnoreCase)))
                {
                    var regex = new Regex("[0-9]+");
                    var separatingChars = new char[] { '.', ',' };
                    foreach (var item in dataItems.GroupBy(x => x.DataAddress.Split(separatingChars).First()))
                    {
                        var amountItems = item.Select(x => Convert.ToInt32(regex.Match(x.DataAddress.Split(separatingChars)[1]).Value));
                        var amountStart = amountItems.Min();
                        var amountEnd = amountItems.Max();

                        var lastItem = item.MaxBy(x => Convert.ToInt32(regex.Match(x.DataAddress.Split(separatingChars)[1]).Value));
                        //最后一个地址占用的Byte数量,Word类型需要加2,Real需要加4
                        var lastByteAmount = lastItem.DataType switch
                        {
                            EquipmentDataType.BOOL => 1,
                            EquipmentDataType.WORD => 2,//Int16
                            EquipmentDataType.DWORD => 4,//UInt16
                            EquipmentDataType.INT => 2,//Int32
                            EquipmentDataType.DINT => 4,//UInt32
                            EquipmentDataType.CHAR => lastItem.Length,
                            EquipmentDataType.REAL => 4,//Float
                            _ => 1
                        };

                        var amount = (ushort)(amountEnd - amountStart + lastByteAmount);
                        var multiReadResult = Siemens.Read($"{item.Key}.{amountStart}", amount);
                        if (!multiReadResult.IsSuccess)
                        {
                            throw new Exception(multiReadResult.Message);
                        }

                        //根据数据类型按byte转换,不同数据类型字节数不同
                        foreach (var prop in item)
                        {
                            _ = int.TryParse(regex.Match(prop.DataAddress.Split(separatingChars)[1]).Value, out int currentAmountEnd);
                            _ = int.TryParse(regex.Match(prop.DataAddress.Split(separatingChars).Skip(2).FirstOrDefault() ?? "0").Value, out int bitIndex);
                            var index = currentAmountEnd - amountStart;
                            prop.Value = prop.DataType switch
                            {
                                EquipmentDataType.BYTE => reverseBytesTransform.TransInt32(multiReadResult.Content, index).ToString(),
                                EquipmentDataType.BOOL => Convert.ToBoolean(multiReadResult.Content[index] & 1 << bitIndex).ToString(),
                                EquipmentDataType.DINT => reverseBytesTransform.TransInt32(multiReadResult.Content, index).ToString(),
                                EquipmentDataType.DWORD => reverseBytesTransform.TransUInt32(multiReadResult.Content, index).ToString(),
                                EquipmentDataType.WORD => reverseBytesTransform.TransUInt16(multiReadResult.Content, index).ToString(),
                                EquipmentDataType.INT => reverseBytesTransform.TransInt16(multiReadResult.Content, index).ToString(),
                                EquipmentDataType.CHAR => reverseBytesTransform.TransString(multiReadResult.Content, index, prop.Length, Encoding.ASCII).Replace("\u0003", "").Trim(),
                                EquipmentDataType.REAL => reverseBytesTransform.TransSingle(multiReadResult.Content, index).ToString(),
                                _ => string.Empty
                            };
                        }
                    }
                    return BllResultFactory.Success();
                }

                //单个地址读取
                foreach (var item in dataItems)
                {
                    switch (item.DataType)
                    {
                        case EquipmentDataType.BOOL:
                            var boolDataResult = Siemens.ReadBool(item.DataAddress);
                            if (!boolDataResult.IsSuccess)
                            {
                                item.Value = string.Empty;
                                return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}出现异常:{boolDataResult.Message}");
                            }
                            item.Value = boolDataResult.Content.ToString();
                            break;
                        case EquipmentDataType.BYTE:
                            var byteDataResult = Siemens.ReadByte(item.DataAddress);
                            if (!byteDataResult.IsSuccess)
                            {
                                item.Value = string.Empty;
                                return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}出现异常:{byteDataResult.Message}");
                            }
                            item.Value = byteDataResult.Content.ToString();
                            break;
                        case EquipmentDataType.WORD:
                            var shortDataResult = Siemens.ReadInt16(item.DataAddress);
                            if (!shortDataResult.IsSuccess)
                            {
                                item.Value = string.Empty;
                                return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}出现异常:{shortDataResult.Message}");
                            }
                            item.Value = shortDataResult.Content.ToString();
                            break;
                        case EquipmentDataType.DWORD:
                            var ushortDataResult = Siemens.ReadUInt16(item.DataAddress);
                            if (!ushortDataResult.IsSuccess)
                            {
                                item.Value = string.Empty;
                                return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}出现异常:{ushortDataResult.Message}");
                            }
                            item.Value = ushortDataResult.Content.ToString();
                            break;
                        case EquipmentDataType.INT:
                            var intDataResult = Siemens.ReadInt32(item.DataAddress);
                            if (!intDataResult.IsSuccess)
                            {
                                item.Value = string.Empty;
                                return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}出现异常:{intDataResult.Message}");
                            }
                            item.Value = intDataResult.Content.ToString();
                            break;
                        case EquipmentDataType.DINT:
                            var uintDataResult = Siemens.ReadUInt32(item.DataAddress);
                            if (!uintDataResult.IsSuccess)
                            {
                                item.Value = string.Empty;
                                return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}出现异常:{uintDataResult.Message}");
                            }
                            item.Value = uintDataResult.Content.ToString();
                            break;
                        case EquipmentDataType.REAL:
                            var floatDataResult = Siemens.ReadFloat(item.DataAddress);
                            if (!floatDataResult.IsSuccess)
                            {
                                item.Value = string.Empty;
                                return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}出现异常:{floatDataResult.Message}");
                            }
                            item.Value = floatDataResult.Content.ToString();
                            break;
                        //case "double":
                        //    var doubleDataResult = Siemens.ReadDouble(item.DataAddress);
                        //    if (!doubleDataResult.IsSuccess)
                        //    {
                        //        item.Value = string.Empty;
                        //        systemLog.LogError($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}出现异常:{doubleDataResult.Message}");
                        //        return;
                        //    }
                        //    item.Value = doubleDataResult.Content.ToString();
                        //    break;
                        case EquipmentDataType.CHAR:
                            var stringDataResult = Siemens.ReadString(item.DataAddress);
                            if (!stringDataResult.IsSuccess)
                            {
                                item.Value = string.Empty;
                                return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}出现异常:{stringDataResult.Message}");
                            }
                            item.Value = stringDataResult.Content.ToString();
                            break;
                        default:
                            return BllResultFactory.Error($"读取PLC[{Siemens.IpAddress}]地址{item.DataAddress}失败:不支持“{item.DataType}”数据类型");
                    }
                }
                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]);
        }
    }
}