Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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:

  1. Work around the header's deficiencies in the main code
  2. Copy the header file to the local project and fix it
  3. Fix the header file in the spot where it's stored as a vendor-supplied tool
  4. Fix the header file in the central spot, but also make a local copy and try to always have the two match
  5. 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?

Edit

In this vendor's data file, I/O device registers are defined by using structure definitions like the above with macro definitions like #define GPIOB (*((struct GPIO_TypeDef*)GPIO_BASE + 0x100)). Because GPIOA, GPIOB etc. are defined as macros rather than identifiers, any macro substitution of GPIO_TypeDef which goes into effect after the structure is defined would affect future uses of that type but also apply to GPIOA, GPIOB, etc. Thus, my present inclination would be to define my own project-wide header file which #includes the vendor's file, and then defines my own structure and macro-substitutes my structure's name for the vendor's. That would allow code to be written to use the registers in the normal idiomatic fashion while using the vendor-supplied definitions for just about everything else, and while providing a clear patch-point.

share|improve this question
add comment

1 Answer 1

I would refrain from changing vendors the headers, and work around limitations unless the workaround is being used too many times (more than once?). I now apply the following a guides.

  • In most cases its presumptuous to think I know better than the vendor. (he says with only a slight hint of sarcasm)
  • Upgrading the tool chain later can be a problem - solvable with good revision control of the vendors code.
  • Code can no longer be simply documented as " Prerequisite : Install Product XYZ V1.2.3"
  • You code does not match vendors and others expectations - can be harder to discuss if needed - even discussions with other engineers very familiar with the vendors headers.

Where I have been in this situation, I have modified vendors headers and paid an expensive penalty later. I now tend to create my own header that wraps the vendors, leaving theirs as delivered. I have also on occasion send the improvements to the vendor for future releases. All assumptions my code makes about the size and shape of the vendors data structures are verified at compile (or run time) using #error and asserts or other suitable means.

So in the above example, I would simply create "ImprovedGPIO_typeDef" with a

assert (sizeof (GPIO_typeDef) == sizeof(ImprovedGPIO_typedef) );

share|improve this answer
    
Hmm... The vendor's file defines the indicated struct, and then defines GPIOA, GPIOB, etc. using something like #define GPIOA (*((struct GPIO_TypeDef*)GPIO_BASE + 0x100)). What would you think of defining an alternate structure and then #define GPIO_TypeDef GPIO_TypeDef_with_BSRR? I hadn't thought of that possibility until I saw your last line, but it would work around the issue in this case, provided the vendor doesn't change the style of those #defines (except perhaps by adding a volatile which I think ought to be there). Incidentally, with regard to expectations... –  supercat Oct 6 '12 at 8:13
    
...I certainly agree conforming to expectations is important, but sometimes get stymied trying to conform to expectations that conflict. In this case, whether to use names consistent with the manufacturer's written documentation (data sheet) or the header file. My normal tendency is to favor the data sheet very strongly, so as to allow a reader to search for identifiers in the data sheet to find out what a register write will do. –  supercat Oct 6 '12 at 8:27
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.