-

   rss_rss_hh_new

 - e-mail

 

 -

 LiveInternet.ru:
: 17.03.2011
:
:
: 51

:


template + constexpr (C++14)

, 23 2017 . 11:07 +


, .

: , , , . , ( ).



, , .

:


  1. C++14.
  2. , , .
  3. .
  4. .
  5. .
  6. .

C++14


, , C++ constexpr. , C++11, ( constexpr ..), C++14, C++11 (C++17 , .. , , C++14, GCC, , , ).

, constexpr C++14 , , , - . . :
. - constexpr-, , . , static_assert . static_assert , constexpr, - .

? - , , :
constexpr , , throw constexpr . , - , , ( ).

, : static_assert , throw , printf .

, ,


? , (, , ). constexpr, , , .

, - ( ) ( , ). , 1 0 . .

, , , , . , ( , ). :

/*
 *   .
 */
struct __attribute__( ( packed ) ) pin_config_t {
    EC_PORT_NAME                port;             //   
                                                  // ( : EC_PORT_NAME::A ).
    EC_PORT_PIN_NAME            pin_name;         //   
                                                  // ( : EC_PORT_PIN_NAME::PIN_0 ).
    EC_PIN_MODE                 mode;             //   
                                                  // ( : EC_PIN_MODE::OUTPUT ).
    EC_PIN_OUTPUT_CFG           output_config;    //   
                                                  // ( : EC_PIN_OUTPUT_CFG::NOT_USE ).
    EC_PIN_SPEED                speed;            //  
                                                  // ( : EC_PIN_SPEED::MEDIUM ).
    EC_PIN_PULL                 pull;             //   
                                                  // ( : EC_PIN_PULL::NO ).
    EC_PIN_AF                   af;               //    
                                                  // ( : EC_PIN_AF::NOT_USE ).
    EC_LOCKED                   locked;           //    
                                                  //     
                                                  // global_port  
                                                  // (  EC_LOCKED::NOT_LOCKED ).
    EC_PIN_STATE_AFTER_INIT     state_after_init; //     
                                                  // (  ,      ).
                                                  // ( EC_PIN_STATE_AFTER_INIT::NO_USE).
};

enum class-
/**********************************************************************
 *  enum class-.
 **********************************************************************/

/*
 *    .
 */
enum class EC_PORT_PIN_NAME {
    PIN_0   = 0,
    PIN_1   = 1,
    PIN_2   = 2,
    PIN_3   = 3,
    PIN_4   = 4,
    PIN_5   = 5,
    PIN_6   = 6,
    PIN_7   = 7,
    PIN_8   = 8,
    PIN_9   = 9,
    PIN_10  = 10,
    PIN_11  = 11,
    PIN_12  = 12,
    PIN_13  = 13,
    PIN_14  = 14,
    PIN_15  = 15
};

/*
 *  .
 */
enum class EC_PIN_MODE {
    INPUT   = 0,    // .
    OUTPUT  = 1,    // .
    AF      = 2,    //  .
    ANALOG  = 3     //  .
};

/*
 *  .
 */
enum class EC_PIN_OUTPUT_CFG {
    NO_USE      = 0,    //     .
    PUSH_PULL   = 0,    // "-".
    OPEN_DRAIN  = 1     // " ".
};

/*
 *  .
 */
enum class EC_PIN_SPEED {
    LOW         = 0,    // .
    MEDIUM      = 1,    // .
    FAST        = 2,    // .
    HIGH        = 3     //  
};

/*
 *  
 */
enum class EC_PIN_PULL {
    NO_USE  = 0,    //  .
    UP      = 1,    //   .
    DOWN    = 2     //   .
};

/*
 *   ,  .
 */
enum class EC_PIN_AF {
    AF_0        = 0,
    NO_USE      = AF_0,
    SYS         = AF_0,

    AF_1        = 1,
    TIM1        = AF_1,
    TIM2        = AF_1,

    AF_2        = 2,
    TIM3        = AF_2,
    TIM4        = AF_2,
    TIM5        = AF_2,

    AF_3        = 3,
    TIM8        = AF_3,
    TIM9        = AF_3,
    TIM10       = AF_3,
    TIM11       = AF_3,

    AF_4        = 4,
    I2C1        = AF_4,
    I2C2        = AF_4,
    I2C3        = AF_4,

    AF_5        = 5,
    SPI1        = AF_5,
    SPI2        = AF_5,
    I2S2        = AF_5,


    AF_6        = 6,
    SPI3        = AF_6,
    I2S3        = AF_6,

    AF_7        = 7,
    USART1      = AF_7,
    USART2      = AF_7,
    USART3      = AF_7,

    AF_8        = 8,
    UART4       = AF_8,
    UART5       = AF_8,
    USART6      = AF_8,

    AF_9        = 9,
    CAN1        = AF_9,
    CAN2        = AF_9,
    TIM12       = AF_9,
    TIM13       = AF_9,
    TIM14       = AF_9,

    AF_10       = 10,
    OTG_FS      = AF_10,

    AF_11       = 11,
    ETH         = AF_11,

    AF_12       = 12,
    FSMC        = AF_12,
    SDIO        = AF_12,

    AF_13       = 13,
    DCMI        = AF_13,

    AF_14       = 14,

    AF_15       = 15,
    EVENTOUT    = AF_15
};

/*
 *       set_locked_key_port 
 * set_locked_keys_all_port   global_port.
 * !       global_port.   
 *          - .
 *     -  .
 */
enum class EC_LOCKED {
    NOT_LOCKED  = 0,    //   .
    LOCKED      = 1     //  .
};

/*
 *     
 * ( ,     ).
 */
enum class EC_PIN_STATE_AFTER_INIT {
    NO_USE  = 0,
    RESET   = 0,
    SET     = 1
};


, (). stm32f2 ( ), GPIO BSR, (1) 0-15 ( (1) 0- 0 1), (1) 16-31 16 ( (1) 31- 31-16 = 15- 0).

, 1 BSR 1 << _, 1 << _ + 16.

port pin_name. .

:

class pin {
public:
    constexpr pin ( const pin_config_t* const pin_cfg_array );

    void    set     ( void ) const;
    void    reset   ( void ) const;
    void    set     ( uint8_t state ) const;
    void    set     ( bool state ) const;
    void    set     ( int state ) const;

private:
    constexpr uint32_t  p_bsr_get                ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  set_msk_get              ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  reset_msk_get            ( const pin_config_t* const pin_cfg_array );

    const uint32_t  p_bsr;
    const uint32_t  bsr_set_msk, bsr_reset_msk;
};

, :

  • set 1;
  • reset 0;
  • set c ( ), .

. .

/*
 *      <<1>>,
 *     .
 */
void pin::set ( void ) const {
    *M_U32_TO_P(this->p_bsr) = this->bsr_set_msk;
}

/*
 *      <<0>>,
 *     .
 */
void pin::reset ( void ) const {
    *M_U32_TO_P(this->p_bsr) = this->bsr_reset_msk;
}

/*
 *      ,
 *     .
 */
void pin::set ( uint8_t state ) const {
    if ( state ) {
        this->set();
    } else {
        this->reset();
    }
}

void pin::set ( bool state ) const {
    this->set( static_cast< uint8_t >( state ) );
}

void pin::set ( int state ) const {
    this->set( static_cast< uint8_t >( state ) );
}

set reset define uint32_t uint32_t .

//    uint32_t     uint32_t.
//     .
#define M_U32_TO_P(point)				((uint32_t *)(point))

, , (, ) .

:

  1. set_msk_get uint32_t , BSR <<1>>.
  2. reset_msk_get uint32_t , BSR <<0>>.
  3. p_bsr_get uint32_t , BSR .

, , :

/**********************************************************************
 *  constexpr .
 **********************************************************************/

/*
 *       "1"   BSR.
 */
constexpr uint32_t pin::set_msk_get ( const pin_config_t* const pin_cfg_array ) {
    return 1 << M_EC_TO_U8(pin_cfg_array->pin_name);
}

/*
 *       "0"   BSR.
 */
constexpr uint32_t pin::reset_msk_get ( const pin_config_t* const pin_cfg_array ) {
    return 1 << M_EC_TO_U8( pin_cfg_array->pin_name ) + 16;
}

/*
 *      BSR,    .
 */
constexpr uint32_t pin::p_bsr_get( const pin_config_t* const pin_cfg_array ) {
    uint32_t p_port = p_base_port_address_get( pin_cfg_array->port );
    return p_port + 0x18;
}

define enum class- uint8_t .

//  enum class  uint8_t.
#define M_EC_TO_U8(ENUM_VALUE)			((uint8_t)ENUM_VALUE)

p_bsr_get p_base_port_address_get, enum class- EC_PORT_NAME ( ) . :

p_base_port_address_get
/*
 *        -
 *        .
 */
constexpr uint32_t p_base_port_address_get( EC_PORT_NAME port_name ) {
    switch( port_name ) {
#ifdef PORTA
    case EC_PORT_NAME::A:   return 0x40020000;
#endif
#ifdef PORTB
    case EC_PORT_NAME::B:   return 0x40020400;
#endif
#ifdef PORTC
    case EC_PORT_NAME::C:   return 0x40020800;
#endif
#ifdef PORTD
    case EC_PORT_NAME::D:   return 0x40020C00;
#endif
#ifdef PORTE
    case EC_PORT_NAME::E:   return 0x40021000;
#endif
#ifdef PORTF
    case EC_PORT_NAME::F:   return 0x40021400;
#endif
#ifdef PORTG
    case EC_PORT_NAME::G:   return 0x40021800;
#endif
#ifdef PORTH
    case EC_PORT_NAME::H:   return 0x40021C00;
#endif
#ifdef PORTI
    case EC_PORT_NAME::I:   return 0x40022000;
#endif
    }
}
, / .

/**********************************************************************
 *  constexpr .
 **********************************************************************/

constexpr pin::pin ( const pin_config_t* const pin_cfg_array ):
    p_bsr               ( this->p_bsr_get( pin_cfg_array ) ),
    bsr_set_msk         ( this->set_msk_get( pin_cfg_array ) ),
    bsr_reset_msk       ( this->reset_msk_get( pin_cfg_array ) ) {};

, , ,

.


, , . , , constexpr . template. ( , () , ), template- . , template- static_assert. . , :

template class, , , template , , .

!

/**********************************************************************
 *  template .
 **********************************************************************/
template < EC_PORT_NAME              PORT,
           EC_PORT_PIN_NAME          PIN_NAME,
           EC_PIN_MODE               MODE,
           EC_PIN_OUTPUT_CFG         OUTPUT_CONFIG,
           EC_PIN_SPEED              SPEED,
           EC_PIN_PULL               PULL,
           EC_PIN_AF                 AF,
           EC_LOCKED                 LOCKED,
           EC_PIN_STATE_AFTER_INIT   STATE_AFTER_INIT >
class pin_config_check_param : public pin_config_t {
public:
    constexpr pin_config_check_param(): pin_config_t( {
        .port               = PORT,
        .pin_name           = PIN_NAME,
        .mode               = MODE,
        .output_config      = OUTPUT_CONFIG,
        .speed              = SPEED,
        .pull               = PULL,
        .af                 = AF,
        .locked             = LOCKED,
        .state_after_init   = STATE_AFTER_INIT
    } ) {
/*
 *       .
 */
#if defined(STM32F205RB)|defined(STM32F205RC)|defined(STM32F205RE) \
    |defined(STM32F205RF)|defined(STM32F205RG)
            static_assert( PORT >= EC_PORT_NAME::A && 
                    PORT <= EC_PORT_NAME::H, 
                    "Invalid port name. The port name must be A..H." );
#endif
            
            static_assert( PIN_NAME >= EC_PORT_PIN_NAME::PIN_0 &&
                    PIN_NAME <= EC_PORT_PIN_NAME::PIN_15,
                    "Invalid output name. An output with this name does not"
                    "exist in any port. The output can have a name PIN_0..PIN_15." );

            static_assert( MODE >= EC_PIN_MODE::INPUT &&
                    MODE <= EC_PIN_MODE::ANALOG,
                    "The selected mode does not exist. "
                    "The output can be set to mode: INPUT, OUTPUT, AF or ANALOG." );

            static_assert( OUTPUT_CONFIG == EC_PIN_OUTPUT_CFG::PUSH_PULL ||
                    OUTPUT_CONFIG == EC_PIN_OUTPUT_CFG::OPEN_DRAIN,
                    "A non-existent output mode is selected. "
                    "The output can be in the mode: PUSH_PULL, OPEN_DRAIN." );

            static_assert( SPEED >= EC_PIN_SPEED::LOW &&
                    SPEED <= EC_PIN_SPEED::HIGH,
                    "A non-existent mode of port speed is selected. "
                    "Possible modes: LOW, MEDIUM, FAST or HIGH." );

            static_assert( PULL >= EC_PIN_PULL::NO_USE &&
                    PULL <= EC_PIN_PULL::DOWN,
                    "A non-existent brace mode is selected."
                    "The options are: NO_USE, UP or DOWN." );

            static_assert( AF >= EC_PIN_AF::AF_0 &&
                    AF <= EC_PIN_AF::AF_15,
                    "A non-existent mode of the alternative port function is selected." );

            static_assert( LOCKED == EC_LOCKED::NOT_LOCKED ||
                    LOCKED == EC_LOCKED::LOCKED,
                    "Invalid port lock mode selected." );

            static_assert( STATE_AFTER_INIT == EC_PIN_STATE_AFTER_INIT::NO_USE ||
                    STATE_AFTER_INIT == EC_PIN_STATE_AFTER_INIT::SET,
                    "The wrong state of the output is selected."
                    "The status can be: NO_USE, UP or DOWN." );
    };
};

:

const pin_config_check_param< EC_PORT_NAME::C,        EC_PORT_PIN_NAME::PIN_4,  
                              EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   
                              EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    
                              EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      
                              EC_PIN_STATE_AFTER_INIT::SET > lcd_res;


, pin , :

const constexpr pin pin_lcd_res( &lcd_res );

, :

void port_test ( void ) {
    pin_lcd_res.reset();
    pin_lcd_res.set();
}


, . , ? , , , . .

(2) :

  1. p_bb_odr_read ODR ( , ). bit-banding .
  2. p_bb_idr_read IDR ( , , ). bit-banding .

, .

/*
 *     bit_banding
 *  ,      .
 */
constexpr uint32_t pin::bb_p_idr_read_get ( const pin_config_t* const pin_cfg_array ) {
    uint32_t p_port = p_base_port_address_get( pin_cfg_array->port );
    uint32_t p_idr  = p_port + 0x10;
    return M_GET_BB_P_PER(p_idr, M_EC_TO_U8(pin_cfg_array->pin_name));
}
/*
 *     bit banding  ,
 *       .
 */
constexpr uint32_t pin::odr_bit_read_bb_p_get ( const pin_config_t* const pin_cfg_array ) {
    uint32_t p_port     = p_base_port_address_get( pin_cfg_array->port );
    uint32_t p_reg_odr  = p_port + 0x14;
    return M_GET_BB_P_PER(p_reg_odr, M_EC_TO_U8(pin_cfg_array->pin_name));
}

define M_GET_BB_P_PER uint32_t uint32_t bit-banding .

define M_GET_BB_P_PER
//*********************************************************************
// ,    .
//*********************************************************************
#define BIT_BAND_SRAM_REF   0x20000000
#define BIT_BAND_SRAM_BASE  0x22000000

//   RAM  Bit Banding .
#define MACRO_GET_BB_P_SRAM(reg, bit) \
  ((BIT_BAND_SRAM_BASE + (reg - BIT_BAND_SRAM_REF)*32 + (bit * 4)))

#define BIT_BAND_PER_REF   ((uint32_t)0x40000000)
#define BIT_BAND_PER_BASE  ((uint32_t)0x42000000)

//      Bit Banding .
#define M_GET_BB_P_PER(ADDRESS,BIT) \
    ((BIT_BAND_PER_BASE + (ADDRESS - BIT_BAND_PER_REF)*32 + (BIT * 4)))


.

/**********************************************************************
 *  constexpr .
 **********************************************************************/

constexpr pin::pin ( const pin_config_t* const pin_cfg_array ):
    p_bsr               ( this->p_bsr_get( pin_cfg_array ) ),
    p_bb_odr_read       ( this->odr_bit_read_bb_p_get( pin_cfg_array ) ),
    bsr_set_msk         ( this->set_msk_get( pin_cfg_array ) ),
    bsr_reset_msk       ( this->reset_msk_get( pin_cfg_array ) ),
    p_bb_idr_read       ( this->bb_p_idr_read_get( pin_cfg_array ) ) {};

, :

/*
 *      ,
 *     .
 */
void pin::invert( void ) const {
    if (*M_U32_TO_P_CONST(p_bb_odr_read)) {			//   1,   0.
        this->reset();
    } else {
        this->set();
    }
}

/*
 *      .
 */
int pin::read() const {
    return *M_U32_TO_P_CONST(p_bb_idr_read);
}

1 define (M_U32_TO_P_CONST), , uint32_t uint32_t , .

//    uint32_t     uint32_t.
//    ,    ( ).
#define M_U32_TO_P_CONST(point)		((const uint32_t *const)(point))

, :

class pin {
public:
    constexpr pin ( const pin_config_t* const pin_cfg_array );

    void    set     ( void ) const;
    void    reset   ( void ) const;
    void    set     ( uint8_t state ) const;
    void    set     ( bool state ) const;
    void    set     ( int state ) const;
    void    invert  ( void ) const;
    int     read    ( void ) const;

private:
    constexpr uint32_t  p_bsr_get                ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  set_msk_get              ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  reset_msk_get            ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  odr_bit_read_bb_p_get    ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  bb_p_idr_read_get        ( const pin_config_t* const pin_cfg_array );


    const uint32_t  p_bsr;
    const uint32_t  bsr_set_msk, bsr_reset_msk;
    const uint32_t  p_bb_odr_read, p_bb_idr_read;
};

.


, (, ADC). , . template class, template class. ADC :


template < EC_PORT_NAME              PORT,
           EC_PORT_PIN_NAME          PIN_NAME >
class pin_config_adc_check_param : public pin_config_check_param< PORT, PIN_NAME,
                                                                  EC_PIN_MODE::INPUT,
                                                                  EC_PIN_OUTPUT_CFG::NO_USE,
                                                                  EC_PIN_SPEED::LOW,
                                                                  EC_PIN_PULL::UP,
                                                                  EC_PIN_AF::NO_USE,
                                                                  EC_LOCKED::LOCKED,
                                                                  EC_PIN_STATE_AFTER_INIT::NO_USE > {
public:
    constexpr pin_config_adc_check_param() {};
};

:

const pin_config_adc_check_param< EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_1 >      adc_left;


, , , . , .

, . , , , PLL, . - . , - - , , , , , . .

, pin . . flash uint32_t , , .

. . .

madcomaker , .
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331468/

:  

: [1] []
 

:
: 

: ( )

:

  URL