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();