Как преобразовать байтовый массив C # в структурированные данные? - PullRequest
7 голосов
/ 25 ноября 2010

Я передаю 64-байтовые пакеты данных через USB на микроконтроллер.В коде C микроконтроллера пакеты имеют структуру,

typedef union
{
    unsigned char data[CMD_SIZE];
    cmd_get_t get;
    // plus more union options
} cmd_t;

с

typedef struct
{
    unsigned char cmd;          //!< Command ID
    unsigned char id;           //!< Packet ID
    unsigned char get_id;       //!< Get identifier
    unsigned char rfu[3];       //!< Reserved for future use
    union
    {
        unsigned char data[58];     //!< Generic data
        cmd_get_adc_t adc;          //!< ADC data
        // plus more union options
    } data;                     //!< Response data
} cmd_get_t;

и

typedef struct
{
    int16_t supply;
    int16_t current[4];
} cmd_get_adc_t;

На стороне ПК в C # я предоставлялс функцией, которая возвращает 64-байтовый пакет в виде байта [].Функция использует Marshal.Copy для копирования полученных данных в массив Byte [].Затем я использовал C # структуру вида

[StructLayout(LayoutKind.Sequential, Pack=1)]
    public struct COMMAND_GET_ADC
    {
        public byte CommandID;
        public byte PacketID;
        public byte GetID;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
            public byte[] RFU;
        public short Supply;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
            public short[] Current;
    }

и снова использовал Marshal.Copy, чтобы скопировать байтовый массив в структуру, чтобы я мог работать как структурированные данные, например,

COMMAND_GET_ADC cmd = (COMMAND_GET_ADC)RawDeserialize(INBuffer, 1, typeof(COMMAND_GET_ADC));
short supply = cmd.Supply;

с

public static object RawDeserialize(Byte[] rawData, int position, Type anyType)
{
    int rawsize = Marshal.SizeOf(anyType);
    if(rawsize > rawData.Length)
    {
        return null;
    }
    IntPtr buffer = Marshal.AllocHGlobal(rawsize);
    Marshal.Copy(rawData, position, buffer, rawsize);
    object retobj = Marshal.PtrToStructure(buffer, anyType);
    Marshal.FreeHGlobal(buffer);
    return retobj;
}

Такое ощущение, что я делаю много копий данных и, возможно, это не самый продуктивный способ достижения того, чего я хочу.Мне также нужно преобразовать структурированные данные обратно в байтовый массив для команд на устройство.У меня есть метод, который использует тот же процесс (то есть использовать структуру, а затем сериализовать ее в байтовый массив и передать байтовый массив в функцию записи).

Есть ли лучшие альтернативы?

Ответы [ 2 ]

2 голосов
/ 25 ноября 2010

Если вы сами вызываете native dll, вы можете определить свои DllImport-ы, чтобы они возвращались и принимали COMMAND_GET_ADC напрямую - при условии, что у вас правильно представлены структуры.Сам фреймворк должен позаботиться об этом.

Если вам нужно использовать байтовый массив, предписанный использованием предоставленных вам методов - тогда я не знаю, у меня никогда не было такого ограничения.Я всегда пытался представлять свои данные о взаимодействии так же, как в родных библиотеках, и я не помню, чтобы у меня были серьезные проблемы с этим.

РЕДАКТИРОВАТЬ:

[StructLayout(LayoutKind.Explicit)]
public struct COMMAND_GET
{
    [FieldOffset(0)]
    public byte CommandID;
    [FieldOffset(1)]
    public byte PacketID;
    [FieldOffset(2)]
    public byte GetID;
    [FieldOffset(3)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
    public byte[] RFU;
    [FieldOffset(6)]
    public ADC_Data Adc_data;
    [FieldOffset(6)]
    public SomeOther_Data other_data;
    [FieldOffset(6)]
    ....
}


[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct ADC_Data
{
    public short Supply;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
    public short[] Current;
}

В основном там, где выFieldOffset (6) вы создаете объединение как объединение данных в cmd_get_t

2 голосов
/ 25 ноября 2010

Если вы можете использовать небезопасный код, вы можете привести байтовый массив к указателю на вашу структуру, используя ключевое слово «fixed».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...