惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
H
Help Net Security
V
Visual Studio Blog
J
Java Code Geeks
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
MyScale Blog
MyScale Blog
The Cloudflare Blog
Martin Fowler
Martin Fowler
D
Docker
腾讯CDC
F
Fortinet All Blogs
雷峰网
雷峰网
GbyAI
GbyAI
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
博客园 - 叶小钗

博客园 - HackerVirus

在window系统下搭建C/C++开发环境 C#中DataGridView处理大数据量的技巧分享 CSharp-MVVM框架 多线程&线程池 Prism的事件聚合器 Toggling Focus Assist mode in Win 10 Programmatically Windsurf:超越 Cursor 的下一代 AI 编辑器 编程辅助新选择:Devin与Cursor的性能对比评测 支持多语言、多商店的商城,.Net7 + EF7领域驱动设计架构 Mysql高可用架构方案 软件架构中的那些惯用手段 .Net轻量级的CMS开源项目 前后端分离的权限管理框架,前端采用 Vue 3 框架,后端采用 .NET 8、ORM 采用 EF 8 linux文件属性 Roslyn的源生成器 IHostedService 和 BackgroundService 区别 Uno Platform是一个基于C#开源、功能强大、灵活的跨平台开发框架,用于快速构建单一代码库原生移动、Web、桌面和嵌入式应用程序 功能齐全的 WPF 自定义控件 Sprint Planning
使用HslCommunication类库读取Siemens PLC DATA
HackerVirus · 2025-01-05 · via 博客园 - HackerVirus

using HslCommunication.Profinet.Siemens;
using HslCommunication;

using System;
using System.Threading;
using Microsoft.Extensions.Logging;
using HslCommunication.Profinet.Siemens;
using HslCommunication;
using SamplePreparation_System.Common;
using SamplePreparation_System.Models;
using System.Collections.Generic;
using System.Text.Json;
using System.Text;
using HslCommunication.LogNet;
using System.Windows.Interop;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

namespace System.PLC
{
    public class Plc
    {
        private readonly object Lockobj = new object(); // 用于PLC写入时先锁定再写入
        private readonly ExponentialBackoff _backoff;
        private readonly int _maxRetryCount = 5; // 最大重试次数
        private readonly int _maxRetryDelay = 100; // 最大重试延迟时间(毫秒)
        private readonly int _baseConnectTimeOutDelay = 500; // 基础延迟时间(毫秒)
        // private readonly string ipAddress_SamplePreparationPLC = "192.168.1.1";
        private readonly string ipAddress_SamplePreparationPLC = System.Configuration.ConfigurationManager.AppSettings["ZyPlcIp"] ?? "172.21.38.100";

        // HslCommunication.LogNet.
        //private readonly ILogNet logNet = new LogNetDateTime(AppContext.BaseDirectory + "PLCLogs", GenerateMode.ByEveryDay);//按每天; // 日志
        public SiemensS7Net SiemensS7_SamplePreparation { get; set; }

        readonly ILogger<SamplePreparationPlc> _logger;
        public SamplePreparationPlc(ILogger<SamplePreparationPlc> logger)
        {
            _logger = logger;
            SiemensS7_SamplePreparation = new SiemensS7Net(SiemensPLCS.S1200, ipAddress_SamplePreparationPLC) { ConnectTimeOut = _baseConnectTimeOutDelay };
            SiemensS7_SamplePreparation.ConnectServer();
            _backoff = new ExponentialBackoff(_maxRetryDelay, logger); // 基础延迟 100 毫秒  
        }

        /// <summary>
        /// 读取PLC
        /// </summary>
        /// <param name="address">点位</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public string PlcRead(string address, string type)
        {
            string data = "";
            _backoff.SendWithBackoff(() =>
            {
                switch (type.ToLower())
                {
                    case "bool":
                        var result = SiemensS7_SamplePreparation.ReadBool(address);
                        if (!result.IsSuccess)
                        {
                            _logger.LogError(result.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result.Message); // 抛出异常以触发重试 
                        }

                        data = result.Content.ToString();
                        break;
                    case "float":
                        var result1 = SiemensS7_SamplePreparation.ReadFloat(address);
                        if (!result1.IsSuccess)
                        {
                            _logger.LogError(result1.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result1.Message); // 抛出异常以触发重试 
                        }

                        data = result1.Content.ToString();
                        break;
                    case "datetime":
                        var result2 = SiemensS7_SamplePreparation.ReadDateTime(address);
                        if (!result2.IsSuccess)
                        {
                            _logger.LogError(result2.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result2.Message); // 抛出异常以触发重试 
                        }

                        data = result2.Content.ToString();
                        break;
                    case "int32":
                    case "int":
                        var result3 = SiemensS7_SamplePreparation.ReadInt32(address);
                        if (!result3.IsSuccess)
                        {
                            _logger.LogError(result3.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result3.Message); // 抛出异常以触发重试 
                        }

                        data = result3.Content.ToString();
                        break;
                    case "int16":
                        var result4 = SiemensS7_SamplePreparation.ReadInt16(address);
                        if (!result4.IsSuccess)
                        {
                            _logger.LogError(result4.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result4.Message); // 抛出异常以触发重试 
                        }

                        data = result4.Content.ToString();
                        break;
                    case "string":
                        var result5 = SiemensS7_SamplePreparation.ReadString(address);
                        if (!result5.IsSuccess)
                        {
                            _logger.LogError(result5.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result5.Message); // 抛出异常以触发重试 
                        }

                        data = result5.Content.ToString();
                        break;
                    case "double":
                        var result6 = SiemensS7_SamplePreparation.ReadDouble(address);
                        if (!result6.IsSuccess)
                        {
                            _logger.LogError(result6.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result6.Message); // 抛出异常以触发重试 
                        }

                        data = result6.Content.ToString();
                        break;
                    case "byte":
                        var result7 = SiemensS7_SamplePreparation.ReadByte(address);
                        if (!result7.IsSuccess)
                        {
                            _logger.LogError(result7.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result7.Message); // 抛出异常以触发重试 
                        }

                        data = result7.Content.ToString();
                        break;
                    default:
                        throw new ArgumentException("Unsupported type");

                }

            }, maxRetries: _maxRetryCount); // 最大重试次数  

            return data;
        }

        /// <summary>
        /// 读取PLC
        /// </summary>
        /// <param name="address">点位</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public async Task<string> PlcReadAsync(string address, string type)
        {
            string data = "";
            _backoff.SendWithBackoff(async () =>
            {
                switch (type.ToLower())
                {
                    case "bool":
                        var result = await SiemensS7_SamplePreparation.ReadBoolAsync(address);
                        if (!result.IsSuccess)
                        {
                            _logger.LogError(result.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result.Message); // 抛出异常以触发重试 
                        }

                        data = result.Content.ToString();
                        break;
                    case "float":
                        var result1 = await SiemensS7_SamplePreparation.ReadFloatAsync(address);
                        if (!result1.IsSuccess)
                        {
                            _logger.LogError(result1.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result1.Message); // 抛出异常以触发重试 
                        }

                        data = result1.Content.ToString();
                        break;
                    case "datetime":
                        var result2 = await SiemensS7_SamplePreparation.ReadDateTimeAsync(address);
                        if (!result2.IsSuccess)
                        {
                            _logger.LogError(result2.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result2.Message); // 抛出异常以触发重试 
                        }

                        data = result2.Content.ToString();
                        break;
                    case "int32":
                    case "int":
                        var result3 = await SiemensS7_SamplePreparation.ReadInt32Async(address);
                        if (!result3.IsSuccess)
                        {
                            _logger.LogError(result3.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result3.Message); // 抛出异常以触发重试 
                        }

                        data = result3.Content.ToString();
                        break;
                    case "int16":
                        var result4 = await SiemensS7_SamplePreparation.ReadInt16Async(address);
                        if (!result4.IsSuccess)
                        {
                            _logger.LogError(result4.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result4.Message); // 抛出异常以触发重试 
                        }

                        data = result4.Content.ToString();
                        break;
                    case "string":
                        var result5 = await SiemensS7_SamplePreparation.ReadStringAsync(address);
                        if (!result5.IsSuccess)
                        {
                            _logger.LogError(result5.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result5.Message); // 抛出异常以触发重试 
                        }

                        data = result5.Content.ToString();
                        break;
                    case "double":
                        var result6 = await SiemensS7_SamplePreparation.ReadDoubleAsync(address);
                        if (!result6.IsSuccess)
                        {
                            _logger.LogError(result6.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result6.Message); // 抛出异常以触发重试 
                        }

                        data = result6.Content.ToString();
                        break;
                    case "byte":
                        var result7 = await SiemensS7_SamplePreparation.ReadByteAsync(address);
                        if (!result7.IsSuccess)
                        {
                            _logger.LogError(result7.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result7.Message); // 抛出异常以触发重试 
                        }

                        data = result7.Content.ToString();
                        break;
                    default:
                        throw new ArgumentException("Unsupported type");

                }

            }, maxRetries: _maxRetryCount); // 最大重试次数  

            return data;
        }

        /// <summary>
        /// 写入PLC
        /// </summary>
        /// <param name="address">点位</param>
        /// <param name="value">值</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public OperateResult PlcWrite(string address, object value, string type)
        {
            lock(Lockobj)
            {
                var result = new OperateResult();
                //while (true)
                //{
                _backoff.SendWithBackoff(() =>
                {
                    try
                    {
                        switch (type.ToLower())
                        {
                            case "bool":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToBoolean(value));
                                break;
                            case "float":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToSingle(value));
                                break;
                            case "datetime":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToDateTime(value));
                                break;
                            case "int32":
                            case "int":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToInt32(value));
                                break;
                            case "int16":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToInt16(value));
                                break;
                            case "string":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToString(value));
                                break;
                            case "byte":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToByte(value));
                                break;
                            default:
                                throw new ArgumentException("Unsupported type");
                        }

                        if (!result.IsSuccess)
                        {
                            _logger.LogError(result.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result.Message); // 抛出异常以触发重试 
                        }

                        //return result;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex.Message + ex.StackTrace);
                        throw; // 重新抛出异常以便重试
                    }
                }, maxRetries: _maxRetryCount); // 最大重试次数  
                return result;
                //Thread.Sleep(1000);
                //}
            }
        }

        /// <summary>
        /// 写入PLC
        /// </summary>
        /// <param name="address">点位</param>
        /// <param name="value">值</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public async Task<OperateResult> PlcWriteAsync(string address, object value, string type)
        {
            //lock (Lockobj)
            //{
            var result = new OperateResult();
            //while (true)
            //{
            _backoff.SendWithBackoff(async () =>
            {
                try
                {
                    switch (type.ToLower())
                    {
                        case "bool":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToBoolean(value));
                            break;
                        case "float":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToSingle(value));
                            break;
                        case "datetime":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToDateTime(value));
                            break;
                        case "int32":
                        case "int":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToInt32(value));
                            break;
                        case "int16":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToInt16(value));
                            break;
                        case "string":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToString(value));
                            break;
                        case "byte":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToByte(value));
                            break;
                        default:
                            throw new ArgumentException("Unsupported type");
                    }

                    if (!result.IsSuccess)
                    {
                        _logger.LogError(result.Message);
                        //Thread.Sleep(1000);
                        //continue;
                        throw new Exception(result.Message); // 抛出异常以触发重试 
                    }

                    //return result;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex.Message + ex.StackTrace);
                    throw; // 重新抛出异常以便重试
                }
            }, maxRetries: _maxRetryCount); // 最大重试次数  
            return result;
            //Thread.Sleep(1000);
            //}
            //}
        }

        /// <summary>
        /// 批量读取PLC点位值.
        /// Batches the read.
        /// </summary>
        /// <param name="pointList">The point list.</param>
        /// <returns></returns>
        public List<PLCPointData> BatchRead(List<PLCPointData> pointList)
        {
            List<string> plcAddress = new List<string>();
            ushort[]  dataLength = new ushort[pointList.Count];
            int index = 0;
            foreach (var point in pointList)
            {
                dataLength[index] = (ushort)point.DataLength;
                index++;
                plcAddress.Add(point.Address);
            }

            OperateResult<byte[]> resultData = SiemensS7_SamplePreparation.Read(plcAddress.ToArray(), dataLength);
            if (resultData.IsSuccess)
            {
                index = 0;
                for (int i = 0; i < pointList.Count; i++)
                {
                    ByteTrans(resultData.Content, pointList[i], index);
                    index += pointList[i].DataLength;
                }
            }
            else
            {
                PLCPointData pointData = new PLCPointData();
                pointData = pointList[0];
                pointData.ResultMsg = resultData.Message;

                pointList.Clear();

                pointList.Add(pointData);
            }

            return pointList;
        }

        /// <summary>
        /// 批量读取PLC点位值.
        /// Batches the read.
        /// </summary>
        /// <param name="pointList">The point list.</param>
        /// <returns></returns>
        public async Task<List<PLCPointData>> BatchReadAsync(List<PLCPointData> pointList)
        {
            List<string> plcAddress = new List<string>();
            ushort[] dataLength = new ushort[pointList.Count];
            int index = 0;
            foreach (var point in pointList)
            {
                dataLength[index] = (ushort)point.DataLength;
                index++;
                plcAddress.Add(point.Address);
            }

            OperateResult<byte[]> resultData = await SiemensS7_SamplePreparation.ReadAsync(plcAddress.ToArray(), dataLength);
            if (resultData.IsSuccess)
            {
                index = 0;
                for (int i = 0; i < pointList.Count; i++)
                {
                    ByteTrans(resultData.Content, pointList[i], index);
                    index += pointList[i].DataLength;
                }
            }
            else
            {
                PLCPointData pointData = new PLCPointData();
                pointData = pointList[0];
                pointData.ResultMsg = resultData.Message;

                pointList.Clear();

                pointList.Add(pointData);
            }

            return pointList;
        }

        /// <summary>
        /// 写入PLC点位值.
        /// the write.
        /// </summary>
        /// <param name="pLCPoint">The p lc point.</param>
        /// <returns></returns>
        public PLCPointData Write(PLCPointData pLCPoint)
        {
            lock (Lockobj)
            {
                if (pLCPoint.ResultData is JsonElement)
                {
                    pLCPoint.ResultData = ConvertValueKind(pLCPoint.ResultData);
                }

                if (pLCPoint.ResultData == null)
                {
                    pLCPoint.ResultCode = 0;
                    pLCPoint.ResultMsg = $"参数中缺少ResultData值";
                    return pLCPoint;
                }

                var result = new OperateResult();
                try
                {
                    Type type = ConvertPointDataType(pLCPoint.DataType);
                    string value = pLCPoint.ResultData.ToString();
                    if (type == typeof(bool))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, bool.Parse(value));
                    }
                    else if (type == typeof(byte))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, byte.Parse(value));
                    }
                    else if (type == typeof(float))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, float.Parse(value));
                    }
                    else if (type == typeof(double))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, double.Parse(value));
                    }
                    else if (type == typeof(DateTime))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, DateTime.Parse(value));
                    }
                    else if (type == typeof(int))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, int.Parse(value));
                    }
                    else if (type == typeof(short))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, Convert.ToInt16(value));
                    }
                    else
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, value, pLCPoint.DataLength);
                    }

                    pLCPoint.ResultCode = result.IsSuccess ? 1 : 0;
                    pLCPoint.ResultMsg = result.IsSuccess ? "Success" : result.Message;
                    return pLCPoint;
                }
                catch (Exception ex)
                {
                    pLCPoint.ResultCode = 0;
                    pLCPoint.ResultMsg = $"(写入)失败:{ex.Message}{ex.StackTrace}";
                    return pLCPoint;
                }
            }
        }

        /// <summary>
        /// 写入PLC点位值.
        /// the write.
        /// </summary>
        /// <param name="pLCPoint">The p lc point.</param>
        /// <returns></returns>
        public async Task<PLCPointData> WriteAsync(PLCPointData pLCPoint)
        {
            //lock (Lockobj)
            //{
                if (pLCPoint.ResultData is JsonElement)
                {
                    pLCPoint.ResultData = ConvertValueKind(pLCPoint.ResultData);
                }

                if (pLCPoint.ResultData == null)
                {
                    pLCPoint.ResultCode = 0;
                    pLCPoint.ResultMsg = $"参数中缺少ResultData值";
                    return pLCPoint;
                }

                var result = new OperateResult();
                try
                {
                    Type type = ConvertPointDataType(pLCPoint.DataType);
                    string value = pLCPoint.ResultData.ToString();
                    if (type == typeof(bool))
                    {
                        result = await SiemensS7_SamplePreparation.WaitAsync(pLCPoint.Address, bool.Parse(value));
                    }
                    else if (type == typeof(byte))
                    {
                        result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, byte.Parse(value));
                    }
                    else if (type == typeof(float))
                    {
                        result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, float.Parse(value));
                    }
                    else if (type == typeof(double))
                    {
                        result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, double.Parse(value));
                    }
                    else if (type == typeof(DateTime))
                    {
                        result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, DateTime.Parse(value));
                    }
                    else if (type == typeof(int))
                    {
                        result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, int.Parse(value));
                    }
                    else if (type == typeof(short))
                    {
                        result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, Convert.ToInt16(value));
                    }
                    else
                    {
                        result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, value, pLCPoint.DataLength);
                    }

                    pLCPoint.ResultCode = result.IsSuccess ? 1 : 0;
                    pLCPoint.ResultMsg = result.IsSuccess ? "Success" : result.Message;
                    return pLCPoint;
                }
                catch (Exception ex)
                {
                    pLCPoint.ResultCode = 0;
                    pLCPoint.ResultMsg = $"(写入)失败:{ex.Message}{ex.StackTrace}";
                    return pLCPoint;
                }
            //}
        }

        /// <summary>
        /// Bytes the trans.
        /// </summary>
        /// <param name="content">The content.</param>
        /// <param name="pLCPoint">The p lc point.</param>
        /// <param name="index">The index.</param>
        private void ByteTrans(byte[] content, PLCPointData pLCPoint, int index)
        {
            try
            {
                Type type = ConvertPointDataType(pLCPoint.DataType);
                if (type == typeof(bool))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransBool(content, index);
                }
                else if (type == typeof(byte))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransByte(content, index);
                }
                else if (type == typeof(float))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransSingle(content, index);
                }
                else if (type == typeof(double))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransDouble(content, index);
                }
                else if (type == typeof(int))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransInt32(content, index);
                }
                else
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransString(content, index, pLCPoint.DataLength, Encoding.ASCII).Replace("\0", "").Replace("\u0001", "");
                }
            }
            catch (Exception ex)
            {
                pLCPoint.ResultCode = 0;
                pLCPoint.ResultMsg = $"(读取)错误:{ex.Message}{ex.StackTrace}";
            }
        }

        /// <summary>
        /// 数据类型转换
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        private Type ConvertPointDataType(string dataType)
        {
            Type type = null;
            switch (dataType.Trim().ToLower())
            {
                case "bool":
                    type = typeof(bool);
                    break;
                case "byte":
                    type = typeof(byte);
                    break;
                case "int":
                    type = typeof(int);
                    break;
                case "datetime":
                    type = typeof(DateTime);
                    break;
                case "dint":
                    type = typeof(int);
                    break;
                case "real":
                    type = typeof(float);
                    break;
                case "lreal":
                    type = typeof(double);
                    break;
                case "lint":
                    type = typeof(long);
                    break;
                case "string":
                    type = typeof(string);
                    break;
                case "short":
                    type = typeof(short);
                    break;
                default:
                    {
                        AddSysError(SiemensS7_SamplePreparation.IpAddress, $"{dataType}数据类型不存在");
                        //throw new ArgumentOutOfRangeException(dataType, "数据类型不存在");
                        break;
                    }

            }

            return type;
        }

        /// <summary>
        /// Converts the kind of the value.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        private object? ConvertValueKind(JsonElement element)
        {
            switch (element.ValueKind)
            {
                case JsonValueKind.String: return element.GetString();
                case JsonValueKind.Null: return null;
                case JsonValueKind.False: return false;
                case JsonValueKind.True: return true;
                case JsonValueKind.Number: return element.GetDouble();
                case JsonValueKind.Object: return element.ValueKind.ToString();
                default: break;
            }

            return element;
        }

        /// <summary>
        /// Adds the system message.
        /// </summary>
        /// <param name="msg">The MSG.</param>
        private void AddSysMessage(string msg)
        {
            //logNet.WriteInfo(msg);
            _logger.LogInformation(msg);
        }

        /// <summary>
        /// Adds the system error.
        /// </summary>
        /// <param name="plcIp">The PLC ip.</param>
        /// <param name="error">The error.</param>
        private void AddSysError(string plcIp, string error)
        {
            //logNet.WriteError(plcIp, error);
            _logger.LogError(plcIp + ", error:" + error);
        }
    }


    public class PlcEx
    {
        private readonly object Lockobj = new object(); // 用于PLC写入时先锁定再写入
        private readonly ExponentialBackoff _backoff;
        private readonly int _maxRetryCount = 5; // 最大重试次数
        private readonly int _maxRetryDelay = 100; // 最大重试延迟时间(毫秒)
        private readonly int _baseConnectTimeOutDelay = 500; // 基础延迟时间(毫秒)
        // private readonly string ipAddress_SamplePreparationPLC = "192.168.1.1";
        private readonly string ipAddress_SamplePreparationPLC = System.Configuration.ConfigurationManager.AppSettings["HygpPlcIp"] ?? "172.21.38.101";

        // HslCommunication.LogNet.
        //private readonly ILogNet logNet = new LogNetDateTime(AppContext.BaseDirectory + "PLCLogs", GenerateMode.ByEveryDay);//按每天; // 日志
        public SiemensS7Net SiemensS7_SamplePreparation { get; set; }

        readonly ILogger<SamplePreparationPlc> _logger;
        public Hygp_SamplePreparationPlc(ILogger<SamplePreparationPlc> logger)
        {
            _logger = logger;
            SiemensS7_SamplePreparation = new SiemensS7Net(SiemensPLCS.S1200, ipAddress_SamplePreparationPLC) { ConnectTimeOut = _baseConnectTimeOutDelay };
            SiemensS7_SamplePreparation.ConnectServer();
            _backoff = new ExponentialBackoff(_maxRetryDelay, logger); // 基础延迟 100 毫秒  
        }

        /// <summary>
        /// 读取PLC
        /// </summary>
        /// <param name="address">点位</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public string PlcRead(string address, string type)
        {
            string data = "";
            _backoff.SendWithBackoff(() =>
            {
                switch (type.ToLower())
                {
                    case "bool":
                        var result = SiemensS7_SamplePreparation.ReadBool(address);
                        if (!result.IsSuccess)
                        {
                            _logger.LogError(result.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result.Message); // 抛出异常以触发重试 
                        }

                        data = result.Content.ToString();
                        break;
                    case "float":
                        var result1 = SiemensS7_SamplePreparation.ReadFloat(address);
                        if (!result1.IsSuccess)
                        {
                            _logger.LogError(result1.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result1.Message); // 抛出异常以触发重试 
                        }

                        data = result1.Content.ToString();
                        break;
                    case "datetime":
                        var result2 = SiemensS7_SamplePreparation.ReadDateTime(address);
                        if (!result2.IsSuccess)
                        {
                            _logger.LogError(result2.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result2.Message); // 抛出异常以触发重试 
                        }

                        data = result2.Content.ToString();
                        break;
                    case "int32":
                    case "int":
                        var result3 = SiemensS7_SamplePreparation.ReadInt32(address);
                        if (!result3.IsSuccess)
                        {
                            _logger.LogError(result3.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result3.Message); // 抛出异常以触发重试 
                        }

                        data = result3.Content.ToString();
                        break;
                    case "int16":
                        var result4 = SiemensS7_SamplePreparation.ReadInt16(address);
                        if (!result4.IsSuccess)
                        {
                            _logger.LogError(result4.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result4.Message); // 抛出异常以触发重试 
                        }

                        data = result4.Content.ToString();
                        break;
                    case "string":
                        var result5 = SiemensS7_SamplePreparation.ReadString(address);
                        if (!result5.IsSuccess)
                        {
                            _logger.LogError(result5.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result5.Message); // 抛出异常以触发重试 
                        }

                        data = result5.Content.ToString();
                        break;
                    case "double":
                        var result6 = SiemensS7_SamplePreparation.ReadDouble(address);
                        if (!result6.IsSuccess)
                        {
                            _logger.LogError(result6.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result6.Message); // 抛出异常以触发重试 
                        }

                        data = result6.Content.ToString();
                        break;
                    case "byte":
                        var result7 = SiemensS7_SamplePreparation.ReadByte(address);
                        if (!result7.IsSuccess)
                        {
                            _logger.LogError(result7.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result7.Message); // 抛出异常以触发重试 
                        }

                        data = result7.Content.ToString();
                        break;
                    default:
                        throw new ArgumentException("Unsupported type");

                }

            }, maxRetries: _maxRetryCount); // 最大重试次数  

            return data;
        }

        /// <summary>
        /// 读取PLC
        /// </summary>
        /// <param name="address">点位</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public async Task<string> PlcReadAsync(string address, string type)
        {
            string data = "";
            _backoff.SendWithBackoff(async () =>
            {
                switch (type.ToLower())
                {
                    case "bool":
                        var result = await SiemensS7_SamplePreparation.ReadBoolAsync(address);
                        if (!result.IsSuccess)
                        {
                            _logger.LogError(result.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result.Message); // 抛出异常以触发重试 
                        }

                        data = result.Content.ToString();
                        break;
                    case "float":
                        var result1 = await SiemensS7_SamplePreparation.ReadFloatAsync(address);
                        if (!result1.IsSuccess)
                        {
                            _logger.LogError(result1.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result1.Message); // 抛出异常以触发重试 
                        }

                        data = result1.Content.ToString();
                        break;
                    case "datetime":
                        var result2 = await SiemensS7_SamplePreparation.ReadDateTimeAsync(address);
                        if (!result2.IsSuccess)
                        {
                            _logger.LogError(result2.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result2.Message); // 抛出异常以触发重试 
                        }

                        data = result2.Content.ToString();
                        break;
                    case "int32":
                    case "int":
                        var result3 = await SiemensS7_SamplePreparation.ReadInt32Async(address);
                        if (!result3.IsSuccess)
                        {
                            _logger.LogError(result3.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result3.Message); // 抛出异常以触发重试 
                        }

                        data = result3.Content.ToString();
                        break;
                    case "int16":
                        var result4 = await SiemensS7_SamplePreparation.ReadInt16Async(address);
                        if (!result4.IsSuccess)
                        {
                            _logger.LogError(result4.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result4.Message); // 抛出异常以触发重试 
                        }

                        data = result4.Content.ToString();
                        break;
                    case "string":
                        var result5 = await SiemensS7_SamplePreparation.ReadStringAsync(address);
                        if (!result5.IsSuccess)
                        {
                            _logger.LogError(result5.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result5.Message); // 抛出异常以触发重试 
                        }

                        data = result5.Content.ToString();
                        break;
                    case "double":
                        var result6 = await SiemensS7_SamplePreparation.ReadDoubleAsync(address);
                        if (!result6.IsSuccess)
                        {
                            _logger.LogError(result6.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result6.Message); // 抛出异常以触发重试 
                        }

                        data = result6.Content.ToString();
                        break;
                    case "byte":
                        var result7 = await SiemensS7_SamplePreparation.ReadByteAsync(address);
                        if (!result7.IsSuccess)
                        {
                            _logger.LogError(result7.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result7.Message); // 抛出异常以触发重试 
                        }

                        data = result7.Content.ToString();
                        break;
                    default:
                        throw new ArgumentException("Unsupported type");

                }

            }, maxRetries: _maxRetryCount); // 最大重试次数  

            return data;
        }

        /// <summary>
        /// 写入PLC
        /// </summary>
        /// <param name="address">点位</param>
        /// <param name="value">值</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public OperateResult PlcWrite(string address, object value, string type)
        {
            lock (Lockobj)
            {
                var result = new OperateResult();
                //while (true)
                //{
                _backoff.SendWithBackoff(() =>
                {
                    try
                    {
                        switch (type.ToLower())
                        {
                            case "bool":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToBoolean(value));
                                break;
                            case "float":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToSingle(value));
                                break;
                            case "datetime":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToDateTime(value));
                                break;
                            case "int32":
                            case "int":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToInt32(value));
                                break;
                            case "int16":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToInt16(value));
                                break;
                            case "string":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToString(value));
                                break;
                            case "byte":
                                result = SiemensS7_SamplePreparation.Write(address, Convert.ToByte(value));
                                break;
                            default:
                                throw new ArgumentException("Unsupported type");
                        }

                        if (!result.IsSuccess)
                        {
                            _logger.LogError(result.Message);
                            //Thread.Sleep(1000);
                            //continue;
                            throw new Exception(result.Message); // 抛出异常以触发重试 
                        }

                        //return result;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex.Message + ex.StackTrace);
                        throw; // 重新抛出异常以便重试
                    }
                }, maxRetries: _maxRetryCount); // 最大重试次数  
                return result;
                //Thread.Sleep(1000);
                //}
            }
        }

        /// <summary>
        /// 写入PLC
        /// </summary>
        /// <param name="address">点位</param>
        /// <param name="value">值</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public async Task<OperateResult> PlcWriteAsync(string address, object value, string type)
        {
            //lock (Lockobj)
            //{
            var result = new OperateResult();
            //while (true)
            //{
            _backoff.SendWithBackoff(async () =>
            {
                try
                {
                    switch (type.ToLower())
                    {
                        case "bool":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToBoolean(value));
                            break;
                        case "float":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToSingle(value));
                            break;
                        case "datetime":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToDateTime(value));
                            break;
                        case "int32":
                        case "int":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToInt32(value));
                            break;
                        case "int16":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToInt16(value));
                            break;
                        case "string":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToString(value));
                            break;
                        case "byte":
                            result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToByte(value));
                            break;
                        default:
                            throw new ArgumentException("Unsupported type");
                    }

                    if (!result.IsSuccess)
                    {
                        _logger.LogError(result.Message);
                        //Thread.Sleep(1000);
                        //continue;
                        throw new Exception(result.Message); // 抛出异常以触发重试 
                    }

                    //return result;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex.Message + ex.StackTrace);
                    throw; // 重新抛出异常以便重试
                }
            }, maxRetries: _maxRetryCount); // 最大重试次数  
            return result;
            //Thread.Sleep(1000);
            //}
            //}
        }

        /// <summary>
        /// 批量读取PLC点位值.
        /// Batches the read.
        /// </summary>
        /// <param name="pointList">The point list.</param>
        /// <returns></returns>
        public List<PLCPointData> BatchRead(List<PLCPointData> pointList)
        {
            List<string> plcAddress = new List<string>();
            ushort[] dataLength = new ushort[pointList.Count];
            int index = 0;
            foreach (var point in pointList)
            {
                dataLength[index] = (ushort)point.DataLength;
                index++;
                plcAddress.Add(point.Address);
            }

            OperateResult<byte[]> resultData = SiemensS7_SamplePreparation.Read(plcAddress.ToArray(), dataLength);
            if (resultData.IsSuccess)
            {
                index = 0;
                for (int i = 0; i < pointList.Count; i++)
                {
                    ByteTrans(resultData.Content, pointList[i], index);
                    index += pointList[i].DataLength;
                }
            }
            else
            {
                PLCPointData pointData = new PLCPointData();
                pointData = pointList[0];
                pointData.ResultMsg = resultData.Message;

                pointList.Clear();

                pointList.Add(pointData);
            }

            return pointList;
        }

        /// <summary>
        /// 批量读取PLC点位值.
        /// Batches the read.
        /// </summary>
        /// <param name="pointList">The point list.</param>
        /// <returns></returns>
        public async Task<List<PLCPointData>> BatchReadAsync(List<PLCPointData> pointList)
        {
            List<string> plcAddress = new List<string>();
            ushort[] dataLength = new ushort[pointList.Count];
            int index = 0;
            foreach (var point in pointList)
            {
                dataLength[index] = (ushort)point.DataLength;
                index++;
                plcAddress.Add(point.Address);
            }

            OperateResult<byte[]> resultData = await SiemensS7_SamplePreparation.ReadAsync(plcAddress.ToArray(), dataLength);
            if (resultData.IsSuccess)
            {
                index = 0;
                for (int i = 0; i < pointList.Count; i++)
                {
                    ByteTrans(resultData.Content, pointList[i], index);
                    index += pointList[i].DataLength;
                }
            }
            else
            {
                PLCPointData pointData = new PLCPointData();
                pointData = pointList[0];
                pointData.ResultMsg = resultData.Message;

                pointList.Clear();

                pointList.Add(pointData);
            }

            return pointList;
        }

        /// <summary>
        /// 写入PLC点位值.
        /// the write.
        /// </summary>
        /// <param name="pLCPoint">The p lc point.</param>
        /// <returns></returns>
        public PLCPointData Write(PLCPointData pLCPoint)
        {
            lock (Lockobj)
            {
                if (pLCPoint.ResultData is JsonElement)
                {
                    pLCPoint.ResultData = ConvertValueKind(pLCPoint.ResultData);
                }

                if (pLCPoint.ResultData == null)
                {
                    pLCPoint.ResultCode = 0;
                    pLCPoint.ResultMsg = $"参数中缺少ResultData值";
                    return pLCPoint;
                }

                var result = new OperateResult();
                try
                {
                    Type type = ConvertPointDataType(pLCPoint.DataType);
                    string value = pLCPoint.ResultData.ToString();
                    if (type == typeof(bool))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, bool.Parse(value));
                    }
                    else if (type == typeof(byte))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, byte.Parse(value));
                    }
                    else if (type == typeof(float))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, float.Parse(value));
                    }
                    else if (type == typeof(double))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, double.Parse(value));
                    }
                    else if (type == typeof(DateTime))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, DateTime.Parse(value));
                    }
                    else if (type == typeof(int))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, int.Parse(value));
                    }
                    else if (type == typeof(short))
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, Convert.ToInt16(value));
                    }
                    else
                    {
                        result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, value, pLCPoint.DataLength);
                    }

                    pLCPoint.ResultCode = result.IsSuccess ? 1 : 0;
                    pLCPoint.ResultMsg = result.IsSuccess ? "Success" : result.Message;
                    return pLCPoint;
                }
                catch (Exception ex)
                {
                    pLCPoint.ResultCode = 0;
                    pLCPoint.ResultMsg = $"(写入)失败:{ex.Message}{ex.StackTrace}";
                    return pLCPoint;
                }
            }
        }

        /// <summary>
        /// 写入PLC点位值.
        /// the write.
        /// </summary>
        /// <param name="pLCPoint">The p lc point.</param>
        /// <returns></returns>
        public async Task<PLCPointData> WriteAsync(PLCPointData pLCPoint)
        {
            //lock (Lockobj)
            //{
            if (pLCPoint.ResultData is JsonElement)
            {
                pLCPoint.ResultData = ConvertValueKind(pLCPoint.ResultData);
            }

            if (pLCPoint.ResultData == null)
            {
                pLCPoint.ResultCode = 0;
                pLCPoint.ResultMsg = $"参数中缺少ResultData值";
                return pLCPoint;
            }

            var result = new OperateResult();
            try
            {
                Type type = ConvertPointDataType(pLCPoint.DataType);
                string value = pLCPoint.ResultData.ToString();
                if (type == typeof(bool))
                {
                    result = await SiemensS7_SamplePreparation.WaitAsync(pLCPoint.Address, bool.Parse(value));
                }
                else if (type == typeof(byte))
                {
                    result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, byte.Parse(value));
                }
                else if (type == typeof(float))
                {
                    result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, float.Parse(value));
                }
                else if (type == typeof(double))
                {
                    result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, double.Parse(value));
                }
                else if (type == typeof(DateTime))
                {
                    result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, DateTime.Parse(value));
                }
                else if (type == typeof(int))
                {
                    result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, int.Parse(value));
                }
                else if (type == typeof(short))
                {
                    result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, Convert.ToInt16(value));
                }
                else
                {
                    result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, value, pLCPoint.DataLength);
                }

                pLCPoint.ResultCode = result.IsSuccess ? 1 : 0;
                pLCPoint.ResultMsg = result.IsSuccess ? "Success" : result.Message;
                return pLCPoint;
            }
            catch (Exception ex)
            {
                pLCPoint.ResultCode = 0;
                pLCPoint.ResultMsg = $"(写入)失败:{ex.Message}{ex.StackTrace}";
                return pLCPoint;
            }
            //}
        }

        /// <summary>
        /// Bytes the trans.
        /// </summary>
        /// <param name="content">The content.</param>
        /// <param name="pLCPoint">The p lc point.</param>
        /// <param name="index">The index.</param>
        private void ByteTrans(byte[] content, PLCPointData pLCPoint, int index)
        {
            try
            {
                Type type = ConvertPointDataType(pLCPoint.DataType);
                if (type == typeof(bool))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransBool(content, index);
                }
                else if (type == typeof(byte))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransByte(content, index);
                }
                else if (type == typeof(float))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransSingle(content, index);
                }
                else if (type == typeof(double))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransDouble(content, index);
                }
                else if (type == typeof(int))
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransInt32(content, index);
                }
                else
                {
                    pLCPoint.ResultCode = 1;
                    pLCPoint.ResultMsg = "Success";
                    pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransString(content, index, pLCPoint.DataLength, Encoding.ASCII).Replace("\0", "").Replace("\u0001", "");
                }
            }
            catch (Exception ex)
            {
                pLCPoint.ResultCode = 0;
                pLCPoint.ResultMsg = $"(读取)错误:{ex.Message}{ex.StackTrace}";
            }
        }

        /// <summary>
        /// 数据类型转换
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        private Type ConvertPointDataType(string dataType)
        {
            Type type = null;
            switch (dataType.Trim().ToLower())
            {
                case "bool":
                    type = typeof(bool);
                    break;
                case "byte":
                    type = typeof(byte);
                    break;
                case "int":
                    type = typeof(int);
                    break;
                case "datetime":
                    type = typeof(DateTime);
                    break;
                case "dint":
                    type = typeof(int);
                    break;
                case "real":
                    type = typeof(float);
                    break;
                case "lreal":
                    type = typeof(double);
                    break;
                case "lint":
                    type = typeof(long);
                    break;
                case "string":
                    type = typeof(string);
                    break;
                case "short":
                    type = typeof(short);
                    break;
                default:
                    {
                        AddSysError(SiemensS7_SamplePreparation.IpAddress, $"{dataType}数据类型不存在");
                        //throw new ArgumentOutOfRangeException(dataType, "数据类型不存在");
                        break;
                    }

            }

            return type;
        }

        /// <summary>
        /// Converts the kind of the value.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        private object? ConvertValueKind(JsonElement element)
        {
            switch (element.ValueKind)
            {
                case JsonValueKind.String: return element.GetString();
                case JsonValueKind.Null: return null;
                case JsonValueKind.False: return false;
                case JsonValueKind.True: return true;
                case JsonValueKind.Number: return element.GetDouble();
                case JsonValueKind.Object: return element.ValueKind.ToString();
                default: break;
            }

            return element;
        }

        /// <summary>
        /// Adds the system message.
        /// </summary>
        /// <param name="msg">The MSG.</param>
        private void AddSysMessage(string msg)
        {
            //logNet.WriteInfo(msg);
            _logger.LogInformation(msg);
        }

        /// <summary>
        /// Adds the system error.
        /// </summary>
        /// <param name="plcIp">The PLC ip.</param>
        /// <param name="error">The error.</param>
        private void AddSysError(string plcIp, string error)
        {
            //logNet.WriteError(plcIp, error);
            _logger.LogError(plcIp + ", error:" + error);
        }
    }
}

这段代码定义了一个名为 `SamplePreparationPlc` 的类,用于与西门子S7-1200 PLC进行通信。该类提供了读取和写入PLC点位的方法,并支持异步操作。下面是对代码的详细解释:

### 类成员变量

- `Lockobj`:一个 `object` 类型的对象,用于在写入PLC时进行锁定,防止多线程同时写入。
- `_backoff`:一个 `ExponentialBackoff` 对象,用于实现指数退避重试机制。
- `_maxRetryCount`:最大重试次数。
- `_maxRetryDelay`:最大重试延迟时间(毫秒)。
- `_baseConnectTimeOutDelay`:基础连接超时时间(毫秒)。
- `ipAddress_SamplePreparationPLC`:PLC的IP地址,从配置文件中读取,如果没有配置则使用默认值。
- `SiemensS7_SamplePreparation`:一个 `SiemensS7Net` 对象,用于与PLC进行通信。
- `_logger`:一个 `ILogger<SamplePreparationPlc>` 对象,用于记录日志。

### 构造函数

- 在构造函数中,初始化 `_logger` 对象,并创建 `SiemensS7Net` 对象,并尝试连接到PLC。如果连接失败,则记录错误日志。

### 方法

1. **PlcRead(string address, string type)**:同步读取PLC点位数据。
- 根据点位类型(如 `bool`、`float` 等)调用相应的 `Read` 方法。
- 如果读取失败,记录错误日志并抛出异常以触发重试。
- 返回读取到的数据。

2. **PlcReadAsync(string address, string type)**:异步读取PLC点位数据。
- 与 `PlcRead` 方法类似,但使用异步方法进行读取。

3. **PlcWrite(string address, object value, string type)**:同步写入PLC点位数据。
- 使用 `lock` 确保写入操作的线程安全。
- 根据点位类型调用相应的 `Write` 方法。
- 如果写入失败,记录错误日志并抛出异常以触发重试。
- 返回操作结果。

4. **PlcWriteAsync(string address, object value, string type)**:异步写入PLC点位数据。
- 与 `PlcWrite` 方法类似,但使用异步方法进行写入。

5. **BatchRead(List<PLCPointData> pointList)**:批量读取PLC点位数据。
- 将点位地址和数据长度转换为数组,调用 `Read` 方法进行批量读取。
- 根据读取到的数据,填充 `PLCPointData` 对象并返回。

6. **BatchReadAsync(List<PLCPointData> pointList)**:异步批量读取PLC点位数据。
- 与 `BatchRead` 方法类似,但使用异步方法进行读取。

7. **Write(PLCPointData pLCPoint)**:同步写入PLC点位数据。
- 使用 `lock` 确保写入操作的线程安全。
- 根据点位类型调用相应的 `Write` 方法。
- 返回操作结果。

8. **WriteAsync(PLCPointData pLCPoint)**:异步写入PLC点位数据。
- 与 `Write` 方法类似,但使用异步方法进行写入。

9. **ByteTrans(byte[] content, PLCPointData pLCPoint, int index)**:字节转换方法。
- 根据点位类型,将字节数组转换为相应的数据类型,并填充到 `PLCPointData` 对象中。

10. **ConvertPointDataType(string dataType)**:数据类型转换方法。
- 将字符串类型的数据类型转换为 `Type` 对象。

11. **ConvertValueKind(JsonElement element)**:值类型转换方法。
- 将 `JsonElement` 对象转换为相应的值类型。

12. **AddSysMessage(string msg)**:添加系统消息日志。
- 记录系统消息日志。

13. **AddSysError(string plcIp, string error)**:添加系统错误日志。
- 记录系统错误日志。

### 注意事项

- 代码中使用了 `lock` 关键字来确保写入操作的线程安全。
- 使用了指数退避重试机制来处理读取和写入操作中的异常情况。
- 日志记录使用了 `ILogger` 接口,便于日志的配置和输出。
- 代码中包含了一些异常处理逻辑,确保在发生错误时能够记录日志并重新抛出异常以触发重试。