/* ---------------------------------------------------------------------------
 * dac.c - v0.1                                     (c) 2007 Micro-key bv
 * ---------------------------------------------------------------------------
 * Micro-key bv
 * Industrieweg 28, 9804 TG Noordhorn
 * Postbus 92, 9800 AB Zuidhorn
 * The Netherlands
 * Tel: +31 594 503020
 * Fax: +31 594 505825
 * Email: support@microkey.nl  
 * Web: www.microkey.nl
 * ---------------------------------------------------------------------------
 * Description: ADC-driver
 * ---------------------------------------------------------------------------
 * Version(s):  0.1, 28-11-2007, fvds.
 *                   Creation.
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * System include files
 * ---------------------------------------------------------------------------
 */
#include "LPC23xx.h"
#include "types.h"

/* FreeRTOS includes */
#include "FreeRTOS.h"
/* ---------------------------------------------------------------------------
 * Application include files
 * ---------------------------------------------------------------------------
 */
#include "dac.h"
#include "sys_config.h"
#include "ssp0.h"
#include "dio.h"
#include "calibrateaio.h"
#include "ElecStatusCache.h"


/* ---------------------------------------------------------------------------
 * Local constant and macro definitions
 * ---------------------------------------------------------------------------
 */
#define DAC_CS_DIR_REG        FIO1DIR
#define DAC_CS_SET_REG        FIO1SET
#define DAC_CS_CLR_REG        FIO1CLR
#define DAC1_CS_BIT           BIT( 21 )
#define DAC2_CS_BIT           BIT( 22 )
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define DAC3_CS_BIT           BIT( 19)
#endif

// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define DACS_CS_BITS          (DAC1_CS_BIT | DAC2_CS_BIT | DAC3_CS_BIT) 
#else
#define DACS_CS_BITS          (DAC1_CS_BIT | DAC2_CS_BIT)        
#endif

#define DAC1_CS_DISABLE       (DAC_CS_SET_REG = DAC1_CS_BIT)
#define DAC1_CS_ENABLE        (DAC_CS_CLR_REG = DAC1_CS_BIT)
#define DAC2_CS_DISABLE       (DAC_CS_SET_REG = DAC2_CS_BIT)
#define DAC2_CS_ENABLE        (DAC_CS_CLR_REG = DAC2_CS_BIT)
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define DAC3_CS_DISABLE       (DAC_CS_SET_REG = DAC3_CS_BIT)
#define DAC3_CS_ENABLE        (DAC_CS_CLR_REG = DAC3_CS_BIT)
#endif

// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define DAC_CV_DIR_REG         FIO4DIR
#define DAC_CV_SET_REG         FIO4SET
#define DAC_CV_CLR_REG         FIO4CLR
#else
#define DAC_CV_DIR_REG         FIO3DIR
#define DAC_CV_SET_REG         FIO3SET
#define DAC_CV_CLR_REG         FIO3CLR
#endif

// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define CURRENT_VOLTAGE_BITS   (0x0000003F)
#else
#define CURRENT_VOLTAGE_BITS   (0x07800000)
#endif

// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define DAC_MUX_DIR         FIO3DIR
#define DAC_MUX_SET         FIO3SET         
#define DAC_MUX_CLR         FIO3CLR

#define DAC_MUX_BIT         BIT(24)
#define DAC_MUX_EN          (DAC_MUX_SET = DAC_MUX_BIT)
#define DAC_MUX_DS          (DAC_MUX_CLR = DAC_MUX_BIT)
#endif

#define spiWrite               ssp0Write
#define spiRead                ssp0Read
#define spiWriteBuffer         ssp0WriteBuffer
#define spiReadBuffer          ssp0ReadBuffer
#define spiTakeBus             ssp0TakeBus
#define spiReleaseBus          ssp0ReleaseBus


#define DAC_CHANNEL_A          (0x8000) 
#define DAC_CHANNEL_B          (0x0000) 

#define DAC_OUTPUT_BUFFERED    (0x4000)
#define DAC_OUTPUT_UNBUFFERED  (0x0000)
#define DAC_OUTPUT_GAIN_1x     (0x2000)
#define DAC_OUTPUT_GAIN_2x     (0x0000)
#define DAC_SHDN_OPDC          (0x1000)
#define DAC_SHDN_DISABLED      (0x0000)
#define DAC_MAX_SETTING        (4095)
#define DAC_MAX_CURRENT        (20000)
#define DAC_MAX_VOLTAGE        (10000)



/* ---------------------------------------------------------------------------
 * Global variable definitions
 * ---------------------------------------------------------------------------
 */
UINT16 OutputVoltageCorrection[maxDAC_Channels];
UINT16 OutputCurrentCorrection[maxDAC_Channels];
/* ---------------------------------------------------------------------------
 * Local variable definitions
 * ---------------------------------------------------------------------------
 */

// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
t_dac_mode channelModes[maxDAC_Channels] =
{
        dacCURRENT,
        dacCURRENT,
        dacCURRENT,
        dacCURRENT,
        dacCURRENT,
        dacCURRENT
};

UINT16 channelSetting[maxDAC_Channels] =
{
        0,
        0,
        0,
        0,
        0,
        0
};
#else
t_dac_mode channelModes[maxDAC_Channels] =
{
        dacCURRENT,
        dacCURRENT,
        dacCURRENT,
        dacCURRENT
};

UINT16 channelSetting[maxDAC_Channels] =
{
        0,
        0,
        0,
        0
};
#endif

/* ---------------------------------------------------------------------------
 * Local function definitions
 * ---------------------------------------------------------------------------
 */



void dacInit (void)
{
    DAC_CV_DIR_REG |= CURRENT_VOLTAGE_BITS;
    DAC_CV_CLR_REG = CURRENT_VOLTAGE_BITS; // Default all bits to current
    DAC_CS_DIR_REG |= DACS_CS_BITS;
    DAC1_CS_DISABLE;
    DAC2_CS_DISABLE;
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
    DAC3_CS_DISABLE;
    DAC_MUX_DIR |= DAC_MUX_BIT;
#endif
    
    loadCorrectionValue(OutputVoltageCorrection, VoltageOutput);
    loadCorrectionValue(OutputCurrentCorrection, CurrentOutput);


}


void dac_MuxEn (BOOLEAN mode)
{
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
    if (mode == TRUE)
        {
        DAC_MUX_EN;                        /* Set MUX to ExtensionBoard    */
        }
    else
        {
        DAC_MUX_DS;                        /* Set MUX to MainBoard         */
        }
#endif
}

BOOLEAN dac_MuxRB (void)
{
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
    if (DAC_MUX_SET & DAC_MUX_BIT)
        {
        /* Mux is switched to ExtensionBoard                                */
        return (TRUE);                      
        }
    else
        {
        /* Mux is switched to MainBoard                                     */
        return (FALSE);
        }
#endif
}



/** \brief Select output mode (Voltage or Current) of a certain channel. */
void dacMode (
  UINT8 channel, /*< 0..5 = valid */
  t_dac_mode mode
)
{
    UINT32 channelMask;
    
    if (channel >= maxDAC_Channels ) return; // Channel doesn't exist
    
    channelModes[channel] = mode;
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
    channelMask = BIT( (UINT32)(channel) ); /* channel bit + offset         */
#else
    channelMask = BIT( (UINT32)(channel + 23) );  /* channel bit + offset   */
#endif
    if (mode == dacVOLTAGE)
        {
        DAC_CV_SET_REG = channelMask;
        }
    else
        {
        DAC_CV_CLR_REG = channelMask;
        }

}

/** \brief Write analog value in mV or uA depending on dacMode */
void dacWrite(
  UINT8 device,                        /**< 0 = Self, valid                 */
  UINT8 channel,                     /**< 0..5 = valid                      */
  UINT16 value             /*< VOLTAGE: 0..10000[mV], CURRENT: 0..20000[uA] */
)
{
    UINT16 spiCommand;
    UINT32 dacSetting;
    UINT32 divideValue;
    
    if (device == 0)
        {
    	
        if (channel >= maxDAC_Channels ) return; // Channel doesn't exist
        
        channelSetting[ channel] = value;
        
        // Assemble DAC command
        spiCommand = DAC_OUTPUT_UNBUFFERED | DAC_OUTPUT_GAIN_1x | DAC_SHDN_OPDC;
        spiCommand |= ( (channel & 0x01) == 0x01 ? DAC_CHANNEL_B : DAC_CHANNEL_A);
        divideValue = (channelModes[channel] == dacVOLTAGE ? DAC_MAX_VOLTAGE : DAC_MAX_CURRENT); 

//        dacSetting = ((UINT32)value * DAC_MAX_SETTING) / divideValue;
        
        if (channelModes[channel] == dacVOLTAGE)
            {
            dacSetting = (UINT32)value * OutputVoltageCorrection[channel] / divideValue;
            }
        else
            {
            dacSetting = (UINT32)value * OutputCurrentCorrection[channel] / divideValue;
            }
        
        if (dacSetting > DAC_MAX_SETTING) return;
       
        spiCommand |= (UINT16) dacSetting;
        
        /* devide channel by 2 on send the SPI command with WriteDacCommand
         * channel 0-1: dac0
         * channel 2-3: dac1
         * channel 4-5: dac2 */
        WriteDacCommand( spiCommand, (channel >> 1)); 
        }
    else
    	{
    	bpecWriteDacValue(device, channel, value);
    	}
}
        

UINT16 dacReadBack (
  UINT8 device, /**< 0 = Self, 1..32 = Remote device */
  UINT8 channel /**< 0..3 = valid, 8..255 = future use */
)
{
    if (device == 0)
        {
        if (channel >= maxDAC_Channels ) return 0; // Channel doesn't exist)

        return channelSetting[ channel ];
        }
    else
    	{
    	return bpecDacReadBack(device, channel);
    	}
}


void WriteDacCommand( UINT16 spiCommand, UINT8 dacNr )
{
    UINT8 spiCommandArray[2];
    UINT8 spiResponse[2];
    
    spiTakeBus();
        {
        // dacNr 0: DAC 0
        // dacNr 1: DAC 1
        // dacNr 2: DAC 2
        // Enable correct ChipSelect
        switch (dacNr)
            {
            case 0:
                DAC1_CS_ENABLE;
                break;
            case 1:
                DAC2_CS_ENABLE;
                break;
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
            case 2: DAC3_CS_ENABLE;
                break;
#endif
            }
        
//        if (dacNr == 0)
//            {
//            DAC1_CS_ENABLE;
//            } else
//            {
//            DAC2_CS_ENABLE;
//            }

        spiCommandArray[0] = (spiCommand >> 8) & 0xFF;
        spiCommandArray[1] = spiCommand & 0xFF;

        spiWriteBuffer( spiCommandArray, 2);
        spiReadBuffer( spiResponse, 2 );
        
        // dacNr 0: DAC 0
        // dacNr 1: DAC 1
        // dacNr 2: DAC 2
        // Enable correct ChipSelect
        switch (dacNr)
            {
            case 0:
                DAC1_CS_DISABLE;
                break;
            case 1:
                DAC2_CS_DISABLE;
                break;
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
            case 2: 
                DAC3_CS_DISABLE;
                break;
#endif
            }

//        if (dacNr == 0)
//            {
//            DAC1_CS_DISABLE;
//            } else
//            {
//            DAC2_CS_DISABLE;
//            }
        }
    spiReleaseBus();
}

void dacModeAll (t_dac_mode mode)
{
    dacMode(0, mode);
    dacMode(1, mode);
    dacMode(2, mode);
    dacMode(3, mode);
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
    dacMode(4, mode);
    dacMode(5, mode);
#endif
    
    
}
