0

Question only for C. Vectors, lists and C++ do not solving.

I have buffer with received data: (from there and further U8 is uin8_t (unsigned char) and so on)

buffer_pic

Data is packetized (it always has info about start, end and len).

Examples of data (hex):

(1 packet)

24 0C 00 02 00 00 00 11 AA 0D 78 C8

(2 packet)

24 0F 00 02 00 00 00 14 D0 07 00 00 0D 7D 53

Here:

  • '24' - start of packet

  • 2 bytes of full packet len (bold)

  • 4 bytes - special ID (here is 02 00 00 00)

  • 1 byte commad

  • DATA block (makred as bold)

  • '0D' - end of packet

  • last 2 bytes - CRC

I want to use structures to work with this data.

Here is what I did:

typedef __packed struct FM_Packet_s
{
  U8  head;
  U16 len;
  U32 uid;
  U8  cmd;
  U8  data;
  U8  end;
  U16 crc;
} FM_Packet_t, *FM_Packet_p;


U8 RX_buff[255];
  …

  FM_Packet_t *pFM_Packet = (FM_Packet_t *) &RX_buf;

  handlerData()
  {

   // check received CRC

    if(pFM_Packet->uid == ID_NUMBER)
    {
       if(pFM_Packet->cmd == NEEDED_COMMAND)
       {
          // command received, make actions

          if (pFM_Packet->data == SPECIAL_DATA)
          {
            // do stuff
          }
       }
    }
  }

Everything was good until I received 2nd packet, which have more than 1 byte in DATA field. Now data is blended

Of course, field "data" may have different length, not only as showed in this two packets.

How can I handle (place into structures correctly) received data?

tadman
  • 208,517
  • 23
  • 234
  • 262
M_V
  • 3
  • 3
  • I don't think C supports a variable length array in the middle of a structure. I think you'll just have to reference the bytes that follow directly, or define a Packet_Tail structure for them, or something else. – Rup Sep 25 '18 at 17:05
  • 2
    Don't depend on the compiler's structure arrangement. Always read in data piece by piece and store it in the structure. Reading and writing raw data structures works if and only if the structures are loaded back through same executable. If it's a new version, or different compiler settings, that structure might shift into an incompatible form. – tadman Sep 25 '18 at 17:05
  • @tadman I think that's what `__packed` is for. – Rup Sep 25 '18 at 17:06
  • @Rup I'd only trust that so much, the compiler is not going like mis-aligning values, plus there's still endian issues to deal with here. Is `__packed` a request to the compiler, or a hard requirement? – tadman Sep 25 '18 at 17:06
  • using structures across compile domains us unreliable, you should avoid this approach. looking at your packet structure there is no reason to bother with a struct, just adding risk and long term maintenance to code that would otherwise not need any. – old_timer Sep 25 '18 at 17:09
  • Given "field "data" may have different length", `U8 RX_buff[255];` is too small to hold a complete packet when 16-bit `len` is more than 255. Unless `RX_buff` can represent a sub-packet, there is no _general solution_. – chux - Reinstate Monica Sep 25 '18 at 17:29
  • Can you change `U8 data;` --> `U8 data[65535 - 11];`? or is that too big? If OK, then after reading, simply move `end,crc` to their correct location. – chux - Reinstate Monica Sep 25 '18 at 17:31
  • Why were the answers you were given in [this question](https://stackoverflow.com/questions/52497916/how-to-use-structure-with-dynamically-changing-size-of-data) not sufficient? – Eric Postpischil Sep 25 '18 at 17:45

2 Answers2

2
U8  data; 

needs to be a pointer to a buffer that's the right size to hold your data, not an unsigned integer.

You would need to allocate the buffer to be whatever size you need, before loading the data, then point the pointer to it.

You could also just make your packet buffer a lot larger and use U16 len;to figure out where the data stops.

Terry Carmen
  • 3,720
  • 1
  • 16
  • 32
  • "Is there a field in there that tells you how large the data payload is? You need one" - No, but I always know full len of data. Other parts of packet always have same sizes, so I think I can calculate payload. – M_V Sep 25 '18 at 17:10
  • There is one. I just found it. – Terry Carmen Sep 25 '18 at 17:10
  • I think this structure is the wire format, isn't it? So it's not a case of allocating a variable length buffer to store the data, it's processing data in a buffer we already have with a variable-length chunk in the middle. – Rup Sep 25 '18 at 17:11
  • @Rup The buffer is currently fixed length, and the OP is putting variable length data in it. Either the buffer needs to grow or memory needs to be allocated for the variable length portion. – Terry Carmen Sep 25 '18 at 17:13
  • @Rup You might be right. I can't find a definition for FM_Packet_s, but if it's a standard, the OP probably has it declared incorrectly. – Terry Carmen Sep 25 '18 at 17:22
  • @TerryCarmen, I cant automatically parce tail (end and crc) in case I insert U8 *data in structure – M_V Sep 25 '18 at 17:23
  • @MichaelVLV A pointer to a structure is the same size, so if you replace the U* with a U8 *, you'll always have the same size structure. – Terry Carmen Sep 25 '18 at 17:30
0

You can use the "unwarranted chumminess of C" http://computer-programming-forum.com/47-c-language/6c323b3186a9a335.htm

typedef __packed struct FM_Packet_s
{
  U8  head;
  U16 len;
  U32 uid;
  U8  cmd;
  U8  data[1];
} FM_Packet_t, *FM_Packet_p;

It uses a flexible array - the [1] is just to keep the compiler quiet. On the nit-picking compilers, you may get warnings about array sizes. If we assign pFM_Packet->len to len,

  • The size of the array is len - 11
  • The end is at &pFM_Packet->data[len - 11]
  • The CRC is at &pFM_Packet->data[len - 10]

If you are using gcc, you can use the gcc extension which allows declaration of

U8 data[0];

This is illegal in most compilers but gcc allows it.

cup
  • 7,589
  • 4
  • 19
  • 42