[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