#ifndef _BIWAK_GPIO_H_
#define _BIWAK_GPIO_H_
//-----------------------------------------------------------------------------
///
/// \brief  Class representing an GPIO
///
/// \date   20121107
/// \author Maximilian Seesslen <development.seesslen.net>
///
//-----------------------------------------------------------------------------


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


#include <stdbool.h>
#include <stdint.h>
#if defined ( STM32 )
   #include <HALWrapper/stm32_gpio.h>         // GPIOx defines
#else
   #define GPIO_TypeDef       void
   #define GPIO_InitTypeDef   int
   #define GPIOA              nullptr
   #define GPIOB              nullptr
   #define GPIOC              nullptr
   #define GPIOD              nullptr
   #define GPIOE              nullptr
   #define GPIOF              nullptr
   #define GPIOG              nullptr
   #define GPIO_PIN_0         0
   #define GPIO_PIN_1         1
   #define GPIO_PIN_2         1
   #define GPIO_PIN_3         1
   #define GPIO_PIN_4         1
   #define GPIO_PIN_5         1
   #define GPIO_PIN_6         1
   #define GPIO_PIN_7         1
   #define GPIO_PIN_8         1
   #define GPIO_PIN_9         1
   #define GPIO_PIN_10        1
   #define GPIO_PIN_11        1
   #define GPIO_PIN_12        1
   #define GPIO_PIN_13        1
   #define GPIO_PIN_14        1
   #define GPIO_PIN_15        1
#endif
#include <biwak/gpio_modes.hpp>


//---Declaration---------------------------------------------------------------

#define enumType char
//#define enumType unsigned int

// For debug builds, building with CONFIG_DIRECT_GPIO_INSTANCE is a tiny bit
// smaler.
// For release builds, binary is slighty bit bigger.
#define CONFIG_DIRECT_GPIO_INSTANCE
//#undef CONFIG_DIRECT_GPIO_INSTANCE
#define CONFIG_DIRECT_GPIO_PIN


#if defined CONFIG_DIRECT_GPIO_PIN
#define pinEnumToDefine(pin) (pin)
#else
#define pinEnumToDefine(pin) (1 << (int)pin)
#endif


#if defined CONFIG_DIRECT_GPIO_INSTANCE

typedef GPIO_TypeDef* EGpioPeripheral;
#define eGpioPeripheralA      GPIOA
#define eGpioPeripheralB      GPIOB
#define eGpioPeripheralC      GPIOC
#define eGpioPeripheralD      GPIOD
#define eGpioPeripheralF      GPIOF
#define eGpioPeripheralG      GPIOG

#else
enum EGpioPeripheral: enumType
{
   eGpioPeripheralNone = 0,

   eGpioPeripheralA,
   eGpioPeripheralB,
#if defined GPIOC
   eGpioPeripheralC,
#endif

#if defined GPIOD
   eGpioPeripheralD,
#endif

#if defined GPIOE
   eGpioPeripheralE,
#endif

#if defined( GPIOF )
   eGpioPeripheralF,
#endif

#if defined GPIOH
   eGpioPeripheralH,
#endif

   eGpioPeripheralMax,
};
#endif

#if defined CONFIG_DIRECT_GPIO_PIN
/*
enum EGpioPin: int
{
   eGpioPin0 = GPIO_PIN_0,
   eGpioPin1 = GPIO_PIN_1,
   eGpioPin2 = GPIO_PIN_2,
   eGpioPin3 = GPIO_PIN_3,
   eGpioPin4 = GPIO_PIN_4,
   eGpioPin5 = GPIO_PIN_5,
   eGpioPin6 = GPIO_PIN_6,
   eGpioPin7 = GPIO_PIN_7,
   eGpioPin8 = GPIO_PIN_8,
   eGpioPin9 = GPIO_PIN_9,
   eGpioPin10 = GPIO_PIN_10,
   eGpioPin11 = GPIO_PIN_11,
   eGpioPin12 = GPIO_PIN_12,
   eGpioPin13 = GPIO_PIN_13,
   eGpioPin14 = GPIO_PIN_14,
   eGpioPin15 = GPIO_PIN_15
};
*/
typedef uint16_t EGpioPin;
#define eGpioPin0      GPIO_PIN_0
#define eGpioPin1      GPIO_PIN_1
#define eGpioPin2      GPIO_PIN_2
#define eGpioPin3      GPIO_PIN_3
#define eGpioPin4      GPIO_PIN_4
#define eGpioPin5      GPIO_PIN_5
#define eGpioPin6      GPIO_PIN_6
#define eGpioPin7      GPIO_PIN_7
#define eGpioPin8      GPIO_PIN_8
#define eGpioPin9      GPIO_PIN_9
#define eGpioPin10     GPIO_PIN_10
#define eGpioPin11     GPIO_PIN_11
#define eGpioPin12     GPIO_PIN_12
#define eGpioPin13     GPIO_PIN_13
#define eGpioPin14     GPIO_PIN_14
#define eGpioPin15     GPIO_PIN_15


#endif

// STM32F1 does not support alternate function. But we need to remap some stuff
// by our self. (only STM32F103xB or STM32F1 ???)
#if defined(STM32F1)
#define     GPIO_AFx_SPI1_DEFAULT     1
#define     GPIO_AFx_SPI1_REMAP       2
#define     GPIO_AFx_SPI1_NOREMAP       20
#define     GPIO_AFx_USART1_DEFAULT   3
#define     GPIO_AFx_USART2_DEFAULT   4
#define     GPIO_AFx_I2C1_DEFAULT     5
#define     GPIO_AFx_SPI2_DEFAULT     6
#define     GPIO_AFx_CAN1_DEFAULT     7
#define     GPIO_AFx_CAN1_2           8

#define     GPIO_AFx_I2C1              0
#define     GPIO_AFx_I2C2              0
#define     GPIO_AFx_CAN1              0
//#define     GPIO_AFx_CAN1              GPIO_AFx_CAN1_DEFAULT
#define     GPIO_AFx_CAN2              0
#define     GPIO_AFx_SPI1              GPIO_AFx_SPI1_NOREMAP
#define     GPIO_AFx_SPI2              0
#define     GPIO_AFx_UART1             0
#define     GPIO_AFx_UART2             0
#define     GPIO_AFx_TIM3              0
#elif ! defined STM32

#define GPIO_AF0_SPI1                  0
#define GPIO_AF0_SPI2                  1
#define GPIO_AF0_QSPI1                 0
#define GPIO_AF0_SD                    0

#endif

class CGpioDimpl;

struct SGpioMode;

class CGpio
{
   private:
      #if ! defined( STM32 )
         CGpioDimpl *m_pDimpl;
         bool m_value;
      #endif

    protected:    // Let CLed use this members...
        EGpioPeripheral m_eGpioPeripheral;
        EGpioPin m_eGpioPin;

    public:
        CGpio( EGpioPeripheral eGpioPeripheral, EGpioPin eGpioPin
              , const SGpioMode &gpioMode=gpioModeInput, int altFunc=0);
        CGpio( const char* label
              , const SGpioMode &gpioMode=gpioModeInput, int altFunc=0);
        ~CGpio();
        static int init( EGpioPeripheral eGpioPeripheral, EGpioPin eGpioPin
                 , const SGpioMode &gpioMode=gpioModeInput, int altFunc=0 );
        int init();
        void deInit();
        void reset();
        static void setMode(EGpioPeripheral eGpioPeripheral, EGpioPin eGpioPin,
                        const SGpioMode &gpioMode , int altFunc);
        void setMode( const SGpioMode &gpioMode );
        bool getValue() const;
        #if defined (STM32)
        void setValue(bool _value) const;
        #else
        void setValue(bool value);
        #endif

        static inline int peripheralToPortSource(EGpioPeripheral _eGpioPeripheral);
        static inline int pinToPinIndex(EGpioPin _eGpioPin)
        {
            return(_eGpioPin);
        };
        EGpioPin getPin()
        {
           return(m_eGpioPin);
        }
        EGpioPeripheral getPeriphery()
        {
           return(m_eGpioPeripheral);
        }
        int getPinIndex()
        {
           return( pinToPinIndex( m_eGpioPin ) );
        }

        int getHalPin()
        {
           return( pinEnumToDefine( m_eGpioPin ) );
        }
};


//---fin-----------------------------------------------------------------------
#endif // ? ! _BIWAK_GPIO_H_
