首页 > 其他分享 >S7.NET读写西门子字符串处理

S7.NET读写西门子字符串处理

时间:2022-11-11 21:14:38浏览次数:40  
标签:string S7 读写 bytes length reservedLength new NET

S7.NET读写西门子字符串处理

由于西门子字符串存储跟C#字符串的存储格式不一样,在与西门子通讯时,在解析/编码字符串时需要特殊处理。在没有看到S7.NET开源库前,一直都在琢磨怎么处理好,也一直没有想到很合理的解决办法,只能怪自己的水平不行。直到看到S7.NET采用特性的办法来处理,才眼前一亮。

S7.NET字符串的特性代码如下:

using System;

namespace S7.Net.Types
{
    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
    public sealed class S7StringAttribute : Attribute
    {
        private readonly S7StringType type;
        private readonly int reservedLength;

        /// <summary>
        /// Initializes a new instance of the <see cref="S7StringAttribute"/> class.
        /// </summary>
        /// <param name="type">The string type.</param>
        /// <param name="reservedLength">Reserved length of the string in characters.</param>
        /// <exception cref="ArgumentException">Please use a valid value for the string type</exception>
        public S7StringAttribute(S7StringType type, int reservedLength)
        {
            if (!Enum.IsDefined(typeof(S7StringType), type))
                throw new ArgumentException("Please use a valid value for the string type");

            this.type = type;
            this.reservedLength = reservedLength;
        }

        /// <summary>
        /// Gets the type of the string.
        /// </summary>
        /// <value>
        /// The string type.
        /// </value>
        public S7StringType Type => type;

        /// <summary>
        /// Gets the reserved length of the string in characters.
        /// </summary>
        /// <value>
        /// The reserved length of the string in characters.
        /// </value>
        public int ReservedLength => reservedLength;

        /// <summary>
        /// Gets the reserved length in bytes.
        /// </summary>
        /// <value>
        /// The reserved length in bytes.
        /// </value>
        public int ReservedLengthInBytes => type == S7StringType.S7String ? reservedLength + 2 : (reservedLength * 2) + 4;
    }


    /// <summary>
    /// String type.
    /// </summary>
    public enum S7StringType
    {
        /// <summary>
        /// ASCII string.
        /// </summary>
        S7String = VarType.S7String,

        /// <summary>
        /// Unicode string.
        /// </summary>
        S7WString = VarType.S7WString
    }
}

解码与编码字符串代码如下:

using System;
using System.Text;

namespace S7.Net.Types
{
    /// <summary>
    /// Contains the methods to convert from S7 strings to C# strings
    /// An S7 String has a preceeding 2 byte header containing its capacity and length
    /// </summary>
    public static class S7String
    {
        private static Encoding stringEncoding = Encoding.ASCII;

        /// <summary>
        /// The Encoding used when serializing and deserializing S7String (Encoding.ASCII by default)
        /// </summary>
        /// <exception cref="ArgumentNullException">StringEncoding must not be null</exception>
        public static Encoding StringEncoding
        {
            get => stringEncoding;
            set => stringEncoding = value ?? throw new ArgumentNullException(nameof(StringEncoding));
        }

        /// <summary>
        /// Converts S7 bytes to a string
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string FromByteArray(byte[] bytes)
        {
            if (bytes.Length < 2)
            {
                throw new PlcException(ErrorCode.ReadData, "Malformed S7 String / too short");
            }

            int size = bytes[0];
            int length = bytes[1];
            if (length > size)
            {
                throw new PlcException(ErrorCode.ReadData, "Malformed S7 String / length larger than capacity");
            }

            try
            {
                return StringEncoding.GetString(bytes, 2, length);
            }
            catch (Exception e)
            {
                throw new PlcException(ErrorCode.ReadData,
                    $"Failed to parse {VarType.S7String} from data. Following fields were read: size: '{size}', actual length: '{length}', total number of bytes (including header): '{bytes.Length}'.",
                    e);
            }
        }

        /// <summary>
        /// Converts a <see cref="T:string"/> to S7 string with 2-byte header.
        /// </summary>
        /// <param name="value">The string to convert to byte array.</param>
        /// <param name="reservedLength">The length (in characters) allocated in PLC for the string.</param>
        /// <returns>A <see cref="T:byte[]" /> containing the string header and string value with a maximum length of <paramref name="reservedLength"/> + 2.</returns>
        public static byte[] ToByteArray(string value, int reservedLength)
        {
            if (value is null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            if (reservedLength > 254) throw new ArgumentException($"The maximum string length supported is 254.");

            var bytes = StringEncoding.GetBytes(value);
            if (bytes.Length > reservedLength) throw new ArgumentException($"The provided string length ({bytes.Length} is larger than the specified reserved length ({reservedLength}).");

            var buffer = new byte[2 + reservedLength];
            Array.Copy(bytes, 0, buffer, 2, bytes.Length);
            buffer[0] = (byte)reservedLength;
            buffer[1] = (byte)bytes.Length;
            return buffer;
        }
    }
}

在处理Class中使用方法如下:

using System;
using System.Text;

namespace S7.Net.Types
{
    /// <summary>
    /// Contains the methods to convert from S7 strings to C# strings
    /// An S7 String has a preceeding 2 byte header containing its capacity and length
    /// </summary>
    public static class S7String
    {
        private static Encoding stringEncoding = Encoding.ASCII;

        /// <summary>
        /// The Encoding used when serializing and deserializing S7String (Encoding.ASCII by default)
        /// </summary>
        /// <exception cref="ArgumentNullException">StringEncoding must not be null</exception>
        public static Encoding StringEncoding
        {
            get => stringEncoding;
            set => stringEncoding = value ?? throw new ArgumentNullException(nameof(StringEncoding));
        }

        /// <summary>
        /// Converts S7 bytes to a string
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string FromByteArray(byte[] bytes)
        {
            if (bytes.Length < 2)
            {
                throw new PlcException(ErrorCode.ReadData, "Malformed S7 String / too short");
            }

            int size = bytes[0];
            int length = bytes[1];
            if (length > size)
            {
                throw new PlcException(ErrorCode.ReadData, "Malformed S7 String / length larger than capacity");
            }

            try
            {
                return StringEncoding.GetString(bytes, 2, length);
            }
            catch (Exception e)
            {
                throw new PlcException(ErrorCode.ReadData,
                    $"Failed to parse {VarType.S7String} from data. Following fields were read: size: '{size}', actual length: '{length}', total number of bytes (including header): '{bytes.Length}'.",
                    e);
            }
        }

        /// <summary>
        /// Converts a <see cref="T:string"/> to S7 string with 2-byte header.
        /// </summary>
        /// <param name="value">The string to convert to byte array.</param>
        /// <param name="reservedLength">The length (in characters) allocated in PLC for the string.</param>
        /// <returns>A <see cref="T:byte[]" /> containing the string header and string value with a maximum length of <paramref name="reservedLength"/> + 2.</returns>
        public static byte[] ToByteArray(string value, int reservedLength)
        {
            if (value is null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            if (reservedLength > 254) throw new ArgumentException($"The maximum string length supported is 254.");

            var bytes = StringEncoding.GetBytes(value);
            if (bytes.Length > reservedLength) throw new ArgumentException($"The provided string length ({bytes.Length} is larger than the specified reserved length ({reservedLength}).");

            var buffer = new byte[2 + reservedLength];
            Array.Copy(bytes, 0, buffer, 2, bytes.Length);
            buffer[0] = (byte)reservedLength;
            buffer[1] = (byte)bytes.Length;
            return buffer;
        }
    }
}

字符串使用方式,使用特性指定字符串长度:

        [S7String(S7StringType.S7WString, 10)] 
        public string WStringVariable;


        [S7String(S7StringType.S7String, 10)]
        public string StringVariable;

大家如果有更好的办法,欢迎评论!

标签:string,S7,读写,bytes,length,reservedLength,new,NET
From: https://www.cnblogs.com/slowly-snail/p/16882000.html

相关文章

  • netfilter/iptables 简介(转载)
    from:http://www.ibm.com/developerworks/cn/linux/network/s-netip/netfilter/iptables是与最新的2.4.x版本Linux内核集成的IP信息包过滤系统。如果Lin......
  • .net Elasticsearch 学习入门笔记
    .netElasticsearch(es)学习入门笔记及简要总结。一.es安装相关1.elasticsearch安装运行http://localhost:9200/2.head插件3.bigdesk插件安装(安装细节百度:windows......
  • .net 大型分布式电子商务架构说明
    构建具备高可用,高扩展性,高性能,能承载高并发,大流量的.net分布式电子商务平台的架构说明。其中包含基础框架沉淀,分库分表,基础服务架构(消息队列,任务调度......
  • 篇(3)-Asp.Net Core入门实战-数据库配置说明
    入门实战-创建数据库和安装NuGet软件包注意,我们用到asp.netcore新功能中的所谓CodeFirst或者DbFirst,我们先不管这功能,为了快速上手简单功能,我计划使用EF(微软新的数据......
  • 【DL经典论文精读】ResNet
    Abstract利用残差学习架构释放深度152层深度是VGG的8倍,且复杂度更低ImageNet上的错误率3.57%在ILSVRC和2015COCO竞赛,在多项任务拿到第一 3.1Introductio......
  • 【DL经典论文精读笔记】AlexNet
    1.1引言1.2数据集就是ImageNet,当时计算机视觉最大的数据集1.3结构  采用双GPU结构实现,并行处理图像,2-3,5-全连接部分中间还将特征图共享最后全连接层输出的4096......
  • Linux Centos7 部署步骤 mysql
    0.首先查看cpu架构uname-a输出内容中有关键词ARM或aarch64就是ARM架构,有关键词x86_64就是X86架构1.下载mysql8(https://dev.mysql.com/)选择 RedHat......
  • 紧急通知,Citrix Netscaler 13.1.33.52之前版本存在的安全隐患问题
    一、前言:在CitrixGateway和CitrixADC中发现了下面列出的漏洞。请注意,只有作为网关运行的设备(SSLVPN、ICA代理、CVPN、RDP代理)才会受到第一个问题的影响,该问题被评......
  • ASP.Net Core Web 在IIS下的发布流程
    1.新建项目,选择Asp.NETWeb应用程序2.选择Web应用程序(模型视图控制器)3.鼠标右键项目,选择【发布】4.选择【IIS、FTP等】5.发布方法选择【文件......
  • 使用NSP机制解决windows7 dns溯源问题
    挂钩(hook)具体的接口函数,比如挂钩(hook)gethostbyname接口等函数。这些接口函数可不止gethostbyname,还包括getaddrinfo,WSALookupServiceBegin,WSALookupServiceNext,DnsQuery_X......