//###########################################################################
//
// FILE:   dac.h
//
// TITLE:  C29x DAC driver.
//
//###########################################################################
// $Copyright:
//###########################################################################

#ifndef DAC_H
#define DAC_H

//*****************************************************************************
//
// If building with a C++ compiler, make all of the definitions in this header
// have a C binding.
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif

//*****************************************************************************
//
//! \addtogroup dac_api DAC
//! @{
//
//*****************************************************************************

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_dac.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "cpu.h"
#include "debug.h"

//
// A 8-bit register mask
//
#define DAC_REG_BYTE_MASK       (0xFFU)   //!< Register Byte Mask

//
// Lock Key
//
#define DAC_LOCK_KEY            (0xA000U) //!< DAC Lock Key

#ifndef DOXYGEN_PDF_IGNORE
//*****************************************************************************
//
// The following are defines for the reg parameter of the
// DAC_lockRegister() and DAC_isRegisterLocked() functions.
//
//*****************************************************************************
#define DAC_LOCK_CONTROL        (0x1U)    //!< Lock the control register
#define DAC_LOCK_SHADOW         (0x2U)    //!< Lock the shadow value register
#define DAC_LOCK_OUTPUT         (0x4U)    //!< Lock the output enable register

#endif // DOXYGEN_PDF_IGNORE

//*****************************************************************************
//
//! Values that can be passed to DAC_setReferenceVoltage() as the \e source
//! parameter.
//
//*****************************************************************************
typedef enum
{
    DAC_REF_VDAC        = 0,  //!< VDAC reference voltage
    DAC_REF_ADC_VREFHI  = 1   //!< ADC VREFHI reference voltage
}DAC_ReferenceVoltage;

//*****************************************************************************
//
//! Values that can be passed to DAC_setGainMode() as the \e mode parameter.
//
//*****************************************************************************
typedef enum
{
    DAC_GAIN_ONE = 0,     //!< Gain set to 1
    DAC_GAIN_TWO = 2      //!< Gain set to 2
}DAC_GainMode;

//*****************************************************************************
//
//! Values that can be passed to DAC_setLoadMode() as the \e mode parameter.
//
//*****************************************************************************
typedef enum
{
    DAC_LOAD_SYSCLK  = 0,     //!< Load on next SYSCLK
    DAC_LOAD_PWMSYNC = 4      //!< Load on next PWMSYNC specified by SYNCSEL
}DAC_LoadMode;

//*****************************************************************************
//
// Prototypes for the APIs.
//
//*****************************************************************************
//*****************************************************************************
//
//! \internal
//! Checks DAC base address.
//!
//! \param base specifies the DAC module base address.
//!
//! This function determines if an DAC module base address is valid.
//!
//! \return Returns \b true if the base address is valid and \b false
//! otherwise.
//
//*****************************************************************************
#ifdef DEBUG
__attribute__((always_inline))
static inline bool
DAC_isBaseValid(uint32_t base)
{
return (
           ((base & BASE_ADDR_MASK) == DACA_BASE_FRAME(0U)) ||
           ((base & BASE_ADDR_MASK) == DACB_BASE_FRAME(0U))
          );
}
#endif

//*****************************************************************************
//
//! Get the DAC Revision value
//!
//! \param base is the DAC module base address
//!
//! This function gets the DAC revision value.
//!
//! \return Returns the DAC revision value.
//
//*****************************************************************************
__attribute__((always_inline))
static inline uint16_t
DAC_getRevision(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));

    //
    // Get the revision value.
    //
    return(HWREGH(base + DAC_O_REV) & DAC_REV_REV_M);
}

//*****************************************************************************
//
//! Sets the DAC Reference Voltage
//!
//! \param base is the DAC module base address
//! \param source is the selected reference voltage
//!
//! This function sets the DAC reference voltage.
//!
//! The \e source parameter can have the following value:
//! - \b DAC_REF_VDAC       - The VDAC reference voltage
//! - \b DAC_REF_ADC_VREFHI - The ADC VREFHI reference voltage
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline void
DAC_setReferenceVoltage(uint32_t base, DAC_ReferenceVoltage source)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));

    //
    // Set the reference voltage
    //

    HWREGH(base + DAC_O_CTL) = (HWREGH(base + DAC_O_CTL) &
                                ~DAC_CTL_DACREFSEL) | (uint16_t)source;
}

//*****************************************************************************
//
//! Sets the DAC Gain Mode
//!
//! \param base is the DAC module base address
//! \param mode is the selected gain mode
//!
//! This function sets the DAC gain mode for the buffered output.
//!
//! The \e mode parameter can have one of two values:
//! - \b DAC_GAIN_ONE  - Gain is set to 1
//! - \b DAC_GAIN_TWO  - Gain is set to 2
//!
//! \note This value is only used when \e DAC_REF_ADC_VREFHI is set using
//! DAC_setReferenceVoltage() and internal ADC reference mode is selected.
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline void
DAC_setGainMode(uint32_t base, DAC_GainMode mode)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));

    //
    // Set the gain mode
    //

    HWREGH(base + DAC_O_CTL) = (HWREGH(base + DAC_O_CTL) &
                                ~DAC_CTL_MODE) | (uint16_t)mode;
}

//*****************************************************************************
//
//! Sets the DAC Load Mode
//!
//! \param base is the DAC module base address
//! \param mode is the selected load mode
//!
//! This function sets the DAC load mode.
//!
//! The \e mode parameter can have one of two values:
//! - \b DAC_LOAD_SYSCLK   - Load on next SYSCLK
//! - \b DAC_LOAD_PWMSYNC  - Load on next PWMSYNC specified by SYNCSEL
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline void
DAC_setLoadMode(uint32_t base, DAC_LoadMode mode)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));

    //
    // Set the load mode
    //

    HWREGH(base + DAC_O_CTL) = (HWREGH(base + DAC_O_CTL) &
                                ~DAC_CTL_LOADMODE) | (uint16_t)mode;
}

//*****************************************************************************
//
//! Sets the DAC PWMSYNC Signal
//!
//! \param base is the DAC module base address
//! \param signal is the selected PWM signal
//!
//! This function sets the DAC PWMSYNC signal.
//!
//! The \e signal parameter must be set to a number that represents the PWM
//! signal that will be set. For instance, passing 2 into \e signal will
//! select PWM sync signal 2.
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline void
DAC_setPWMSyncSignal(uint32_t base, uint16_t pwmSignal)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));
    ASSERT((pwmSignal > 0U) && (pwmSignal < 33U));

    //
    // Set the PWM sync signal
    //

    HWREGH(base + DAC_O_CTL) = (HWREGH(base + DAC_O_CTL) &
                                ~DAC_CTL_SYNCSEL_M) |
                               ((uint16_t)(pwmSignal - 1U) <<
                                DAC_CTL_SYNCSEL_S);
}

//*****************************************************************************
//
//! Get the DAC Active Output Value
//!
//! \param base is the DAC module base address
//!
//! This function gets the DAC active output value.
//!
//! \return Returns the DAC active output value.
//
//*****************************************************************************
__attribute__((always_inline))
static inline uint16_t
DAC_getActiveValue(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));

    //
    // Get the active value
    //
    return(HWREGH(base + DAC_O_VALA) & DAC_VALA_DACVALA_M);
}

//*****************************************************************************
//
//! Set the DAC Shadow Output Value
//!
//! \param base is the DAC module base address
//! \param value is the 12-bit code to be loaded into the active value register
//!
//! This function sets the DAC shadow output value.
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline void
DAC_setShadowValue(uint32_t base, uint16_t value)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));
    ASSERT(value <= DAC_VALS_DACVALS_M);

    //
    // Set the shadow value
    //
    HWREGH(base + DAC_O_VALS) = (HWREGH(base + DAC_O_VALS) &
                                 ~DAC_VALS_DACVALS_M) |
                                (value & DAC_VALS_DACVALS_M);
}

//*****************************************************************************
//
//! Get the DAC Shadow Output Value
//!
//! \param base is the DAC module base address
//!
//! This function gets the DAC shadow output value.
//!
//! \return Returns the DAC shadow output value.
//
//*****************************************************************************
__attribute__((always_inline))
static inline uint16_t
DAC_getShadowValue(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));

    //
    // Get the shadow value
    //
    return(HWREGH(base + DAC_O_VALS) & DAC_VALS_DACVALS_M);
}

//*****************************************************************************
//
//! Enable the DAC Output
//!
//! \param base is the DAC module base address
//!
//! This function enables the DAC output.
//!
//! \note A delay is required after enabling the DAC. Further details
//! regarding the exact delay time length can be found in the device datasheet.
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline void
DAC_enableOutput(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));

    //
    // Enable the output
    //

    HWREGH(base + DAC_O_OUTEN) |= DAC_OUTEN_DACOUTEN;
}

//*****************************************************************************
//
//! Disable the DAC Output
//!
//! \param base is the DAC module base address
//!
//! This function disables the DAC output.
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline void
DAC_disableOutput(uint32_t base)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));

    //
    // Disable the output
    //

    HWREGH(base + DAC_O_OUTEN) &= ~DAC_OUTEN_DACOUTEN;
}

//*****************************************************************************
//
//! Set DAC Offset Trim
//!
//! \param base is the DAC module base address
//! \param offset is the specified value for the offset trim
//!
//! This function sets the DAC offset trim. The \e offset value should be a
//! signed number in the range of -128 to 127.
//!
//! \note The offset should not be modified unless specifically indicated by
//! TI Errata or other documentation. Modifying the offset value could cause
//! this module to operate outside of the datasheet specifications.
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline void
DAC_setOffsetTrim(uint32_t base, int16_t offset)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));
    ASSERT((offset > -129) && (offset < 128));

    //
    // Set the offset trim value
    //

    HWREGH(base + DAC_O_TRIM) = (HWREGH(base + DAC_O_TRIM) &
                                 ~DAC_TRIM_OFFSET_TRIM_M) | (uint16_t)offset;
}

//*****************************************************************************
//
//! Get DAC Offset Trim
//!
//! \param base is the DAC module base address
//!
//! This function gets the DAC offset trim value.
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline int16_t
DAC_getOffsetTrim(uint32_t base)
{
    uint16_t value;

    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));

    //
    // Get the sign-extended offset trim value
    //
    value = (HWREGH(base + DAC_O_TRIM) & DAC_TRIM_OFFSET_TRIM_M);
    value = ((value & (uint16_t)DAC_REG_BYTE_MASK) ^ 0x80U) -
            0x80U;

    return((int16_t)value);
}

//*****************************************************************************
//
//! Lock write-access to DAC Register
//!
//! \param base is the DAC module base address
//! \param reg is the selected DAC registers
//!
//! This function locks the write-access to the specified DAC register. Only a
//! system reset can unlock the register once locked.
//!
//! The \e reg parameter can be an ORed combination of any of the following
//! values:
//! - \b DAC_LOCK_CONTROL  - Lock the DAC control register
//! - \b DAC_LOCK_SHADOW   - Lock the DAC shadow value register
//! - \b DAC_LOCK_OUTPUT   - Lock the DAC output enable/disable register
//!
//! \return None.
//
//*****************************************************************************
__attribute__((always_inline))
static inline void
DAC_lockRegister(uint32_t base, uint16_t reg)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));
    ASSERT((reg & ~(DAC_LOCK_CONTROL | DAC_LOCK_SHADOW |
                    DAC_LOCK_OUTPUT)) == 0U);

    //
    // Lock the specified registers
    //

    HWREGH(base + DAC_O_LOCK) |= (DAC_LOCK_KEY | reg);
}

//*****************************************************************************
//
//! Check if DAC Register is locked
//!
//! \param base is the DAC module base address
//! \param reg is the selected DAC register locks to check
//!
//! This function checks if write-access has been locked on the specified DAC
//! register.
//!
//! The \e reg parameter can be an ORed combination of any of the following
//! values:
//! - \b DAC_LOCK_CONTROL  - Lock the DAC control register
//! - \b DAC_LOCK_SHADOW   - Lock the DAC shadow value register
//! - \b DAC_LOCK_OUTPUT   - Lock the DAC output enable/disable register
//!
//! \return Returns \b true if any of the registers specified are locked, and
//! \b false if all specified registers aren't locked.
//
//*****************************************************************************
__attribute__((always_inline))
static inline bool
DAC_isRegisterLocked(uint32_t base, uint16_t reg)
{
    //
    // Check the arguments.
    //
    ASSERT(DAC_isBaseValid(base));
    ASSERT((reg & ~(DAC_LOCK_CONTROL | DAC_LOCK_SHADOW |
                    DAC_LOCK_OUTPUT)) == 0U);

    //
    // Return the lock status on the specified registers
    //
    return(((HWREGH(base + DAC_O_LOCK) & reg) != 0U));
}

//*****************************************************************************
//
//! Tune DAC Offset Trim
//!
//! \param base is the DAC module base address
//! \param referenceVoltage is the reference voltage the DAC
//! module is operating at.
//!
//! This function adjusts/tunes the DAC offset trim. The \e referenceVoltage
//! value should be a floating point number in the range specified in the
//! device data manual.
//!
//! \note Use this function to adjust the DAC offset trim if operating
//! at a reference voltage other than 2.5v. Since this function modifies
//! the DAC offset trim register, it should only be called once after
//! Device_cal. If it is called multiple times after Device_cal, the offset
//! value scaled would be the wrong value.
//!
//! \return None.
//
//*****************************************************************************
extern void
DAC_tuneOffsetTrim(uint32_t base, float32_t referenceVoltage);

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************

//*****************************************************************************
//
// Mark the end of the C bindings section for C++ compilers.
//
//*****************************************************************************
#ifdef __cplusplus
}
#endif

#endif // DAC_H
