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

/*
 * ----------------------------------------------------------------------------------
 * The code in this file is based on:
 *     esp8266_peri.h - peripheral registers exposed in more AVR style for esp8266
 * ----------------------------------------------------------------------------------
 * Copyright (C) 2015 Hristo Gochkov. All rights reserved.
 *
 * This file is part of the esp8266 core for Arduino environment.
 *
 * This library is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation; either version 2.1 of the License, or (at your option) any later
 * version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along
 * with this library; if not, write to the Free Software Foundation, Inc., 51
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 * ----------------------------------------------------------------------------------
 */


#ifndef ECXX_PLATFORM_NODEMCU_GPIO_UTIL_H
#define ECXX_PLATFORM_NODEMCU_GPIO_UTIL_H


#include "ESP8266Peripheral.h"


namespace eCxx {

namespace NodeMCU {


//
// GPIO utility functions
//

// Check if the specified pin can be used for GPIO pin
namespace internal {

    // GPIO16 does not support interrupt and fast-digital-read/write in eCxx
    template <bool IntAndFDWR> struct UserGPIOPin {
        static constexpr bool _(uint8_t pin) __ECXX_ATTR_ALWAYS_INLINE
        { return pin <= 5 || (pin >= 12 && pin <= 16); }
    };

    // GPIO16 does not support interrupt and fast-digital-read/write in eCxx
    template<> struct UserGPIOPin<true> {
        static constexpr bool _(uint8_t pin) __ECXX_ATTR_ALWAYS_INLINE
        { return pin <= 5 || (pin >= 12 && pin <= 15); }
    };

} // namespace internal

template <bool IntAndFDWR> static constexpr bool userGPIOPin(uint8_t pin) __ECXX_ATTR_ALWAYS_INLINE;
template <bool IntAndFDWR> static constexpr bool userGPIOPin(uint8_t pin)
{ return internal::UserGPIOPin<IntAndFDWR>::_(pin); }


// Check if the specified pin can be used for OWI pin
static constexpr bool userOWIPin(uint8_t pin) __ECXX_ATTR_ALWAYS_INLINE;
static constexpr bool userOWIPin(uint8_t pin)
{ return pin == 0 || pin == 2 || pin == 4 || pin == 5 || pin == 12 || pin == 13 || pin == 14; }


// Access to GPIO[0:15] pin control registers
static constexpr volatile uint32_t& _GPC(uint8_t pin)
{ return ESP8266_REG( 0x328 + ( (pin & 0x0F) * 4 ) ); }


// Access to GPIO[0:15] pin function registers
static constexpr volatile uint32_t* const GPIO_PFR[16] = {
    &GPF0, &GPF1, &GPF2, &GPF3, &GPF4, &GPF5, &GPF6, &GPF7, &GPF8, &GPF9, &GPF10, &GPF11, &GPF12, &GPF13, &GPF14, &GPF15
};

static constexpr volatile uint32_t& _GPF(uint8_t pin)
{ return *GPIO_PFR[pin & 0x0F]; }


} // namespace NodeMCU

} // namespace eCxx


#endif
