//#############################################################################
// $Copyright:
// Copyright (C) 2017-2023 Texas Instruments Incorporated - http://www.ti.com/
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//   Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the
//   distribution.
//
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//#############################################################################


//! \file   /solutions/tidm_02010_dmpfc/common/source/communication.c
//! \brief  This project is used to control two motor and pfc with one MCU
//!         Support for dualmtrpfc board with F28002x/F28003x/F280013x
//!

//
// include the related header files
//
#include "sys_main.h"

#include "communication.h"


//
// Defines
//
I2CMsg_Obj i2cMsgData;
I2CMsg_Handle i2cMsgHandle;

uint16_t i2cMsgTxBuffer[I2C_BUFFER_SIZE];  // Array holding message data.
uint16_t i2cMsgRxBuffer[I2C_BUFFER_SIZE];  // Array holding message data.

void I2C_writeAT24C32(I2CMsg_Handle msgHandle, uint32_t i2cBase)
{
    I2CMsg_Obj *msg = (I2CMsg_Obj *)msgHandle;

    msg->slaveAddr = I2C_AT24C32_D1_ADDR;
    msg->numOfAddrBytes = 1;
    msg->numOfDataBytes = 2;

    return;
}

void I2C_readAT24C32(I2CMsg_Handle msgHandle, uint32_t i2cBase)
{
    I2CMsg_Obj *msg = (I2CMsg_Obj *)msgHandle;

    if(msg->msgStatus == I2C_STATUS_INACTIVE)
    {
        msg->slaveAddr = I2C_AT24C32_D1_ADDR;
        msg->numOfAddrBytes = 1;
        msg->numOfDataBytes = 2;

        msg->msgStatus = I2C_STATUS_SEND_WITHSTOP;
    }

    return;
}

// I2C Scan Bus State
void I2C_scanBusState(I2CMsg_Handle msgHandle, uint32_t i2cBase)
{
    I2CMsg_Obj *msg = (I2CMsg_Obj *)msgHandle;

    I2C_InterruptSource intSource;
    uint16_t i;

    // Read interrupt source
    intSource = I2C_getInterruptSource(i2cBase);

    // Interrupt source = stop condition detected
    if(intSource == I2C_INTSRC_STOP_CONDITION)
    {
        // If completed message was writing data, reset msg to inactive state
        if(msg->msgStatus == I2C_STATUS_WRITE_BUSY)
        {
            msg->msgStatus = I2C_STATUS_INACTIVE;
        }
        else
        {
            // If a message receives a NACK during the address setup portion of
            // the EEPROM read, the code further below included in the register
            // access ready interrupt source code will generate a stop
            // condition. After the stop condition is received (here), set the
            // message status to try again. User may want to limit the number
            // of retries before generating an error.
            if(msg->msgStatus == I2C_STATUS_SEND_NOSTOP_BUSY)
            {
                msg->msgStatus = I2C_STATUS_SEND_NOSTOP;
            }
            // If completed message was reading EEPROM data, reset message to
            // inactive state and read data from FIFO.
            else if(msg->msgStatus == I2C_STATUS_READ_BUSY)
            {
                msg->msgStatus = I2C_STATUS_INACTIVE;

                for(i = 0; i < msg->numOfDataBytes; i++)
                {
                    msg->pRxMsgBuffer[i++] = I2C_getData(i2cBase);
                }
            }
        }
    }
    // Interrupt source = Register Access Ready
    // This interrupt is used to determine when the EEPROM address setup
    // portion of the read data communication is complete. Since no stop bit
    // is commanded, this flag tells us when the message has been sent
    // instead of the SCD flag.
    else if(intSource == I2C_INTSRC_REG_ACCESS_RDY)
    {
        // If a NACK is received, clear the NACK bit and command a stop.
        // Otherwise, move on to the read data portion of the communication.
        if((I2C_getStatus(i2cBase) & I2C_STS_NO_ACK) != 0)
        {
            I2C_sendStopCondition(i2cBase);
            I2C_clearStatus(i2cBase, I2C_STS_NO_ACK);
        }
        else if(msg->msgStatus == I2C_STATUS_SEND_NOSTOP_BUSY)
        {
            msg->msgStatus = I2C_STATUS_RESTART;
        }
    }

    return;
}

// Function to send the data that is to be written to the EEPROM
uint16_t I2C_writeData(I2CMsg_Handle msgHandle, uint32_t i2cBase)
{
    I2CMsg_Obj *msg = (I2CMsg_Obj *)msgHandle;

    uint16_t i;

    // Wait until the STP bit is cleared from any previous master
    // communication. Clearing of this bit by the module is delayed until after
    // the SCD bit is set. If this bit is not checked prior to initiating a new
    // message, the I2C could get confused.
    if(I2C_getStopConditionStatus(i2cBase))
    {
        return(I2C_ERROR_STOP_NOT_READY);
    }

    // Setup slave address
    I2C_setSlaveAddress(i2cBase, msg->slaveAddr);

    // Check if bus busy
    if(I2C_isBusBusy(i2cBase))
    {
        return(I2C_ERROR_BUS_BUSY);
    }

    if(msg->numOfAddrBytes == 2)
    {
        // Setup number of bytes to send msgBuffer and address
        I2C_setDataCount(i2cBase, (msg->numOfDataBytes + 2));

        // Setup data to send
        I2C_putData(i2cBase, msg->memoryHighAddr);
        I2C_putData(i2cBase, msg->memoryLowAddr);
    }
    else if(msg->numOfAddrBytes == 1)
    {
        // Setup number of bytes to send msgBuffer and address
        I2C_setDataCount(i2cBase, (msg->numOfDataBytes + 1));

        // Setup data to send
        I2C_putData(i2cBase, msg->memoryLowAddr);
    }

    for (i = 0; i < msg->numOfDataBytes; i++)
    {
        I2C_putData(i2cBase, msg->pTxMsgBuffer[i++]);
    }

    // Send start as master transmitter
    I2C_setConfig(i2cBase, I2C_MASTER_SEND_MODE);
    I2C_sendStartCondition(i2cBase);
    I2C_sendStopCondition(i2cBase);

    return(I2C_SUCCESS);
}

// Function to prepare for the data that is to be read from the EEPROM
uint16_t I2C_readData(I2CMsg_Handle msgHandle, uint32_t i2cBase)
{
    I2CMsg_Obj *msg = (I2CMsg_Obj *)msgHandle;

    // Wait until the STP bit is cleared from any previous master
    // communication. Clearing of this bit by the module is delayed until after
    // the SCD bit is set. If this bit is not checked prior to initiating a new
    // message, the I2C could get confused.
    if(I2C_getStopConditionStatus(i2cBase))
    {
        return(I2C_ERROR_STOP_NOT_READY);
    }

    // Setup slave address
    I2C_setSlaveAddress(i2cBase, msg->slaveAddr);

    // If we are in the the address setup phase, send the address without a
    // stop condition.
    if(msg->msgStatus == I2C_STATUS_SEND_NOSTOP)
    {
        // Check if bus busy
        if(I2C_isBusBusy(i2cBase))
        {
            return(I2C_ERROR_BUS_BUSY);
        }

        if(msg->numOfAddrBytes == 2)
        {
            // Send data to setup EEPROM address
            I2C_setDataCount(i2cBase, 2);
            I2C_putData(i2cBase, msg->memoryHighAddr);
            I2C_putData(i2cBase, msg->memoryLowAddr);
        }
        else if(msg->numOfAddrBytes == 1)
        {
            // Send data to setup EEPROM address
            I2C_setDataCount(i2cBase, 1);
            I2C_putData(i2cBase, msg->memoryLowAddr);
        }

        I2C_setConfig(i2cBase, I2C_MASTER_SEND_MODE);
        I2C_sendStartCondition(i2cBase);
    }
    else if(msg->msgStatus == I2C_STATUS_RESTART)
    {
        // Address setup phase has completed. Now setup how many bytes expected
        // and send restart as master-receiver.
        I2C_setDataCount(i2cBase, (msg->numOfDataBytes));
        I2C_setConfig(i2cBase, I2C_MASTER_RECEIVE_MODE);
        I2C_sendStartCondition(i2cBase);
        I2C_sendStopCondition(i2cBase);
    }

    return(I2C_SUCCESS);
}

//
uint16_t I2C_checkBusStatus(uint32_t i2cBase)
{
    if(I2C_isBusBusy(i2cBase))
    {
        return(I2C_ERROR_BUS_BUSY);
    }

    if(I2C_getStopConditionStatus(i2cBase))
    {
        return(I2C_ERROR_STOP_NOT_READY);
    }

    return(I2C_SUCCESS);
}

//
uint16_t I2C_handleNACK(uint32_t i2cBase)
{
    if(I2C_getStatus(i2cBase) & I2C_STS_NO_ACK)
    {
        I2C_clearStatus(i2cBase, I2C_STS_NO_ACK);
        I2C_sendStopCondition(i2cBase);

        return(I2C_ERROR_NACK_RECEIVED);
    }

    return(I2C_SUCCESS);
}


//
//-- end of this file ----------------------------------------------------------
//
