/**
 * *************************************************************************************************************
 * @file I2cMaster.c
 * @author BH_CodeGenerator
 * @version 0.1
 * @date 2022-04-01
 * @warning <!--auto generated by Tools, do not modify or add anything, otherwise, your change will be lost!!! -->
 * @brief all the functions prototypes for I2cMaster firmware library
 * MCU / CFG Ver. :BH66F2475/1.7
 * Version = 1.0.0

 * *************************************************************************************************************
 *  @attention
 *
 *  Firmware Disclaimer Information
 *
 *  1. The customer hereby acknowledges and agrees that the program technical documentation, including the
 *     code, which is supplied by BEST HEALTH ELECTRONIC Inc., (hereinafter referred to as BestHealth) is the
 *     proprietary and confidential intellectual property of BestHealth, and is protected by copyright law and
 *     other intellectual property laws.
 *
 *  2. The customer hereby acknowledges and agrees that the program technical documentation, including the
 *     code, is confidential information belonging to BestHealth, and must not be disclosed to any third parties
 *     other than BestHealth and the customer.
 *
 *  3. The program technical documentation, including the code, is provided and for customer reference
 *     only. After delivery by BestHealth, the customer shall use the program technical documentation, including
 *     the code, at their own risk. BestHealth disclaims any expressed, implied or statutory warranties, including
 *     the warranties of merchantability, satisfactory quality and fitness for a particular purpose.
 *
 *  <h2><center>Copyright (C) BEST HEALTH ELECTRONIC Inc. All rights reserved</center></h2>
 */
#include "I2cMaster.h"
#include "..\board\BoardCfg.h"
#include "stdbool.h"

// Master I2C Pin configuration,Unified in BoardCfg.h file for easy management
// #define PIN_MASTER_I2C_SCL_P	pa
// #define PIN_MASTER_I2C_SCL_N	1
// #define PIN_MASTER_I2C_SDA_P	pa
// #define PIN_MASTER_I2C_SDA_N	2

//--You can directly include Gpio.h, here for the convenience of porting, directly copy the code here to avoid including
// clang-format off
#define PIN_ModeOutput(p, n)        { _##p##c##n = 0;}
#define PIN_ModeInput(p, n)         { _##p##c##n = 1;}
#define PIN_OutputHigh(p, n)        { _##p####n = 1;}
#define PIN_OutputLow(p, n)         { _##p####n = 0;}
#define PIN_OutputInvert(p, n)      { _##p####n = ~_##p####n;}
#define PIN_PullHigh_Enable(p, n)   { _##p##pu##n = 1;}
#define PIN_PullHigh_Disable(p, n)  { _##p##pu##n = 0;}
#define PIN_IsHigh(p, n)            _##p####n == 1
#define PIN_IsLow(p, n)             _##p####n == 0
#define PIN_Data(p, n)              _##p####n

#define SCL_INPUT_MODE(port , n)    { PIN_ModeInput(port,n);}
#define SCL_OUTPUT_MODE(port , n)	{ PIN_ModeOutput(port,n);}
#define SCL_OUTPUT_LOW(port , n)	{ PIN_OutputLow(port,n);}
#define SCL_OUTPUT_HIGH(port , n)	{ PIN_OutputHigh(port,n);}

#define SDA_DATA(port, n)			PIN_Data(port, n)
#define SDA_INPUT_MODE(port , n)	{ PIN_ModeInput(port,n);}
#define SDA_OUTPUT_MODE(port , n)	{ PIN_ModeOutput(port,n);}
#define SDA_OUTPUT_LOW(port , n)	{ PIN_OutputLow(port,n);}
#define SDA_OUTPUT_HIGH(port , n)	{ PIN_OutputHigh(port,n);}

// clang-format on

// IIC CLOCK
#define IIC_SPEED 30    // IIC Clock = 1/( instruction cycles*N)

/**
 * @brief IIC Start
 * IIC Start: when CLK is high,SDA change from high to low
 */
void I2c_Master_Start(void)
{
    SCL_OUTPUT_MODE(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    SDA_OUTPUT_MODE(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    SDA_OUTPUT_HIGH(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    SCL_OUTPUT_HIGH(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    GCC_DELAY(IIC_SPEED);
    SDA_OUTPUT_LOW(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    GCC_DELAY(IIC_SPEED);
    SCL_OUTPUT_LOW(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
}

/**
 * @brief IIC Stop
 */
void I2c_Master_Stop(void)
{
    SDA_OUTPUT_LOW(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    SDA_OUTPUT_MODE(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    GCC_DELAY(IIC_SPEED);
    SCL_OUTPUT_HIGH(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    GCC_DELAY(IIC_SPEED);
    SDA_OUTPUT_HIGH(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    GCC_DELAY(IIC_SPEED);
    SDA_INPUT_MODE(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
}

/**
 * @brief IIC sends ACK to continue receiving
 *
 */
void I2c_Master_Ack(void)
{
    SDA_OUTPUT_MODE(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    SDA_OUTPUT_LOW(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    GCC_DELAY(IIC_SPEED);
    SCL_OUTPUT_HIGH(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    GCC_DELAY(IIC_SPEED);
    SCL_OUTPUT_LOW(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    GCC_DELAY(IIC_SPEED);
    SDA_OUTPUT_HIGH(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    GCC_DELAY(IIC_SPEED);
}

/**
 * @brief IIC Send NoACK Stop
 *
 */
void I2c_Master_NoAck(void)
{
    SDA_OUTPUT_MODE(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    SDA_OUTPUT_HIGH(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    GCC_DELAY(IIC_SPEED);
    SCL_OUTPUT_HIGH(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    GCC_DELAY(IIC_SPEED);
    SCL_OUTPUT_LOW(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    GCC_DELAY(IIC_SPEED);
}

/**
 * @brief IIC Waiting for ACK Signal
 *
 */
void I2c_Master_WaitAck(void)
{
    SDA_INPUT_MODE(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    // GCC_DELAY(IIC_SPEED);
    SCL_OUTPUT_HIGH(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    uint8_t i = 0;
    while (SDA_DATA(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N) && (i < 250))
    {
        i++;
    }
    SCL_OUTPUT_LOW(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    // GCC_DELAY(IIC_SPEED);
}

/**
 * @brief IIC Write Byte
 *
 * @param WData
 */
void I2c_Master_WByte(uint8_t WData)
{
    SDA_OUTPUT_MODE(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        SCL_OUTPUT_LOW(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
        GCC_DELAY(IIC_SPEED);
        if (WData & 0x80)
        {
            SDA_OUTPUT_HIGH(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
        }
        else
        {
            SDA_OUTPUT_LOW(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
        }
        GCC_DELAY(IIC_SPEED);
        SCL_OUTPUT_HIGH(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
        GCC_DELAY(IIC_SPEED);
        WData <<= 1;
    }
    SCL_OUTPUT_LOW(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    SDA_INPUT_MODE(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
}

/**
 * @brief IIC Write Byte
 *
 * @param RxContinue Whether to continue sending and receiving
 * @return uint8_t
 */
uint8_t I2c_Master_RByte(bool RxContinue)
{
    SDA_INPUT_MODE(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
    SCL_OUTPUT_LOW(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    volatile uint8_t i, RData = 0;
    GCC_DELAY(IIC_SPEED);
    SCL_OUTPUT_HIGH(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
    for (i = 0; i < 8; i++)
    {
        SCL_OUTPUT_HIGH(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N)
        GCC_DELAY(IIC_SPEED);
        RData = (RData << 1) | SDA_DATA(PIN_MASTER_I2C_SDA_P, PIN_MASTER_I2C_SDA_N);
        SCL_OUTPUT_LOW(PIN_MASTER_I2C_SCL_P, PIN_MASTER_I2C_SCL_N);
        GCC_DELAY(IIC_SPEED);
    }
    if (RxContinue)
    {
        I2c_Master_Ack();
    }
    else
    {
        I2c_Master_NoAck();
    }
    return RData;
}

/**
 * @ Brief Write Data to Slave
 *
 * @ Param Slave_Address device I2C address
 * @ Param buf Write data start address
 * @ Param len write data length
 */
void I2c_Master_WriteData(uint8_t Slave_Address, uint8_t *buf, uint8_t len)
{
    I2c_Master_Start();
    I2c_Master_WByte(Slave_Address);
    I2c_Master_WaitAck();
    I2c_Master_WByte(*buf);
    buf++;
    I2c_Master_WaitAck();
    uint8_t i;
    for (i = 0; i < len; i++)
    {
        I2c_Master_WByte(*buf);
        buf++;
        I2c_Master_WaitAck();
    }
    I2c_Master_Stop();
}

/**
 * @brief Read data
 *
 * @param Slave_Address Device I2C Address
 * @param buf Read data start address
 * @param len Read data length
 */
void I2c_Master_ReadData(uint8_t Slave_Address, uint8_t *buf, uint8_t len)
{
    I2c_Master_Start();
    I2c_Master_WByte(Slave_Address);
    I2c_Master_WaitAck();
    I2c_Master_WByte(*buf);
    I2c_Master_WaitAck();
    buf++;
    I2c_Master_Start();
    I2c_Master_WByte(Slave_Address + 1);
    I2c_Master_WaitAck();
    GCC_DELAY(IIC_SPEED);
    uint8_t i;
    for (i = 0; i < len - 1; i++)
    {
        *buf = I2c_Master_RByte(true);
        buf++;
    }
    *buf = I2c_Master_RByte(false);
    I2c_Master_Stop();
}