- Muchas notas - Fran Acién

20230518 - C Binary Data structures

It is common to share information in buffers in a binary structure. Here are some example how to do it elegant:

/* Pack mandatory fields of header */
can_id = (((packet->id.pri & CFP2_PRIO_MASK) << CFP2_PRIO_OFFSET) |
			  ((packet->id.dst & CFP2_DST_MASK) << CFP2_DST_OFFSET) |
			  ((iface->addr & CFP2_SENDER_MASK) << CFP2_SENDER_OFFSET) |
			  ((sender_count & CFP2_SC_MASK) << CFP2_SC_OFFSET) |
			  ((1 & CFP2_BEGIN_MASK) << CFP2_BEGIN_OFFSET));

Or even more elegant for extracting and writting:

/**
   @defgroup CFP_SIZE CAN message id field size.
   @{
*/
/** Host - source/destination address. */
#define CFP_HOST_SIZE		5
/** Type - \a begin fragment or \a more fragments. */
#define CFP_TYPE_SIZE		1
/** Remaining fragments */
#define CFP_REMAIN_SIZE		8
/** CFP identification. */
#define CFP_ID_SIZE		10
/** @} */

/**
   @defgroup CFP_FIELDS Macros for extracting fields from CAN message id.
   @{
*/
/** Helper macro */
#define CFP_FIELD(id,rsiz,fsiz) ((uint32_t)((uint32_t)((id) >> (rsiz)) & (uint32_t)((1 << (fsiz)) - 1)))
/** Extract source address */
#define CFP_SRC(id)		CFP_FIELD(id, CFP_HOST_SIZE + CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_HOST_SIZE)
/** Extract destination address */
#define CFP_DST(id)		CFP_FIELD(id, CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_HOST_SIZE)
/** Extract type (begin or more) */
#define CFP_TYPE(id)		CFP_FIELD(id, CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_TYPE_SIZE)
/** Extract remaining fragments */
#define CFP_REMAIN(id)		CFP_FIELD(id, CFP_ID_SIZE, CFP_REMAIN_SIZE)
/** Extract CFP identification */
#define CFP_ID(id)		CFP_FIELD(id, 0, CFP_ID_SIZE)
/** @} */

/**
   @defgroup CFP_MAKE Macros for building CAN message id.
   @{
*/
/** Helper macro */
#define CFP_MAKE_FIELD(id,fsiz,rsiz) ((uint32_t)(((id) & (uint32_t)((uint32_t)(1 << (fsiz)) - 1)) << (rsiz)))
/** Make source */
#define CFP_MAKE_SRC(id)	CFP_MAKE_FIELD(id, CFP_HOST_SIZE, CFP_HOST_SIZE + CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE)
/** Make destination */
#define CFP_MAKE_DST(id)	CFP_MAKE_FIELD(id, CFP_HOST_SIZE, CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE)
/** Make type */
#define CFP_MAKE_TYPE(id)	CFP_MAKE_FIELD(id, CFP_TYPE_SIZE, CFP_REMAIN_SIZE + CFP_ID_SIZE)
/** Make remaining fragments */
#define CFP_MAKE_REMAIN(id)	CFP_MAKE_FIELD(id, CFP_REMAIN_SIZE, CFP_ID_SIZE)
/** Make CFP id */
#define CFP_MAKE_ID(id)		CFP_MAKE_FIELD(id, CFP_ID_SIZE, 0)
/** @} */
/**
 * CSP 1.x Frame Header:
 * Data offset is always 6.
 */
can_id = (CFP_MAKE_SRC(packet->id.src) |
          CFP_MAKE_DST(dest) |
          CFP_MAKE_ID(ident) |
          CFP_MAKE_TYPE(CFP_BEGIN) |
          CFP_MAKE_REMAIN((packet->length + CFP1_DATA_OFFSET - 1) / CAN_FRAME_SIZE));

Other example

packet->primary_header->version = (buffer[0] >> 5) & 0b111;
packet->primary_header->type = (buffer[0] >> 4) & 0b1;
packet->primary_header->sec_header_flag = (buffer[0] >> 3) & 0b1;
packet->primary_header->proc_id = ((buffer[0] & 0b111) << 8) | buffer[1];
packet->primary_header->seq_flags = (buffer[2] >> 6) & 0b11;
packet->primary_header->seq_cnt = (buffer[2] & 0b111111) | buffer[3];
packet->primary_header->length = (unsigned short) buffer[4] << 8 | 
                                 (unsigned short) buffer[5];