/* ---------------------------------------------------------------------------
 * testaio.c                                           (c) 2008 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: 
 * Analogue Test File 
 * 
 * Note:
 * Output 0 is connected to Input 0 and 4
 * Output 1 is connected to Input 1 and 5
 * Output 2 is connected to Input 2 and 6
 * Output 3 is connected to Input 3 and 7
 * 
 * 
 * ---------------------------------------------------------------------------
 * Version(s):  0.1, Sep 08, 2008, MMi
 *                   Creation.
 * ---------------------------------------------------------------------------
 */

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


/* FreeRTOS includes */
#include "FreeRTOS.h"
#include "Task.h"

/* ---------------------------------------------------------------------------
 * Application include files
 * ---------------------------------------------------------------------------
 */ 
#include "adc.h"
#include "dac.h"
#include "dio.h"
#include "testaio.h"
#include "calibrateaio.h"

#include "SerOut.h"
#include "BusProtocol.h"

#include "remote_misc.h"
/* ---------------------------------------------------------------------------
 * Local constant and macro definitions
 * ---------------------------------------------------------------------------
 */

#define NumberOfAIs     maxADC_Channels     /* See adc.h                    */ 
#define NumberOfAIOs    maxDAC_Channels     /* See dac.h                    */ 

#define vTestValue          5000     /* Value for Test Voltage Output in mV */ 
#define cTestValue          10000    /* Value for Test Current Output in uA */
#define vNullValue          0
#define cNullValue          0

#define vLimit              20       /* Test Limit for Voltage Test         */
#define cLimit              100      /* Test Limit for Current Test         */

#define vNullLimit          50       /* Test Limit for NULL-Voltage Test    */
#define cNullLimit          50       /* Test Limit for NULL-Current Test    */

#define TestDelay           200

#define VoltageOutputCalibrationValue   10000 /* Calibration Value for V    */
#define CurrentOutputCalibrationValue   20000 /* Calibration Value for C    */

#define VoltageOutputTestValue          7000  /* Remote Test Value for V    */
#define CurrentOutputTestValue          15000 /* Remote Test Value for C    */

#define ident_calibrated    0x55        /* Calibrated status identifier     */
#define ident_default       0xAA        /* Default status identifier        */

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

/* Bus informations from protocolfunctions.c */
extern UINT8 remoteDeviceNumber;
extern UINT8 thisDeviceNumber;
/* ---------------------------------------------------------------------------
 * Local variable definitions
 * ---------------------------------------------------------------------------
 */

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

BOOLEAN testaioStart (void)
{
    BOOLEAN AIOTestResult = FALSE;      /* BOOLEAN Variable to return Result*/
    BOOLEAN VoltageTest_MB;
    BOOLEAN CurrentTest_MB;
    BOOLEAN VoltageTest_EB;
    BOOLEAN CurrentTest_EB;
   
    /* Do analogue line test for Mainboard Connectors                       */
    VoltageTest_MB = doAIOVoltageTest(); /* Call Test Function              */
    CurrentTest_MB = doAIOCurrentTest();
    
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
    /* Enable extension-board channels by switching multiplexers            */
    adc_MuxEn(TRUE);
    dac_MuxEn(TRUE);
    
    /* Do analogue line test for extension Board Connectors                 */
    VoltageTest_EB = doAIOVoltageTest(); /* Call Test Function              */
    CurrentTest_EB = doAIOCurrentTest();
    
    /* Switch off multiplexers again to main-board connectors               */
    adc_MuxEn(FALSE);
    dac_MuxEn(FALSE);
#endif
	
    if ((VoltageTest_MB == TRUE) && (CurrentTest_MB == TRUE)
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
     && (VoltageTest_EB == TRUE) && (CurrentTest_EB == TRUE)
#endif
         )
        {
        AIOTestResult = TRUE;
        }
    else
        {
        AIOTestResult = FALSE;
        }
    
    return (AIOTestResult);             /* Return Test Result               */
}

BOOLEAN doAIOVoltageTest (void)
{
    UINT32 aiocnt;
    BOOLEAN AIOLineTestResult = FALSE;
    BOOLEAN LowTest = TRUE;
    BOOLEAN AllOtherTest = TRUE;
    BOOLEAN HighTest = TRUE;
    UINT32 LowBuffer;
    BOOLEAN AllOtherBuffer;
    UINT32 HighBuffer;
    
    SetAnalogueInput(FALSE);            /* Set Analogue Input to Voltage    */
    dacMode (0, dacVOLTAGE);            /* Set Output Types to Voltage      */
    dacMode (1, dacVOLTAGE);
    dacMode (2, dacVOLTAGE);
    dacMode (3, dacVOLTAGE);
    
    dacWrite (thisDeviceNumber, 0, vNullValue); /* Write 0 Volts to Output  */
    dacWrite (thisDeviceNumber, 1, vNullValue);
    dacWrite (thisDeviceNumber, 2, vNullValue);
    dacWrite (thisDeviceNumber, 3, vNullValue);
    vTaskDelay (TestDelay); 
    
    sendString (SerOutPort, FALSE, testMessage, NewLine,
            "\tVoltage Test Value: ", ItoDStr (vTestValue));
    sendString (SerOutPort, FALSE, testMessage,
            "\t\tTolerance: ", ItoDStr (vLimit), Dummy);
    
    for (aiocnt = 0; aiocnt < NumberOfAIs; aiocnt++) /*Test Line by Line    */
        {
        /* Test if Input Voltage is below NullLimit                         */
        if ((LowBuffer = adcRead (thisDeviceNumber, aiocnt)) > vNullLimit)
            {
            LowTest = FALSE;            /* Failed, then set Test failed     */
            }
        
        /* Write chosen Output to Test Value                                */
        if (aiocnt < NumberOfAIOs)
            {
            dacWrite (thisDeviceNumber, aiocnt, vTestValue);
            }
        else                            /* if selected Input is > possible  */
            {                           /* Outputs, restart at Output 0     */
            dacWrite (thisDeviceNumber, (aiocnt - NumberOfAIOs), vTestValue);
            }
        vTaskDelay (TestDelay);         /* Wait for Output to be set        */
        
        /* Check if all other Inputs are Zero                               */
        if ((AllOtherBuffer = CheckAllOtherAIOZero(aiocnt, TRUE)) == FALSE)
            {
            AllOtherTest = FALSE;
            }
        
        /* Read Test Level on Input                                         */
        HighBuffer = adcRead (thisDeviceNumber, aiocnt);
        if ((HighBuffer < (vTestValue - vLimit))
         || (HighBuffer > (vTestValue + vLimit)))                          // \TODO is this working???
            {                           /* Is read Value in the Limits?     */
            HighTest = FALSE;
            }
        
        /* Write chosen Output back to Null                                 */
        if (aiocnt < NumberOfAIOs)
            {
            dacWrite (thisDeviceNumber, aiocnt, vNullValue);
            }
        else                            /* if selected Input is > possible  */
            {                           /* Outputs, restart at Output 0     */
            dacWrite (thisDeviceNumber, (aiocnt - NumberOfAIOs), vNullValue);
            }
        
        /* Message out Test Results                                         */
        sendString (SerOutPort, TRUE, testMessage,
                "\tVoltage Test for Analogue Input ", ItoDStr(aiocnt), ": ");
        sendString (SerOutPort, FALSE, testMessage,
                "  ", Dummy, ItoDStr (LowBuffer));
        sendString (SerOutPort, FALSE, testMessage,
                "  ", Dummy, ItoDStr (HighBuffer));
        sendString (SerOutPort, FALSE, testMessage,
                "  All Other: ", Dummy, BoolRestoStr (AllOtherBuffer));

        vTaskDelay (TestDelay);
        }
    
    /* Set complete LineTestResult                                          */
    if ((LowTest == TRUE)  && (HighTest == TRUE) && (AllOtherTest == TRUE))
        {
        AIOLineTestResult = TRUE;
        }
    
    return (AIOLineTestResult);    
}


BOOLEAN doAIOCurrentTest (void)
{
    UINT32 aiocnt;
    UINT32 LowBuffer;
    UINT32 HighBuffer;
    BOOLEAN AIOCurrentTest = TRUE;
    BOOLEAN LowTest;
    BOOLEAN HighTest;


    
    dacMode (0, dacCURRENT);            /* Set Output Types to Current      */
    dacMode (1, dacCURRENT);
    dacMode (2, dacCURRENT);
    dacMode (3, dacCURRENT);
    
    dacWrite (thisDeviceNumber, 0, cNullValue);        /* Write 0 uA to Output             */
    dacWrite (thisDeviceNumber, 1, cNullValue);
    dacWrite (thisDeviceNumber, 2, cNullValue);
    dacWrite (thisDeviceNumber, 3, cNullValue);
    vTaskDelay (TestDelay);
    
    sendString (SerOutPort, TRUE, testMessage, NewLine,
            "\tCurrent Test Value: ", ItoDStr (cTestValue));
    sendString (SerOutPort, FALSE, testMessage,
            "\t\tTolerance: ", ItoDStr (cLimit), Dummy);
    
    for (aiocnt = 0; aiocnt < NumberOfAIs; aiocnt++)
        {
        adcMode( aiocnt, adcCURRENT ); /* Inputs set to Current            */
        vTaskDelay (200);
        
        /* Read back the low Value on Input                                 */
        LowBuffer = adcRead (thisDeviceNumber, aiocnt);
        if (LowBuffer < cNullLimit)
            {
            /* If read Value is within the Limit, test passed               */
            LowTest = TRUE;
            }
        else
            {
            /* If read Value is out of Limit, test failed                   */
            LowTest = FALSE;
            }
        
        /* Write Output to defined Test Value                               */
        if (aiocnt < NumberOfAIOs)
            {
            dacWrite(thisDeviceNumber, aiocnt, cTestValue);
            }
        else
            {
            dacWrite(thisDeviceNumber, (aiocnt - NumberOfAIOs), cTestValue);
            }
        vTaskDelay (500);
        
        HighBuffer = adcRead(thisDeviceNumber, aiocnt);
        if ((HighBuffer < (cTestValue - cLimit))
         || (HighBuffer > (cTestValue + cLimit)))
            {
            /* If read Value is within the Limit, test passed               */
            HighTest = FALSE;
            }
        else
            {
            /* If read Value is out of Limit, test failed                   */
            HighTest = TRUE;
            }
        
        /* Drive Output back to Zero Value                                  */
        if (aiocnt < NumberOfAIOs)
            {
            dacWrite(thisDeviceNumber, aiocnt, cNullValue);
            }
        else
            {
            dacWrite(thisDeviceNumber, (aiocnt - NumberOfAIOs), cNullValue);
            }
        /* Set Input Mode to Voltage to prevent of leek Current             */
        adcMode (aiocnt, adcVOLTAGE);
        
        /* Message out Test Results                                         */
        sendString (SerOutPort, TRUE, testMessage,
                "\tCurrent Test for Analogue Input ", ItoDStr(aiocnt), ": ");
        sendString (SerOutPort, FALSE, testMessage,
                "  ", Dummy, ItoDStr (LowBuffer));
        sendString (SerOutPort, FALSE, testMessage,
                "  ", Dummy, ItoDStr (HighBuffer));
       
        /* Set complete LineTestResult                                      */
        if ((LowTest != TRUE)  || (HighTest != TRUE))
            {
            AIOCurrentTest = FALSE;
            }
        }
    
    return (AIOCurrentTest);
}


BOOLEAN CheckAllOtherAIOZero (UINT32 AIONumber, BOOLEAN local)
{
    
    UINT32 loopcnt;
    BOOLEAN AllZeroResult = TRUE;
    
    for (loopcnt = 0; loopcnt < NumberOfAIs; loopcnt++) /* Test Line by Line*/
        {
        if ((loopcnt == AIONumber) || /* except currently tested Input      */       
            (loopcnt == (AIONumber + NumberOfAIOs)) ||
            (loopcnt == (AIONumber - NumberOfAIOs)))
            {
            if (loopcnt < (NumberOfAIOs - 1))
                {                       
                loopcnt++;              /* Skip currently tested Output     */
                }
            else
                {
                break;                  /* If tested Output is the last one,*/ 
                }                       /* simply break out of loop         */
            }
        if (local == TRUE)
            {
            if (adcRead (thisDeviceNumber, loopcnt) > vNullLimit) 
                {                           /* If Input Value exceeds Limit */
                AllZeroResult = FALSE;
                }
            }
        else
            {
            if (adcRead (remoteDeviceNumber, loopcnt) > vNullLimit)
                {                           /* If Input Value exceeds Limit */
                sendString (SerOutPort, TRUE, testMessage,
                        "line: ", ItoDStr (loopcnt), Dummy);
                sendString (SerOutPort, TRUE, testMessage,
                        "Value: ", 
                        ItoDStr (adcRead (remoteDeviceNumber, loopcnt)), Dummy);
                
                AllZeroResult = FALSE;
                }
            vTaskDelay (100);
            }
        }
    return (AllZeroResult);
}


void SetAnalogueInput(BOOLEAN isCurrent)
{
    if (isCurrent == TRUE)
        {
        adcMode( 0, adcCURRENT );      /* Inputs set to Current             */
        adcMode( 1, adcCURRENT );
        adcMode( 2, adcCURRENT );
        adcMode( 3, adcCURRENT );
        adcMode( 4, adcCURRENT );
        adcMode( 5, adcCURRENT );
        adcMode( 6, adcCURRENT );
        adcMode( 7, adcCURRENT );
        }
    else
        {
        adcMode( 0, adcVOLTAGE );      /* Inputs set to Voltage             */
        adcMode( 1, adcVOLTAGE );
        adcMode( 2, adcVOLTAGE );
        adcMode( 3, adcVOLTAGE );
        adcMode( 4, adcVOLTAGE );
        adcMode( 5, adcVOLTAGE );
        adcMode( 6, adcVOLTAGE );
        adcMode( 7, adcVOLTAGE );
        }
}

