C3032
2026-01-16 919a8efe5f75b9d84ed79c91dfbea5263da8ce59
LB_VisionProcesses/Communicators/SiemensS7/SiemensLBS7.cs
@@ -1,44 +1,103 @@
using LB_SmartVisionCommon;
using LB_SmartVisionCommon;
using S7.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Threading;
namespace LB_VisionProcesses.Communicators.SiemensS7
{
    public class SiemensLBS7 : BaseCommunicator
    {
        private Plc plc;
        public string variable = string.Empty;
        /// <summary>
        ///
        /// </summary>
        /// <param name="name"></param>
        public SiemensLBS7(string name = "西门子S7")
        // 默认变量地址
        public string variable = "DB1.DBD0";
        // 数据类型
        private string dataType = "String";
        // 缓存连接参数
        private string ip = "127.0.0.1";
        private short rack = 0;
        private short slot = 1;
        private CpuType cpuType = CpuType.S71500;
        public SiemensLBS7(string name = "西门子S7") : base(name)
        {
            CommunicatorConnections.Add("地址", "127.0.0.1");
            CommunicatorConnections.Add("端口", "1");
            CommunicatorConnections.Add("型号", S7.Net.CpuType.S71500);
            CommunicatorBrand = CommunicatorBrand.SiemensS7;
            CommunicatorName = name;
            CommunicatorBrand = CommunicatorBrand.SiemensS7;
            // 初始化默认参数
            if (!CommunicatorConnections.Contains("地址")) CommunicatorConnections.Add("地址", "192.168.0.1");
            if (!CommunicatorConnections.Contains("机架号")) CommunicatorConnections.Add("机架号", "0");
            if (!CommunicatorConnections.Contains("插槽号")) CommunicatorConnections.Add("插槽号", "1");
            if (!CommunicatorConnections.Contains("型号")) CommunicatorConnections.Add("型号", CpuType.S71500);
            if (!CommunicatorConnections.Contains("变量地址")) CommunicatorConnections.Add("变量地址", "DB1.DBD0");
            if (!CommunicatorConnections.Contains("数据类型")) CommunicatorConnections.Add("数据类型", "String");
            // 兼容旧配置 "端口"
            if (CommunicatorConnections.Contains("端口"))
            {
                CommunicatorConnections["插槽号"] = CommunicatorConnections["端口"];
            }
            // 设置默认心跳消息
            strHeartbeat = "HEARTBEAT";
        }
        public override bool Connect()
        {
            try
            {
                string IP = CommunicatorConnections["地址"].ToString();
                short slot;
                short.TryParse(CommunicatorConnections["端口"].ToString(), out slot);
                S7.Net.CpuType cpuType = (CpuType)CommunicatorConnections["型号"];
                plc = new Plc(cpuType, IP, 0, slot);
                plc.Open();
                return true;
                // 更新参数
                if (CommunicatorConnections.Contains("地址")) ip = CommunicatorConnections["地址"].ToString();
                if (CommunicatorConnections.Contains("机架号"))
                    short.TryParse(CommunicatorConnections["机架号"].ToString(), out rack);
                if (CommunicatorConnections.Contains("插槽号"))
                    short.TryParse(CommunicatorConnections["插槽号"].ToString(), out slot);
                else if (CommunicatorConnections.Contains("端口"))
                    short.TryParse(CommunicatorConnections["端口"].ToString(), out slot);
                if (CommunicatorConnections.Contains("型号"))
                {
                    if (CommunicatorConnections["型号"] is CpuType type)
                        cpuType = type;
                    else
                        Enum.TryParse(CommunicatorConnections["型号"].ToString(), out cpuType);
                }
                if (CommunicatorConnections.Contains("变量地址"))
                    variable = CommunicatorConnections["变量地址"].ToString();
                if (CommunicatorConnections.Contains("数据类型"))
                    dataType = CommunicatorConnections["数据类型"].ToString();
                // 关闭旧连接
                plc?.Close();
                plc = new Plc(cpuType, ip, rack, slot);
                plc.Open();
                if (plc.IsConnected)
                {
                    bConnected = true;
                    AsyncLogHelper.Info($"Device:[{CommunicatorName}] 已连接到 {ip} 机架:{rack} 插槽:{slot}");
                    return true;
                }
                else
                {
                    bConnected = false;
                    AsyncLogHelper.Error($"Device:[{CommunicatorName}] 连接失败: IsConnected 为 false");
                    return false;
                }
            }
            catch
            catch (Exception ex)
            {
                bConnected = false;
                AsyncLogHelper.Error($"Device:[{CommunicatorName}] 连接错误: {ex.Message}");
                return false;
            }
        }
@@ -47,20 +106,223 @@
        {
            try
            {
                plc?.Close();
                if (plc != null)
                {
                    plc.Close();
                    bConnected = false;
                    AsyncLogHelper.Info($"Device:[{CommunicatorName}] 已断开连接");
                }
                return true;
            }
            catch
            catch (Exception ex)
            {
                AsyncLogHelper.Error($"Device:[{CommunicatorName}] 断开连接错误: {ex.Message}");
                return false;
            }
        }
        public override bool SendMessage(string message)
        {
            if (plc == null || !plc.IsConnected)
            {
                Msg = "连接未开启";
                return false;
            }
            if (message == strHeartbeat) return plc.IsConnected;
            try
            {
                plc.Write(variable, message);
                string targetVar = variable;
                string strValue = message;
                // 简单的协议解析:地址:值
                if (message.Contains(":"))
                {
                    var parts = message.Split(new char[] { ':' }, 2);
                    if (parts.Length == 2 && !string.IsNullOrWhiteSpace(parts[0]))
                    {
                        targetVar = parts[0];
                        strValue = parts[1];
                    }
                }
                object valueToWrite = strValue;
                // 获取当前数据类型配置
                string currentDataType = CommunicatorConnections.Contains("数据类型") ? CommunicatorConnections["数据类型"].ToString() : "String";
                // 根据配置的数据类型进行转换
                try
                {
                    switch (currentDataType)
                    {
                        case "Bool":
                            if (strValue == "1") valueToWrite = true;
                            else if (strValue == "0") valueToWrite = false;
                            else valueToWrite = bool.Parse(strValue);
                            break;
                        case "Byte":
                            valueToWrite = byte.Parse(strValue);
                            break;
                        case "Int": // 16-bit
                            valueToWrite = short.Parse(strValue);
                            break;
                        case "DInt": // 32-bit
                            valueToWrite = int.Parse(strValue);
                            break;
                        case "Word": // 16-bit unsigned
                            valueToWrite = ushort.Parse(strValue);
                            break;
                        case "DWord": // 32-bit unsigned
                            valueToWrite = uint.Parse(strValue);
                            break;
                        case "Real": // Float
                            valueToWrite = float.Parse(strValue);
                            break;
                        case "Double": // LReal
                            valueToWrite = double.Parse(strValue);
                            break;
                        case "String":
                        default:
                            valueToWrite = strValue;
                            break;
                    }
                }
                catch (FormatException)
                {
                    Msg = $"无效的{currentDataType}值,请输入正确格式。";
                    if (currentDataType == "Bool") Msg += " (true/false 或 1/0)";
                    AsyncLogHelper.Error($"Device:[{CommunicatorName}] {Msg}");
                    return false;
                }
                catch (Exception castEx)
                {
                    Msg = $"数据转换错误({currentDataType}): {castEx.Message}";
                    AsyncLogHelper.Error($"Device:[{CommunicatorName}] {Msg}");
                    return false;
                }
                // 尝试写入
                plc.Write(targetVar, valueToWrite);
                AsyncLogHelper.Info($"Device:[{CommunicatorName}] 写入({currentDataType}) {targetVar} = {valueToWrite}");
                return true;
            }
            catch (Exception ex)
            {
                Msg = $"发送消息错误: {ex.Message}";
                AsyncLogHelper.Error($"Device:[{CommunicatorName}] {Msg}");
                return false;
            }
        }
        public override string ReceiveMsg()
        {
            if (plc == null || !plc.IsConnected) return string.Empty;
            try
            {
                // 获取当前数据类型配置
                string currentDataType = CommunicatorConnections.Contains("数据类型") ? CommunicatorConnections["数据类型"].ToString() : "String";
                if (currentDataType == "String")
                {
                    var match = Regex.Match(variable, @"DB(\d+)\.DB[B|W|D|X]?(\d+)", RegexOptions.IgnoreCase);
                    if (match.Success)
                    {
                        try
                        {
                            int db = int.Parse(match.Groups[1].Value);
                            int startByte = int.Parse(match.Groups[2].Value);
                            // 读取头部 (MaxLen, ActLen)
                            byte[] header = plc.ReadBytes(DataType.DataBlock, db, startByte, 2);
                            if (header != null && header.Length >= 2)
                            {
                                int actLen = header[1];
                                if (actLen > 0)
                                {
                                    // 读取实际字符数据
                                    byte[] strBytes = plc.ReadBytes(DataType.DataBlock, db, startByte + 2, actLen);
                                    strReceiveMsg = Encoding.ASCII.GetString(strBytes);
                                    return strReceiveMsg;
                                }
                                else
                                {
                                    strReceiveMsg = string.Empty;
                                    return strReceiveMsg;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            AsyncLogHelper.Error($"Device:[{CommunicatorName}] 读取S7String失败: {ex.Message}");
                        }
                    }
                    // 如果正则不匹配或读取失败,回退到默认读取
                }
                var result = plc.Read(variable);
                if (result != null)
                {
                    // 尝试根据 dataType 格式化输出 (S7.Net 读出来的类型可能与预期不符,特别是 DWord/Real)
                    // 例如 DBD0 默认读出来是 UInt32,如果 dataType 是 Real,需要转换
                    if (currentDataType == "Real" && (result is uint || result is int))
                    {
                        byte[] bytes = BitConverter.GetBytes(Convert.ToUInt32(result));
                        float f = BitConverter.ToSingle(bytes, 0);
                        strReceiveMsg = f.ToString();
                    }
                    else
                    {
                        strReceiveMsg = result.ToString();
                    }
                    return strReceiveMsg;
                }
            }
            catch (Exception ex)
            {
                AsyncLogHelper.Error($"Device:[{CommunicatorName}] 接收消息错误: {ex.Message}");
            }
            return string.Empty;
        }
        /// <summary>
        /// 带填充的 S7 字符串写入,防止残留数据
        /// </summary>
        private bool WriteS7StringWithPadding(string address, string value)
        {
            try
            {
                // 解析地址,例如 DB1.DBB0, DB1.DBD0
                var match = Regex.Match(address, @"DB(\d+)\.DB[B|W|D|X]?(\d+)", RegexOptions.IgnoreCase);
                if (!match.Success) return false;
                int db = int.Parse(match.Groups[1].Value);
                int startByte = int.Parse(match.Groups[2].Value);
                byte maxLen = 254; // 默认最大值
                try
                {
                    var header = plc.ReadBytes(DataType.DataBlock, db, startByte, 1);
                    if (header != null && header.Length > 0 && header[0] > 0)
                    {
                        maxLen = header[0];
                    }
                }
                catch { }
                byte[] buffer = new byte[maxLen + 2];
                buffer[0] = maxLen;
                int currentLen = Math.Min(value.Length, maxLen);
                buffer[1] = (byte)currentLen;
                if (currentLen > 0)
                {
                    byte[] strBytes = Encoding.ASCII.GetBytes(value);
                    Array.Copy(strBytes, 0, buffer, 2, Math.Min(strBytes.Length, currentLen));
                }
                plc.WriteBytes(DataType.DataBlock, db, startByte, buffer);
                return true;
            }
            catch
@@ -68,21 +330,31 @@
                return false;
            }
        }
        public object Read(string address)
        {
             if (plc == null || !plc.IsConnected) return null;
             return plc.Read(address);
        }
        public void Write(string address, object value)
        {
             if (plc != null && plc.IsConnected)
                plc.Write(address, value);
        }
        public override void Dispose()
        {
            try
            {
                AsyncLogHelper.Info($"Device:[{CommunicatorName}],Dispose()");
                AsyncLogHelper.Info($"Device:[{CommunicatorName}],释放资源(Dispose)");
                plc?.Close();
                plc = null;
                // Suppress finalization.
                GC.SuppressFinalize(this);
            }
            catch (Exception ex)
            {
                AsyncLogHelper.Error($"Device:[{CommunicatorName}],Dispose(),Error" + ex);
                AsyncLogHelper.Error($"Device:[{CommunicatorName}],释放资源(Dispose)错误: " + ex.Message);
            }
        }
    }