Home > Software design >  Assemble a struct from Bytes received through serial port in C#
Assemble a struct from Bytes received through serial port in C#

Time:02-26

In C I simply do a memcpy from my data buffer array to the address of my struct. I am not sure how to do this in C# for the desktop side of things. This is my struct in 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;

    }

And I have a Datareceived serial port callback, the dataIn variable below is a string but obviously I can change it something else to make it easier to grab all those bytes and assemble the frame.

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

So any suggestions are welcome.

CodePudding user response:

ok big caveat, I have no serial port so cannot test

      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);
        }
        // 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);
    }

the core is using BinaryReader this reads serialized elements from a byte stream, ReadUInt32 pulls the next 4 bytes and marshalls to a UIn32 etc.

The fiddly bit is getting the bytes from thr port into a stream since we cant connect a stream directly to the port (I coulsnt see how to do it) so I use a MemoryStream which, as the name suggests , is a byte stream in memory

CodePudding user response:

In C I simply do a memcpy from my data buffer array to the address of my struct.

I suppose the following is something similar, but I'm not in a position to test it:

[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;
            }
        }
  
    }    
}

It should allow you to just straight assign a byte array of length 18 to the struct

frame_type f = aByteArray18Long;

Of course, it is the root of all evil and a safe approach would perhaps look like:

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; it's perhaps easiest to get your bytes by something like:

var buf = new byte[18];
for(int x = 0; x<18; x  )
    buf[x] = port.Read();
  • Related