2010-11-25 6 views
7

Je passe des paquets de données de 64 octets par USB à un microcontrôleur. Dans le code microcontrôleur C les paquets ont la structure,Comment convertir un tableau d'octets C# en données structurées?

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

avec

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; 

et

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

Du côté PC en C# Je suis muni d'une fonction qui renvoie le Un paquet de 64 octets est un octet []. La fonction utilise Marshal.Copy pour copier les données reçues dans le tableau Byte []. J'ai ensuite utilisé une struct C# de la forme

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

et Marshal.Copy utilisé à nouveau pour copier le tableau d'octets dans la structure afin que je puisse travailler avec des données structurées est comme, par exemple

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

avec

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

Cela se sent comme je fais beaucoup de copies des données et comme il pourrait ne pas être la manière la plus productive de réaliser ce que je veux. J'ai également besoin de convertir les données structurées en un tableau d'octets pour les commandes à l'appareil. J'ai une méthode qui utilise le même processus (c'est-à-dire utilise une structure puis le sérialise dans un tableau d'octets et passe le tableau d'octets à la fonction d'écriture).

Y a-t-il de meilleures alternatives?

Répondre

2

Si vous pouvez utiliser du code non sécurisé, vous pouvez convertir le tableau d'octets en pointeur vers votre structure en utilisant le mot clé 'fixed'.

+0

Dans la base de code, je travaille de la classe est déclarée dangereuse (pour permettre interaction avec les dll Win32 USB HID). Donc oui, je suppose que je pourrais. J'ai juste besoin de comprendre quelles sont les implications et les dangers de dangereux. Je l'évitais parce que je ne comprends pas encore tout à fait. –

2

Si vous appelez vous-même dll native, vous pouvez définir vos DllImport-s pour qu'ils reviennent et acceptent COMMAND_GET_ADC directement - à condition que vous ayez des structures correctement représentées. Le cadre lui-même devrait en prendre soin.

Si vous devez utiliser un tableau d'octets mandaté par l'utilisation des méthodes qui vous sont fournies - alors je ne sais pas, je n'ai jamais eu une telle contrainte. J'ai toujours essayé de représenter mes données d'interopérabilité de la même manière que dans les DLL natives et je ne me souviens pas d'avoir eu des problèmes majeurs avec ça.

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

Fondamentalement où vous avez FieldOffset (6) vous créez union comme union de données dans cmd_get_t

+0

Je ne vous suis pas à 100%. Je dois d'abord vérifier le premier octet (ID de commande), puis mapper les données à la structure appropriée. Comment cela cadrerait-il avec votre solution proposée? Pourriez-vous donner une sorte d'exemple simple (ou en désigner un)? –

+0

Voir mon édition ci-dessus - J'ai ajouté un exemple de code – Mihailo

+1

J'ai effectivement essayé ceci mais pour une raison quelconque, le fil semble se bloquer juste quand LayoutKind est défini sur explicite et j'utilise les MarshalAs pour les tableaux. Je ne l'ai pas encore compris. Merci pour l'exemple. –

Questions connexes