//-----------------------------------------------------------------------------
///
/// \brief  Class representing an GPIO
///
/// \date   20121107
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//-----------------------------------------------------------------------------


//---Includes------------------------------------------------------------------


#include <biwak/gpio.hpp>
#include <biwak/rcc.h>        // rccGpioClockEnable()
#include <biwak/exception.h>
#include <HALWrapper/stm32_rcc.h>
#include <HALWrapper/stm32_gpio.h>
#include <biwak/biwak.h>      // exception
#include <biwak/timer.hpp>      // usleep


//---Implementation------------------------------------------------------------


#if defined CONFIG_DIRECT_GPIO_INSTANCE
   #define peripheralEnumToPeripheral(periphery)      periphery
#endif

static_assert ( GPIO_PIN_SET == 1, "" );
static_assert ( GPIO_PIN_RESET == 0, "" );

#define pinStateEnumToPinSTate( _value ) ((GPIO_PinState)_value)

struct SGpioMode
{
   const uint32_t mode;
   const uint8_t speed;
   const uint8_t pp;
   //const uint8_t af;
}; // __attribute__ ( ( packed ) ); // packed increases binary size


#if ! defined ( GPIO_SPEED_FREQ_VERY_HIGH )
   #define GPIO_SPEED_FREQ_VERY_HIGH   GPIO_SPEED_FREQ_HIGH
#endif

constexpr const SGpioMode gpioModeOutput={ .mode=GPIO_MODE_OUTPUT_PP, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_NOPULL};
//const SGpioMode gpioModeLed={ .mode=GPIO_MODE_OUTPUT_PP, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_NOPULL, .af=0};
constexpr const SGpioMode gpioModeAf={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_NOPULL};
constexpr const SGpioMode gpioModeAfHighSpeed={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_VERY_HIGH, .pp=GPIO_NOPULL};
//const SGpioMode gpioModeUart={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_NOPULL, .af=1};
//const SGpioMode gpioModePwm={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_NOPULL, .af=1};
#if defined BIWAK_QUIRK_INPUT_PD
const SGpioMode gpioModeInput={ .mode=GPIO_MODE_INPUT, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_PULLDOWN };
const SGpioMode gpioModeInputInterrupt=
         { .mode=GPIO_MODE_IT_RISING_FALLING, .speed=GPIO_SPEED_FREQ_LOW,
                 .pp=GPIO_PULLDOWN };
#else
constexpr const SGpioMode gpioModeInput={ .mode=GPIO_MODE_INPUT, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_NOPULL};
constexpr const SGpioMode gpioModeInputInterrupt=
         { .mode=GPIO_MODE_IT_RISING_FALLING, .speed=GPIO_SPEED_FREQ_LOW,
                 .pp=GPIO_NOPULL};
#endif
constexpr const SGpioMode gpioModeInputInterruptPullDown=
         { .mode=GPIO_MODE_IT_RISING_FALLING, .speed=GPIO_SPEED_FREQ_LOW,
                 .pp=GPIO_PULLDOWN };
// GPIO_SPEED_FREQ_LOW: up to 2Mhz
constexpr const SGpioMode gpioModeInputFrequency=
         { .mode=GPIO_MODE_IT_RISING, .speed=GPIO_SPEED_FREQ_LOW,.pp=GPIO_PULLDOWN};
constexpr const SGpioMode gpioModeAfInOut={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_HIGH, .pp=GPIO_PULLUP};
constexpr const SGpioMode gpioModeI2c={ .mode=GPIO_MODE_AF_OD, .speed=GPIO_SPEED_FREQ_HIGH, .pp=GPIO_PULLUP};
constexpr const SGpioMode gpioModeSpi={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_NOPULL};
constexpr const SGpioMode gpioModeSD={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_VERY_HIGH, .pp=GPIO_NOPULL};
constexpr const SGpioMode gpioModeSDCmd={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_VERY_HIGH, .pp=GPIO_PULLUP};
constexpr const SGpioMode gpioModeButton={ .mode=GPIO_MODE_IT_RISING_FALLING, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_NOPULL};
constexpr const SGpioMode gpioModeAnalog={ .mode=GPIO_MODE_ANALOG, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_NOPULL};
constexpr const SGpioMode gpioModeAfIn={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_PULLUP};

#if defined STM32F1
   // Verified with STM32CubeMX for STM32F103
   const SGpioMode gpioModeCanRx={ .mode=GPIO_MODE_INPUT, .speed=GPIO_SPEED_FREQ_HIGH, .pp=GPIO_NOPULL};
   const SGpioMode gpioModeCanTx={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_HIGH, .pp=GPIO_NOPULL};
#else
   // Verified with STM32CubeMX for STM32L431RC
   const SGpioMode gpioModeCan={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_VERY_HIGH, .pp=GPIO_NOPULL};
   extern const SGpioMode gpioModeCanRx  __attribute__((alias("gpioModeCan")));
   extern const SGpioMode gpioModeCanTx  __attribute__((alias("gpioModeCan")));
#endif 

const SGpioMode gpioModeQSpi={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_VERY_HIGH, .pp=GPIO_PULLUP};

// CAN-Reference: NOPULL, HIGH
//const SGpioMode gpioModeAfOut={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_HIGH, .pp=GPIO_NOPULL, .af=1};
const SGpioMode gpioModeAfOut={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_LOW, .pp=GPIO_PULLDOWN };

// At least the input should be pulled up or there might be a issue with
// floating RX pin when UART/Debug-Adapter is not connected
const SGpioMode gpioModeUart={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_HIGH, .pp=GPIO_NOPULL};

#if defined BIWAK_QUIRK_UART_RX_PU
   const SGpioMode gpioModeUartRx={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_HIGH, .pp=GPIO_PULLUP};
   //const SGpioMode gpioModeUartTx={ .mode=GPIO_MODE_AF_PP, .speed=GPIO_SPEED_FREQ_HIGH, .pp=GPIO_NOPULL}; // , .af=1
   extern const SGpioMode gpioModeUartTx __attribute__((alias("gpioModeUart")));
#else
   extern const SGpioMode gpioModeUartRx __attribute__((alias("gpioModeUart")));
   extern const SGpioMode gpioModeUartTx __attribute__((alias("gpioModeUart")));
#endif

#if defined ( BIWAK_QUIRK_UART_RX_PD )
   #error "Pull-Down? Really?"
#endif

extern const SGpioMode gpioModePwm __attribute__((alias("gpioModeAf")));
extern const SGpioMode gpioModeLed __attribute__((alias("gpioModeOutput")));
extern const SGpioMode gpioModeLcd __attribute__((alias("gpioModeAf")));
extern const SGpioMode gpioModeAfCap __attribute__((alias("gpioModeAf")));
extern const SGpioMode gpioModeAfTsc __attribute__((alias("gpioModeAf")));


//---fin-----------------------------------------------------------------------
