Handling bugs, quirks, or annoyances in vendor-supplied headers
- by supercat
If the header file supplied by a vendor of something with whom one's code must interact is deficient in some way, in what cases is it better to:
Work around the header's deficiencies in the main code
Copy the header file to the local project and fix it
Fix the header file in the spot where it's stored as a vendor-supplied tool
Fix the header file in the central spot, but also make a local copy and try to always have the two match
Do something else
As an example, the header file supplied by ST Micro for the STM320LF series contains the lines:
typedef struct
{
__IO uint32_t MODER;
__IO uint16_t OTYPER;
uint16_t RESERVED0;
....
__IO uint16_t BSRRL; /* BSRR register is split to 2 * 16-bit fields BSRRL */
__IO uint16_t BSRRH; /* BSRR register is split to 2 * 16-bit fields BSRRH */
....
} GPIO_TypeDef;
In the hardware, and in the hardware documentation, BSRR is described as a single 32-bit register. About 98% of the time one wants to write to BSRR, one will only be interested in writing the upper half or the lower half; it is thus convenient to be able to use BSSRH and BSSRL as a means of writing half the register. On the other hand, there are occasions when it is necessary that the entire 32-bit register be written as a single atomic operation. The "optimal" way to write it (setting aside white-spacing issues) would be:
typedef struct
{
__IO uint32_t MODER;
__IO uint16_t OTYPER;
uint16_t RESERVED0;
....
union // Allow BSRR access as 32-bit register or two 16-bit registers
{
__IO uint32_t BSRR; // 32-bit BSSR register as a whole
struct { __IO uint16_t BSRRL, BSRRH; };// Two 16-bit parts
};
....
} GPIO_TypeDef;
If the struct were defined that way, code could use BSRR when necessary to write all 32 bits, or BSRRH/BSRRL when writing 16 bits. Given that the header isn't that way, would better practice be to use the header as-is, but apply an icky typecast in the main code writing what would be idiomatically written as thePort->BSRR = 0x12345678; as *((uint32_t)&(thePort->BSSRH)) = 0x12345678;, or would be be better to use a patched header file? If the latter, where should the patched file me stored and how should it be managed?