/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef INCLUDE_ECXX_PLATFORM_SPECIFIC_PIN_DDX_H
#error "this file cannot be included directly"
#endif
#undef INCLUDE_ECXX_PLATFORM_SPECIFIC_PIN_DDX_H


#ifndef ECXX_PLATFORM_AVRX_PIN_DDX_H
#define ECXX_PLATFORM_AVRX_PIN_DDX_H


#define ECXX_DECLARE_ARRAY_FOR_DDX
#include "PinMapping.h"


namespace eCxx {


//
// A simple direct digital configure, read, and write wrapper class
//
template <uint8_t PinN>
class PinDDX : public Uncopyable {
    static_assert(PinN < sizeof(pin_to_port_number), "template argument substituting PinN is out of range");

    public:
        inline PinDDX() = default;
        inline ~PinDDX() = default;

    private:
        constexpr PORT_t& port() const
        { return *( &PORTA + pin_to_port_number[PinN] ); }

        constexpr volatile uint8_t& pinctrl() const
        { return *( &( port().PIN0CTRL ) + pin_to_bit_position[PinN] ); }

    public:
        inline void pinModeOutput() const __ECXX_ATTR_ALWAYS_INLINE
        {
            port().DIRSET = pin_to_bit_mask[PinN];
        }

        inline void digitalWrite(bool bit) const __ECXX_ATTR_ALWAYS_INLINE
        {
            if(bit) port().OUTSET = pin_to_bit_mask[PinN];
            else    port().OUTCLR = pin_to_bit_mask[PinN];
        }

    public:
        inline void pinModeInput() const __ECXX_ATTR_ALWAYS_INLINE
        {
            port().DIRCLR = pin_to_bit_mask[PinN];
        }

        inline void pinModeInput(bool withPullUp) const __ECXX_ATTR_ALWAYS_INLINE
        {
            pinModeInput();

            if(withPullUp) pinctrl() |=  PORT_PULLUPEN_bm;
            else           pinctrl() &= ~PORT_PULLUPEN_bm;
        }

        inline bool digitalRead() const __ECXX_ATTR_ALWAYS_INLINE
        {
            return port().IN & pin_to_bit_mask[PinN];
        }
};


} // namespace eCxx


#endif
