Есть структура данных (С#) необходимо принимая данные из SerialPort записать их в структуру побайтно.
Код объявления структуры (VS2010) Структура упакована побайтно, размер соответствует.
:
// ------------------ telemetry data structures
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BMS // BMS telemetry data
{
public ushort voltage;
public short current;
public sbyte temperature;
public byte status;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MOTOR // Traction MOTOR telemetry data
{
sbyte acceleration;
short current;
short speed;
sbyte motor_temp;
sbyte controller_temp;
byte status;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct GENERATOR // Gasoline GENERATOR telemetry data
{
byte fuel_level;
short speed;
short current;
ushort voltage;
sbyte motor_temp;
sbyte generator_temp;
sbyte controller_temp;
byte status;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CABLE_REEL // CABLE REEL telemetry data
{
sbyte force;
short speed;
sbyte motor_temp;
sbyte controller_temp;
byte status;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UTP_TELEMETRY // UTP-1 telemetry packet struct
{
public BMS bms1;
public BMS bms2;
public MOTOR left_motor;
public MOTOR right_motor;
public GENERATOR generator;
public CABLE_REEL reel;
}
//UTP_TELEMETRY packet;
int packet_data_len = Marshal.SizeOf(typeof(UTP_TELEMETRY)); // number of bytes for data (45 bytes at the moment)
// defines exactly as union in C++
[StructLayout(LayoutKind.Explicit, Size=45)]
public struct UNION_BUFF
{
[FieldOffset(0)]
public byte buff;
//public byte[] buff;
[FieldOffset(0)]
public UTP_TELEMETRY data_packet;
}
public UNION_BUFF data_buffer;
проект unsafe, разные способы испытал, но не знаю тонкостей работы с указателями С#, ничего не получается. пробовал запись по указателю, по индексу buff[index], еще несколько разных идей и все никак. Как необходимо организовать запись побайтно в данную структуру?
Ну например, для структур, состоящих только из примитивных полей, подойдёт такой хелпер:
static void FillFromStream<T>(ref T t, Stream stream) where T : struct
{
object boxed = t;
using (var br = new BinaryReader(stream, Encoding.ASCII, leaveOpen: true))
{
var fields = typeof(T).GetFields().OrderBy(f => f.MetadataToken);
foreach (var field in fields)
{
if (!field.FieldType.IsPrimitive)
throw new NotImplementedException("nested compound types");
// for primitive types:
if (!primitiveExtractors.TryGetValue(field.FieldType, out var extractor))
throw new NotImplementedException("unsupported primitive type");
var value = extractor(br);
field.SetValue(boxed, value);
}
}
t = (T)boxed;
}
Вспомогательная таблица:
static Dictionary<Type, Func<BinaryReader, object>> primitiveExtractors =
new Dictionary<Type, Func<BinaryReader, object>>()
{
[typeof(sbyte)] = br => br.ReadSByte(),
[typeof(byte)] = br => br.ReadByte(),
[typeof(short)] = br => br.ReadInt16(),
[typeof(ushort)] = br => br.ReadUInt16(),
[typeof(int)] = br => br.ReadInt32(),
[typeof(uint)] = br => br.ReadUInt32(),
[typeof(long)] = br => br.ReadInt64(),
[typeof(ulong)] = br => br.ReadUInt64(),
[typeof(float)] = br => br.ReadSingle(),
[typeof(double)] = br => br.ReadDouble()
};
Как вы видите, без unsafe
и прочих небезопасных методов можно обойтись.
Не забудьте открыть доступ у полям.
.OrderBy(f => f.MetadataToken)
нужно для того, чтобы порядок полей соответствовал текстуальному порядку.
Например, используя Marshal.PtrToStructure:
object ByteArrayToStructure(byte[] bytearray, Type t)
{
if (t.IsValueType == false) throw new ArgumentException("Type is not structure");
IntPtr p = IntPtr.Zero;
object obj = null;
try
{
int len = Marshal.SizeOf(t);
p = Marshal.AllocHGlobal(len);
Marshal.Copy(bytearray, 0, p, len);
obj = Marshal.PtrToStructure(p, t);
}
finally
{
if (p != IntPtr.Zero) Marshal.FreeHGlobal(p);
}
return obj;
}
/*...*/
byte[] arr = /*Считать массив байт из потока*/;
MyStruct s = (MyStruct)ByteArrayToStructure(arr,typeof(MyStruct));
Или как-то так (извращенный способ, но не требует выделения промежуточного блока памяти):
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MyStruct
{
/*Список полей*/
short x;
short y;
sbyte a;
byte b;
/*Статические методы*/
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
private static extern void CopyMemory(
[In, Out] ref MyStruct dest,
[MarshalAs(UnmanagedType.LPArray)] byte[] src,
int count);
public static MyStruct ByteArrayToStructure(byte[] bytearray)
{
MyStruct obj = new MyStruct();
CopyMemory(ref obj, bytearray, bytearray.Length);
return obj;
}
}
/*...*/
byte[] arr = /*Считать массив байт из потока*/;
MyStruct s = MyStruct.ByteArrayToStructure(arr);
Виртуальный выделенный сервер (VDS) становится отличным выбором
Использую RichTextBoxНужно, что бы каждая новая строка была своего цвета, например:
Я новичек в програмировании, не до конца понимаю методы классы и обьектыМне нужно: Подключитесь к локальному SQL-серверу с помощью C # и загрузите...
Программа работает, сохраняет в БД и достает данные из, в вкладке Обозреватель SQL Server не отображаетсяКак и где можно ее найти?