/* ###################################################################
**     This component module is generated by Processor Expert. Do not modify it.
**     Filename    : G4XS1.c
**     CDE edition : Internal
**     Project     : G4XS_K64F_FreeMASTER
**     Processor   : MK64FN1M0VLQ12
**     Component   : Gen4eXtremeSwitch
**     Version     : Component 01.000, Driver 01.00, CPU db: 3.00.000
**     Repository  : My Components
**     Compiler    : GNU C Compiler
**     Date/Time   : 2016-04-07, 10:19, # CodeGen: 4
**     Abstract    :
**
**     Settings    :
**          Component Name                                 : G4XS1
**          SPI Configuration                              : Parallel SPI
**          Global Configuration                           : 
**            RSTB Link                                    : BitIO_LDD
**            RSTB Pin                                     : PTE26/ENET_1588_CLKIN/UART4_CTS_b/RTC_CLKOUT/USB_CLKIN
**            CLK Link                                     : PWM_LDD
**            External Clock Frequency                     : 50000
**            CLK Pin                                      : ADC0_SE15/PTC1/LLWU_P6/SPI0_PCS3/UART1_RTS_b/FTM0_CH0/FB_AD13/I2S0_TXD0
**            Watchdog Timeout                             : 128 ms
**            Direct Input Control                         : Disabled
**            Current, Voltage and Temperature Sensing     : Enabled
**              ADC Link                                   : AD1
**              ADC Conversion Time                        : 4.768372 µs
**              CSNS Function                              : Temperature
**              CSNS Pin                                   : ADC1_SE14/PTB10/SPI1_PCS0/UART3_RX/FB_AD19/FTM0_FLT1
**              CSNS Synchronization                       : Off
**          Devices                                        : 1
**            Device1                                      : 
**              Device Model                               : MC17XSF500
**              SPI Link                                   : SPI_Device
**              SOA Mode                                   : Single read
**              Overtemperature Warning Threshold          : 115 °C
**              HID Selection                              : Disabled
**              OCHI Type                                  : Default
**              Global PWM Duty Cycle                      : 0
**              Channels                                   : 6
**                Output1                                  : Enabled
**                  PWM Output Control                     : 
**                    Global PWM                           : Disabled
**                    Channel Duty Cycle                   : 0
**                    Phase Selection                      : 0
**                    Pulse Skipping                       : Disabled
**                    Slew Rate Prescaler                  : 1
**                    Output Initial State                 : Off
**                  Direct Input Control                   : Disabled
**                  Open Load                              : 
**                    Open Load LED                        : Disabled
**                    OLON Deglitch Time                   : 64 us
**                  Overcurrent                            : 
**                    OCLO Threshold                       : Low
**                    Advanced Current Sensing Mode        : Disabled
**                    Short OCHI                           : Disabled
**                    No OCHI                              : Disabled
**                Output2                                  : Enabled
**                  PWM Output Control                     : 
**                    Global PWM                           : Disabled
**                    Channel Duty Cycle                   : 0
**                    Phase Selection                      : 0
**                    Pulse Skipping                       : Disabled
**                    Slew Rate Prescaler                  : 1
**                    Output Initial State                 : Off
**                  Direct Input Control                   : Disabled
**                  Open Load                              : 
**                    Open Load LED                        : Disabled
**                    OLON Deglitch Time                   : 64 us
**                  Overcurrent                            : 
**                    OCLO Threshold                       : Low
**                    Advanced Current Sensing Mode        : Disabled
**                    Short OCHI                           : Disabled
**                    No OCHI                              : Disabled
**                Output3                                  : Enabled
**                  PWM Output Control                     : 
**                    Global PWM                           : Disabled
**                    Channel Duty Cycle                   : 0
**                    Phase Selection                      : 0
**                    Pulse Skipping                       : Disabled
**                    Slew Rate Prescaler                  : 1
**                    Output Initial State                 : Off
**                  Direct Input Control                   : Disabled
**                  Open Load                              : 
**                    Open Load LED                        : Disabled
**                    OLON Deglitch Time                   : 64 us
**                  Overcurrent                            : 
**                    OCLO Threshold                       : Low
**                    Advanced Current Sensing Mode        : Disabled
**                    Short OCHI                           : Disabled
**                    No OCHI                              : Disabled
**                Output4                                  : Enabled
**                  PWM Output Control                     : 
**                    Global PWM                           : Disabled
**                    Channel Duty Cycle                   : 0
**                    Phase Selection                      : 0
**                    Pulse Skipping                       : Disabled
**                    Slew Rate Prescaler                  : 1
**                    Output Initial State                 : Off
**                  Direct Input Control                   : Disabled
**                  Open Load                              : 
**                    Open Load LED                        : Disabled
**                    OLON Deglitch Time                   : 64 us
**                  Overcurrent                            : 
**                    OCLO Threshold                       : Low
**                    Advanced Current Sensing Mode        : Disabled
**                    Short OCHI                           : Disabled
**                    No OCHI                              : Disabled
**                Output5                                  : Enabled
**                  PWM Output Control                     : 
**                    Global PWM                           : Disabled
**                    Channel Duty Cycle                   : 0
**                    Phase Selection                      : 0
**                    Pulse Skipping                       : Disabled
**                    Slew Rate Prescaler                  : 1
**                    Output Initial State                 : Off
**                  Open Load                              : 
**                    Open Load LED                        : Disabled
**                    OLON Deglitch Time                   : 64 us
**                  Overcurrent                            : 
**                    OCLO Threshold                       : Low
**                    Advanced Current Sensing Mode        : Disabled
**                    Short OCHI                           : Disabled
**                    No OCHI                              : Disabled
**                Output6                                  : Enabled
**                  PWM Output Control                     : 
**                    Global PWM                           : Disabled
**                    Channel Duty Cycle                   : 0
**                    Phase Selection                      : 0
**                    Slew Rate Prescaler                  : 1
**                    Output Initial State                 : Off
**                  Open Load LED                          : Disabled
**                  OLON Deglitch Time                     : 64 us
**                  OCLO Threshold                         : Low
**                  Advanced Current Sensing Mode          : Disabled
**                  Short OCHI                             : Disabled
**                  No OCHI                                : Disabled
**          Auto Initialization                            : yes
**     Contents    :
**         Init                  - TError G4XS1_Init(TUserDataPtr UserDataPtr);
**         GetQuickStatus        - TError G4XS1_GetQuickStatus(TDeviceIdx DeviceIndex,uint16_t *StatusData);
**         GetChannelStatus      - TError G4XS1_GetChannelStatus(TDeviceIdx DeviceIndex,uint16_t *StatusData);
**         GetDeviceStatus       - TError G4XS1_GetDeviceStatus(TDeviceIdx DeviceIndex,uint16_t *StatusData);
**         GetIOStatus           - TError G4XS1_GetIOStatus(TDeviceIdx DeviceIndex,uint16_t *StatusData);
**         ReadRegister          - TError G4XS1_ReadRegister(TDeviceIdx DeviceIndex,TSORegister...
**         WriteRegister         - TError G4XS1_WriteRegister(TDeviceIdx DeviceIndex,TSIRegister...
**         FeedWatchdog          - TError G4XS1_FeedWatchdog(void);
**         SetOutputState        - TError G4XS1_SetOutputState(TDeviceIdx DeviceIndex,bool *OutputStates);
**         SetPWMDuty            - TError G4XS1_SetPWMDuty(TDeviceIdx DeviceIndex,uint8_t Channel,uint16_t Duty);
**         SetGPWMDuty           - TError G4XS1_SetGPWMDuty(TDeviceIdx DeviceIndex,uint16_t Duty);
**         SetPWMControl         - TError G4XS1_SetPWMControl(TDeviceIdx DeviceIndex,uint8_t...
**         IncrementalPWMControl - TError G4XS1_IncrementalPWMControl(TDeviceIdx DeviceIndex,TIDSign...
**         ConfigureMonitoring   - TError G4XS1_ConfigureMonitoring(TDeviceIdx DeviceIndex,TSenseMux...
**         GetSenseValue         - TError G4XS1_GetSenseValue(uint16_t *Result);
**
**     (c) Copyright <company/user-name>, 2015
**     http://www.<company>.com
**     mail: info@<company>.com
** ###################################################################*/
/*!
** @file G4XS1.c
** @version 01.00
** @brief
**
*/         
/*!
**  @addtogroup G4XS1_module G4XS1 module documentation
**  @{
*/         

/* MODULE G4XS1. */

#include "XS65_Drv/G4XS1.h"
#include "XS65_Drv/XS65_port.h"

                                                                                                                      
#ifdef __cplusplus
extern "C" {
#endif 

/* PEx initialization values */
#define G4XS1_DEV0_INIT1_PEX_VALUE ( \
  G4XS_SOA_MODE_SINGLE_READ | \
  G4XS_SYNC_OFF | \
  G4XS_MUX_CTRL_DIE_TMP | \
  G4XS_WD_SEL_128MS \
)

#define G4XS1_DEV0_INIT2_PEX_VALUE ( \
  G4XS_OTW_LOW | \
  G4XS_HID_UNAVAILABLE | \
  G4XS_OCHI_THERMAL_DISABLE | G4XS_OCHI_TRANSIENT_DISABLE \
)

#define G4XS1_DEV0_CH1_CTRL_PEX_VALUE ( \
  G4XS_CHX_CTRL_SET_PWM_DUTY(G4XS_SI_CH1_CTRL_ADDR, 0) | \
  G4XS_CHX_CTRL_ONX_DISABLE | \
  G4XS_CHX_PHASE_0 \
)
#define G4XS1_DEV0_CH2_CTRL_PEX_VALUE ( \
  G4XS_CHX_CTRL_SET_PWM_DUTY(G4XS_SI_CH2_CTRL_ADDR, 0) | \
  G4XS_CHX_CTRL_ONX_DISABLE | \
  G4XS_CHX_PHASE_0 \
)
#define G4XS1_DEV0_CH3_CTRL_PEX_VALUE ( \
  G4XS_CHX_CTRL_SET_PWM_DUTY(G4XS_SI_CH3_CTRL_ADDR, 0) | \
  G4XS_CHX_CTRL_ONX_DISABLE | \
  G4XS_CHX_PHASE_0 \
)
#define G4XS1_DEV0_CH4_CTRL_PEX_VALUE ( \
  G4XS_CHX_CTRL_SET_PWM_DUTY(G4XS_SI_CH4_CTRL_ADDR, 0) | \
  G4XS_CHX_CTRL_ONX_DISABLE | \
  G4XS_CHX_PHASE_0 \
)
#define G4XS1_DEV0_CH5_CTRL_PEX_VALUE ( \
  G4XS_CHX_CTRL_SET_PWM_DUTY(G4XS_SI_CH5_CTRL_ADDR, 0) | \
  G4XS_CHX_CTRL_ONX_DISABLE | \
  G4XS_CHX_PHASE_0 \
)
#define G4XS1_DEV0_CH6_CTRL_PEX_VALUE ( \
  G4XS_CHX_CTRL_SET_PWM_DUTY(G4XS_SI_CH6_CTRL_ADDR, 0) | \
  G4XS_CHX_CTRL_ONX_DISABLE | \
  G4XS_CHX_PHASE_0 \
)

#define G4XS1_DEV0_OUT_CTRL_PEX_VALUE ( \
  G4XS_OUT_CTRL_ON1_DISABLE | \
  G4XS_OUT_CTRL_ON2_DISABLE | \
  G4XS_OUT_CTRL_ON3_DISABLE | \
  G4XS_OUT_CTRL_ON4_DISABLE | \
  G4XS_OUT_CTRL_ON5_DISABLE | \
  G4XS_OUT_CTRL_ON6_DISABLE | \
  G4XS_PSF1_DISABLE | \
  G4XS_PSF2_DISABLE | \
  G4XS_PSF3_DISABLE | \
  G4XS_PSF4_DISABLE | \
  G4XS_PSF5_DISABLE \
)

#define G4XS1_DEV0_GPWM1_CTRL_PEX_VALUE ( \
  G4XS_GPWM1_DISABLE | \
  G4XS_GPWM2_DISABLE | \
  G4XS_GPWM3_DISABLE | \
  G4XS_GPWM4_DISABLE | \
  G4XS_GPWM5_DISABLE | \
  G4XS_GPWM6_DISABLE \
)

#define G4XS1_DEV0_GPWM2_CTRL_PEX_VALUE G4XS_SET_GPWM_DUTY(G4XS_SI_GPWM_CTRL_2_ADDR, 0)

#define G4XS1_DEV0_OC1_CTRL_PEX_VALUE ( \
  G4XS_ACM1_DISABLE | \
  G4XS_ACM2_DISABLE | \
  G4XS_ACM3_DISABLE | \
  G4XS_ACM4_DISABLE | \
  G4XS_ACM5_DISABLE | \
  G4XS_OCLO1_THRESHOLD_LOW | \
  G4XS_OCLO2_THRESHOLD_LOW | \
  G4XS_OCLO3_THRESHOLD_LOW | \
  G4XS_OCLO4_THRESHOLD_LOW | \
  G4XS_OCLO5_THRESHOLD_LOW \
)

#define G4XS1_DEV0_OC2_CTRL_PEX_VALUE  ( \
  G4XS_SHORT_OCHI1_DISABLE | \
  G4XS_SHORT_OCHI2_DISABLE | \
  G4XS_SHORT_OCHI3_DISABLE | \
  G4XS_SHORT_OCHI4_DISABLE | \
  G4XS_SHORT_OCHI5_DISABLE | \
  G4XS_NO_OCHI1_DISABLE | \
  G4XS_NO_OCHI2_DISABLE | \
  G4XS_NO_OCHI3_DISABLE | \
  G4XS_NO_OCHI4_DISABLE | \
  G4XS_NO_OCHI5_DISABLE \
)

#define G4XS1_DEV0_IE_PEX_VALUE  ( \
  G4XS_INEN1_00 | \
  G4XS_INEN2_00 | \
  G4XS_INEN3_00 | \
  G4XS_INEN4_00 \
)

#define G4XS1_DEV0_PRS1_PEX_VALUE ( \
  G4XS_PRS1_1 | \
  G4XS_PRS2_1 | \
  G4XS_PRS3_1 | \
  G4XS_PRS4_1 | \
  G4XS_PRS5_1 \
)

#define G4XS1_DEV0_PRS2_PEX_VALUE ( \
  G4XS_PRS6_1 \
)
            
#define G4XS1_DEV0_OL_CTRL_PEX_VALUE ( \
  G4XS_OLON_DGL1_64US | \
  G4XS_OLON_DGL2_64US | \
  G4XS_OLON_DGL3_64US | \
  G4XS_OLON_DGL4_64US | \
  G4XS_OLON_DGL5_64US \
)

#define G4XS1_DEV0_OLLED_CTRL_PEX_VALUE ( \
  G4XS_OLLED1_DISABLE | \
  G4XS_OLLED2_DISABLE | \
  G4XS_OLLED3_DISABLE | \
  G4XS_OLLED4_DISABLE | \
  G4XS_OLLED5_DISABLE \
)

/* device settings and state global structure */
static G4XS1_TDeviceData G4XS1_DeviceData;
/* pointer to device data global structure */
G4XS1_TDeviceDataPtr G4XS1_DeviceDataPtr;

/* SI registers address table */
const uint16_t G4XS1_si_addr_table[G4XS1_SI_NUM] = {
                      G4XS_SI_INIT1_ADDR, G4XS_SI_INIT2_ADDR, \
                      G4XS_SI_CH1_CTRL_ADDR, G4XS_SI_CH2_CTRL_ADDR, G4XS_SI_CH3_CTRL_ADDR, G4XS_SI_CH4_CTRL_ADDR, G4XS_SI_CH5_CTRL_ADDR, G4XS_SI_CH6_CTRL_ADDR, \
                      G4XS_SI_OUT_CTRL_ADDR, \
                      G4XS_SI_GPWM_CTRL_1_ADDR,  G4XS_SI_GPWM_CTRL_2_ADDR, \
                      G4XS_SI_OC_CTRL_1_ADDR, G4XS_SI_OC_CTRL_2_ADDR, \
                      G4XS_SI_IE_ADDR, \
                      G4XS_SI_PS1_ADDR, G4XS_SI_PS2_ADDR, \
                      G4XS_SI_OL_CTRL_ADDR, G4XS_SI_OLLED_CTRL_ADDR, \
                      G4XS_SI_INC_DEC_ADDR
                   };

/* SO registers address table */
const uint16_t G4XS1_so_addr_table[G4XS1_SO_NUM] = {
                     G4XS_SO_QS_ADDR, \
                     G4XS_SO_CH1_STATUS_ADDR, G4XS_SO_CH2_STATUS_ADDR, G4XS_SO_CH3_STATUS_ADDR, G4XS_SO_CH4_STATUS_ADDR, G4XS_SO_CH5_STATUS_ADDR, \
                     G4XS_SO_DEVICE_STATUS_ADDR, \
                     G4XS_SO_IO_STATUS_ADDR, \
                     G4XS_SO_DEVICE_ID_ADDR
                   };

/* SPIDEV function pointers */
typedef void (*SPIDEV_SelectPtr)(void);
typedef void (*SPIDEV_UnselectPtr)(void);
typedef uint8_t (*SPIDEV_RequestBusPtr)(void);
typedef uint8_t (*SPIDEV_ReleaseBusPtr)(void);
typedef uint8_t (*SPIDEV_TransferBlockPtr)(void* SendDataPtr, void* ReceiveDataPtr, uint32_t Length, bool UnselectAfterTransfer);

/* SPIDEV function tables */
SPIDEV_SelectPtr const G4XS1_spi_select_func_table[G4XS1_DEV_NUM] = { \
  SPI_Device1_Select\
};
        
SPIDEV_UnselectPtr const G4XS1_spi_unselect_func_table[G4XS1_DEV_NUM] = { \
  SPI_Device1_Unselect\
};
        
SPIDEV_RequestBusPtr const G4XS1_spi_request_bus_func_table[G4XS1_DEV_NUM] = { \
  SPI_Device1_RequestBus\
};
        
SPIDEV_ReleaseBusPtr const G4XS1_spi_release_bus_func_table[G4XS1_DEV_NUM] = { \
  SPI_Device1_ReleaseBus\
};
        
SPIDEV_TransferBlockPtr const G4XS1_spi_transfer_block_func_table[G4XS1_DEV_NUM] = { \
  SPI_Device1_TransferBlock\
};
        

/**
 * Converts output bit mask to array of output states.
 * @param DeviceIndex specification of the device
 * @param ChStateMask bitmask representing channel output states
 * @param ChStateArray array representing channel output states
 * @return void
 */
void G4XS1_bitmask_to_array(G4XS1_TDeviceIdx DeviceIndex, uint8_t ChStateMask, bool ChStateArray[]) {
  for (uint8_t i = 0, j = 0; i < G4XS1_SI_CH_MAX; i++) {
    if (G4XS1_CH_MASK_GET(G4XS1_DeviceDataPtr->ChUsedMask[DeviceIndex], i)) {
      ChStateArray[j] = G4XS1_CH_MASK_GET(ChStateMask, i) ? TRUE : FALSE;
      j++;
    }
  }
}

/**
 * Converts array of output states to output bit mask.
 * @param DeviceIndex specification of the device
 * @param ChStateMask bitmask representing channel output states
 * @param ChStateArray array representing channel output states
 * @return void
 */
void G4XS1_array_to_bitmask(G4XS1_TDeviceIdx DeviceIndex, uint8_t *ChStateMask, bool ChStateArray[]) {
  *ChStateMask = 0;
  for (uint8_t i = 0, j = 0; i < G4XS1_SI_CH_MAX; i++) {
    if (G4XS1_CH_MASK_GET(G4XS1_DeviceDataPtr->ChUsedMask[DeviceIndex], i)) {
      if (ChStateArray[j]) {
        *ChStateMask = G4XS1_CH_MASK_SET(*ChStateMask, i);
      }
      j++;
    }
  }
}

/*
** ===================================================================
**     Method      :  G4XS1_Init (component Gen4eXtremeSwitch)
**     @brief
**         Initializes the device according to the component properties.
**         This method writes the data gathered from the component properties 
**         into registers via SPI. When auto initialization is enabled, 
**         this method will be called automatically within PE initialization 
**         function - PE_low_level_init(). 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TUserDataPtr UserDataPtr - User data pointer 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_Init(TUserDataPtr UserDataPtr)
{
  G4XS1_TError     Error = ERR_OK;
  G4XS1_DeviceDataPtr = &G4XS1_DeviceData;
  G4XS1_DeviceDataPtr->UserDataPtr = UserDataPtr;

  for (uint8_t i = 0; i < G4XS1_DEV_NUM; i++) {
    for (uint8_t j = sirINIT1; j <= sirINC_DEC; j++) {
      G4XS1_DeviceDataPtr->SIRegisters[i][j] = 0;
    }
  }
  
  /* Device 0 initialization START */
  
  /* assignment of PEx initialization values */
  G4XS1_DeviceDataPtr->SIRegisters[0][sirINIT1] = G4XS1_DEV0_INIT1_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirINIT2] = G4XS1_DEV0_INIT2_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirCH1_CTRL] = G4XS1_DEV0_CH1_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirCH2_CTRL] = G4XS1_DEV0_CH2_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirCH3_CTRL] = G4XS1_DEV0_CH3_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirCH4_CTRL] = G4XS1_DEV0_CH4_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirCH5_CTRL] = G4XS1_DEV0_CH5_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirCH6_CTRL] = G4XS1_DEV0_CH6_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirOUT_CTRL] = G4XS1_DEV0_OUT_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirGPWM_CTRL1] = G4XS1_DEV0_GPWM1_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirGPWM_CTRL2] = G4XS1_DEV0_GPWM2_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirOC_CTRL1] = G4XS1_DEV0_OC1_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirOC_CTRL2] = G4XS1_DEV0_OC2_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirIE] = G4XS1_DEV0_IE_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirPRS1] = G4XS1_DEV0_PRS1_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirPRS2] = G4XS1_DEV0_PRS2_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirOL_CTRL] = G4XS1_DEV0_OL_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirOLLED_CTRL] = G4XS1_DEV0_OLLED_CTRL_PEX_VALUE;
  G4XS1_DeviceDataPtr->SIRegisters[0][sirINC_DEC] = 0x00;

  G4XS1_DeviceDataPtr->WDMask[0] = 0x00;

  /* PEx channel index mapping */
  G4XS1_DeviceDataPtr->ChIndexMap[0][0] = 0;
  G4XS1_DeviceDataPtr->ChIndexMap[0][1] = 1;
  G4XS1_DeviceDataPtr->ChIndexMap[0][2] = 2;
  G4XS1_DeviceDataPtr->ChIndexMap[0][3] = 3;
  G4XS1_DeviceDataPtr->ChIndexMap[0][4] = 4;
  G4XS1_DeviceDataPtr->ChIndexMap[0][5] = 5;

  /* PEx for each enabled channel */
  G4XS1_DeviceDataPtr->ChUsedMask[0] = 0x00;
  G4XS1_DeviceDataPtr->ChUsedMask[0] = G4XS1_CH_MASK_SET(G4XS1_DeviceDataPtr->ChUsedMask[0], 0);
  G4XS1_DeviceDataPtr->ChUsedMask[0] = G4XS1_CH_MASK_SET(G4XS1_DeviceDataPtr->ChUsedMask[0], 1);
  G4XS1_DeviceDataPtr->ChUsedMask[0] = G4XS1_CH_MASK_SET(G4XS1_DeviceDataPtr->ChUsedMask[0], 2);
  G4XS1_DeviceDataPtr->ChUsedMask[0] = G4XS1_CH_MASK_SET(G4XS1_DeviceDataPtr->ChUsedMask[0], 3);
  G4XS1_DeviceDataPtr->ChUsedMask[0] = G4XS1_CH_MASK_SET(G4XS1_DeviceDataPtr->ChUsedMask[0], 4);
  G4XS1_DeviceDataPtr->ChUsedMask[0] = G4XS1_CH_MASK_SET(G4XS1_DeviceDataPtr->ChUsedMask[0], 5);

  /* PEx for each enabled channel which has state ON after initialization */
  G4XS1_DeviceDataPtr->ChStateMask[0] = 0x00;
  
  /* Device 0 initialization END */
  
  G4XS1_DeviceDataPtr->MonitoredDevice = didxDEV1;
  G4XS1_DeviceDataPtr->MonitoredOutput = smCTRL_DIE_TEMP;
	
  /* RST -> 1 (wakes up the device and the SPI is enabled) */
  XS65_RstPinHigh();

  for (uint8_t i = 0; i < G4XS1_DEV_NUM; i++) {
    /* writes configuration to the device */
    for (uint8_t j = sirINIT1; j < sirINC_DEC; j++) {
      if (((j >= sirCH1_CTRL) && (j <= sirCH6_CTRL)) && (!G4XS1_CH_MASK_GET(G4XS1_DeviceDataPtr->ChUsedMask[i], j - 2))) { /* configures only used channels */
        continue;
      }
      Error = G4XS1_WriteRegister(i, j, G4XS1_DeviceDataPtr->SIRegisters[i][j]);
      if (Error != ERR_OK) {
        return Error;
      }
    }
  }
  
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  G4XS1_GetQuickStatus (component Gen4eXtremeSwitch)
**     @brief
**         Returns current status of the device.
**         Reads the quick status register which provides glance at failure overview. As long as 
**         no failure flag is set (logic 1), no control action by the microcontroller 
**         is necessary.
**         Meaning of bits in quick status register can be found in datasheet or header file. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         uint16_t StatusData - Pointer to variable that will be filled with 
**                           the status information. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_GetQuickStatus(G4XS1_TDeviceIdx DeviceIndex, uint16_t *StatusData)
{
  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  if (StatusData == NULL) {
    return ERR_PARAM_ADDRESS;
  }
  
  return G4XS1_ReadRegister(DeviceIndex, sorQUICK_STATUS, StatusData);
}

/*
** ===================================================================
**     Method      :  G4XS1_GetChannelStatus (component Gen4eXtremeSwitch)
**     @brief
**         Gets the information of the fault for all available channels.
**         Reads information from CHx status register.
**         Meaning of bits in CHx status register can be found in datasheet or header file. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         uint16_t StatusData - Pointer to an array that will be filled with 
**                           the fault information. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_GetChannelStatus(G4XS1_TDeviceIdx DeviceIndex, uint16_t *StatusData)
{
  G4XS1_TError     Error;
  
  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  if (StatusData == NULL) {
    return ERR_PARAM_ADDRESS;
  }

  for (uint8_t i = 0, j = 0; i < G4XS1_SO_CH_MAX; i++) {
    if (!G4XS1_CH_MASK_GET(G4XS1_DeviceDataPtr->ChUsedMask[DeviceIndex], i)) {
      continue;
    }
    Error = G4XS1_ReadRegister(DeviceIndex, i + 1, &StatusData[j]);
    if (Error != ERR_OK) {
      return Error;
    }
    j++;
  }

  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  G4XS1_GetDeviceStatus (component Gen4eXtremeSwitch)
**     @brief
**         Gets information on the status of the device.
**         Reads information from device status register.
**         Meaning of bits in device status register can be found in datasheet or header file. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         uint16_t StatusData - Pointer to variable that will be filled with 
**                           the fault information. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_GetDeviceStatus(G4XS1_TDeviceIdx DeviceIndex, uint16_t *StatusData)
{
  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  if (StatusData == NULL) {
    return ERR_PARAM_ADDRESS;
  }
  
  return G4XS1_ReadRegister(DeviceIndex, sorDEVICE_STATUS, StatusData);
}

/*
** ===================================================================
**     Method      :  G4XS1_GetIOStatus (component Gen4eXtremeSwitch)
**     @brief
**         Gets information on the I/O of the device.
**         Reads information from I/O status register.
**         Meaning of bits in I/O status register can be found in datasheet or header file. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         uint16_t StatusData - Pointer to variable that will be filled with 
**                           the fault information. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_GetIOStatus(G4XS1_TDeviceIdx DeviceIndex, uint16_t *StatusData)
{
  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  if (StatusData == NULL) {
    return ERR_PARAM_ADDRESS;
  }
  
  return G4XS1_ReadRegister(DeviceIndex, sorIO_STATUS, StatusData);
}

/*
** ===================================================================
**     Method      :  G4XS1_send_rcv_16b (component Gen4eXtremeSwitch)
**     @brief
**         Sends and receives value of the given register via SPI. This method is 
**         by other methods to read content from a register of the device(s). 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         uint8_t sendData - Data to send. 
**         @param
**         uint16_t rcvData - Pointer to the variable for resulting data. 
**                           If there are more devices in a daisy chain, 
**                           all devices are read at once. The size of the 
**                           array must match the length of the daisy-chain 
**                           configured in component. In case there is only 
**                           single device, the size is 1. 
**         @return
**         LDD_TError      - Return values:
**                           ERR_OK - OK
**                           ERR_PARA - input value is invalid
**                           ERR_COMM - communication error
** ===================================================================
*/
#if 0
G4XS1_TError G4XS1_send_rcv_16b(G4XS1_TDeviceIdx DeviceIndex, uint16_t SendData, uint16_t *RcvData)
{
  LDD_TError       Error;
  uint8_t          InOutBuff[2];

  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  if (RcvData == NULL) {
    return ERR_PARAM_ADDRESS;
  }

  /* toggles WD bit */
  SendData |= G4XS1_DeviceDataPtr->WDMask[DeviceIndex];
  G4XS1_DeviceDataPtr->WDMask[DeviceIndex] = G4XS_TOGGLE_WD(G4XS1_DeviceDataPtr->WDMask[DeviceIndex]);
  
  InOutBuff[0] = (uint8_t)(SendData >> 8);
  InOutBuff[1] = (uint8_t)(SendData & 0x00FF);

  /* requests bus, sends and receives data, releases bus */
  if (!(*G4XS1_spi_request_bus_func_table[DeviceIndex])()) {
    return ERR_BUSOFF;
  }
  (*G4XS1_spi_select_func_table[DeviceIndex])();
  Error = (*G4XS1_spi_transfer_block_func_table[DeviceIndex])(InOutBuff, InOutBuff, 2, TRUE);
  (*G4XS1_spi_release_bus_func_table[DeviceIndex])();

  /* stores high byte */
  *RcvData = (uint16_t)InOutBuff[0];
  /* stores low byte */
  *RcvData <<= 8;
  *RcvData &= 0xFF00;
  *RcvData |= (uint16_t)(InOutBuff[1] & 0x00FF);

  return Error;
}
#else
G4XS1_TError G4XS1_send_rcv_16b(G4XS1_TDeviceIdx DeviceIndex, uint16_t SendData, uint16_t *RcvData)
{
  G4XS1_TError       Error;
  uint16_t         InOutBuff;

  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  if (RcvData == NULL) {
    return ERR_PARAM_ADDRESS;
  }

  /* toggles WD bit */
  SendData |= G4XS1_DeviceDataPtr->WDMask[DeviceIndex];
  G4XS1_DeviceDataPtr->WDMask[DeviceIndex] = G4XS_TOGGLE_WD(G4XS1_DeviceDataPtr->WDMask[DeviceIndex]);

  InOutBuff = SendData;

  /* requests bus, sends and receives data, releases bus */
  if (!(*G4XS1_spi_request_bus_func_table[DeviceIndex])()) {
    return ERR_BUSOFF;
  }
  (*G4XS1_spi_select_func_table[DeviceIndex])();
  Error = (*G4XS1_spi_transfer_block_func_table[DeviceIndex])(&InOutBuff, &InOutBuff, 1, TRUE);
  (*G4XS1_spi_release_bus_func_table[DeviceIndex])();

  /* stores high byte */
  *RcvData = InOutBuff;

  return Error;
}
#endif

/*
** ===================================================================
**     Method      :  G4XS1_ReadRegister (component Gen4eXtremeSwitch)
**     @brief
**         Reads value of the given register via SPI.
**         This method allows the user to read content from a register of the device(s). 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         TSORegister Register - Address of the register. 
**         @param
**         uint16_t RegVal - Pointer to the variable for resulting data. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_ReadRegister(G4XS1_TDeviceIdx DeviceIndex, G4XS1_TSORegister Register, uint16_t *RegVal)
{
  G4XS1_TError     Error;
  uint16_t         Tmp;

  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  if (Register > sorDEVICE_ID) {
	  return ERR_PARAM_VALUE;
  }
  if (RegVal == NULL) {
    return ERR_PARAM_ADDRESS;
  }

  Tmp = G4XS_SI_INIT1_ADDR | G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][sirINIT1];
  Tmp = G4XS_SOA_SET_ADDR(Tmp, G4XS1_so_addr_table[Register] >> 12); /* sets SO register address */

  Error = G4XS1_send_rcv_16b(DeviceIndex, Tmp, RegVal); /* first transfer sets address of SO register */
  if (Error != ERR_OK) {
    return Error;
  }

  Error = G4XS1_send_rcv_16b(DeviceIndex, Tmp, RegVal); /* second transfer receives value of previously addressed SO register */
  if (Error != ERR_OK) {
    return Error;
  }
  
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  G4XS1_WriteRegister (component Gen4eXtremeSwitch)
**     @brief
**         Writes value to the given register via SPI.
**         This method allows the user to set a custom value to a register of the device. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         TSIRegister Register - Address of the register. 
**         @param
**         uint16_t RegVal - Pointer to the value to be written. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_WriteRegister(G4XS1_TDeviceIdx DeviceIndex, G4XS1_TSIRegister Register, uint16_t RegVal)
{
  G4XS1_TError     Error;
  
  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  if (Register > sirINC_DEC) {
    return ERR_PARAM_VALUE;
  }

  Error = G4XS1_send_rcv_16b(DeviceIndex, G4XS1_si_addr_table[Register] | (RegVal & 0x0FFF), &G4XS1_DeviceDataPtr->SORegister[DeviceIndex]);
  if (Error != ERR_OK) {
    return Error;
  }
  else {
    G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][Register] = RegVal & 0x0FFF;
    return ERR_OK;
  }
}

/*
** ===================================================================
**     Method      :  G4XS1_FeedWatchdog (component Gen4eXtremeSwitch)
**     @brief
**         Toggles the watchdog bit in all devices to avoid watchdog timeout.
**         Watchdog is fed with every SPI write. If there is not SPI communication 
**         it is necessary to feed it before the timeout expires. The watchdog 
**         timeout depends on WD SEL bit in Intialization register 1. The 
**         timeout is either 32 ms or 128 ms. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_FeedWatchdog(void)
{
  G4XS1_TError     Error;
  
  for (uint8_t i = 0; i < G4XS1_DEV_NUM; i++) { /* dummy SPI communication with all devices */
    Error = G4XS1_WriteRegister(i, sirPRS2, G4XS1_DeviceDataPtr->SIRegisters[i][sirPRS2]);
    if (Error != ERR_OK) {
      return Error;
    }
  }
  
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  G4XS1_SetOutputState (component Gen4eXtremeSwitch)
**     @brief
**         Turns on/off channels of the device. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         uint8_t OutputStates - Pointer to array containing states of
**                           available channels (TRUE = enabled, FALSE = disabled). 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_SetOutputState(G4XS1_TDeviceIdx DeviceIndex, bool *OutputStates)
{
  G4XS1_TError     Error;
  uint16_t         RegVal = G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][sirOUT_CTRL];

  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  
  if (OutputStates == NULL) {
    return ERR_PARAM_ADDRESS;
  }
  
  for (uint8_t i = 0; G4XS1_DeviceDataPtr->ChIndexMap[DeviceIndex][i] != 7; i++) {
    if ((OutputStates[i] != TRUE) && (OutputStates[i] != FALSE)) {
      return ERR_PARAM_VALUE;
    } 
  }

  /* array to bitmask */
  uint8_t          OutputMask;
  G4XS1_array_to_bitmask(DeviceIndex, &OutputMask, OutputStates);

  if (OutputMask == G4XS1_DeviceDataPtr->ChStateMask[DeviceIndex]) {
    return ERR_OK;
  }

  for (uint8_t i = 0; i < G4XS1_SI_CH_MAX; i++) {
    /* sets output state only if channel was configured in PEx */
    if (G4XS1_CH_MASK_GET(G4XS1_DeviceDataPtr->ChUsedMask[DeviceIndex], i)) {
      RegVal = G4XS1_CH_MASK_GET(OutputMask, i) ? RegVal | (G4XS_ON1_MASK << i) : RegVal & ~(G4XS_ON1_MASK << i);
    }
  }
  
  Error = G4XS1_WriteRegister(DeviceIndex, sirOUT_CTRL, RegVal);
  if (Error != ERR_OK) {
    return Error;
  }
  else {
    G4XS1_DeviceDataPtr->ChStateMask[DeviceIndex] = G4XS1_DeviceDataPtr->ChUsedMask[DeviceIndex] & OutputMask;
    return ERR_OK;
  }
}

/*
** ===================================================================
**     Method      :  G4XS1_SetPWMDuty (component Gen4eXtremeSwitch)
**     @brief
**         Sets PWM duty for specified channel.
**         Calling this method will set PWM output immediately (if PWM is enabled).
**         This method writes PWM value into CHx register. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         uint8_t Channel - Output channel index. 
**         @param
**         uint16_t Duty   - PWM duty value for selected channel. The range 
**                           of the duty is 0..256, where 0 = OFF and 1 
**                           = 0.4% duty and 256 = 100%. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_SetPWMDuty(G4XS1_TDeviceIdx DeviceIndex, uint8_t Channel, uint16_t Duty)
{
  Channel = G4XS1_DeviceDataPtr->ChIndexMap[DeviceIndex][Channel];

  G4XS1_TError     Error;
  uint16_t         RegVal = G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][Channel + 2];
  uint8_t          StateMask = G4XS1_DeviceDataPtr->ChStateMask[DeviceIndex];

  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  
  if (Channel > (G4XS1_SI_CH_MAX - 1)) {
    return ERR_PARAM_RANGE;
  }
  
  if (!G4XS1_CH_MASK_GET(G4XS1_DeviceDataPtr->ChUsedMask[DeviceIndex], Channel)) {
    return ERR_CH_NOT_USED;
  }
  
  if (Duty > G4XS1_MAX_PWM_DUTY) {
    return ERR_PARAM_RANGE;
  }

  /* alters channel state according to the new duty value */
  StateMask = (Duty > 0) ? G4XS1_CH_MASK_SET(StateMask, Channel) : G4XS1_CH_MASK_UNSET(StateMask, Channel);
  RegVal = (Duty > 0) ? RegVal | G4XS_ONX_MASK : RegVal & ~(G4XS_ONX_MASK);

  /* sets new duty value */
  RegVal = G4XS_CHX_CTRL_SET_PWM_DUTY(RegVal, Duty == 0 ? 0 : (Duty - 1));

  Error = G4XS1_WriteRegister(DeviceIndex, Channel + 2, RegVal);
  if (Error != ERR_OK) {
    return Error;
  }
  else {
    G4XS1_DeviceDataPtr->ChStateMask[DeviceIndex] = StateMask;
    return ERR_OK;
  }
}

/*
** ===================================================================
**     Method      :  G4XS1_SetGPWMDuty (component Gen4eXtremeSwitch)
**     @brief
**         Sets Global PWM duty cycle value.
**         Calling this method will set PWM output immediately (if PWM is enabled). This method writes 
**         into global register. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         uint16_t Duty   - Global PWM duty value for selected device. The range 
**                           of the duty is 0..256, where 0 = OFF and 1 
**                           = 0.4% duty and 256 = 100%. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_SetGPWMDuty(G4XS1_TDeviceIdx DeviceIndex, uint16_t Duty)
{
  G4XS1_TError     Error;
  uint8_t          StateMask = G4XS1_DeviceDataPtr->ChStateMask[DeviceIndex];
  uint16_t         RegVal = G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][sirGPWM_CTRL2];
  bool             OutputState[6];

  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  if (Duty > G4XS1_MAX_PWM_DUTY) {
    return ERR_PARAM_RANGE;
  }

  Error = G4XS1_WriteRegister(DeviceIndex, sirGPWM_CTRL2, G4XS_SET_GPWM_DUTY(RegVal, Duty == 0 ? 0 : (Duty - 1)));
  if (Error != ERR_OK) {
    return Error;
  }

  for (uint8_t i = 0; i < G4XS1_SI_CH_MAX; i++) {
    if (!G4XS1_CH_MASK_GET(G4XS1_DeviceDataPtr->ChUsedMask[DeviceIndex], i)) {
      continue;
    }
    /* alters channel state according to the new duty value but only for channels which use GPWM */
    if (G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][sirGPWM_CTRL1] & (0x01 << i)) {
      StateMask = (Duty > 0) ? G4XS1_CH_MASK_SET(StateMask, i) : G4XS1_CH_MASK_UNSET(StateMask, i);
    }
  }  
  
  G4XS1_bitmask_to_array(DeviceIndex, StateMask, OutputState);

  return G4XS1_SetOutputState(DeviceIndex, OutputState);
}

/*
** ===================================================================
**     Method      :  G4XS1_SetPWMControl (component Gen4eXtremeSwitch)
**     @brief
**         Sets PWM output to Global or individual PWM control. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         uint8_t Channel - Output channel index. 
**         @param
**         TChannelControl Control - Individual state of the PWM type control for 
**                           each single output. The value is ccGLOBAL 
**                           if a channel is supposed to be controlled by 
**                           global PWM register or ccINDIVIDUAL if individually. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_SetPWMControl(G4XS1_TDeviceIdx DeviceIndex, uint8_t Channel, G4XS1_TChannelControl Control)
{
  Channel = G4XS1_DeviceDataPtr->ChIndexMap[DeviceIndex][Channel];

  uint16_t         RegVal = G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][sirGPWM_CTRL1];

  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }
  
  if (Channel > (G4XS1_SI_CH_MAX - 1)) {
    return ERR_PARAM_RANGE;
  }
  
  if (!G4XS1_CH_MASK_GET(G4XS1_DeviceDataPtr->ChUsedMask[DeviceIndex], Channel)) {
    return ERR_CH_NOT_USED;
  }
  
  switch (Control) {
    case ccINDIVIDUAL:
      RegVal &= ~(G4XS_GPWM_EN1_MASK << Channel);
      break;
    case ccGLOBAL:
      RegVal |= (G4XS_GPWM_EN1_MASK << Channel);
      break;
    default:
      return ERR_PARAM_VALUE;
  }
  
  return G4XS1_WriteRegister(DeviceIndex, sirGPWM_CTRL1, RegVal);
}

/*
** ===================================================================
**     Method      :  G4XS1_IncrementalPWMControl (component Gen4eXtremeSwitch)
**     @brief
**         This method sets LSB step according to which the duty cycle will 
**         be incremented or decremented with every call of this method. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         TIDSign Sign    - idsPOSITIVE = increment, idsNEGATIVE = decrement. 
**         @param
**         TLSBStep LSBStep - Array for available channels with step of increment/decrement 
**                           (idsNONE, ids4LSB, ids8LSB, ids16LSB). 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_IncrementalPWMControl(G4XS1_TDeviceIdx DeviceIndex, G4XS1_TIDSign Sign, G4XS1_TLSBStep *LSBStep)
{
  G4XS1_TError     Error;
  uint16_t         RegVal = G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][sirINC_DEC];
  int8_t           DutyUpdate[5] = {0};
  uint16_t         *ChRegPtr;
  uint16_t         ChDuty;

  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }

  if (LSBStep == NULL) {
    return ERR_PARAM_ADDRESS;
  }

  for (uint8_t i = 0, j = 0; i < (G4XS1_SI_CH_MAX - 1); i++) {
    if (!G4XS1_CH_MASK_GET(G4XS1_DeviceDataPtr->ChUsedMask[DeviceIndex], i)) {
      continue;
    }
    
    RegVal &= ~((G4XS_INCR01_MASK | G4XS_INCR11_MASK) << (i * 2)); /* resets step settings */

    /* sets increment value */
    switch (LSBStep[j]) {
      case idsNONE:
        RegVal |= (G4XS_INC1_NO << (i * 2));
        break;
      case ids4LSB:
        RegVal |= (G4XS_INC1_4LSB << (i * 2));
        DutyUpdate[i] += 4; 
        break;
      case ids8LSB:
        RegVal |= (G4XS_INC1_8LSB << (i * 2));
        DutyUpdate[i] += 8;
        break;
      case ids16LSB:
        RegVal |= (G4XS_INC1_16LSB << (i * 2));
        DutyUpdate[i] += 16;
        break;
      default:
        return ERR_PARAM_VALUE;
    }
    
    j++;
  }

  /* sets increment sign */
  switch (Sign) {
    case idsNEGATIVE:
      RegVal &= ~G4XS_INCR_SGN_MASK;
      break;
    case idsPOSITIVE:
      RegVal |= G4XS_INCR_SGN_MASK;
      break;
    default:
      return ERR_PARAM_VALUE;
  }

  Error = G4XS1_WriteRegister(DeviceIndex, sirINC_DEC, RegVal);
  if (Error != ERR_OK) {
    return Error;
  }
  else { /* updates internal duty values according to increment/decrement */
    for (uint8_t i = 0; i < (G4XS1_SI_CH_MAX - 1); i++) {
      if (DutyUpdate[i]) {
        ChRegPtr = &G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][i + 2];
        ChDuty = G4XS_CHX_CTRL_GET_PWM_DUTY(*ChRegPtr);
        if (Sign == idsPOSITIVE) {
          if ((ChDuty + DutyUpdate[i]) < 255) {
            *ChRegPtr = G4XS_CHX_CTRL_SET_PWM_DUTY(*ChRegPtr, ChDuty + DutyUpdate[i]);
          }
          else {
            *ChRegPtr = G4XS_CHX_CTRL_SET_PWM_DUTY(*ChRegPtr, 255);
            Error = ERR_MAX_DUTY;
          }
        }
        else {
          if ((ChDuty - DutyUpdate[i]) > 0) {
            *ChRegPtr = G4XS_CHX_CTRL_SET_PWM_DUTY(*ChRegPtr, ChDuty - DutyUpdate[i]);
          }
          else {
            *ChRegPtr = G4XS_CHX_CTRL_SET_PWM_DUTY(*ChRegPtr, 0);
            Error = ERR_MIN_DUTY;
          }
        }
      }
    }
  }
  
  return Error;
}


/*
** ===================================================================
**     Method      :  G4XS1_ConfigureMonitoring (component Gen4eXtremeSwitch)
**     @brief
**         Configures CSNS pin output.
**         This method sets monitored parameter and synchronization. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         TDeviceIdx DeviceIndex - Index of device (didxDEV1..4). 
**         @param
**         TSenseMux SenseMux - Measured value (CSNS pin function). 
**         @param
**         TSenseSyncTrigger Trigger - Synchronization trigger. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_ConfigureMonitoring(G4XS1_TDeviceIdx DeviceIndex, G4XS1_TSenseMux SenseMux, G4XS1_TSenseSyncTrigger Trigger)
{
  G4XS1_TError     Error;
  uint16_t         RegVal, RegVal2;

  if (DeviceIndex > (G4XS1_DEV_NUM - 1)) {
    return ERR_PARAM_VALUE;
  }

  RegVal = G4XS1_DeviceDataPtr->SIRegisters[DeviceIndex][sirINIT1];
  RegVal &= ~(G4XS_SYNC_EN0_MASK | G4XS_SYNC_EN1_MASK);

  /* sets new trigger value */
  switch (Trigger) {
    case sstOFF:
      RegVal |= G4XS_SYNC_OFF;
      break;
    case sstVALID:
      RegVal |= G4XS_SYNC_VALID;
      break;
    case sstTRIG0:
      RegVal |= G4XS_SYNC_TRIG0;
      break;
    case sstTRIG12:
      RegVal |= G4XS_SYNC_TRIG12;
      break;
    default:
      return ERR_PARAM_VALUE;
  }

  RegVal &= ~(G4XS_MUX0_MASK | G4XS_MUX1_MASK | G4XS_MUX2_MASK);

  /* switches mux to selected output for selected device */
  switch (SenseMux) {
    case smOUT1_CURRENT:
      RegVal |= G4XS_MUX_OUT1_CURRENT;
      break;
    case smOUT2_CURRENT:
      RegVal |= G4XS_MUX_OUT2_CURRENT;
      break;
    case smOUT3_CURRENT:
      RegVal |= G4XS_MUX_OUT3_CURRENT;
      break;
    case smOUT4_CURRENT:
      RegVal |= G4XS_MUX_OUT4_CURRENT;
      break;
    case smOUT5_CURRENT:
      RegVal |= G4XS_MUX_OUT5_CURRENT;
      break;
    case smVBAT_MONITOR:
      RegVal |= G4XS_MUX_VBAT_MONITOR;
      break;
    case smCTRL_DIE_TEMP:
      RegVal |= G4XS_MUX_CTRL_DIE_TMP;
      break;
    default:
      return ERR_PARAM_VALUE;
  }
  
  /* turns off CSNS pin for all devices except selected */
  for (uint8_t i = 0; i < G4XS1_DEV_NUM; i++) {
    RegVal2 = G4XS1_DeviceDataPtr->SIRegisters[i][sirINIT1];
    RegVal2 &= ~(G4XS_MUX0_MASK | G4XS_MUX1_MASK | G4XS_MUX2_MASK);
    
    if (i == DeviceIndex) {
      RegVal2 = RegVal;
    }

    Error = G4XS1_WriteRegister(i, sirINIT1, RegVal2);
    if (Error != ERR_OK) {
      return Error;
    }
    else {
      G4XS1_DeviceDataPtr->SIRegisters[i][sirINIT1] = RegVal2;
    }
  }

  G4XS1_DeviceDataPtr->MonitoredDevice = DeviceIndex;
  G4XS1_DeviceDataPtr->MonitoredOutput = SenseMux;

  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  G4XS1_GetSenseValue (component Gen4eXtremeSwitch)
**     @brief
**         Configures monitoring of current, voltage or temperature on the 
**         CSNS pin and returns the corresponding value from the ADC. Waits 
**         until measurement is completed. 
**     Parameters  :
**         NAME            - DESCRIPTION
**         @param
**         uint16_t Result - Pointer to variable where the measured data will be stored. 
**         @return
**         TError          - Error code, ERR_OK if successful 
** ===================================================================
*/
G4XS1_TError G4XS1_GetSenseValue(uint16_t *Result)
{
  G4XS1_TError     Error=0;
  uint16_t         RegVal, FSRValue;
  uint16_t         RawValue, ConvValue;

  if (Result == NULL) {
    return ERR_PARAM_ADDRESS;
  }
  /* wait till ADC2 is idle, use inject trigger to start a sample on XS65 CSNS pin (ADC2_P6 on White Board) */
  XS65_ADC_GetCsnsValue(XS65_ADC_INST, XS65_ADC_CH_IDX, &RawValue);

  /* get measured value */
  //RawValue = adc2RsltArray[4];	//ADC2_P6 (2/3/4/5/6/7 ...)

  RegVal = G4XS1_DeviceDataPtr->SIRegisters[G4XS1_DeviceDataPtr->MonitoredDevice][sirOC_CTRL1];
  
  /* selects appropriate FSR value according to OCLO threshold and ACM settings */
  if (RegVal & (G4XS_OCLO1_MASK << (G4XS1_DeviceDataPtr->MonitoredOutput - 1))) { /* OCLO LOW */
    FSRValue = (RegVal & (G4XS_ACM_EN1_MASK << (G4XS1_DeviceDataPtr->MonitoredOutput - 1))) ? 2750 : 5500;
  }
  else { /* OCLO HIGH */
    FSRValue = (RegVal & (G4XS_ACM_EN1_MASK << (G4XS1_DeviceDataPtr->MonitoredOutput - 1))) ? 5500 : 11000;
  }

  /* converts raw value to selected sense value */
  switch (G4XS1_DeviceDataPtr->MonitoredOutput) {
    case smOUT1_CURRENT:
    case smOUT2_CURRENT:
    case smOUT3_CURRENT:
    case smOUT4_CURRENT:
    case smOUT5_CURRENT:
      ConvValue = (3300 * RawValue) / 65535;           /* (voltage reference * measured raw value) / adc resolution */
      ConvValue = (FSRValue * ConvValue) / 5000;       /* I = U/R [mA] 5kOhm resistor */
      break;
    case smVBAT_MONITOR:
      ConvValue = (3300 * RawValue) / 65535;           /* (voltage reference * measured raw value) / adc resolution */
      ConvValue *= 4;                                  /* 1/4 of VBAT voltage */
      break;
    case smCTRL_DIE_TEMP:
      ConvValue = (3300 * RawValue) / 65535;            /* (voltage reference * measured raw value) / adc resolution */
      ConvValue -= 2117;                                /* 2117 mV at 0 deg. C */
      ConvValue = ConvValue / 7.72;                     /* 7.72 mV per deg. C */
      break;
    default:
      return ERR_PARAM_VALUE;
  }

  *Result = ConvValue;

  return Error;
}


#ifdef __cplusplus
}  /* extern "C" */
#endif 
/* END G4XS1. */

/*!
** @}
*/
/*
** ###################################################################
**
**     This file was created by Processor Expert 10.5 [05.21]
**     for the Freescale Kinetis series of microcontrollers.
**
** ###################################################################
*/
