Assemble 在 C# 中通过串行端口接收到的字节结构
Assemble a struct from Bytes received through serial port in C#
在 C 中,我只是简单地从我的数据缓冲区数组执行一个 memcpy 到我的结构的地址。
我不确定如何在 C# 中为桌面端执行此操作。这是我在 C#
中的结构
struct frame_type
{
public UInt32 start_of_frame;
public UInt32 frame_id;
public UInt16 frame_len;
public UInt32 crc;
public UInt32 end_of_frame;
}
而且我有一个 Datareceived 串行端口回调,下面的 dataIn 变量是一个字符串,但显然我可以将它更改为其他内容,以便更容易地获取所有这些字节和 assemble 帧。
private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
dataIN = port.ReadExisting();
//increment variable and when i have 34 bytes assemble a frame
//and checkl if it is an ack frame.
bytes_received_count++;
if(bytes_received_count == 34)
{
//assemble a frame_type frame
}
this.Invoke(new EventHandler(sendFirmware));
}
欢迎提出任何建议。
更新:
经过一些研究,我最终得到了这段代码:
private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
for (int i = 0; i < 34; i++)
{
bytes_received[i] = (byte)port.ReadByte();
}
assemble_frame_from_port_bytes();
// this.Invoke(new EventHandler(sendFirmware));
}
public void assemble_frame_from_port_bytes()
{
frame.start_of_frame = (UInt32)(bytes_received[3] << 24 | bytes_received[2] << 16 | bytes_received[1] << 8 | bytes_received[0] << 0);
frame.frame_id = (UInt32)(bytes_received[7] << 24 | bytes_received[6] << 16 | bytes_received[5] << 8 | bytes_received[4] << 0);
frame.frame_len = (UInt16)(bytes_received[9] << 8 | bytes_received[8] << 0);
int idx = 10;
for (int i = 0; i < 16; i++)
{
payload[i] = bytes_received[idx++];
}
frame.crc = (UInt32)(bytes_received[29] << 24 | bytes_received[28] << 16 | bytes_received[27] << 8 | bytes_received[26] << 0);
frame.end_of_frame = (UInt32)(bytes_received[33] << 24 | bytes_received[32] << 16 | bytes_received[31] << 8 | bytes_received[30] << 0);
}
它完成了工作,很棒吗?我不知道,但它在这个阶段达到了目的。 C#固然是一个非常强大的工具,但在傻瓜手中它是残废的哈哈。
好的,请注意,我没有串口,所以无法测试
MemoryStream buffer = new MemoryStream();
private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) {
for (int i = 0; i < port.BytesToRead; i++) {
if (buffer.Length == 34)
break;
// write needs an array even though its only 1
byte[] bytes = new bytes[1];
bytes[0] = port.ReadByte();
buffer.Write(bytes, 0, 1);
}
if (buffer.Length == 34){
// ok we now have the next 34 bytes in buffer
var frame = new frame_type();
// rewind to the beginning
buffer.Seek(0, SeekOrigin.Begin);
using (var br = new BinaryReader(buffer)) {
frame.start_of_frame = br.ReadUInt32();
frame.frame_id = br.ReadUint32();
.......
}
// rewind to be ready for next block
buffer.Seek(0, SeekOrigin.Begin);
}
}
核心正在使用 BinaryReader,它从字节流中读取序列化元素,ReadUInt32 提取接下来的 4 个字节并编组到 UIn32 等。
由于我们不能将流直接连接到端口(我不知道如何做),所以我使用了 MemoryStream,顾名思义,它是内存中的一个字节流
In C I simply do a memcpy from my data buffer array to the address of my struct.
我想下面是类似的东西,但我无法对其进行测试:
[StructLayout(LayoutKind.Sequential)]
struct frame_type
{
public UInt32 start_of_frame;
public UInt32 frame_id;
public UInt16 frame_len;
public UInt32 crc;
public UInt32 end_of_frame;
public static implicit operator frame_type(byte[] data)
{
unsafe
{
fixed (byte* b = &data[0])
{
return *(frame_type*)b;
}
}
}
}
它应该允许您直接将长度为 18 的字节数组分配给结构
frame_type f = aByteArray18Long;
当然,它是万恶之源,安全的方法可能ps看起来像:
static public implicit operator frame_type(byte[] b)
{
var f = new frame_type();
f.start_of_frame = (uint)(b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3]);
f.frame_id = (uint)(b[4]<<24 | b[5]<<16 | b[6]<<8 | b[7]);
f.frame_len = (ushort)(b[8]<<8 | b[9]);
f.crc = (uint)(b[10]<<24 | b[11]<<16 | b[12]<<8 | b[13]);
f.end_of_frame = (uint)(b[14]<<24 | b[15]<<16 | b[16]<<8 | b[17]);
return f;
}
ps;可能 ps 最容易通过以下方式获取字节:
var buf = new byte[18];
for(int x = 0; x<18; x++)
buf[x] = port.Read();
在 C 中,我只是简单地从我的数据缓冲区数组执行一个 memcpy 到我的结构的地址。 我不确定如何在 C# 中为桌面端执行此操作。这是我在 C#
中的结构 struct frame_type
{
public UInt32 start_of_frame;
public UInt32 frame_id;
public UInt16 frame_len;
public UInt32 crc;
public UInt32 end_of_frame;
}
而且我有一个 Datareceived 串行端口回调,下面的 dataIn 变量是一个字符串,但显然我可以将它更改为其他内容,以便更容易地获取所有这些字节和 assemble 帧。
private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
dataIN = port.ReadExisting();
//increment variable and when i have 34 bytes assemble a frame
//and checkl if it is an ack frame.
bytes_received_count++;
if(bytes_received_count == 34)
{
//assemble a frame_type frame
}
this.Invoke(new EventHandler(sendFirmware));
}
欢迎提出任何建议。
更新: 经过一些研究,我最终得到了这段代码:
private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
for (int i = 0; i < 34; i++)
{
bytes_received[i] = (byte)port.ReadByte();
}
assemble_frame_from_port_bytes();
// this.Invoke(new EventHandler(sendFirmware));
}
public void assemble_frame_from_port_bytes()
{
frame.start_of_frame = (UInt32)(bytes_received[3] << 24 | bytes_received[2] << 16 | bytes_received[1] << 8 | bytes_received[0] << 0);
frame.frame_id = (UInt32)(bytes_received[7] << 24 | bytes_received[6] << 16 | bytes_received[5] << 8 | bytes_received[4] << 0);
frame.frame_len = (UInt16)(bytes_received[9] << 8 | bytes_received[8] << 0);
int idx = 10;
for (int i = 0; i < 16; i++)
{
payload[i] = bytes_received[idx++];
}
frame.crc = (UInt32)(bytes_received[29] << 24 | bytes_received[28] << 16 | bytes_received[27] << 8 | bytes_received[26] << 0);
frame.end_of_frame = (UInt32)(bytes_received[33] << 24 | bytes_received[32] << 16 | bytes_received[31] << 8 | bytes_received[30] << 0);
}
它完成了工作,很棒吗?我不知道,但它在这个阶段达到了目的。 C#固然是一个非常强大的工具,但在傻瓜手中它是残废的哈哈。
好的,请注意,我没有串口,所以无法测试
MemoryStream buffer = new MemoryStream();
private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) {
for (int i = 0; i < port.BytesToRead; i++) {
if (buffer.Length == 34)
break;
// write needs an array even though its only 1
byte[] bytes = new bytes[1];
bytes[0] = port.ReadByte();
buffer.Write(bytes, 0, 1);
}
if (buffer.Length == 34){
// ok we now have the next 34 bytes in buffer
var frame = new frame_type();
// rewind to the beginning
buffer.Seek(0, SeekOrigin.Begin);
using (var br = new BinaryReader(buffer)) {
frame.start_of_frame = br.ReadUInt32();
frame.frame_id = br.ReadUint32();
.......
}
// rewind to be ready for next block
buffer.Seek(0, SeekOrigin.Begin);
}
}
核心正在使用 BinaryReader,它从字节流中读取序列化元素,ReadUInt32 提取接下来的 4 个字节并编组到 UIn32 等。
由于我们不能将流直接连接到端口(我不知道如何做),所以我使用了 MemoryStream,顾名思义,它是内存中的一个字节流
In C I simply do a memcpy from my data buffer array to the address of my struct.
我想下面是类似的东西,但我无法对其进行测试:
[StructLayout(LayoutKind.Sequential)]
struct frame_type
{
public UInt32 start_of_frame;
public UInt32 frame_id;
public UInt16 frame_len;
public UInt32 crc;
public UInt32 end_of_frame;
public static implicit operator frame_type(byte[] data)
{
unsafe
{
fixed (byte* b = &data[0])
{
return *(frame_type*)b;
}
}
}
}
它应该允许您直接将长度为 18 的字节数组分配给结构
frame_type f = aByteArray18Long;
当然,它是万恶之源,安全的方法可能ps看起来像:
static public implicit operator frame_type(byte[] b)
{
var f = new frame_type();
f.start_of_frame = (uint)(b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3]);
f.frame_id = (uint)(b[4]<<24 | b[5]<<16 | b[6]<<8 | b[7]);
f.frame_len = (ushort)(b[8]<<8 | b[9]);
f.crc = (uint)(b[10]<<24 | b[11]<<16 | b[12]<<8 | b[13]);
f.end_of_frame = (uint)(b[14]<<24 | b[15]<<16 | b[16]<<8 | b[17]);
return f;
}
ps;可能 ps 最容易通过以下方式获取字节:
var buf = new byte[18];
for(int x = 0; x<18; x++)
buf[x] = port.Read();