簡體   English   中英

如何使用具有動態變化的數據大小的結構?

[英]How to use structure with dynamically changing size of data?

僅針對C的問題,C ++和向量不能解決問題。

我有這樣的結構:

typedef __packed struct Packet_s
{
  U8  head;
  U16 len;
  U32 id;
  U8  data;
  U8  end;
  U16 crc;
} Packet_t, *Packet_p;

編輯 :U8是uint8_t(unsigned char)等)

例如,我收到了packet(hex):

24 0B 00 07 00 00 00 AA 0D 16 1C

哪里

頭= 0x24

len = 0x0B 0x00

id = 0x07 0x00 0x00 0x00

數據= 0xAA

結束= 0x0D

crc = 0x16 0x1C

我可以這樣從傳入緩沖區復制它

U8 Buffer[SIZE]; // receives all bytes here
memcpy(&Packet, &Buffer, buffer_len);

並繼續努力。

如果字段“ DATA”長於1個字節,是否可以使用我的結構?

我該如何處理這樣的事情?

24 0F 00 07 00 00 00 AA BB CC DD EE 0D BD 66

數據包的長度將始終為已知(2和3個字節具有有關長度的信息)。

編輯:在“句柄”下,我的意思是我想下一步:

  if (isCRCmatch() )
  {
    if(Packet.id == SPECIAL_ID_1)
    {
      // do something
    }

    if(Packet.id == SPECIAL_ID_2)
    {
      // do other 
    }

    if(Packet.data[0] == 0xAA)
    {
      // do one stuff
    }

    if(Packet.data[1] == 0xBB && Packet.id == SPECIAL_ID_3 )
    {
      // do another stuff
    }

  }

並且(如果可能的話,我也想)使用相同的結構發送“ anwers”:

U8 rspData[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};

SendResponce(Packet.id, rspData);

void SendResponce (U8 id_rsp, uint8_t* data_rsp)
{
  Packet_t ResponceData;
  uint16_t crc;
  uint8_t *data;

  ResponceData.head  = 0x24;
  ResponceData.len   = sizeof(ResponceData); // HERE IS PROBLEM ONE
  ResponceData.id   = id_rsp;
  ResponceData.data  = *data_rsp; // HERE IS PROBLEM TWO
  ResponceData.end   = 0x0D; // symbol '\r'

  data = (uint8_t*)&ResponceData;
  crc = GetCrc(data, sizeof(ResponceData)-2); // last 2 bytes with crc

  ResponceData.crc = crc;//(ack_crc >> 8 | ack_crc);

  SendData((U8*)&ResponceData, sizeof(ResponceData));  // Send rsp packet
}

第一個問題-我無法自動獲得所有結構的大小,因為指針將始終為4個字節...第二個問題-我確定我會丟失rsp數據,因為我不知道它的結尾。

您不能在結構中間使用動態緩沖區。

解決該問題的另一種方法是將結構分為兩部分。 例如(注意,這里的data是一個靈活的數組成員 ):

typedef __packed struct Packet_s
{
  U8  head;
  U16 len;
  U32 id;
  U8  data[];
} Packet_t, *Packet_p;

typedef __packed struct PacketEnd_s
{
  U8  end;
  U16 crc;
} PacketEnd_t, *PacketEnd_p;

然后使用

Packet_t *pPacket = (Packet_t *)&Buffer;
PacketEnd_t *pPacketEnd = (PacketEnd_t *)( count pointer here by using pPacket->len );

假設__packed允許使用對__packed結構成員的未對齊訪問。

如果字段“ DATA”長於1個字節,是否可以使用我的結構?

不可以,因為它只能容納1個data字節。 但是您可以使用略微修改的結構版本。

typedef __packed struct Packet_s
{
  U8  head;
  U16 len;
  U32 id;
  U8  data[DATALENMAX]; // define appropriately
  U8  end;
  U16 crc;
} Packet_t, *Packet_p;

當然,您必須相應地調整復制:

memcpy(&Packet, &Buffer, buffer_len), memmove(&Packet.end, &Packet.data[buffer_len-7-3], 3);

關於增加的問題,有必要將數據長度傳遞給SendResponce()

SendResponce(rspData, sizeof rspData);

void SendResponce(uint8_t* data_rsp, int datalen)
{
  Packet_t ResponceData;
  uint16_t crc;
  uint8_t *data;

  ResponceData.head  = 0x24;
  ResponceData.len   = 7+datalen+3; // HERE WAS PROBLEM ONE
  ResponceData.id   = SPECIAL_ID_X;
  memcpy(ResponceData.data, data_rsp, datalen); // HERE WAS PROBLEM TWO
  ResponceData.data[datalen] = 0x0D; // symbol '\r'
  data = (uint8_t*)&ResponceData;
  crc = GetCrc(data, 7+datalen+1); // last 2 bytes with crc
  ResponceData.crc = crc;//(ack_crc >> 8 | ack_crc);
  memmove(ResponceData.data+datalen+1, &ResponceData.crc, 2);
  SendData((U8*)&ResponceData, ResponceData.len);  // Send rsp packet
}

您應該將處理功能分為兩個不同的功能:

  • 一種將丟棄所有內容,直到找到head字節為止。 該字節通常是一個恆定字節,標記數據包的開始。 這樣做是為了避免在先前發送的數據包中間開始讀取(請考慮發送者和偵聽器設備的啟動順序)。

    一旦找到數據包的開始,它就可以讀取標頭, lenid並將接收到的所有數據存儲到您的Buffer變量中,直到讀取end字節或緩沖區溢出為止,在這種情況下,它只會丟棄數據,然后重新開始。

    注意,僅應將實際數據寫入Buffer變量。 其他所有字段(len,id等)可以存儲在不同的變量中,也可以存儲在僅包含Packet information但不包含數據的結構中。 這樣,您可以從傳輸信息中吐出應用程序數據。

    還要注意,此函數既不解釋id字段,也不解釋data字段。 它只是將此信息發送到另一個函數,如果iddata不正確/未知,它將進行處理或丟棄。

  • 一旦找到end字節,就可以將信息傳遞給實際的processing功能。 它的標頭類似於:

     void processPacket(U8 *data, U32 id, U16 len); 

    對其的調用將是:

     void receiveFrame() { //Receive head //Receive id //Receive len //Fill in Buffer with the actual data //Call the processPacket function processPacket(&Buffer[0], id, len); } 

一個更完整的示例可能是:

//It is not packet, since you fill it reading from the buffer and assigning
//to it, not casting the buffer into it.
//It has no data field. The data is in a different variable.
typedef struct Packet_s
{
    U8  head;
    U16 len;
    U32 id;
    U8  end;
    U16 crc;
} PacketInfo_t;

U8 Buffer[MAX_BUFFER_SIZE];
PacketInfo_t info;
void receiveFrame() {
    info.head=//Receive head
    info.len=//Receive len
    info.id=//Receive id
    //Fill the buffer variable
    processPacket(&Buffer[0], &info);
}
void processPacket(U8 *data, PacketInfo_t *info);

對於發送,只需使用相同的格式:

void sendPacket(U8 *data, PacketInfo_t *info);

該函數根據info准備Packet頭,並從data讀取data


最后,要提一個警告:將接收到的數據包直接投射(或存儲)到結構中絕不是一個好主意。 您不僅要考慮零孔(使用__packet屬性),還要考慮發送方和接收方系統的字節序和數據格式表示,因為如果它們不同,那么最終將得到錯誤的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM