I had idea about message parsing in serial communication, there are many kind of packets which have different form. but they're all sent by byte array.
so I thought using union to parse each message. but it's not working well. following code is the sample code which I'm In Error
[StructLayout(LayoutKind.Explicit, Size=12)]
public struct UnionPacket
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=12)]
public byte[] data;
[FieldOffset(0)]
public float Time;
[FieldOffset(4)]
public Int16 CoordX;
[FieldOffset(6)]
public Int16 CoordY;
[FieldOffset(8)]
public byte Red;
[FieldOffset(9)]
public byte Green;
[FieldOffset(10)]
public byte Blue;
[FieldOffset(11)]
public byte Alpha;
}
if this were possible, it would be very happy, but it isn't. This code occurs TypeLoadException "... because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field."
So I changed some code like this
[StructLayout(LayoutKind.Explicit, Size= 12)]
public struct UnionPacket
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
[FieldOffset(0)]
public byte[] data;
//[FieldOffset(0)]
//public float Time;
[FieldOffset(4)]
public Int16 CoordX;
[FieldOffset(6)]
public Int16 CoordY;
[FieldOffset(8)]
public byte Red;
[FieldOffset(9)]
public byte Green;
[FieldOffset(10)]
public byte Blue;
[FieldOffset(11)]
public byte Alpha;
}
for test, i just disabled Time field which offset is 0, and this didn't occur Exception. but, if i change other fields, it doesn't change byte array. i think that byte array's real memory location is allocated in other heap, so it cannot be done.
Is there any way to solve this problem in C#? only C++ or C can solve this? and if i use this with inheritance, is it possible?
P.S. Sorry about my poor english
I'm not 100% sure what you are trying to do, but:
first approach, with array stored inside of a structure is possible, if you use it with fixed/unsafe keywords. I don't know if this is possible for you. So having code like this should work:
[StructLayout(LayoutKind.Explicit, Size = 12)]
public unsafe struct UnionPacket
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
[FieldOffset(0)]
public fixed byte data[12];
[FieldOffset(0)]
public float Time;
[FieldOffset(4)]
public Int16 CoordX;
[FieldOffset(6)]
public Int16 CoordY;
[FieldOffset(8)]
public byte Red;
[FieldOffset(9)]
public byte Green;
[FieldOffset(10)]
public byte Blue;
[FieldOffset(11)]
public byte Alpha;
}
Of course, then you have to enable unsafe code blocks in VS and use wrap your structure around with it:
unsafe
{
var u = new UnionPacket();
for (byte i = 0; i < 12; i++)
{
u.data[i] = i;
}
Console.WriteLine(u.Time);
Console.WriteLine(u.CoordX);
Console.WriteLine(u.CoordY);
Console.WriteLine(u.Red);
Console.WriteLine(u.Green);
Console.WriteLine(u.Blue);
Console.WriteLine(u.Alpha);
}
Other approach would be - just forgetting about this array inside struct, and handle parsing using Marshal.Copy
:
[StructLayout(LayoutKind.Explicit, Size = 12)]
public struct UnionPacket2
{
[FieldOffset(0)]
public float Time;
[FieldOffset(4)]
public Int16 CoordX;
[FieldOffset(6)]
public Int16 CoordY;
[FieldOffset(8)]
public byte Red;
[FieldOffset(9)]
public byte Green;
[FieldOffset(10)]
public byte Blue;
[FieldOffset(11)]
public byte Alpha;
}
static void Main(string[] args)
{
var len = Marshal.SizeOf(typeof(UnionPacket2));
var buffer = new byte[len];
for (byte i = 0; i < len; i++)
{
buffer[i] = i;
}
var ptr = Marshal.AllocHGlobal(len);
Marshal.Copy(buffer, 0, ptr, len);
var u = (UnionPacket2)Marshal.PtrToStructure(ptr, typeof(UnionPacket2));
Marshal.FreeHGlobal(ptr);
Console.WriteLine(u.Time);
Console.WriteLine(u.CoordX);
Console.WriteLine(u.CoordY);
Console.WriteLine(u.Red);
Console.WriteLine(u.Green);
Console.WriteLine(u.Blue);
Console.WriteLine(u.Alpha);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With