2015-06-13 45 views
0

我正在嘗試設計一個數據結構(爲了節省空間,我認爲它更簡短,但我認爲您有這個想法)用於字節級通信:初始化,構造並將結構轉換爲字節數組會導致錯位

/* PACKET.H */  
#define CM_HEADER_SIZE   3 
#define CM_DATA_SIZE   16 
#define CM_FOOTER_SIZE   3 
#define CM_PACKET_SIZE  (CM_HEADER_SIZE + CM_DATA_SIZE + CM_FOOTER_SIZE) 
// + some other definitions 

typedef struct cm_header{ 
    uint8_t  PacketStart; //Start Indicator 0x5B [ 
    uint8_t  DeviceId;  //ID Of the device which is sending 
    uint8_t  PacketType; 
} CM_Header; 

typedef struct cm_footer { 
    uint16_t  DataCrc;  //CRC of the 'Data' part of CM_Packet 
    uint8_t  PacketEnd;  //should be 0X5D or ] 
} CM_Footer; 

//Here I am trying to conver a few u8[4] tp u32 (4*u32 = 16 byte, hence data size) 
typedef struct cm_data { 
    union { 
     struct{ 
     uint8_t   Value_0_0:2; 
     uint8_t   Value_0_1:2; 
     uint8_t   Value_0_2:2; 
     uint8_t   Value_0_3:2;   
     }; 
    uint32_t    Value_0; 
    }; 
    //same thing for Value_1, 2 and 3 
} CM_Data; 

typedef struct cm_packet { 
    CM_Header Header; 
    CM_Data Data; 
    CM_Footer Footer; 
} CM_Packet; 

typedef struct cm_inittypedef{ 
    uint8_t    DeviceId; 
    CM_Packet    Packet;   
} CM_InitTypeDef; 

typedef struct cm_appendresult{ 
    uint8_t Result; 
    uint8_t Reason; 
} CM_AppendResult; 

extern CM_InitTypeDef cmHandler; 

這裏的目標是爲通過USB接口傳輸數據建立可靠的結構。最後CM_Packet應該被轉換爲一個uint8_t數組,並被賦予一個單片機(stm32)的數據發送寄存器。

main.c文件我嘗試初始化結構,以及與此相關的包中一些其他的東西:

/* MAIN.C */ 
uint8_t packet[CM_PACKET_SIZE]; 
int main(void) { 
    //use the extern defined in packet.h to init the struct 
    cmHandler.DeviceId = 0x01; //assign device id 
    CM_Init(&cmHandler); //construct the handler 
    //rest of stuff 

    while(1) { 
     CM_GetPacket(&cmHandler, (uint8_t*)packet); 
     CDC_Transmit_FS(&packet, CM_PACKET_SIZE); 
    } 
} 

這裏是packet.h它搞砸了一切,所以不好實現。我添加了packet[CM_PACKET_SIZE]來觀看,但它就像是隨機生成的。有時候通過純粹的運氣,我可以在這個數組中看到我感興趣的一些值!但它就像1%的時間!

/* PACKET.C */ 
CM_InitTypeDef cmHandler; 

void CM_Init(CM_InitTypeDef *cm_initer) { 
    cmHandler.DeviceId = cm_initer->DeviceId; 

    static CM_Packet cmPacket; 
    cmPacket.Header.DeviceId = cm_initer->DeviceId; 
    cmPacket.Header.PacketStart = CM_START; 
    cmPacket.Footer.PacketEnd = CM_END; 
    cm_initer->Packet = cmPacket; 
} 

CM_AppendResult CM_AppendData(CM_InitTypeDef *handler, uint8_t identifier, 
           uint8_t *data){  

    CM_AppendResult result; 

    switch(identifier){ 
     case CM_VALUE_0: 
     handler->Packet.Data.Value_0_0 = data[0]; 
     handler->Packet.Data.Value_0_1 = data[1]; 
     handler->Packet.Data.Value_0_2 = data[2]; 
     handler->Packet.Data.Value_0_3 = data[3]; 
     break; 

     //Also cases for CM_VALUE_0, 1 , 2 
     //to build up the CM_Data sturct of CM_Packet 

    default: 
     result.Result = CM_APPEND_FAILURE; 
     result.Reason = CM_APPEND_CASE_ERROR; 
     return result; 
     break; 

    }  

    result.Result = CM_APPEND_SUCCESS; 
    result.Reason = 0x00; 
    return result; 
} 

void CM_GetPacket(CM_InitTypeDef *handler, uint8_t *packet){ 
    //copy the whole struct in the given buffer and later send it to USB host 
    memcpy(packet, &handler->Packet, sizeof(CM_PACKET_SIZE)); 
} 

所以,問題是這個代碼給了我99%的時間隨機的東西。它從不具有CM_START這是數據包的開始指示符到我想要的值。但大多數情況下,它的字節都是CM_END!我很困惑,找不到原因。正在一個難以調試的嵌入式平臺上工作,我有點迷失在這裏...

+1

提示:在沒有USB代碼的情況下(使用管道或套接字)測試您的代碼,並打包所有結構以避免類型對齊問題。使用代碼來避免字節順序問題(用文字)也是明智的。 – Gil

+0

@Gil檢查了所有函數中的'handler' ...它永遠不會正確對齊,我不認爲這是因爲USB堆棧。因爲它甚至在進入USB傳輸緩衝區之前就已經完成了...... –

+0

這正是我的觀點:如果問題不在USB com中,那麼它就在您的代碼中。然後,printf()和hexdump()是你的朋友,可以找到你做錯的地方。 – Gil

回答

1

如果您將數據傳輸到另一個(不同的)架構,不要只將結構作爲blob傳遞。這是下地獄的方式:永久性,對齊,填充字節等等都可以(也可能會)造成麻煩。

更好地使用一致的方式序列化結構,可能會使用一些解釋的控制流,因此您不必手動編寫每個字段。 (但仍然使用標準函數來生成該流)。

潛在的或可能麻煩一些地區:

  • CM_Footer:第二場可能會在32或64位邊界很好的開始,所以前述場之後,將填充。此外,該結構的結尾很可能會在32位體系結構中填充至少1個字節,以便在數組中使用正確的對齊方式(如果實際需要,編譯器不關心您)。它甚至可能是8字節對齊的。
  • CM_Header:在這裏你很可能(不保證)得到一個uint8_t與4 * 2位與排序不規範。該字段後面跟着3個未使用的字節,這是uint32_t解釋聯合所需的。
  • 如何保證主機和目標的相同字節(對於> uint8_t:高字節在前或低字節在前?)?
  • 通常,結構/聯合不需要具有相同的主機和目標佈局。即使使用相同的編譯器,它們的ABI也可能不同,等等。即使它是相同的CPU,也可能有其他系統限制。另外,對於某些CPU,存在不同的ABI(應用程序二進制接口)。
+0

非常感謝提示。我肯定不知道結構的填充。我在頁眉和頁腳中添加了一個虛擬u8,現在我看到了一些改進。我正在使用STM32F103RBT6,嘗試使用STM32庫的VCP堆棧將數據發送到PC(win 8.1 x64)。我可以繼續前進,擺脫所有這些結構,只發送ASCII,但我的觀點是要學習一些東西 –

+0

@SaeidYazdani:這不是解決方案。只需將結構序列化爲一個字節數組** **。不_依靠特定的佈局! – Olaf