/**
  ******************************************************************************
  * @file    i2c_common_interface.c
  * @author  MCD Application Team
  * @brief   Contains USART HW configuration
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by Puya under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

#include "i2c_common_interface.h"
#include "iwdg_interface.h"
#include "wwdg_interface.h"
#include "openbl_usart_cmd.h"

#define I2C_ADDRESS      0xA6                /* Own address 0xA6 */
#define I2C_SPEEDCLOCK   1000000             /* Communication speed : 1M */
#define I2C_DUTYCYCLE    I2C_DUTYCYCLE_16_9  /* Duty cycle */

void I2C_Init(I2C_TypeDef * i2c, I2C_HandleTypeDef* hi2c)
{
  hi2c->Instance             = i2c;
  hi2c->Init.ClockSpeed      = I2C_SPEEDCLOCK;
  hi2c->Init.DutyCycle       = I2C_DUTYCYCLE;
  hi2c->Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
  hi2c->Init.DataHoldTimeSel = I2C_DATA_HOLD_TIME_HARDWARE;   /* Data hold time selection */
  hi2c->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;       /* Disable dual address */
  hi2c->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;       /* Disable general call */
  hi2c->Init.NoStretchMode   = I2C_NOSTRETCH_ENABLE;          /* Disable clock stretching */
  hi2c->Init.OwnAddress1     = I2C_ADDRESS;
  hi2c->Init.OwnAddress2     = 0x0;                           /* Second address */

  HAL_I2C_Init(hi2c);
}

void I2C_DeInit(I2C_HandleTypeDef* hi2c)
{
  HAL_I2C_DeInit(hi2c);
}

void I2C_Read(I2C_HandleTypeDef* hi2c, uint8_t *buf, uint16_t size)
{
  __IO uint32_t tmpreg = 0x00U;

  /* Check if the I2C is already enabled */
  if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE)
  {
    /* Enable I2C peripheral */
    SET_BIT(hi2c->Instance->CR1, I2C_CR1_PE);
  }

  /* Disable Pos */
  CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS);

  /* Enable Address Acknowledge */
  SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);

  /* Wait until ADDR flag is set */
  while (READ_BIT(hi2c->Instance->SR1, I2C_SR1_ADDR) != I2C_SR1_ADDR)
  {
    OPENBL_WWDG_Refresh();
    OPENBL_IWDG_Refresh();
  }

  /* Clear ADDR flag */
  tmpreg = hi2c->Instance->SR1;
  tmpreg = hi2c->Instance->SR2;

  while (size)
  {
    /* Wait until RXNE flag is set */
    while (READ_BIT(hi2c->Instance->SR1, I2C_SR1_RXNE) != (I2C_SR1_RXNE))
    {
      OPENBL_WWDG_Refresh();
      OPENBL_IWDG_Refresh();
    }

    /* Read data from DR */
    *buf++ = (uint8_t)hi2c->Instance->DR;
    size--;

    if(READ_BIT(hi2c->Instance->SR1, I2C_SR1_BTF) == (I2C_SR1_BTF) && size != 0U)
    {
      /* Read data from DR */
      *buf++ = (uint8_t)hi2c->Instance->DR;
      size--;
    }
  }

  /* Wait until STOP flag is set */
  while (READ_BIT(hi2c->Instance->SR1, I2C_SR1_STOPF) != I2C_SR1_STOPF)
  {
    OPENBL_WWDG_Refresh();
    OPENBL_IWDG_Refresh();
  }

  /* Clear STOP flag */
  tmpreg = hi2c->Instance->SR1;
  SET_BIT(hi2c->Instance->CR1, I2C_CR1_PE);

  /* Disable Address Acknowledge */
  CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);

  CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_PE);
}

void I2C_Write(I2C_HandleTypeDef* hi2c, uint8_t *buf, uint16_t size)
{
  __IO uint32_t tmpreg = 0x00U;

  /* Check if the I2C is already enabled */
  if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE)
  {
    /* Enable I2C peripheral */
    SET_BIT(hi2c->Instance->CR1, I2C_CR1_PE);
  }

  /* Disable Pos */
  CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS);

  /* Enable Address Acknowledge */
  SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);

  /* Wait until ADDR flag is set */
  while(READ_BIT(hi2c->Instance->SR1, I2C_SR1_ADDR) != I2C_SR1_ADDR)
  {
    OPENBL_WWDG_Refresh();
    OPENBL_IWDG_Refresh();
  }

  /* Clear ADDR flag */
  tmpreg = hi2c->Instance->SR1;
  tmpreg = hi2c->Instance->SR2;

  while (size)
  {
    /* Wait until TXE flag is set */
    while (READ_BIT(hi2c->Instance->SR1, I2C_SR1_TXE) != (I2C_SR1_TXE))
    {
      OPENBL_WWDG_Refresh();
      OPENBL_IWDG_Refresh();
    }

    /* Write data to DR */
    hi2c->Instance->DR = *buf++;
    size--;

    if(READ_BIT(hi2c->Instance->SR1, I2C_SR1_BTF) == (I2C_SR1_BTF))
    {
      /* Write data to DR */
      hi2c->Instance->DR = *buf++;
      size--;
    }
  }

  /* Wait until AF flag is set */
  while (READ_BIT(hi2c->Instance->SR1, I2C_SR1_AF) != I2C_SR1_AF)
  {
    OPENBL_WWDG_Refresh();
    OPENBL_IWDG_Refresh();
  }

  /* Clear AF flag */
  CLEAR_BIT(hi2c->Instance->SR1, I2C_SR1_AF);

  /* Disable Address Acknowledge */
  CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);

  CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_PE);
}

uint8_t I2C_ProtocolDetection(I2C_HandleTypeDef* hi2c)
{
  __IO uint32_t tmpreg = 0x00U;
  uint8_t tmp = 0U;

  OPENBL_WWDG_Refresh();
  OPENBL_IWDG_Refresh();

  /* Check if the I2C3 is addressed */

  /* Disable Pos */
  CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS);

  /* Enable Address Acknowledge */
  SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);

  /* Check if the I2C3 is addressed */
  if (READ_BIT(hi2c->Instance->SR1, I2C_SR1_ADDR) != I2C_SR1_ADDR)
  {
    return 0;
  }

  /* Clear ADDR flag */
  tmpreg = hi2c->Instance->SR1;
  tmpreg = hi2c->Instance->SR2;

  /* Wait until RXNE flag is set */
  while (READ_BIT(hi2c->Instance->SR1, I2C_SR1_RXNE) != (I2C_SR1_RXNE))
  {
    OPENBL_WWDG_Refresh();
    OPENBL_IWDG_Refresh();
  }

  /* Read data from DR */
  if (SYNC_BYTE != (uint8_t)hi2c->Instance->DR)
  {
    return 0;
  }

  if(READ_BIT(hi2c->Instance->SR1, I2C_SR1_BTF) == (I2C_SR1_BTF))
  {
    /* Read data from DR */
    tmpreg = (uint8_t)hi2c->Instance->DR;
  }

  /* Wait until STOP flag is set */
  while (READ_BIT(hi2c->Instance->SR1, I2C_SR1_STOPF) != I2C_SR1_STOPF)
  {
    /* Read data from DR */
    tmpreg = (uint8_t)hi2c->Instance->DR;
    OPENBL_WWDG_Refresh();
    OPENBL_IWDG_Refresh();
  }

  /* Clear STOP flag */
  tmpreg = hi2c->Instance->SR1;
  SET_BIT(hi2c->Instance->CR1, I2C_CR1_PE);

  /* Disable Address Acknowledge */
  CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);

  /* Aknowledge the host */
  tmp = ACK_BYTE;
  I2C_Write(hi2c, &tmp, 1);

  return 1;
}

/************************ (C) COPYRIGHT Puya *****END OF FILE****/
