3
votes

I'm using X macros to generate a MCU pin configuration table. The table would look like this.

#define IO_DEFS\
  /*    Port  Pin  Type    Name  */\
  IODEF(00,   0,   input,  "Pin A")\
  IODEF(00,   1,   input,  "Pin B")\
  IODEF(01,   2,   output, "Pin C")\
  IODEF(01,   4,   output, "Pin D")\
  IODEF(02,   0,   input,  "Pin E")\
  IODEF(03,   7,   input,  "Pin F")\
  IODEF(03,   8,   output, "Pin G")\
  IODEF(03,   9,   input,  "Pin H")\

But then, among the various expansions that I need to generate from this table I need an enum that looks like this:

typedef enum PORT_IO_Defs_Tag
{
    PORT_00,
    PORT_01,
    PORT_02,
    PORT_03,
} PORT_IO_Defs_T;

But the problem is that when creating the macro expansion using the next code:

#undef IODEF
#define IODEF(port, pin, type, name) PORT_##port,
typedef enum PORT_IO_Defs_Tag
{
    IO_DEFS
} PORT_IO_Defs_T;

What I'm getting is the following:

typedef enum PORT_IO_Defs_Tag
{
    PORT_00,
    PORT_00,
    PORT_01,
    PORT_01,
    PORT_02,
    PORT_03,
    PORT_03,
    PORT_03,
} PORT_IO_Defs_T;

I know that this macro expansion is correct but is not what I want since this is generating multiple same values for the enum and compilation errors.

My question here is if anyone know some C Preprocessor trick or technique I could use to achieve this. I was reading this article https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms which contain some pretty interesting preprocessor macro techniques but I can't tweak them to ger the results I need.

I need to achieve this without using M4 macro processor if possible.

Regards.

1
Are the definitions always in pairs, with the same port number for each pair, as per your example above ? If so then I can see one possible, but slightly clunky solution.Paul R
@PaulR no, the definitions are not always in pairs. There could be tons of possible combinations for this. Different number of ports defined as well as different number of pin definitions for each port. But definitely no possible defined way of specifying this table. The only consistent thing here is that there will always be ordered by port number from 00 to NN.m4l490n
@PaulR: No; there's one 02 and three 03 ports if the example is to be believed.Jonathan Leffler
Exactly. Or there could not be 01 at all and eight 03. It's just an example and the combinations are not tied to any pattern.m4l490n
@Barmar - en.wikipedia.org/wiki/X_Macro that's a very good explanation of X macros.m4l490n

1 Answers

2
votes

You could include an additional parameter for IODEF macro indicating the first occurrence of the port

#define IO_DEFS\
/*    Port  Pin  Type    Name  */\
IODEF(00,   0,   input,  "Pin A", 1)\
IODEF(00,   1,   input,  "Pin B", 0)\
IODEF(01,   2,   output, "Pin C", 1)\
IODEF(01,   4,   output, "Pin D", 0)\
IODEF(02,   0,   input,  "Pin E", 1)\
IODEF(03,   7,   input,  "Pin F", 1)\
IODEF(03,   8,   output, "Pin G", 0)\
IODEF(03,   9,   input,  "Pin H", 0)\

and change your macros for something like this

#undef IODEF
#define PRINT_0(port)
#define PRINT_1(port) PORT_##port,
#define IODEF(port, pin, type, name, flag) PRINT_##flag(port)

Now, only one occurrence of each port will appear in your enum

typedef enum PORT_IO_Defs_Tag
{
    PORT_00, PORT_01, PORT_02, PORT_03,
} PORT_IO_Defs_T;