首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C# Modbus帧分割和存储过程

C# Modbus帧分割和存储过程
EN

Stack Overflow用户
提问于 2018-08-22 08:40:32
回答 1查看 278关注 0票数 1

前提

我不断地从嵌入式设备中轮询自定义modbus帧,并且我的c# wpf应用程序间隔很低。目前,我接收到的帧中的字节每次都位于相同的位置(例如,frame15+frame16 = 0x0532 = errorcode2)。

问题

  1. 我是否可以使用智能过程(除了简单地硬编码字节存储)从帧接收到拆分/解析?
  2. 什么样的数据结构会更好地使帧能够更深入地动态处理?
EN

回答 1

Stack Overflow用户

发布于 2018-08-24 18:44:43

方法1:

您可以在C#中定义显式布局的结构,并对数据进行封送,就像在下面的代码中所做的那样。但是,如果您没有在大终端硬件上运行(Modbus数据以大端发送),则由于endian排序,您将在数据方面出现问题。这也不会处理可变长度的Modbus数据包(即读取输入寄存器)。注意:假设框架已经被CRC检查过,所以没有必要声明和读取它。

代码语言:javascript
复制
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyPacket
{
    public Byte Address;        // Byte 0
    public Byte FunctionCode;   // Byte 1
    public Byte ByteField;      // Byte 2
    public UInt32 UInt32Field;  // Bytes 3-6
    public UInt64 UInt64Field;  // Byte 7-14
    public UInt16 ErrorCode;    // Bytes 15-16
}

public static bool TryParse<T>(byte[] array, out T packet) where T : struct
{
    try
    {
        var size = Marshal.SizeOf(typeof(T));
        var p = Marshal.AllocHGlobal(size);
        Marshal.Copy(array, 0, p, size);
        packet = (T)Marshal.PtrToStructure(p, typeof(T));
        Marshal.FreeHGlobal(p);
        return true;
    }
    catch
    {
        packet = default(T);
        return false;
    }
}

static int Main(string[] args)
{
    // Create a sample frame
    byte[] bytes = new byte[] { 0x0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };

    MyPacket packet;

    if (TryParse<MyPacket>(bytes, out packet))
    {
        // Process packet here...
    }

    return 0;
}

方法2:

我认为更好的解决方案是为您使用的每个函数类型定义一个类,并按下面的代码分别读取每个字段。注意:假设框架已经被CRC检查过,所以没有必要声明和读取它。

代码语言:javascript
复制
// VERY SIMPLE BigEndianReader class
public class BigEndianReader
{
    private Stream _stream;

    public BigEndianReader(Stream stream)
    {
        if (stream == null) throw new ArgumentNullException(nameof(stream));
        if (!stream.CanRead) throw new ArgumentException(nameof(stream));
        _stream = stream;
    }
    public byte ReadByte()
    {
        int b = _stream.ReadByte();
        if (b < 0) throw new EndOfStreamException();
        return (byte)b;
    }

    public UInt16 ReadUInt16()
    {
        UInt16 v = 0;
        for (int i = 0; i < sizeof(UInt16); i++){v <<= 8;v |= ReadByte();}
        return v;
    }

    public UInt32 ReadUInt32()
    {
        UInt32 v = 0;
        for (int i = 0; i < sizeof(UInt32); i++){v <<= 8;v |= ReadByte();}
        return v;
    }

    public UInt64 ReadUInt64()
    {
        UInt64 v = 0;
        for (int i = 0; i < sizeof(UInt64); i++) { v <<= 8; v |= ReadByte(); }
        return v;
    }
}

class MyPacket
{
    public Byte Address { get; private set; }
    public Byte FunctionCode { get; private set; }
    public Byte ByteField { get; private set; }
    public UInt32 UInt32Field { get; private set; }
    public UInt64 UInt64Field { get; private set; }
    public UInt16 ErrorCode { get; private set; }

    public static bool TryParse(byte[] bytes, out MyPacket result)
    {
        result = null;

        try
        {
            BigEndianReader r = new BigEndianReader(new MemoryStream(bytes));
            MyPacket p = new MyPacket();
            p.Address = r.ReadByte();
            p.FunctionCode = r.ReadByte();
            p.ByteField = r.ReadByte();
            p.UInt32Field = r.ReadUInt32();
            p.UInt64Field = r.ReadUInt64();
            p.ErrorCode = r.ReadUInt16();
            result = p;
            return true;
        }
        catch
        {
            return false;
        }
    }
}

static int Main(string[] args)
{
    // Create a sample frame
    byte[] bytes = new byte[] { 0x0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 };

    MyPacket packet;

    if (MyPacket.TryParse(bytes, out packet))
    {
        // Process packet here...
    }

    //==================================================================
    Console.Write("(press any key to exit)");
    Console.ReadKey(true);
    return 0;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51962899

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档