/* ---------------------------------------------------------------------------
 * adc.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 (MCP3208-CI/SL)
 * ---------------------------------------------------------------------------
 * 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 "adc.h"
#include "ssp0.h"
#include "ElecStatusCache.h"
#include "calibrateaio.h"
#include "sys_config.h"
#include "dio.h"

/* ---------------------------------------------------------------------------
 * Local constant and macro definitions
 * ---------------------------------------------------------------------------
 */
#define ADC_CS_DIR_REG        FIO1DIR
#define ADC_CS_SET_REG        FIO1SET
#define ADC_CS_CLR_REG        FIO1CLR
#define ADC_CS_BIT            BIT( 25 )
#define ADC_CS_DISABLE        (ADC_CS_SET_REG = ADC_CS_BIT)
#define ADC_CS_ENABLE         (ADC_CS_CLR_REG = ADC_CS_BIT)

// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define ADC_CV_DIR_REG        FIO3DIR
#define ADC_CV_PIN_REG        FIO3PIN
#define ADC_CV_SET_REG        FIO3SET
#define ADC_CV_CLR_REG        FIO3CLR
#else
#define ADC_CV_DIR_REG_P1     FIO1DIR
#define ADC_CV_DIR_REG_P2     FIO2DIR
#define ADC_CV_PIN_REG_P1     FIO1PIN
#define ADC_CV_PIN_REG_P2     FIO2PIN
#define ADC_CV_SET_REG_P1     FIO1SET
#define ADC_CV_SET_REG_P2     FIO2SET
#define ADC_CV_CLR_REG_P1     FIO1CLR
#define ADC_CV_CLR_REG_P2     FIO2CLR
#endif

// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define CURRENT_VOLTAGE_BITS  (0x000000FF)
#else
#define CURRENT_VOLTAGE_BITS_P1  (0x3C000000)
#define CURRENT_VOLTAGE_BITS_P2  (0x00000078)
#endif

// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define ADC_MUX_DIR         FIO3DIR
#define ADC_MUX_SET         FIO3SET         
#define ADC_MUX_CLR         FIO3CLR

#define ADC_MUX_BIT         BIT(23)
#define ADC_MUX_EN          (ADC_MUX_SET = ADC_MUX_BIT)
#define ADC_MUX_DS          (ADC_MUX_CLR = ADC_MUX_BIT)
#endif

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

#define ADC_START_CMD         (0x04)
#define ADC_SINGLE_ENDED      (0x02)
#define ADC_DIFFERENTIAL      (0x00)



/* ---------------------------------------------------------------------------
 * Global variable definitions
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * Local variable definitions
 * ---------------------------------------------------------------------------
 */
UINT16 InputVoltageCorrection[8];
UINT16 InputCurrentCorrection[8];

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

void adcInit (void)
{
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
    /* TESTER Pins like IO_CTRL REV_B                                           */
    ADC_CV_DIR_REG |= CURRENT_VOLTAGE_BITS;
#else 
    ADC_CV_DIR_REG_P1 |= CURRENT_VOLTAGE_BITS_P1;
    ADC_CV_DIR_REG_P2 |= CURRENT_VOLTAGE_BITS_P2;
#endif
#if (PINSET_TESTER == 2)    
    /* TESTER Pins like IO_CTRL REV_B                                           */
    ADC_CV_SET_REG = CURRENT_VOLTAGE_BITS; // Default all bits to current
#else
    ADC_CV_SET_REG_P1 = CURRENT_VOLTAGE_BITS_P1;
    ADC_CV_SET_REG_P2 = CURRENT_VOLTAGE_BITS_P2;
#endif    
    
    ADC_CS_DIR_REG |= ADC_CS_BIT;
    ADC_CS_DISABLE;
  
    loadCorrectionValue(InputVoltageCorrection, VoltageInput);
    loadCorrectionValue(InputCurrentCorrection, CurrentInput);
    
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
    ADC_MUX_DIR |= ADC_MUX_BIT;
#endif

}



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

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


/** \brief Select input mode (Voltage or Current) of a certain channel. */
void adcMode (
  UINT8 channel, /**< 0..7 = valid, 8..255 = future use */
  t_adc_mode mode
)
{
#if (PINSET_TESTER == 2)
    /* TESTER Pins like IO_CTRL REV_B                                           */
    if (channel >= maxADC_Channels ) return; // Channel doesn't exist
    
    if (mode == adcVOLTAGE)
        {
        ADC_CV_CLR_REG = BIT( channel );
        }
    else
        {
        ADC_CV_SET_REG = BIT( channel );
        }
#else
    if (channel >= maxADC_Channels ) return; // Channel doesn't exist
    
    if (mode == adcVOLTAGE)
        {
        if (channel <= 3)
            {
            ADC_CV_CLR_REG_P1 = BIT (26 + channel);
            }
        else
            {
            ADC_CV_CLR_REG_P2 = BIT (channel - 1);
            }
        }
    else
        {
        if (channel <= 3)
            {
            ADC_CV_SET_REG_P1 = BIT (26 + channel);
            }
        else
            {
            ADC_CV_SET_REG_P2 = BIT (channel - 1);
            }
        }
#endif
}

/** \brief Read  analog value in mV or uA depending on adcMode
    \retval value VOLTAGE: 0..10000[mV], CURRENT: 0..20000[uA] */
UINT16 adcRead (
  UINT8 device, /**< 0 = Self, 1..32 = Remote device */
  UINT8 channel /**< 0..7 = valid, 8..255 = future use */
)
{
    UINT8 spiAdcCommand[3];
    UINT8 spiAdcResponse[3];
    UINT16 adcResult;
    UINT32 range;
    UINT32 measuredValue;

    if (device > 0)
    	{
    	measuredValue = bpecAdcRead(device, channel);
    	}
    else
    	{    
	    
	    if (channel >= maxADC_Channels) return 0;
	    
	    spiAdcCommand[0] = (ADC_START_CMD | ADC_SINGLE_ENDED);
	    spiAdcCommand[0] |= (channel >> 2) & 0x01;
	    spiAdcCommand[1] = (channel << 6);
	    spiAdcCommand[2] = 0;
	    
	    spiTakeBus();
            {
            ADC_CS_ENABLE;

            spiWriteBuffer( spiAdcCommand, 3 );
            spiReadBuffer( spiAdcResponse, 3 );

            ADC_CS_DISABLE;
            }
        spiReleaseBus();
	    
	    adcResult = (UINT16)(spiAdcResponse[1] & 0x0F) << 8;
	    adcResult |= (UINT16)spiAdcResponse[2];
	    
	    // Convert ADC value (0-4096) to measured value 
	    // Determin range Voltage = 10000 & Ampere = 20000
#if (PINSET_TESTER == 2)
	    /* TESTER Pins like IO_CTRL REV_B                                           */
	    if ((ADC_CV_PIN_REG & BIT( channel )) == 0)
#else
	    if ((((ADC_CV_PIN_REG_P1 & BIT (26 + channel)) == 0) && (channel <= 3))
	     || (((ADC_CV_PIN_REG_P2 & BIT (channel -  1)) == 0) && (channel >= 4)))
#endif
	        {
	        range = 10000;
	        measuredValue = (adcResult * range) / InputVoltageCorrection[channel];
	        }
	    else
	        {
	        range = 20000;
	        measuredValue = (adcResult * range) / InputCurrentCorrection[channel];
	        }
    	}
    
	return (UINT16)measuredValue;
}

void adcModeAll (t_adc_mode mode)
{
    adcMode (0, mode);
    adcMode (1, mode);
    adcMode (2, mode);
    adcMode (3, mode);
    adcMode (4, mode);
    adcMode (5, mode);
    adcMode (6, mode);
    adcMode (7, mode);
}
