/*******************************************************************************
  MPLAB Harmony Application Source File
  
  Company:
    Microchip Technology Inc.
  
  File Name:
    Reflow.c
 Yes, this is really the PSU code.  Phil, change the file names.

  Summary:
    This file contains the source code for the MPLAB Harmony application.

  Description:
 * Ver 2020-10
 * - Hack reflow oven code as core of app
 * - Get state machine running
 * - User interface pics (basic set)
 *  
 * Ver 2020_10_11 - baselined generally functioning version with standard
 *  rotary controller
 * 
 * Ver post 2020_10_11
 * - Implement new user interface with 2 rotary controls
 * - Add pullups for second rotary in IC config
 * - Add pullups for switch in IC config
 * 
 * Ver 2020_12_24
 * - Fix Voltage / Current Set and Display
 * - Sped up current display - note this uses the heartbeat timer....
 * - Fixed screen update on exit from "Setup" menu
 * - Fix entry screen
 * - Do you want to add a menu selection for voltage step?
 *  
 * Extras 2020-12-25 (V1.3)
 * - Current and voltage errors added to GUI
 * - Add shutdown button
 * - Voltage step overshoot OK
 * - Boot up with blank EEPROM - fix defaults
 * 
 * Extras 2021-03-04 (V1.3)
 * - Increase voltage step to 0.25V (header file change)
 * - Increase current step for fast current change
 * - set current limit to 5.0A
 * - Added realtime update of calibration measurement for V and I
 *
 * Extras 2021-04 (V1.4)
 * Tidy up
 * 
 * Extras 2021-08-30 (V1.5)
 * - Slow current display filter (change Current_Filter_Coeff from 0.2 to 0.03)
 * 
 *  *******************************************************************************/

// DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright (c) 2013-2014 released Microchip Technology Inc.  All rights reserved.

Microchip licenses to you the right to use, modify, copy and distribute
Software only when embedded on a Microchip microcontroller or digital signal
controller that is integrated into your product or third party product
(pursuant to the sublicense terms in the accompanying license agreement).

You should refer to the license agreement accompanying this Software for
additional information regarding your rights and obligations.

SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER
CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
 *******************************************************************************/
// DOM-IGNORE-END


// *****************************************************************************
// *****************************************************************************
// Section: Included Files 
// *****************************************************************************
// *****************************************************************************

#include "Reflow.h"
#include "delay.h"
#include "KS0108-PIC16.h"
#include "KS0108.h"
#include "Solder.h"
#include "Zap_Off.h"
#include "Zap_On.h"
#include "TGM_Logo.h"
#include "EEPROM.h"
#include <stdio.h>
#include <xc.h>
#include <math.h>
#include "framework/driver/spi/static/drv_spi_static.h"



// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************

// *****************************************************************************

WELLER_DATA wellerData;

static unsigned char Old_Rot_Status, Old_Rot_Status_RE2 = 0;   /* Records state of rotary control */
int Fast_Loop_Counter = Fast_Counter_Init; /* Used to set Fast_Cnt */
int Slow_Loop_Counter = Slow_Counter_Init; /* Used to see if user turning control continuously */
static unsigned char Keypress_Read, Keypress_Read_RE2 = 0;    /* this is the data on key / rotation changes */
static unsigned char Key_Just_Pressed, Key_Just_Pressed_RE2 = 0; 	/* use this to keep track of which keys have been pressed */
int Fast_Change = 1;			/* use this to indicate fast change of values */

char loop, test_temp;
/* location at which input data is written into a cyclical buffer */
unsigned int Write_Pointer_Offset, Ch1_Rd_Offset, Ch2_Rd_Offset; 
/* used for output clipping to 24 bits */
int Out_Test_Temp;    

/* SPI Globals*/
uint8_t __attribute__ ((aligned (16))) txData[]  = "                ";
uint8_t __attribute__ ((aligned (16))) rxData[sizeof(txData)];
uint8_t txDataSize = sizeof(txData);
 



/*****************************************************************************/
// Graphics Buffers
//  Graphics Macros
/*****************************************************************************/
//unsigned char ScreenBuff[KS0108_SCREEN_HEIGHT/8][KS0108_SCREEN_WIDTH] , ScreenBuff1[KS0108_SCREEN_HEIGHT/8][KS0108_SCREEN_WIDTH]; 
unsigned char ScreenBuff[KS0108_SCREEN_WIDTH][KS0108_SCREEN_HEIGHT/8] , ScreenBuff1[KS0108_SCREEN_WIDTH][KS0108_SCREEN_HEIGHT/8]; 
/* You might want to move these into the display LCD function - though it is really not a gut buster for these two */
char line1[] =   Line1_Init;
char line2[] =   Line2_Init;
char *line1_ptr, *line2_ptr;				/* use these to point into the arrays */
/* These are ROM constants used in building the display */
const char Blank_Char = Blank_Char_Init;            /* ROM */
unsigned int display_temp;

// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************
static void APP_TimerCallback ( uintptr_t context, uint32_t alarmCount )
{
    /* feed the watchdog */
    WDTCONbits.WDTCLRKEY = 0x5743;
    
    wellerData.heartbeatCount++;
    if (wellerData.heartbeatCount >= APP_HEARTBEAT_COUNT_MAX)
    {
        wellerData.heartbeatCount = 0;
        wellerData.heartbeatToggle = true;
        
        /* then decrement the Revert To Idle timer */
        if (wellerData.Revert_To_Idle_Counter > 0)
            wellerData.Revert_To_Idle_Counter--;
        /* add this to drive screen updates in idle */
        wellerData.UI_Update_Display = true;
    }
        /* add this to drive screen updates in idle */
        wellerData.UI_Update_Display = true;
}


static void APP_UI_Callback ( uintptr_t context, uint32_t alarmCount )
{
    unsigned char Current_Rot_Status, Current_Rot_Status_RE2 = 0;
    
    /****************************************************************/
    /* Add in Current and Voltage read either here or in main loop  */
    /* update data on the screen if this is best done here          */
    /****************************************************************/
    /*********************************************/
    /* Start with the Voltage and "Main" encoder */
    /*********************************************/
    
    /*Read Rot Status and mask off bits of interest */
	Current_Rot_Status = HMI_Port & (Vals_0 + Vals_1 + Exit + Sel + Shutdown_Sw);
	Key_Just_Pressed = (Current_Rot_Status != Old_Rot_Status);
    /* set the flag */
   
    if(Key_Just_Pressed)
    {
        /* Only do this if something has changed - but neither of the select or exit buttons are pressed */
        if (Key_Just_Pressed  && !(Current_Rot_Status & (Sel + Exit + Shutdown_Sw)))
        {
            /* Old Type Encoder is biphase input on two ports with */
            /*      Each detent click of the resolver being one change in phase*/
            /*      Thus one gray code change of the inputs occurs per click*/
            if Encoder_Type_Is_Old
            {
                if (Old_Rot_Status == Phase_0)  /* From here need to work out if going up or down */
                {
                    if (Current_Rot_Status == Phase_1)
                        Keypress_Read = Rot_Up;
                    else
                        Keypress_Read = Rot_Down;
                }
                else if (Old_Rot_Status == Phase_1)  /* From here need to work out if going up or down */
                {
                    if (Current_Rot_Status == Phase_2)
                        Keypress_Read = Rot_Up;
                    else
                        Keypress_Read = Rot_Down;
                }
                else if (Old_Rot_Status == Phase_2)  /* From here need to work out if going up or down */
                {
                    if (Current_Rot_Status == Phase_3)
                        Keypress_Read = Rot_Up;
                    else
                        Keypress_Read = Rot_Down;
                }
                else if (Old_Rot_Status == Phase_3)  /* From here need to work out if going up or down */
                {
                    if (Current_Rot_Status == Phase_0)
                        Keypress_Read = Rot_Up;
                    else
                        Keypress_Read = Rot_Down;
                }
                wellerData.UI_Keypressed = true;
            }

            /* Type A - TYPE 2 on schematics - Encoder is biphase input on two ports with */
            /*      Each detent click of the resolver being four changes in phase*/
            /*      Thus one complete cycle of gray code occurs per click*/
            /*      Type A goes 11 -> 10 -> 00 -> 01 -> 11 and vice versa*/
            /*      This is the ALTRONICS device and my EBAY sourced devices */
            else if Encoder_Type_Is_TypeA
            {
                /* Phase_0 = 00*/
                /* From here need to work out if going up or down or reading crap*/
                /* CW 00 -> 01 */
                /* CCW 00-> 10 */
                /* But we do not want to act on these as it is mid-click*/
                if (Old_Rot_Status == Phase_0)
                {
                    /* Have read crap*/
                    Keypress_Read = 0;
                }
                /* From here need to work out if going up or down or reading crap*/
                /* CW 01 -> 11 */
                /* CCW 01-> 00 */
                /* But we do not want to act on these as it is mid-click*/
                else if (Old_Rot_Status == Phase_1)
                {
                    if (Current_Rot_Status == Phase_3)
                    {
                        /* have read noise again */
                        Keypress_Read = 0;
                        wellerData.UI_Keypressed = false;
                    }
                    else if (Current_Rot_Status == Phase_0)
                    {
                        Keypress_Read = Rot_Up;
                        wellerData.UI_Keypressed = true;
                    }
                    else Keypress_Read = 0;

                }
                /* From here need to work out if going up or down or reading crap*/
                /* CW 11 -> 10 */
                /* CCW 11-> 01 */
                /* This is it... do something*/
                else if (Old_Rot_Status == Phase_2)
                {
                    if (Current_Rot_Status == Phase_3)
                    {
                        Keypress_Read = Rot_Down;
                        wellerData.UI_Keypressed = false;
                    }
                    else if (Current_Rot_Status == Phase_1)
                    {
                        Keypress_Read = Rot_Up;
                        wellerData.UI_Keypressed = false;
                    }
                    else Keypress_Read = 0;
                    
                }
                /* From here need to work out if going up or down or reading crap*/
                /* CW 10 -> 00 */
                /* CCW 10-> 11 */
                /* But we do not want to act on these as it is mid-click*/
                else if (Old_Rot_Status == Phase_3)
                {
                    if (Current_Rot_Status == Phase_1)
                    {
                        /* have read noise again */
                        Keypress_Read = 0;
                        wellerData.UI_Keypressed = false;
                    }
                    else if (Current_Rot_Status == Phase_0)
                    {
                        Keypress_Read = Rot_Down;
                        wellerData.UI_Keypressed = true;
                    }
                    else Keypress_Read = 0;
                }
            }
            /* Type B  - TYPE 2 on schematics -  Encoder is biphase input on two ports with */
            /*  This is the JAYCAR encoder. */
            /*      Each detent click of the resolver being two changes in phase*/
            /*      Thus one complete cycle of pseudo gray code occurs every 2nd click*/
            /*      Type B goes 11 -> 10 -> 00 CW on the first click then...*/
            /*                  00 -> 10 -> 11 CW on the second click*/
            /*                  11 -> 01 -> 00 CW on the first click, then...*/
            /*                  00 -> 01 -> 11 CW on the second click*/
            else if Encoder_Type_Is_TypeB
            {
                /* Phase_0 = 00*/
                /* From here need to work out if going up or down or reading crap*/
                /* CW 00 -> 10 */
                /* CCW 00-> 01 */
                if (Old_Rot_Status == Phase_0)
                {
                    if (Current_Rot_Status == Phase_1)
                    {
                        Keypress_Read = Rot_Up;
                        wellerData.UI_Keypressed = true;
                    }
                    else if (Current_Rot_Status == Phase_3)
                    {
                        Keypress_Read = Rot_Down;
                        wellerData.UI_Keypressed = true;
                    }
                    else
                        Keypress_Read = 0;
                    
                    /* The Jaycar encoders have reversed pinouts to 
                       the baseline code!*/
                }
                /* Phase_1 = 01*/
                /* This is an intermediate state as the encoder is clicked...*/
                /* Do not want to act on these */
                else if (Old_Rot_Status == Phase_1)
                {
                    /* Have read crap*/
                    Keypress_Read = 0;
                }
                /* Phase_2 = 11*/
                /* From here need to work out if going up or down or reading crap*/
                /* CW 11 -> 10 */
                /* CCW 11-> 01 */
                /* OK This is it... */
                else if (Old_Rot_Status == Phase_2)
                {
                    if (Current_Rot_Status == Phase_1)
                    {
                        Keypress_Read = Rot_Down;
                        wellerData.UI_Keypressed = true;
                    }
                    else if (Current_Rot_Status == Phase_3)
                    {
                        Keypress_Read = Rot_Up;
                        wellerData.UI_Keypressed = true;
                    }
                    else
                        Keypress_Read = 0;
                }
                /* Phase_3 = 10*/
                /* again an intermediate state */
                /* We do not want to act on these */
                else if (Old_Rot_Status == Phase_3)  /* From here need to work out if going up or down */
                {
                    /* Have read crap*/
                    Keypress_Read = 0;
                }
                else
                {
                    Keypress_Read = 0;
                }
            }

            Slow_Loop_Counter = Slow_Counter_Init;	/* If key just pressed initialise slow counter */

            if (Fast_Loop_Counter > (unsigned int)0)
                Fast_Loop_Counter--;
        }
        /* else if key pressed is not a rotation, then...*/
        else if (Key_Just_Pressed && (Current_Rot_Status & (Sel + Exit + Shutdown_Sw)))
        {
            if (Current_Rot_Status & Sel)
                Keypress_Read = Sel;
            else if (Current_Rot_Status & Exit)
                Keypress_Read = Exit;
            else if (Current_Rot_Status & Shutdown_Sw)
                Keypress_Read = Shutdown_Sw;
            Fast_Change = 1;
            wellerData.UI_Keypressed = true;
        }
        else    /* else not Key_just_Pressed */
        {
            Keypress_Read = 0;
            if (Slow_Loop_Counter > (unsigned int)0)
                Slow_Loop_Counter--;
        }
    }
        

    /********************************************/
    /*   Second Encoder                         */
    /********************************************/
    /*Read Rot Status and mask off bits of interest */
	Current_Rot_Status_RE2 = HMI_Port & (Vals_0_RE2 + Vals_1_RE2);
	Key_Just_Pressed_RE2 = (Current_Rot_Status_RE2 != Old_Rot_Status_RE2);
    /* set the flag */

    if(Key_Just_Pressed_RE2)
    {
        /* Only do this if something has changed - but neither of the select or exit buttons are pressed */
        if (Key_Just_Pressed_RE2  && !(Current_Rot_Status_RE2 & (Sel + Exit)))
        {
            /* Old Type Encoder is bi-phase input on two ports with */
            /*      Each detent click of the resolver being one change in phase*/
            /*      Thus one gray code change of the inputs occurs per click*/
            if Encoder_Type_Is_Old
            {
                if (Old_Rot_Status_RE2 == Phase_0_RE2)  /* From here need to work out if going up or down */
                {
                    if (Current_Rot_Status_RE2 == Phase_1_RE2)
                        Keypress_Read_RE2 = Rot_Up;
                    else
                        Keypress_Read_RE2 = Rot_Down;
                }
                else if (Old_Rot_Status_RE2 == Phase_1_RE2)  /* From here need to work out if going up or down */
                {
                    if (Current_Rot_Status_RE2 == Phase_2_RE2)
                        Keypress_Read_RE2 = Rot_Up;
                    else
                        Keypress_Read_RE2 = Rot_Down;
                }
                else if (Old_Rot_Status_RE2 == Phase_2_RE2)  /* From here need to work out if going up or down */
                {
                    if (Current_Rot_Status_RE2 == Phase_3_RE2)
                        Keypress_Read_RE2 = Rot_Up;
                    else
                        Keypress_Read_RE2 = Rot_Down;
                }
                else if (Old_Rot_Status_RE2 == Phase_3_RE2)  /* From here need to work out if going up or down */
                {
                    if (Current_Rot_Status_RE2 == Phase_0_RE2)
                        Keypress_Read_RE2 = Rot_Up;
                    else
                        Keypress_Read_RE2 = Rot_Down;
                }
                wellerData.UI_Keypressed_RE2 = true;
            }

            /* Type A - TYPE 2 on schematics - Encoder is biphase input on two ports with */
            /*      Each detent click of the resolver being four changes in phase*/
            /*      Thus one complete cycle of gray code occurs per click*/
            /*      Type A goes 11 -> 10 -> 00 -> 01 -> 11 and vice versa*/
            /*      This is the ALTRONICS device and my EBAY sourced devices */
            else if Encoder_Type_Is_TypeA
            {
                /* Phase_0_RE2 = 00*/
                /* From here need to work out if going up or down or reading crap*/
                /* CW 00 -> 01 */
                /* CCW 00-> 10 */
                /* But we do not want to act on these as it is mid-click*/
                if (Old_Rot_Status_RE2 == Phase_0_RE2)
                {
                    /* Have read crap*/
                    Keypress_Read_RE2 = 0;
                }
                /* From here need to work out if going up or down or reading crap*/
                /* CW 01 -> 11 */
                /* CCW 01-> 00 */
                /* But we do not want to act on these as it is mid-click*/
                else if (Old_Rot_Status_RE2 == Phase_1_RE2)
                {
                    if (Current_Rot_Status_RE2 == Phase_3_RE2)
                    {
                        /* have read noise again */
                        Keypress_Read_RE2 = 0;
                        wellerData.UI_Keypressed_RE2 = false;
                    }
                    else if (Current_Rot_Status_RE2 == Phase_0_RE2)
                    {
                        Keypress_Read_RE2 = Rot_Up;
                        wellerData.UI_Keypressed_RE2 = true;
                    }
                    else Keypress_Read_RE2 = 0;

                }
                /* From here need to work out if going up or down or reading crap*/
                /* CW 11 -> 10 */
                /* CCW 11-> 01 */
                /* This is it... do something*/
                else if (Old_Rot_Status_RE2 == Phase_2_RE2)
                {
                    if (Current_Rot_Status_RE2 == Phase_3_RE2)
                    {
                        Keypress_Read_RE2 = Rot_Down;
                        wellerData.UI_Keypressed_RE2 = false;
                    }
                    else if (Current_Rot_Status_RE2 == Phase_1_RE2)
                    {
                        Keypress_Read_RE2 = Rot_Up;
                        wellerData.UI_Keypressed_RE2 = false;
                    }
                    else Keypress_Read_RE2 = 0;
                    
                }
                /* From here need to work out if going up or down or reading crap*/
                /* CW 10 -> 00 */
                /* CCW 10-> 11 */
                /* But we do not want to act on these as it is mid-click*/
                else if (Old_Rot_Status_RE2 == Phase_3_RE2)
                {
                    if (Current_Rot_Status_RE2 == Phase_1_RE2)
                    {
                        /* have read noise again */
                        Keypress_Read_RE2 = 0;
                        wellerData.UI_Keypressed_RE2 = false;
                    }
                    else if (Current_Rot_Status_RE2 == Phase_0_RE2)
                    {
                        Keypress_Read_RE2 = Rot_Down;
                        wellerData.UI_Keypressed_RE2 = true;
                    }
                    else Keypress_Read_RE2 = 0;
                }
            }
            /* Type B  - TYPE 2 on schematics -  Encoder is biphase input on two ports with */
            /*  This is the JAYCAR encoder. */
            /*      Each detent click of the resolver being two changes in phase*/
            /*      Thus one complete cycle of pseudo gray code occurs every 2nd click*/
            /*      Type B goes 11 -> 10 -> 00 CW on the first click then...*/
            /*                  00 -> 10 -> 11 CW on the second click*/
            /*                  11 -> 01 -> 00 CW on the first click, then...*/
            /*                  00 -> 01 -> 11 CW on the second click*/
            else if Encoder_Type_Is_TypeB
            {
                /* Phase_0_RE2 = 00*/
                /* From here need to work out if going up or down or reading crap*/
                /* CW 00 -> 10 */
                /* CCW 00-> 01 */
                if (Old_Rot_Status_RE2 == Phase_0_RE2)
                {
                    if (Current_Rot_Status_RE2 == Phase_1_RE2)
                    {
                        Keypress_Read_RE2 = Rot_Up;
                        wellerData.UI_Keypressed_RE2 = true;
                    }
                    else if (Current_Rot_Status_RE2 == Phase_3_RE2)
                    {
                        Keypress_Read_RE2 = Rot_Down;
                        wellerData.UI_Keypressed_RE2 = true;
                    }
                    else
                        Keypress_Read_RE2 = 0;
                    
                    /* The Jaycar encoders have reversed pinouts to 
                       the baseline code!*/
                }
                /* Phase_1_RE2 = 01*/
                /* This is an intermediate state as the encoder is clicked...*/
                /* Do not want to act on these */
                else if (Old_Rot_Status_RE2 == Phase_1_RE2)
                {
                    /* Have read crap*/
                    Keypress_Read_RE2 = 0;
                }
                /* Phase_2_RE2 = 11*/
                /* From here need to work out if going up or down or reading crap*/
                /* CW 11 -> 10 */
                /* CCW 11-> 01 */
                /* OK This is it... */
                else if (Old_Rot_Status_RE2 == Phase_2_RE2)
                {
                    if (Current_Rot_Status_RE2 == Phase_1_RE2)
                    {
                        Keypress_Read_RE2 = Rot_Down;
                        wellerData.UI_Keypressed_RE2 = true;
                    }
                    else if (Current_Rot_Status_RE2 == Phase_3_RE2)
                    {
                        Keypress_Read_RE2 = Rot_Up;
                        wellerData.UI_Keypressed_RE2 = true;
                    }
                    else
                        Keypress_Read_RE2 = 0;
                }
                /* Phase_3_RE2 = 10*/
                /* again an intermediate state */
                /* We do not want to act on these */
                else if (Old_Rot_Status_RE2 == Phase_3_RE2)  /* From here need to work out if going up or down */
                {
                    /* Have read crap*/
                    Keypress_Read_RE2 = 0;
                }
                else
                {
                    Keypress_Read_RE2 = 0;
                }
            }

            Slow_Loop_Counter = Slow_Counter_Init;	/* If key just pressed initialise slow counter */

            if (Fast_Loop_Counter > (unsigned int)0)
                Fast_Loop_Counter--;
        }

    }
    
    
    /********************************************/
    /*   Done with Second Encoder               */
    /********************************************/
    
	if (Slow_Loop_Counter == (unsigned int)0)
	{
		Fast_Change = 1;
		Fast_Loop_Counter = Fast_Counter_Init;
	}

	if (Fast_Loop_Counter == (unsigned int)0)   /* move into fast change of value for user */
	{
        Fast_Change = 100;
	}

	Old_Rot_Status = Current_Rot_Status;   /*Record Rot Status to allow comparison next ISR loop */
	Old_Rot_Status_RE2 = Current_Rot_Status_RE2;   /*Record Rot Status to allow comparison next ISR loop */
    
    // Increment User Interface Update Counter
    // This simply cycles and the UI is only updated at UI_DIV intervals of this
    wellerData.UI_Update_Counter++;
    
}


// *****************************************************************************
// *****************************************************************************
// Section: Application Local Functions
// *****************************************************************************
// *****************************************************************************
/************************************************************************/
/* 	Write Line 1 and Line 2 of LCD							   */
/************************************************************************/
void Update_LCD(void)
{
    /* Clear Screen */
    GLCD_ClearScreen();

    /* write line1 */
    GLCD_WriteString_12x7_buf(ScreenBuff,&(line1[0]),0, 0);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(line2[0]),0, 16);
    Refresh_LCD;
}

void Write_Boot_Ver()
{
    /* write value to screen buffer */
    GLCD_ClearRegion_buff(ScreenBuff, UI_BootClr_X1, UI_BootClr_Y1, UI_BootClr_X2, UI_BootClr_Y2);
    sprintf(line1, Line1_Init);
    sprintf(line2, Line2_Init);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(line1[0]),UI_BootVer_X, UI_BootVer_Y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(line2[0]),UI_BootMod_X, UI_BootMod_Y);
}


/***********************************************************************/
/* LDAC is tied low, output is at CSEL going high                      */
/* /SHDN is tied high so this input is not used                        */
/* CSEL must go low first                                              */
/* The DAC expects 16 bits in a transaction                            */
/* Four config bits then 12 bits of data MSB first                     */
/***********************************************************************/
int Read_ADC(int PSU_Channel, int Channel_Selected)
{
    int Value_Tmp, Read_1, Read_2, Read_3, Value_Read;


    if(PSU_Channel == PSU_Ch_1)
        PSU_CH1_ADC_ChipSelect_Assert;                //Select Device
    else
        PSU_CH2_ADC_ChipSelect_Assert;                //Select Device
    DelayUs(ADC_Tsucs);                               // More than 40nS

    PLIB_SPI_WRITE_C (PSU_SPI_Port, ADC_Read_CMD1 );  //Write first byte
    do {} while (PLIB_SPI_IsBusy(PSU_SPI_Port));
    Read_1 = PLIB_SPI_BufferRead(PSU_SPI_Port);                      // Read first word
    if(Channel_Selected == ADC_Voltage_Channel)
    {
        PLIB_SPI_WRITE_C (PSU_SPI_Port, ADC_Read_CMD2_CH0 );  //Write first byte
    }
    else
    {
        PLIB_SPI_WRITE_C (PSU_SPI_Port, ADC_Read_CMD2_CH1 );  //Write first byte
    }
    do {} while (PLIB_SPI_IsBusy(PSU_SPI_Port));
    Read_2 = PLIB_SPI_BufferRead(PSU_SPI_Port);                      // Read second word

    //    DelayUs(ADC_Tsample);                              // More than 1.5 clock cycles
    PLIB_SPI_WRITE_C (PSU_SPI_Port, ADC_Read_CMD3 );  //this is null
    do {} while (PLIB_SPI_IsBusy(PSU_SPI_Port));
    Read_3 = PLIB_SPI_BufferRead(PSU_SPI_Port);                      // Read third word

    DelayUs(ADC_Tcsh);
    if(PSU_Channel == PSU_Ch_1)
        PSU_CH1_ADC_ChipSelect_DeAssert;             //DeSelect Device
    else
        PSU_CH2_ADC_ChipSelect_DeAssert;             //DeSelect Device
    DelayUs(ADC_Tcsh);                               // More than Give it a sec to settle down

    Value_Read = Read_2 & ADC_Top_Bitmask;
    Value_Read = Value_Read * 256;  //Shift left 8 bits
    Value_Read += Read_3;
    return(Value_Read);
}



/***********************************************************************/
/* LDAC is tied low, output is at CSEL going high                      */
/* /SHDN is tied high so this input is not used                        */
/* CSEL must go low first                                              */
/* The DAC expects 16 bits in a transaction                            */
/* Four config bits then 12 bits of data MSB first                     */
/***********************************************************************/
void Write_DAC(int PSU_Channel, int Channel_Selected, int Value_To_Write)
{
    int Value_Tmp, Value_Tmp1;

    Value_To_Write = Value_To_Write & DAC_BitMask;    //should never be needed :)
    Value_Tmp1 = Value_To_Write & 0x000000FF; //bottom byte of word
    Value_Tmp = Value_To_Write >>8; //look at top byte of word only
    if(Channel_Selected == DAC_Voltage_Channel)
        Value_Tmp += DAC1_Write_CMD;
    else
        Value_Tmp += DAC2_Write_CMD;
        
    if(PSU_Channel == PSU_Ch_1)
        PSU_CH1_DAC_ChipSelect_Assert;                //Select Device
    else
        PSU_CH2_DAC_ChipSelect_Assert;                //Select Device
        
    DelayUs(DAC_Tcsl);                               // More than 40nS
    PLIB_SPI_WRITE_C (PSU_SPI_Port, Value_Tmp );     //Write top byte
    DelayUs(1);                                      // More than 40nS
    PLIB_SPI_BufferRead(PSU_SPI_Port);               // clear the read buffer - will be nothing here
    DelayUs(1);                                      // More than 40nS
    PLIB_SPI_WRITE_C (PSU_SPI_Port, Value_Tmp1 );     //Write bottom byte
    DelayUs(1);                                      // More than 40nS
    PLIB_SPI_BufferRead(PSU_SPI_Port);               // clear the read buffer - will be nothing here
    DelayUs(DAC_Tcsh);                               // More than Give it a sec to settle down

    if(PSU_Channel == PSU_Ch_1)
        PSU_CH1_DAC_ChipSelect_DeAssert;             //DeSelect Device
    else
        PSU_CH2_DAC_ChipSelect_DeAssert;             //DeSelect Device
    DelayUs(DAC_Tcsh);                               // More than Give it a sec to settle down

}


void WELLER_Set_Outputs()
{
    int Temp_Voltage, Temp_Current, Output_Temp;
    
    /* Write V1, I1, V2 and I2 */
    /****************************************************/
    /* write V1, I1, V2 and I2 to DAC                   */
    /*     check V1 is in bound                         */
    /*      greater than V_Min, I_Min                   */
    /*      less that wellerData.V_Max                  */
    /*      less than wellerData.I_Max                  */
    /****************************************************/

    /* deal with shutdown */
    if(wellerData.Shutdown_Output == true)
    {
        Write_DAC(PSU_Ch_1,DAC_Voltage_Channel,V_Min);
//        Write_DAC(PSU_Ch_1,DAC_Current_Channel,I_Min);
        Write_DAC(PSU_Ch_2,DAC_Voltage_Channel,V_Min);    
//        Write_DAC(PSU_Ch_2,DAC_Current_Channel,I_Min);
    }
    else
    {
        /* Remember this is all in mV */
        Temp_Voltage = wellerData.V1 + wellerData.V1_Offset; // Now check this is > 0
        Temp_Voltage = Temp_Voltage * wellerData.V1_Output_Cal; // and check the output is not too high
        Temp_Voltage = Temp_Voltage/1000; /* scale back to mV */
        if (Temp_Voltage < V_Min)
            Temp_Voltage = V_Min;
        if (Temp_Voltage > wellerData.V_Max)
            Temp_Voltage = wellerData.V_Max;
        Output_Temp = (Temp_Voltage *1000) / wellerData.Vout_Scale;
        Write_DAC(PSU_Ch_1,DAC_Voltage_Channel,Output_Temp);

        /* Remember this is all in mA */
        Temp_Current = wellerData.I1; // Now check this is > 0
        Temp_Current = Temp_Current * wellerData.I1_Cal; // and check the output is not too high
        Temp_Current = Temp_Current/1000; /* scale back to mV */
        if (Temp_Current < I_Min)
            Temp_Current = I_Min;
        if (Temp_Current > wellerData.I_Max)
            Temp_Current = wellerData.I_Max;
        Output_Temp = (Temp_Current *1000) / wellerData.Iout_Scale;
        Write_DAC(PSU_Ch_1,DAC_Current_Channel,Output_Temp);

        /* Do second Channel */
        Temp_Voltage = wellerData.V2 + wellerData.V2_Offset; // Now check this is > 0
        Temp_Voltage = Temp_Voltage * wellerData.V2_Output_Cal; // and check the output is not too high
        Temp_Voltage = Temp_Voltage/1000; /* scale back to mV */
        if (Temp_Voltage < V_Min)
            Temp_Voltage = V_Min;
        if (Temp_Voltage > wellerData.V_Max)
            Temp_Voltage = wellerData.V_Max;
        Output_Temp = (Temp_Voltage *1000) / wellerData.Vout_Scale;
        Write_DAC(PSU_Ch_2,DAC_Voltage_Channel,Output_Temp);    

        /* Remember this is all in mA */
        Temp_Current = wellerData.I2; // Now check this is > 0
        Temp_Current = Temp_Current * wellerData.I2_Cal; // and check the output is not too high
        Temp_Current = Temp_Current/1000; /* scale back to mV */
        if (Temp_Current < I_Min)
            Temp_Current = I_Min;
        if (Temp_Current > wellerData.I_Max)
            Temp_Current = wellerData.I_Max;
        Output_Temp = (Temp_Current *1000) / wellerData.Iout_Scale;
        Write_DAC(PSU_Ch_2,DAC_Current_Channel,Output_Temp);
    }
}

/*******************************************************************************
  Function:
    void Splash_Screen ( void )
  Remarks:
 * Presents start up screen, initialises display for idle state
******************************************************************************/
void Splash_Screen()
{    
    /* write TGM splash to screen buffer */
    WriteBMP(ScreenBuff, SC_Logo_Full, 0, 0, 128, 64);
    Refresh_LCD;
    DelayMs(2500);
    /* write version to screen buffer*/
    Write_Boot_Ver();
    Refresh_LCD;
    DelayMs(1000);
}



/*******************************************************************************
  Function:
    void Idle_Screen ( void )
  Remarks:
 * PResents start up screen, initialises display for idle state
******************************************************************************/
void Idle_Screen(void)
{    
    int Target_Temp, Process_Error; /* used to draw the bar */
    char V1_Set[20];
    char V1_Meas[20];
    char I1_Set[20];
    char I1_Meas[20];
    char V2_Set[20];
    char V2_Meas[20];
    char I2_Set[20];
    char I2_Meas[20];
    int Tx, Ty, Ex;

    /* set up the screen*/
    if(((wellerData.V1_Error) || (wellerData.V2_Error)) && ((!wellerData.I1_Error) && (!wellerData.I2_Error)))
        WriteBMP(ScreenBuff, VI_Set_Display_VErr, 0, 0, 128, 64);
    else if(((!wellerData.V1_Error) && (!wellerData.V2_Error)) && ((wellerData.I1_Error) || (wellerData.I2_Error)))
        WriteBMP(ScreenBuff, VI_Set_Display_IErr, 0, 0, 128, 64);
    else if(((wellerData.V1_Error) || (wellerData.V2_Error)) && ((wellerData.I1_Error) || (wellerData.I2_Error)))
        WriteBMP(ScreenBuff, VI_Set_Display_VIErr, 0, 0, 128, 64);
    else    
        WriteBMP(ScreenBuff, VI_Set_Display, 0, 0, 128, 64);
 
    /* load the strings */     
    sprintf(V1_Set, "%.2fV",(float)wellerData.V1/1000);
    sprintf(V2_Set, "%.2fV",(float)wellerData.V2/1000);
    sprintf(I1_Set, "%.2fA",(float)wellerData.I1/1000);
    sprintf(I2_Set, "%.2fA",(float)wellerData.I2/1000);
    sprintf(V1_Meas, "Pos %.2fV",(float)wellerData.V1_Meas/1000);
    sprintf(V2_Meas, "Neg %.2fV",(float)wellerData.V2_Meas/1000);
    sprintf(I1_Meas, "Pos %.2fA",(float)wellerData.I1_Meas/1000);
    sprintf(I2_Meas, "Neg %.2fA",(float)wellerData.I2_Meas/1000);

    if(wellerData.Num_Rails == 2)
    {    
        /* write the ,measured voltages */
        GLCD_WriteString_8x5_buf(ScreenBuff,&(V1_Meas[0]),UI_Idle_CH1x, UI_Idle_V1Measy);
        GLCD_WriteString_8x5_buf(ScreenBuff,&(I1_Meas[0]),UI_Idle_CH1x, UI_Idle_I1Measy);
        GLCD_WriteString_8x5_buf(ScreenBuff,&(V2_Meas[0]),UI_Idle_CH2x, UI_Idle_V2Measy);
        GLCD_WriteString_8x5_buf(ScreenBuff,&(I2_Meas[0]),UI_Idle_CH2x, UI_Idle_I2Measy);        


        if (wellerData.UI_Action == WELLER_ACTION_V1)
            {
            GLCD_WriteString_8x5_INV_buf(ScreenBuff,&(V1_Set[0]),UI_Idle_V1setx, UI_Idle_V1Measy);
            GLCD_WriteString_8x5_INV_buf(ScreenBuff,&(I1_Set[0]),UI_Idle_I1setx, UI_Idle_I1Measy);
            /* OK, this is a kludge - line above the inverse font to make it pretty */    
            if(wellerData.V1/1000 >= 10)
                Ex = 36;
            else
                Ex = 30;
            for(Tx = UI_Idle_V1setx; Tx < Ex;Tx++)
                {
                GLCD_SetPixelBuf(ScreenBuff, Tx,UI_Idle_V1Measy-1, 1);
                }

            for(Tx = UI_Idle_I1setx; Tx < 30;Tx++)
                {
                GLCD_SetPixelBuf(ScreenBuff, Tx,UI_Idle_I1Measy-1, 1);
                }
        }
        else
            {
            GLCD_WriteString_8x5_buf(ScreenBuff,&(V1_Set[0]),UI_Idle_V1setx, UI_Idle_V1Measy);
            GLCD_WriteString_8x5_buf(ScreenBuff,&(I1_Set[0]),UI_Idle_I1setx, UI_Idle_I1Measy);
            }
        if (wellerData.UI_Action == WELLER_ACTION_V2)
            {
            GLCD_WriteString_8x5_INV_buf(ScreenBuff,&(V2_Set[0]),UI_Idle_V2setx, UI_Idle_V2Measy);
            GLCD_WriteString_8x5_INV_buf(ScreenBuff,&(I2_Set[0]),UI_Idle_I2setx, UI_Idle_I2Measy);
            /* OK, this is a kludge - line above the inverse font to make it pretty */    
            if(wellerData.V2/1000 >= 10)
                Ex = 36;
            else
                Ex = 30;
            for(Tx = UI_Idle_V2setx; Tx < Ex;Tx++)
                {
                GLCD_SetPixelBuf(ScreenBuff, Tx,UI_Idle_V2Measy-1, 1);
                }

            for(Tx = UI_Idle_I2setx; Tx < 30;Tx++)
                {
                GLCD_SetPixelBuf(ScreenBuff, Tx,UI_Idle_I2Measy-1, 1);
                }
            }
        else
            {
            GLCD_WriteString_8x5_buf(ScreenBuff,&(V2_Set[0]),UI_Idle_V2setx, UI_Idle_V2Measy);
            GLCD_WriteString_8x5_buf(ScreenBuff,&(I2_Set[0]),UI_Idle_I2setx, UI_Idle_I2Measy);
            }
        }
    else if(wellerData.Num_Rails == 1)
    {
        /* do single channel string */
        sprintf(V1_Meas, "%.2fV",(float)wellerData.V1_Meas/1000);
        sprintf(I1_Meas, "%.2fA",(float)wellerData.I1_Meas/1000);
        /* write the ,measured voltages */
        GLCD_WriteString_12x7_buf(ScreenBuff,&(V1_Meas[0]),UI_Idle_CH1x_Single, UI_Idle_V1_Single_Measy);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(I1_Meas[0]),UI_Idle_CH1x_Single, UI_Idle_I1_Single_Measy);

        GLCD_WriteString_8x5_INV_buf(ScreenBuff,&(V1_Set[0]),UI_Idle_V1setx, UI_Idle_V1_Single_Measy);
        GLCD_WriteString_8x5_INV_buf(ScreenBuff,&(I1_Set[0]),UI_Idle_I1setx, UI_Idle_I1_Single_Measy);
        /* OK, this is a kludge - line above the inverse font to make it pretty */    
        if(wellerData.V1/1000 >= 10)
            Ex = 36;
        else
            Ex = 30;
        for(Tx = UI_Idle_V1setx; Tx < Ex;Tx++)
            {
            GLCD_SetPixelBuf(ScreenBuff, Tx,UI_Idle_V1_Single_Measy-1, 1);
            }

        for(Tx = UI_Idle_I1setx; Tx < 30;Tx++)
            {
            GLCD_SetPixelBuf(ScreenBuff, Tx,UI_Idle_I1_Single_Measy-1, 1);
            }
    }
    else
    {
       WriteBMP(ScreenBuff, Oops, 0, 0, 128, 64);
    } 

    
    /* Clear the lock */
   Refresh_LCD;
}

/*******************************************************************************
  Function:
    void WELLER_Initialize ( void )

  Remarks:
    See prototype in weller.h.
******************************************************************************/
void REFLOW_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    wellerData.state = WELLER_STATE_INIT;
    wellerData.UI_Timer = DRV_HANDLE_INVALID;
    wellerData.UI_Count = 3;
    wellerData.UI_Update_Counter = 0;
    wellerData.UI_Update_Display = true;
    wellerData.UI_Display_Lockout = false;
    wellerData.UI_Keypressed = false;
    wellerData.UI_Keypressed_RE2 = false;
    wellerData.UI_Action = WELLER_ACTION_V1;
    wellerData.V1 = V_Init; /* start with init from header, update from EEPROM */
    wellerData.I1 = I_Init; /* start with init from header, update from EEPROM */
    wellerData.V2 = V_Init; /* start with init from header, update from EEPROM */
    wellerData.I2 = I_Init; /* start with init from header, update from EEPROM */
    wellerData.V_Max = V_Min_Setup;   /* should pull from EEPROM */
    wellerData.I_Max = I_Init;   /* should pull from EEPROM */
    wellerData.Tracking = Tracking_Default;  /* should pull from EEPROM */
    wellerData.Num_Rails = Num_Rails_Default;  /* should pull from EEPROM */
    wellerData.Transformer_VA = Transformer_VA_Min; /* should pull from EEPROM */
    wellerData.V1_Offset = V_Offset_Default; /* should pull from EEPROM */
    wellerData.V2_Offset = V_Offset_Default; /* should pull from EEPROM */
    wellerData.I1_Offset = I_Offset_Default; /* should pull from EEPROM */
    wellerData.I2_Offset = I_Offset_Default; /* should pull from EEPROM */
    wellerData.V1_Output_Cal =  Cal_Init; /* should pull from EEPROM */
    wellerData.V2_Output_Cal =  Cal_Init; /* should pull from EEPROM */
    wellerData.V1_Read_Cal =  Cal_Init; /* should pull from EEPROM */
    wellerData.V2_Read_Cal =  Cal_Init; /* should pull from EEPROM */    
    wellerData.I1_Cal =  Cal_Init; /* should pull from EEPROM */
    wellerData.I2_Cal =  Cal_Init; /* should pull from EEPROM */
    wellerData.heartbeatTimer = DRV_HANDLE_INVALID;
    wellerData.heartbeatCount = 0;
    wellerData.heartbeatToggle = false;
    wellerData.MemoryBankSelected = 0;
    wellerData.UI_Fast_Count = Fast_Counter_Init;
    wellerData.UI_Slow_Count = Slow_Counter_Init;
    wellerData.UI_Speed = Speed_Init;
    wellerData.Revert_To_Idle_Counter = Revert_To_Idle;
    wellerData.I1_Meas = 0;   /* will be updated each read cycle */
    wellerData.V1_Meas = 0;   /* will be updated each read cycle */
    wellerData.I2_Meas = 0;   /* will be updated each read cycle */
    wellerData.V2_Meas = 0;   /* will be updated each read cycle */
    /* you just divide the required voltage or current in uV or uA to get the required value */
    wellerData.Vout_Scale = (1000*Voltage_Output_DAC_FSD_mV*Feedback_Voltage_Divider)/DAC_Resolution; /* scale in uV per bit */
    wellerData.Iout_Scale = ((1000*((1000*Current_Output_DAC_FSD_mV)/Current_Sense_Resistor_mOhms)) / Current_Sense_Amplifier_Gain)/DAC_Resolution; /* scale in uA per bit */
    /* you just multiply the ADC value by these to get real V or A measured */
    wellerData.Vmeas_Scale = (1000*Measurement_ADC_FSD_mV*Feedback_Voltage_Divider)/ADC_Resolution; /* scale in uV per bit */
    wellerData.Imeas_Scale = ((1000*((1000*Measurement_ADC_FSD_mV)/Current_Sense_Resistor_mOhms)) / Current_Sense_Amplifier_Gain)/ADC_Resolution; /* scale in uA per bit */
    wellerData.Update_Outputs = false; /* start with no update */
    wellerData.Shutdown_Output = false; /* start with output on */
    wellerData.V1_Error = false;  /* start out assuming things are OK! */
    wellerData.V2_Error = false;  /* start out assuming things are OK! */
    wellerData.I1_Error = false;  /* start out assuming things are OK! */
    wellerData.I2_Error = false;  /* start out assuming things are OK! */
    /* set port E to drive logic high for encoder / buttons*/
    Drive_PortE_Out;
    EEPROM_Disable_Hold;
}


/******************************************************************************/
//  Function:
//    void WELLER_EEPROM_Initialize ( void )
//    
// AIm
//      - Set up EEPROM for operation
//     - Read in Init values stored in EEPROM
/*******************************************************************************/
void WELLER_EEPROM_Initialize(void)
{
    int Read_Temp; /* coeffs stored in an integer */
    
     /* this function clears write protect and any other necessary housekeeping*/
    EEPROM_Init();
                
    /* Read in stored V1 register for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V1_Offset_In_Mem), &wellerData.V1, 4 );
    if (wellerData.V1 > V_Limit_mV)
        wellerData.V1 = V_Limit_mV;
    else if (wellerData.V1 < V_Min)
        wellerData.V1 = V_Min;

    /* Read in stored I1 register for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I1_Offset_In_Mem), &wellerData.I1, 4 );
    if (wellerData.I1 > I_Limit_mA)
        wellerData.I1 = I_Limit_mA;
    else if (wellerData.I1 < I_Min)
        wellerData.I1 = I_Min;

    /* Read in stored V2 register for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V2_Offset_In_Mem), &wellerData.V2, 4 );
    if (wellerData.V2 > V_Limit_mV)
        wellerData.V2 = V_Limit_mV;
    else if (wellerData.V2 < V_Min)
        wellerData.V2 = V_Min;

    /* Read in stored I2 register for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I2_Offset_In_Mem), &wellerData.I2, 4 );
    if (wellerData.I2 > I_Limit_mA)
        wellerData.I2 = I_Limit_mA;
    else if (wellerData.I2 < I_Min)
        wellerData.I2 = I_Min;
                
    /* Read in stored V MAx for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V_Max_Offset), &wellerData.V_Max, 4 );
    if (wellerData.V_Max > V_Limit_mV)
        wellerData.V_Max = V_Limit_mV;
    else if (wellerData.V_Max < V_Min_Setup)
        wellerData.V_Max = V_Min_Setup;

    /* Read in stored I_MAX for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I_Max_Offset), &wellerData.I_Max, 4 );
    if (wellerData.I_Max > I_Limit_mA)
        wellerData.I_Max = I_Lim_Default;
    else if (wellerData.I_Max < I_Min)
        wellerData.I_Max = I_Lim_Default;

    /* Read in stored Tracking status for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + Tracking_Offset), &wellerData.Tracking, 4 );
    if (wellerData.Tracking != 0)
        wellerData.Tracking = 1;

    /* Read in stored number of rails for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + Num_Rails_Offset), &wellerData.Num_Rails, 4 );
    if (wellerData.Num_Rails > 2)
        wellerData.Num_Rails = 2;
    else if (wellerData.Num_Rails < 2) 
        wellerData.Num_Rails = 1;

    /* Read in stored VA Rating of each Rail transformer winding for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + Transformer_VA_Offset), &wellerData.Transformer_VA, 4 );
    if (wellerData.Transformer_VA > Transformer_VA_Max)
        wellerData.Transformer_VA = Transformer_VA_Max;
    else if (wellerData.Transformer_VA < Transformer_VA_Min)
        wellerData.Transformer_VA = Transformer_VA_Min;
    
    /* Read in stored V1 measurement offset voltage for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V1_Offset_Offset), &wellerData.V1_Offset, 4 );
    if (wellerData.V1_Offset > V_Offset_Max)
        wellerData.V1_Offset = V_Offset_Max;
    else if (wellerData.V1_Offset < V_Offset_Min)
        wellerData.V1_Offset = V_Offset_Min;

    /* Read in stored V2 measurement offset voltage for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V2_Offset_Offset), &wellerData.V2_Offset, 4 );
    if (wellerData.V2_Offset > V_Offset_Max)
        wellerData.V2_Offset = V_Offset_Max;
    else if (wellerData.V2_Offset < V_Offset_Min)
        wellerData.V2_Offset = V_Offset_Min;

    /* Read in stored V1 calibration coefficient for PSU output */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V1_Output_Cal_Offset), &wellerData.V1_Output_Cal, 4 );
    if (wellerData.V1_Output_Cal > V_Cal_Max)
        wellerData.V1_Output_Cal = Cal_Init;
    else if (wellerData.V1_Output_Cal < V_Cal_Min)
        wellerData.V1_Output_Cal = Cal_Init;

    /* Read in stored V2 calibration coefficient for PSU output */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V2_Output_Cal_Offset), &wellerData.V2_Output_Cal, 4 );
    if (wellerData.V2_Output_Cal > V_Cal_Max)
        wellerData.V2_Output_Cal = Cal_Init;
    else if (wellerData.V2_Output_Cal < V_Cal_Min)
        wellerData.V2_Output_Cal = Cal_Init;

    /* Read in stored V1 calibration coefficient for read voltage */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V1_Read_Cal_Offset), &wellerData.V1_Read_Cal, 4 );
    if (wellerData.V1_Read_Cal > V_Cal_Max)
        wellerData.V1_Read_Cal = Cal_Init;
    else if (wellerData.V1_Read_Cal < V_Cal_Min)
        wellerData.V1_Read_Cal = Cal_Init;

    /* Read in stored V2 calibration coefficient for read voltage */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V2_Read_Cal_Offset), &wellerData.V2_Read_Cal, 4 );
    if (wellerData.V2_Read_Cal > V_Cal_Max)
        wellerData.V2_Read_Cal = Cal_Init;
    else if (wellerData.V2_Read_Cal < V_Cal_Min)
        wellerData.V2_Read_Cal = Cal_Init;

    /* Read in stored I1 measurement Offset voltage for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I1_Offset_Offset), &wellerData.I1_Offset, 4 );
    if (wellerData.I1_Offset > I_Offset_Max)
        wellerData.I1_Offset = I_Offset_Max;
    else if (wellerData.I1_Offset < I_Offset_Min)
        wellerData.I1_Offset = I_Offset_Min;
                
    /* Read in stored I2 measurement Offset voltage for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I2_Offset_Offset), &wellerData.I2_Offset, 4 );
    if (wellerData.I2_Offset > I_Offset_Max)
        wellerData.I2_Offset = I_Offset_Max;
    else if (wellerData.I2_Offset < I_Offset_Min)
        wellerData.I2_Offset = I_Offset_Min;

    /* Read in stored I1 Calibration scale for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I1_Cal_Offset), &wellerData.I1_Cal, 4 );
    if (wellerData.I1_Cal > I_Cal_Max)
        wellerData.I1_Cal = Cal_Init;
    else if (wellerData.I1_Cal < I_Cal_Min)
        wellerData.I1_Cal = Cal_Init;

     /* Read in stored I2 Calibration for PSU */
    HDWordReadSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I2_Cal_Offset), &wellerData.I2_Cal, 4 );
    if (wellerData.I2_Cal > I_Cal_Max)
        wellerData.I2_Cal = Cal_Init;
    else if (wellerData.I2_Cal < I_Cal_Min)
        wellerData.I2_Cal = Cal_Init;
    
}

/******************************************************************************/
//  Function:
//    void WELLER_EEPROM_READ_COMPLETE ( void )
//    
// AIm
//     - Tell user we are done
/*******************************************************************************/
void WELLER_EEPROM_READ_COMPLETE( void )
{
    char ER_line_1[20];
    char ER_line_2[20];
    char ER_line_3[20];
    char ER_line_4[20];

    /* clear the screen */
    GLCD_ClearScreen_buff(ScreenBuff);
    /* SET UP THE STRINGS */
    sprintf(ER_line_1, "                 ");
    sprintf(ER_line_2, "      EEPROM     ");
    sprintf(ER_line_3, "  Read Complete  ");
    sprintf(ER_line_4, "                 ");
    GLCD_WriteString_12x7_buf(ScreenBuff,&(ER_line_1[0]),Tracking_L1x, Tracking_L1y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(ER_line_2[0]),Tracking_L1x, Tracking_L2y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(ER_line_3[0]),Tracking_L1x, Tracking_L3y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(ER_line_4[0]),Tracking_L1x, Tracking_L4y);
    Refresh_LCD;
}



/******************************************************************************/
//  Function:
//    void WELLER_EEPROM_Save ( void )
// AIm
//     - Save the data set to EEPROM
// call this after user presses "Select" on data entry
// Save voltage changes and cal parameters.
/*******************************************************************************/
void WELLER_EEPROM_Save( void )
{
    char line[16];
    
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V1_Offset_In_Mem), wellerData.V1);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I1_Offset_In_Mem), wellerData.I1);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V2_Offset_In_Mem), wellerData.V2);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I2_Offset_In_Mem), wellerData.I2);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V_Max_Offset), wellerData.V_Max);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I_Max_Offset), wellerData.I_Max);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + Tracking_Offset), (int)(wellerData.Tracking));
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + Num_Rails_Offset), wellerData.Num_Rails);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + Transformer_VA_Offset), wellerData.Transformer_VA);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V1_Offset_Offset), wellerData.V1_Offset);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V2_Offset_Offset), wellerData.V2_Offset);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V1_Output_Cal_Offset), wellerData.V1_Output_Cal);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V2_Output_Cal_Offset), wellerData.V2_Output_Cal);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V1_Read_Cal_Offset), wellerData.V1_Read_Cal);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + V2_Read_Cal_Offset), wellerData.V2_Read_Cal);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I1_Offset_Offset), wellerData.I1_Offset);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I2_Offset_Offset), wellerData.I2_Offset);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I1_Cal_Offset), wellerData.I1_Cal);
    HDWordWriteSPI(((wellerData.MemoryBankSelected*ParmSet_Array_Size) + I2_Cal_Offset), wellerData.I2_Cal);
}

/******************************************************************************/
//  Function:
//    void WELLER_Tracking ( void )
//    
// AIm
//     - Allow user to set dual tracking or independent
/*******************************************************************************/
void WELLER_Tracking( void )
{
    char TD_line_1[20];
    char TD_line_2[20];
    char TD_line_3[20];
    char TD_line_4[20];

    /* clear the screen */
    GLCD_ClearScreen_buff(ScreenBuff);
    /* SET UP THE STRINGS */
    sprintf(TD_line_1, "   Output Mode:  ");
    if (wellerData.UI_Action == WELLER_ACTION_YES)
    {
        WriteBMP(ScreenBuff, TRACKING_DUAL, 0, 0, 128, 64);
        sprintf(TD_line_2, "Dual Tracking");
    }
    else
    {
        WriteBMP(ScreenBuff, TRACKING_IND, 0, 0, 128, 64);
        sprintf(TD_line_2, "Independent");
    }
    sprintf(TD_line_3, "                ");
    sprintf(TD_line_4, "                ");
    GLCD_WriteString_12x7_buf(ScreenBuff,&(TD_line_1[0]),Tracking_L1x, Tracking_L1y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(TD_line_2[0]),Tracking_L1x, Tracking_L2y);
    Refresh_LCD;
}


/******************************************************************************/
//  Function:
//    void WELLER_Cal ( void )
//    
// AIm
//     - Display Cal Data 
//       this applies to V1, I1, V2 and I2
//    V1_Offset,  V2_Offset,  V1_ScaleFSD, V2_ScaleFSD, I1_Offset, I2_Offset, I1_ScaleFSD, I2_ScaleFSD
/*******************************************************************************/
void WELLER_Cal( void )

{
    char Cal_line_1[20];
    char Cal_line_2[20];
    char Cal_line_3[20];
    char Cal_line_4[20];
    char Cal_line_5[20];
    /* clear the screen */
    GLCD_ClearScreen_buff(ScreenBuff);
    /* SET UP THE STRINGS */

    switch (wellerData.state)
    {
        case WELLER_STATE_CAL_V1_OUTPUT_OFFSET:
            {
                sprintf(Cal_line_1, "Ch # 1 Output   ");
                sprintf(Cal_line_2, "Offset measured ");
                sprintf(Cal_line_3, "At 0.0 volts set");
                sprintf(Cal_line_4, "%d mV", wellerData.V1_Offset);
            }
        break;
        case WELLER_STATE_CAL_V2_OUTPUT_OFFSET:
            {
                sprintf(Cal_line_1, "Ch # 2 Output   ");
                sprintf(Cal_line_2, "Offset measured ");
                sprintf(Cal_line_3, "At 0.0 volts set");
                sprintf(Cal_line_4, "%d mV", wellerData.V2_Offset);            }
        break;
        case WELLER_STATE_CAL_V1_SET_SCALE:
            {
                sprintf(Cal_line_1, "Ch#1 Voltage    ");
                sprintf(Cal_line_2, "SET Correction");
                sprintf(Cal_line_3, "Coefficient     ");
                sprintf(Cal_line_4, "Scale: %.3f", ((float)wellerData.V1_Output_Cal)/1000);
            }
        break;
        case WELLER_STATE_CAL_V2_SET_SCALE:
            {
                sprintf(Cal_line_1, "Ch#2 Voltage    ");
                sprintf(Cal_line_2, "SET Correction  ");
                sprintf(Cal_line_3, "Coefficient     ");
                sprintf(Cal_line_4, "Scale: %.3f", ((float)wellerData.V2_Output_Cal)/1000);
            }
        break;
        case WELLER_STATE_CAL_V1_READ_SCALE:
            {
                sprintf(Cal_line_1, "Ch # 1 Voltage  ");
                sprintf(Cal_line_2, "READ Correction ");
                sprintf(Cal_line_3, "Coefficient     ");
                sprintf(Cal_line_4, "Scale: %.3f", ((float)wellerData.V1_Read_Cal)/1000);
                sprintf(Cal_line_5, "Meas V1: %.2f", ((float)wellerData.V1_Meas)/1000);
           }
        break;
        case WELLER_STATE_CAL_V2_READ_SCALE:
            {
                sprintf(Cal_line_1, "Ch # 2 Voltage  ");
                sprintf(Cal_line_2, "READ Correction ");
                sprintf(Cal_line_3, "Coefficient     ");
                sprintf(Cal_line_4, "Scale: %.3f", ((float)wellerData.V2_Read_Cal)/1000);
                sprintf(Cal_line_5, "Meas V2: %.2f", ((float)wellerData.V2_Meas)/1000);
            }
        break;
        case WELLER_STATE_CAL_I1_OFFSET:
            {
                sprintf(Cal_line_1, "Ch # 1 Current  ");
                sprintf(Cal_line_2, "Read Offset     ");
                sprintf(Cal_line_3, "%d mA", wellerData.I1_Offset);
                sprintf(Cal_line_4, "                ");
                sprintf(Cal_line_5, "Meas I1: %.2f", ((float)wellerData.I1_Meas)/1000);
        }
        break;
        case WELLER_STATE_CAL_I2_OFFSET:
            {
                sprintf(Cal_line_1, "Ch # 2 Current  ");
                sprintf(Cal_line_2, "Read Offset     ");
                sprintf(Cal_line_3, "%d mA", wellerData.I2_Offset);
                sprintf(Cal_line_4, "                ");
                sprintf(Cal_line_5, "Meas I2: %.2f", ((float)wellerData.I2_Meas)/1000);
            }
        break;
        case WELLER_STATE_CAL_I1_SCALE:
            {
                sprintf(Cal_line_1, "Ch # 1 Current  ");
                sprintf(Cal_line_2, "Correction      ");
                sprintf(Cal_line_3, "Coefficient     ");
                sprintf(Cal_line_4, "Scale: %.3f", ((float)wellerData.I1_Cal)/1000);
                sprintf(Cal_line_5, "Meas I1: %.2f", ((float)wellerData.I1_Meas)/1000);
            }
        break;
        case WELLER_STATE_CAL_I2_SCALE:
            {
                sprintf(Cal_line_1, "Ch # 2 Current  ");
                sprintf(Cal_line_2, "Correction      ");
                sprintf(Cal_line_3, "Coefficient     ");
                sprintf(Cal_line_4, "Scale: %.3f", ((float)wellerData.I2_Cal)/1000);
                sprintf(Cal_line_5, "Meas I2: %.2f", ((float)wellerData.I2_Meas)/1000);
            }
        break;
        default:
        {
                sprintf(Cal_line_1, "Damn!!!!  ");
                sprintf(Cal_line_2, "That was not the");
                sprintf(Cal_line_3, "Plan at all!");
                sprintf(Cal_line_4, ":(");
        };
    }
        

    GLCD_WriteString_12x7_buf(ScreenBuff,&(Cal_line_1[0]),Tracking_L1x, Tracking_L1y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Cal_line_2[0]),Tracking_L1x, Tracking_L2y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Cal_line_3[0]),Tracking_L1x, Tracking_L3y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Cal_line_4[0]),Tracking_L1x, Tracking_L4y);
    if ((wellerData.state == WELLER_STATE_CAL_V1_READ_SCALE) || (wellerData.state == WELLER_STATE_CAL_V2_READ_SCALE) ||
            (wellerData.state == WELLER_STATE_CAL_I1_OFFSET) || (wellerData.state == WELLER_STATE_CAL_I2_OFFSET) ||
            (wellerData.state == WELLER_STATE_CAL_I1_SCALE) || (wellerData.state == WELLER_STATE_CAL_I2_SCALE))
    {
        GLCD_WriteString_8x5_buf(ScreenBuff,&(Cal_line_5[0]),Tracking_L1x, Tracking_L5y);
    }
    Refresh_LCD;
}


/******************************************************************************/
//  Function:
//    void WELLER_Transformer_VA ( void )
//    
// AIm
//     - Display Transformer VA Rating 
//       this applies to both rails
//       Current at user voltages defined by VA rating
/*******************************************************************************/
void WELLER_Transformer_VA( void )

{
    char VA_line_1[20];
    char VA_line_2[20];
    char VA_line_3[20];
    char VA_line_4[20];

    /* clear the screen */
    GLCD_ClearScreen_buff(ScreenBuff);
    /* SET UP THE STRINGS */
    sprintf(VA_line_1, "Transformer     ");
    sprintf(VA_line_2, "Power Rating    ");
    sprintf(VA_line_3, "%d VA", wellerData.Transformer_VA);
    sprintf(VA_line_4, "                ");
    GLCD_WriteString_12x7_buf(ScreenBuff,&(VA_line_1[0]),Tracking_L1x, Tracking_L1y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(VA_line_2[0]),Tracking_L1x, Tracking_L2y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(VA_line_3[0]),Tracking_L1x, Tracking_L3y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(VA_line_4[0]),Tracking_L1x, Tracking_L4y);
    Refresh_LCD;
}

/******************************************************************************/
//  Function:
//    void WELLER_Maximum_Voltage ( void )
//    
// AIm
//     - Display MAximum Voltage 
//       this applies to both rails
//       Max voltage is independent of the max current - current defined by VA rating
/*******************************************************************************/
void WELLER_Max_Voltage( void )

{
    char TV_line_1[20];
    char TV_line_2[20];
    char TV_line_3[20];
    char TV_line_4[20];

    /* clear the screen */
    GLCD_ClearScreen_buff(ScreenBuff);
    /* SET UP THE STRINGS */
    sprintf(TV_line_1, "Maximum Output");
    sprintf(TV_line_2, "Voltage: %.1f V", ((float)wellerData.V_Max/1000));
    sprintf(TV_line_3, "Requires %.0f Volt", ((float)(wellerData.V_Max +Losses_in_Rect)/1.414)/1000 + Loss_Margin/1000 );
    sprintf(TV_line_4, "Transformer");
    GLCD_WriteString_12x7_buf(ScreenBuff,&(TV_line_1[0]),Tracking_L1x, Tracking_L1y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(TV_line_2[0]),Tracking_L1x, Tracking_L2y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(TV_line_3[0]),Tracking_L1x, Tracking_L3y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(TV_line_4[0]),Tracking_L1x, Tracking_L4y);
    Refresh_LCD;
}

/******************************************************************************/
//  Function:
//    void WELLER_Max_Current ( void )
//    
// AIm
//     - Display MAxumum Allowed Current Current
//       this applies at low voltages and may be in excess f the transformer VA rating
//       Must be less that the current 0.8 time the rating of the inductor in the power supply
/*******************************************************************************/
void WELLER_Max_Current( void )

{
    char MC_line_1[20];
    char MC_line_2[20];
    char MC_line_3[20];


    /* clear the screen */
    GLCD_ClearScreen_buff(ScreenBuff);
    /* SET UP THE STRINGS */
    sprintf(MC_line_1, "Absolute Maximum");
    sprintf(MC_line_2, "Current Limit:");
    sprintf(MC_line_3, "%.1f Amps", ((float)wellerData.I_Max)/1000);

    WriteBMP(ScreenBuff, Fuse, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(MC_line_1[0]),Tracking_L1x, Tracking_L1y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(MC_line_2[0]),Tracking_L1x, Tracking_L2y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(MC_line_3[0]),Tracking_L1x, Tracking_L3y);
    
    Refresh_LCD;
}


/******************************************************************************/
//  Function:
//    void WELLER_Num_Outputs ( void )
//    
// AIm
//     - Display Number of outputs
/*******************************************************************************/
void WELLER_Num_Outputs( void )

{
    char NO_line_1[20];
    char NO_line_2[20];

    /* clear the screen */
    GLCD_ClearScreen_buff(ScreenBuff);
    /* SET UP THE STRINGS */
    sprintf(NO_line_1, "Number of Rails:");
    if (wellerData.Num_Rails == 1)
    {
        WriteBMP(ScreenBuff, Single_Setup, 0, 0, 128, 64);
        sprintf(NO_line_2, "Single Rail");
    }
    else if (wellerData.Num_Rails == 2)
    {
        WriteBMP(ScreenBuff, Dual_Setup, 0, 0, 128, 64);
        sprintf(NO_line_2, "Dual Rail");
    }
    else
        sprintf(NO_line_2, "Oops thats odd");

    GLCD_WriteString_12x7_buf(ScreenBuff,&(NO_line_1[0]),Tracking_L1x, Tracking_L1y);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(NO_line_2[0]),Tracking_L1x, Tracking_L2y);
      Refresh_LCD;
}

/******************************************************************************/
//  Function:
//    void WELLER_Setup_Function ( void )
//    
// AIm
//     - Present options to user for choice of other functions
/*******************************************************************************/
void WELLER_Setup_Function( void )
{
    char SU_line_1[20];

    
    switch (wellerData.UI_Action)
    {
        /********************************************/
        /*  TODO                                    */
        /* Right bitmap, implement selection  state */
        /********************************************/
        case WELLER_ACTION_TRACKING:
        {
            WriteBMP(ScreenBuff, CHOOSE_TRACK, 0, 0, 128, 64);
            Refresh_LCD;
         }
        break;
        
        /********************************************/
        /*  TODO                                    */
        /* Right bitmap, implement input screens    */
        /********************************************/
        case WELLER_ACTION_POWER:
        {
            WriteBMP(ScreenBuff, CHOOSE_POWER, 0, 0, 128, 64);
            if (wellerData.Num_Rails == 1)
            {
                sprintf(SU_line_1, " N/A ");
                GLCD_WriteString_8x5_buf(ScreenBuff,&(SU_line_1[0]),SU_Tracking_L1x, SU_Tracking_L1y);
            }
            Refresh_LCD;
        }
        break;
        
        /********************************************/
        /*  TODO                                    */
        /* Right bitmap, implement input screens    */
        /********************************************/
        case WELLER_ACTION_CAL:
        {
            WriteBMP(ScreenBuff, CHOOSE_CAL, 0, 0, 128, 64);
            if (wellerData.Num_Rails == 1)
            {
                sprintf(SU_line_1, " N/A ");
                GLCD_WriteString_8x5_buf(ScreenBuff,&(SU_line_1[0]),SU_Tracking_L1x, SU_Tracking_L1y);
            }
            Refresh_LCD;
        }
        break;
        
    }
}


/******************************************************************************/
//  Function:
//    void WELLER_Set_Voltage ( void )
//    
// AIm
//     - Respond to User Interface Changes for Voltage
/*******************************************************************************/
void WELLER_Set_Voltage( void )
{
if (Keypress_Read == Rot_Up)
    {
        if(wellerData.UI_Action == WELLER_ACTION_V1)
        {
            wellerData.V1 +=  wellerData.UI_Speed * Voltage_Step;
            if (wellerData.V1 >= wellerData.V_Max)
            {
                wellerData.V1 = wellerData.V_Max;
            }

            if (wellerData.V1 > ((Assumed_Efficiency*1000000*(float)wellerData.Transformer_VA)/wellerData.I1))
            {
                wellerData.V1 = ((Assumed_Efficiency*1000000*(float)wellerData.Transformer_VA)/wellerData.I1);
            }
        }
        else if(wellerData.UI_Action == WELLER_ACTION_V2)
        {
            wellerData.V2 +=  wellerData.UI_Speed * Voltage_Step;
            if (wellerData.V2 >= wellerData.V_Max)
            {
                wellerData.V2 = wellerData.V_Max;
            }

            if (wellerData.V2 > ((Assumed_Efficiency*1000000*(float)wellerData.Transformer_VA)/wellerData.I2))
            {
                wellerData.V2 = ((Assumed_Efficiency*1000000*(float)wellerData.Transformer_VA)/wellerData.I2);
            }
        }
        /* check current settings are consistent */    
        if (wellerData.V1 > wellerData.V_Max)
            wellerData.V1 = wellerData.V_Max;
        if (wellerData.V2 > wellerData.V_Max)
            wellerData.V2 = wellerData.V_Max;
        /* This function displays the maximum current  */

        /* if tracking, V2 = V1 */
        if(wellerData.Tracking == 1)
        {
            wellerData.V2 = wellerData.V1;
        }
        wellerData.Update_Outputs = true;
        Idle_Screen();
    }    
    else if  (Keypress_Read == Rot_Down)
    {
        if (wellerData.UI_Action == WELLER_ACTION_V1)
        {
            wellerData.V1 -=  wellerData.UI_Speed * Voltage_Step;
            if (wellerData.V1 <= V_Min)
            {
                wellerData.V1 = V_Min;
            }
        }
        else if (wellerData.UI_Action == WELLER_ACTION_V2)
        {
            wellerData.V2 -=  wellerData.UI_Speed * Voltage_Step;
            if (wellerData.V2 <= V_Min)
            {
                wellerData.V2 = V_Min;
            }
        }

        /* check current settings are consistent */    
        if (wellerData.V1 > wellerData.V_Max)
            wellerData.V1 = wellerData.V_Max;
        if (wellerData.V2 > wellerData.V_Max)
            wellerData.V2 = wellerData.V_Max;

        /* if tracking, V2 = V1 */
        if(wellerData.Tracking == 1)
        {
            wellerData.V2 = wellerData.V1;
        }

        /* This updates and displays the output*/
        wellerData.Update_Outputs = true;
        Idle_Screen();
    }
    wellerData.UI_Keypressed = false;
}


/******************************************************************************/
//  Function:
//    void WELLER_Set_Current ( void )
//    
// AIm
//     - Respond to User Interface Changes for Current
/*******************************************************************************/
void WELLER_Set_Current( void )
{
if (Keypress_Read_RE2 == Rot_Up)
    {
        if(wellerData.UI_Action == WELLER_ACTION_V1)
        {
            wellerData.I1 +=  wellerData.UI_Speed * Current_Step;
            if (wellerData.I1 >= wellerData.I_Max)
            {
                wellerData.I1 = wellerData.I_Max;
            }

            if (wellerData.I1 > ((Assumed_Efficiency*1000000*(float)wellerData.Transformer_VA)/wellerData.V1))
            {
                wellerData.I1 = ((Assumed_Efficiency*1000000*(float)wellerData.Transformer_VA)/wellerData.V1);
            }
        }
        else if(wellerData.UI_Action == WELLER_ACTION_V2)
        {
            wellerData.I2 +=  wellerData.UI_Speed * Current_Step;
            if (wellerData.I2 >= I_Limit_mA)
            {
                wellerData.I2 = I_Limit_mA;
            }
            /* this checks the overall power rating driven current limit */
            if (wellerData.I2 > ((Assumed_Efficiency*1000000*(float)wellerData.Transformer_VA)/wellerData.V2))
            {
                wellerData.I2 = ((Assumed_Efficiency*1000000*(float)wellerData.Transformer_VA)/wellerData.V2);
            }
        }

        /* check current settings are consistent */    
        if (wellerData.I1 > wellerData.I_Max)
            wellerData.I1 = wellerData.I_Max;
        if (wellerData.I2 > wellerData.I_Max)
            wellerData.I2 = wellerData.I_Max;
        /* This function displays the maximum current  */

        /* if tracking, I2 = I1 */
        if(wellerData.Tracking)
        {
            wellerData.I2 = wellerData.I1;
        }

        /* update current limit */
        wellerData.Update_Outputs = true;
        Idle_Screen();
    }    
    else if  (Keypress_Read_RE2 == Rot_Down)
    {
        if (wellerData.UI_Action == WELLER_ACTION_V1)
        {
            wellerData.I1 -=  wellerData.UI_Speed * Current_Step;
            if (wellerData.I1 <= I_Min)
            {
                wellerData.I1 = I_Min;
            }
        }
        else if (wellerData.UI_Action == WELLER_ACTION_V2)
        {
            wellerData.I2 -=  wellerData.UI_Speed * Current_Step;
            if (wellerData.I2 <= I_Min)
            {
                wellerData.I2 = I_Min;
            }
        }

        /* check current settings are consistent */    
        if (wellerData.I1 > wellerData.I_Max)
            wellerData.I1 = wellerData.I_Max;
        if (wellerData.I2 > wellerData.I_Max)
            wellerData.I2 = wellerData.I_Max;
        /* This function displays the maximum current  */

        /* if tracking, I2 = I1 */
        if(wellerData.Tracking)
        {
            wellerData.I2 = wellerData.I1;
        }

        /* This updates and displays the output*/
        wellerData.Update_Outputs = true;
        Idle_Screen();
    }
wellerData.UI_Keypressed_RE2 = false;
}

/******************************************************************************/
//  Function:
//    void WELLER_Check_VI_Bounds()
//    
// AIm
//     - check the measure voltage and current against bounds and 
//     - set flags as required
/*******************************************************************************/
WELLER_Check_VI_Bounds()
{
    /* data is in wellerData.V1_Meas, V2_Meas, I1_Meas and I2_Meas */
    /* flags are in wellerData.V1_Error V2_Error, I1_Error and I2_Error*/

    if (wellerData.V1_Meas > (((wellerData.V1 * (100 + V_Bound_Percent))/100) + V_Bound_mV))
        wellerData.V1_Error = true;
    else if (wellerData.V1_Meas < (((wellerData.V1 * (100 - V_Bound_Percent))/100) - V_Bound_mV))
        wellerData.V1_Error = true;
    else 
        wellerData.V1_Error = false;
    wellerData.V2_Error = false;
    /* only set flag for second rail it if is actually there! */
    if (wellerData.Num_Rails == 2)
        {
        if (wellerData.V2_Meas > (((wellerData.V2 * (100 + V_Bound_Percent))/100) + V_Bound_mV))
            wellerData.V2_Error = true;
        else if (wellerData.V2_Meas < (((wellerData.V2 * (100 - V_Bound_Percent))/100) - V_Bound_mV))
            wellerData.V2_Error = true;
        else 
            wellerData.V2_Error = false;
        }
    
    if (wellerData.I1_Meas > ((wellerData.I1 * I_Bound)/100))
        wellerData.I1_Error = true;
    else    
        wellerData.I1_Error = false;            
    /* only set flag for second rail it if is actually there! */
    wellerData.I2_Error = false;
    if (wellerData.Num_Rails == 2)
        {
        if (wellerData.I2_Meas > ((wellerData.I2 * I_Bound)/100))
            wellerData.I2_Error = true;
        else    
            wellerData.I2_Error = false;            
        }
}


/******************************************************************************/
//  Function:
//    void WELLER_UI_Fast_Slow( int Fast, int Slow )
//    
// AIm
//     - Update Fast Count in a couple of places
/*******************************************************************************/
WELLER_UI_Fast_Slow(int Fast, int Slow)
{
    /* check Slow Counter - if this is non zero then decrement fast counter */
    if (wellerData.UI_Slow_Count)
        {
        if (wellerData.UI_Fast_Count)
            {
            wellerData.UI_Fast_Count--;
            }
        }
    else /* slow counter expired, go back to normal speed */ 
        {
            wellerData.UI_Fast_Count = Fast_Counter_Init;
        }
    
    /* if fast counter is expired, then go max speed*/
    if (wellerData.UI_Fast_Count == 0)
        wellerData.UI_Speed = Fast;
    else
        wellerData.UI_Speed = Slow;
    /* reset slow counter to init value */
    wellerData.UI_Slow_Count = Slow_Counter_Init;
}


/******************************************************************************
  Function:
    void WELLER_Tasks ( void )

  Remarks:
    See prototype in weller.h.
****************************************************************************/
void REFLOW_Tasks ( void )
{
    int il, jl;
    char DisplayLine[20];
    char DisplayLine1[20];
    char DisplayLine2[20];
    int Read_Val_TMP;
 
    /* keep track of how often we run through the loop */
    wellerData.UI_Update_Counter++;
    
    /* Signal the application's heartbeat. */
    if (wellerData.heartbeatToggle == true)
    {
       // SYS_PORTS_PinToggle(PORTS_ID_0, APP_HEARTBEAT_PORT,
        //                    APP_HEARTBEAT_PIN);
        wellerData.heartbeatToggle = false;
    }


    /* if the timer has gone off, read the ADC */
    if( wellerData.UI_Update_Display == true)
        {    
            Read_Val_TMP = Read_ADC(PSU_Ch_1, ADC_Voltage_Channel);
            Read_Val_TMP = Read_Val_TMP & 0x00000FFF;    /* mask off any crud */
            wellerData.V1_Meas = (1 - Voltage_Filter_Coeff)* wellerData.V1_Meas + Voltage_Filter_Coeff*(((wellerData.Vmeas_Scale * wellerData.V1_Read_Cal)/1000) * Read_Val_TMP)/1000;  /* mV */

            Read_Val_TMP = Read_ADC(PSU_Ch_1, ADC_Current_Channel);
            Read_Val_TMP = Read_Val_TMP & 0x00000FFF;    /* mask off any crud */
            wellerData.I1_Meas =  (1 - Current_Filter_Coeff)* wellerData.I1_Meas + Current_Filter_Coeff * (wellerData.I1_Offset + (((wellerData.Imeas_Scale * wellerData.I1_Cal)/1000) * Read_Val_TMP)/1000);  /* mV */

            Read_Val_TMP = Read_ADC(PSU_Ch_2, ADC_Voltage_Channel);
            Read_Val_TMP = Read_Val_TMP & 0x00000FFF;    /* mask off any crud */
            wellerData.V2_Meas = (1 - Voltage_Filter_Coeff)* wellerData.V2_Meas + Voltage_Filter_Coeff*(((wellerData.Vmeas_Scale * wellerData.V2_Read_Cal)/1000) * Read_Val_TMP)/1000;  /* mV */

            Read_Val_TMP = Read_ADC(PSU_Ch_2, ADC_Current_Channel);
            Read_Val_TMP = Read_Val_TMP & 0x00000FFF;    /* mask off any crud */
            wellerData.I2_Meas = (1 - Current_Filter_Coeff)* wellerData.I2_Meas + Current_Filter_Coeff * (wellerData.I2_Offset + (((wellerData.Imeas_Scale * wellerData.I2_Cal)/1000) * Read_Val_TMP)/1000);  /* mV */

            wellerData.Update_Outputs = true;
            wellerData.UI_Update_Display = false;
            /* set bounds flags for V and I */
            WELLER_Check_VI_Bounds();
        }

    /* Check the application's current state. */
    switch ( wellerData.state )
    {
        /* Application's initial state. */
        case WELLER_STATE_INIT:
        {
            // Heartbeat ISR Timer
            wellerData.heartbeatTimer = DRV_TMR_Open( APP_HEARTBEAT_TMR,
                DRV_IO_INTENT_EXCLUSIVE);
            if ( DRV_HANDLE_INVALID != wellerData.heartbeatTimer )
            {
                DRV_TMR_AlarmRegister(wellerData.heartbeatTimer,
                                    APP_HEARTBEAT_TMR_PERIOD,
                                    APP_HEARTBEAT_TMR_IS_PERIODIC,
                                    (uintptr_t)&wellerData,
                                    APP_TimerCallback);
                DRV_TMR_Start(wellerData.heartbeatTimer);
                //wellerData.state = WELLER_STATE_LCDINIT;
            }
            // User Interface ISR Timer
            wellerData.UI_Timer = DRV_TMR_Open( APP_UI_TMR,
                DRV_IO_INTENT_EXCLUSIVE);
            if ( DRV_HANDLE_INVALID != wellerData.UI_Timer )
            {
                DRV_TMR_AlarmRegister(wellerData.UI_Timer,
                                    APP_UI_TMR_PERIOD,
                                    APP_UI_TMR_IS_PERIODIC,
                                    (uintptr_t)&wellerData,
                                    APP_UI_Callback);
                DRV_TMR_Start(wellerData.UI_Timer);
                wellerData.state = WELLER_STATE_LCDINIT;
            }
        }
         break;

        /* Application's initial state. */
        case WELLER_STATE_LCDINIT:
        {
            for(jl = 0; jl < KS0108_SCREEN_HEIGHT/8; jl++)
            {
                for(il = 0; (il < (int)(KS0108_SCREEN_WIDTH)); il++)
                {
                    ScreenBuff[il][jl] = 0;
                    ScreenBuff1[il][jl] = 0;
                }
            }
            /* Function Select */  /* Display On */
            GLCD_Initalize();
            /* Display Clear */
            GLCD_ClearScreen();
            GLCD_WriteCommand(DISPLAY_ON_CMD | DISPLAY_ON, 0);
            GLCD_WriteCommand(DISPLAY_ON_CMD | DISPLAY_ON, 1);
            // Splash Start Up Screen
            Splash_Screen();
            /* get the EEPROM up and running and loaded into data structure */
            WELLER_EEPROM_Initialize();
            WELLER_EEPROM_READ_COMPLETE();
            DelayMs(500);
            wellerData.state = WELLER_STATE_SLOW_START;
        }        
        break;

        /* TODO............*/
        /* This state need to:                                              */
        /* Set V, I1 and V2, I2 to zero                                     */
        /* we can simply do both as if the dac is not there no bother....   */
        /* Then over say 300mS ramp V and I up to that from the EEPROM      */
        /* If the monitor functions throw an error then set I and V to zero */
        /* This says to me that reading the ADCs for V and I needs to be    */
        /* run in an ISR, say the HMI one... */
        /* Slow Start. */
        case WELLER_STATE_SLOW_START:
        {
            /* Needs to be filled in */
            /* nothing should point at this yet! */
            
            /* let things settle*/
            DelayMs(200);
            wellerData.UI_Keypressed = 0;
            
            /* move on */
            WELLER_Set_Outputs();
            wellerData.state = WELLER_STATE_IDLE;
            Idle_Screen();
            wellerData.Update_Outputs = true;
        }        
        break;


        /* This state needs to change focus from V1, I2                 */
        /* and if installed V2, I2                                      */
        /* also capture Select to jump to change the item in focus      */
        /* and on exit go to the SETUP state                            */
        /* If data has changed for V and I, then update                 */
        /* we are just sitting there at the "normal" screen             */        
        case WELLER_STATE_IDLE:
        {
            /* code for emergency shutdown */
            if (wellerData.UI_Keypressed && (Keypress_Read == Shutdown_Sw))
            {
                /* toggle shutdown */
                if (wellerData.Shutdown_Output) 
                    wellerData.Shutdown_Output = false;
                else
                    wellerData.Shutdown_Output = true;
                /* update outputs */
                WELLER_Set_Voltage();
                wellerData.UI_Keypressed = false;
            }
        
            /* reset the countdown timer */
            wellerData.Revert_To_Idle_Counter = Revert_To_Idle;
            
            /* catch error of not having set user interface action pointer */
            if ((wellerData.UI_Action != WELLER_ACTION_V1) &&
                    (wellerData.UI_Action != WELLER_ACTION_V2))
                wellerData.UI_Action = WELLER_ACTION_V1;
           
            /*****************************************************************/
            /*  Check rotary encoder 1 and Select and Exit                   */
            /*****************************************************************/
            if(wellerData.UI_Keypressed)
            {
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Voltage_Speed, Voltage_Normal_Speed);
               
                if ((Keypress_Read == Rot_Up) || (Keypress_Read == Rot_Down))
                {
                    WELLER_Set_Voltage();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO to state for focus, V1, V2, I1, I2 */        
                    /******************************************************/
                    /*  This needs to jump to the V or I that is in focus */
                    /*  Use wellerData.UI_Action as the state variable    */
                    /******************************************************/
                    WELLER_EEPROM_Save();

                    if ((wellerData.Num_Rails == 1) || (wellerData.Tracking == 1))
                        wellerData.UI_Action = WELLER_ACTION_V1;
                    else if ((wellerData.Num_Rails == 2) && (wellerData.Tracking == 0))
                    {
                        if (wellerData.UI_Action == WELLER_ACTION_V1)
                            wellerData.UI_Action = WELLER_ACTION_V2;    
                        else if (wellerData.UI_Action == WELLER_ACTION_V2)
                            wellerData.UI_Action = WELLER_ACTION_V1;    
                    }
                    wellerData.UI_Update_Display = true; 
                }
                else if (Keypress_Read == Exit)
                {
                    /******************************************************/
                    /*  This needs to jump to the SETUP screen            */
                    /******************************************************/
                    if (wellerData.Num_Rails == 2)
                        wellerData.UI_Action = WELLER_ACTION_TRACKING;
                    else
                        wellerData.UI_Action = WELLER_ACTION_CAL;
                    wellerData.state = WELLER_STATE_SETUP;
                    /* put the right display up */
                    WELLER_Setup_Function();
                    wellerData.UI_Update_Display = false;
                }
                wellerData.UI_Keypressed = false;
            }    

            /*****************************************************************/
            /*  Check rotary encoder 2                                       */
            /*****************************************************************/
            if(wellerData.UI_Keypressed_RE2)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Current_Speed, Current_Normal_Speed);

                if ((Keypress_Read_RE2 == Rot_Up) || (Keypress_Read_RE2 == Rot_Down))
                {
                    WELLER_Set_Current();
                }
            }    
            
            if (wellerData.UI_Update_Display) 
            {
                Idle_Screen();
                Reset_UI_Timer;
                wellerData.UI_Update_Display = false;
            }
        }
        break;
        
        
        /************************************************************************/
        /* Selection of:                                                        */
        /*   Dual tracking or not (to state WELLER_STATE_TRACKING)              */
        /*   Power Settings (to state WELLER_STATE_POWER_SETTINGS)              */
        /*      - one or two outputs (to state WELLER_STATE_POWER_NUM_OUTPUTS)  */
        /*      - Max Current  (to state WELLER_STATE_POWER_MAX_CURRENT)        */
        /*      - Transformer Voltage ( state WELLER_STATE_POWER_TRANSFORMER_V) */
        /*      - Transformer VA rating ( state WELLER_STATE_POWER_TRANSFORMER_VA) */
        /*  CAL  (to state WELLER_STATE_CAL)                                   */
        /***********************************************************************/
        case WELLER_STATE_SETUP:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* reset this just to be clear */
                wellerData.UI_Speed = 1;

                if (Keypress_Read == Rot_Up)
                {
                    if (wellerData.UI_Action == WELLER_ACTION_TRACKING)
                        wellerData.UI_Action = WELLER_ACTION_POWER;
                    else if (wellerData.UI_Action == WELLER_ACTION_POWER)
                        wellerData.UI_Action = WELLER_ACTION_CAL;
                    else if (wellerData.UI_Action == WELLER_ACTION_CAL)
                        if (wellerData.Num_Rails == 2)
                            wellerData.UI_Action = WELLER_ACTION_TRACKING;
                        else 
                            wellerData.UI_Action = WELLER_ACTION_POWER;
                    else   /* catch all */
                        wellerData.UI_Action = WELLER_ACTION_TRACKING;
                    /* This function displays the choose function screen  */
                    WELLER_Setup_Function();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    if (wellerData.UI_Action == WELLER_ACTION_TRACKING)
                        wellerData.UI_Action = WELLER_ACTION_CAL;
                    else if (wellerData.UI_Action == WELLER_ACTION_CAL)
                        wellerData.UI_Action = WELLER_ACTION_POWER;
                    else if (wellerData.UI_Action == WELLER_ACTION_POWER)
                        if (wellerData.Num_Rails == 2)
                            wellerData.UI_Action = WELLER_ACTION_TRACKING;
                        else
                            wellerData.UI_Action = WELLER_ACTION_CAL;
                    else   /* catch all */
                        wellerData.UI_Action = WELLER_ACTION_TRACKING;
                    /* This function displays the choose function screen  */
                    WELLER_Setup_Function();
                }
                else if (Keypress_Read == Sel)
                {
                    if (wellerData.UI_Action == WELLER_ACTION_TRACKING)
                    {
                        /* Jump into the tracking selection state */
                        /* start with Yes as this is the likely default*/
                        wellerData.UI_Action = WELLER_ACTION_YES;
                        wellerData.state = WELLER_STATE_TRACKING;
                        /* whack up the display */
                        WELLER_Tracking();
                    }
                    else if (wellerData.UI_Action == WELLER_ACTION_POWER)
                    {
                        /* start with no */
                        wellerData.UI_Action = WELLER_ACTION_NO;
                        WELLER_Num_Outputs();
                        wellerData.state = WELLER_STATE_POWER_NUM_OUTPUTS;
                    }
                    else if (wellerData.UI_Action == WELLER_ACTION_CAL)
                    {
                        /* start with no */
                        wellerData.UI_Action = WELLER_ACTION_NO;
                        wellerData.state = WELLER_STATE_CAL_V1_OUTPUT_OFFSET;
                        WELLER_Cal();
                    }
                    /* This function displays the choose function screen  */
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    wellerData.state = WELLER_STATE_IDLE;
                    Idle_Screen();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case WELLER_STATE_TRACKING:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;
        
                /* reset this just to be clear */
                wellerData.UI_Speed = 1;

                if (Keypress_Read == Rot_Up)
                {
                    if (wellerData.UI_Action == WELLER_ACTION_NO)
                        wellerData.UI_Action = WELLER_ACTION_YES;
                    else if (wellerData.UI_Action == WELLER_ACTION_YES)
                        wellerData.UI_Action = WELLER_ACTION_NO;
                    /* This function displays the tracking display screen  */
                    WELLER_Tracking();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    if (wellerData.UI_Action == WELLER_ACTION_NO)
                        wellerData.UI_Action = WELLER_ACTION_YES;
                    else if (wellerData.UI_Action == WELLER_ACTION_YES)
                        wellerData.UI_Action = WELLER_ACTION_NO;
                    /* This function displays the tracking display screen  */
                    WELLER_Tracking();
                }
                else if (Keypress_Read == Sel)
                {
                    if (wellerData.UI_Action == WELLER_ACTION_NO)
                    {
                        /* GO BACK TO IDLE STATE */        
                        wellerData.Tracking = 0;
                        WELLER_EEPROM_Save();
                        wellerData.Update_Outputs = true;
                        wellerData.UI_Action = WELLER_ACTION_V1;
                        wellerData.state = WELLER_STATE_IDLE;
                        Idle_Screen();
                    }
                    else if (wellerData.UI_Action == WELLER_ACTION_YES)
                    {
                        /* go to dual rail - copy wellerData.V1 to V2 and I1 to I2*/
                        wellerData.Tracking = 1;
                        WELLER_EEPROM_Save();
                        wellerData.V2 = wellerData.V1;
                        wellerData.I2 = wellerData.I1;
                        wellerData.Update_Outputs = true;
                        /* it is most likely this is all the user wants to change*/
                        wellerData.UI_Action = WELLER_ACTION_V1;
                        wellerData.state = WELLER_STATE_IDLE;
                        Idle_Screen();
                    }
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO SETUP STATE */        
                    wellerData.UI_Action = WELLER_ACTION_TRACKING;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
        
        case WELLER_STATE_POWER_NUM_OUTPUTS:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;
        
                /* reset this just to be clear */
                wellerData.UI_Speed = 1;

                if (Keypress_Read == Rot_Up)
                {
                    if (wellerData.Num_Rails == 1)
                        wellerData.Num_Rails = 2;
                    else if (wellerData.Num_Rails == 2)
                        wellerData.Num_Rails = 1;
                    /* This function displays the choose function screen  */
                    /* show on display */
                    WELLER_Num_Outputs();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    if (wellerData.Num_Rails == 1)
                        wellerData.Num_Rails = 2;
                    else if (wellerData.Num_Rails == 2)
                        wellerData.Num_Rails = 1;
                    /* This function displays the choose function screen  */
                    /* show on display */
                    WELLER_Num_Outputs();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO BACK TO MAX CURRENT STATE */        
                    if (wellerData.Num_Rails == 1)
                        wellerData.Tracking = 0;
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_POWER_MAX_CURRENT;
                    WELLER_Max_Current();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO SETUP STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
        
        case WELLER_STATE_POWER_MAX_CURRENT:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Current_Speed, Current_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.I_Max +=  wellerData.UI_Speed * Current_Limit_Step;
                    if (wellerData.I_Max >= I_Limit_mA)
                    {
                        wellerData.I_Max = I_Limit_mA;
                    }
                    /* check current settings are consistent */    
                    if (wellerData.I1 > wellerData.I_Max)
                        wellerData.I1 = wellerData.I_Max;
                    if (wellerData.I2 > wellerData.I_Max)
                        wellerData.I2 = wellerData.I_Max;
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Max_Current();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.I_Max -=  wellerData.UI_Speed * Current_Limit_Step;
                    if (wellerData.I_Max <= I_Min)
                    {
                        wellerData.I_Max = I_Min;
                    }
                    /* check current settings are consistent - this is for exceptions */    
                    if (wellerData.I1 > wellerData.I_Max)
                        wellerData.I1 = wellerData.I_Max;
                    if (wellerData.I2 > wellerData.I_Max)
                        wellerData.I2 = wellerData.I_Max;
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Max_Current();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE MAXIMUM VOLTAGE SCREEN */        
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_POWER_MAXIMUM_V;
                    WELLER_Max_Voltage();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO SETUP STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case WELLER_STATE_POWER_MAXIMUM_V:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Voltage_Setup_Speed, Voltage_Setup_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.V_Max +=  wellerData.UI_Speed * Voltage_Setup_Step;
                    if (wellerData.V_Max >= V_Limit_mV)
                    {
                        wellerData.V_Max = V_Limit_mV;
                    }
                    /* check current settings are consistent */    
                    if (wellerData.V1 > wellerData.V_Max)
                        wellerData.V1 = wellerData.V_Max;
                    if (wellerData.V2 > wellerData.V_Max)
                        wellerData.V2 = wellerData.V_Max;
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Max_Voltage();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.V_Max -=  wellerData.UI_Speed * Voltage_Setup_Step;
                    if (wellerData.V_Max <= V_Min_Setup)
                    {
                        wellerData.V_Max = V_Min_Setup;
                    }
                    /* check current settings are consistent */    
                    if (wellerData.V1 > wellerData.V_Max)
                        wellerData.V1 = wellerData.V_Max;
                    if (wellerData.V2 > wellerData.V_Max)
                        wellerData.V2 = wellerData.V_Max;
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Max_Voltage();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE TRANSFORMER VA SCREEN */        
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_POWER_TRANSFORMER_VA;
                    WELLER_Transformer_VA();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO SETUP STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case WELLER_STATE_POWER_TRANSFORMER_VA:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(VA_Speed, VA_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.Transformer_VA +=  wellerData.UI_Speed * VA_Step;
                    if (wellerData.Transformer_VA >= Transformer_VA_Max)
                    {
                        wellerData.Transformer_VA = Transformer_VA_Max;
                    }
                    /* check current settings are consistent */    
                    if ((wellerData.V1 * wellerData.I1) * Transformer_VA_To_DCOUT_Scale > (wellerData.Transformer_VA * 1000000))
                        wellerData.I1 = ((wellerData.Transformer_VA * 1000000)/(wellerData.V1 * Transformer_VA_To_DCOUT_Scale));
                    if ((wellerData.V2 * wellerData.I2) * Transformer_VA_To_DCOUT_Scale > (wellerData.Transformer_VA * 1000000))
                        wellerData.I2 = ((wellerData.Transformer_VA * 1000000)/(wellerData.V2 * Transformer_VA_To_DCOUT_Scale));
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Transformer_VA();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.Transformer_VA -=  wellerData.UI_Speed * VA_Step;
                    if (wellerData.Transformer_VA <= Transformer_VA_Min)
                    {
                        wellerData.Transformer_VA = Transformer_VA_Min;
                    }
                    /* check current settings are consistent */    
                    if ((wellerData.V1 * wellerData.I1) * Transformer_VA_To_DCOUT_Scale > (wellerData.Transformer_VA * 1000000))
                        wellerData.I1 = ((wellerData.Transformer_VA * 1000000)/(wellerData.V1 * Transformer_VA_To_DCOUT_Scale));
                    if ((wellerData.V2 * wellerData.I2) * Transformer_VA_To_DCOUT_Scale > (wellerData.Transformer_VA * 1000000))
                        wellerData.I2 = ((wellerData.Transformer_VA * 1000000)/(wellerData.V2 * Transformer_VA_To_DCOUT_Scale));
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Transformer_VA();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE CAL SCREEN */
                    WELLER_EEPROM_Save();
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO SETUP STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        /* output offset at zero volts set */
        case WELLER_STATE_CAL_V1_OUTPUT_OFFSET:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Offset_Speed, Offset_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.V1_Offset +=  wellerData.UI_Speed * Offset_Step;
                    if (wellerData.V1_Offset >= V_Offset_Max)
                    {
                        wellerData.V1_Offset = V_Offset_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.V1_Offset -=  wellerData.UI_Speed * Offset_Step;
                    if (wellerData.V1_Offset <= V_Offset_Min)
                    {
                        wellerData.V1_Offset = V_Offset_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE WELLER_STATE_CAL_V1_SET_SCALE SCREEN */        
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_CAL_V1_SET_SCALE;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        /* V1 set scale factor variance around 1.000 */
        case WELLER_STATE_CAL_V1_SET_SCALE:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Cal_Speed_Step , Cal_Step );

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.V1_Output_Cal +=  wellerData.UI_Speed;
                    if (wellerData.V1_Output_Cal >= V_Cal_Max)
                    {
                        wellerData.V1_Output_Cal = V_Cal_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.V1_Output_Cal -=  wellerData.UI_Speed;
                    if (wellerData.V1_Output_Cal <= V_Cal_Min)
                    {
                        wellerData.V1_Output_Cal = V_Cal_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE WELLER_STATE_V1_READ_SCALE SCREEN */
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_CAL_V1_READ_SCALE;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        /* V1 READ scale factor variance around 1.000 */
        case WELLER_STATE_CAL_V1_READ_SCALE:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Cal_Speed_Step , Cal_Step );

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.V1_Read_Cal +=  wellerData.UI_Speed;
                    if (wellerData.V1_Read_Cal >= V_Cal_Max)
                    {
                        wellerData.V1_Read_Cal = V_Cal_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.V1_Read_Cal -=  wellerData.UI_Speed;
                    if (wellerData.V1_Read_Cal <= V_Cal_Min)
                    {
                        wellerData.V1_Read_Cal = V_Cal_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE WELLER_STATE_I1_OFFSET SCREEN */
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_CAL_I1_OFFSET;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    

            /* update display of read value if heartbeat timer has ticked but not exit*/
            if ((wellerData.UI_Update_Display == true) && (wellerData.state != WELLER_STATE_SETUP))
                WELLER_Cal();
        
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case WELLER_STATE_CAL_I1_OFFSET:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Offset_Speed, Offset_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.I1_Offset +=  wellerData.UI_Speed * Offset_Step;
                    if (wellerData.I1_Offset >= I_Offset_Max)
                    {
                        wellerData.I1_Offset = I_Offset_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.I1_Offset -=  wellerData.UI_Speed * Offset_Step;
                    if (wellerData.I1_Offset <= I_Offset_Min)
                    {
                        wellerData.I1_Offset = I_Offset_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE WELLER_STATE_CAL_I1_SCALE SCREEN */
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_CAL_I1_SCALE;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            
            /* update display of read value if heartbeat timer has ticked but not exit*/
            if ((wellerData.UI_Update_Display == true) && (wellerData.state != WELLER_STATE_SETUP))
                WELLER_Cal();

            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
                
         case WELLER_STATE_CAL_I1_SCALE:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Cal_Speed_Step, Cal_Step);

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.I1_Cal +=  wellerData.UI_Speed;
                    if (wellerData.I1_Cal >= I_Cal_Max)
                    {
                        wellerData.I1_Cal = I_Cal_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.I1_Cal -=  wellerData.UI_Speed;
                    if (wellerData.I1_Cal <= I_Cal_Min)
                    {
                        wellerData.I1_Cal = I_Cal_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE WELLER_STATE_CAL_V2_OUTPUT_OFFSET SCREEN */
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_CAL_V2_OUTPUT_OFFSET;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            
            /* update display of read value if heartbeat timer has ticked but not exit*/
            if ((wellerData.UI_Update_Display == true) && (wellerData.state != WELLER_STATE_SETUP))
                WELLER_Cal();

            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case WELLER_STATE_CAL_V2_OUTPUT_OFFSET:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Offset_Speed, Offset_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.V2_Offset +=  wellerData.UI_Speed * Offset_Step;
                    if (wellerData.V2_Offset >= V_Offset_Max)
                    {
                        wellerData.V2_Offset = V_Offset_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.V2_Offset -=  wellerData.UI_Speed * Offset_Step;
                    if (wellerData.V2_Offset <= V_Offset_Min)
                    {
                        wellerData.V2_Offset = V_Offset_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE WELLER_STATE_CAL_V2_SET_SCALE SCREEN */
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_CAL_V2_SET_SCALE;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
 
        /* Scale for SET Voltage - will be 1.000 plus or minus something */
        case WELLER_STATE_CAL_V2_SET_SCALE:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Cal_Speed_Step, Cal_Step); 
                if (Keypress_Read == Rot_Up)
                {
                    wellerData.V2_Output_Cal +=  wellerData.UI_Speed;
                    if (wellerData.V2_Output_Cal >= V_Cal_Max)
                    {
                        wellerData.V2_Output_Cal = V_Cal_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.V2_Output_Cal -=  wellerData.UI_Speed;
                    if (wellerData.V2_Output_Cal <= V_Cal_Min)
                    {
                        wellerData.V2_Output_Cal = V_Cal_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE WELLER_STATE_CAL_V2_READ_SCALE SCREEN */
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_CAL_V2_READ_SCALE;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        /* Scale for READ Voltage - will be 1.000 plus or minus something */
        case WELLER_STATE_CAL_V2_READ_SCALE:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Cal_Speed_Step, Cal_Step); 
                if (Keypress_Read == Rot_Up)
                {
                    wellerData.V2_Read_Cal +=  wellerData.UI_Speed;
                    if (wellerData.V2_Read_Cal >= V_Cal_Max)
                    {
                        wellerData.V2_Read_Cal = V_Cal_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.V2_Read_Cal -=  wellerData.UI_Speed;
                    if (wellerData.V2_Read_Cal <= V_Cal_Min)
                    {
                        wellerData.V2_Read_Cal = V_Cal_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE WELLER_STATE_CAL_I2_OFFSET SCREEN */
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_CAL_I2_OFFSET;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    

            /* update display of read value if heartbeat timer has ticked but not exit*/
            if ((wellerData.UI_Update_Display == true) && (wellerData.state != WELLER_STATE_SETUP))
                WELLER_Cal();

            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case WELLER_STATE_CAL_I2_OFFSET:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Offset_Speed, Offset_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.I2_Offset +=  wellerData.UI_Speed * Offset_Step;
                    if (wellerData.I2_Offset >= I_Offset_Max)
                    {
                        wellerData.I2_Offset = I_Offset_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.I2_Offset -=  wellerData.UI_Speed * Offset_Step;
                    if (wellerData.I2_Offset <= I_Offset_Min)
                    {
                        wellerData.I2_Offset = I_Offset_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO TO THE WELLER_STATE_CAL_I2_SCALE SCREEN */
                    WELLER_EEPROM_Save();
                    wellerData.state = WELLER_STATE_CAL_I2_SCALE;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            
            /* update display of read value if heartbeat timer has ticked but not exit*/
            if ((wellerData.UI_Update_Display == true) && (wellerData.state != WELLER_STATE_SETUP))
                WELLER_Cal();

            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
                
         case WELLER_STATE_CAL_I2_SCALE:
        {
            if(wellerData.UI_Keypressed)
            {
                /* reset the countdown timer */
                wellerData.Revert_To_Idle_Counter = Revert_To_Idle;

                /* run update to counters to see if rapid value change needed */
                WELLER_UI_Fast_Slow(Cal_Speed_Step, Cal_Step);

                if (Keypress_Read == Rot_Up)
                {
                    wellerData.I2_Cal +=  wellerData.UI_Speed;
                    if (wellerData.I2_Cal >= I_Cal_Max)
                    {
                        wellerData.I2_Cal = I_Cal_Max;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }    
                else if  (Keypress_Read == Rot_Down)
                {
                    wellerData.I2_Cal -=  wellerData.UI_Speed;
                    if (wellerData.I2_Cal <= I_Cal_Min)
                    {
                        wellerData.I2_Cal = I_Cal_Min;
                    }
                    /* This function displays the maximum current  */
                    wellerData.Update_Outputs = true;
                    WELLER_Cal();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO BACK TO IDLE STATE */
                    WELLER_EEPROM_Save();
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                else if (Keypress_Read == Exit)
                {
                    /* fair chance the user did not want to be here...*/
                    /* GO BACK TO IDLE STATE */        
                    wellerData.UI_Action = WELLER_ACTION_POWER;
                    wellerData.state = WELLER_STATE_SETUP;
                    WELLER_Setup_Function();
                }
                wellerData.UI_Keypressed = false;
                // no need to update the display
            }    
            
            /* update display of read value if heartbeat timer has ticked but not exit*/
            if ((wellerData.UI_Update_Display == true) && (wellerData.state != WELLER_STATE_SETUP))
                WELLER_Cal();

            /* if revert timer is out, then quit back to idle screen */
            if (wellerData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO IDLE STATE */        
                wellerData.UI_Action = WELLER_ACTION_V1;
                wellerData.state = WELLER_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;                        
        
        case WELLER_STATE_SERVICE_TASKS:
        {
        
        }
        break;


        /* The default state should never be executed. */
        default:
        {
            /* TODO: Handle error in application's state machine. */
            break;
        }
    }
 
            
    /* decrement this outside the UI loop, if it gets to zero then */
    /* the UI will reset the fast counter and not got to fast change */
    if(wellerData.UI_Slow_Count > 0)
        wellerData.UI_Slow_Count--;
    
    if(wellerData.Update_Outputs)
    {
        WELLER_Set_Outputs();
        wellerData.Update_Outputs = false; /* clear the flag */
    }
}

 

/*******************************************************************************
 End of File
 */
