//*****************************************************************************
//
// smbus.c - SMBus protocol layer API.
//
// Copyright (c) 2010-2020 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
// 
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 2.2.0.295 of the Tiva Utility Library.
//
//*****************************************************************************

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_i2c.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "driverlib/i2c.h"
#include "driverlib/sw_crc.h"
#include "driverlib/sysctl.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/udma.h"
#include "utils/smbus.h"

//*****************************************************************************
//
//! \addtogroup smbus_api
//! @{
//
//*****************************************************************************

//*****************************************************************************
//
// The states for the master and slave interrupt handler state machines.
//
//*****************************************************************************
#define SMBUS_STATE_IDLE                0
#define SMBUS_STATE_SLAVE_POST_COMMAND  1
#define SMBUS_STATE_WRITE_BLOCK_SIZE    2
#define SMBUS_STATE_WRITE_NEXT          3
#define SMBUS_STATE_WRITE_FINAL         4
#define SMBUS_STATE_WRITE_DONE          5
#define SMBUS_STATE_READ_ONE            6
#define SMBUS_STATE_READ_FIRST          7
#define SMBUS_STATE_READ_BLOCK_SIZE     8
#define SMBUS_STATE_READ_NEXT           9
#define SMBUS_STATE_READ_FINAL          10
#define SMBUS_STATE_READ_WAIT           11
#define SMBUS_STATE_READ_PEC            12
#define SMBUS_STATE_READ_DONE           13
#define SMBUS_STATE_READ_ERROR_STOP     14

//*****************************************************************************
//
// Status flags for various instance-specific tasks.
//
//*****************************************************************************
#define FLAG_PEC                        0
#define FLAG_PROCESS_CALL               1
#define FLAG_BLOCK_TRANSFER             2
#define FLAG_TRANSFER_IN_PROGRESS       3
#define FLAG_RAW_I2C                    4
#define FLAG_ADDRESS_RESOLVED           5
#define FLAG_ADDRESS_VALID              6
#define FLAG_ARP                        7
//*****************************************************************************
//
//! Enables Packet Error Checking (PEC).
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function enables the transmission and checking of a PEC byte in SMBus
//! transactions.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusPECEnable(tSMBus *psSMBus)
{
    //
    // Set the PEC flag in the configuration structure.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 1;
}

//*****************************************************************************
//
//! Disables Packet Error Checking (PEC).
//!
//!    \param psSMBus specifies the SMBus configuration structure.
//!
//! This function disables the transmission and checking of a PEC byte in SMBus
//! transactions.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusPECDisable(tSMBus *psSMBus)
{
    //
    // Clear the PEC flag in the configuration structure.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
}

//*****************************************************************************
//
//! Sets the ARP flag in the configuration structure.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function sets the Address Resolution Protocol (ARP) flag in the
//! configuration structure.  This flag can be used to track the state of a
//! device during the ARP process.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusARPEnable(tSMBus *psSMBus)
{
    //
    // Set the ARP flag in the configuration structure.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_ARP) = 1;
}

//*****************************************************************************
//
//! Clears the ARP flag in the configuration structure.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function clears the Address Resolution Protocol (ARP) flag in the
//! configuration structure.  This flag can be used to track the state of a
//! device during the ARP process.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusARPDisable(tSMBus *psSMBus)
{
    //
    // Clear the ARP flag in the configuration structure.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_ARP) = 0;
}

//*****************************************************************************
//
//! Returns the number of bytes in the receive buffer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function returns the number of bytes in the active receive buffer.
//! It can be used to determine how many bytes have been received in the slave
//! receive or master block read configurations.
//!
//! \return Number of bytes in the buffer.
//
//*****************************************************************************
uint8_t
SMBusRxPacketSizeGet(tSMBus *psSMBus)
{
    //
    // Return the number of bytes received.
    //
    return(psSMBus->ui8RxIndex);
}

//*****************************************************************************
//
//! Returns the state of an SMBus transfer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function returns the status of an SMBus transaction.  It can be used
//! to determine whether a transfer is ongoing or complete.
//!
//! \return Returns \b SMBUS_TRANSFER_IN_PROGRESS if transfer is ongoing, or
//! \b SMBUS_TRANSFER_COMPLETE if transfer has completed.
//
//*****************************************************************************
tSMBusStatus
SMBusStatusGet(tSMBus *psSMBus)
{
    //
    // Check to see if there is an ongoing transfer.
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS))
    {
        //
        // If the flag is set, return in progress status.
        //
        return(SMBUS_TRANSFER_IN_PROGRESS);
    }

    //
    // If the transfer complete flag is cleared, transfer is done.
    //
    else
    {
        //
        // If the flag isn't set, return complete status.
        //
        return(SMBUS_TRANSFER_COMPLETE);
    }
}

//*****************************************************************************
//
//! Encodes a UDID structure and address into SMBus-transferable byte order.
//!
//! \param pUDID specifies the structure to encode.
//! \param ui8Address specifies the address to send with the UDID (byte 17).
//! \param pui8Data specifies the location of the destination data buffer.
//!
//! This function takes a tSMBusUDID structure and re-orders the bytes so that
//! it can be transferred on the bus.  The destination data buffer must contain
//! at least 17 bytes.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusARPUDIDPacketEncode(tSMBusUDID *pUDID, uint8_t ui8Address,
                         uint8_t *pui8Data)
{
    //
    // Place data from the UDID structure and address into the data buffer
    // using the correct MSB->LSB + address order.
    //
    pui8Data[0] = pUDID->ui8DeviceCapabilities;
    pui8Data[1] = pUDID->ui8Version;
    pui8Data[2] = (uint8_t)((pUDID->ui16VendorID & 0xff00) >> 8);
    pui8Data[3] = (uint8_t)(pUDID->ui16VendorID & 0x00ff);
    pui8Data[4] = (uint8_t)((pUDID->ui16DeviceID & 0xff00) >> 8);
    pui8Data[5] = (uint8_t)(pUDID->ui16DeviceID & 0x00ff);
    pui8Data[6] = (uint8_t)((pUDID->ui16Interface & 0xff00) >> 8);
    pui8Data[7] = (uint8_t)(pUDID->ui16Interface & 0x00ff);
    pui8Data[8] = (uint8_t)((pUDID->ui16SubSystemVendorID & 0xff00) >> 8);
    pui8Data[9] = (uint8_t)(pUDID->ui16SubSystemVendorID & 0x00ff);
    pui8Data[10] = (uint8_t)((pUDID->ui16SubSystemDeviceID & 0xff00) >> 8);
    pui8Data[11] = (uint8_t)(pUDID->ui16SubSystemDeviceID & 0x00ff);
    pui8Data[12] = (uint8_t)((pUDID->ui32VendorSpecificID & 0xff000000) >>
                             24);
    pui8Data[13] = (uint8_t)((pUDID->ui32VendorSpecificID & 0x00ff0000) >>
                             16);
    pui8Data[14] = (uint8_t)((pUDID->ui32VendorSpecificID & 0x0000ff00) >>
                             8);
    pui8Data[15] = (uint8_t)(pUDID->ui32VendorSpecificID & 0x000000ff);
    pui8Data[16] = ui8Address;
}

//*****************************************************************************
//
//! Decodes an SMBus packet into a UDID structure and address.
//!
//! \param pUDID specifies the structure that is updated with new data.
//! \param pui8Address specifies the location of the variable that holds the
//! the address sent with the UDID (byte 17).
//! \param pui8Data specifies the location of the source data.
//!
//! This function takes a data buffer and decodes it into a tSMBusUDID
//! structure and an address variable.  It is assumed that there are 17 bytes
//! in the data buffer.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusARPUDIDPacketDecode(tSMBusUDID *pUDID, uint8_t *pui8Address,
                         uint8_t *pui8Data)
{
    //
    // Populate the UDID structure with data from the input data buffer.
    //
    pUDID->ui8DeviceCapabilities = pui8Data[0];
    pUDID->ui8Version = pui8Data[1];
    pUDID->ui16VendorID = (uint16_t)((pui8Data[2] << 8) | pui8Data[3]);
    pUDID->ui16DeviceID = (uint16_t)((pui8Data[4] << 8) | pui8Data[5]);
    pUDID->ui16Interface = (uint16_t)((pui8Data[6] << 8) | pui8Data[7]);
    pUDID->ui16SubSystemVendorID = (uint16_t)((pui8Data[8] << 8) |
                                              pui8Data[9]);
    pUDID->ui16SubSystemDeviceID = (uint16_t)((pui8Data[10] << 8) |
                                              pui8Data[11]);
    pUDID->ui32VendorSpecificID = (uint32_t)((pui8Data[12] << 24) |
                                             (pui8Data[13] << 16) |
                                             (pui8Data[14] << 8) |
                                             pui8Data[15]);

    //
    // Populate the address.
    //
    *pui8Address = pui8Data[16];
}

//*****************************************************************************
//
//! Initiates a master Quick Command transfer to an SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param bData is the value of the single data bit sent to the slave.
//!
//! Quick Command is an SMBus protocol that sends a single data bit using the
//! I2C R/S bit.  This function issues a single I2C transfer with the slave
//! address and data bit.
//!
//! This protocol does not support PEC.  The PEC flag is explicitly cleared
//! within this function, so if PEC is enabled prior to calling it, it must
//! be re-enabled afterwards.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterQuickCommand(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                        bool bData)
{
    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->ui8TxSize = 0;
    psSMBus->ui8RxSize = 0;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Clear the block transfer, process call and raw I2C flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // This protocol does NOT support PEC, so the flag must be cleared.  If
    // PEC is needed again after this transaction, it should be explicitly
    // enabled again.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;

    //
    // Initialize the buffer index to 0 and the interrupt state machine to
    // the appropriate state so that there is a known starting point
    // for each transaction.
    //
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8MasterState = SMBUS_STATE_IDLE;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, bData);

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Initiate the write operation.
    //
    MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_QUICK_COMMAND);

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a master Host Notify transfer to the SMBus Host.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8OwnSlaveAddress specifies the peripheral's own slave address.
//! \param pui8Data is a pointer to the two byte data payload.
//!
//! The Host Notify protocol is used by SMBus slaves to alert the bus Host
//! about an event.  Most slave devices that operate in this environment only
//! become a bus master when this packet type is used.  Host Notify always
//! sends two data bytes to the host along with the peripheral's own slave
//! address so that the Host knows which peripheral requested the Host's
//! attention.
//!
//! This protocol does not support PEC.  The PEC flag is explicitly cleared
//! within this function, so if PEC is enabled prior to calling it, it must
//! be re-enabled afterwards.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterHostNotify(tSMBus *psSMBus, uint8_t ui8OwnSlaveAddress,
                      uint8_t *pui8Data)
{
    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = SMBUS_ADR_HOST;
    psSMBus->pui8TxBuffer = pui8Data;
    psSMBus->ui8TxSize = 2;
    psSMBus->ui8RxSize = 0;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Clear the block transfer, process call and raw I2C flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // This protocol does NOT support PEC, so the flag must be cleared.  If
    // PEC is needed again after this transaction, it should be explicitly
    // enabled again.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;

    //
    // Initialize the buffer index to 0 and the interrupt state machine to
    // the appropriate state so that there is a known starting point
    // for each transaction.
    //
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Put the SMBus command code on the bus.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, ui8OwnSlaveAddress);

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Initiate the write operation.
    //
    MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                         I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a master Send Byte transfer to an SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param ui8Data is the data byte to send to the slave.
//!
//! The Send Byte protocol is a basic SMBus protocol that sends a single data
//! byte to the slave.  Unlike most of the other SMBus protocols, Send Byte
//! does not send a ``command'' byte before the data payload and is intended
//! for basic communication.
//!
//! This protocol supports the optional PEC byte for error checking.  To use
//! PEC, SMBusPECEnable() must be called before this function.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterByteSend(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                    uint8_t ui8Data)
{
    uint8_t ui8TempData;

    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->ui8CurrentCommand = ui8Data;
    psSMBus->pui8TxBuffer = &ui8Data;
    psSMBus->ui8TxSize = 0;
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8RxSize = 0;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Clear the block transfer, process call and raw I2C flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Put the data byte on the bus.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, ui8Data);

    //
    // Calculate the CRC for PEC (if used).
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
    {
        //
        // Place the target slave address into a temporary data variable and
        // make sure the R/S bit is set to '0' for the CRC calculation.
        //
        ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;

        //
        // Start off by calculating the CRC of the target slave address with
        // an initial value of 0.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);

        //
        // Add the data to the running CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &psSMBus->pui8TxBuffer[0],
                                                  1);

        //
        // Update the state machine.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;

        //
        // Make sure that the bus is idle.
        //
        if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
        {
            return(SMBUS_BUS_BUSY);
        }

        //
        // Initiate the write operation.
        //
        MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                             I2C_MASTER_CMD_BURST_SEND_START);
    }
    else
    {
        //
        // Update the state machine.  Since it's the only byte being sent,
        // the state machine's next state is idle.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_IDLE;

        //
        // Make sure that the bus is idle.
        //
        if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
        {
            return(SMBUS_BUS_BUSY);
        }

        //
        // Initiate the write operation.
        //
        MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_SINGLE_SEND);
    }

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a master Receive Byte transfer to an SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param pui8Data is a pointer to the location to store the received data
//! byte.
//!
//! The Receive Byte protocol is a basic SMBus protocol that receives a single
//! data byte from the slave.  Unlike most of the other SMBus protocols,
//! Receive Byte does not send a ``command'' byte before the data payload and
//! is intended for basic communication.
//!
//! This protocol supports the optional PEC byte for error checking.  To use
//! PEC, SMBusPECEnable() must be called before this function.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterByteReceive(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                       uint8_t *pui8Data)
{
    uint8_t ui8TempData;

    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->ui8TxSize = 0;
    psSMBus->ui8TxIndex = 0;
    psSMBus->pui8RxBuffer = pui8Data;
    psSMBus->ui8RxSize = 1;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Clear the block transfer, process call and raw I2C flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, true);

    //
    // Calculate the CRC for PEC (if used).
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
    {
        //
        // Place the target slave address into a temporary data variable and
        // set the R/S bit to '1' for the CRC calculation.
        //
        ui8TempData = ((psSMBus->ui8TargetSlaveAddress << 1) & 0xfe) | 1;

        //
        // Start off by calculating the CRC of the target slave address with
        // an initial value of 0.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);

        //
        // Update the state machine.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;

        //
        // Make sure that the bus is idle.
        //
        if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
        {
            return(SMBUS_BUS_BUSY);
        }

        //
        // Initiate the read operation.
        //
        MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                             I2C_MASTER_CMD_BURST_RECEIVE_START);
    }
    else
    {
        //
        // Update the state machine.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;

        //
        // Make sure that the bus is idle.
        //
        if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
        {
            return(SMBUS_BUS_BUSY);
        }

        //
        // Initiate the read operation.
        //
        MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                             I2C_MASTER_CMD_SINGLE_RECEIVE);
    }

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a master Write Byte or Write Word transfer to an SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param ui8Command is the command byte sent before the data payload.
//! \param pui8Data is a pointer to the transmit data buffer.
//! \param ui8Size is the number of bytes to send to the slave.
//!
//! This function supports both the Write Byte and Write Word protocols.  The
//! amount of data to send is user defined, but limited to 1 or 2 bytes.
//!
//! This protocol supports the optional PEC byte for error checking.  To use
//! PEC, SMBusPECEnable() must be called before this function.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 2, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterByteWordWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                         uint8_t ui8Command, uint8_t *pui8Data,
                         uint8_t ui8Size)
{
    uint8_t ui8TempData;

    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // If more than 2 bytes are requested, indicate error.
    //
    if(ui8Size > 2)
    {
        return(SMBUS_DATA_SIZE_ERROR);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->ui8CurrentCommand = ui8Command;
    psSMBus->pui8TxBuffer = pui8Data;
    psSMBus->ui8TxSize = ui8Size;
    psSMBus->ui8RxSize = 0;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Clear the block transfer, process call and raw I2C flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // Initialize the buffer index to 0 and the interrupt state machine to
    // the appropriate state so that there is a known starting point
    // for each transaction.
    //
    psSMBus->ui8TxIndex = 0;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Calculate the CRC for PEC (if used).
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
    {
        //
        // Place the target slave address into a temporary data variable and
        // make sure the R/S bit is set to '0' for the CRC calculation.
        //
        ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;

        //
        // Start off by calculating the CRC of the target slave address with
        // an initial value of 0.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);

        //
        // Add the command to the running CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &psSMBus->ui8CurrentCommand,
                                                  1);

        //
        // Add the data array to the calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  psSMBus->pui8TxBuffer,
                                                  psSMBus->ui8TxSize);

        //
        // Set the next state.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
    }
    else
    {
        //
        // If only one byte to send, move to the final state.
        //
        if(ui8Size == 1)
        {
            //
            // Set the next state.
            //
            psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
        }
        else
        {
            //
            // Set the next state.
            //
            psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
        }
    }

    //
    // Put the SMBus command code on the bus.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Initiate the write operation.
    //
    MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                         I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a master Read Byte or Read Word transfer to an SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param ui8Command is the command byte sent before the data is requested.
//! \param pui8Data is a pointer to the receive data buffer.
//! \param ui8Size is the number of bytes to receive from the slave.
//!
//! This function supports both the Read Byte and Read Word protocols.  The
//! amount of data to receive is user defined, but limited to 1 or 2 bytes.
//!
//! This protocol supports the optional PEC byte for error checking.  To use
//! PEC, SMBusPECEnable() must be called before this function.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 2, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterByteWordRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                        uint8_t ui8Command, uint8_t *pui8Data,
                        uint8_t ui8Size)
{
    uint8_t ui8TempData;

    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // If more than 2 bytes are requested, indicate error.
    //
    if(ui8Size > 2)
    {
        return(SMBUS_DATA_SIZE_ERROR);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->ui8CurrentCommand = ui8Command;
    psSMBus->pui8RxBuffer = pui8Data;
    psSMBus->ui8TxSize = 0;
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8RxSize = ui8Size;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Clear the block transfer, process call and raw I2C flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Put the SMBus command code on the bus.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);

    //
    // Calculate the CRC for PEC (if used).
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
    {
        //
        // Place the target slave address into a temporary data variable and
        // set the R/S bit to '1' for the CRC calculation.
        //
        ui8TempData = psSMBus->ui8TargetSlaveAddress << 1;

        //
        // Start off by calculating the CRC of the target slave address with
        // an initial value of 0.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);

        //
        // Add the command to the running CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &psSMBus->ui8CurrentCommand,
                                                  1);

        //
        // Update the state machine.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
    }
    else
    {
        //
        // Update the state machine.
        //
        if(psSMBus->ui8RxSize == 2)
        {
            psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
        }
        else
        {
            psSMBus->ui8MasterState = SMBUS_STATE_READ_ONE;
        }
    }

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Initiate the write operation.
    //
    MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                         I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a master Block Write transfer to an SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param ui8Command is the command byte sent before the data is requested.
//! \param pui8Data is a pointer to the transmit data buffer.
//! \param ui8Size is the number of bytes to send to the slave.
//!
//! This function supports the Block Write protocol.  The amount of data sent
//! to the slave is user defined, but limited to 32 bytes per the SMBus spec.
//!
//! This protocol supports the optional PEC byte for error checking.  To use
//! PEC, SMBusPECEnable() must be called before this function.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 32, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterBlockWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                      uint8_t ui8Command, uint8_t *pui8Data,
                      uint8_t ui8Size)
{
    uint8_t ui8TempData;

    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // If more than 32 bytes are requested, indicate error.
    //
    if(ui8Size > 32)
    {
        return(SMBUS_DATA_SIZE_ERROR);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->ui8CurrentCommand = ui8Command;
    psSMBus->pui8TxBuffer = pui8Data;
    psSMBus->ui8TxSize = ui8Size;
    psSMBus->ui8RxSize = 0;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Set the block transfer flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;

    //
    // Clear the process call and raw I2C flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // Initialize the buffer index to 0 and the interrupt state machine to
    // the appropriate state so that there is a known starting point
    // for each transaction.
    //
    psSMBus->ui8TxIndex = 0;

    //
    // Calculate the CRC for PEC (if used).
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
    {
        //
        // Place the target slave address into a temporary data variable and
        // make sure the R/S bit is set to '0' for the CRC calculation.
        //
        ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;

        //
        // Start off by calculating the CRC of the target slave address with
        // an initial value of 0.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);

        //
        // Add the command to the running CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &psSMBus->ui8CurrentCommand,
                                                  1);

        //
        // Add the size to the running CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &psSMBus->ui8TxSize, 1);

        //
        // Add the data array to the calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  psSMBus->pui8TxBuffer,
                                                  psSMBus->ui8TxSize);
    }

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Write the first byte of the data.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);

    //
    // Update the state machine.
    //
    psSMBus->ui8MasterState = SMBUS_STATE_WRITE_BLOCK_SIZE;

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Initiate the write operation.
    //
    MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                         I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a master Block Read transfer to an SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param ui8Command is the command byte sent before the data is requested.
//! \param pui8Data is a pointer to the receive data buffer.
//!
//! This function supports the Block Read protocol.  The amount of data read
//! is defined by the slave device, but should never exceed 32 bytes per the
//! SMBus spec.  The receive size is the first data byte returned by the slave,
//! so this function assumes a size of 3 until the actual number is sent by
//! the slave.  In the application interrupt handler, SMBusRxPacketSizeGet()
//! can be used to obtain the amount of data sent by the slave.
//!
//! This protocol supports the optional PEC byte for error checking.  To use
//! PEC, SMBusPECEnable() must be called before this function.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterBlockRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                     uint8_t ui8Command, uint8_t *pui8Data)
{
    uint8_t ui8TempData;

    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->ui8CurrentCommand = ui8Command;
    psSMBus->pui8RxBuffer = pui8Data;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8TxSize = 0;
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Set the block transfer flag..
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;

    //
    // Clear the process call and raw I2C flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Put the SMBus command code on the bus.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);

    //
    // Initially set the RX size to 3 to make the state machine work.
    // The slave will respond with the actual size of the transfer in the
    // first byte and that data will replace this initial value.
    //
    psSMBus->ui8RxSize = 3;

    //
    // Calculate the CRC for PEC (if used).
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
    {
        //
        // Place the target slave address into a temporary data variable and
        // set the R/S bit to '1' for the CRC calculation.
        //
        ui8TempData = psSMBus->ui8TargetSlaveAddress << 1;

        //
        // Start off by calculating the CRC of the target slave address with
        // an initial value of 0.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);

        //
        // Add the command to the running CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &psSMBus->ui8CurrentCommand,
                                                  1);
    }

    //
    // Update the state machine.
    //
    psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Initiate the write operation.
    //
    MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                         I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a master Process Call transfer to an SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param ui8Command is the command byte sent before the data is requested.
//! \param pui8TxData is a pointer to the transmit data buffer.
//! \param pui8RxData is a pointer to the receive data buffer.
//!
//! This function supports the Process Call protocol.  The amount of data sent
//! to and received from the slave is fixed to 2 bytes per direction (2 sent,
//! 2 received).
//!
//! This protocol supports the optional PEC byte for error checking.  To use
//! PEC, SMBusPECEnable() must be called before this function.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterProcessCall(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                       uint8_t ui8Command, uint8_t *pui8TxData,
                       uint8_t *pui8RxData)
{
    uint8_t ui8TempData;

    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->ui8CurrentCommand = ui8Command;
    psSMBus->pui8TxBuffer = pui8TxData;
    psSMBus->pui8RxBuffer = pui8RxData;
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8TxSize = 2;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8RxSize = 2;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Set the process call flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;

    //
    // Clear the block transfer and raw I2C flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Calculate the CRC for PEC (if used).
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
    {
        //
        // Place the target slave address into a temporary data variable and
        // make sure the R/S bit is set to '0' for the CRC calculation.
        //
        ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;

        //
        // Start off by calculating the CRC of the target slave address with
        // an initial value of 0.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);

        //
        // Add the command to the running CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &psSMBus->ui8CurrentCommand,
                                                  1);

        //
        // Add the data array to the calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  psSMBus->pui8TxBuffer,
                                                  psSMBus->ui8TxSize);
    }

    //
    // Put the SMBus command code on the bus.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);

    //
    // Update the state machine.
    //
    psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Initiate the write operation.
    //
    MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                         I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a master Block Process Call transfer to an SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param ui8Command is the command byte sent before the data is requested.
//! \param pui8TxData is a pointer to the transmit data buffer.
//! \param ui8TxSize is the number of bytes to send to the slave.
//! \param pui8RxData is a pointer to the receive data buffer.
//!
//! This function supports the Block Write/Block Read Process Call protocol.
//! The amount of data sent to the slave is user defined but limited to 32 data
//! bytes.  The amount of data read is defined by the slave device, but should
//! never exceed 32 bytes per the SMBus spec.  The receive size is the first
//! data byte returned by the slave, so the actual size is populated in
//! SMBusMasterISRProcess().  In the application interrupt handler,
//! SMBusRxPacketSizeGet() can be used to obtain the amount of data sent by
//! the slave.
//!
//! This protocol supports the optional PEC byte for error checking.  To use
//! PEC, SMBusPECEnable() must be called before this function.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
//! \b SMBUS_DATA_SIZE_ERROR if ui8TxSize is greater than 32, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterBlockProcessCall(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                            uint8_t ui8Command, uint8_t *pui8TxData,
                            uint8_t ui8TxSize, uint8_t *pui8RxData)
{
    uint8_t ui8TempData;

    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // If more than 32 bytes are requested, indicate error.
    //
    if(ui8TxSize > 32)
    {
        return(SMBUS_DATA_SIZE_ERROR);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->ui8CurrentCommand = ui8Command;
    psSMBus->pui8TxBuffer = pui8TxData;
    psSMBus->pui8RxBuffer = pui8RxData;
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8TxSize = ui8TxSize;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8RxSize = 3;
    psSMBus->ui8CalculatedCRC = 0;

    //
    // Set the process call and block transfer flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;

    //
    // Clear the raw I2C flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;

    //
    // Calculate the CRC for PEC (if used).
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
    {
        //
        // Place the target slave address into a temporary data variable and
        // make sure the R/S bit is set to '0' for the CRC calculation.
        //
        ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;

        //
        // Start off by calculating the CRC of the target slave address with
        // an initial value of 0.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);

        //
        // Add the command to the running CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &psSMBus->ui8CurrentCommand,
                                                  1);

        //
        // Add the size to the running CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &psSMBus->ui8TxSize, 1);

        //
        // Add the data array to the calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  psSMBus->pui8TxBuffer,
                                                  psSMBus->ui8TxSize);
    }

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Put the SMBus command code on the bus.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);

    //
    // Update the state machine.
    //
    psSMBus->ui8MasterState = SMBUS_STATE_WRITE_BLOCK_SIZE;

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Initiate the write operation.
    //
    MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                         I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a ``raw'' I2C write transfer to a slave device.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param pui8Data is a pointer to the transmit data buffer.
//! \param ui8Size is the number of bytes to send to the slave.
//!
//! This function sends a user-defined number of bytes to an I2C slave without
//! using an SMBus protocol.  The data size is only limited to the size of the
//! ui8Size variable, which is an unsigned character (8 bits, value of 255).
//!
//! Because this function uses ``raw'' I2C, PEC is not supported.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterI2CWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                    uint8_t *pui8Data, uint8_t ui8Size)
{
    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->pui8TxBuffer = pui8Data;
    psSMBus->ui8TxSize = ui8Size;
    psSMBus->ui8TxIndex = 1;
    psSMBus->ui8RxSize = 0;
    psSMBus->ui8RxIndex = 0;

    //
    // PEC is not supported by raw I2C transfers, so force it to be disabled.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;

    //
    // Clear the block transfer and process call flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;

    //
    // Set the raw I2C flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Put the first byte on the bus.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->pui8TxBuffer[0]);

    //
    // Choose what to do based on the transmit size.
    //
    if(ui8Size == 1)
    {
        //
        // Update the state machine.  Since it's the only byte being sent,
        // the state machine's next state is idle.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_IDLE;

        //
        // Make sure that the bus is idle.
        //
        if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
        {
            return(SMBUS_BUS_BUSY);
        }

        //
        // Initiate the write operation.
        //
        MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_SINGLE_SEND);
    }
    else if(ui8Size == 2)
    {
        //
        // If there are only 2 bytes to send just jump to the final write
        // state.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;

        //
        // Make sure that the bus is idle.
        //
        if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
        {
            return(SMBUS_BUS_BUSY);
        }

        //
        // Initiate the write operation.
        //
        MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                             I2C_MASTER_CMD_BURST_SEND_START);
    }
    else
    {
        //
        // Set the next state.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;

        //
        // Make sure that the bus is idle.
        //
        if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
        {
            return(SMBUS_BUS_BUSY);
        }

        //
        // Initiate the write operation.
        //
        MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                             I2C_MASTER_CMD_BURST_SEND_START);
    }

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a ``raw'' I2C read transfer to a slave device.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param pui8Data is a pointer to the receive data buffer.
//! \param ui8Size is the number of bytes to send to the slave.
//!
//! This function receives a user-defined number of bytes from an I2C slave
//! without using an SMBus protocol.  The data size is only limited to the size
//! of the ui8Size variable, which is an unsigned character (8 bits, value of
//! 255).
//!
//! Because this function uses ``raw'' I2C, PEC is not supported.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterI2CRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                   uint8_t *pui8Data, uint8_t ui8Size)
{
    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->pui8RxBuffer = pui8Data;
    psSMBus->ui8TxSize = 0;
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8RxSize = ui8Size;

    //
    // PEC is not supported by raw I2C transfers, so force it to be disabled.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;

    //
    // Clear the block transfer and process call flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;

    //
    // Set the raw I2C flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, true);

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Choose what to do based on the receive size.
    //
    if(ui8Size == 1)
    {
        //
        // Update the state machine.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
    }
    else if(ui8Size == 2)
    {
        psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
    }
    else
    {
        //
        // Set the next state.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
    }

    if(ui8Size == 1)
    {
        //
        // Start the single receive.
        //
        MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                             I2C_MASTER_CMD_SINGLE_RECEIVE);
    }
    else
    {
        //
        // Start the burst receive.
        //
        MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                             I2C_MASTER_CMD_BURST_RECEIVE_START);
    }

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Initiates a ``raw'' I2C write-read transfer to a slave device.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param pui8TxData is a pointer to the transmit data buffer.
//! \param ui8TxSize is the number of bytes to send to the slave.
//! \param pui8RxData is a pointer to the receive data buffer.
//! \param ui8RxSize is the number of bytes to receive from the slave.
//!
//! This function initiates a write-read transfer to an I2C slave without using
//! an SMBus protocol.  The user-defined number of bytes is written to the
//! slave first, followed by the reception of the user-defined number of bytes.
//! The transmit and receive data sizes are only limited to the size of the
//! ui8TxSize and ui8RxSize variables, which are unsigned characters (8 bits,
//! value of 255).
//!
//! Because this function uses ``raw'' I2C, PEC is not supported.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterI2CWriteRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                        uint8_t *pui8TxData, uint8_t ui8TxSize,
                        uint8_t *pui8RxData, uint8_t ui8RxSize)
{
    //
    // Make sure that the peripheral is not currently active.
    //
    if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_PERIPHERAL_BUSY);
    }

    //
    // Update the configuration structure with the data for this transfer.
    //
    psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
    psSMBus->pui8TxBuffer = pui8TxData;
    psSMBus->pui8RxBuffer = pui8RxData;
    psSMBus->ui8TxIndex = 1;
    psSMBus->ui8TxSize = ui8TxSize;
    psSMBus->ui8RxIndex = 0;
    psSMBus->ui8RxSize = ui8RxSize;

    //
    // PEC is not supported by raw I2C transfers, so force it to be disabled.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;

    //
    // Set the process call flag.  Even though this is technically not an SMBus
    // process call, this flag is used in the interrupt state machine for
    // the bus turn around.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;

    //
    // Clear the block transfer flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;

    //
    // Set the raw I2C flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;

    //
    // Set the slave address and R/S bit.
    //
    MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                              psSMBus->ui8TargetSlaveAddress, false);

    //
    // Write the first byte of the data.
    //
    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->pui8TxBuffer[0]);

    //
    // Choose what to do based on the transmit size.
    //
    if(ui8TxSize == 1)
    {
        //
        // Move to appropriate read state for the turn around based on
        // receive size.
        //
        if(ui8RxSize == 1)
        {
           psSMBus->ui8MasterState = SMBUS_STATE_READ_ONE;
        }
        else
        {
           psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
        }
    }
    else if(ui8TxSize == 2)
    {
        psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
    }
    else
    {
        //
        // Set the next state.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
    }

    //
    // Make sure that the bus is idle.
    //
    if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
    {
        return(SMBUS_BUS_BUSY);
    }

    //
    // Initiate the write operation.
    //
    MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                         I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Set the transfer in progress flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

    //
    // Return to the caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! \internal
//! Sends a ``general'' Get UDID packet.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param pui8Data is a pointer to the receive data buffer.
//!
//! This function sends a ``general'' Get UDID packet, used during Address
//! Resolution Protocol (ARP).  Since SMBus requires that data bytes be
//! transmitted in a certain order, the raw data in the pui8Data needs to be
//! treated as such.  To put the data in a known order, use
//! SMBusARPUDIDPacketDecode().
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterARPGetUDIDGen(tSMBus *psSMBus, uint8_t *pui8Data)
{
    //
    // Use the block read protocol to receive the UDID.
    //
    return(SMBusMasterBlockRead(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
                                SMBUS_CMD_ARP_GET_UDID, pui8Data));
}

//*****************************************************************************
//
//! \internal
//! Sends a ``directed'' Get UDID packet.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8TargetAddress specifies the slave address of the target device.
//! \param pui8Data is a pointer to the receive data buffer.
//!
//! This function sends a ``directed'' Get UDID packet, used during Address
//! Resolution Protocol (ARP).  A directed packet differs from a general packet
//! in that it targets a specific slave device.  Since SMBus requires that data
//! bytes be transmitted in a certain order, the raw data in the pui8Data needs
//! to be treated as such.  To put the data in a known order, use
//! SMBusARPUDIDPacketDecode().
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterARPGetUDIDDir(tSMBus *psSMBus, uint8_t ui8TargetAddress,
                         uint8_t *pui8Data)
{
    //
    // Use the block read protocol to receive the UDID.
    //
    return(SMBusMasterBlockRead(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
                                (ui8TargetAddress << 1 | 1), pui8Data));
}

//*****************************************************************************
//
//! \internal
//! Sends a ``general'' Reset Device packet.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function sends a ``general'' Reset Device packet, used during Address
//! Resolution Protocol (ARP).  This packet is used by an ARP Master to force
//! all non-PSA (Persistent Slave Address), ARP-capable devices to return to
//! their initial state.  This packet also tells the devices to clear their
//! Address Resolved (AR) and Address Valid (AV) flags.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterARPResetDeviceGen(tSMBus *psSMBus)
{
    //
    // Use the Send Byte protocol to send the packet.
    //
    return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
                               SMBUS_CMD_ARP_RESET_DEVICE));
}

//*****************************************************************************
//
//! \internal
//! Sends a ``directed'' Reset Device packet.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function sends a ``directed'' Reset Device packet, used during Address
//! Resolution Protocol (ARP).  This packet is used by an ARP Master to force
//! a specific non-PSA (Persistent Slave Address), ARP-capable device to return
//! to its initial state.  This packet also tells the device to clear its
//! Address Resolved (AR) and Address Valid (AV) flags.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterARPResetDeviceDir(tSMBus *psSMBus, uint8_t ui8TargetAddress)
{
    //
    // Use the Send Byte protocol to send the packet.
    //
    return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
                               (ui8TargetAddress << 1)));
}

//*****************************************************************************
//
//! Sends an ARP Assign Address packet.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param pui8Data is a pointer to the transmit data buffer.  This buffer
//!        should be correctly formatted using SMBusARPUDIDPacketEncode() and
//!        should contain the UDID data and the address for the slave.
//!
//! This function sends an Assign Address packet, used during Address
//! Resolution Protocol (ARP).  Because SMBus requires data bytes be sent out
//! MSB first, the UDID and target address should be formatted correctly by the
//! application or using SMBusARPUDIDPacketEncode() and placed into a data
//! buffer pointed to by pui8Data.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterARPAssignAddress(tSMBus *psSMBus, uint8_t *pui8Data)
{
    //
    // Use the Block Write protocol to send the packet.
    //
    return(SMBusMasterBlockWrite(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
                                 SMBUS_CMD_ARP_ASSIGN_ADDRESS, pui8Data, 17));
}

//*****************************************************************************
//
//! Sends a Notify ARP Master packet.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param pui8Data is a pointer to the transmit data buffer.  The data payload
//!        should be 0x0000 for this packet.
//!
//! This function sends a Notify ARP Master packet, used during Address
//! Resolution Protocol (ARP).  This packet is used by a slave to indicate
//! to the ARP Master that it needs attention.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterARPNotifyMaster(tSMBus *psSMBus, uint8_t *pui8Data)
{
    //
    // Use the Host Notify protocol to send the packet.
    //
    return(SMBusMasterHostNotify(psSMBus, (SMBUS_ADR_DEFAULT_DEVICE << 1),
                                 pui8Data));
}

//*****************************************************************************
//
//! Sends a Prepare to ARP packet.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function sends a Prepare to ARP packet, used during Address Resolution
//! Protocol (ARP).  This packet is used by an ARP Master to alert devices on
//! the bus that ARP is about to begin.    All ARP-capable devices must
//! acknowledge all bytes in this packet and clear their Address Resolved (AR)
//! flag.
//!
//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
//! the transfer has successfully been initiated.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterARPPrepareToARP(tSMBus *psSMBus)
{
    //
    // Use the Send Byte protocol to send the packet.
    //
    return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
                               SMBUS_CMD_PREPARE_TO_ARP));
}

//*****************************************************************************
//
//! Master ISR processing function for the SMBus application.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function must be called in the application interrupt service routine
//! (ISR) to process SMBus master interrupts.
//!
//! \return Returns \b SMBUS_TIMEOUT if a bus timeout is detected,
//! \b SMBUS_ARB_LOST if I2C bus arbitration lost is detected,
//! \b SMBUS_ADDR_ACK_ERROR if the address phase of a transfer results in a
//! NACK, \b SMBUS_DATA_ACK_ERROR if the data phase of a transfer results in a
//! NACK, \b SMBUS_DATA_SIZE_ERROR if a receive buffer overrun is detected or
//! if a transmit operation tries to write more data than is allowed,
//! \b SMBUS_MASTER_ERROR if an unknown error occurs, \b SMBUS_PEC_ERROR if the
//! received PEC byte does not match the locally calculated value, or
//! \b SMBUS_OK if processing finished successfully.
//
//*****************************************************************************
tSMBusStatus
SMBusMasterIntProcess(tSMBus *psSMBus)
{
    uint32_t ui32IntStatus;
    uint32_t ui32ErrorStatus;
    uint8_t ui8TempData;

    //
    // Determine which interrupt made us get here.
    //
    ui32IntStatus = MAP_I2CMasterIntStatusEx(psSMBus->ui32I2CBase, true);

    //
    // Check for the timeout interrupt.  Since the peripheral will
    // automatically issue a stop, just clear the interrupt and return.
    //
    if(ui32IntStatus & I2C_MASTER_INT_TIMEOUT)
    {
        //
        // Clear all pending interrupts and wait for the bus to become
        // free so we can issue a STOP.
        //
        MAP_I2CMasterIntClearEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_TIMEOUT |
                                I2C_MASTER_INT_DATA);

        //
        // Clear the transfer in progress flag.  New transactions will
        // be aborted until the bus is free.
        //
        HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;

        //
        // Return to caller.
        //
        return(SMBUS_TIMEOUT);
    }
    else
    {
        //
        // Clear the data interrupt.
        //
        MAP_I2CMasterIntClearEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_DATA);
    }

    //
    // Read the master interrupt status bits.
    //
    ui32ErrorStatus = HWREG(psSMBus->ui32I2CBase + I2C_O_MCS);

    //
    // Check for arbitration lost.
    //
    if(ui32ErrorStatus & I2C_MCS_ARBLST)
    {
        //
        // Put the state machine back in the idle state.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_IDLE;

        //
        // Clear the transfer in progress flag.
        //
        HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;

        //
        // Return to caller.
        //
        return(SMBUS_ARB_LOST);
    }

    //
    // Check for an error.
    //
    if(ui32ErrorStatus & I2C_MCS_ERROR)
    {
        //
        // Put the state machine back in the idle state.
        //
        psSMBus->ui8MasterState = SMBUS_STATE_IDLE;

        //
        // Check to see if the bus is free.  There are two interrupts when a
        // NACK happens, and the bus should only be free during the second
        // interrupt.  During the first interrupt (when the bus is busy),
        // generate the necessary STOP condition.
        //
        if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
        {
            //
            // Issue a STOP.
            //
            MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                 I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
        }
        else
        {
            //
            // Clear the transfer in progress flag.
            //
            HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
        }

        //
        // Check for ACK errors.
        //
        if(ui32ErrorStatus & I2C_MCS_ADRACK)
        {
            //
            // Return to caller.
            //
            return(SMBUS_ADDR_ACK_ERROR);
        }
        else if(ui32ErrorStatus & I2C_MCS_DATACK)
        {
            //
            // Return to caller.
            //
            return(SMBUS_DATA_ACK_ERROR);
        }
        else
        {
            //
            // Return to caller.  Should never get here.
            //
            return(SMBUS_MASTER_ERROR);
        }
    }

    //
    // If no error conditions, determine what to do based on the state.
    //
    switch(psSMBus->ui8MasterState)
    {
        //
        // The idle state.  This state should only be reached after the last
        // byte of a master transmit.
        //
        case SMBUS_STATE_IDLE:
        {
            //
            // If the peripheral is not busy clear the transfer in progress
            // flag.  This means that the peripheral has given up the bus,
            // most likely due to the end of a transmit operation.
            //
            if(!MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
            {
                //
                // Clear the transfer in progress flag.
                //
                HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
            }

            //
            // This state is done.
            //
            break;
        }

        //
        // When using a block write, the transfer size must be sent before the
        // data payload.
        //
        case SMBUS_STATE_WRITE_BLOCK_SIZE:
        {
            //
            // Write the block write size to the data register.
            //
            MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8TxSize);

            //
            // Continue the burst write.
            //
            MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                 I2C_MASTER_CMD_BURST_SEND_CONT);

            //
            // The next data byte is from the data payload.
            //
            if((psSMBus->ui8TxSize == 1) &&
               !(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC)))
            {
                psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
            }
            else
            {
                psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
            }

            //
            // This state is done.
            //
            break;
        }
        //
        // The state for the middle of a burst write.
        //
        case SMBUS_STATE_WRITE_NEXT:
        {
            //
            // Write the next byte to the data register.
            //
            MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
                                 psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++]);

            //
            // Continue the burst write.
            //
            MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                 I2C_MASTER_CMD_BURST_SEND_CONT);

            //
            // Determine the next state based on the values of the PEC and
            // process call flags.
            //

            //
            // If PEC is active and process call is not active.
            //
            if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
            {
                //
                // If a process call, there is no PEC byte on the transmit.
                //
                if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
                {
                    //
                    // Check to see if the TX index is equal to size minus 1.
                    //
                    if(psSMBus->ui8TxIndex == (psSMBus->ui8TxSize - 1))
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
                    }
                }
                else
                {
                    //
                    // If the TX index is the same as the size, we're done.
                    //
                    if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
                    }
                }
            }

            //
            // If PEC is not used, regardless of whether this is a process
            // call.
            //
            else
            {
                //
                // Check to see if the TX index is equal to the size minus 1.
                //
                if(psSMBus->ui8TxIndex == (psSMBus->ui8TxSize - 1))
                {
                    psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
                }
            }

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for the final write of a burst sequence.
        //
        case SMBUS_STATE_WRITE_FINAL:
        {
            //
            // Determine what data to write to the data register based
            // on the values of the PEC and process call flags.
            //
            //
            // If PEC is active, write the PEC byte to the data register.
            //
            if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
            {
                //
                // If a process call is active, send data, not CRC.
                //
                if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
                {
                    //
                    // Write the final byte from TX buffer to the data
                    // register.
                    //
                    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
                                         psSMBus->pui8TxBuffer[psSMBus->
                                                               ui8TxIndex++]);
                }
                else
                {
                    //
                    // Write the calculated CRC (PEC) byte to the data
                    // register.
                    //
                    MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
                                         psSMBus->ui8CalculatedCRC);
                }
            }
            else
            {
                //
                // Write the final byte from TX buffer to the data register.
                //
                MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
                                     psSMBus->pui8TxBuffer[psSMBus->
                                                           ui8TxIndex++]);
            }

            //
            // If a process call is active, send out the repeated start to
            // begin the RX portion.
            //
            if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
            {
                //
                // Move to the read first "turnaround" state.
                //
                psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;

                //
                // Continue the burst write.
                //
                MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                     I2C_MASTER_CMD_BURST_SEND_CONT);
            }
            else
            {
                //
                // Finish the burst write.
                //
                MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                     I2C_MASTER_CMD_BURST_SEND_FINISH);

                //
                // Since we end the transaction after the last byte is sent,
                // the next state is idle.
                //
                psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
            }

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for a single byte read.
        //
        case SMBUS_STATE_READ_ONE:
        {
            //
            // Put the I2C master into receive mode.
            //
            MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                                      psSMBus->ui8TargetSlaveAddress, true);

            //
            // Perform a single byte read.
            //
            MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                 I2C_MASTER_CMD_SINGLE_RECEIVE);

            //
            // The next state is the wait for final read state.
            //
            psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for the start of a burst read.
        //
        case SMBUS_STATE_READ_FIRST:
        {
            //
            // Put the I2C master into receive mode.
            //
            MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
                                      psSMBus->ui8TargetSlaveAddress, true);

            //
            // Handle the case where PEC is used.
            //
            if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
            {
                //
                // Add the target address and R/S bit to the running CRC
                // calculation.
                //
                ui8TempData =
                    ((psSMBus->ui8TargetSlaveAddress << 1) & 0xfe) | 1;

                //
                // Update the calculated CRC value in the configuration
                // structure.
                //
                psSMBus->ui8CalculatedCRC =
                    MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC, &ui8TempData, 1);

                //
                // Set the next state in the state machine.
                //
                if(psSMBus->ui8RxSize > 1)
                {
                    //
                    // If this is a block transfer, the next state is to read
                    // back the number of bytes that the slave will be sending.
                    //
                    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_READ_BLOCK_SIZE;
                    }

                    //
                    // For every other case...
                    //
                    else
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
                    }
                }

                //
                // If 1 byte remains, move to the final read state.
                //
                else
                {
                    psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
                }
            }
            else
            {
                //
                // Set the next state in the state machine.
                //
                if(psSMBus->ui8RxSize > 2)
                {
                    //
                    // If this is a block transfer, the next state is to read
                    // back the number of bytes that the slave will be sending.
                    //
                    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_READ_BLOCK_SIZE;
                    }

                    //
                    // For every other case...
                    //
                    else
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
                    }
                }

                //
                // If 2 bytes remain, move to the final read state.
                //
                else
                {
                    psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
                }
            }

            //
            // Start the burst receive.
            //
            MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                 I2C_MASTER_CMD_BURST_RECEIVE_START);

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for the size of a block read.
        //
        case SMBUS_STATE_READ_BLOCK_SIZE:
        {
            //
            // Update the RX size with the data byte.
            //
            psSMBus->ui8RxSize = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);

            //
            // If more than 32 bytes are going to be sent, error.
            //
            if((psSMBus->ui8RxSize > 32) || (psSMBus->ui8RxSize == 0))
            {
                //
                // Set the next state.
                //
                psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;

                //
                // If too many or too few bytes, error.
                //
                MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                     I2C_MASTER_CMD_SINGLE_RECEIVE);

                //
                // Break from this case.
                //
                break;
            }

            //
            // If PEC is enabled, add the size byte to the calculation and
            // add one to the size variable to account for the extra PEC byte.
            //
            if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
            {
                //
                // Calculate the new CRC and update configuration structure.
                //
                psSMBus->ui8CalculatedCRC =
                    MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                  &psSMBus->ui8RxSize, 1);
            }

            //
            // Update the state machine.
            //
            switch(psSMBus->ui8RxSize)
            {
                //
                // 1 byte remaining.
                //
                case 1:
                {
                    //
                    // If only one byte remains and PEC, go to the second
                    // to last byte state.
                    //
                    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
                    }

                    //
                    // If only one byte remains and no PEC, end the burst
                    // transfer.
                    //
                    else
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
                    }

                    //
                    // This switch is done.
                    //
                    break;
                }

                //
                // 2 bytes remaining.
                //
                case 2:
                {
                    //
                    // If two bytes and PEC remain, move to read next
                    // state.
                    //
                    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
                    }

                    //
                    // If two bytes remain, move to the final read state.
                    //
                    else
                    {
                        psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
                    }

                    //
                    // This switch is done.
                    //
                    break;
                }

                //
                // For every other situation (in other words, remaining bytes
                // is greater than 2).
                //
                default:
                {
                    //
                    // If more than 2 bytes to read, move to the next byte
                    // state.
                    //
                    psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;

                    //
                    // This switch is done.
                    //
                    break;
                }
            }

            //
            // Determine how to step the I2C state machine.
            //
            if((psSMBus->ui8RxSize == 1) &&
               !HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
            {
                //
                // If exactly 1 byte remains, read the byte and send a STOP.
                //
                MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                     I2C_MASTER_CMD_BURST_SEND_FINISH);
            }
            else
            {
                //
                // Otherwise, continue the burst read.
                //
                MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                     I2C_MASTER_CMD_BURST_RECEIVE_CONT);
            }

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for the middle of a burst read.
        //
        case SMBUS_STATE_READ_NEXT:
        {
            //
            // Check for a buffer overrun.
            //
            if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
            {
                //
                // Dummy read of data register.
                //
                ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);

                //
                // If too many or too few bytes, error.
                //
                MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                     I2C_MASTER_CMD_BURST_RECEIVE_FINISH);

                //
                // Set the next state.
                //
                psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;

                //
                // Break from this case.
                //
                break;
            }

            //
            // Read the received character.
            //
            psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] =
                MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);

            //
            // Continue the burst read.
            //
            MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                 I2C_MASTER_CMD_BURST_RECEIVE_CONT);

            //
            // If PEC is enabled, add the received byte to the calculation.
            //
            if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
            {
                //
                // Calculate the new CRC and update configuration structure.
                //
                psSMBus->ui8CalculatedCRC =
                    MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                  &psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex],
                                  1);

                //
                // Increment the receive buffer index.
                //
                psSMBus->ui8RxIndex++;

                //
                // If there is 1 byte remaining, make next state be the
                // end of burst read state.
                //
                if((psSMBus->ui8RxSize - psSMBus->ui8RxIndex) == 1)
                {
                    psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
                }
            }
            else
            {
                //
                // Increment the receive buffer index.
                //
                psSMBus->ui8RxIndex++;

                //
                // If there are two bytes remaining, make next state be the
                // end of burst read state.
                //
                if((psSMBus->ui8RxSize - psSMBus->ui8RxIndex) == 2)
                {
                    psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
                }
            }

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for the end of a burst read.
        //
        case SMBUS_STATE_READ_FINAL:
        {
            //
            // Check for a buffer overrun.
            //
            if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
            {
                //
                // Dummy read of data register.
                //
                ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);

                //
                // If too many or too few bytes, error.
                //
                MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                     I2C_MASTER_CMD_BURST_RECEIVE_FINISH);

                //
                // Set the next state.
                //
                psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;

                //
                // Break from this case.
                //
                break;
            }

            //
            // Read the received character.
            //
            psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] =
                MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);

            //
            // The next state is the wait for final read state.
            //
            psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;

            //
            // Finish the burst read.
            //
            MAP_I2CMasterControl(psSMBus->ui32I2CBase,
                                 I2C_MASTER_CMD_BURST_RECEIVE_FINISH);

            //
            // If PEC is enabled, add the received byte to the calculation.
            //
            if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
            {
                //
                // Calculate the new CRC and update configuration structure.
                //
                psSMBus->ui8CalculatedCRC =
                    MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                  &psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex],
                                  1);
            }

            //
            // Increment the receive buffer index.
            //
            psSMBus->ui8RxIndex++;

            //
            // This state is done.
            //
            break;
        }

        //
        // This state is for the final read of a single or burst read.
        //
        case SMBUS_STATE_READ_WAIT:
        {
            //
            // Read the received byte.
            //
            ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);

            //
            // If PEC is enabled, check the value that just came in to see
            // if it matches.
            //
            if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
            {
                //
                // Check for a buffer overrun.
                //
                if(psSMBus->ui8RxIndex > psSMBus->ui8RxSize)
                {
                    //
                    // Clear the transfer in progress flag.
                    //
                    HWREGBITB(&psSMBus->ui16Flags,
                              FLAG_TRANSFER_IN_PROGRESS) = 0;

                    //
                    // Return the error condition.
                    //
                    return(SMBUS_DATA_SIZE_ERROR);
                }

                //
                // Store the received CRC byte.
                //
                psSMBus->ui8ReceivedCRC = ui8TempData;

                //
                // If the CRC doesn't match, send a NACK and indicate the
                // failure to the application.
                //
                if(psSMBus->ui8ReceivedCRC != psSMBus->ui8CalculatedCRC)
                {
                    //
                    // Clear the transfer in progress flag.
                    //
                    HWREGBITB(&psSMBus->ui16Flags,
                              FLAG_TRANSFER_IN_PROGRESS) = 0;

                    //
                    // Return the error condition.
                    //
                    return(SMBUS_PEC_ERROR);
                }
            }
            else
            {
                //
                // Check for a buffer overrun.
                //
                if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
                {
                    //
                    // Clear the transfer in progress flag.
                    //
                    HWREGBITB(&psSMBus->ui16Flags,
                              FLAG_TRANSFER_IN_PROGRESS) = 0;

                    //
                    // Return the error condition.
                    //
                    return(SMBUS_DATA_SIZE_ERROR);
                }

                //
                // Read the received byte.
                //
                psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] = ui8TempData;

                //
                // Increment the receive buffer index.
                //
                psSMBus->ui8RxIndex++;
            }

            //
            // The state machine is now idle.
            //
            psSMBus->ui8MasterState = SMBUS_STATE_IDLE;

            //
            // Clear the transfer in progress flag.
            //
            HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;

            //
            // This state is done.
            //
            break;
        }

        //
        // This state is for a transaction that needed to end due to a
        // size error.
        //
        case SMBUS_STATE_READ_ERROR_STOP:
        {
            //
            // Dummy read the received byte.
            //
            ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);

            //
            // The state machine is now idle.
            //
            psSMBus->ui8MasterState = SMBUS_STATE_IDLE;

            //
            // Clear the transfer in progress flag.
            //
            HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;

            //
            // Return the error condition.
            //
            return(SMBUS_DATA_SIZE_ERROR);
        }
    }

    //
    // Return to caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Enables the appropriate master interrupts for stack processing.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function enables the I2C interrupts used by the SMBus master.  Both
//! the peripheral-level and NVIC-level interrupts are enabled.
//! SMBusMasterInit() must be called before this function because this function
//! relies on the I2C base address being defined.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusMasterIntEnable(tSMBus *psSMBus)
{
    //
    // Enable the master interrupts.
    //
    MAP_I2CMasterIntEnableEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_DATA |
                             I2C_MASTER_INT_TIMEOUT);

    //
    // Enable the interrupt in the NVIC.
    //
    switch(psSMBus->ui32I2CBase)
    {
        case I2C0_BASE:
        {
            MAP_IntEnable(INT_I2C0);
            break;
        }

        case I2C1_BASE:
        {
            MAP_IntEnable(INT_I2C1);
            break;
        }

        case I2C2_BASE:
        {
            if(CLASS_IS_TM4C123)
            {
                MAP_IntEnable(INT_I2C2_TM4C123);
            }
            else if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C2_TM4C129);
            }
            break;
        }

        case I2C3_BASE:
        {
            if(CLASS_IS_TM4C123)
            {
                MAP_IntEnable(INT_I2C3_TM4C123);
            }
            else if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C3_TM4C129);
            }
            break;
        }

        case I2C4_BASE:
        {
            if(CLASS_IS_TM4C123)
            {
                MAP_IntEnable(INT_I2C4_TM4C123);
            }
            else if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C4_TM4C129);
            }
            break;
        }

        case I2C5_BASE:
        {
            if(CLASS_IS_TM4C123)
            {
                MAP_IntEnable(INT_I2C5_TM4C123);
            }
            else if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C5_TM4C129);
            }
            break;
        }

        case I2C6_BASE:
        {
            if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C6_TM4C129);
            }
            break;
        }

        case I2C7_BASE:
        {
            if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C7_TM4C129);
            }
            break;
        }

        case I2C8_BASE:
        {
            if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C8_TM4C129);
            }
            break;
        }

        case I2C9_BASE:
        {
            if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C9_TM4C129);
            }
            break;
        }
    }
}

//*****************************************************************************
//
//! Initializes an I2C master peripheral for SMBus functionality.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui32I2CBase specifies the base address of the I2C master peripheral.
//! \param ui32SMBusClock specifies the system clock speed of the MCU.
//!
//! This function initializes an I2C peripheral for SMBus master use.  The
//! instance-specific configuration structure is initialized to a set of known
//! values and the I2C peripheral is configured for 100kHz use, which is
//! required by the SMBus specification.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusMasterInit(tSMBus *psSMBus, uint32_t ui32I2CBase,
                uint32_t ui32SMBusClock)
{
    //
    // Initialize the configuration structure.
    //
    psSMBus->pUDID = 0;
    psSMBus->ui32I2CBase = ui32I2CBase;
    psSMBus->ui16Flags = 0;
    psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
    psSMBus->ui8OwnSlaveAddress = 0;
    psSMBus->ui8TargetSlaveAddress = 0;
    psSMBus->ui8CurrentCommand = 0;
    psSMBus->ui8CalculatedCRC = 0;
    psSMBus->ui8TxSize = 0;
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8RxSize = 0;
    psSMBus->ui8RxIndex = 0;

    //
    // Enable and initialize the I2C master module Using the system clock.
    // The I2C transfer rate will always be 100kHz since fast mode is not
    // supported by SMBus.
    //
    MAP_I2CMasterInitExpClk(psSMBus->ui32I2CBase, ui32SMBusClock, false);

    //
    // Configure bus timeout to 25ms.  12-bit value for 25ms is 0x9C4 (2500
    // clocks), so round upper 8 bits to 0x9C.  Each clock is 10us since
    // 100kHz I2C is required for SMBus.
    //
    MAP_I2CMasterTimeoutSet(psSMBus->ui32I2CBase, 0x9C);
}

//*****************************************************************************
//
//! Slave ISR processing function for the SMBus application.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function must be called in the application interrupt service routine
//! (ISR) to process SMBus slave interrupts.
//!
//! If manual acknowledge is enabled using SMBusSlaveManualACKEnable(), this
//! function processes the data byte, but does not send the ACK/NACK value.  In
//! this case, the user application is responsible for sending the acknowledge
//! bit based on the return code of this function.
//!
//! When receiving a Quick Command from the master, the slave has some set-up
//! requirements.  When the master sends the R/S (data) bit as '0', nothing
//! additional needs to be done in the slave and SMBusSlaveIntProcess() returns
//! \b SMBUS_SLAVE_QCMD_0.  However, when the master sends the R/S (data) bit
//! as '1', the slave must write the data register with data containing a '1'
//! in bit 7.  This means that when receiving a Quick Command, the slave must
//! set up the TX buffer to either have 1 data byte with bit 7 set to '1' or
//! set up the TX buffer to be zero length.  In the case where 1 data byte is
//! put in the TX buffer, SMBusSlaveIntProcess() returns \b SMBUS_OK the first
//! time its called and \b SMBUS_SLAVE_QCMD_0 the second.  In the case where
//! the TX buffer has no data, SMBusSlaveIntProcess() will return
//! \b SMBUS_SLAVE_ERROR the first time its called, and \b SMBUS_SLAVE_QCMD_1
//! the second time.
//!
//! \return Returns \b SMBUS_SLAVE_FIRST_BYTE if the first byte (typically the
//! SMBus command) has been received; \b SMBUS_SLAVE_NOT_READY if the slave's
//! transmit buffer is not yet initialized when the master requests data from
//! the slave; \b SMBUS_DATA_SIZE_ERROR if during a master block write, the
//! size sent by the master is greater than the amount of available space in
//! the receive buffer; \b SMBUS_SLAVE_ERROR if a buffer overrun is detected
//! during a slave receive operation or if data is sent and was not expected;
//! \b SMBUS_SLAVE_QCMD_0 if a Quick Command was received with data '0';
//! \b SMBUS_SLAVE_QCMD_1 if a Quick Command was received with data '1';
//! \b SMBUS_TRANSFER_COMPLETE if a STOP is detected on the bus, marking the
//! end of a transfer; \b SMBUS_PEC_ERROR if the received PEC byte does not
//! match the locally calculated value; or \b SMBUS_OK if processing finished
//! successfully.
//
//*****************************************************************************
tSMBusStatus
SMBusSlaveIntProcess(tSMBus *psSMBus)
{
    uint32_t ui32InterruptStatus;
    uint32_t ui32SlaveStatus = 0;
    uint8_t ui8CRCTemp;
    uint8_t ui8DataTemp;

    //
    // Determine which interrupt was asserted.
    //
    ui32InterruptStatus = I2CSlaveIntStatusEx(psSMBus->ui32I2CBase, true);

    //
    // Check the status register.
    //
    ui32SlaveStatus = I2CSlaveStatus(psSMBus->ui32I2CBase);

    //
    // Check for the START interrupt.
    //
    if(ui32InterruptStatus & I2C_SLAVE_INT_START)
    {
        //
        // Clear the interrupt.
        //
        I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_START);


        //
        // This interrupt is not supported outside of using the FIFO.
        //
        return(SMBUS_OK);
    }

    //
    // Check for the STOP interrupt.
    //
    if(ui32InterruptStatus & I2C_SLAVE_INT_STOP)
    {
        //
        // Make sure the transfer in progress flag is cleared.  In the case
        // of Quick Command, it should never be set, so this is safe.
        //
        HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;

        //
        // Clear the interrupt.
        //
        I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_STOP);

        //
        // Check to see if a Quick Command was sent.
        //
        if(ui32SlaveStatus & 0x10)
        {
            //
            // Make sure the TX/RX index is 0.  If not, we should not be here.
            // Other data should not have been sent or received during a Quick
            // Command.
            //
            if((psSMBus->ui8RxIndex != 0) || (psSMBus->ui8TxIndex != 0))
            {
                //
                // Return an error.
                //
                return(SMBUS_SLAVE_ERROR);
            }

            //
            // Tell caller a Quick Command has occurred and the data value.
            //
            if(ui32SlaveStatus & 0x20)
            {
                return(SMBUS_SLAVE_QCMD_1);
            }
            else
            {
                return(SMBUS_SLAVE_QCMD_0);
            }
        }

        //
        // Move to the idle state.
        //
        psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;

        //
        // Return end of transfer.
        //
        return(SMBUS_TRANSFER_COMPLETE);
    }

    //
    // Check for the DATA interrupt.
    //
    if(ui32InterruptStatus & I2C_SLAVE_INT_DATA)
    {
        //
        // Clear the I2C interrupt.
        //
        I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_DATA);

        //
        // Make sure that at least one of the relevant status bits is set.
        //
        if(!(ui32SlaveStatus & 0x07))
        {
            //
            // No status bits were set - this is bad.  Should never get here.
            //
            return(SMBUS_SLAVE_ERROR);
        }

        //
        // Every time this interrupt occurs, a transfer is in progress.  Make
        // sure the flag is set appropriately.
        //
        HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;

        //
        // Handle the request type.
        //
        switch((ui32SlaveStatus & 0x07))
        {
            //
            // The first byte after the slave's own address has been received.
            // This is almost always the command byte in SMBus.  The only
            // exception is when the Send Byte protocol is used by the master.
            //
            case I2C_SLAVE_ACT_RREQ_FBR:
            {
                //
                // Check which slave address was called out.  Set the active
                // address to the matched address.
                //
                if(I2CSlaveStatus(psSMBus->ui32I2CBase) & I2C_SCSR_OAR2SEL)
                {
                    psSMBus->ui8OwnSlaveAddress =
                        HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR2) & 0x7f;
                }
                else
                {
                    psSMBus->ui8OwnSlaveAddress =
                        HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR);
                }

                //
                // If raw I2C, data goes into buffer.
                //
                if(HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C))
                {
                    psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
                        I2CSlaveDataGet(psSMBus->ui32I2CBase);
                }

                //
                // Read the first byte into the ui8CurrentCommand member.
                //
                else
                {
                    psSMBus->ui8CurrentCommand =
                        I2CSlaveDataGet(psSMBus->ui32I2CBase);
                }

                //
                // If PEC is enabled, add the address to the CRC calculation.
                //
                if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                {
                    //
                    // Add the address to the CRC calculation.  In this case
                    // R/S will always be 0.  Also, this is the start of the
                    // CRC calculation, so the initial value is 0.
                    //
                    ui8CRCTemp = psSMBus->ui8OwnSlaveAddress << 1;

                    //
                    // Calculate new CRC.
                    //
                    psSMBus->ui8CalculatedCRC = Crc8CCITT(0, &ui8CRCTemp, 1);

                    //
                    // Add the data byte (ui8CurrentCommand) to the CRC
                    // calculation.
                    //
                    psSMBus->ui8CalculatedCRC =
                        MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                      &psSMBus->ui8CurrentCommand, 1);
                }

                //
                // Update the state machine.
                //
                psSMBus->ui8SlaveState = SMBUS_STATE_SLAVE_POST_COMMAND;

                //
                // Actions for this case are complete.
                //
                return(SMBUS_SLAVE_FIRST_BYTE);
            }

            //
            // A data byte other than the first data byte has been received.
            //
            case I2C_SLAVE_ACT_RREQ:
            {
                //
                // Determine what to do based on the current state.
                //
                switch(psSMBus->ui8SlaveState)
                {
                    //
                    // Receive first post-command byte.
                    //
                    case SMBUS_STATE_SLAVE_POST_COMMAND:
                    {
                        //
                        // Read the data into the a temporary variable.
                        //
                        ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);

                        //
                        // Check if this is a block transfer.
                        //
                        if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
                        {
                            //
                            // Make sure there is enough space in the buffer.
                            // If not, NACK.  If there is, overwrite the
                            // current size with the size sent by the master.
                            //
                            if(ui8DataTemp > psSMBus->ui8RxSize)
                            {
                                //
                                // Update the state machine.
                                //
                                psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;

                                //
                                // Indicate a size error.
                                //
                                return(SMBUS_DATA_SIZE_ERROR);
                            }
                            else
                            {
                                //
                                // Update the size.
                                //
                                psSMBus->ui8RxSize = ui8DataTemp;

                                //
                                // Check to see if PEC is enabled.
                                //
                                if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                                {
                                    //
                                    // Add the size byte to the CRC
                                    // calculation.
                                    //
                                    psSMBus->ui8CalculatedCRC =
                                       MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                     &ui8DataTemp, 1);
                                }

                                //
                                // Update the state machine.
                                //
                                psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
                            }

                            //
                            // This state is done.
                            //
                            break;
                        }

                        //
                        // If there is no data to receive and no PEC, nothing
                        // to do.  Software should never get here.
                        //
                        if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
                        {
                            //
                            // Update the state machine.
                            //
                            psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;

                            //
                            // Report an error.
                            //
                            return(SMBUS_SLAVE_ERROR);
                        }
                        else
                        {
                            //
                            // Put the data in the buffer.
                            //
                            psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
                                ui8DataTemp;

                            //
                            // If this is the last data byte.
                            //
                            if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
                            {
                                //
                                // Check for PEC usage.
                                //
                                if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                                {
                                    //
                                    // Add the size byte to the CRC
                                    // calculation.
                                    //
                                    psSMBus->ui8CalculatedCRC =
                                       MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                     &ui8DataTemp, 1);

                                    //
                                    // Update the state machine.
                                    //
                                    psSMBus->ui8SlaveState =
                                        SMBUS_STATE_READ_PEC;
                                }
                                else
                                {
                                    //
                                    // Update the state machine.
                                    //
                                    psSMBus->ui8SlaveState =
                                        SMBUS_STATE_READ_DONE;
                                }
                            }

                            //
                            // All other cases.
                            //
                            else
                            {
                                //
                                // Check for PEC usage.
                                //
                                if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                                {
                                    //
                                    // Add the size byte to the CRC
                                    // calculation.
                                    //
                                    psSMBus->ui8CalculatedCRC =
                                       MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                     &ui8DataTemp, 1);
                                }

                                //
                                // Update the state machine.
                                //
                                psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
                            }
                        }

                        //
                        // Actions for this case are complete.
                        //
                        break;
                    }

                    //
                    // Read the next byte into the buffer.
                    //
                    case SMBUS_STATE_READ_NEXT:
                    {
                        //
                        // Read the data into the a temporary variable.
                        //
                        ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);

                        //
                        // If there is no data to receive and no PEC, nothing
                        // to do.  Software should never get here.
                        //
                        if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
                        {
                            //
                            // Update the state machine.
                            //
                            psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;

                            //
                            // Report an error.
                            //
                            return(SMBUS_SLAVE_ERROR);
                        }
                        else
                        {
                            //
                            // Put the data in the buffer.
                            //
                            psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
                                ui8DataTemp;

                            //
                            // If this is the last data byte.
                            //
                            if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
                            {
                                //
                                // Check for PEC usage.
                                //
                                if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                                {
                                    //
                                    // Add the size byte to the CRC
                                    // calculation.
                                    //
                                    psSMBus->ui8CalculatedCRC =
                                       MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                     &ui8DataTemp, 1);

                                    //
                                    // Update the state machine.
                                    //
                                    if(HWREGBITB(&psSMBus->ui16Flags,
                                                 FLAG_PROCESS_CALL))
                                    {
                                        psSMBus->ui8SlaveState =
                                            SMBUS_STATE_READ_DONE;
                                    }
                                    else
                                    {
                                        psSMBus->ui8SlaveState =
                                            SMBUS_STATE_READ_PEC;
                                    }
                                }
                                else
                                {
                                    //
                                    // Update the state machine.
                                    //
                                    psSMBus->ui8SlaveState =
                                        SMBUS_STATE_READ_DONE;
                                }
                            }

                            //
                            // All other cases.
                            //
                            else
                            {
                                //
                                // Check for PEC usage.
                                //
                                if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                                {
                                    //
                                    // Add the size byte to the CRC
                                    // calculation.
                                    //
                                    psSMBus->ui8CalculatedCRC =
                                       MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                     &ui8DataTemp, 1);
                                }

                                //
                                // Update the state machine.
                                //
                                psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
                            }
                        }

                        break;
                    }

                    //
                    // Read the PEC byte and compare it.
                    //
                    case SMBUS_STATE_READ_PEC:
                    {
                        //
                        // Read the data into the a temporary variable.
                        //
                        ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);

                        //
                        // Compare PEC.
                        //
                        if(psSMBus->ui8CalculatedCRC != ui8DataTemp)
                        {
                            //
                            // Indicate PEC error.
                            //
                            return(SMBUS_PEC_ERROR);
                        }

                        //
                        // Update the state machine.
                        //
                        psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;

                        break;
                    }

                    //
                    // No more data to receive.  If we get here, read data
                    // into a dummy variable and NACK.
                    //
                    case SMBUS_STATE_READ_DONE:
                    {
                        //
                        // Read the data into the a temporary variable.
                        //
                        ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);

                        //
                        // Report an error.
                        //
                        return(SMBUS_SLAVE_ERROR);
                    }
                }

                //
                // Actions for this case are complete.
                //
                break;
            }

            //
            // The master has requested that the slave transmit data back to
            // master.
            //
            case I2C_SLAVE_ACT_TREQ:
            {
                //
                // Initialize temporary variable that stores transmit byte to
                // 0xff.  If data is not set by another condition, the 0xff
                // carries through.  This happens if ui8TxIndex is equal to or
                // greater than ui8TxSize.
                //
                ui8DataTemp = 0xff;

                //
                // Determine what to do based on the current state.
                //
                switch(psSMBus->ui8SlaveState)
                {
                    //
                    // The state machine is currently idle, or if the last
                    // state was SMBUS_STATE_SLAVE_POST_COMMAND or
                    // SMBUS_READ_DONE, this is the first byte transmitted.  In
                    // the case of slave post command, this means that the
                    // command was received followed by a repeated start (with
                    // R/S = 1).  In the case of read next, this means that a
                    // raw I2C master transmit changed direction with a
                    // repeated start and is now a master receive.  In the case
                    // of read done, this means that a previous master transmit
                    // was finished (non-command followed by a repeated start).
                    //
                    case SMBUS_STATE_IDLE:
                    case SMBUS_STATE_SLAVE_POST_COMMAND:
                    case SMBUS_STATE_READ_NEXT:
                    case SMBUS_STATE_READ_DONE:
                    {
                        //
                        // Check which slave address was called out.  Set the
                        // active address to the matched address.
                        //
                        if(I2CSlaveStatus(psSMBus->ui32I2CBase) &
                           I2C_SCSR_OAR2SEL)
                        {
                            psSMBus->ui8OwnSlaveAddress =
                                (HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR2) &
                                 0x7f);
                        }
                        else
                        {
                            psSMBus->ui8OwnSlaveAddress =
                                HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR);
                        }

                        //
                        // Check to see if the TX buffer is populated.  If not,
                        // return not ready without writing to the data
                        // register.
                        //
                        if(psSMBus->ui8TxSize == 0)
                        {
                            return(SMBUS_SLAVE_NOT_READY);
                        }

                        //
                        // Is this a block transfer?
                        //
                        if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
                        {
                            //
                            // The first byte to send is the size.
                            //
                            ui8DataTemp = psSMBus->ui8TxSize;
                        }
                        else
                        {
                            //
                            // Is there data to send?
                            //
                            if(psSMBus->ui8TxIndex < psSMBus->ui8TxSize)
                            {
                                //
                                // Set the transmit data to the next item in
                                // the buffer.
                                //
                                ui8DataTemp =
                                    psSMBus->pui8TxBuffer[psSMBus->
                                                          ui8TxIndex++];
                            }
                            else
                            {
                                //
                                // Send 0xff per spec.
                                //
                                ui8DataTemp = 0xff;
                            }
                        }

                        //
                        // Check to see if PEC is required.
                        //
                        if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                        {
                            //
                            // Start calculating the CRC with the address.
                            //
                            ui8CRCTemp =
                                (psSMBus->ui8OwnSlaveAddress << 1) | 1;

                            //
                            // Add the address and R/S bit to the CRC.
                            //
                            psSMBus->ui8CalculatedCRC =
                                MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                              &ui8CRCTemp, 1);

                            //
                            // Add the data byte to the CRC calculation.
                            //
                            psSMBus->ui8CalculatedCRC =
                                MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                              &ui8DataTemp, 1);

                            //
                            // Move to the next state.
                            //
                            if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
                            {
                                //
                                // Final byte is the CRC byte.
                                //
                                psSMBus->ui8SlaveState =
                                    SMBUS_STATE_WRITE_FINAL;
                            }
                            else
                            {
                                //
                                // All other cases, move to the next byte
                                // state.
                                //
                                psSMBus->ui8SlaveState =
                                    SMBUS_STATE_WRITE_NEXT;
                            }
                        }
                        else
                        {
                            //
                            // Move to the next state.
                            //
                            switch(psSMBus->ui8TxSize - psSMBus->ui8TxIndex)
                            {
                                //
                                // If all of the data has been sent, move to
                                // the done state.
                                //
                                case 0:
                                {
                                    psSMBus->ui8SlaveState =
                                        SMBUS_STATE_WRITE_DONE;

                                    break;
                                }

                                //
                                // If 1 left, move to the final byte state.
                                //
                                case 1:
                                {
                                    psSMBus->ui8SlaveState =
                                        SMBUS_STATE_WRITE_FINAL;

                                    break;
                                }

                                //
                                // All other cases, move to the next byte
                                // state.
                                //
                                default:
                                {
                                    psSMBus->ui8SlaveState =
                                        SMBUS_STATE_WRITE_NEXT;

                                    break;
                                }
                            }
                        }

                        //
                        // Send the data.
                        //
                        I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);

                        //
                        // This state is done.
                        //
                        break;
                    }

                    //
                    // The first byte has already been sent, handle the rest.
                    //
                    case SMBUS_STATE_WRITE_NEXT:
                    {
                        //
                        // Set the transmit data to the next item in the
                        // buffer.
                        //
                        ui8DataTemp =
                            psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];

                        //
                        // Check to see if PEC is required.
                        //
                        if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                        {
                            //
                            // Add the byte to the CRC calculation.
                            //
                            psSMBus->ui8CalculatedCRC =
                                MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                              &ui8DataTemp, 1);

                            //
                            // Check if it's time to move to the next state.
                            //
                            if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
                            {
                                //
                                // Final byte is the CRC byte.
                                //
                                psSMBus->ui8SlaveState =
                                    SMBUS_STATE_WRITE_FINAL;
                            }
                        }
                        else
                        {
                            //
                            // Move to the next state.
                            //
                            if((psSMBus->ui8TxSize - psSMBus->ui8TxIndex) == 1)
                            {
                                //
                                // If only 1 byte remains, move to the final
                                // state.
                                //
                                psSMBus->ui8SlaveState =
                                    SMBUS_STATE_WRITE_FINAL;
                            }
                        }

                        //
                        // Send the data.
                        //
                        I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);

                        //
                        // This state is done.
                        //
                        break;
                    }

                    //
                    // Write the final byte, whether PEC or data.
                    //
                    case SMBUS_STATE_WRITE_FINAL:
                    {
                        //
                        // Check to see if PEC is required.
                        //
                        if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
                        {
                            //
                            // Send the CRC byte.
                            //
                            ui8DataTemp = psSMBus->ui8CalculatedCRC;
                        }
                        else
                        {
                            //
                            // Send the last data byte.
                            //
                            ui8DataTemp =
                                psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
                        }

                        //
                        // Send the data.
                        //
                        I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);

                        //
                        // Move to the write done state.
                        //
                        psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_DONE;

                        //
                        // This state is done.
                        //
                        break;
                    }

                    //
                    // All data has been sent, send 0xff.
                    //
                    case SMBUS_STATE_WRITE_DONE:
                    {
                        //
                        // Send 0xff because there is no more data to send.
                        //
                        I2CSlaveDataPut(psSMBus->ui32I2CBase, 0xff);

                        //
                        // This state is done.
                        //
                        break;
                    }
                }

                //
                // Actions for this case are complete.
                //
                break;
            }
        }

        //
        // Return OK status.
        //
        return(SMBUS_OK);
    }

    //
    // Return OK.  Should never get here.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Sends data outside of the interrupt processing function.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function sends data outside the interrupt processing function, and
//! should only be used when SMBusSlaveIntProcess() returns
//! \b SMBUS_SLAVE_NOT_READY.  At this point, the application should set up the
//! transfer and call this function (it assumes that the transmit buffer has
//! already been populated when called).  When called, this function updates
//! the slave state machine as if SMBusSlaveIntProcess() were called.
//!
//! \return Returns \b SMBUS_SLAVE_NOT_READY if the slave's transmit buffer is
//! not yet initialized (ui8TxSize is 0), or \b SMBUS_OK if processing finished
//! successfully.
//
//*****************************************************************************
tSMBusStatus
SMBusSlaveDataSend(tSMBus *psSMBus)
{
    uint8_t ui8CRCTemp;
    uint8_t ui8DataTemp;

    //
    // Check to see if the TX buffer is populated.  If not,
    // return not ready without writing to the data register.
    //
    if(psSMBus->ui8TxSize == 0)
    {
        return(SMBUS_SLAVE_NOT_READY);
    }

    //
    // Is this a block transfer?
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
    {
        //
        // The first byte to send is the size.
        //
        ui8DataTemp = psSMBus->ui8TxSize;
    }
    else
    {
        //
        // Is there data to send?
        //
        if(psSMBus->ui8TxIndex < psSMBus->ui8TxSize)
        {
            //
            // Set the transmit data to the next item in
            // the buffer.
            //
            ui8DataTemp = psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
        }
        else
        {
            //
            // Send 0xff per spec.  Should not get here.
            //
            ui8DataTemp = 0xff;
        }
    }

    //
    // Check to see if PEC is required.
    //
    if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
    {
        //
        // Start calculating the CRC with the address.
        //
        ui8CRCTemp = (psSMBus->ui8OwnSlaveAddress << 1) | 1;

        //
        // Add the address and R/S bit to the CRC.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &ui8CRCTemp, 1);

        //
        // Add the data byte to the CRC calculation.
        //
        psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
                                                  &ui8DataTemp, 1);

        //
        // Move to the next state.
        //
        if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
        {
            //
            // Final byte is the CRC byte.
            //
            psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_FINAL;
        }
        else
        {
            //
            // All other cases, move to the next byte state.
            //
            psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_NEXT;
        }
    }
    else
    {
        //
        // Move to the next state.
        //
        switch(psSMBus->ui8TxSize - psSMBus->ui8TxIndex)
        {
            //
            // If all of the data has been sent, move to the
            // done state.
            //
            case 0:
            {
                psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_DONE;

                break;
            }

            //
            // If 1 left, move to the final byte state.
            //
            case 1:
            {
                psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_FINAL;

                break;
            }

            //
            // All other cases, move to the next byte state.
            //
            default:
            {
                psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_NEXT;

                break;
            }
        }
    }

    //
    // Send the data.
    //
    I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);

    //
    // Return to caller.
    //
    return(SMBUS_OK);
}

//*****************************************************************************
//
//! Set the address and size of the slave transmit buffer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param pui8Data is a pointer to the transmit data buffer.
//! \param ui8Size is the number of bytes in the buffer.
//!
//! This function sets the address and size of the slave transmit buffer.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveTxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
                      uint8_t ui8Size)
{
    //
    // Set the trasmit buffer.
    //
    psSMBus->pui8TxBuffer = pui8Data;

    //
    // Set the size.
    //
    psSMBus->ui8TxSize = ui8Size;
}

//*****************************************************************************
//
//! Set the address and size of the slave receive buffer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param pui8Data is a pointer to the receive data buffer.
//! \param ui8Size is the number of bytes in the buffer.
//!
//! This function sets the address and size of the slave receive buffer.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveRxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
                      uint8_t ui8Size)
{
    //
    // Set the receive buffer.
    //
    psSMBus->pui8RxBuffer = pui8Data;

    //
    // Set the size.
    //
    psSMBus->ui8RxSize = ui8Size;
}

//*****************************************************************************
//
//! Get the current command byte.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! Returns the current value of the ui8CurrentCommand variable in the SMBus
//! configuration structure.  This can be used to help the user application
//! set up the SMBus slave transmit and receive buffers.
//!
//! \return None.
//
//*****************************************************************************
uint8_t
SMBusSlaveCommandGet(tSMBus *psSMBus)
{
    //
    // Return the current command.
    //
    return(psSMBus->ui8CurrentCommand);
}

//*****************************************************************************
//
//! Sets the process call flag for an SMBus slave transfer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! Sets the process call flag in the configuration structure so that the SMBus
//! slave can respond correctly to a Process Call request.  This flag must be
//! set prior to the data portion of the packet.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveProcessCallEnable(tSMBus *psSMBus)
{
    //
    // Set the block transfer flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
}

//*****************************************************************************
//
//! Clears the process call flag for an SMBus slave transfer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! Clears the process call flag in the configuration structure.  The user
//! application can either call this function to clear the flag, or use
//! SMBusSlaveTransferInit() to clear out all transfer-specific flags.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveProcessCallDisable(tSMBus *psSMBus)
{
    //
    // Clear the block transfer flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
}

//*****************************************************************************
//
//! Sets the block transfer flag for an SMBus slave transfer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! Sets the block transfer flag in the configuration structure so that the
//! SMBus slave can respond correctly to a Block Write or Block Read request.
//! This flag must be set prior to the data portion of the packet.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveBlockTransferEnable(tSMBus *psSMBus)
{
    //
    // Set the block transfer flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
}

//*****************************************************************************
//
//! Clears the block transfer flag for an SMBus slave transfer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! Clears the block transfer flag in the configuration structure.  The user
//! application can either call this function to clear the flag, or use
//! SMBusSlaveTransferInit() to clear out all transfer-specific flags.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveBlockTransferDisable(tSMBus *psSMBus)
{
    //
    // Clear the block transfer flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
}

//*****************************************************************************
//
//! Sets the ``raw'' I2C flag for an SMBus slave transfer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! Sets the raw I2C flag in the configuration structure so that the
//! SMBus slave can respond correctly to raw I2C (non-SMBus protocol) requests.
//! This flag must be set prior to the transfer, and is a global setting.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveI2CEnable(tSMBus *psSMBus)
{
    //
    // Set the block transfer flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
}

//*****************************************************************************
//
//! Clears the ``raw'' I2C flag for an SMBus slave transfer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! Clears the raw I2C flag in the configuration structure.  This flag is a
//! global setting similar to the PEC flag and cannot be cleared using
//! SMBusSlaveTransferInit().
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveI2CDisable(tSMBus *psSMBus)
{
    //
    // Clear the block transfer flag.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
}

//*****************************************************************************
//
//! Sets the value of the AR (Address Resolved) flag.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param bValue is the value to set the flag.
//!
//! This function allows the application to set the value of the AR flag.  All
//! SMBus slaves must support the AR and AV flags.  On POR, the AR flag is
//! cleared.  It is also cleared when a slave receives the ARP Reset Device
//! command.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveARPFlagARSet(tSMBus *psSMBus, bool bValue)
{
    //
    // Set the block address resolved flag to the desired value.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_RESOLVED) = bValue;
}

//*****************************************************************************
//
//! Returns the current value of the AR (Address Resolved) flag.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This returns the value of the AR (Address Resolved) flag.
//!
//! \return Returns \b true if set, \b false if cleared.
//
//*****************************************************************************
bool
SMBusSlaveARPFlagARGet(tSMBus *psSMBus)
{
    //
    // Get the value of the block address resolved flag.
    //
    return(HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_RESOLVED));
}

//*****************************************************************************
//
//! Sets the value of the AV (Address Valid) flag.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param bValue is the value to set the flag.
//!
//! This function allows the application to set the value of the AV flag.  All
//! SMBus slaves must support the AR and AV flags.  On POR, the AV flag is
//! cleared.  It is also cleared when a slave receives the ARP Reset Device
//! command.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveARPFlagAVSet(tSMBus *psSMBus, bool bValue)
{
    //
    // Set the block address valid flag to the desired value.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_VALID) = bValue;
}

//*****************************************************************************
//
//! Returns the current value of the AV (Address Valid) flag.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This returns the value of the AV (Address Valid) flag.
//!
//! \return Returns \b true if set, or \b false if cleared.
//
//*****************************************************************************
bool
SMBusSlaveARPFlagAVGet(tSMBus *psSMBus)
{
    //
    // Get the value of the block address valid flag.
    //
    return(HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_VALID));
}

//*****************************************************************************
//
//! Sets up the SMBus slave for a new transfer.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function is used to re-initialize the configuration structure for a
//! new transfer.  Once a transfer is complete and the data has been processed,
//! unused flags, states, the data buffers and buffer indexes should be reset
//! to a known state before a new transfer.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveTransferInit(tSMBus *psSMBus)
{
    //
    // Clear the block transfer, process call and transfer in progress flags.
    //
    HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
    HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;

    //
    // Set the configuration structure to a known, zeroed state.
    //
    psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
    psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
    psSMBus->ui8CurrentCommand = 0;
    psSMBus->ui8CalculatedCRC = 0;
    psSMBus->ui8TxSize = 0;
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8RxSize = 0;
    psSMBus->ui8RxIndex = 0;
}

//*****************************************************************************
//
//! Sets the value of the ACK bit when using manual acknowledgement.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param bACK specifies whether to ACK (\b true) or NACK (\b false).
//!
//! This function sets the value of the ACK bit.  In order for the ACK bit to
//! take effect, manual acknowledgement must be enabled on the slave using
//! SMBusSlaveManualACKEnable().
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveACKSend(tSMBus *psSMBus, bool bACK)
{
    //
    // Send ACK or NACK based on the value of bACK.
    //
    if(bACK)
    {
        I2CSlaveACKValueSet(psSMBus->ui32I2CBase, true);
    }
    else
    {
        I2CSlaveACKValueSet(psSMBus->ui32I2CBase, false);
    }
}

//*****************************************************************************
//
//! Enables manual acknowledgement for the SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function enables manual acknowledge capability in the slave.  If the
//! application requires that the slave NACK on a bad command or a bad PEC
//! calculation, manual acknowledgement allows this to happen.
//!
//! In the case of responding to a bad command with a NACK, the application
//! should use SMBusSlaveACKSend() to ACK/NACK the command.   The slave ISR
//! should check for the SMBUS_SLAVE_FIRST_BYTE return code from
//! SMBusSlaveISRProcess() and ACK/NACK accordingly.  All other cases should be
//! handled in the application based on the return code of
//! SMBusSlaveISRProcess().
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveManualACKEnable(tSMBus *psSMBus)
{
    //
    // Enable manual acknowledge.
    //
    I2CSlaveACKOverride(psSMBus->ui32I2CBase, true);
}

//*****************************************************************************
//
//! Disables manual acknowledgement for the SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function disables manual acknowledge capability in the slave.  When
//! manual acknowledgement is disabled, the slave automatically ACKs every
//! byte sent by the master.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveManualACKDisable(tSMBus *psSMBus)
{
    //
    // Disable manual acknowledge.
    //
    I2CSlaveACKOverride(psSMBus->ui32I2CBase, false);
}

//*****************************************************************************
//
//! Returns the manual acknowledgement status of the SMBus slave.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function returns the state of the I2C ACKOEN bit in the I2CSACKCTL
//! register.  This feature is disabled out of reset and must be enabled
//! using SMBusSlaveManualACKEnable().
//!
//! \return Returns \b true if manual acknowledge is enabled, or \b false if
//! manual acknowledge is disabled.
//
//*****************************************************************************
bool
SMBusSlaveManualACKStatusGet(tSMBus *psSMBus)
{
    //
    // Return the value of the bit.
    //
    return(HWREG(psSMBus->ui32I2CBase + I2C_O_SACKCTL) & 0x1);
}

//*****************************************************************************
//
//! Determine whether primary or secondary slave address has been requested by
//! the master.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! Tells the caller whether the I2C slave address requested by the master or
//! SMBus Host is the primary or secondary I2C slave address of the peripheral.
//! The primary is defined as the address programmed into I2CSOAR, and the
//! secondary as the address programmed into I2CSOAR2.
//!
//! \return Returns \b SMBUS_SLAVE_ADDR_PRIMARY if the primary address is
//! called out or \b SMBUS_SLAVE_ADDR_SECONDARY if the secondary address is
//! called out.
//
//*****************************************************************************
tSMBusStatus
SMBusSlaveIntAddressGet(tSMBus *psSMBus)
{
    //
    // Determine whether the primary or secondary address was called out.
    //
    if(I2CSlaveStatus(psSMBus->ui32I2CBase) & I2C_SCSR_OAR2SEL)
    {
        return(SMBUS_SLAVE_ADDR_SECONDARY);
    }
    else
    {
        return(SMBUS_SLAVE_ADDR_PRIMARY);
    }
}

//*****************************************************************************
//
//! Enables the appropriate slave interrupts for stack processing.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//!
//! This function enables the I2C interrupts used by the SMBus slave.  Both
//! the peripheral-level and NVIC-level interrupts are enabled.
//! SMBusSlaveInit() must be called before this function because this function
//! relies on the I2C base address being defined.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveIntEnable(tSMBus *psSMBus)
{
    //
    // Enable the slave interrupts.
    //
    I2CSlaveIntEnableEx(psSMBus->ui32I2CBase,
                        I2C_SLAVE_INT_DATA | I2C_SLAVE_INT_STOP);

    //
    // Enable the interrupt in the NVIC.
    //
    switch(psSMBus->ui32I2CBase)
    {
        case I2C0_BASE:
        {
            MAP_IntEnable(INT_I2C0);
            break;
        }

        case I2C1_BASE:
        {
            MAP_IntEnable(INT_I2C1);
            break;
        }

        case I2C2_BASE:
        {
            if(CLASS_IS_TM4C123)
            {
                MAP_IntEnable(INT_I2C2_TM4C123);
            }
            else if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C2_TM4C129);
            }
            break;
        }

        case I2C3_BASE:
        {
            if(CLASS_IS_TM4C123)
            {
                MAP_IntEnable(INT_I2C3_TM4C123);
            }
            else if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C3_TM4C129);
            }
            break;
        }

        case I2C4_BASE:
        {
            if(CLASS_IS_TM4C123)
            {
                MAP_IntEnable(INT_I2C4_TM4C123);
            }
            else if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C4_TM4C129);
            }
            break;
        }

        case I2C5_BASE:
        {
            if(CLASS_IS_TM4C123)
            {
                MAP_IntEnable(INT_I2C5_TM4C123);
            }
            else if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C5_TM4C129);
            }
            break;
        }

        case I2C6_BASE:
        {
            if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C6_TM4C129);
            }
            break;
        }

        case I2C7_BASE:
        {
            if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C7_TM4C129);
            }
            break;
        }

        case I2C8_BASE:
        {
            if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C8_TM4C129);
            }
            break;
        }

        case I2C9_BASE:
        {
            if(CLASS_IS_TM4C129)
            {
                MAP_IntEnable(INT_I2C9_TM4C129);
            }
            break;
        }
    }
}

//*****************************************************************************
//
//! Sets the slave address for an SMBus slave peripheral.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui8AddressNum specifies which address (primary or secondary)
//! \param ui8SlaveAddress is the address of the slave.
//!
//! This function sets the slave address.  Both the primary and secondary
//! addresses can be set using this function.  To set the primary address
//! (stored in I2CSOAR), ui8AddressNum should be '0'.  To set the secondary
//! address (stored in I2CSOAR2), ui8AddressNum should be '1'.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveAddressSet(tSMBus *psSMBus, uint8_t ui8AddressNum,
                     uint8_t ui8SlaveAddress)
{
    //
    // Write the slave address.
    //
    I2CSlaveAddressSet(psSMBus->ui32I2CBase, ui8AddressNum, ui8SlaveAddress);
}

//*****************************************************************************
//
//! Sets a slave's UDID structure.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param pUDID is a pointer to the UDID configuration for the slave.  This
//! is only needed if the slave is on a bus that uses ARP.
//!
//! This function sets the UDID for a slave instance.
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveUDIDSet(tSMBus *psSMBus, tSMBusUDID *pUDID)
{
    psSMBus->pUDID = pUDID;
}

//*****************************************************************************
//
//! Initializes an I2C slave peripheral for SMBus functionality.
//!
//! \param psSMBus specifies the SMBus configuration structure.
//! \param ui32I2CBase specifies the base address of the I2C slave peripheral.
//!
//! This function initializes an I2C peripheral for SMBus slave use.  The
//! instance-specific configuration structure is initialized to a set of known
//! values and the I2C peripheral is configured based on the input arguments.
//!
//! The default configuration of the SMBus slave uses automatic
//! acknowledgement.  If manual acknowledgement is required, call
//! SMBusSlaveManualACKEnable().
//!
//! \return None.
//
//*****************************************************************************
void
SMBusSlaveInit(tSMBus *psSMBus, uint32_t ui32I2CBase)
{
    //
    // Initialize the configuration structure.
    //
    psSMBus->pUDID = 0;
    psSMBus->ui32I2CBase = ui32I2CBase;
    psSMBus->ui16Flags = 0;
    psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
    psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
    psSMBus->ui8OwnSlaveAddress = 0;
    psSMBus->ui8TargetSlaveAddress = 0;
    psSMBus->ui8CurrentCommand = 0;
    psSMBus->ui8CalculatedCRC = 0;
    psSMBus->ui8TxSize = 0;
    psSMBus->ui8TxIndex = 0;
    psSMBus->ui8RxSize = 0;
    psSMBus->ui8RxIndex = 0;

    //
    // Enable the I2C slave module.  The slave is always enabled because the
    // SMBus spec requires that all devices respond whne their slave address
    // is put on the bus.
    //
    I2CSlaveEnable(psSMBus->ui32I2CBase);
}

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
