// Example program
#include <iostream>
#include <string>


#include <stdint.h>

/**
 * @brief Template class for portable Bitfields
 * 
 * @tparam T type of variable in which the bitfield resides
 * @tparam START bit index starting from LSB where the bitfield starts
 * @tparam SIZE number of bits
 */
template<typename T, uint8_t START, uint8_t SIZE>
struct BitField
{   
    /**
     * @brief Construct a new Bit Field object
     * 
     */
    BitField()
    {
        static_assert(SIZE != 0, "Bitfield SIZE must be > 0!");
		static_assert(START < sizeof(T) * 8, "START exceeds number of bits of the chosen typename T!");
    }
    
    /**
     * @brief assignment operator
     * 
     * @param v value to be written in the bitfield
     * @return BitField&
     */
    BitField& operator =(T v)
    {

#if 0
        _raw = ((v & ((1ULL << SIZE)-1)) << START);
        return *this;
#else
        //_raw & ~(((1ULL << SIZE)-1) << START);
        
        // use bit band alias if system permits
        _raw = ((v & ((1ULL << SIZE)-1)) << START) | (_raw & ~(((1ULL << SIZE)-1) << START));
        return *this;
        //#endif
#endif
    }
    
    /**
     * @brief return the value inside the bitfield
     * 
     * @return T 
     */
    operator T() const
    {
        return _raw >> START;
    }
    
    /**
     * @brief return the raw value
     * 
     * @return T 
     */
    T operator ()() const
    {
        return _raw;
    }
    
    private:
    T _raw;
};

union Reg_Control
{
    // bit 4
    struct POWER_DEV{
        typedef BitField<uint8_t, 7, 1> Bits;
        enum{TURN_OFF = 0, TURN_ON = 1};
    };
    // bits 2-3
    struct SPEED{
        typedef BitField<uint8_t, 0, 2> Bits;
        enum{STAND_STILL = 0,
             SLOW = 1,
             NORMAL = 2,
             FAST = 3};
    };
    union Bits{
        Reg_Control::POWER_DEV::Bits POWER_DEV;
        Reg_Control::SPEED::Bits SPEED;
    } bits;
    // raw value. all bitfields will be "unified" here ;)
    uint8_t raw;
    // union Ctor with default value set to 0x00
    Reg_Control(uint8_t v = 0x00) : raw(v) {}
};



int main()
{
    Reg_Control reg;
    
    //reg.bits.SPEED = Reg_Control::SPEED::FAST;
    reg.bits.POWER_DEV = Reg_Control::POWER_DEV::TURN_ON;
    
    
    std::cout << +reg.raw << std::endl;
    
    reg.bits.POWER_DEV = Reg_Control::POWER_DEV::TURN_OFF;
    
    std::cout << +reg.raw << std::endl;
    
    reg.bits.POWER_DEV = Reg_Control::POWER_DEV::TURN_ON;
    reg.bits.SPEED = Reg_Control::SPEED::SLOW;
    
    std::cout << +reg.raw << std::endl;
    
    reg.bits.POWER_DEV = Reg_Control::POWER_DEV::TURN_OFF;
    reg.bits.SPEED = Reg_Control::SPEED::FAST;
    
    std::cout << +reg.raw << std::endl;

    return 0;
}