[En-Nut-Discussion] Using boost::preprocessor (preprocessor metaprogramming)
Henrik Maier
hmnews at proconx.com
Wed Feb 11 06:19:32 CET 2009
Thank you Thiago!
Well, I certainly can see the benefit. In particular I had it several times
that I introduced the classic copy and paste error by copying code for
device1 to device2 and then forgot to renumber some variables or
definitions. With the boost::preprocessor macros that would be a matter of
the past. It also follows the DRY principle
(http://en.wikipedia.org/wiki/Don%27t_repeat_yourself).
The only concern I have is that Nut/OS contributors have to learn
boost::preprocessor, which could impose a potential hurdle for people
willing to contribute or change code.
The other issue would be debugability.
What do the other contributors think?
Regards
Henrik
> -----Original Message-----
> From: en-nut-discussion-bounces at egnite.de [mailto:en-nut-discussion-
> bounces at egnite.de] On Behalf Of Thiago A. Corrêa
> Sent: Wednesday, 11 February 2009 12:19 PM
> To: Ethernut User Chat (English)
> Subject: Re: [En-Nut-Discussion] Using boost::preprocessor (preprocessor
> metaprogramming)
>
> 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
> _______________________________________________
> http://lists.egnite.de/mailman/listinfo/en-nut-discussion
More information about the En-Nut-Discussion
mailing list