cancel
Showing results for 
Search instead for 
Did you mean: 

[BlueNRG-MS] X-CUBE-BLE1 stack code messes up __packed macro

fronders
Senior

Hello! I am using STM32L476 with X-NUCLEO-IDB05A1 (SPBTLE-RF) and X-CUBE-BLE1 v4.4.0 and STM32CubeIDE v1.2.1 on Windows 10 x64.

I was implementing a custom HID-over-GATT Profile device using the X-CUBE-BLE1 examples.

So as I did before for USB HID I would make a struct for the HID report that would map to individual bytes and bits in the report packet. That struct has to be packed in order to correspond to the actual byte pattern of the report. Since I use GCC i would implement my struct with packing enabled the following way:

typedef struct __packed {
	struct {
		uint8_t left :1;
		uint8_t right :1;
		uint8_t middle :1;
		uint8_t :5;
	};
	uint16_t x;
	uint16_t y;
	int8_t wheel;
} CT_HID_Mouse_Single_t;

Note the __packed notation which is a commonly used macro that is unwrapped to GCC's __attribute__((__packed__)).

It is defined multiple times across an STM32 project:

  • inside arm-gcc toolchain - cdefs.h

0690X00000DByXTQA1.jpg

  • HAL libs ensure that macro exists - stm32l4xx_hal_defs.h

0690X00000DByYgQAL.jpg

  • CubeMX adds such a define as compiler cmd args - GCC Compiler Settings -> Preprocessor

0690X00000DBya8QAD.jpg

However all these three defines are undef'ed by the X-CUBE-BLE1 stack internals.

The X-CUBE-BLE1 internals use a lot of structures with packing enabled, this is how they look:

typedef __packed struct _evt_gap_device_found{
  	uint8_t		evt_type;     /**< Type of event (@ref ADV_IND, @ref ADV_DIRECT_IND, @ref ADV_SCAN_IND, @ref ADV_NONCONN_IND, @ref SCAN_RSP) */
	uint8_t		bdaddr_type;  /**< Type of the peer address (@ref PUBLIC_ADDR, @ref RANDOM_ADDR). */
	tBDAddr	    bdaddr;       /**< Address of the peer device found during scanning. */
	uint8_t		data_length;  /**< Length of advertising or scan response data. */
	uint8_t		data_RSSI[VARIABLE_SIZE]; /**< Advertising or scan response data + RSSI. RSSI is last octect (signed integer). */
} PACKED evt_gap_device_found;

Note there is __packed macro present as well as the other one - PACKED. From what I can tell this is done to ensure different compilers pack these structs.

Compiler compatibility is intended to be done in a file from X-CUBE-BLE1 stack called compiler.h (X-CUBE-BLE1\4.4.0\Middlewares\ST\BlueNRG-MS\includes). This is how it looks:

0690X00000DByf3QAD.jpg

So what REALLY happens: if we have GCC then __GNUC__ macro is defined, then __packed gets undef'ed, redefined to be empty and PACKED macro is used instead. While if we don't have the GCC both __packed would be absent on a project level as well as PACKED gets defined as empty.

As a result, my structs declared with __packed are NOT PACKED in fact, because __packed gets redefined to be empty instead of __attribute__((packed)).

This is absolutely ridiculous and I've killed couple of days figuring out the issue was that structs were not packed when I expected them being so.

I would assume the initial intention was compiler.h line 19 to be #ifndef __GNUC__ like this:

#ifndef __GNUC__
#undef __packed
#define __packed
#define PACKED __attribute__((packed))
#else
#define PACKED
#endif

then the code would use __packed in case of GCC and PACKED in case of other compilers. However this exact code is also copied to file "bluenrg_types.h" of the same "includes" folder. Looks like a copy-paste error to me.

Could you please tell me if this is an error or not. And if not, why such a decision to override standard macro was used?

Thanks

0 REPLIES 0