[En-Nut-Discussion] Using boost::preprocessor (preprocessor metaprogramming)
Thiago A. Corrêa
thiago.correa at gmail.com
Wed Feb 11 03:19:16 CET 2009
On Mon, Feb 9, 2009 at 1:16 AM, Henrik Maier <hmnews at proconx.com> wrote:
> Hi Thiago,
>
> Maybe some smaller examples would help to understand the benefits and how
> such a metalanguage can be applied to a problem?
>
Sure.
This snippet from nut/dev/spibus0gpio.c:
/*!
* \brief Set the specified chip select to a given level.
*/
static GSPIREG *GpioSpi0ChipSelect(uint_fast8_t cs, uint_fast8_t hi)
{
GSPIREG *rc;
switch (cs) {
case 0:
/* If CS0 is undefined, we assume permanent selection. */
#if defined(SBBI0_CS0_BIT)
GpioPinSet(SBBI0_CS0_PORT, SBBI0_CS0_BIT, hi);
GpioPinConfigSet(SBBI0_CS0_PORT, SBBI0_CS0_BIT, GPIO_CFG_OUTPUT);
#endif
rc = &gspi_reg0;
break;
#if defined(SBBI0_CS1_BIT)
case 1:
GpioPinSet(SBBI0_CS1_PORT, SBBI0_CS1_BIT, hi);
GpioPinConfigSet(SBBI0_CS1_PORT, SBBI0_CS1_BIT, GPIO_CFG_OUTPUT);
rc = &gspi_reg1;
break;
#endif
#if defined(SBBI0_CS2_BIT)
case 2:
GpioPinSet(SBBI0_CS2_PORT, SBBI0_CS2_BIT, hi);
GpioPinConfigSet(SBBI0_CS2_PORT, SBBI0_CS2_BIT, GPIO_CFG_OUTPUT);
rc = &gspi_reg2;
break;
#endif
#if defined(SBBI0_CS3_BIT)
case 3:
GpioPinSet(SBBI0_CS3_PORT, SBBI0_CS3_BIT, hi);
GpioPinConfigSet(SBBI0_CS3_PORT, SBBI0_CS3_BIT, GPIO_CFG_OUTPUT);
rc = &gspi_reg3;
break;
#endif
default:
errno = EIO;
rc = NULL;
break;
}
return rc;
}
Could become:
/*!
* \brief Set the specified chip select to a given level.
*/
static GSPIREG *GpioSpi0ChipSelect(uint_fast8_t cs, uint_fast8_t hi)
{
GSPIREG *rc;
switch (cs) {
#define BOOST_PP_LOCAL_MACRO( n ) \
case n: \
GpioPinSet(SBBI0_CS##n_PORT, SBBI0_CS##n_BIT, hi); \
GpioPinConfigSet(SBBIO_CS##n_PORT, SBBI0_CS#n_BIT, GPIO_CFG_OUTPUT); \
rc = &gspi_reg##n; \
break; \
#define BOOST_PP_LOCAL_LIMITS (0, SBBI0_CS_COUNT)
#define BOOST_PP_LOCAL_ITERATE()
default:
errno = EIO;
rc = NULL;
break;
}
return rc;
}
Provided that we set a SBBI0_CS_COUNT in NutConf. Then, the code would
be generated during compile time for any number of SPI_CS's.
Similarly this could be used for USARTs. In the atmega128 family, we
have chips with 2 (supported) and 4 (only 2 supported) USART's.
In my specific case, the AVR32 port could easily support all of the
UC3A, UC3B and AP700x families, because they are almost the same, with
diferences in peripherals mostly. Such code generation tecnique allows
me to generate interrupt handlers for existing and future chips.
There are also support for tuples, arrays, lists, etc (never used
myself), that could help simplify the configuration preamble of most
drivers, that are repetitive and predictable:
#if (UART1_RTS_AVRPORT == AVRPORTB)
#define UART_RTS_PORT PORTB
#define UART_RTS_DDR DDRB
#elif (UART1_RTS_AVRPORT == AVRPORTD)
#define UART_RTS_PORT PORTD
#define UART_RTS_DDR DDRD
#elif (UART1_RTS_AVRPORT == AVRPORTE)
#define UART_RTS_PORT PORTE
#define UART_RTS_DDR DDRE
#elif (UART1_RTS_AVRPORT == AVRPORTF)
#define UART_RTS_PORT PORTF
#define UART_RTS_DDR DDRF
#elif (UART1_RTS_AVRPORT == AVRPORTG)
#define UART_RTS_PORT PORTG
#define UART_RTS_DDR DDRG
#elif (UART1_RTS_AVRPORT == AVRPORTH)
#define UART_RTS_PORT PORTH
#define UART_RTS_DDR DDRH
#endif
It's very powerfull and mind bogling at times. If Harald is open to
it, I can go ahead and try to produce some working code.
Kind Regards,
Thiago A. Correa
More information about the En-Nut-Discussion
mailing list