C#Modbus帧分割和存储程序
前提 我使用我的c#wpf应用程序以较低的间隔不断轮询来自嵌入式设备的自定义modbus帧。此时,我接收的帧中的字节每次都位于相同的位置(例如帧[15]+帧[16]=0x0532=errorcode2) 问题C#Modbus帧分割和存储程序,c#,validation,types,bytebuffer,modbus,C#,Validation,Types,Bytebuffer,Modbus,前提 我使用我的c#wpf应用程序以较低的间隔不断轮询来自嵌入式设备的自定义modbus帧。此时,我接收的帧中的字节每次都位于相同的位置(例如帧[15]+帧[16]=0x0532=errorcode2) 问题 是否有智能程序(除了简单地硬编码bytestorage)可以用于从帧接收到拆分/解析 什么样的数据结构更适合使帧能够被进一步动态处理 方法1: 您可以在C#中定义一个显式布局的结构,并像下面的代码一样将数据封送到它。然而,若您并没有在big-endian硬件上运行(Modbus数据以big
[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;
}
// 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;
}
[StructLayout(LayoutKind.Sequential,Pack=1)]
结构MyPacket
{
公共字节地址;//字节0
公共字节FunctionCode;//字节1
公共字节ByteField;//字节2
公共UInt32 UInt32字段;//字节3-6
公共UInt64 UInt64字段;//字节7-14
公共UInt16错误代码;//字节15-16
}
公共静态bool TryParse(字节[]数组,out T数据包),其中T:struct
{
尝试
{
var size=Marshal.SizeOf(typeof(T));
var p=封送。AllocHGlobal(大小);
封送处理副本(数组,0,p,大小);
packet=(T)Marshal.PtrToStructure(p,typeof(T));
弗里赫全球元帅(p);
返回true;
}
抓住
{
数据包=默认值(T);
返回false;
}
}
静态int Main(字符串[]args)
{
//创建一个示例框架
字节[]字节=新字节[]{0x0、0x01、0x02、0x03、0x04、0x05、0x06、0x07、0x08、0x09、0x10、0x11、0x12、0x13、0x14、0x15、0x16};
我的包;
if(TryParse(字节,输出数据包))
{
//在这里处理数据包。。。
}
返回0;
}
方法2:
我认为更好的解决方案是为您使用的每个函数类型定义一个类,并单独读取每个字段,如下面的代码所示。注意:假设帧已经过CRC检查,因此不需要声明和读取它
[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;
}
// 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;
}
//非常简单的BigEndianReader类
公共类BigEndianReader
{
私有流(u流),;
公共BigEndianReader(流)
{
如果(stream==null)抛出新的ArgumentNullException(nameof(stream));
如果(!stream.CanRead)抛出新的ArgumentException(nameof(stream));
_溪流=溪流;
}
公共字节ReadByte()
{
int b=_stream.ReadByte();
如果(b<0)抛出新的EndOfStreamException();
返回(字节)b;
}
公共UInt16 ReadUInt16()
{
UInt16 v=0;
对于(inti=0;i