describe protocol format in struct - c

I would like to directly assign a byte array to a struct in C. The protocol looks like this(yes I know this is not compiling because flexlible arrays are only allowed as the last element of a struct)
struct telegram{
uint8_t controll;
uint16_t src_addr;
uint16_t dst_addr;
uint8_t is_group_addr :1;
uint8_t routing_cnt :3;
uint8_t data_len :3;
uint8_t data[];
uint8_t chksum;
};
how could I solve that? I like that I can directly access the field within the protocol very easy with a struct. The easy way would be to to say the last element of the data[] is the checksum, but I would like to know if there is a better/prettier way to do that.

Related

Dynamically allocate memory for an array of unions inside a struct

I'm not sure that I'm approaching this correct, but what I'm trying to do is to dynamically allocate memory for the array of unions inside the struct, I could use
Registers regs[20];
But I don't want it to be fixed to 20*2 bytes.
Instead I want something like this:
typedef union
uint16_t reg;
uint8_t low;
uint8_t high;
}Registers;
typedef struct{
uint8_t updateIntervall;
uint8_t prio;
Registers *regs; // <--- Array of unions
}Config;
uint8_t amount = 4;
Config cfg;
cfg.regs = malloc((amount * 2) * sizeof(uint8_t));
And I guess that
Config cfg;
Already inits the struct, so this should not work.
I'm guessing that I'm doing it completely the wrong way, so if someone could point me in the right direction I would appreciate it.
I would do it another way. nregs is the size of the array
typedef struct{
uint8_t updateIntervall;
uint8_t prio;
Registers regs[]; // <--- Array of unions
}Config;
Config *cfg=malloc(sizeof(*cfg) + nregs * sizeof(cfg->regs[0]));

How to union an array pointer?

I have the following struct definition:
typedef struct mb32_packet_t {
union {
struct {
uint16_t preamble;
uint8_t system_id;
uint8_t message_id;
uint8_t reserved;
uint32_t paylen;
};
uint8_t header[9];
};
uint8_t *payload;
uint16_t checksum;
} __attribute__((packed)) mb32_packet_t;
Now I would like to have another union, so that I can get an uint8_t body[] pointer to the entire packet object. Something like this:
typedef struct mb32_packet_t {
union {
struct {
union {
struct {
uint16_t preamble;
uint8_t system_id;
uint8_t message_id;
uint8_t reserved;
uint32_t paylen;
};
uint8_t header[9];
};
uint8_t *payload;
uint16_t checksum;
};
uint8_t body[?];
};
} __attribute__((packed)) mb32_packet_t;
The problem is that the payload field size is dynamically determined at runtime. Is there another way to accomplish this other than making payload fixed sized?
I basically want to send objects of this type through a network socket, so I need a uint8_t pointer that points to an object of this type. At the time of sending the object, I know the size of the entire object in bytes.
Introduction
The question is unclear, so I will discuss three apparent possibilities.
Fixed-length header followed by variable-length payload
A typical way to define a packet for a networking or messaging service is to have a fixed-length header followed by a variable-length payload. In modern C, the variable-length payload may be defined using a flexible array member, which is an array with no dimension at the end of a structure:
typedef struct
{
uint16_t preamble;
uint8_t system_id;
uint8_t message_id;
uint8_t reserved;
uint32_t paylen;
uint8_t payload[];
} mb32_packet_t;
Memory for such a structure is allocated use the base size provided by sizeof plus additional memory for the payload:
mb32_packet_t *MyPacket = malloc(sizeof *MyPacket + PayloadLength);
When you pass such an object to a routine that requires a char * or uint8_t * or similar type for its argument, you can simply convert the pointer:
SendMyMessage(…, (uint8_t *) MyPacket,…);
That cast, (uint8_t *) MyPacket, provides the pointer to the first byte of the packet requested in the question. There is no need to wedge another member into the structure or layer on a union or other declaration.
Prior to the introduction of flexible array members in C 1999, people would use one of two workarounds to create structures with variable amounts of data. One, they might just define a member array with one element and adjust the space calculations accordingly:
typedef struct
{
…
unsigned char payload[1];
} mb32_packet_t;
mb32_packet_t *MyPacket = malloc(sizeof *MyPacket + PayloadLength - 1);
Technically, that violated the C standard, since the structure contained an array of only one element even though more space was allocated for it. However, compilers were not as aggressive in their analysis of program semantics and their optimization as they are now, so it generally worked. So you may still see old code using that method.
Two, GCC had its own pre-standard implementation of flexible array members, just using an array dimension of zero instead of omitting a dimension:
typedef struct
{
…
unsigned char payload[0];
} mb32_packet_t;
Again, you may see old code using that, but new code should use the standard flexible array member.
Fixed-length header with pointer to variable-length payload
The payload-after-header form shown above is the form of packet I would most expect in a messaging packet, because it matches what the hardware has to put “on the wire” when sending bytes across a network: It writes the header bytes followed by the data bytes. So it is convenient to have them arranged that way in memory.
However, your code shows another option: The data is not in the packet but is pointed to by a pointer in the packet, with uint8_t *payload;. I would suspect that is a mistake, that the network or messaging service really wants a flexible array member, but you show it followed by another member, uint16_t checksum. A flexible array member must be the last member in a structure, so the fact that there is another member after the payload suggests this definition with a pointer may be correct for the messaging service you are working with.
However, if that is the case, it is not possible to get a pointer to the complete packet object, because the object is in two pieces. One contains the header, and the other, at some unrelated location in memory, contains the data.
As above, you can produce a uint8_t * pointer to the start of the packet with (uint8_t) MyPacket. If the messaging system knows about the pointer in the structure, that should work. If you have mistaken what the packet structure must be, it will fail.
Fixed-length header followed by fixed-length payload space
Code elsewhere on Stack Overflow shows a struct mb32_packet_t with a fixed amount of space for a payload:
typedef struct mb32_packet_t {
uint8_t compid;
uint8_t servid;
uint8_t payload[248];
uint8_t checksum;
} __attribute__((packed)) mb32_packet_s;
In this form, the packet is always a fixed size, although the amount of space used for the payload could vary. Again, you would obtain a uint8_t * pointer to the packet by a cast. There is no need for a special member for that.
This is possible, but not with a struct or union, because all parts of a struct or union need to have a known size. You can still use a struct for the header.
Because the body starts at a known location, there's a trick you can use to access it as if it was part of the structure. You can declare it with no size at all (a "flexible array member") or as 0 bytes (a GCC extension that predates the standard). The compiler will not allocate any space for it, but it will still let you use the name to refer to the end of the struct. The trick is that you can malloc extra bytes after the end of the struct, and then use body to refer to them.
typedef struct mb32_packet_t {
union {
struct {
uint16_t preamble;
uint8_t system_id;
uint8_t message_id;
uint8_t reserved;
uint32_t paylen;
};
uint8_t header[9];
};
uint8_t body[]; // flexible array member
} __attribute__((packed)) mb32_packet_t;
// This is not valid. The body is 0 bytes long, so the write is out of bounds.
mb32_packet_t my_packet;
my_packet.body[0] = 1;
// This is valid though!
mb32_packet_t *my_packet2 = malloc(sizeof(*my_packet2) + 50);
my_packet2->body[49] = 1;
// Alternative way to calculate size
mb32_packet_t *my_packet3 = malloc(offsetof(mb32_packet_t, body[50]));
my_packet3->body[49] = 1;
The flexible array member must be last. To access the checksum, you will need to allocate an extra 2 bytes, and use pointer arithmetic. Fortunately, this is just for the checksum, and not the entire header.
mb32_packet_t *my_packet = malloc(sizeof(*my_packet) + body_size + 2);
uint16_t *pchecksum = (uint16_t*)&my_packet.body[body_size];
// or
uint16_t *pchecksum = (uint16_t*)(my_packet.body + body_size);
After you fill in the header, body and checksum, then because they are contiguous in memory, a pointer to the header is also a pointer to the entire packet object.
I usually do it this way:
typedef struct
{
size_t payload_size;
double x;
char y[45];
/* another members */
unsigned char payload[];
}my_packet_t;
or if your compiler does not support FAMs
typedef struct
{
size_t payload_size;
double x;
char y[45];
/* another members */
unsigned char payload[0];
}my_packet_t;
So it the payload can be at the end of the header structure

Copying a struct into a byte array

I have a 1-byte pragma packed struct in C which I want to copy into a byte array for serialization purpose to be sent over a serial port.
#pragma pack(push, 1)
typedef struct {
uint8_t ck_a;
uint8_t ck_b;
} UBXChecksum_t ;
#pragma pack(pop)
What is the best way of serializing it into a byte array, should I just use memcpy()?
void writeStructToArray(const void* inStruct,
const uint16_t inLenStruct,
uint8_t* const outArray)
{
memcpy(outArray, inStruct, inLenStruct);
}
or better use byte-by-byte copying doing pointer typecasting?
void writeStructToArray(const void* inStruct,
const uint16_t inLenStruct,
uint8_t* const outArray)
{
for(uint16_t i = 0; i < inLenStruct; i++)
{
outArray[i] = ((uint8_t*)inStruct)[i];
}
}
As Kamil Cuk commented, your two proposals are nearly the same with some possible speed difference.
Another option would be to use a union:
typedef struct {
uint8_t ck_a;
uint8_t ck_b;
} UBXChecksum_t ;
union convert {
UBXChecksum_t checksum;
char buffer[sizeof UBXChecksum_t];
};
UBXChecksum_t checksum;
union convert converter;
converter.checksum = checksum;
passArrayToSomeFunction(converter.buffer, sizeof(converter.buffer));
You don't have to copy the data to convert it to an array. You could pass a pointer to the structure (if necessary casted to char* or void*) and the structure size to a function that sends the data to the serial port. Example:
typedef struct {
uint8_t ck_a;
uint8_t ck_b;
} UBXChecksum_t ;
int sendData(void *buf, size_t size);
UBXChecksum_t checksum;
/* ... */
int rc = sendData(&checksum, sizeof(checksum));
All these variants send the structure's internal representation as binary data. Normally "serializing" is understood as a way to convert the data into a platform-independent format.
Sending binary data structures works if the receiving system is of the same type and using the same compiler. You might get problems when the receiving system uses different byte order or different data type sizes.
In your case you have a structure of two uint8_t values, so the size is fixed and the byte order is not a problem.
It is OK to send binary data if the requirement for the structure is to match a specified binary data protocol and you are prepared to handle the byte order if necessary.
memcpy() will not consider endiannsess of the system. so if Sender is big endian and receiver is little endian then then will be a conflict in the receiver for the structure variable value.
With the second method you know how the byte stream is prepared at sender so at the receiving end also it can receive accordingly to make sure of the proper structure variable value.
If the endianness of the systems is same and endianness is not a concern then both the method will serve the purpose and memcpy() will be faster compare to the assigning the byte value in a loop.

array take size of struct in union

I have a union in a project i'm working on that represents a USB joystick report:
union {
struct{
uint8_t xaxis;
uint8_t yaxis;
uint8_t xraxis;
uint8_t yraxis;
uint8_t zraxis;
uint8_t slider;
uint8_t buttons8;
uint8_t buttons16;
};
uchar buffer[8];
} report;
this way i can easily put the values into the struct members and use the buffer member to send that data over USB, however I end up modifying this union for different projects (different resolutions on the axis, more/less buttons etc) so then i have to work out what the new size of the struct is to declare the array with the same size.
is there a way to automatically make the array the same size? i thought of using sizeof which requires me to change the struct like this:
union {
struct _data{ // either this
uint8_t xaxis;
uint8_t yaxis;
uint8_t xraxis;
uint8_t yraxis;
uint8_t zraxis;
uint8_t slider;
uint8_t buttons8;
uint8_t buttons16;
} data; // or this
uchar buffer[8];
} report;
but then i can no longer put data into the struct like this:
report.xaxis = value;
but instead:
report.data.xaxis = value;
which i don't want.
is there a way to do this cleanly?
Step 1 is to get a standard C compiler. Then you can use an anonymous struct. To get the appropriate size for the array, use a struct tag, which is only needed internally by the union.
typedef union {
struct data {
uint8_t xaxis;
uint8_t yaxis;
uint8_t xraxis;
uint8_t yraxis;
uint8_t zraxis;
uint8_t slider;
uint8_t buttons8;
uint8_t buttons16;
};
uint8_t buffer[sizeof(struct data)];
} report_t;
...
report_t r;
r.xaxis = 123;
You could use offsetof() for this with the last element in the struct
union
{
struct data
{
uint8_t xaxis;
uint8_t yaxis;
uint8_t xraxis;
uint8_t yraxis;
uint8_t zraxis;
uint8_t slider;
uint8_t buttons8;
uint8_t buttons16;
};
uint8_t buffer[offsetof(struct data, buttons16)+1];
} report;
The solutions other people have proposed here will work. However, they are all hacks, due to your use of a union for ease of conversion to bytes. There is a cleaner solution, which is to do away with the union. Simply make your struct the top-level type, and have your function that sends data over USB take parameters of (void * data, size_t length) . Then, you can easily send any data type over USB.

fixed length structure with variable length reserved space

In the embedded world we often have data structures that are passed around via fixed-length buffers. These are relatively easy to handle using something like this:
#define TOTAL_BUFFER_LENGTH 4096
struct overlay {
uint16_t field1;
uint16_t field2;
uint8_t array1[ARY1_LEN];
};
static_assert(sizeof(struct overlay) <= TOTAL_BUFFER_LENGTH);
struct overlay* overlay = malloc(TOTAL_BUFFER_LENGTH);
That is, we use a data structure as an overlay to allow easy access to the part of the buffer that is currently being used.
We have a number of buffer formats, however, that also use the last few bytes of the buffer to store things like checksums. We currently use constructions like this:
struct overlay {
uint16_t field1;
uint16_t field2;
uint8_t array1[ARY1_LEN];
char reserved[TOTAL_BUFFER_LENGTH -
sizeof(uint16_t) - sizeof(uint16_t) -
(sizeof(uint8_t) * ARY1_LEN) -
sizeof(uint32_t)];
uint32_t crc;
};
As ugly as this looks for this simple data structure, it's an absolute monstrosity when the structure grows to have dozens of fields. It's also a maintainability nightmare, as adding or removing a structure field means that the size calculation for reserved must be updated at the same time.
When the end of the structure only contains one item (like a checksum), then we sometimes use a helper function for reading/writing the value. That keeps the data structure clean and maintainable, but it doesn't scale well when the end of the buffer has multiple fields.
It would help greatly if we could do something like this instead:
struct overlay {
uint16_t field1;
uint16_t field2;
uint8_t array1[ARY1_LEN];
char reserved[TOTAL_BUFFER_LENGTH -
offsetof(struct overlay, reserved) -
sizeof(uint32_t)];
uint32_t crc;
};
Unfortunately, offsetof only works on complete object types and since this is in the middle of the definition of struct overlay, that type isn't yet complete.
Is there a cleaner, more maintainable way to do this sort of thing? I essentially need a fixed-length structure with fields at the beginning and at the end, with the remaining space in the middle reserved/unused.
In your situation, I think I'd probably do things this way:
typedef struct overlay_head
{
uint16_t field1;
uint16_t field2;
uint8_t array1[ARY1_LEN];
} overlay_head;
typedef struct overlay_tail
{
uint32_t crc;
} overlay_tail;
enum { OVERLAY_RSVD = TOTAL_BUFFER_LENGTH - sizeof(overlay_head)
- sizeof(overlay_tail) };
typedef struct overlay
{
overlay_head h;
uint8_t reserved[OVERLAY_RSVD];
overlay_tail t;
} overlay;
You can then work almost as before, except that where you used to write p->field1
you now write p->h.field1, and where you used to write p->crc you now write p->t.crc.
Note that this handles arbitrarily large tail structures quite effectively, as long as the head and tail both fit inside the overall size.
You could define a structure that simply has the buffer with a CRC field at the end:
struct checked_buffer {
char data[TOTAL_BUFFER_LENGTH - sizeof(uint32_t)];
uint32_t crc;
};
and then place your "overlays" on its data field. You're presumably already casting pointers to "convert" a raw buffer's char* into an overlay*, so it shouldn't be a big deal to cast from overlay* to checked_buffer* when you want to access the CRC field.
But if you want to have a field in a consistent position across a bunch of structures, it'd be easier to put it at the beginning of each structure. That way you can declare it directly in each structure without needing to do anything strange, and you don't need any pointer casts to access it.
How about that?
union a256
{
struct
{
int field_a;
int field_b;
char name[16];
//
int crcshadow;
};
struct
{
char buff[256-sizeof(int)];
int crc;
};
} ;
static_assert(offsetof(a256, crcshadow) < offsetof(a256, crc), "data too big");
The first struct contains data, the second define fixed size for this union.

Resources