//-----------------------------------------------------------------------------
///
/// \brief  I2C slave
///
///         Blah blah blub
///
/// \date   20190920
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//-----------------------------------------------------------------------------


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


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

#include <biwak/i2c.hpp>
#include <biwak/i2c_slave.h>
#include <biwak/systick.h>       // usleep
#include <lepto/log.h>
#include <lepto/lepto.h>         // IS_ENABLED


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


CI2cSlave::CI2cSlave( const CI2c &_i2c, int address)
   :m_i2c(_i2c)
   ,m_slaveAddress(address)
   ,m_addressSize( EAddressSize::_8Bits )
{
   #if IS_ENABLED( CONFIG_BIWAK_I2C_NODE_ABSENT )
      m_present=false;
   #endif
}


CI2cSlave::~CI2cSlave()
{

}


int CI2cSlave::i2cReadData(uint16_t MemAddress, void* data, int size) const
{
   HAL_StatusTypeDef status;
   #if IS_ENABLED( CONFIG_BIWAK_USE_I2C_RETRIES )
   int retries=I2C_RETRIES;
   do
   {
   #endif
         status=HAL_I2C_Mem_Read( m_i2c.getHandler(), m_slaveAddress << 1, MemAddress
                        , ( m_addressSize==EAddressSize::_16Bits )
                               ? I2C_MEMADD_SIZE_16BIT : I2C_MEMADD_SIZE_8BIT
                        , (uint8_t *)data, size, I2C_TIMEOUT);
         
         if(status)
         {
            lDebug("I2C: W: %d", m_i2c.getHandler()->ErrorCode);
         }
   #if IS_ENABLED( CONFIG_BIWAK_USE_I2C_RETRIES )
         retries--;
      } while( status && retries);
      if(status)
      {
         // An error can happen on purpose when scanning devices
         lDebug("I2C: R: %d; size=%d; addr=%d ", m_i2c.getHandler()->ErrorCode, size, MemAddress);
      }
   #endif // ? BIWAK_USE_I2C_RETRIES

   return(status);
}


int CI2cSlave::i2cWriteData(uint16_t MemAddress, const void* data, int size) const
{
   HAL_StatusTypeDef status;

   #if IS_ENABLED( CONFIG_BIWAK_USE_I2C_RETRIES )
      int retries=I2C_RETRIES;
      
      do
      {
   #endif
         
         status=HAL_I2C_Mem_Write( m_i2c.getHandler(), m_slaveAddress << 1, MemAddress
                           , ( m_addressSize==EAddressSize::_16Bits ) ? I2C_MEMADD_SIZE_16BIT : I2C_MEMADD_SIZE_8BIT
                           , (uint8_t *)data, size, I2C_TIMEOUT);
         if(status)
         {
            lDebug("I2C: W: %d", m_i2c.getHandler()->ErrorCode);
         }
   #if IS_ENABLED( CONFIG_BIWAK_USE_I2C_RETRIES )
         retries--;
      } while( status && retries);
      if(status)
      {
         // An error can happen on purpose when scanning devices
         lDebug("I2C: R: %d; size=%d; addr=%d ", m_i2c.getHandler()->ErrorCode, size, MemAddress);
      }
   #endif // ? BIWAK_USE_I2C_RETRIES

   return(status);
}


int CI2cSlave::i2cWriteData(void* data, int size) const
{
   HAL_StatusTypeDef status;

   #if IS_ENABLED( CONFIG_BIWAK_USE_I2C_RETRIES )
   
      int retries=I2C_RETRIES;
      
      do
      {
   #endif
         status=HAL_I2C_Master_Transmit( m_i2c.getHandler(), m_slaveAddress << 1, (uint8_t *)data, size, I2C_TIMEOUT );
         if(status)
         {
            lDebug("I2C: W: %d", m_i2c.getHandler()->ErrorCode);
         }
   #if IS_ENABLED( CONFIG_BIWAK_USE_I2C_RETRIES )
         retries--;
      } while( status && retries);
      if(status)
      {
         // An error can happen on purpose when scanning devices
         lDebug("I2C: R: %d; size=%d", m_i2c.getHandler()->ErrorCode, size);
      }
   #endif
      
   return(status);
}

int CI2cSlave::i2cReadData(void* data, int size ) const
{
   HAL_StatusTypeDef status;
   #if IS_ENABLED( CONFIG_BIWAK_USE_I2C_RETRIES )
      
      int retries=I2C_RETRIES;
      
      do
      {
   #endif
         status=HAL_I2C_Master_Receive( m_i2c.getHandler(), m_slaveAddress << 1, (uint8_t *)data, size, I2C_TIMEOUT );
         if(status)
         {
            lDebug("I2C: W: %d", m_i2c.getHandler()->ErrorCode);
         }
   #if IS_ENABLED( CONFIG_BIWAK_USE_I2C_RETRIES )
            retries--;
         } while( status && retries);
         if(status)
         {
            // An error can happen on purpose when scanning devices
            lDebug("I2C: R: %d; size=%d", m_i2c.getHandler()->ErrorCode, size);
         }
   #endif
         
   return(status);
}


int CI2cSlave::waitBusy()
{
   // When timeout is HAL_MAX_DELAY, HAL_I2C_IsDeviceReady can stuck.
   // Don't use BIWAK_USE_I2C_RETRIES implementation; function is supposed to
   // wait.
   // 4 retries where not ok with 5us delay on candis. 8 were ok.
   int retries=16;
   int sta;
   do{
      // No measurements for write timeouts with slow eeproms.
      // It can happen, that HAL_I2C_IsDeviceReady returns immediately
      // with an error. This function has to insert delay then.
      sta=HAL_I2C_IsDeviceReady( m_i2c.getHandler()
                                  , m_slaveAddress << 1
                                  , 16, 250);
      retries--;
      if(sta)
      {
         usleep( 5 );
      }
   }while( sta && retries );
   
   return(sta);
}


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