//-----------------------------------------------------------------------------
///
/// \brief  I2C
///
///         HAL Library needs 8bit slave addresses but we prever 7Bit notation.
///         All conversation is done here and no where else.
///
/// \date   20151225
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//-----------------------------------------------------------------------------


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


//---Own------------------------------

#include <biwak/biwak.h>            // exception
#include <biwak/i2c.hpp>
#include <biwak/stm32/i2c.hpp>
#include <biwak/gpio.hpp>
#include <biwak/rcc.h>              // rccDacClockEnable
#include <biwak/handler.h>          // IRQ_Funcion_imp
#include <biwak/exception.h>

#include <HALWrapper/stm32_i2c.h>
#include <HALWrapper/stm32_rcc.h>   // Reset
#include <HALWrapper/stm32_gpio.h>

#include <biwak/nvic.h>             // ePeripheral
#include <lepto/log.h>
#include <string.h>                 // memset()
#include <unistd.h>                 // sleep


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


CI2c::CI2c(const SI2cConfig &_configData)
{
   #if defined ( BIWAK_CONFIG_AUTO_RCC )
      rccI2cClockEnable(pHandler->Instance);
   #endif
   
   #if defined ( BIWAK_AUTO_GPIO_INIT )
   CGpio::init( _configData.eGpioPeripheralScl, _configData.eGpioPinScl, gpioModeI2c, _configData.altFuncSda );
   CGpio::init( _configData.eGpioPeripheralSda, _configData.eGpioPinSda, gpioModeI2c, _configData.altFuncScl );
   #endif // ? BIWAK_AUTO_GPIO_INIT

   pHandler=new I2C_HandleTypeDef{
      .Instance { _configData.instance },
      .Init {
         #if defined(STM32F1) || defined(STM32L1)
            .ClockSpeed = 400000,
            .DutyCycle = I2C_DUTYCYCLE_2,
            .OwnAddress1 = 0x0,
            .AddressingMode= I2C_ADDRESSINGMODE_7BIT,
            .DualAddressMode= I2C_DUALADDRESS_DISABLE,
            .OwnAddress2 = 0x0,
            .GeneralCallMode = I2C_GENERALCALL_DISABLE,
            .NoStretchMode = I2C_NOSTRETCH_DISABLE,
         #else
           
            #if defined STM32G441xx
            .Timing = 0x2010091A,      // CubeMX for 48Mhz / 400KHz
            // .Timing = 0x20303E5D,         // CubeMX for 48Mhz / 100KHz
            //.Timing = 0x1080111C,       // Timing-tool for 48Mhz / 400KHz
            // .Timing = 0x30A03536,       // Timing-tool for 48Mhz / 100KHz
            #else
            .Timing = 0x00E0D3FF,
            #endif

            .OwnAddress1 = 0x0,  //Eigene Adresse
            .AddressingMode = I2C_ADDRESSINGMODE_7BIT,  //7Bit Adressierungsmodus;
            .DualAddressMode = I2C_DUALADDRESS_DISABLE, //Keine Dualadressnutzung
         #if defined I2C_OA2_NOMASK
            .OwnAddress2 = 0x0,
            .OwnAddress2Masks = I2C_OA2_NOMASK,
         #endif // ? I2C_OA2_NOMASK
            .GeneralCallMode = I2C_GENERALCALL_DISABLE, //Kein Gerneralcall
            .NoStretchMode = I2C_NOSTRETCH_DISABLE, //Aktiviere Nostretch
         #if defined(STM32L1) || defined(STM32F4) || defined(STM32F1)
            .ClockSpeed = 400000,
            .DutyCycle = I2C_DUTYCYCLE_2,
         #else
            //pHandler->Init.Timing = 0x8088ffff; // STM32F042 13,6Khz
            //  pHandler->Init.Timing = 0x00201D2C; //Timingwert für I2C STM303 nucleo @HSI, 95Khz
            /*
            pHandler->Init.Timing = 0x0070081?8;  // 185KHz
            pHandler->Init.Timing = 0x00100101;  // 570kHz
            pHandler->Init.Timing = 0x00000000;  // 666kHz
            pHandler->Init.Timing = 0x00700818;
            pHandler->Init.Timing = 0x0050081A;
            */
            //pHandler->Init.Timing = 0x00A51314;
            //pHandler->Init.Timing = 0x00C4092A;
         #endif
         #endif // ? ! STM32F1
      }
   };

   init( _configData );

}

CI2c::~CI2c()
{

}

void CI2c::init(const SI2cConfig &configData) const
{
   #if IS_ENABLED( CONFIG_BIWAK_I2C_INTERRUPT )
   // Wen need high priority because timer might be used in ISRs.
   setNVInterrupt( configData.irqn, true, NVI_DEFAULT_PRIORITY);
   #endif

   if (HAL_I2C_Init(pHandler) != HAL_OK)
   {
      exception( );
   }

   #if 0
   if (HAL_I2CEx_ConfigAnalogFilter(pHandler, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
   {
      lFatal("");
   }
   /** Configure Digital filter
  */
   if (HAL_I2CEx_ConfigDigitalFilter(pHandler, 0) != HAL_OK)
   {
      lFatal("");
   }
   #endif
}

/// A common Problem of I2C bus hangs is that a slave hangs up and holds the
/// clock line. The slave can not be reset (without powring it off).
/// This function can at least reset the line on simple bus errors like holding
/// down clock line manually.
/*
void CI2c::reset() const
{
   HAL_I2C_DeInit(pHandler);
   //__HAL_RCC_I2C1_FORCE_RESET();
   //__HAL_RCC_I2C1_RELEASE_RESET();
   rccI2cClockDisable(pHandler->Instance);
   usleep(250*USECS_PER_MSEC);

   __HAL_I2C_RESET_HANDLE_STATE(pHandler);

   init();
   return;
}
*/

// Ignore possibly clobbered FP registers
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes"

IRQ_Funcion_imp( I2C1_IRQHandler )
{
   exception();
   return;
}

#pragma GCC diagnostic pop


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