前提
我不断地从嵌入式设备中轮询自定义modbus帧,并且我的c# wpf应用程序间隔很低。目前,我接收到的帧中的字节每次都位于相同的位置(例如,frame15+frame16 = 0x0532 = errorcode2)。
问题
发布于 2018-08-24 18:44:43
方法1:
您可以在C#中定义显式布局的结构,并对数据进行封送,就像在下面的代码中所做的那样。但是,如果您没有在大终端硬件上运行(Modbus数据以大端发送),则由于endian排序,您将在数据方面出现问题。这也不会处理可变长度的Modbus数据包(即读取输入寄存器)。注意:假设框架已经被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;
}方法2:
我认为更好的解决方案是为您使用的每个函数类型定义一个类,并按下面的代码分别读取每个字段。注意:假设框架已经被CRC检查过,所以没有必要声明和读取它。
// 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;
}https://stackoverflow.com/questions/51962899
复制相似问题