2010-11-25 16 views
7

Estoy pasando paquetes de datos de 64 bytes a través de USB a un microcontrolador. En el código de microcontrolador C que los paquetes tienen la estructura,¿Cómo convierto una matriz de bytes C# en datos estructurados?

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

con

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; 

y

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

En el lado de la PC en C# me ha proporcionado con una función que devuelve el Paquete de 64 bytes como un byte []. La función utiliza Marshal.Copy para copiar los datos recibidos en la matriz Byte []. Luego utiliza un C# struct de la forma

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

y otra vez utilizado Marshal.Copy para copiar la matriz de bytes en el struct de modo que pudiera trabajar es como datos estructurados, por ejemplo

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

con

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

Esto sólo se siente como que estoy haciendo un montón de copias de los datos y, como tal vez no sea la manera más productiva de lograr lo que quiero. También necesito convertir los datos estructurados a una matriz de bytes para los comandos en el dispositivo. Tengo un método que usa el mismo proceso (es decir, usa una estructura y luego la serializa en una matriz de bytes y pasa la matriz de bytes a la función de escritura).

¿Hay mejores alternativas?

Respuesta

2

Si puede usar un código inseguro, puede convertir el conjunto de bytes en un puntero a su estructura con la palabra clave 'fija'.

+0

En la base de código que estoy trabajando desde la clase se declara insegura (para permitir interacción con el dll de USB de Win32 USB). Entonces sí, supongo que podría. Solo necesito descubrir cuáles son las implicaciones y peligros de inseguridad. Lo estaba evitando porque aún no lo entiendo del todo. –

2

Si llama usted mismo a dll nativo, podría definir sus DllImport-s para que devuelvan y acepten COMMAND_GET_ADC directamente, siempre que tenga las estructuras representadas correctamente. El marco en sí debería ocuparse de eso.

Si tiene que usar la matriz de bytes ordenada por el uso de los métodos que se le proporcionan, entonces no sé, nunca tuve esa restricción. Siempre traté de representar mis datos de interoperabilidad de la misma manera que en dlls nativos y no recuerdo haber tenido problemas importantes con eso.

EDIT:

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

Básicamente en la que han FieldOffset (6) que está creando la unión como unión de datos en cmd_get_t

+0

No te sigo al 100%. Necesito verificar primero el primer byte (ID del comando) y luego asignar los datos a la estructura apropiada. ¿Cómo encajaría esto con su solución propuesta? ¿Podría dar algún tipo de ejemplo simple (o señalarme a uno)? –

+0

Ver mi edición anterior - Agregué un código de muestra – Mihailo

+1

En realidad lo intenté pero por alguna razón el hilo parece que se cuelga cuando LayoutKind se establece en explícito y yo uso MarshalAs para las matrices. No lo he descubierto todavía. Gracias por el ejemplo. –

Cuestiones relacionadas