//#############################################################################
// $TI Release: MotorControl SDK v0.02.00.00 $
// $Release Date: Fri Jun  8 14:48:41 CDT 2018 $
// $Copyright:
// Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
//   Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// 
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the
//   distribution.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//#############################################################################

#ifndef _HAL_H_
#define _HAL_H_

//! \file   solutions/drv8301_hc_c2_kit/f28004x/drivers/hal.h
//! \brief  Contains public interface to various functions related
//!         to the HAL object
//!


// **************************************************************************
// the includes


// platforms
#include "hal_obj.h"

#include "libraries/svgen/source/svgen_current.h"

//!
//!
//! \defgroup HAL HAL
//!
//@{


#ifdef __cplusplus
extern "C" {
#endif


// **************************************************************************
// the defines

//! Trip Zones all interrupt
//!
#define EPWM_TZ_INTERRUPT_ALL      EPWM_TZ_INTERRUPT_DCBEVT2 \
                                 + EPWM_TZ_INTERRUPT_DCBEVT1 \
                                 + EPWM_TZ_INTERRUPT_DCAEVT2 \
                                 + EPWM_TZ_INTERRUPT_DCAEVT1 \
                                 + EPWM_TZ_INTERRUPT_OST \
                                 + EPWM_TZ_INTERRUPT_CBC

//! \brief Defines the gpio for start command
//!
#define START_CMD_GPIO            13

//! \brief Defines the gpio for stop command
//!
#define STOP_CMD_GPIO             7

//! \brief Defines the gpio for the enable gate of DRV device
//!
#define DRV83XX_EN_GATE_GPIO     28

//! \brief Defines the PWM deadband falling edge delay count (system clocks)
//!
#define HAL_PWM_DBFED_CNT         20

//! \brief Defines the PWM deadband rising edge delay count (system clocks)
//!
#define HAL_PWM_DBRED_CNT         20

//! \brief Defines the real PWM deadband delay count (system clocks)
//!
#define PM_DRV_PWM_DB_CNT         20


//! \brief Defines the bypassed delay for PWM on/off noise
//!
#define PM_DRV_NOISE_WID_SET      30


//! \brief Defines the function to turn LEDs off
//!
#define HAL_turnLedOff            HAL_setGpioLow

//! \brief Defines the function to turn LEDs on
//!
#define HAL_turnLedOn             HAL_setGpioHigh

//! \brief Defines the function to turn LEDs on
//!
#define HAL_toggleLed             HAL_toggleGpio

// **************************************************************************
// the typedefs

//! \brief Enumeration for the LED numbers
//!
typedef enum
{
  HAL_Gpio_LED1 = 31,  //!< GPIO pin number for ControlCARD LED 2
  HAL_Gpio_LED2 = 34   //!< GPIO pin number for ControlCARD LED 3
} HAL_LedNumber_e;

//! \brief Enumeration for the sensor types
//!
typedef enum
{
  HAL_SensorType_Current = 0,  //!< Enumeration for current sensor
  HAL_SensorType_Voltage = 1   //!< Enumeration for voltage sensor
} HAL_SensorType_e;

//! \brief Enumeration for the QEP setup
//!
typedef enum
{
  HAL_Qep_QEP1=0,  //!< Select QEP1
  HAL_Qep_QEP2=1   //!< Select QEP2
} HAL_QepSelect_e;



// **************************************************************************
// the globals

extern interrupt void mainISR(void);
extern interrupt void mainM2ISR(void);
extern interrupt void mainPfcISR(void);

// CLA Tasks
extern interrupt void task_initModules(void);
extern interrupt void task_mainISR(void);
extern interrupt void task_mainM2ISR(void);
extern interrupt void task_mainPfcISR(void);
extern interrupt void task_mainLoop(void);
extern interrupt void cla1Task4(void);
extern interrupt void cla1Task5(void);
extern interrupt void cla1Task6(void);
extern interrupt void cla1Task7(void);
extern interrupt void cla1Task8(void);
extern interrupt void cla_EST_run_BackgroundTask(void);
// **************************************************************************
// the function prototypes

//! \brief     Acknowledges an interrupt from the ADC so that another ADC interrupt can 
//!            happen again.
//! \param[in] handle     The hardware abstraction layer (HAL) handle
//! \param[in] adcIntNum  The interrupt number
static inline void HAL_acqAdcInt(HAL_Handle handle,const ADC_IntNumber adcIntNum)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  // clear the ADC interrupt flag
  // RB2
  ADC_clearInterruptStatus(obj->adcHandle[1], adcIntNum);         // ADCB

  // Acknowledge interrupt from PIE group 1
  Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);

  return;
} // end of HAL_acqAdcInt() function

//! \brief      Executes calibration routines
//! \details    Values for offset and gain are programmed into OTP memory at
//!             the TI factory.  This calls and internal function that programs
//!             these offsets and gains into the ADC registers.
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_cal(HAL_Handle handle);

//! \brief      Forces a CLA task
//! \param[in]  handle     The hardware abstraction layer (HAL) handle
//! \param[in]  taskFlags  The task to be forced
static inline void
HAL_CLA_forceTasks(HAL_Handle handle, const uint16_t taskFlags)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  // force task
  CLA_forceTasks(obj->claHandle, taskFlags);

  return;
} // end of HAL_CLA_forceTasks() function

//! \brief      Gets the run status of the specified CLA task
//! \param[in]  handle      The hardware abstraction layer (HAL) handle
//! \param[in]  taskNumber  The task to check the run status on
static inline bool HAL_CLA_getTaskRunStatus(HAL_Handle handle, const CLA_TaskNumber taskNumber)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  // return the run status of the specified task
  return(CLA_getTaskRunStatus(obj->claHandle, taskNumber));
} // end of HAL_CLA_getTaskRunStatus() function

//! \brief      Disables global interrupts
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_disableGlobalInts(HAL_Handle handle);

//! \brief      Enables the ADC interrupts
//! \details    Enables the ADC interrupt in the PIE, and CPU.  Enables the 
//!             interrupt to be sent from the ADC peripheral.
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_enableAdcInts(HAL_Handle handle);

//! \brief      Enables the ADC interrupts without CPU interrupts
//! \details    Enables the ADC interrupts to only trigger CLA, and without
//!             interrupting the CPU
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_enableAdcIntsToTriggerCLA(HAL_Handle handle);

//! \brief      Enables the debug interrupt
//! \details    The debug interrupt is used for the real-time debugger.  It is
//!             not needed if the real-time debugger is not used.  Clears
//!             bit 1 of ST1.
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_enableDebugInt(HAL_Handle handle);

//! \brief      Enables the 8301 device
//! \details    Provides the correct timing to enable the drv8301
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_enableDrv(HAL_Handle handle);

//! \brief     Enables global interrupts
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_enableGlobalInts(HAL_Handle handle);

//! \brief     Gets the current scale factor
//! \param[in] handle  The hardware abstraction layer (HAL) handle
//! \return    The current scale factor
static inline float_t HAL_getCurrentScaleFactor(HAL_Handle handle)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  return(obj->current_sf);
} // end of HAL_getCurrentScaleFactor() function

//! \brief     Gets the PWM duty cycle times
//! \param[in] handle       The hardware abstraction layer (HAL) handle
//! \param[in] pDutyCycles  A pointer to memory for the duty cycle durations
static inline void HAL_getDutyCycles(HAL_Handle handle,uint16_t *pDutyCycles)
{
    HAL_Obj *obj = (HAL_Obj *)handle;

    pDutyCycles[0] = EPWM_getCounterCompareValue(obj->pwmHandle[0],
                                                 EPWM_COUNTER_COMPARE_A);
    pDutyCycles[1] = EPWM_getCounterCompareValue(obj->pwmHandle[1],
                                                 EPWM_COUNTER_COMPARE_A);
    pDutyCycles[2] = EPWM_getCounterCompareValue(obj->pwmHandle[2],
                                                 EPWM_COUNTER_COMPARE_A);
    return;
} // end of HAL_getDutyCycles() function


//! \brief     Gets the number of current sensors
//! \param[in] handle  The hardware abstraction layer (HAL) handle
//! \return    The number of current sensors
static inline uint_least8_t HAL_getNumCurrentSensors(HAL_Handle handle)
{
  HAL_Obj *obj = (HAL_Obj *)handle;
  

  return(obj->numCurrentSensors);
} // end of HAL_getNumCurrentSensors() function


//! \brief     Gets the number of voltage sensors
//! \param[in] handle  The hardware abstraction layer (HAL) handle
//! \return    The number of voltage sensors
static inline uint_least8_t HAL_getNumVoltageSensors(HAL_Handle handle)
{
  HAL_Obj *obj = (HAL_Obj *)handle;
  

  return(obj->numVoltageSensors);
} // end of HAL_getNumVoltageSensors() function

//! \brief     Gets the pwm enable status
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
//! \return    The pwm enable
static inline bool HAL_getPwmEnableStatus(HAL_Handle handle)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  return(obj->Flag_enablePwm);
} // end of HAL_getPwmStatus() function

//! \brief     Gets the voltage scale factor
//! \param[in] handle  The hardware abstraction layer (HAL) handle
//! \return    The voltage scale factor
static inline float_t HAL_getVoltageScaleFactor(HAL_Handle handle)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  return(obj->voltage_sf);
} // end of HAL_getVoltageScaleFactor() function

//! \brief      Configures the fault protection logic
//! \details    Sets up the trip zone inputs so that when a comparator
//!             signal from outside the micro-controller trips a fault,
//!             the EPWM peripheral blocks will force the
//!             power switches into a high impedance state.
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupFaults(HAL_Handle handle);

//! \brief      Initializes the hardware abstraction layer (HAL) object
//! \details    Initializes all handles to the microcontroller peripherals.
//!             Returns a handle to the HAL object.
//! \param[in]  pMemory   A pointer to the memory for the hardware abstraction layer object
//! \param[in]  numBytes  The number of bytes allocated for the hardware abstraction layer object, bytes
//! \return     The hardware abstraction layer (HAL) object handle
extern HAL_Handle HAL_init(void *pMemory,const size_t numBytes);

//! \brief      Initializes the interrupt vector table
//! \details    Points the ISR to the function mainISR.
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
static inline void HAL_initIntVectorTable(HAL_Handle handle)
 {

    Interrupt_register(INT_ADCB1, &mainISR);

    return;
 } // end of HAL_initIntVectorTable() function

//! \brief      Reads the ADC data
//! \details    Reads in the ADC result registers and scales the values
//!             according to the settings in user.h.  The structure gAdcData
//!             holds three phase voltages, three line currents, and one DC bus
//!             voltage.
//! \param[in]  handle    The hardware abstraction layer (HAL) handle
//! \param[in]  pAdcData  A pointer to the ADC data buffer
// TODO:
static inline void HAL_readAdcDataWithOffsets(HAL_Handle handle,HAL_AdcData_t *pAdcData)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  float_t value;

  float_t current_sf = HAL_getCurrentScaleFactor(handle);
  float_t voltage_sf = HAL_getVoltageScaleFactor(handle);

  // convert phase A current        ->RA0/A6
  value = (float_t)ADC_readResult(obj->adcResult[0], ADC_SOC_NUMBER0);
  pAdcData->I_A.value[0] = value * current_sf;

  // convert phase B current        ->RC0/C1
  value = (float_t)ADC_readResult(obj->adcResult[2], ADC_SOC_NUMBER0);
  pAdcData->I_A.value[1] = value * current_sf;

  // convert phase C current        ->RB0/B15
  value = (float_t)ADC_readResult(obj->adcResult[1], ADC_SOC_NUMBER0);
  pAdcData->I_A.value[2] = value * current_sf;

  // convert phase A voltage        ->RC1/C2
  value = (float_t)ADC_readResult(obj->adcResult[2], ADC_SOC_NUMBER1);
  pAdcData->V_V.value[0] = value * voltage_sf;

  // convert phase B voltage        ->RA1/A9
  value = (float_t)ADC_readResult(obj->adcResult[0], ADC_SOC_NUMBER1);
  pAdcData->V_V.value[1] = value * voltage_sf;

  // convert phase C voltage        ->RB1/B4
  value = (float_t)ADC_readResult(obj->adcResult[1], ADC_SOC_NUMBER1);
  pAdcData->V_V.value[2] = value * voltage_sf;

  // convert dcBus voltage          ->RB2/B2
  value = (float_t)ADC_readResult(obj->adcResult[1], ADC_SOC_NUMBER2);
  pAdcData->dcBus_V = value * voltage_sf;

  pAdcData->Tspeed = (float_t)ADC_readResult(obj->adcResult[2], ADC_SOC_NUMBER2);
  return;
} // end of HAL_readAdcDataWithOffsets() function

//! \brief      Reads the ADC data
//! \details    Reads in the ADC result registers and scales the values
//!             according to the settings in user.h.  The structure gAdcData
//!             holds three phase voltages, three line currents, and one DC bus
//!             voltage.
//! \param[in]  handle    The hardware abstraction layer (HAL) handle
//! \param[in]  pAdcData  A pointer to the ADC data buffer
// TODO:
static inline void HAL_readAdcDataWithoutOffsets(HAL_Handle handle,HAL_AdcData_t *pAdcData)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  float_t value;

  float_t current_sf = -HAL_getCurrentScaleFactor(handle);
  float_t voltage_sf = HAL_getVoltageScaleFactor(handle);

  // convert phase A current
  value = (float_t)ADC_readResult(obj->adcResult[1], ADC_SOC_NUMBER0);
  pAdcData->I_A.value[0] = value * current_sf;

  // convert phase B current
  value = (float_t)ADC_readResult(obj->adcResult[2], ADC_SOC_NUMBER1);
  pAdcData->I_A.value[1] = value * current_sf;

  // convert phase C current
  value = (float_t)ADC_readResult(obj->adcResult[0], ADC_SOC_NUMBER2);
  pAdcData->I_A.value[2] = value * current_sf;

  // convert phase A voltage
  value = (float_t)ADC_readResult(obj->adcResult[2], ADC_SOC_NUMBER3);
  pAdcData->V_V.value[0] = value * voltage_sf;

  // convert phase B voltage
  value = (float_t)ADC_readResult(obj->adcResult[0], ADC_SOC_NUMBER4);
  pAdcData->V_V.value[1] = value * voltage_sf;

  // convert phase C voltage
  value = (float_t)ADC_readResult(obj->adcResult[1], ADC_SOC_NUMBER5);
  pAdcData->V_V.value[2] = value * voltage_sf;

  // convert dcBus voltage
  value = (float_t)ADC_readResult(obj->adcResult[1], ADC_SOC_NUMBER6);
  pAdcData->dcBus_V = value * voltage_sf;

  return;
} // end of HAL_readAdcDataWithOffsets() function

//! \brief     Reads the timer count
//! \param[in] handle       The hardware abstraction layer (HAL) handle
//! \param[in] timerNumber  The timer number, 0,1 or 2
//! \return    The timer count
static inline uint32_t HAL_readTimerCnt(HAL_Handle handle,const uint_least8_t timerNumber)
{
    HAL_Obj *obj = (HAL_Obj *)handle;

    uint32_t timerCnt = CPUTimer_getTimerCount(obj->timerHandle[timerNumber]);

    return(timerCnt);
} // end of HAL_readTimerCnt() function

//! \brief     Sets the GPIO pin high
//! \param[in] handle      The hardware abstraction layer (HAL) handle
//! \param[in] gpioNumber  The GPIO number
static inline void HAL_setGpioHigh(HAL_Handle handle,const uint32_t gpioNumber)
{

  // set GPIO high
  GPIO_writePin(gpioNumber, 1);

  return;
} // end of HAL_setGpioHigh() function


//! \brief     Read the GPIO pin
//! \param[in] handle      The hardware abstraction layer (HAL) handle
//! \param[in] gpioNumber  The GPIO number
//! \return    The GPIO pin
static inline uint32_t HAL_ReadGpioData(HAL_Handle handle,const uint32_t gpioNumber)
{
  uint32_t GpioPinData;

  // set GPIO high
  GpioPinData = GPIO_readPin(gpioNumber);

  return(GpioPinData);
} // end of HAL_ReadGpioData() function


//! \brief     Sets the GPIO pin low
//! \param[in] handle      The hardware abstraction layer (HAL) handle
//! \param[in] gpioNumber  The GPIO number
static inline void HAL_setGpioLow(HAL_Handle handle,const uint32_t gpioNumber)
{

  // set GPIO low
  GPIO_writePin(gpioNumber, 0);

  return;
} // end of HAL_setGpioLow() function

//! \brief     Sets the number of voltage sensors
//! \param[in] handle             The hardware abstraction layer (HAL) handle
//! \param[in] numVoltageSensors  The number of voltage sensors
static inline void HAL_setNumVoltageSensors(HAL_Handle handle,const uint_least8_t numVoltageSensors)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  obj->numVoltageSensors = numVoltageSensors;

  return;
} // end of HAL_setNumVoltageSensors() function

//! \brief     Sets the number of current sensors
//! \param[in] handle             The hardware abstraction layer (HAL) handle
//! \param[in] numCurrentSensors  The number of current sensors
static inline void HAL_setNumCurrentSensors(HAL_Handle handle,const uint_least8_t numCurrentSensors)
{
  HAL_Obj *obj = (HAL_Obj *)handle;


  obj->numCurrentSensors = numCurrentSensors;

  return;
} // end of HAL_setNumCurrentSensors() function

//! \brief      Sets the hardware abstraction layer parameters
//! \details    Sets up the microcontroller peripherals.  Creates all of the scale
//!             factors for the ADC voltage and current conversions.  Sets the initial
//!             offset values for voltage and current measurements.
//! \param[in]  handle       The hardware abstraction layer (HAL) handle
extern void HAL_setParams(HAL_Handle handle);


//! \brief      Sets up the ADCs (Analog to Digital Converters)
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupAdcs(HAL_Handle handle);

//! \brief      Sets up the ADCs (Analog to Digital Converters)
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_adcZeroOffsetCalibration(uint32_t base);


//! \brief      Sets up the PGAs (Programmable Gain Amplifiers)
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupPGAs(HAL_Handle handle);


//! \brief      Sets up the CMPSSs (Comparator Subsystems)
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupCMPSSs(HAL_Handle handle);


//! \brief      Sets up the DACs (Buffered Digital-to-Analog Converter)
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupDACs(HAL_Handle handle);


//! \brief      Sets up the clocks
//! \details    Sets up the micro-controller's main oscillator
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupClks(HAL_Handle handle);


//! \brief     Sets up the faults
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupFaults(HAL_Handle handle);

//! \brief     Sets up the GATE object
//! \param[in] handle       The hardware abstraction layer (HAL) handle
extern void HAL_setupGate(HAL_Handle handle);

//! \brief     Sets up the GPIO (General Purpose I/O) pins
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupGpios(HAL_Handle handle);


//! \brief     Sets up the FLASH.
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupFlash(HAL_Handle handle);

//! \brief     Sets up the CLA
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupCLA(HAL_Handle handle);

//! \brief     Sets up the peripheral clocks
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupPeripheralClks(HAL_Handle handle);


//! \brief     Sets up the PIE (Peripheral Interrupt Expansion)
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupPie(HAL_Handle handle);

//! \brief     Sets up the PWMs (Pulse Width Modulators)
//! \param[in] handle          The hardware abstraction layer (HAL) handle
//! \param[in] systemFreq_MHz  The system frequency, MHz
extern void HAL_setupPwmDacs(HAL_Handle handle,
                   const float_t systemFreq_MHz);

//! \brief     Sets up the QEP peripheral
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupQEP(HAL_Handle handle,HAL_QepSelect_e qep);

//! \brief     Sets up the SCIA
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupSciA(HAL_Handle handle);


//! \brief     Sets up the SPIA
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupSpiA(HAL_Handle handle);


//! \brief     Sets up the SPIB
//! \param[in] handle  The hardware abstraction layer (HAL) handle
extern void HAL_setupSpiB(HAL_Handle handle);


//! \brief     Sets up the timers
//! \param[in] handle          The hardware abstraction layer (HAL) handle
//! \param[in] systemFreq_MHz  The system frequency, MHz
extern void HAL_setupTimers(HAL_Handle handle,const float_t systemFreq_MHz);


//! \brief     Sets up the timers
//! \param[in] handle          The hardware abstraction layer (HAL) handle
//! \param[in] CPUTimerNumber  The CPU timer number
bool HAL_getTimerStatus(HAL_Handle halHandle, const uint16_t CPUTimerNumber);


//! \brief     Sets up the timers
//! \param[in] handle          The hardware abstraction layer (HAL) handle
//! \param[in] CPUTimerNumber  The CPU timer number
void HAL_clearTimerFlag(HAL_Handle halHandle, const uint16_t CPUTimerNumber);


//! \brief     Sets up the DMA for datalog
//! \param[in] handle          The hardware abstraction layer (HAL) handle
//! \param[in] DMAChNumber     The DMC Channel Number
//! \param[in] dlogDestAddr    The Datalog buffer dest address
//! \param[in] dlogSrcAddr     The Datalog buffer src address
void HAL_setupDlogDMA(HAL_Handle handle, const uint16_t DMAChNumber,
                     const void *dlogDestAddr, const void *dlogSrcAddr);

//! \brief     reset the DMA for datalog
static inline void HAL_resetDlogDMA(void)
{
    DMA_initController();
    return;
}

//! \brief     Force trig the DMA channel for datalog
//! \param[in] handle          The hardware abstraction layer (HAL) handle
//! \param[in] DMAChNumber     The DMC Channel Number
static inline void HAL_forceTrigDlogDMA(HAL_Handle handle, const uint16_t DMAChannel)
{
    HAL_Obj *obj = (HAL_Obj *)handle;

    DMA_startChannel(obj->dmaChHandle[DMAChannel]);
    DMA_forceTrigger(obj->dmaChHandle[DMAChannel]);

    return;
} // end of HAL_forceTrigDlogDMA() function

//! \brief     Toggles the GPIO pin
//! \param[in] handle      The hardware abstraction layer (HAL) handle
//! \param[in] gpioNumber  The GPIO number
static inline void HAL_toggleGpio(HAL_Handle handle,const uint32_t gpioNumber)
{

    // set GPIO high
    GPIO_togglePin(gpioNumber);

    return;
} // end of HAL_toggleGpio() function

//! \brief     Writes DAC data to the PWM comparators for DAC (digital-to-analog conversion) output
//! \param[in] handle    The hardware abstraction layer (HAL) handle
//! \param[in] pPwmDacData  The pointer to the DAC data
static inline void HAL_writePwmDacData(HAL_Handle handle, HAL_PwmDacData_t *pPwmDacData)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  // convert values from _IQ to _IQ15
  uint_least8_t cnt;
  float_t period;
  float_t dacData_sat_dc;
  float_t value;

  period = (float_t)pPwmDacData->PeriodMax;

  for(cnt=0;cnt<4;cnt++)
    {
      dacData_sat_dc = pPwmDacData->value[cnt]*pPwmDacData->gain[cnt] + pPwmDacData->offset[cnt];
      value = dacData_sat_dc*period;
      pPwmDacData->cmpValue[cnt] = (int16_t)MATH_sat(value, period, 0);
    }

  // write the DAC data
  if(obj->pwmDacHandle[PWMDAC_Number_1])
  {
      // write the PWM data value, EPWM8A
      EPWM_setCounterCompareValue(obj->pwmDacHandle[PWMDAC_Number_1],
                                  EPWM_COUNTER_COMPARE_A,
                                  pPwmDacData->cmpValue[0]);
  }

  if(obj->pwmDacHandle[PWMDAC_Number_2])
  {
      // write the PWM data value, EPWM8B
      EPWM_setCounterCompareValue(obj->pwmDacHandle[PWMDAC_Number_2],
                                  EPWM_COUNTER_COMPARE_B,
                                  pPwmDacData->cmpValue[1]);
  }

  if(obj->pwmDacHandle[PWMDAC_Number_3])
  {
      // write the PWM data value, EPWM7A
      EPWM_setCounterCompareValue(obj->pwmDacHandle[PWMDAC_Number_3],
                                  EPWM_COUNTER_COMPARE_A,
                                  pPwmDacData->cmpValue[2]);
  }


  if(obj->pwmDacHandle[PWMDAC_Number_4])
  {
      // write the PWM data value, EPWM4A
      EPWM_setCounterCompareValue(obj->pwmDacHandle[PWMDAC_Number_4],
                                  EPWM_COUNTER_COMPARE_A,
                                  pPwmDacData->cmpValue[3]);
  }

  return;
} // end of HAL_writePwmDacData() function


//! \brief     Writes DAC data to the PWM comparators for DAC (digital-to-analog conversion) output
//! \param[in] handle    The hardware abstraction layer (HAL) handle
//! \param[in] pPwmDacData  The pointer to the DAC data
void HAL_setPwmDacParameters(HAL_Handle handle, HAL_PwmDacData_t *pPwmDacData);

//! \brief
//! \param[in]
//! \param[in]
void HAL_ClearDataRAM(void *pMemory, uint16_t lengthMemory);

//TODO:
//! \brief     Reads PWM period register
//! \param[in] handle     The hardware abstraction layer (HAL) handle
//! \param[in] pwmNumber  The PWM number
//! \return    The PWM period value
static inline uint16_t HAL_readPwmPeriod(HAL_Handle handle,const uint16_t pwmNumber)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  // the period value to be returned
  uint16_t pwmPeriodValue;

  pwmPeriodValue = EPWM_getTimeBasePeriod(obj->pwmHandle[pwmNumber]);

  return(pwmPeriodValue);
} // end of HAL_readPwmPeriod() function


//! \brief     Writes PWM data to the PWM comparators for motor control
//! \param[in] handle    The hardware abstraction layer (HAL) handle
//! \param[in] pPwmData  The pointer to the PWM data
static inline void HAL_writePwmData(HAL_Handle handle,const HAL_PwmData_t *pPwmData)
{
  HAL_Obj *obj = (HAL_Obj *)handle;
  uint_least8_t pwmCnt;

  for(pwmCnt=0;pwmCnt<3;pwmCnt++)
    {
      // compute the value
      float_t period = (float_t)(EPWM_getTimeBasePeriod(obj->pwmHandle[pwmCnt]));
      float_t V_pu = -pPwmData->Vabc_pu.value[pwmCnt];
      float_t V_sat_pu = MATH_sat(V_pu,0.5,-0.5);
      float_t V_sat_dc_pu = V_sat_pu + 0.5;
      int16_t pwmValue  = (int16_t)(V_sat_dc_pu * period);

      // write the PWM data value
      EPWM_setCounterCompareValue(obj->pwmHandle[pwmCnt],
                                  EPWM_COUNTER_COMPARE_A,
                                  pwmValue);
    }

  return;
} // end of HAL_writePwmData() function

//! \brief      Enables the PWM devices
//! \details    Turns on the outputs of the EPWM peripheral which will allow
//!             the power switches to be controlled.
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
static inline void HAL_enablePwm(HAL_Handle handle)
{
    HAL_Obj *obj = (HAL_Obj *)handle;

    EPWM_clearTripZoneFlag(obj->pwmHandle[0], EPWM_TZ_INTERRUPT_ALL);
    EPWM_clearTripZoneFlag(obj->pwmHandle[1], EPWM_TZ_INTERRUPT_ALL);
    EPWM_clearTripZoneFlag(obj->pwmHandle[2], EPWM_TZ_INTERRUPT_ALL);

    obj->Flag_enablePwm = true;

    return;
} // end of HAL_enablePwm() function

//! \brief      Disables the PWM device
//! \details    Turns off the outputs of the EPWM peripherals which will put
//!             the power switches into a high impedance state.
//! \param[in]  handle  The hardware abstraction layer (HAL) handle
static inline void HAL_disablePwm(HAL_Handle handle)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  EPWM_forceTripZoneEvent(obj->pwmHandle[0], EPWM_TZ_FORCE_EVENT_OST);
  EPWM_forceTripZoneEvent(obj->pwmHandle[1], EPWM_TZ_FORCE_EVENT_OST);
  EPWM_forceTripZoneEvent(obj->pwmHandle[2], EPWM_TZ_FORCE_EVENT_OST);

  obj->Flag_enablePwm = false;

  return;
} // end of HAL_disablePwm() function


//! \brief     Sets up the PWMs (Pulse Width Modulators)
//! \param[in] handle          The hardware abstraction layer (HAL) handle
//! \param[in] systemFreq_MHz  The system frequency, MHz
//! \param[in] pwmPeriod_usec  The PWM period, usec
//! \param[in] numPwmTicksPerIsrTick  The number of PWM clock ticks per ISR clock tick
extern void HAL_setupPwms(HAL_Handle handle,
                          const float_t systemFreq_MHz,
                          const float_t pwmPeriod_usec,
                          const uint_least16_t numPwmTicksPerIsrTick);

//! \brief     Writes data to the driver
//! \param[in] handle         The hardware abstraction layer (HAL) handle
//! \param[in] Spi_8301_Vars  SPI variables
void HAL_writeDrvData(HAL_Handle handle, DRV_SPI_8301_Vars_t *Spi_8301_Vars);


//! \brief     Reads data from the driver
//! \param[in] handle         The hardware abstraction layer (HAL) handle
//! \param[in] Spi_8301_Vars  SPI variables
void HAL_readDrvData(HAL_Handle handle, DRV_SPI_8301_Vars_t *Spi_8301_Vars);

//! \brief     Sets up the SPI interface for the driver
//! \param[in] handle         The hardware abstraction layer (HAL) handle
//! \param[in] Spi_8301_Vars  SPI variables
extern void HAL_setupDrvSpi(HAL_Handle handle, DRV_SPI_8301_Vars_t *Spi_8301_Vars);

//! \brief     Sets the current scale factor in the hal
//! \param[in] handle      The hardware abstraction layer (HAL) handle
//! \param[in] current_sf  The current scale factor
static inline void HAL_setCurrentScaleFactor(HAL_Handle handle,const float_t current_sf)
{
  HAL_Obj *obj = (HAL_Obj *)handle;


  obj->current_sf = current_sf;

  return;
} // end of HAL_setCurrentScaleFactor() function

//! \brief     Sets the voltage scale factor in the hal
//! \param[in] handle      The hardware abstraction layer (HAL) handle
//! \param[in] voltage_sf  The voltage scale factor
static inline void HAL_setVoltageScaleFactor(HAL_Handle handle,const float_t voltage_sf)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  obj->voltage_sf = voltage_sf;

  return;
} // end of HAL_setVoltageScaleFactor() function


static inline uint16_t HAL_getTripFaults(HAL_Handle handle)
{
    HAL_Obj *obj = (HAL_Obj *)handle;
    uint16_t TripFault = 0;

//    TripFault = EPWM_getTripZoneFlag(obj->pwmHandle[0])
//              | EPWM_getTripZoneFlag(obj->pwmHandle[1])
//              | EPWM_getTripZoneFlag(obj->pwmHandle[2]);

    TripFault = (EPWM_getTripZoneFlagStatus(obj->pwmHandle[0]) & (EPWM_TZ_FLAG_OST | EPWM_TZ_FLAG_DCAEVT1 | EPWM_TZ_FLAG_DCAEVT2))
              | (EPWM_getTripZoneFlagStatus(obj->pwmHandle[1]) & (EPWM_TZ_FLAG_OST | EPWM_TZ_FLAG_DCAEVT1 | EPWM_TZ_FLAG_DCAEVT2))
              | (EPWM_getTripZoneFlagStatus(obj->pwmHandle[2]) & (EPWM_TZ_FLAG_OST | EPWM_TZ_FLAG_DCAEVT1 | EPWM_TZ_FLAG_DCAEVT2));

    return(TripFault);
}

//! \brief     Set trigger point in the middle of the low side pulse
//! \param[in] handle    The hardware abstraction layer (HAL) handle
//! \param[in] pPwmData  The pointer to the PWM data
static inline void HAL_setOvmPwm(HAL_Handle handle, HAL_PwmData_t *pPwmData)
{
    HAL_Obj *obj = (HAL_Obj *)handle;

    pPwmData->period = EPWM_getTimeBasePeriod(obj->pwmHandle[0]);
    pPwmData->deadBand[0] = PM_DRV_PWM_DB_CNT;
    pPwmData->deadBand[1] = PM_DRV_PWM_DB_CNT;
    pPwmData->deadBand[2] = PM_DRV_PWM_DB_CNT;

    pPwmData->noiseWid = PM_DRV_NOISE_WID_SET;
}



//! \brief     Set trigger point in the middle of the low side pulse
//! \param[in] handle    The hardware abstraction layer (HAL) handle
//! \param[in] pPwmData  The pointer to the PWM data
//! \param[in] ignoreShunt  The low side shunt that should be ignored
//! \param[in] midVolShunt  The middle length of output voltage
static inline void HAL_setTrigger(HAL_Handle handle, HAL_PwmData_t *pPwmData,
                                  const SVGENCURRENT_IgnoreShunt_e ignoreShunt,
                                  const SVGENCURRENT_VmidShunt_e midVolShunt)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  uint16_t pwmCMPA[3];

  pwmCMPA[0] = EPWM_getCounterCompareValue(obj->pwmHandle[0], EPWM_COUNTER_COMPARE_A);
  pwmCMPA[1] = EPWM_getCounterCompareValue(obj->pwmHandle[1], EPWM_COUNTER_COMPARE_A);
  pwmCMPA[2] = EPWM_getCounterCompareValue(obj->pwmHandle[2], EPWM_COUNTER_COMPARE_A);

  int16_t pwmNum = 0;
  int16_t pwmSocCMP = 1;

  if(ignoreShunt == use_all)
  {
      pwmSocCMP = 2;

      // write the PWM data value  for ADC trigger
      EPWM_setADCTriggerSource(obj->pwmHandle[0],
                               EPWM_SOC_A,
                               EPWM_SOC_TBCTR_D_CMPC);
  }
  else
  {
      if(midVolShunt == Vmid_a)
      {
          pwmNum = 0;
      }
      else if(midVolShunt == Vmid_b)
      {
          pwmNum = 1;
      }
      else      // (midVolShunt == Vmid_b)
      {
          pwmNum = 2;
      }

      pwmSocCMP = pwmCMPA[pwmNum] - pPwmData->deadBand[pwmNum] - pPwmData->noiseWid;

      if(pwmSocCMP < 0)
      {
          pwmSocCMP = -pwmSocCMP;

          // write the PWM data value  for ADC trigger
          EPWM_setADCTriggerSource(obj->pwmHandle[0],
                                   EPWM_SOC_A,
                                   EPWM_SOC_TBCTR_U_CMPC);
      }
      else
      {
          // write the PWM data value  for ADC trigger
          EPWM_setADCTriggerSource(obj->pwmHandle[0],
                                   EPWM_SOC_A,
                                   EPWM_SOC_TBCTR_D_CMPC);
      }

  }

  //
  pPwmData->cmpSoc = pwmSocCMP;

  // write the PWM data value  for ADC trigger
  EPWM_setCounterCompareValue(obj->pwmHandle[0],
                              EPWM_COUNTER_COMPARE_C,
                              pwmSocCMP);
  return;
} // end of HAL_setTrigger() function


#ifdef __cplusplus
}
#endif // extern "C"

//@}  // ingroup


#endif // end of _HAL_H_ definition

