Search code examples
c#ethercat

How to change array reference index with don't use pointer in C#?


I'm writing code to parse packets.

I want to change the reference address of the array, but I do not know how to change the reference address without using the pointer. If I copy a part of an array, I think it will slow down. If I use a pointer, it will be unsafe.

Below is the code I am writing.

public class Datagrams : LinkedList<DatagramPacket>
{
    public Datagrams(byte[] RowData) : base()
    {
        AddLast(new DatagramPacket(RowData));
        while(Last.Value.header.Length.LastIndicator)
        {
            ///////////////////////////////////////////
            //I want do that. But this is unsafe code//
            ///////////////////////////////////////////
            AddLast(new DatagramPacket( RowData + sizeof[Last.Value] ));
        }
    }
}

public class DatagramPacket : Packet
{
    public enum DatagramCmd : Byte
    {
        NOP = 0x0,
        APRD = 0x1,
        APWR = 0x2,
        APRW = 0x3,
        FPRD = 0x4,
        FPWR = 0x5,
        FPRW = 0x6,
        BRD = 0x7,
        BWR = 0x8,
        BRW = 0x9,
        LRD = 0xA,
        LWR = 0xB,
        LRW = 0xC,
        ARMW = 0xD,
        FRMW = 0xE
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct DatagramAddr
    {
        [MarshalAs(UnmanagedType.U4), FieldOffset(0)]
        public UInt32 LogicalAddr;
        [MarshalAs(UnmanagedType.U2), FieldOffset(0)]
        public UInt16 SlaveAddr;
        [MarshalAs(UnmanagedType.U2), FieldOffset(2)]
        public UInt16 OffsetAddr;
    }

    public struct DatagramLength
    {
        [MarshalAs(UnmanagedType.U2)]
        public UInt16 bits;

        public int Length { get => bits & 0x07FF; }
        public bool Valid { get => (bits & 0x0380) == 0; }
        public bool RoundTrip { get => (bits & 0x4000) != 0; }
        public bool LastIndicator { get => (bits & 0x8000) != 0; }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct DatagramHeader
    {
        [MarshalAs(UnmanagedType.U1)]
        public DatagramCmd Cmd;
        [MarshalAs(UnmanagedType.U1)]
        public Byte Index;
        [MarshalAs(UnmanagedType.Struct)]
        public DatagramAddr Addr;
        [MarshalAs(UnmanagedType.Struct)]
        public DatagramLength Length;
        [MarshalAs(UnmanagedType.U2)]
        public UInt16 Interrupt;
    }

    public DatagramHeader header;
    public UInt16 wc;  //Working Count

    public DatagramPacket(byte[] RowData) : base(RowData)
    {
        header = new DatagramHeader();
        GCHandle handle = GCHandle.Alloc(RowData, GCHandleType.Pinned);
        try
        {
            header = (DatagramHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(DatagramHeader));
        }
        finally
        {
            handle.Free();
        }
        body = new byte[header.Length.Length];
        Buffer.BlockCopy(RowData, Marshal.SizeOf<DatagramHeader>(), body, 0, body.Length);
        wc = BitConverter.ToUInt16(RowData, Marshal.SizeOf<DatagramHeader>() + body.Length);
    }

    public override Packet Parse()
    {
        throw new NotImplementedException();
    }
}

Is there a way that change reference without using pointer?


Solution

  • I have already solved the problem by copying the array as shown below, but I think it will be slower than referring to it by any means. I tried to process packets in real time for showing graph, but should I give up real time processing as much as I use .net?

     public class Datagrams : LinkedList<DatagramPacket>
    {
        public Datagrams(byte[] RowData) : base()
        {
            AddLast(new DatagramPacket(RowData));
            while(Last.Value.header.Length.LastIndicator)
            {
                int index = Marshal.SizeOf<DatagramPacket.DatagramHeader>() + Last.Value.header.Length.Length + sizeof(UInt16);
                byte[] temp = new byte[RowData.Length - index];
                Buffer.BlockCopy(RowData, index, temp, 0, RowData.Length - index);
                RowData = temp;
                AddLast(new DatagramPacket(RowData));
            }
        }
    }