/*
 * I2C.cpp
 *
 *  Created on: Aug 5, 2023
 *      Author: Carst
 */
#include <stm32g0xx_ll_bus.h>
#include <stm32g0xx_ll_gpio.h>
#include <stm32g0xx_ll_i2c.h>
#include "I2C.hpp"

namespace ElektronischeLast
{

  iI2C::iI2C(std::uint8_t device_address)
  {
    this->device_address = device_address;

  }
  void iI2C::init(void)
  {
    LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
    /**I2C2 GPIO Configuration
    PA11 [PA9]   ------> I2C2_SCL
    PA12 [PA10]   ------> I2C2_SDA
    */
    LL_GPIO_InitTypeDef GPIO_InitStruct =
    {
      .Pin = LL_GPIO_PIN_11,
      .Mode = LL_GPIO_MODE_ALTERNATE,
      .Speed = LL_GPIO_SPEED_FREQ_LOW,
      .OutputType = LL_GPIO_OUTPUT_OPENDRAIN,
      .Pull = LL_GPIO_PULL_NO,
      .Alternate = LL_GPIO_AF_6,
    };
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_12;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /** I2C Initialization
    */
    LL_I2C_InitTypeDef I2C_InitStruct =
    {
      .PeripheralMode = LL_I2C_MODE_I2C,
      .Timing = 0x10707DBCUL,
      .AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE,
      .DigitalFilter = 0UL,
      .OwnAddress1 = 0UL,
      .TypeAcknowledge = LL_I2C_ACK,
      .OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT,
    };
    LL_I2C_Init(I2C2, &I2C_InitStruct);
    LL_I2C_EnableAutoEndMode(I2C2);
    LL_I2C_SetOwnAddress2(I2C2, 0, LL_I2C_OWNADDRESS2_NOMASK);
    LL_I2C_DisableOwnAddress2(I2C2);
    LL_I2C_DisableGeneralCall(I2C2);
    LL_I2C_EnableClockStretching(I2C2);
    LL_I2C_SetMasterAddressingMode(I2C2, LL_I2C_ADDRESSING_MODE_7BIT);

    LL_I2C_Enable(I2C2);
  }
  bool iI2C::read(std::uint32_t address, std::uint32_t length, std::uint8_t buffer[])
  {
    std::uint32_t transfered = 0UL;
    LL_I2C_SetSlaveAddr(I2C2, this->device_address + ((address >= 256U) ? 2U : 0U));
    LL_I2C_SetTransferRequest(I2C2, LL_I2C_REQUEST_WRITE);
    LL_I2C_SetTransferSize(I2C2, 1U);
    LL_I2C_DisableAutoEndMode(I2C2);
    LL_I2C_GenerateStartCondition(I2C2);
    while(!LL_I2C_IsActiveFlag_TXIS(I2C2))
    {
      if(LL_I2C_IsActiveFlag_NACK(I2C2))
      {
        return false;
      }
    }
    LL_I2C_TransmitData8(I2C2, address & 0xFFU);
    while(!LL_I2C_IsActiveFlag_TC(I2C2));

    LL_I2C_SetTransferRequest(I2C2, LL_I2C_REQUEST_READ);
    LL_I2C_SetTransferSize(I2C2, length);
    LL_I2C_EnableAutoEndMode(I2C2);
    LL_I2C_GenerateStartCondition(I2C2);
    while(transfered < length)
    {
      if(LL_I2C_IsActiveFlag_RXNE(I2C2))
      {
        buffer[transfered++] = LL_I2C_ReceiveData8(I2C2);
      }
    }

    return true;
  }
  bool iI2C::write(std::uint32_t address, std::uint32_t length, std::uint8_t buffer[])
  {
    std::uint32_t transfered = 0UL;
    LL_I2C_SetSlaveAddr(I2C2, this->device_address + ((address >= 256U) ? 2U : 0U));
    LL_I2C_SetTransferRequest(I2C2, LL_I2C_REQUEST_WRITE);
    LL_I2C_SetTransferSize(I2C2, 1U + length);
    LL_I2C_EnableAutoEndMode(I2C2);
    LL_I2C_GenerateStartCondition(I2C2);
    while (transfered < (length + 1U))
    {
      if(LL_I2C_IsActiveFlag_TXIS(I2C2))
      {
        if(transfered == 0U)
        {
          LL_I2C_TransmitData8(I2C2, address & 0xFFU);
          transfered++;
        }
        else
        {
          LL_I2C_TransmitData8(I2C2, buffer[transfered++ - 1U]);
        }
      }
    }

    return true;
  }
}