0

Is it possible to create a preprocessor function that will cause multiple other preoprocessor macros to be defined?

I'm working in a micro controller framework that requires a few macros to be made in order for a generic interrupt handler to function:

<MODULE_NAME>_IRQ_PIN         //ex: PORTB_PIN(0)
<MODULE_NAME>_IRQ_IN_REGISTER //ex: GPIO_PBIN
<MODULE_NAME>_IRQ_NUMBER      //ex: GPIO_IRQA
<MODULE_NAME>_IRQ_INTCFG_REG  //ex: GPIO_INTCFGA

I am trying to make this process more generic and easier from an implementation standpoint. There are about ten of these macros that need to be defined, but their definitions can all be derived when given 1) the port name 2) the pin number and 3) the IRQ name. I am hoping then to create a pre-processor function that will result in the generation of all of these macros. Something like:

#define MAKE_INTERRUPT_MACROS(module, port, pin, irq_num) \
    #define module##_IRQ_pin         PORT##port##_PIN(##pin##) \
    #define module##_IRQ_IN_REGISTER GPIO_P##port##IN \
    #define module##_IRQ_NUMBER      GPIO_IRQ##irq_num \
    #define module##_IRQ_INTCFG_REG  GPIO_INTCFG##irq_num

Is there a legal way to get the proprocessor to do something like the above, where a single preprocessor function causes the generation of multiple other macros based on the parameters passed to the function?

4
  • 5
    You can't use #define in macro Commented May 3, 2015 at 14:13
  • 1
    en.wikibooks.org/wiki/C_Programming/Preprocessor#X-Macros Commented May 3, 2015 at 14:15
  • 3
    Is it necessary that these are all macros? You just could declare them as static const-qualified objects. If definition and initialization are visible in the header file, this should be as good as a macro. Commented May 3, 2015 at 15:16
  • The preprocessor is parsed one time and is not recursive then is not possible to have what you've written. The simplest solution is the classical way to define all values in function of the CPU you have to use! Commented May 3, 2015 at 20:15

3 Answers 3

1

I think this classical scheme may solve your problem. This is a simple and clear way:

#ifdef CPU_X
#define IRQ_PIN              0
#define IRQ_IN_REGISTER      3
#define IRQ_NUMBER           11
#define IRQ_INTCFG_REG       12 
#endif

#ifdef CPU_YY
#define IRQ_PIN         PORTB_PIN(1)
#define IRQ_IN_REGISTER GPIO_PBIN(6)
#define IRQ_NUMBER      GPIO_IRQA(9)
#define IRQ_INTCFG_REG  GPIO_INTCFGA(0xA)
#endif

#ifdef CPU_KK
/* .
   . Another CPU
   .
*/
#endif

#ifdef CPU_K2
/* .
   . Another CPU
   .
*/
#endif

You may compile the code specifying the CPU using -D CPU_xx and the problem shoudl be solved!

I assume you might have some other macros (E.G.: GPIO_IRQA(9)), and in CPU_YY I've used it, but It might be used also for the other CPUs.

Sign up to request clarification or add additional context in comments.

2 Comments

I was going to answer something in that taste. I can't see any "#define" in your answer, though, and there seems to be two preprocessor identifier per row.
@Gauthier. Thanks a lot for the notice! ( I've to stop to write comment when I'm tired :p )
0

If you can use C++ rather than C, look at using classes, one per CPU type, and simply use constants and interfaces in the class. Then, you don't even care that they are different, simply use the same names to access them (the differentiation is done based upon the class being instantiated.

If you really and truly must use C (such as writing a device driver), you can use the approach device driver writers use (all flavors of *nix, VxWorks, PSOS, QNX, and most of the old DEC OSs use this approach, don't know about Windows): Simply build a structure containing the values and any functions you may need to manipulate the hardware (or anything else, for that matter). Create one instance of this structure per hardware (or in your case, module) type. Then indirect through the structure.

Example:

struct module_wrapper {
    const char *module_name;
    int irq_pin;
    int irq_register;
    int irq_number;
    int irq_intcfg_reg;
    int (*init_fcn)(void);
    int (*reg_access)(int register_number);
    int (*open)(void);
    int (*close)(void);
    int (*read)(char *dst_buffer, int len);
    int (*write)(const char *src_buffer, int len);
};


 module_wrapper portB = { /* initialize here */ };
 module_wrapper gpio = { /* initialize here */ };

 printf("GPIO pin %d\n", gpio.irq_pin);

Obviously, modify as desired. You can also replace the constant variables with functions that return the values.

Comments

0

You can't define other macros with a macro, but you achieve something similar by doing it kind of in a totally opposite way.

You could autogenerate a file which has the following block for each possible module:

#ifdef <MODULE>_IRQ_DATA
#define <MODULE>_IRQ_pin         CALL(GET_IRQ_PIN, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_IN_REGISTER CALL(GET_IRQ_IN_REGISTER, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_NUMBER      CALL(GET_IRQ_NUMBER, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_INTCFG_REG  CALL(GET_IRQ_INTCFG_REG, <MODULE>_IRQ_DATA)
#endif

And then have:

#define CALL(MACRO, ...) MACRO(__VA_ARGS__)

#define GET_IRQ_PIN(port, pin, irq_num)         PORT##port##_PIN(pin)
#define GET_IRQ_IN_REGISTER(port, pin, irq_num) GPIO_P##port##IN
#define GET_IRQ_NUMBER(port, pin, irq_num)      GPIO_IRQ##irq_num
#define GET_IRQ_INTCFG_REG(port, pin, irq_num)  GPIO_INTCFG##irq_num

(Depending on how the defines are used, you can possibly get rid of the #ifdef-#endif -pairs, eg. if all of them must/can always be defined)

Then actually defining the needed values could be done with just:

#define <MODULE>_IRQ_DATA B,0,A

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.