Memory Alignment
ARM Cortex M MCU can perform unaligned access for certain instructions.
Although GCC has option -mnounaligned-access
to do everything byte-wise, the resulting code will be slower. We code carefully to avoid invalid unaligned access.
Defining Compact C Struct
We need to define C struct in compact form, i.e., with only 1 byte alignment, which is the minimum.
Also we need the same code compilable on both GCC and Microsoft VC++. It’s a bit tricky. We finally settled with a BYTE_ALIGNED
macro.
#include "align.h"
Below is a definition of a Hornet/Zigbee NPDU (Network Protocol Data Unit) header.
BYTE_ALIGNED(
typedef struct {
npdu_fcf_t fcf;
uint16_t dest_addr;
uint16_t src_addr;
uint8_t radius;
uint8_t sequence;
}) npdu_header_fixed_t;
C bit field declaration shall also be defined in this way.
BYTE_ALIGNED(
typedef struct {
union {
struct {
uint8_t frame_type : 2;
uint8_t protocol_version : 4;
uint8_t discover_route : 2;
uint8_t multicast : 1;
uint8_t security : 1;
uint8_t source_route : 1;
uint8_t dest_ieee_addr : 1;
uint8_t src_ieee_addr : 1;
uint8_t busy : 1;
uint8_t reserved : 2;
};
uint16_t raw;
};
} ) npdu_fcf_t;
64 Bit Access
For 64 bit types, such as int64_t
or uint64_t
, unaligned access is not allowed on ARM.
Hornet defined appropriate helper functions. Note the input arguments are all pointers to 64 bit numbers.
// Returns true if the 64 bit number is NOT zero.
static inline uint8_t int64_is_nonzero(const void *dest);
// Set 64 bit number ito zero.
static inline void int64_zero(void *dest);
// Copy 64 bit number.
static inline void int64_copy(void *dest, const void *src);
// Test if two 64 bit numbers are equal.
static inline uint8_t int64_equal(const void *dest, const void *src);