/*******************************************************************************
  MPLAB Harmony Application Source File
  
  Company:
    Microchip Technology Inc.
  
  File Name:
    Control.c

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

  Description:
 * Ver 20171008 
 *    - EEPROM running
 *    - ADC running
 *    - Start implementing state machine
 *    - Needs
 *        - state machine and all transitions (none in there yet)
 *        - user interface stuff other than pictures
 * 
 * Ver 20190327
 *    - Fix rotary encoders for Jaycar and Altronics current stock
 * 
 * Ver 2019-04-11
 *  You REALLY want to put code in for pulse waveform to limit manumum frequency to about 1KHz
 * 
 * Ver 2019_06_06
 *   All working but AM and FM code and screens are still in there
 *   Completely unconvinced at the utility of these and will delete
 *   NEEDS
 *     - Check distortion on output
 *     - Check sweeps
 *     - Check processor utilisation
 * 
 * Ver 2019_06_13
 *   All working, 
 *      - AM and FM deleted, 
 *      - LOG sweep added, 
 *      - rewrote sweep implementations
 *  *   NEEDS
 *     - Check distortion on output
 *     - Check processor utilisation
 * 
 * Ver 2019_06_16
 *      - distortion good
 *      - utilisation is about 10% and stable
 * 
 * Ver 2019_06_22
 *      - Sort start up sequencing and ensure L/R data is not awapped!
 * 
 * 
 *******************************************************************************/


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

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

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

// *****************************************************************************
/* Application Data

  Summary:
    Holds application data

  Description:
    This structure holds the application's data.

  Remarks:
    This structure should be initialized by the APP_Initialize function.
    
    Application strings and buffers are be defined outside this structure.
*/
CONTROL_DATA controlData;
data_val_struct *Data_Values_Pointer, *Temp_Data_Values_Pointer;

/****************************************************************************/
// Thse are used by the User interfcae ISR.
// They could be absorbed into controlData structure...
// but I am feeling like a lazy sod right now.
/****************************************************************************/
static unsigned char Old_Rot_Status = 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 = 0;    /* this is the data on key / rotation changes */
static unsigned char Key_Just_Pressed = 0; 	/* use this to keep track of which keys have been pressed */
int Fast_Change = 1;			/* use this to indicate fast change of values */

/*****************************************************************************/
/* This is where global scratch pad stuff is stored... */
/*****************************************************************************/
char loop, test_temp;
int test_data;

/*****************************************************************************/
// 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 bnuilding the display */
const char Blank_Char = Blank_Char_Init;            /* ROM */
unsigned int display_temp;


/*****************************************************************************/
// Audio Buffers
/*****************************************************************************/
long long Acc_Reg;      /* input current sample*/
int *Out_Data;          /* pointer to output data */
/* location at which input data is written into a cyclical buffer */
unsigned int Write_Pointer_Offset, Ch1_Rd_Offset, Ch2_Rd_Offset; 
int New_Filter_Vals;    /* use to flag new filter parms */

int dummy;

unsigned int Ch1_FM_Phase_Reg, Ch2_FM_Phase_Reg;  /* phase accumulators for FM DDS */
unsigned int Ch1_FM_Phase_Inc, Ch2_FM_Phase_Inc;  /* Phase increment for AM DDS   */
unsigned int Ch1_AM_Phase_Reg, Ch2_AM_Phase_Reg;  /* phase accumulators for AM DDS */
unsigned int Ch1_AM_Phase_Inc, Ch2_AM_Phase_Inc;  /* Phase increment for AM DDS   */
unsigned int Phase_Acc_Ch1, Phase_Acc_Ch2;      /* Phase accumulators for Main DDS */
/* Phase step for Main DDS  >>this clock cycle<<*/
unsigned int Delta_Phase_Acc_Ch1, Delta_Phase_Acc_Ch2; 
/* this is an offset that does not affect the accumulator*/
long int Ch1_Sweep_Calc_Freq, Ch2_Sweep_Calc_Freq, Ch1_Sweep_Calc_Freq_Range, Ch2_Sweep_Calc_Freq_Range;
unsigned int Ch1_Phase_Delta, Ch2_Phase_Delta;  
unsigned int Old_Phase_Acc_Ch1, Old_Phase_Acc_Ch2;  /* Used to detect zero cross */
unsigned int Phase_Inc_Ch1, Phase_Inc_Ch2;  /* Phase increment for Main DDS   */
long long Temp_Calc_Store; /* used for calculation of 32 bit DDS parameters */
double Ch1_Log_Scale, Ch2_Log_Scale, Ch1_Log_Intermediate, Ch2_Log_Intermediate; /* used in calculating sweep */
unsigned int Phase_Reg_Temp, Next_Phase_Reg_Temp; /* working variable */
long long Interpolated_Output;                  /* calculations for interpolation requires long int */
long long Temp_Interpolated_Output;             /* calculations for interpolation requires long int */
unsigned int Ch1_Sweep_Start, Ch2_Sweep_Start, Ch1_Sweep_Base, Ch2_Sweep_Base;         /* this is the end DDS increment for sweep */
long Ch1_LUT[Waveform_LUT_Size], Ch2_LUT[Waveform_LUT_Size];   /* channel 1 and 2 waveform LUTs */
int Ch1_Pulse_Output_Active, Ch2_Pulse_Output_Active; /* Channel 1 and 2 Pule Output on */
int Ch1_Pulse_Counter, Ch2_Pulse_Counter; /* use these to track pulse train */
int Ch1_Level_Mult, Ch2_Level_Mult; /* This implements attenuation 2^24 = odB */
unsigned int Ch1_Sweep_Phase_Reg, Ch2_Sweep_Phase_Reg; /* sweep frequency phase registers */
unsigned int Ch1_Sweep_Phase_Inc, Ch2_Sweep_Phase_Inc; /* sweep phase increment */
unsigned int Ch1_Sweep_LUT[4096], Ch2_Sweep_LUT[4096]; /* look up table for sweep phase increment */
unsigned int Ch1_Sweep_Phase, Ch2_Sweep_Phase; /* Phase value for sweep  */
int Xn_L, Xn_R;         /* input current sample*/

int CH1_Output_Data_L, CH1_Output_Data_R; /* use this for output of scale limited values*/
int CH2_Output_Data_L, CH2_Output_Data_R; /* use this for output of scale limited values*/
int Out_Test_Temp;                       /* used for output clipping to 24 bits */



// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************


/****************************************************************************/
/* Uses the following globals                                               */
/*                                                                          */
/* The main DDS function is in an ISR                                       */
/* The main function simply implements the HMI and sets up parameters for   */
/* the DDS.  The following variables are stored globally to ensure they are */
/* accessible to the ISR without going through too much hassle              */
/*                                                                          */
/* DDS data storage                                                         */
/* Phase_Acc_Ch1, Phase_Acc_Ch2;    phase accumulators                      */
/* Phase_Inc_Ch1, Phase_Inc_Ch2     phase increment per clock               */
/* Cycles_On_Ch1, Cycles_On_Ch2;    number of cycles on for pulse mode      */
/* Cycles_Off_Ch1, Cycles_Off_Ch2;  number of cycles off for pulse mode     */
/* FM_Phase_Acc_Ch1, FM_Phase_Acc_Ch2; phase accumulator for FM             */
/* AM_Phase_Acc_Ch1, AM_Phase_Acc_Ch2; phase accumulator for AM             */
/****************************************************************************/
//__attribute__((vector(v), interrupt(ipl), nomips16))
void __ISR(_SPI1_TX_VECTOR, ipl4AUTO) IntHandlerSPITx(void)
{
//DEBUG
/*************************************************************************/
//            SYS_PORTS_Set(PORTS_ID_0, APP_HEARTBEAT_PORT, 4, 4);
/*************************************************************************/
/********************************************************/
/*             calculate channel 1 sweep stuff          */
/********************************************************/
SYS_INT_SourceDisable(INT_SOURCE_SPI_1_TRANSMIT);

    
if(controlData.Data_Values[HardCode_Ch1].Sweep_On)
{
    Ch1_Sweep_Phase_Reg += Ch1_Sweep_Phase_Inc;
    Ch1_Sweep_Phase = Ch1_Sweep_LUT[Ch1_Sweep_Phase_Reg >>20];    
}

/********************************************************/
/*             calculate channel 2 sweep stuff          */
/********************************************************/
if(controlData.Data_Values[HardCode_Ch2].Sweep_On)
{
    Ch2_Sweep_Phase_Reg += Ch2_Sweep_Phase_Inc;
    Ch2_Sweep_Phase = Ch2_Sweep_LUT[Ch2_Sweep_Phase_Reg >>20];    
}

/**************************************************/
/*    Run main DDS accumulators channel 1         */
/*    This line is where the magic happens !      */
/**************************************************/
Phase_Acc_Ch1 += Phase_Inc_Ch1;
Phase_Acc_Ch1 += Ch1_Sweep_Phase;
/**************************************************/
/*    Run main DDS accumulators channel 1         */
/*    This line is where the magic happens !      */
/**************************************************/
Phase_Acc_Ch2 += Phase_Inc_Ch2;
Phase_Acc_Ch2 += Ch2_Sweep_Phase;

    /* implement Pulse modulation */
    if (Old_Phase_Acc_Ch1 > Phase_Acc_Ch1) /* then we have wrapped around zero*/
    {
        if(controlData.Data_Values[HardCode_Ch1].Pulse_On) /* pulse mod is on*/
        {
            if(Ch1_Pulse_Output_Active) /* and the output is on*/
            {
                Ch1_Pulse_Counter--; /* decrement pulse counter*/
                if (!Ch1_Pulse_Counter)  /*if all pulses have been output*/
                {
                    Ch1_Pulse_Output_Active = 0; /* turn output off */
                    /* then count this many pulses for "off"*/
                    Ch1_Pulse_Counter = controlData.Data_Values[HardCode_Ch1].Pulse_Cycles_Off; 
                }
            }
            else /* the output is therefore off*/
            {
                Ch1_Pulse_Counter--; /* decrement pulse counter*/
                if (!Ch1_Pulse_Counter)  /*if all pulses in "off period" have been output*/
                {
                    Ch1_Pulse_Output_Active = 1; /* turn output on */
                    /* then count this many pulses for "on"*/
                    Ch1_Pulse_Counter = controlData.Data_Values[HardCode_Ch1].Pulse_Cycles_On; 
                }
            }
        }
        else
        {
            Ch1_Pulse_Output_Active = 1;
        }
    }
    /* and channel 2 pulse mod*/
    if (Old_Phase_Acc_Ch2 > Phase_Acc_Ch2) /* then we have wrapped around zero*/
    {
        if(controlData.Data_Values[HardCode_Ch2].Pulse_On) /* pulse mod is on*/
        {
            if(Ch2_Pulse_Output_Active) /* and the output is on*/
            {
                Ch2_Pulse_Counter--; /* decrement pulse counter*/
                if (!Ch2_Pulse_Counter)  /*if all pulses have been output*/
                {
                    Ch2_Pulse_Output_Active = 0; /* turn output off */
                    /* then count this many pulses for "off"*/
                    Ch2_Pulse_Counter = controlData.Data_Values[HardCode_Ch2].Pulse_Cycles_Off; 
                }
            }
            else /* the output is therefore off*/
            {
                Ch2_Pulse_Counter--; /* decrement pulse counter*/
                if (!Ch2_Pulse_Counter)  /*if all pulses in "off period" have been output*/
                {
                    Ch2_Pulse_Output_Active = 1; /* turn output on */
                    /* then count this many pulses for "on"*/
                    Ch2_Pulse_Counter = controlData.Data_Values[HardCode_Ch2].Pulse_Cycles_On; 
                }
            }
        }
        else
        {
            Ch2_Pulse_Output_Active = 1;
        }
    }

    /***************************************************************/
    /* Pay attention here... this is the DDS LUT interpolation     */
    /* it is a bit obtuse, but is critical to getting spurs down   */
    /***************************************************************/
    /* Phase step for Main DDS  >>this clock cycle<<*/
    Delta_Phase_Acc_Ch1 = (Phase_Acc_Ch1  + Ch1_Phase_Delta);
    /* this is just the lower 12 bits for the waveform LUT for a 12 bit LUT*/
    Phase_Reg_Temp = Delta_Phase_Acc_Ch1 >> DDS_LUT_Bit_Shift;
    Delta_Phase_Acc_Ch1 = Delta_Phase_Acc_Ch1 & DDS_LUT_Bit_Mask;
    /* This is used to look at the next value in the DDS LUT */
    /* and is used in the interpolation process */
    Next_Phase_Reg_Temp = Phase_Reg_Temp + 1;
    if (Next_Phase_Reg_Temp == Waveform_LUT_Size)
        Next_Phase_Reg_Temp = 0;
    /*Read the "basic" output of closes prior sample in the DDS */
    Interpolated_Output = (long int)Ch1_LUT[Phase_Reg_Temp];
    /* now work out the interpolation between the closest prior and next step */
    /* this is the voltage step between the current and next DDS LUT values */
    Temp_Interpolated_Output = (Ch1_LUT[Next_Phase_Reg_Temp] - Ch1_LUT[Phase_Reg_Temp]);
    /* Now scale it for where the EXACT phase of the current sample is in between the LUT steps*/
    Temp_Interpolated_Output = Temp_Interpolated_Output * Delta_Phase_Acc_Ch1;
    Temp_Interpolated_Output = Temp_Interpolated_Output /Waveform_LUT_Size_Bin;
    /* Temp_Interpolated_Output is the error correction between DDS LUT pulses */
/**********************************/
    /* INTERPOLATION */
    Interpolated_Output = Interpolated_Output + Temp_Interpolated_Output;
    Interpolated_Output = Interpolated_Output * Ch1_Pulse_Output_Active; /* implements pulse modulation*/
    Interpolated_Output = Interpolated_Output * Ch1_Level_Mult; /* implements attenuation*/
    Interpolated_Output = Interpolated_Output  >> 24;
    /* Output the data */
    Xn_L = ((int) Interpolated_Output);
    /* Now Channel 2 - identicial to Channel 1 */
    Delta_Phase_Acc_Ch2 = (Phase_Acc_Ch2  + Ch2_Phase_Delta);
    Phase_Reg_Temp = Delta_Phase_Acc_Ch2 >> DDS_LUT_Bit_Shift;
    Delta_Phase_Acc_Ch2 = Delta_Phase_Acc_Ch2 & DDS_LUT_Bit_Mask;
    Next_Phase_Reg_Temp = Phase_Reg_Temp + 1;
    if (Next_Phase_Reg_Temp == Waveform_LUT_Size)
        Next_Phase_Reg_Temp = 0;/*delta Volts in step */
    Interpolated_Output = (long int)Ch2_LUT[Phase_Reg_Temp];
    Temp_Interpolated_Output = (Ch2_LUT[Next_Phase_Reg_Temp] - Ch2_LUT[Phase_Reg_Temp]);
    Temp_Interpolated_Output = Temp_Interpolated_Output * Delta_Phase_Acc_Ch2;
    Temp_Interpolated_Output = Temp_Interpolated_Output /Waveform_LUT_Size_Bin;
/**********************************/
    /* INTERPOLATION */
 
    Interpolated_Output = Interpolated_Output + Temp_Interpolated_Output;
    Interpolated_Output = Interpolated_Output * Ch2_Pulse_Output_Active; /* implements pulse modulation*/
    Interpolated_Output = Interpolated_Output * Ch2_Level_Mult; /* implements attenuation*/
    Interpolated_Output = Interpolated_Output  >> 24;
    Xn_R = ((int) Interpolated_Output);

    /* set old phase countger = current for next cycle*/
    Old_Phase_Acc_Ch1 = Phase_Acc_Ch1;
    Old_Phase_Acc_Ch2 = Phase_Acc_Ch2;
    
    /* copy internal filter data to output variables - allows us to apply limits*/
    /* while allowing the filters to operate internally with much larger values */
    /* than the DAC can output*/
    Out_Test_Temp = Xn_L & DAC_Valid_BitMask;
    if (Out_Test_Temp & 0x80000000)
        {
            if (!(Out_Test_Temp ^ 0xff800000))
                CH1_Output_Data_L = Xn_L;
            else
                CH1_Output_Data_L = -DAC_Output_Max;
        }
    else if (Out_Test_Temp)
        CH1_Output_Data_L = DAC_Output_Max;
    else
        CH1_Output_Data_L = Xn_L;


    Out_Test_Temp = Xn_R & DAC_Valid_BitMask;
    if (Out_Test_Temp & 0x80000000)
        {
            if (!(Out_Test_Temp ^ 0xff800000))
                CH1_Output_Data_R = Xn_R;
            else
                CH1_Output_Data_R = -DAC_Output_Max;
        }
    else if (Out_Test_Temp)
        CH1_Output_Data_R = DAC_Output_Max;
    else
        CH1_Output_Data_R = Xn_R;

    /* now channel 2 */
    Out_Test_Temp = Xn_L & DAC_Valid_BitMask;
    if (Out_Test_Temp & 0x80000000)
        {
            if (!(Out_Test_Temp ^ 0xff800000))
                CH2_Output_Data_L = Xn_L;
            else
                CH2_Output_Data_L = -DAC_Output_Max;
        }
    else if (Out_Test_Temp)
        CH2_Output_Data_L = DAC_Output_Max;
    else
        CH2_Output_Data_L = Xn_L;


    Out_Test_Temp = Xn_R & DAC_Valid_BitMask;
    if (Out_Test_Temp & 0x80000000)
        {
            if (!(Out_Test_Temp ^ 0xff800000))
                CH2_Output_Data_R = Xn_R;
            else
                CH2_Output_Data_R = -DAC_Output_Max;
        }
    else if (Out_Test_Temp)
        CH2_Output_Data_R = DAC_Output_Max;
    else
        CH2_Output_Data_R = Xn_R;


    //***********************************************************************
    // Left and Right on the DAC are back to front! 
    // Thus flip R and L here
    Chan_1_Port_RW = CH1_Output_Data_R*256;
    Chan_1_Port_RW = CH1_Output_Data_L*256;

    Chan_2_Port_RW = CH2_Output_Data_R*256;
    Chan_2_Port_RW = CH2_Output_Data_L*256;

    
    DRV_SPI_Tasks(sysObj.spiObjectIdx1);
    PLIB_INT_SourceFlagClear(INT_ID_0,_SPI1_TX_VECTOR); 
    
    //DEBUG
    /*************************************************************************/
//            SYS_PORTS_Clear(PORTS_ID_0, APP_HEARTBEAT_PORT, 4);
    /*************************************************************************/
    SYS_INT_SourceEnable(INT_SOURCE_SPI_1_TRANSMIT);
}

static void APP_TimerCallback ( uintptr_t context, uint32_t alarmCount )
{
    controlData.heartbeatCount++;
    if (controlData.heartbeatCount >= APP_HEARTBEAT_COUNT_MAX)
    {
        controlData.heartbeatCount = 0;
        controlData.heartbeatToggle = true;
        
        /* then decrement the Revert To Idle timer */
        if (controlData.Revert_To_Idle_Counter > 0)
            controlData.Revert_To_Idle_Counter--;
    }
}

/****************************************************************************/	
/* Uses the following globals                                               */
/* s_count                                                                  */
/* Old_Rot_Status    Records state of rotary control                        */
/* Fast_Loop_Counter  Used to set Fast_Cnt                                  */
/* Slow_Loop_Counter  Used to see if user turning control continuously      */
/*                                                                          */
/*                                                                          */
/* This sets is the ISR that deals with key presses etc                     */
/****************************************************************************/	
static void APP_UI_Callback ( uintptr_t context, uint32_t alarmCount )
{
    unsigned char Current_Rot_Status = 0;
    unsigned char Debounce_Rot_Status = 0;
    
    //debounce_time_ms used for debouncing...
    /*Read Rot Status and mask off bits of interest */
	Current_Rot_Status = HMI_Port & (Vals_0 + Vals_1 + Exit + Sel);
    Key_Just_Pressed = (Current_Rot_Status != Old_Rot_Status);
    /* set the flag */
    if(Key_Just_Pressed)
    {
        DelayUs(debounce_time_us);
        Current_Rot_Status = HMI_Port & (Vals_0 + Vals_1 + Exit + Sel);
    	Key_Just_Pressed = (Current_Rot_Status != Old_Rot_Status);
    }
    
    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)))
        {
            /* 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;
                }
                controlData.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)
                {
                    /* Have read crap*/
                    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_Up;
                        controlData.UI_Keypressed = true;
                    }
                    else if (Current_Rot_Status == Phase_1)
                    {
                        Keypress_Read = Rot_Down;
                        controlData.UI_Keypressed = true;
                    }
                    else Keypress_Read = 0;
                    DelayUs(debounce_time_us);
                    
                }
                /* 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)
                {
                    /* Have read crap*/
                    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_Down;
                        controlData.UI_Keypressed = true;
                    }
                    else if (Current_Rot_Status == Phase_3)
                    {
                        Keypress_Read = Rot_Up;
                        controlData.UI_Keypressed = true;
                    }
                    else
                        Keypress_Read = 0;
                    
                    /* The Jaycar encoders have reversed pinouts to 
                       the baseline clde!*/
                }
                /* 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_Up;
                        controlData.UI_Keypressed = true;
                    }
                    else if (Current_Rot_Status == Phase_3)
                    {
                        Keypress_Read = Rot_Down;
                        controlData.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)))
        {
            if (Current_Rot_Status & Sel)
                Keypress_Read = Sel;
            else if (Current_Rot_Status & Exit)
                Keypress_Read = Exit;
            Fast_Change = 1;
            controlData.UI_Keypressed = true;
        }
        else    /* else not Key_just_Pressed */
        {
            Keypress_Read = 0;
            if (Slow_Loop_Counter > (unsigned int)0)
                Slow_Loop_Counter--;
        }
    }
        
	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 */

    // Increment User Interface Update Counter
    // This cimply cycles and the UI is only updated at UI_DIV intervals of this
    Increment_UI_Timer;
    
}


//static void APP_SPI_Callback ( uintptr_t context, uint32_t alarmCount )
//DRV_I2S_Tasks (object);

// *****************************************************************************
// *****************************************************************************
// Section: Application Local Functions
// *****************************************************************************
// *****************************************************************************


/****************************************************************************/
/* Do this in one place  -  save memory and hassles with consistency!    	*/
/****************************************************************************/
void Load_From_Memory(char Mem_Bank)
{
/* Read in the parameters for data from default bank of EEPROM */
for (loop=DDS_Channel_Min; loop <= DDS_Channel_Max; loop++)
	{
	/* Use pointers to the data structures */
    /* as it is more code efficient */
	Data_Values_Pointer = &(controlData.Data_Values[loop]);
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Freq_Offset),       &(Data_Values_Pointer->Freq), 4 );
    if (Data_Values_Pointer->Freq < Freq_Min)
        Data_Values_Pointer->Freq = Freq_Min;
    else if (Data_Values_Pointer->Freq > Freq_Max)
        Data_Values_Pointer->Freq = Freq_Max;
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Freq_Speed_Offset),       &(Data_Values_Pointer->Freq_Speed), 4 );
    if (Data_Values_Pointer->Freq_Speed < Freq_Speed_Min)
        Data_Values_Pointer->Freq_Speed = Freq_Speed_Min;
    else if (Data_Values_Pointer->Freq_Speed > Freq_Speed_Max)
        Data_Values_Pointer->Freq_Speed = Freq_Speed_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Atten_Offset),       &(Data_Values_Pointer->Atten), 4 );
    if (Data_Values_Pointer->Atten < Atten_Min)
        Data_Values_Pointer->Atten = Atten_Min;
    else if (Data_Values_Pointer->Atten > Atten_Max)
        Data_Values_Pointer->Atten = Atten_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Waveform_Offset),     &(Data_Values_Pointer->Waveform), 4 );
    if (Data_Values_Pointer->Waveform < Waveform_Min)
        Data_Values_Pointer->Waveform = Waveform_Min;
    else if (Data_Values_Pointer->Waveform > Waveform_Max)
        Data_Values_Pointer->Waveform = Waveform_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Ratio_Offset),    &(Data_Values_Pointer->Ratio), 4 );
    if (Data_Values_Pointer->Ratio < Ratio_Min)
        Data_Values_Pointer->Ratio = Ratio_Min;
    else if (Data_Values_Pointer->Ratio > Ratio_Max)
        Data_Values_Pointer->Ratio = Ratio_Max;
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Sweep_On_Offset), &(Data_Values_Pointer->Sweep_On), 4 );
    if (Data_Values_Pointer->Sweep_On > Sweep_Log)
        Data_Values_Pointer->Sweep_On = Sweep_Log;
    else if (Data_Values_Pointer->Sweep_On < 0) 
        Data_Values_Pointer->Sweep_On = 0;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Sweep_End_Offset), &(Data_Values_Pointer->Sweep_End), 4 );
    if (Data_Values_Pointer->Sweep_End < Sweep_End_Min)
        Data_Values_Pointer->Sweep_End = Sweep_End_Min;
    else if (Data_Values_Pointer->Sweep_End > Sweep_End_Max)
        Data_Values_Pointer->Sweep_End = Sweep_End_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Sweep_Time_Offset),   &(Data_Values_Pointer->Sweep_Time), 4 );
    if (Data_Values_Pointer->Sweep_Time < Sweep_Time_Min)
        Data_Values_Pointer->Sweep_Time = Sweep_Time_Min;
    else if (Data_Values_Pointer->Sweep_Time > Sweep_Time_Max)
        Data_Values_Pointer->Sweep_Time = Sweep_Time_Max;
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Pulse_On_Offset), &(Data_Values_Pointer->Pulse_On), 4 );
    if (Data_Values_Pointer->Pulse_On)
        Data_Values_Pointer->Pulse_On = 1;
    else 
        Data_Values_Pointer->Pulse_On = 0;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Pulse_Cycles_On_Offset), &(Data_Values_Pointer->Pulse_Cycles_On), 4 );
    if (Data_Values_Pointer->Pulse_Cycles_On < Pulse_Cycles_On_Min)
        Data_Values_Pointer->Pulse_Cycles_On = Pulse_Cycles_On_Min;
    else if (Data_Values_Pointer->Pulse_Cycles_On > Pulse_Cycles_On_Max)
        Data_Values_Pointer->Pulse_Cycles_On = Pulse_Cycles_On_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Pulse_Cycles_Off_Offset), &(Data_Values_Pointer->Pulse_Cycles_Off), 4 );
    if (Data_Values_Pointer->Pulse_Cycles_Off < Pulse_Cycles_Off_Min)
        Data_Values_Pointer->Pulse_Cycles_Off = Pulse_Cycles_Off_Min;
    else if (Data_Values_Pointer->Pulse_Cycles_Off > Pulse_Cycles_Off_Max)
        Data_Values_Pointer->Pulse_Cycles_Off = Pulse_Cycles_Off_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Phase_Shift_Offset), &(Data_Values_Pointer->Phase_Shift), 4 );
    if (Data_Values_Pointer->Phase_Shift < Phase_Shift_Min)
        Data_Values_Pointer->Phase_Shift = Phase_Shift_Min;
    else if (Data_Values_Pointer->Phase_Shift > Phase_Shift_Max)
        Data_Values_Pointer->Phase_Shift = Phase_Shift_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + AM_On_Offset), &(Data_Values_Pointer->AM_On), 4 );
    if (Data_Values_Pointer->AM_On)
        Data_Values_Pointer->AM_On = 1;
    else 
        Data_Values_Pointer->AM_On = 0;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + AM_Level_Offset), &(Data_Values_Pointer->AM_Level), 4 );
    if (Data_Values_Pointer->AM_Level < AM_Level_Min)
        Data_Values_Pointer->AM_Level = AM_Level_Min;
    else if (Data_Values_Pointer->AM_Level > AM_Level_Max)
        Data_Values_Pointer->AM_Level = AM_Level_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + AM_Freq_Offset), &(Data_Values_Pointer->AM_Freq), 4 );
    if (Data_Values_Pointer->AM_Freq < AM_Freq_Min)
        Data_Values_Pointer->AM_Freq = AM_Freq_Min;
    else if (Data_Values_Pointer->AM_Freq > AM_Freq_Max)
        Data_Values_Pointer->AM_Freq = AM_Freq_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + FM_On_Offset), &(Data_Values_Pointer->FM_On), 4 );
    if (Data_Values_Pointer->FM_On)
        Data_Values_Pointer->FM_On = 1;
    else 
        Data_Values_Pointer->FM_On = 0;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + FM_Excursion_Offset), &(Data_Values_Pointer->FM_Excursion), 4 );
    if (Data_Values_Pointer->FM_Excursion < FM_Excursion_Min)
        Data_Values_Pointer->FM_Excursion = FM_Excursion_Min;
    else if (Data_Values_Pointer->FM_Excursion > FM_Excursion_Max)
        Data_Values_Pointer->FM_Excursion = FM_Excursion_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + FM_Freq_Offset), &(Data_Values_Pointer->FM_Freq), 4 );
    if (Data_Values_Pointer->FM_Freq < FM_Freq_Min)
        Data_Values_Pointer->FM_Freq = FM_Freq_Min;
    else if (Data_Values_Pointer->FM_Freq > FM_Freq_Max)
        Data_Values_Pointer->FM_Freq = FM_Freq_Max;    
    };
}

/*****************************************************************************/
/*     Write bot version to screen...                                        */
/*****************************************************************************/
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);
}


/*******************************************************************************
  Function:
    void Splash_Screen ( void )
  Remarks:
 * PResents strart up screen, initialises display for idle state
******************************************************************************/
void Splash_Screen()
{    
    char Splash_line_1[20];

    /* Write Bank Number to Screen */
    sprintf(Splash_line_1, "DDS   ");

    /* write TGM splash to screen buffer */
    WriteBMP(ScreenBuff, TGM_Logo_Full, 0, 0, 128, 64);
    Refresh_LCD;
    DelayMs(1500);
    /* write version to screen buffer*/
    WriteBMP(ScreenBuff, Splash_2, 0, 0, 128, 64);
    GLCD_WriteString_16x11_buf(ScreenBuff,&(Splash_line_1[0]),Splash_L1x, Splash_L1y);
    Write_Boot_Ver();
    Refresh_LCD;
    DelayMs(1500);
    CF_ATTEN();
    Refresh_LCD;
}

/*******************************************************************************
  Function:
    void Save_Screen ( void )
  Remarks:
 * Presents screen for which bank to save to in save state
******************************************************************************/
void Save_Screen(void)
{   
    char SS_line_1[20];
    
    /* write save screen (Save_Bank bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

    controlData.UI_Display_Lockout = true;
    WriteBMP(ScreenBuff, Save_Bank, 0, 0, 128, 64);

    /* Write Bank Number to Screen */
    sprintf(SS_line_1, " %d", controlData.MemoryBankSelected);
    GLCD_WriteString_16x11_buf(ScreenBuff,&(SS_line_1[0]),Save_L1x, Save_L1y);
    
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void Load_Screen ( void )
  Remarks:
 * Presents screen for which bank to be used to load data
******************************************************************************/
void Load_Screen(void)
{   
    char LS_line_1[20];
    
    /* write save screen (Save_Bank bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

    controlData.UI_Display_Lockout = true;
    WriteBMP(ScreenBuff, Load_Bank, 0, 0, 128, 64);

    /* Write Bank Number to Screen */
    sprintf(LS_line_1, " %d", controlData.MemoryBankSelected);
    GLCD_WriteString_16x11_buf(ScreenBuff,&(LS_line_1[0]),Load_L1x, Load_L1y);
    
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CONTROL_DDS_Band ( void )
  Remarks:
 * Presents screen for which band to be used to select XO band to change
******************************************************************************/
void CF_DDS_Channel(void)
{   
    char Channel_line_1[20];
    int tx, ty;
    
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;

    /* Write DDS Channel Number to Screen */
    sprintf(Channel_line_1, "DDS Channel %d", (controlData.DDS_Channel +1));
    if(controlData.DDS_Channel == 0) 
    {
//        WriteBMP(ScreenBuff, CH_SELECT_B1, 0, 0, 128, 64);
//        WriteBMP_Buf(ScreenBuff, TGM_MED, BandXO_TGM_X0, BandXO_TGM_Y, 43, 16);
        //
        GLCD_WriteString_12x7_buf(ScreenBuff,&(Channel_line_1[0]),Channel_X1, Channel_Y1);
    }
    else if(controlData.DDS_Channel == 1) 
    {
//        WriteBMP(ScreenBuff, CH_SELECT_B2, 0, 0, 128, 64);
//        WriteBMP_Buf(ScreenBuff, TGM_MED, BandXO_TGM_X1, BandXO_TGM_Y, 43, 16);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(Channel_line_1[0]),Channel_X1, Channel_Y1);
    }
    else 
    {
        WriteBMP(ScreenBuff, Oops_Template, 0, 0, 128, 64);
//        WriteBMP_Buf(ScreenBuff, TGM_MED, BandXO_TGM_X2, BandXO_TGM_Y, 43, 16);
        //GLCD_WriteString_16x11_buf(ScreenBuff,&(XO_line_1[0]),BandXO_X2, BandXO_Y);
        sprintf(Channel_line_1, "Ooops that's not right");
        GLCD_WriteString_12x7_buf(ScreenBuff,&(Channel_line_1[0]),Channel_X1, Channel_Y1);
    }
    
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
        
    controlData.UI_Display_Lockout = false;
}


/*******************************************************************************
  Function:
    void CF_Freq ( void )
  Remarks:
 * Presents screen for Selection of  Frequency 
******************************************************************************/
void CF_FREQUENCY(void)
{   
    char Freq_line_1[20];
    char Freq_line_2[20];
    char Freq_line_3[20];
    
    /* Write data to strings */
    sprintf(Freq_line_1, "Channel %d", (controlData.DDS_Channel + 1));
    sprintf(Freq_line_2, "Freq %5.1fHz", ((float)(controlData.Data_Values[controlData.DDS_Channel].Freq))/10);
    
    /**********************************************************/
    /*  Lets be nice and show the waveform on this screen too */
    /**********************************************************/
    if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Sine)
    {
        /* write correct template to screen buffer */
        WriteBMP(ScreenBuff, Freq_Sine, 0, 0, 128, 64);
        sprintf(Freq_line_3, "Sinewave");
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Triangle)
    {
        /* write correct template to screen buffer */
        WriteBMP(ScreenBuff, Freq_Triangle, 0, 0, 128, 64);
        sprintf(Freq_line_3, "Triangle");
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Square)
    {
        /* write correct template to screen buffer */
        WriteBMP(ScreenBuff, Freq_Square, 0, 0, 128, 64);
        sprintf(Freq_line_3, "Squarewave");
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Pulse)
    {
        /* write correct template to screen buffer */
        WriteBMP(ScreenBuff, Freq_Pulse, 0, 0, 128, 64);
        sprintf(Freq_line_3, "Pulse");
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Noise)
    {
        /* write correct template to screen buffer */
        WriteBMP(ScreenBuff, Freq_Noise, 0, 0, 128, 64);
        sprintf(Freq_line_3, "Noise");
    }
    else 
    {
        /* write correct template to screen buffer */
        WriteBMP(ScreenBuff, Freq_Noise, 0, 0, 128, 64);
        sprintf(Freq_line_3, "Hmmmm.");
    }
            
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Freq_line_1[0]),Freq_X1, Freq_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Freq_line_2[0]),Freq_X2, Freq_Y2);     
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Freq_line_3[0]),Freq_X3, Freq_Y3);
   
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}


/*******************************************************************************
  Function:
    void CF_Freq_Speed ( void )
  Remarks:
 * Presents screen for Selection of  Frequency 
******************************************************************************/
void CF_FREQ_SPEED(void)
{   
    char Freq_Speed_line_1[20];
    char Freq_Speed_line_2[20];
    char Freq_Speed_line_3[20];

    /**********************************************************/
    /*  Lets be nice and show the waveform on this screen too */
    /**********************************************************/
    if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Sine)
    {
        /* write appropriate screen template */
         WriteBMP(ScreenBuff, Freq_Step_Sine, 0, 0, 128, 64);
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Triangle)
    {
        /* write appropriate screen template */
         WriteBMP(ScreenBuff, Freq_Step_Triangle, 0, 0, 128, 64);
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Square)
    {
        /* write appropriate screen template */
         WriteBMP(ScreenBuff, Freq_Step_Square, 0, 0, 128, 64);
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Pulse)
    {
        /* write appropriate screen template */
         WriteBMP(ScreenBuff, Freq_Step_Pulse, 0, 0, 128, 64);
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Noise)
    {
        /* write appropriate screen template */
         WriteBMP(ScreenBuff, Freq_Step_Noise, 0, 0, 128, 64);
    }
    else 
    {
        /* write appropriate screen template */
         WriteBMP(ScreenBuff, Freq_Step_Sine, 0, 0, 128, 64);
    }
    
    /* Write data to strings */
    sprintf(Freq_Speed_line_1, "Channel %d", (controlData.DDS_Channel + 1));
    sprintf(Freq_Speed_line_3, "%3.1f Hertz", ((float)(controlData.Data_Values[controlData.DDS_Channel].Freq_Speed))/10);
    sprintf(Freq_Speed_line_2, "Increment");
    
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Freq_Speed_line_1[0]),Freq_Speed_X1, Freq_Speed_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Freq_Speed_line_2[0]),Freq_Speed_X2, Freq_Speed_Y2);     
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Freq_Speed_line_3[0]),Freq_Speed_X3, Freq_Speed_Y3);
   
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CF_SWEEP_ON ( void )
  Remarks:
 * Presents screen for Selection of Pulse on/off function 
******************************************************************************/
void CF_SWEEP_ON(void)
{   
    char Sweep_On_line_1[20];
    char Sweep_On_line_2[20];
    char Sweep_On_line_3[20];
    char Sweep_On_line_4[20];
   
    /* write template for this screen */
    WriteBMP(ScreenBuff, Sweep_Input_Template, 0, 0, 128, 64);
    
    /* Write data to strings */
    sprintf(Sweep_On_line_1, "DDS Channel %d", (controlData.DDS_Channel + 1));
    if(controlData.Data_Values[controlData.DDS_Channel].Sweep_On == Sweep_Linear)
        sprintf(Sweep_On_line_2, "Sweep Linear");
    else if (controlData.Data_Values[controlData.DDS_Channel].Sweep_On == Sweep_Log)
        sprintf(Sweep_On_line_2, "Sweep Log");
    else
        sprintf(Sweep_On_line_2, "Sweep Off");
    sprintf(Sweep_On_line_3, "Start");
    sprintf(Sweep_On_line_4, "%.1fHz",(float)controlData.Data_Values[controlData.DDS_Channel].Freq/10);
            
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Sweep_On_line_1[0]),Sweep_On_X1, Sweep_On_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Sweep_On_line_2[0]),Sweep_On_X2, Sweep_On_Y2);     
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Sweep_On_line_3[0]),Sweep_On_X3, Sweep_On_Y3);     
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Sweep_On_line_4[0]),Sweep_On_X4, Sweep_On_Y4);     
   
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}


/*******************************************************************************
  Function:
    void CF_SWEEP_END ( void )
  Remarks:
 * Presents screen for Selection of Sweep End frequency 
******************************************************************************/
void CF_SWEEP_END(void)
{   
    char Sweep_End_line_1[20];
    char Sweep_End_line_2[20];
    char Sweep_End_line_3[20];
    char Sweep_End_line_4[20];
    
    /* write template for this screen */
    WriteBMP(ScreenBuff, Sweep_Input_Template, 0, 0, 128, 64);
    
    /* Write data to strings */
    sprintf(Sweep_End_line_1, "Channel %d Sweep", (controlData.DDS_Channel + 1));
    sprintf(Sweep_End_line_2, "End: %.1fHz", ((float)(controlData.Data_Values[controlData.DDS_Channel].Sweep_End))/10);
    sprintf(Sweep_End_line_3, "Start");
    sprintf(Sweep_End_line_4, "%.1fHz",(float)controlData.Data_Values[controlData.DDS_Channel].Freq/10);
            
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Sweep_End_line_1[0]),Sweep_End_X1, Sweep_End_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Sweep_End_line_2[0]),Sweep_End_X2, Sweep_End_Y2);     
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Sweep_End_line_3[0]),Sweep_End_X3, Sweep_End_Y3);     
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Sweep_End_line_4[0]),Sweep_End_X4, Sweep_End_Y4);     
   
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CF_SWEEP_TIME ( void )
  Remarks:
 * Presents screen for Selection of Sweep duration in tenths of a second 
******************************************************************************/
void CF_SWEEP_TIME(void)
{   
    char Sweep_Time_line_1[20];
    char Sweep_Time_line_2[20];
    char Sweep_Time_line_3[20];
    char Sweep_Time_line_4[20];
    
    /* write template for this screen */
    WriteBMP(ScreenBuff, Sweep_Input_Template, 0, 0, 128, 64);
    
    /* Write data to strings */
    sprintf(Sweep_Time_line_1, "Channel %d Sweep", (controlData.DDS_Channel + 1));
    sprintf(Sweep_Time_line_2, "Time: %.1f Sec.", ((float)(controlData.Data_Values[controlData.DDS_Channel].Sweep_Time)/10));
    sprintf(Sweep_Time_line_3, "Start");
    sprintf(Sweep_Time_line_4, "%.1fHz",(float)controlData.Data_Values[controlData.DDS_Channel].Freq/10);
            
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Sweep_Time_line_1[0]),Sweep_Time_X1, Sweep_Time_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Sweep_Time_line_2[0]),Sweep_Time_X2, Sweep_Time_Y2);     
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Sweep_Time_line_3[0]),Sweep_End_X3, Sweep_End_Y3);     
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Sweep_Time_line_4[0]),Sweep_End_X4, Sweep_End_Y4);     
   
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CF_WAVEFORM ( void )
  Remarks:
 * Presents screen for Selection of  Frequency 
******************************************************************************/
void CF_WAVEFORM(void)
{   
    char Waveform_line_1[20];
    char Waveform_line_2[20];
    char Waveform_line_3[20];
    
    /* Write data to strings */
    sprintf(Waveform_line_1, "Channel no: %d", (controlData.DDS_Channel + 1));
    if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Sine)
    {
        /* write WAVEFORM TEMPLATE to screen buffer */
        WriteBMP(ScreenBuff, Sine_Template, 0, 0, 128, 64);
        sprintf(Waveform_line_2, "Sine Wave");
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Triangle)
    {
        /* write WAVEFORM TEMPLATE to screen buffer */
        WriteBMP(ScreenBuff, Triangle_Template, 0, 0, 128, 64);
        sprintf(Waveform_line_2, "Triangle Wave");
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Square)
    {
        /* write WAVEFORM TEMPLATE to screen buffer */
        WriteBMP(ScreenBuff, Square_Template, 0, 0, 128, 64);
        sprintf(Waveform_line_2, "Square Wave");
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Pulse)
    {
        /* write WAVEFORM TEMPLATE to screen buffer */
        WriteBMP(ScreenBuff, Pulse_Template, 0, 0, 128, 64);
        sprintf(Waveform_line_2, "Pulse");
    }
    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Noise)
    {
        /* write WAVEFORM TEMPLATE to screen buffer */
        WriteBMP(ScreenBuff, Noise_Template, 0, 0, 128, 64);
        sprintf(Waveform_line_2, "Noise");
    }
    else 
    {
         /* write WAVEFORM TEMPLATE to screen buffer */
        WriteBMP(ScreenBuff, Oops_Template, 0, 0, 128, 64);
        sprintf(Waveform_line_2, "Something's wrong");
    }
  
//    sprintf(Waveform_line_3, "Test...");
            
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Waveform_line_1[0]),Waveform_X1, Waveform_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Waveform_line_2[0]),Waveform_X2, Waveform_Y2);     
//    GLCD_WriteString_12x7_buf(ScreenBuff,&(Waveform_line_3[0]),Waveform_X3, Waveform_Y3);
   
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CF_Ratio ( void )
  Remarks:
 * Presents screen for Selection of Pulse Waveform Duty Cycle Ratio on/off 
******************************************************************************/
void CF_RATIO(void)
{   
    char Ratio_line_1[20];
    char Ratio_line_2[20];
    char Ratio_line_3[20];
    int ratio_x, x, y;    
    
    /* Write template to screen */
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    WriteBMP(ScreenBuff, Pulse_Ratio, 0, 0, 128, 64);

        /* Write data to strings */
    sprintf(Ratio_line_2, "Duty Cycle %d%%",controlData.Data_Values[controlData.DDS_Channel].Ratio);
    sprintf(Ratio_line_1, "Pulse Waveform");
            
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Ratio_line_1[0]),Ratio_X1, Ratio_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Ratio_line_2[0]),Ratio_X2, Ratio_Y2);

    
    /* fill in the bar graph... */
    /* How many pizels ON*/
    ratio_x = controlData.Data_Values[controlData.DDS_Channel].Ratio / Pixels_per_Percent;
    ratio_x += Ratio_X_Zero;
    /* now draw the top line - from xmin at positive offser for "x" */
        GLCD_DrawLineBuf(ScreenBuff, Ratio_X_Zero, Ratio_y_Zero - Ratio_Height, ratio_x, Ratio_y_Zero - Ratio_Height);
    /* now straight down at ratio from positive to neg*/    
        GLCD_DrawLineBuf(ScreenBuff, ratio_x, Ratio_y_Zero - Ratio_Height, ratio_x, Ratio_y_Zero + Ratio_Height);
    /* now draw the bottom line - from ratiox at negative offset for "x" */
        GLCD_DrawLineBuf(ScreenBuff, ratio_x, Ratio_y_Zero + Ratio_Height, Ratio_Fullwave + Ratio_X_Zero , Ratio_y_Zero + Ratio_Height);
    /* now straight up at fullwave position at positive offser*/    
        GLCD_DrawLineBuf(ScreenBuff, Ratio_Fullwave + Ratio_X_Zero, Ratio_y_Zero + Ratio_Height, Ratio_Fullwave + Ratio_X_Zero, Ratio_y_Zero - Ratio_Height);

    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CF_PULSE_ON ( void )
  Remarks:
 * Presents screen for Selection of Pulse on/off function 
******************************************************************************/
void CF_PULSE_ON(void)
{   
    char Pulses_On_line_1[20];
    char Pulses_On_line_2[20];
    char Pulses_On_line_3[20];
    char Pulses_On_line_4[20];
    
    /* Write template to screen */
    /* use this lock to stop changing display strings half way through */

    controlData.UI_Display_Lockout = true;

    /* Write data to strings */
    sprintf(Pulses_On_line_1, "Channel %d", (controlData.DDS_Channel + 1));
    if(controlData.Data_Values[controlData.DDS_Channel].Pulse_On)
    {
        sprintf(Pulses_On_line_2, "Pulse Train On");
        sprintf(Pulses_On_line_3, "%d on", controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On);
        sprintf(Pulses_On_line_4, "%d off", controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off);
    }
    else 
    {
        sprintf(Pulses_On_line_2, "Pulse Train Off");
        sprintf(Pulses_On_line_3, "- on");
        sprintf(Pulses_On_line_4, "- off");
    }

    WriteBMP(ScreenBuff, Pulse_Train, 0, 0, 128, 64);
    if (controlData.state == CS_PULSE_CYCLES_ON)
    {
        WriteBMP(ScreenBuff, Pulse_Train_Ontime, 0, 0, 128, 64);
        if (controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On == 1)
            sprintf(Pulses_On_line_2,"%d Pulse On", controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On);    
        else
            sprintf(Pulses_On_line_2,"%d Pulses On", controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On);    

    }
    else if  (controlData.state == CS_PULSE_CYCLES_OFF)   
    {
        WriteBMP(ScreenBuff, Pulse_Train_Offtime, 0, 0, 128, 64);
        if(controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off == 1)
            sprintf(Pulses_On_line_2, "%d Pulse Off", controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off);    
        else
            sprintf(Pulses_On_line_2, "%d Pulses Off", controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off);    
            
    }
    else;

    
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Pulses_On_line_1[0]),Pulse_On_X1, Pulse_On_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Pulses_On_line_2[0]),Pulse_On_X2, Pulse_On_Y2);     
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Pulses_On_line_3[0]),Pulse_On_X3, Pulse_On_Y3);
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Pulses_On_line_4[0]),Pulse_On_X4, Pulse_On_Y4);
   
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}


/*******************************************************************************
  Function:
    void CF_PHASE ( void )
  Remarks:
 * Presents screen for Entry of the phase shift to be applied to the channel  
******************************************************************************/
void CF_PHASE(void)
{   
    char Phase_line_1[20];
    char Phase_line_2[20];
    char Phase_line_3[20];
    char Phase_line_4[20];

    controlData.UI_Display_Lockout = true;

    /* Write data to strings */
    sprintf(Phase_line_1, "Channel %d", (controlData.DDS_Channel + 1));
    sprintf(Phase_line_2, "%d Degrees", controlData.Data_Values[controlData.DDS_Channel].Phase_Shift);
    sprintf(Phase_line_3, "Phase");
    sprintf(Phase_line_4, "Shift");

    WriteBMP(ScreenBuff, Phase_Template, 0, 0, 128, 64);
   
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Phase_line_1[0]),Phase_X1, Phase_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(Phase_line_2[0]),Phase_X2, Phase_Y2);     
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Phase_line_3[0]),Phase_X3, Phase_Y3);
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Phase_line_4[0]),Phase_X4, Phase_Y4);
   
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;

}




/* Call this to update all Atten settings etc 					*/
/* This needs to be filled in....                               */
void Update_Atten_Set(int Attenuation)
{
int temp_atten1;
int temp_atten2;

/* do channel 1 first */
}



/*******************************************************************************
  Function:
    void CF_ATTEN ( void )
  Remarks:
 * PResents strart up screen, initialises display for idle state
******************************************************************************/
void CF_ATTEN(void)
{   
    int vol_x, x, y;
    char ATTEN_line_1[20];
    char ATTEN_line_2[20];
    
    /* write idle screed (Solder BMP) to screen buffer */
    /* use this lock to stop changing display strings half way through */

    controlData.UI_Display_Lockout = true;
    WriteBMP(ScreenBuff, TGM_MAIN_VOL, 0, 0, 128, 64);

        /* Write data to strings */
    sprintf(ATTEN_line_1, "Output");
    /* Watch out - Phil the pillock has Atten in 0.1dB steps.  So this is divided by 10 */
    sprintf(ATTEN_line_2, "%3.1f dB Volts",  Level_Offset-(float)((float)controlData.Data_Values[controlData.DDS_Channel].Atten)/10);
            
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    
    //    WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(ATTEN_line_1[0]),Level_X1, Level_Y1);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(ATTEN_line_2[0]),Level_X2, Level_Y2);     

    
    /* fill in the bar graph... */
    vol_x = (((Atten_Max-(controlData.Data_Values[controlData.DDS_Channel].Atten)) * (UI_VOLBAR_XMAX - UI_VOLBAR_XMIN))/(Atten_Max - Atten_Min));
    if (vol_x == 1)
        GLCD_DrawLineBuf(ScreenBuff,UI_VOLBAR_XMIN, UI_VOLBAR_YMIN + 1, UI_VOLBAR_XMIN, UI_VOLBAR_YMAX-1,1);
    if ((vol_x > 1) && (vol_x < Atten_Max))
        for (x = 1; x <= vol_x; x++)
            GLCD_DrawLineBuf(ScreenBuff,UI_VOLBAR_XMIN + x, UI_VOLBAR_YMIN, UI_VOLBAR_XMIN + x, UI_VOLBAR_YMAX,1);
    if (vol_x == Atten_Max)
        GLCD_DrawLineBuf(ScreenBuff,UI_VOLBAR_XMAX, UI_VOLBAR_YMIN + 1, UI_VOLBAR_XMAX -1, UI_VOLBAR_YMAX - 1,1);
   
    Update_Atten_Set((int)controlData.Data_Values[controlData.DDS_Channel].Atten);
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CONTROL_Initialize ( void )

  Remarks:
    See prototype in control.h.
******************************************************************************/
void CONTROL_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    controlData.state = CS_INIT;
    controlData.UI_Timer = DRV_HANDLE_INVALID;
    controlData.UI_Count = 3;
    controlData.UI_Update_Counter = 0;
    controlData.UI_Speed = Speed_Init;
    controlData.UI_Speed = Freq_Normal_Speed;
    controlData.UI_Update_Display = true;
    controlData.UI_Display_Lockout = false;
    controlData.UI_Keypressed = false;
    controlData.UI_Action = CS_SAVE;
    controlData.heartbeatTimer = DRV_HANDLE_INVALID;
    controlData.heartbeatCount = 0;
    controlData.heartbeatToggle = false;
    controlData.MemoryBankSelected = 0;
    controlData.Revert_To_Idle_Counter = Revert_To_Idle;
    controlData.UI_Fast_Count = Fast_Counter_Init;
    controlData.UI_Slow_Count = Slow_Counter_Init;
    controlData.DDS_Channel = DDS_Channel_Min;
    
    /* set port E to drive logic high for encoder / buttons*/
    Drive_PortE_Out;
    EEPROM_Disable_Hold;
}


/******************************************************************************/
//  Function:
//    void CONTROL_EEPROM_Save ( void )
// AIm
//     - Save the data set to EEPROM
/*******************************************************************************/
void CONTROL_EEPROM_Save(char Mem_Bank )
{
    char line[16];
  
    WriteBMP(ScreenBuff, YES, 0, 0, 128, 64);
    sprintf(line, "Saved");
    GLCD_WriteString_16x11_buf(ScreenBuff,&(line[0]),Saved_X, Saved_Y);
    Refresh_LCD;
    /* volume and input */

    for (loop=DDS_Channel_Min; loop <= DDS_Channel_Max; loop++)        
    {
       	Data_Values_Pointer = &(controlData.Data_Values[loop]);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Freq_Offset), Data_Values_Pointer->Freq);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Freq_Speed_Offset), Data_Values_Pointer->Freq_Speed);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Atten_Offset), Data_Values_Pointer->Atten);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Waveform_Offset), Data_Values_Pointer->Waveform);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Ratio_Offset), Data_Values_Pointer->Ratio);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Sweep_On_Offset), Data_Values_Pointer->Sweep_On);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Sweep_End_Offset), Data_Values_Pointer->Sweep_End);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Sweep_Time_Offset), Data_Values_Pointer->Sweep_Time);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Pulse_On_Offset), Data_Values_Pointer->Pulse_On);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Pulse_Cycles_On_Offset), Data_Values_Pointer->Pulse_Cycles_On);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Pulse_Cycles_Off_Offset), Data_Values_Pointer->Pulse_Cycles_Off);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Phase_Shift_Offset), Data_Values_Pointer->Phase_Shift);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + AM_On_Offset), Data_Values_Pointer->AM_On);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + AM_Level_Offset), Data_Values_Pointer->AM_Level);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + AM_Freq_Offset), Data_Values_Pointer->AM_Freq);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + FM_On_Offset), Data_Values_Pointer->FM_On);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + FM_Excursion_Offset), Data_Values_Pointer->FM_Excursion);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + FM_Freq_Offset), Data_Values_Pointer->FM_Freq);
        };

    DelayMs(Delay_After_Save_Ms);
    WriteBMP(ScreenBuff, Splash_2, 0, 0, 128, 64);
    controlData.UI_Update_Display = true;
    Refresh_LCD;
}

/******************************************************************************/
//  Function:
//    void CONTROL_Choose_Fucntion ( void )
//    
// AIm
//     - PResent options to user for choice of other functions
/*******************************************************************************/
void CF_CHOOSE( void )
{
    switch (controlData.UI_Action)
    {
        case CONTROL_ACTION_SAVE:
        {
            WriteBMP(ScreenBuff, Choose_Function, 0, 0, 128, 64);
            WriteBMP_Buf(ScreenBuff, Choose_Save, Q1_Graphic_x, Q1_Graphic_y, 63, 32);
            Refresh_LCD;
        }
        break;
        
        case CONTROL_ACTION_CH2:
        {
            WriteBMP(ScreenBuff, Choose_Function, 0, 0, 128, 64);
            WriteBMP_Buf(ScreenBuff, Choose_CH2, Q3_Graphic_x, Q3_Graphic_y, 64, 32);
            Refresh_LCD;
        }
        break;
        
        case CONTROL_ACTION_LOAD:
        {
            WriteBMP(ScreenBuff, Choose_Function, 0, 0, 128, 64);
            WriteBMP_Buf(ScreenBuff, Choose_Load, Q4_Graphic_x, Q4_Graphic_y, 63, 32);
            Refresh_LCD;
        }
        break;
        
        case CONTROL_ACTION_CH1:
        {
            WriteBMP(ScreenBuff, Choose_Function, 0, 0, 128, 64);
            WriteBMP_Buf(ScreenBuff, Choose_CH1, Q2_Graphic_x, Q2_Graphic_y, 64, 32);
            Refresh_LCD;
        }
        break;
    }
}

/******************************************************************************/
//  Function:
//    void CF_CALC_SWEEP LUT ( void )
//    The application needs to do these calcs a fair bit
//    - each time the frequency isw changed
//    - each time the sweep parameters change
// AIm
//     - Initialise sweeep variables
/*******************************************************************************/
void CF_SWEEP_UPDATE_VARS(void)
{
int temp, chan_temp;

    if(controlData.DDS_Channel == HardCode_Ch1)
    {
        /*********     now the log scaling        ********/
        /*  This is the log range we want to sweep over  */
        Ch1_Log_Scale = log10((double)((double)controlData.Data_Values[DDS_Channel_Min].Sweep_End / (double)controlData.Data_Values[DDS_Channel_Min].Freq));
        /* The sweep Range */
        Ch1_Sweep_Calc_Freq_Range = controlData.Data_Values[DDS_Channel_Min].Sweep_End - controlData.Data_Values[DDS_Channel_Min].Freq;
        Ch1_Sweep_Start = controlData.Data_Values[DDS_Channel_Min].Freq;
        /* We need to know the phase increment at the start of the sweep */
        Temp_Calc_Store = (long long)0x000100000000;
        Temp_Calc_Store = Temp_Calc_Store * Ch1_Sweep_Start;
        Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
        Ch1_Sweep_Base = (unsigned int) Temp_Calc_Store; 
        /* now calculate phase increment - Channel 1*/
        for(temp=0; temp < 4096; temp++)
        {
            if(controlData.Data_Values[HardCode_Ch1].Sweep_On == 0)
            {
                Ch1_Sweep_LUT[temp] = 0; /* no sweep*/
                Ch1_Sweep_Phase = 0;
            }
            else if (controlData.Data_Values[HardCode_Ch1].Sweep_On == Sweep_Linear)
            {
                Temp_Calc_Store = (long long)0x000100000000;
                Temp_Calc_Store = Temp_Calc_Store * ((Ch1_Sweep_Calc_Freq_Range * temp/4095) + Ch1_Sweep_Start);
                Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
                Ch1_Sweep_LUT[temp] = (unsigned int) Temp_Calc_Store - Ch1_Sweep_Base; 
            }
            else if (controlData.Data_Values[HardCode_Ch1].Sweep_On == Sweep_Log)
            {
                Ch1_Log_Intermediate = pow(10, (double)((double)temp*(double)Ch1_Log_Scale/(double)4095));
                Ch1_Log_Intermediate = Ch1_Log_Intermediate * Ch1_Sweep_Start;                    
                Temp_Calc_Store = (long long)(0x000100000000 * Ch1_Log_Intermediate);
                Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
                Ch1_Sweep_LUT[temp] = (unsigned int) Temp_Calc_Store - Ch1_Sweep_Base; 
            }
        }
        /* initialise sweep phase register to zero */
        Ch1_Sweep_Phase_Inc = 0x100000000/Sample_Rate;
        Ch1_Sweep_Phase_Inc *= 10;
        Ch1_Sweep_Phase_Inc /= controlData.Data_Values[HardCode_Ch1].Sweep_Time;
        Ch2_Sweep_Phase_Inc /= controlData.Data_Values[HardCode_Ch2].Sweep_Time;
        Ch1_Sweep_Phase_Reg = 0;
    }
    else
    {
        /*********     now the log scaling        ********/
        /*  This is the log range we want to sweep over  */
        Ch2_Log_Scale = log10((double)((double)controlData.Data_Values[DDS_Channel_Max].Sweep_End / (double)controlData.Data_Values[DDS_Channel_Max].Freq));
        /* The sweep Range */
        Ch2_Sweep_Calc_Freq_Range = controlData.Data_Values[DDS_Channel_Max].Sweep_End - controlData.Data_Values[DDS_Channel_Max].Freq;
        Ch2_Sweep_Start = controlData.Data_Values[DDS_Channel_Max].Freq;
        /* now calculate phase increment - Channel 2*/
        /* We need to know the phase increment at the start of the sweep */
        Temp_Calc_Store = (long long)0x000100000000;
        Temp_Calc_Store = Temp_Calc_Store * Ch2_Sweep_Start;
        Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
        Ch2_Sweep_Base = (unsigned int) Temp_Calc_Store; 

        for(temp=0; temp < 4096; temp++)
        {
            if(controlData.Data_Values[HardCode_Ch2].Sweep_On == 0)
            {
                Ch2_Sweep_LUT[temp] = 0; /* no sweep*/
                Ch2_Sweep_Phase = 0;
            }
            else if (controlData.Data_Values[HardCode_Ch2].Sweep_On == Sweep_Linear)
            {
                Temp_Calc_Store = (long long)0x000100000000;
                Temp_Calc_Store = Temp_Calc_Store * ((Ch2_Sweep_Calc_Freq_Range * temp/4095) + Ch2_Sweep_Start);
                Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
                Ch2_Sweep_LUT[temp] = (unsigned int) Temp_Calc_Store - Ch2_Sweep_Base; 
            }
            else if (controlData.Data_Values[HardCode_Ch2].Sweep_On == Sweep_Log)
            {
                Ch2_Log_Intermediate = pow(10, (double)((double)temp*(double)Ch2_Log_Scale/(double)4095));
                Ch2_Log_Intermediate = Ch2_Log_Intermediate * Ch2_Sweep_Start;                    
                Temp_Calc_Store = (long long)(0x000100000000 * Ch2_Log_Intermediate);
                Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
                Ch2_Sweep_LUT[temp] = (unsigned int) Temp_Calc_Store - Ch2_Sweep_Base; 
            }
        }
        /* initialise sweep phase register to zero */
        Ch2_Sweep_Phase_Inc = 0x100000000/Sample_Rate;
        Ch2_Sweep_Phase_Inc *= 10;
        Ch2_Sweep_Phase_Inc /= controlData.Data_Values[HardCode_Ch2].Sweep_Time;
        Ch2_Sweep_Phase_Reg = 0;
    }
    /* clear key pressed now*/
    controlData.UI_Keypressed = false;
}


/******************************************************************************/
//  Function:
//    void CF_INIT_VARS ( void )
//    
// AIm
//     - Initialise loaded variables
/*******************************************************************************/
void CF_INIT_VARS(void)
{
    int temp, chan_temp;
    /****************************************************************/
    /* initialise DDS                                               */
    /* the DDS phase register (accumulator) is 32 bits winde        */
    /* The DDS adds phase each clock cycle, and the rate the        */
    /* phase accumulator overflows is the frequency                 */
    /* So the phase you want to add each clock is equal to:         */
    /*          Accumulator Width = 2^32 In outr case               */
    /*          Multipled by the frequency we want                  */
    /*          DIVIDED by the sample rate                          */
    /* we need to use a long long for these sums to retain precision*/
    /****************************************************************/
    /* First Channel 1 */
    Temp_Calc_Store = 0x100000000; // 2^32
    Temp_Calc_Store = Temp_Calc_Store * controlData.Data_Values[DDS_Channel_Min].Freq;
    Temp_Calc_Store = Temp_Calc_Store / (Sample_Rate * 10);  // freq is in 10th of Hz
    Phase_Inc_Ch1 = (long) Temp_Calc_Store;

    /* Now Channel 2*/
    Temp_Calc_Store = 0x100000000; // 2^32
    Temp_Calc_Store = Temp_Calc_Store * controlData.Data_Values[DDS_Channel_Min + 1].Freq;
    Temp_Calc_Store = Temp_Calc_Store / (Sample_Rate * 10);  // freq is in 10th of Hz
    Phase_Inc_Ch2 = (long) Temp_Calc_Store;

    /* start with output ON for puse gen*/
    Ch1_Pulse_Output_Active = 1;
    Ch2_Pulse_Output_Active = 1; /* Channel 1 and 2 Pule Output on */
    Ch1_Pulse_Counter = controlData.Data_Values[HardCode_Ch1].Pulse_Cycles_On;
    Ch2_Pulse_Counter = controlData.Data_Values[HardCode_Ch2].Pulse_Cycles_On;   /* start with both at 0 */

    /****************************************************************/
    /*      Load waveforms as defined in EEPROM...                  */
    /****************************************************************/
    for(chan_temp = HardCode_Ch1; chan_temp <= HardCode_Ch2; chan_temp++)
    {
        if (controlData.Data_Values[chan_temp].Waveform == Sine)
        {
            /****************************************************************/
            /*      Load the DDS LUT with a sinewave...                     */
            /****************************************************************/
            for(temp = 0; temp < Waveform_LUT_Size; temp++)
            {
                if(chan_temp == HardCode_Ch1)
                    Ch1_LUT[temp] = Sine_LUT[temp];
                else
                    Ch2_LUT[temp] = Sine_LUT[temp];
            }
        }
        else if (controlData.Data_Values[chan_temp].Waveform == Triangle)
        {
            /****************************************************************/
            /*      Load DDS waveform with a triangle...                    */
            /****************************************************************/
            for(temp = 0; temp < (Waveform_LUT_Size/4); temp++)
            {
                /* ok the 0x2000 is 2^24 divided by 1024*/
                if(chan_temp == HardCode_Ch1)
                    Ch1_LUT[temp] = temp * 0x2000;
                else
                    Ch2_LUT[temp] = temp * 0x2000;
            }
            for(temp = 0; temp < (Waveform_LUT_Size/2); temp++)
            {
                if(chan_temp == HardCode_Ch1)
                    Ch1_LUT[(Waveform_LUT_Size/4) + temp] = 0x7fffff - temp * 0x2000;
                else
                    Ch2_LUT[(Waveform_LUT_Size/4) + temp] = 0x7fffff - temp * 0x2000;
            }
            for(temp = 0; temp < (Waveform_LUT_Size/4); temp++)
            {
                if(chan_temp == HardCode_Ch1)
                    Ch1_LUT[(3*(Waveform_LUT_Size/4)) + temp] = -0x7fffff + temp * 0x2000;
                else
                    Ch2_LUT[(3*(Waveform_LUT_Size/4)) + temp] = -0x7fffff + temp * 0x2000;
            }
        }
        else if (controlData.Data_Values[chan_temp].Waveform == Square)
        {
            /****************************************************************/
            /*      Load DDS waveform with a Square...                    */
            /****************************************************************/
            for(temp = 0; temp < (Waveform_LUT_Size/2); temp++)
            {
                if(chan_temp == HardCode_Ch1)
                    Ch1_LUT[temp] = +0x7fffff;
                else
                    Ch2_LUT[temp] = +0x7fffff;
            }
            for(temp = 0; temp < (Waveform_LUT_Size/2); temp++)
            {
                if(chan_temp == HardCode_Ch1)
                    Ch1_LUT[2048 + temp] = -0x7fffff;
                else
                    Ch2_LUT[2048 + temp] = -0x7fffff;
            }
        }
        else if (controlData.Data_Values[chan_temp].Waveform == Pulse)
        {
            /****************************************************************/
            /*      Load DDS waveform with a pulse...                       */
            /****************************************************************/
            for(temp = 0; temp < ((Waveform_LUT_Size*controlData.Data_Values[chan_temp].Ratio)/100); temp++)
            {
                if(chan_temp == HardCode_Ch1)
                    Ch1_LUT[temp] = 0x7fffff;
                else
                    Ch2_LUT[temp] = 0x7fffff;
            }
            for(temp = ((Waveform_LUT_Size*controlData.Data_Values[chan_temp].Ratio)/100); temp < Waveform_LUT_Size; temp++)
            {
                if(chan_temp == HardCode_Ch1)
                    Ch1_LUT[temp] = -0x7fffff;
                else
                    Ch2_LUT[temp] = -0x7fffff;
            }
        }
        else if (controlData.Data_Values[chan_temp].Waveform == Noise)
        {
            /****************************************************************/
            /*      Start the DDS with a noise...                        */
            /****************************************************************/
            for(temp = 0; temp < Waveform_LUT_Size; temp++)
            {
                if(chan_temp == HardCode_Ch1)
                    Ch1_LUT[temp] = Noise_LUT[temp];
                else
                    Ch2_LUT[temp] = Noise_LUT[temp];
            }
        }
    }
    /****************************************************************/
    /*      Start at amplitude of...                                   */
    /****************************************************************/
    Ch1_Level_Mult = (long)(Atten_Scale * pow(10,(-(float)(((float)controlData.Data_Values[HardCode_Ch1].Atten)/10))/20));
    Ch2_Level_Mult = (long)(Atten_Scale * pow(10,(-(float)(((float)controlData.Data_Values[HardCode_Ch2].Atten)/10))/20));

    /***************************************************************/
    /*                      initilise phase offsets                */
    /***************************************************************/
    Ch1_Phase_Delta = controlData.Data_Values[HardCode_Ch1].Phase_Shift;
    Ch2_Phase_Delta = controlData.Data_Values[HardCode_Ch2].Phase_Shift;

    /***************************************************************/
    /*                      initilise sweep                        */
    /***************************************************************/
    /*********     now the log scaling        ********/
    /*  This is the log range we want to sweep over  */
    Ch1_Log_Scale = log10((double)((double)controlData.Data_Values[DDS_Channel_Min].Sweep_End / (double)controlData.Data_Values[DDS_Channel_Min].Freq));
    Ch2_Log_Scale = log10((double)((double)controlData.Data_Values[DDS_Channel_Max].Sweep_End / (double)controlData.Data_Values[DDS_Channel_Max].Freq));

    /* The sweep Range */
    Ch1_Sweep_Calc_Freq_Range = controlData.Data_Values[DDS_Channel_Min].Sweep_End - controlData.Data_Values[DDS_Channel_Min].Freq;
    Ch1_Sweep_Start = controlData.Data_Values[DDS_Channel_Min].Freq;
    Ch2_Sweep_Calc_Freq_Range = controlData.Data_Values[DDS_Channel_Max].Sweep_End - controlData.Data_Values[DDS_Channel_Max].Freq;
    Ch2_Sweep_Start = controlData.Data_Values[DDS_Channel_Max].Freq;
    /* We need to know the phase increment at the start of the sweep */
    Temp_Calc_Store = (long long)0x000100000000;
    Temp_Calc_Store = Temp_Calc_Store * Ch1_Sweep_Start;
    Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
    Ch1_Sweep_Base = (unsigned int) Temp_Calc_Store; 
    /* We need to know the phase increment at the start of the sweep */
    Temp_Calc_Store = (long long)0x000100000000;
    Temp_Calc_Store = Temp_Calc_Store * Ch2_Sweep_Start;
    Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
    Ch2_Sweep_Base = (unsigned int) Temp_Calc_Store; 

    /* now calculate phase increment - Channel 1*/
    for(temp=0; temp < 4096; temp++)
    {
        if(controlData.Data_Values[HardCode_Ch1].Sweep_On == 0)
        {
            Ch1_Sweep_LUT[temp] = 0; /* no sweep*/
            Ch1_Sweep_Phase = 0;
        }
        else if (controlData.Data_Values[HardCode_Ch1].Sweep_On == Sweep_Linear)
        {
            Temp_Calc_Store = (long long)0x000100000000;
            Temp_Calc_Store = Temp_Calc_Store * ((Ch1_Sweep_Calc_Freq_Range * temp/4095) + Ch1_Sweep_Start);
            Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
            Ch1_Sweep_LUT[temp] = (unsigned int) Temp_Calc_Store - Ch1_Sweep_Base; 
        }
        else if (controlData.Data_Values[HardCode_Ch1].Sweep_On == Sweep_Log)
        {
            Ch1_Log_Intermediate = pow(10, (double)((double)temp*(double)Ch1_Log_Scale/(double)4095));
            Ch1_Log_Intermediate = Ch1_Log_Intermediate * Ch1_Sweep_Start;                    
            Temp_Calc_Store = (long long)(0x000100000000 * Ch1_Log_Intermediate);
            Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
            Ch1_Sweep_LUT[temp] = (unsigned int) Temp_Calc_Store - Ch1_Sweep_Base; 
        }
    }

    /* now calculate phase increment - Channel 2*/
    for(temp=0; temp < 4096; temp++)
    {
        if(controlData.Data_Values[HardCode_Ch2].Sweep_On == 0)
        {
            Ch2_Sweep_LUT[temp] = 0; /* no sweep*/
            Ch2_Sweep_Phase = 0;
        }
        else if (controlData.Data_Values[HardCode_Ch2].Sweep_On == Sweep_Linear)
        {
            Temp_Calc_Store = (long long)0x000100000000;
            Temp_Calc_Store = Temp_Calc_Store * ((Ch2_Sweep_Calc_Freq_Range * temp/4095) + Ch2_Sweep_Start);
            Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
            Ch2_Sweep_LUT[temp] = (unsigned int) Temp_Calc_Store - Ch2_Sweep_Base; 
        }
        else if (controlData.Data_Values[HardCode_Ch2].Sweep_On == Sweep_Log)
        {
            Ch2_Log_Intermediate = pow(10, (double)((double)temp*(double)Ch2_Log_Scale/(double)4095));
            Ch2_Log_Intermediate = Ch2_Log_Intermediate * Ch2_Sweep_Start;                    
            Temp_Calc_Store = (long long)(0x000100000000 * Ch2_Log_Intermediate);
            Temp_Calc_Store = Temp_Calc_Store/((long long)Sample_Rate * 10);
            Ch2_Sweep_LUT[temp] = (unsigned int) Temp_Calc_Store - Ch2_Sweep_Base; 
        }
    }
    /* initialise sweep phase register to zero */
    Ch1_Sweep_Phase_Inc = 0x100000000/Sample_Rate;
    Ch1_Sweep_Phase_Inc *= 10;
    Ch1_Sweep_Phase_Inc /= controlData.Data_Values[HardCode_Ch1].Sweep_Time;
    Ch1_Sweep_Phase_Reg = 0;
    Ch1_Sweep_Phase = 0;

    Ch2_Sweep_Phase_Inc = 0x100000000/Sample_Rate;
    Ch2_Sweep_Phase_Inc *= 10;
    Ch2_Sweep_Phase_Inc /= controlData.Data_Values[HardCode_Ch2].Sweep_Time;
    Ch2_Sweep_Phase_Reg = 0;
    Ch1_Sweep_Phase = 0;

    /* initialise generic stuff*/
    Phase_Acc_Ch1 = 0;   /* start channel 1 at 0 phase */
    Phase_Acc_Ch2 = 0;   /* start channel 2 at 0 phase */
    Old_Phase_Acc_Ch1 = 0;
    Old_Phase_Acc_Ch2 = 0;

}

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

/******************************************************************************
  Function:
    void CONTROL_Tasks ( void )

  Remarks:
    See prototype in CONTROL.h.
****************************************************************************/
void CONTROL_Tasks ( void )
{
    int il, jl, temp, chan_temp;

    /* keep track of how often we run through the loop */
    Increment_UI_Timer;
  
    /* Signal the application's heartbeat. */
    if (controlData.heartbeatToggle == true)
    {
//        SYS_PORTS_PinToggle(PORTS_ID_0, APP_HEARTBEAT_PORT,
//                            APP_HEARTBEAT_PIN);
//        SYS_PORTS_PinClear( PORTS_ID_0, 
//                            APP_HEARTBEAT_PORT,
//                            APP_HEARTBEAT_PIN);        
        controlData.heartbeatToggle = false;
    }
    
    /* Check the application's current state. */
    switch ( controlData.state )
    {
        /* Application's initial state. */
        case CS_INIT:
        {
            //  Initialise the test vector
            test_data = 0;
            // Heartbeat ISR Timer
            controlData.heartbeatTimer = DRV_TMR_Open( APP_HEARTBEAT_TMR,
                DRV_IO_INTENT_EXCLUSIVE);
            if ( DRV_HANDLE_INVALID != controlData.heartbeatTimer )
            {
                DRV_TMR_AlarmRegister(controlData.heartbeatTimer,
                                    APP_HEARTBEAT_TMR_PERIOD,
                                    APP_HEARTBEAT_TMR_IS_PERIODIC,
                                    (uintptr_t)&controlData,
                                    APP_TimerCallback);
                DRV_TMR_Start(controlData.heartbeatTimer);
                //controlData.state = CONTROL_STATE_LCDINIT;
            }

            // User Interface ISR Timer
            controlData.UI_Timer = DRV_TMR_Open( APP_UI_TMR,
                DRV_IO_INTENT_EXCLUSIVE);
            if ( DRV_HANDLE_INVALID != controlData.UI_Timer )
            {
                DRV_TMR_AlarmRegister(controlData.UI_Timer,
                                    APP_UI_TMR_PERIOD,
                                    APP_UI_TMR_IS_PERIODIC,
                                    (uintptr_t)&controlData,
                                    APP_UI_Callback);
                DRV_TMR_Start(controlData.UI_Timer);
                controlData.state = CS_LCDINIT;
            }

            /* set the DSP into RESET */
            /*(needs to stay this way until well after the MCLK etc are running */
            DSP_SET_RESET;
            /* get the EEPROM up and running and loaded into data structure */
            EEPROM_Init();
            controlData.SPI1_handle = DRV_SPI_Open(DRV_SPI_INDEX_0, DRV_IO_INTENT_READWRITE);
            if ( DRV_HANDLE_INVALID != controlData.SPI1_handle )
            {
            }
           
            /**************************************************************/
            /*                  Set up SPI Channel 1                      */
            /**************************************************************/
            SPI1CON2bits.IGNROV = 1; // Ignore Receive Overflow bit (for Audio Data Transmissions)
            /* disable interrupts*/        
            SYS_INT_Disable();
            /* Disable the SPI module to configure it*/
            PLIB_SPI_Disable ( I2S_CH1 );
            //clear SPI buffer
            PLIB_SPI_BufferClear (I2S_CH1);
           
            // Configure General SPI Options
            PLIB_SPI_StopInIdleDisable(I2S_CH1);
            PLIB_SPI_PinEnable(I2S_CH1, SPI_PIN_SLAVE_SELECT|SPI_PIN_DATA_OUT|SPI_PIN_DATA_IN);
            PLIB_SPI_CommunicationWidthSelect(I2S_CH1, SPI_COMMUNICATION_WIDTH_32BITS);
            PLIB_SPI_InputSamplePhaseSelect(I2S_CH1,SPI_INPUT_SAMPLING_PHASE_IN_MIDDLE);
            PLIB_SPI_ClockPolaritySelect(I2S_CH1, SPI_CLOCK_POLARITY_IDLE_HIGH);
            PLIB_SPI_OutputDataPhaseSelect(I2S_CH1, SPI_OUTPUT_DATA_PHASE_ON_ACTIVE_TO_IDLE_CLOCK);
            PLIB_SPI_BaudRateClockSelect(I2S_CH1, SPI_BAUD_RATE_MCLK_CLOCK); 
            PLIB_SPI_BaudRateSet(I2S_CH1,I2S_CLOCK,I2S_BAUD_RATE);
            PLIB_SPI_MasterEnable(I2S_CH1);

            PLIB_SPI_FramedCommunicationEnable(I2S_CH1);
            PLIB_SPI_FrameSyncPulseDirectionSelect(I2S_CH1,SPI_FRAME_PULSE_DIRECTION_OUTPUT);
            PLIB_SPI_FIFOEnable(I2S_CH1);
            PLIB_SPI_FIFOInterruptModeSelect(SPI_ID_1,
                        SPI_FIFO_INTERRUPT_WHEN_TRANSMIT_BUFFER_IS_1HALF_EMPTY_OR_MORE);
            //set to audio mode
            PLIB_SPI_AudioProtocolModeSelect(I2S_CH1,SPI_AUDIO_PROTOCOL_I2S );
            PLIB_SPI_AudioTransmitModeSelect(I2S_CH1,SPI_AUDIO_TRANSMIT_STEREO);
            SPI1CON2bits.IGNTUR = 1; //  Ignore Transmit Underrun bit (for Audio Data Transmissions) 1 = A TUR is not a critical error and zeros are transmitted until thSPIxTXB is not empty 0 = A TUR is a critical error which stop SPI operation
            SYS_INT_SourceDisable(INT_SOURCE_SPI_1_RECEIVE);
            SYS_INT_SourceDisable(INT_SOURCE_SPI_1_ERROR);
            SYS_INT_SourceEnable(INT_SOURCE_SPI_1_TRANSMIT);

            /**************************************************************/
            /*                  Set up SPI Channel 2                      */
            /**************************************************************/
            SPI4CON2bits.IGNROV = 1; // Ignore Receive Overflow bit (for Audio Data Transmissions)
            /* disable interrupts - OK they should still be disabled from above*/        
            SYS_INT_Disable();
            /* Disable the SPI module to configure it*/
            PLIB_SPI_Disable ( I2S_CH2 );
            //clear SPI buffer
            PLIB_SPI_BufferClear (I2S_CH2);

            // Configure General SPI Options
            PLIB_SPI_StopInIdleDisable(I2S_CH2);
            /* Omit enabling the data input pin as it is not used */
            PLIB_SPI_PinEnable(I2S_CH2, SPI_PIN_SLAVE_SELECT|SPI_PIN_DATA_OUT);
            PLIB_SPI_CommunicationWidthSelect(I2S_CH2, SPI_COMMUNICATION_WIDTH_32BITS);
            PLIB_SPI_InputSamplePhaseSelect(I2S_CH2,SPI_INPUT_SAMPLING_PHASE_IN_MIDDLE);
            PLIB_SPI_ClockPolaritySelect(I2S_CH2, SPI_CLOCK_POLARITY_IDLE_HIGH);
            PLIB_SPI_OutputDataPhaseSelect(I2S_CH2, SPI_OUTPUT_DATA_PHASE_ON_ACTIVE_TO_IDLE_CLOCK);
            PLIB_SPI_BaudRateClockSelect(I2S_CH2, SPI_BAUD_RATE_MCLK_CLOCK); 
            PLIB_SPI_BaudRateSet(I2S_CH2,I2S_CLOCK,I2S_BAUD_RATE);
            PLIB_SPI_MasterEnable(I2S_CH2);

            PLIB_SPI_FramedCommunicationEnable(I2S_CH2);
            PLIB_SPI_FrameSyncPulseDirectionSelect(I2S_CH2,SPI_FRAME_PULSE_DIRECTION_OUTPUT);
            PLIB_SPI_FIFOEnable(I2S_CH2);

            PLIB_SPI_AudioProtocolModeSelect(I2S_CH2,SPI_AUDIO_PROTOCOL_I2S );
            PLIB_SPI_AudioTransmitModeSelect(I2S_CH2,SPI_AUDIO_TRANSMIT_STEREO);
            SPI4CON2bits.IGNTUR = 1; //  Ignore Transmit Underrun bit (for Audio Data Transmissions) 1 = A TUR is not a critical error and zeros are transmitted until thSPIxTXB is not empty 0 = A TUR is a critical error which stop SPI operation
            SYS_INT_SourceDisable(INT_SOURCE_SPI_4_RECEIVE);
            SYS_INT_SourceDisable(INT_SOURCE_SPI_4_ERROR);
            SYS_INT_SourceDisable(INT_SOURCE_SPI_4_TRANSMIT);
            /****************************************************************/
            /*    Before we go enabling interrupts and kicking off the I2S  */
            /*    lets load from memoery and get everything set up!!!       */
            /* get the EEPROM up and running and loaded into data structure */
            /****************************************************************/
            EEPROM_Init();
            PLIB_SPI_MasterEnable(EEPROM_SPI_Port);
            DelayMs(EEPROM_WR_Delay);
            /* Clear the DSP into RESET */
            DelayMs(DAC_RESET_Delay);
            DSP_CLEAR_RESET; 
            Load_From_Memory(controlData.MemoryBankSelected);
            /*****************************************************************/
            /*              initialise all the vars as required              */
            /*****************************************************************/
            CF_INIT_VARS();
            /*****************************************************************/
            /*                    enable things                              */
            /*****************************************************************/
            PLIB_SPI_Enable(I2S_CH1);
            PLIB_SPI_Enable(I2S_CH2);
            /*****************************************************************/
            /*                  reset interrupt status                       */        
            /*                            GO!                                */        
            /*****************************************************************/
            DelayMs(100);
            SYS_INT_Enable();       
        }
        break;

        /* Application's initial state. */
        case CS_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();
            controlData.state = CS_CHOOSE;
            CF_CHOOSE();
            /* let things settle*/
            DelayMs(100);
            Key_Just_Pressed = 0;
        }        
        break;
        
        case CS_CHOOSE:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;

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

                if (Keypress_Read == Rot_Up)
                {
                    if (controlData.UI_Action == CONTROL_ACTION_SAVE)
                        controlData.UI_Action = CONTROL_ACTION_CH1;
                    else if (controlData.UI_Action == CONTROL_ACTION_CH1)
                        controlData.UI_Action = CONTROL_ACTION_CH2;
                    else if (controlData.UI_Action == CONTROL_ACTION_CH2)
                        controlData.UI_Action = CONTROL_ACTION_LOAD;
                    else if (controlData.UI_Action == CONTROL_ACTION_LOAD)
                        controlData.UI_Action = CONTROL_ACTION_SAVE;
                    /* This function displays the choose function screen  */
                    CF_CHOOSE();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    if (controlData.UI_Action == CONTROL_ACTION_SAVE)
                        controlData.UI_Action = CONTROL_ACTION_LOAD;
                    else if (controlData.UI_Action == CONTROL_ACTION_LOAD)
                        controlData.UI_Action = CONTROL_ACTION_CH2;
                    else if (controlData.UI_Action == CONTROL_ACTION_CH2)
                        controlData.UI_Action = CONTROL_ACTION_CH1;
                    else if (controlData.UI_Action == CONTROL_ACTION_CH1)
                        controlData.UI_Action = CONTROL_ACTION_SAVE;
                    /* This function displays the choose function screen  */
                    CF_CHOOSE();
                }
                else if (Keypress_Read == Sel)
                {
                    if (controlData.UI_Action == CONTROL_ACTION_SAVE)
                    {
                        controlData.state = CS_SAVE;
                        Save_Screen();
                    }
                    else if (controlData.UI_Action == CONTROL_ACTION_LOAD)
                    {
                        controlData.state = CS_LOAD;
                        Load_Screen();
                    }
                    else if (controlData.UI_Action == CONTROL_ACTION_CH1)
                    {
                        controlData.DDS_Channel = DDS_Channel_Min;
                        controlData.state = CS_FREQUENCY;
                        CF_FREQUENCY();
                    }
                    else if (controlData.UI_Action == CONTROL_ACTION_CH2)
                    {
                        controlData.DDS_Channel = DDS_Channel_Min +1;
                        controlData.state = CS_FREQUENCY;
                        CF_FREQUENCY();
                    }
                    /* This function displays the choose function screen  */
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO FREQ Screen as it will be most used */        
                    controlData.state = CS_CHOOSE;
                    CF_CHOOSE();
                }
                controlData.UI_Keypressed = false;
                // no need to update the display
            }
        }
        break;
              
        case CS_SAVE:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
        
                /* reset this just to be clear */
                controlData.UI_Speed = Atten_Normal_Speed;

                if (Keypress_Read == Rot_Up)
                {
                    controlData.MemoryBankSelected++;
                    if (controlData.MemoryBankSelected > Max_Mem_Banks)
                        controlData.MemoryBankSelected = Default_Mem_Bank;
                    /* This function displays the save screen  */
                    Save_Screen();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.MemoryBankSelected--;
                    if (controlData.MemoryBankSelected < Default_Mem_Bank)
                        controlData.MemoryBankSelected = Max_Mem_Banks;
                    /* This function displays the save screen  */
                    Save_Screen();
                }
                else if (Keypress_Read == Sel)
                {
                    /* This function displays the save logo and writes the data to EEPROM */
                    CONTROL_EEPROM_Save(controlData.MemoryBankSelected);
                    /* GO BACK TO ATTEN STATE */        
                    controlData.state = CS_CHOOSE;
                    CF_CHOOSE();
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO ATTEN STATE */        
                    controlData.state = CS_CHOOSE;
                    CF_CHOOSE();
                }
                controlData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO CHOOSE STATE */        
                controlData.state = CS_CHOOSE;
                CF_CHOOSE();
            }
        }
        break;

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

                if (Keypress_Read == Rot_Up)
                {
                    controlData.MemoryBankSelected++;
                    if (controlData.MemoryBankSelected > Max_Mem_Banks)
                        controlData.MemoryBankSelected = Default_Mem_Bank;
                    /* This function displays the save screen  */
                    Load_Screen();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.MemoryBankSelected--;
                    if (controlData.MemoryBankSelected < Default_Mem_Bank)
                        controlData.MemoryBankSelected = Max_Mem_Banks;
                    /* This function displays the save screen  */
                    Load_Screen();
                }
                else if (Keypress_Read == Sel)
                {
                    /* This function displays the save logo and writes the data to EEPROM */
                    Load_From_Memory(controlData.MemoryBankSelected);
                    Update_Atten_Set(controlData.Data_Values[controlData.DDS_Channel].Atten);	/* Load Attenuator Settings including volume */

                    /* Need to re initialise a bunch of variables */
                    CF_INIT_VARS();
                    
                    /* GO BACK TO ATTEN STATE */        
                    controlData.state = CS_CHOOSE;
                    CF_CHOOSE();
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO ATTEN STATE */        
                    controlData.state = CS_CHOOSE;
                    CF_CHOOSE();
                }
                controlData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO CHOOSE STATE */        
                controlData.state = CS_CHOOSE;
                CF_CHOOSE();
            }
        }
        break;
        
        case CS_FREQUENCY:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
                
                /* run update to counters to see if rapid value change needed */
                CONTROL_UI_Fast_Slow(Freq_Fast_Speed , Freq_Normal_Speed);

        
                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Freq += (controlData.UI_Speed * controlData.Data_Values[controlData.DDS_Channel].Freq_Speed) ;
                    if (controlData.Data_Values[controlData.DDS_Channel].Freq > Freq_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Freq = Freq_Max;
                    /* This function displays the save screen  */
                    CF_FREQUENCY();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Freq -= (controlData.UI_Speed * controlData.Data_Values[controlData.DDS_Channel].Freq_Speed);
                    if (controlData.Data_Values[controlData.DDS_Channel].Freq < Freq_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Freq = Freq_Normal_Speed * controlData.Data_Values[controlData.DDS_Channel].Freq_Speed;
                        /* Set to UI_Speed as it makes more sense to a human*/
                    /* This function displays the save screen  */
                    CF_FREQUENCY();
                }
                else if (Keypress_Read == Sel)
                {
                    HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + controlData.DDS_Channel*Channel_Set_Array_Size + Freq_Offset), controlData.Data_Values[controlData.DDS_Channel].Freq);
                    /* put update type in here */
                    CF_FREQ_SPEED();
                    controlData.state = CS_FREQ_SPEED;
                }
                else if (Keypress_Read == Exit)
                {
                    HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + controlData.DDS_Channel*Channel_Set_Array_Size + Freq_Offset), controlData.Data_Values[controlData.DDS_Channel].Freq);
                    /* GO BACK TO ATTEN STATE */        
                    controlData.state = CS_CHOOSE;
                    CF_CHOOSE();
                }
                /* If a key has been pressed we will notmally need to update */
                /* the phase increments...                                   */
                Temp_Calc_Store = 0x100000000; // 2^32
                Temp_Calc_Store = Temp_Calc_Store * controlData.Data_Values[controlData.DDS_Channel].Freq;
                /* remember freq is in tenths of a Hz */
                Temp_Calc_Store = Temp_Calc_Store / (Sample_Rate * 10); 
                if (controlData.DDS_Channel == DDS_Channel_Min)
                    Phase_Inc_Ch1 = (long) Temp_Calc_Store;
                else
                    Phase_Inc_Ch2 = (long) Temp_Calc_Store;

                /*if sweep, then... */
                if (controlData.Data_Values[controlData.DDS_Channel].Sweep_On)
                    CF_SWEEP_UPDATE_VARS();
                
                controlData.UI_Keypressed = false;
                // no need to update the display

            }    
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                /* Stay here */        
                controlData.state = CS_FREQUENCY;
                CF_FREQUENCY();
            }
        }
        break;
       
        case CS_FREQ_SPEED:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
        
                /* set speed to 1 to be sure.... */
                controlData.UI_Speed = 1;

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Freq_Speed *= 10;
                    if (controlData.Data_Values[controlData.DDS_Channel].Freq_Speed > Freq_Speed_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Freq_Speed = Freq_Speed_Max;
                    /* This function displays the save screen  */
                    CF_FREQ_SPEED();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Freq_Speed /= 10;
                    if (controlData.Data_Values[controlData.DDS_Channel].Freq_Speed < Freq_Speed_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Freq_Speed = Freq_Speed_Min;
                    /* This function displays the save screen  */
                    CF_FREQ_SPEED();
                }
                else if (Keypress_Read == Sel)
                {
                    /* put update level in here */
                    CF_ATTEN();
                    /* GO to Level */        
                    controlData.state = CS_ATTEN;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO FREQUENCY */        
                    controlData.state = CS_FREQUENCY;
                    CF_FREQUENCY();
                }
                controlData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                controlData.state = CS_CHOOSE;
                /* put the right display up */
                CF_CHOOSE();            
            }
        }
        break;

        /* we are just sitting there at the "normal" screen */        
        case CS_ATTEN:
        {
            /* reset the countdown timer */
            controlData.Revert_To_Idle_Counter = Revert_To_Idle;
            
            if(controlData.UI_Keypressed)
            {
            /* run update to counters to see if rapid value change needed */
            CONTROL_UI_Fast_Slow(Atten_Speed , Atten_Normal_Speed);

                if (Keypress_Read == Rot_Down)
                {
                    /* do not use   * controlData.UI_Speed as i could be dangerous to kit under test*/
                    controlData.Data_Values[controlData.DDS_Channel].Atten += Atten_Step*controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Atten > Atten_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Atten = Atten_Max;
                    controlData.UI_Update_Display = true;
   					Update_Atten_Set(controlData.Data_Values[controlData.DDS_Channel].Atten);
                    CF_ATTEN();
                }
                else if  (Keypress_Read == Rot_Up)
                {
                    /* do not use   * controlData.UI_Speed as i could be dangerous to kit under test*/
                    controlData.Data_Values[controlData.DDS_Channel].Atten -= Atten_Step*controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Atten < Atten_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Atten = Atten_Min;
                    controlData.UI_Update_Display = true;
   					Update_Atten_Set(controlData.Data_Values[controlData.DDS_Channel].Atten);
                    CF_ATTEN();
                }
                else if (Keypress_Read == Exit)
                {
//                    controlData.UI_Action = CONTROL_ACTION_CH1;
                    controlData.state = CS_CHOOSE;
                    HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + controlData.DDS_Channel*Channel_Set_Array_Size + Atten_Offset), controlData.Data_Values[controlData.DDS_Channel].Atten);
                    /* put the right display up */
                    CF_CHOOSE();
                }
                else if (Keypress_Read == Sel)
                {
                    controlData.state = CS_WAVEFORM;
                    HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + controlData.DDS_Channel*Channel_Set_Array_Size + Atten_Offset), controlData.Data_Values[controlData.DDS_Channel].Atten);
                    /* put the right display up */
                    CF_WAVEFORM();
                }
                controlData.UI_Keypressed = false;
            }    
            if(controlData.DDS_Channel == HardCode_Ch1)
            {    
                Ch1_Level_Mult = (long)(Atten_Scale * pow(10,(-(float)(((float)controlData.Data_Values[controlData.DDS_Channel].Atten)/10))/20));
            }
            else
            {
                Ch2_Level_Mult = (long)(Atten_Scale * pow(10,(-(float)(((float)controlData.Data_Values[controlData.DDS_Channel].Atten)/10))/20));
            }
            
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                /* Stay here */        
                controlData.state = CS_ATTEN;
                CF_ATTEN();
            }
        }
        break;

        case CS_WAVEFORM:
        {
            
            if(controlData.UI_Keypressed)
            {
                /* be Clear this to be sure */
                controlData.UI_Speed = 1;
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
            
                if (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Waveform += 1;
                    if (controlData.Data_Values[controlData.DDS_Channel].Waveform > Waveform_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Waveform = Waveform_Min;
                    controlData.UI_Update_Display = true;
                    CF_WAVEFORM();
                }
                else if  (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Waveform -= 1;
                    if (controlData.Data_Values[controlData.DDS_Channel].Waveform < Waveform_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Waveform = Waveform_Max;
                    controlData.UI_Update_Display = true;
                    CF_WAVEFORM();
                }
                else if (Keypress_Read == Exit)
                {
                    controlData.state = CS_CHOOSE;
                    /* put the right display up */
                    CF_CHOOSE();
                }
                else if (Keypress_Read == Sel)
                {
                    if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Sine)
                    {
                        /****************************************************************/
                        /*      Load the DDS LUT with a sinewave...                     */
                        /****************************************************************/
                        for(temp = 0; temp < Waveform_LUT_Size; temp++)
                        {
                            if(controlData.DDS_Channel == HardCode_Ch1)
                                Ch1_LUT[temp] = Sine_LUT[temp];
                            else
                                Ch2_LUT[temp] = Sine_LUT[temp];
                        }
                        /* now onto next state */
                        controlData.state = CS_SWEEP;
                        /* put the right display up */
                        CF_SWEEP_ON();
                    }
                    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Triangle)
                    {
                        /****************************************************************/
                        /*      Load DDS waveform with a triangle...                    */
                        /****************************************************************/
                        /* initialise LUT's */
                        for(temp = 0; temp < (Waveform_LUT_Size/4); temp++)
                        {
                            /* ok the 0x2000 is 2^24 divided by 1024*/
                            if(controlData.DDS_Channel == HardCode_Ch1)
                                Ch1_LUT[temp] = temp * 0x2000;
                            else
                                Ch2_LUT[temp] = temp * 0x2000;
                        }
                        for(temp = 0; temp < (Waveform_LUT_Size/2); temp++)
                        {
                            if(controlData.DDS_Channel == HardCode_Ch1)
                                Ch1_LUT[(Waveform_LUT_Size/4) + temp] = 0x7fffff - temp * 0x2000;
                            else
                                Ch2_LUT[(Waveform_LUT_Size/4) + temp] = 0x7fffff - temp * 0x2000;
                        }
                        for(temp = 0; temp < (Waveform_LUT_Size/4); temp++)
                        {
                            if(controlData.DDS_Channel == HardCode_Ch1)
                                Ch1_LUT[(3*(Waveform_LUT_Size/4)) + temp] = -0x7fffff + temp * 0x2000;
                            else
                                Ch2_LUT[(3*(Waveform_LUT_Size/4)) + temp] = -0x7fffff + temp * 0x2000;
                        }
                        controlData.state = CS_SWEEP;
                        /* put the right display up */
                        CF_SWEEP_ON();
                    }
                    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Square)
                    {
                        /****************************************************************/
                        /*      Load DDS waveform with a Square...                    */
                        /****************************************************************/
                        for(temp = 0; temp < (Waveform_LUT_Size/2); temp++)
                        {
                            if(controlData.DDS_Channel == HardCode_Ch1)
                                Ch1_LUT[temp] = +0x7fffff;
                            else
                                Ch2_LUT[temp] = +0x7fffff;
                        }
                        for(temp = 0; temp < (Waveform_LUT_Size/2); temp++)
                        {
                            if(controlData.DDS_Channel == HardCode_Ch1)
                                Ch1_LUT[2048 + temp] = -0x7fffff;
                            else
                                Ch2_LUT[2048 + temp] = -0x7fffff;
                        }
                        controlData.state = CS_SWEEP;
                        /* put the right display up */
                        CF_SWEEP_ON();
                    }
                    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Pulse)
                    {
                        /****************************************************************/
                        /*      Load DDS waveform with a pulse...                       */
                        /****************************************************************/
                        for(temp = 0; temp < ((Waveform_LUT_Size*controlData.Data_Values[controlData.DDS_Channel].Ratio)/100); temp++)
                        {
                            if(controlData.DDS_Channel == HardCode_Ch1)
                                Ch1_LUT[temp] = 0x7fffff;
                            else
                                Ch2_LUT[temp] = 0x7fffff;
                        }
                        for(temp = ((Waveform_LUT_Size*controlData.Data_Values[controlData.DDS_Channel].Ratio)/100); temp < Waveform_LUT_Size; temp++)
                        {
                            if(controlData.DDS_Channel == HardCode_Ch1)
                                Ch1_LUT[temp] = -0x7fffff;
                            else
                                Ch2_LUT[temp] = -0x7fffff;
                        }
                        controlData.state = CS_RATIO;
                        /* put the right display up */
                        CF_RATIO();
                    }
                    else if (controlData.Data_Values[controlData.DDS_Channel].Waveform == Noise)
                    {
                        /****************************************************************/
                        /*      Start the DDS with a sinewave...                        */
                        /****************************************************************/
                        for(temp = 0; temp < Waveform_LUT_Size; temp++)
                        {
                            if(controlData.DDS_Channel == HardCode_Ch1)
                                Ch1_LUT[temp] = Noise_LUT[temp];
                              else
                                Ch2_LUT[temp] = Noise_LUT[temp];
                        }
                        controlData.state = CS_PULSE_ON;
                        /* put the right display up */
                        CF_PULSE_ON();
                    }
                    
                }
                controlData.UI_Keypressed = false;
            }    

            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                controlData.state = CS_CHOOSE;
                /* put the right display up */
                CF_CHOOSE();            
            }
        }
        break;
        
        case CS_SWEEP:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset this */
                controlData.UI_Speed = 1;
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
            
                if (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Sweep_On--;
                    if (controlData.Data_Values[controlData.DDS_Channel].Sweep_On < 0)
                        controlData.Data_Values[controlData.DDS_Channel].Sweep_On = Sweep_Log;
                    controlData.UI_Update_Display = true;
                    if(controlData.DDS_Channel == HardCode_Ch1)
                        Ch1_Sweep_Phase_Reg = 0;
                    else if(controlData.DDS_Channel == HardCode_Ch2)
                        Ch2_Sweep_Phase_Reg = 0;
                    CF_SWEEP_ON();
                }
                else if  (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Sweep_On++;
                    if (controlData.Data_Values[controlData.DDS_Channel].Sweep_On > Sweep_Log)
                        controlData.Data_Values[controlData.DDS_Channel].Sweep_On = 0;
                    controlData.UI_Update_Display = true;
                    if(controlData.DDS_Channel == HardCode_Ch1)
                        Ch1_Sweep_Phase_Reg = 0;
                    else if(controlData.DDS_Channel == HardCode_Ch2)
                        Ch2_Sweep_Phase_Reg = 0;
                    CF_SWEEP_ON();
                }
                else if (Keypress_Read == Exit)
                {
                    controlData.state = CS_CHOOSE;
                    /* put the right display up */
                    CF_CHOOSE();
                }
                else if (Keypress_Read == Sel)
                {
                    if (controlData.Data_Values[controlData.DDS_Channel].Sweep_On)
                    {
                    controlData.state = CS_SWEEP_END;
                    /* put the right display up */
                    CF_SWEEP_END();
                    }
                    else
                    {
                    controlData.state = CS_PULSE_ON;
                    /* put the right display up */
                    CF_PULSE_ON();                        
                    }
                }
                /* The sweep function uses this*/
                
                /*if sweep, then... */
                if (controlData.Data_Values[controlData.DDS_Channel].Sweep_On)
                    CF_SWEEP_UPDATE_VARS();
                
                /* sort out key pressed */
                controlData.UI_Keypressed = false;
                // no need to update the display
            }    

            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                controlData.state = CS_CHOOSE;
                /* put the right display up */
                CF_CHOOSE();            
            }
        }
        break;
        
        case CS_SWEEP_END:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
        
                /* run update to counters to see if rapid value change needed */
                CONTROL_UI_Fast_Slow(Freq_Fast_Speed , Freq_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Sweep_End += (controlData.UI_Speed * controlData.Data_Values[controlData.DDS_Channel].Freq_Speed);
                    if (controlData.Data_Values[controlData.DDS_Channel].Sweep_End > Freq_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Sweep_End = Freq_Max;
                    /* This function displays the save screen  */
                    CF_SWEEP_END();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Sweep_End -= (controlData.UI_Speed * controlData.Data_Values[controlData.DDS_Channel].Freq_Speed);
                    if (controlData.Data_Values[controlData.DDS_Channel].Sweep_End < Freq_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Sweep_End = Freq_Normal_Speed * controlData.Data_Values[controlData.DDS_Channel].Freq_Speed;
                        /* use UI_Speed as it makes more sense to a human*/
                    /* This function displays the save screen  */
                    CF_SWEEP_END();
                }
                else if (Keypress_Read == Sel)
                {
                    /* put update type in here */
                    CF_SWEEP_TIME();
                    controlData.state = CS_SWEEP_TIME;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO ATTEN STATE */        
                    controlData.state = CS_SWEEP;
                    CF_SWEEP_ON();
                }
                /*if sweep, then... */
                if (controlData.Data_Values[controlData.DDS_Channel].Sweep_On)
                    CF_SWEEP_UPDATE_VARS();
                
                /* sort out key pressed */
                controlData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                controlData.state = CS_CHOOSE;
                /* put the right display up */
                CF_CHOOSE();            
            }
        }
        break;
        
        case CS_SWEEP_TIME:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
        
                /* run update to counters to see if rapid value change needed */
                CONTROL_UI_Fast_Slow(Time_Fast , Time_Normal);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Sweep_Time += controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Sweep_Time > Sweep_Time_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Sweep_Time = Sweep_Time_Max;
                    /* This function displays the save screen  */
                    CF_SWEEP_TIME();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Sweep_Time -= controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Sweep_Time < Sweep_Time_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Sweep_Time = Sweep_Time_Min;
                    /* This function displays the save screen  */
                    CF_SWEEP_TIME();
                }
                else if (Keypress_Read == Sel)
                {
                    /* put update type in here */
                    CF_PULSE_ON();
                    controlData.state = CS_PULSE_ON;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO ATTEN STATE */        
                    controlData.state = CS_SWEEP;
                    CF_SWEEP_ON();
                }

                /*if sweep, then... */
                if (controlData.Data_Values[controlData.DDS_Channel].Sweep_On)
                    CF_SWEEP_UPDATE_VARS();
                
                /* sort out key pressed */
                controlData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                controlData.state = CS_CHOOSE;
                /* put the right display up */
                CF_CHOOSE();            
            }
        }
        break;
        
        case CS_RATIO:
        {
            if(controlData.UI_Keypressed)
            {
                /* run update to counters to see if rapid value change needed */
                CONTROL_UI_Fast_Slow(Ratio_Speed , Ratio_Normal_Speed);
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
            
                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Ratio += Ratio_Step * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Ratio > Ratio_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Ratio = Ratio_Max;
                    controlData.UI_Update_Display = true;
                    CF_RATIO();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Ratio -= Ratio_Step  * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Ratio < Ratio_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Ratio = Ratio_Min;
                    controlData.UI_Update_Display = true;
                    CF_RATIO();
                }
                else if (Keypress_Read == Exit)
                {
                    controlData.state = CS_CHOOSE;
                    /* put the right display up */
                    CF_CHOOSE();
                }
                else if (Keypress_Read == Sel)
                {
                    controlData.state = CS_SWEEP;
                    /* put the right display up */
                    CF_SWEEP_ON();
                }
                /****************************************************************/
                /*      Load DDS waveform with pulse...                       */
                /****************************************************************/
                for(temp = 0; temp < ((Waveform_LUT_Size*controlData.Data_Values[controlData.DDS_Channel].Ratio)/100); temp++)
                {
                    if(controlData.DDS_Channel == HardCode_Ch1)
                        Ch1_LUT[temp] = 0x7fffff;
                    else
                        Ch2_LUT[temp] = 0x7fffff;
                }
                for(temp = ((Waveform_LUT_Size*controlData.Data_Values[controlData.DDS_Channel].Ratio)/100); temp < Waveform_LUT_Size; temp++)
                {
                    if(controlData.DDS_Channel == HardCode_Ch1)
                        Ch1_LUT[temp] = -0x7fffff;
                    else
                        Ch2_LUT[temp] = -0x7fffff;
                }

                controlData.UI_Keypressed = false;
            }    

            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                controlData.state = CS_CHOOSE;
                /* put the right display up */
                CF_CHOOSE();            
            }
        }
        break;
        
        case CS_PULSE_ON:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset this */
                controlData.UI_Speed = 1;
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
            
                if (Keypress_Read == Rot_Down)
                {
                    if (controlData.Data_Values[controlData.DDS_Channel].Pulse_On)
                        controlData.Data_Values[controlData.DDS_Channel].Pulse_On = 0;
                    else
                    {
                        controlData.Data_Values[controlData.DDS_Channel].Pulse_On = 1;
                        if (controlData.DDS_Channel == DDS_Channel_Min)
                        {
                            Ch1_Pulse_Output_Active = 1;
                            Ch1_Pulse_Counter = Pulse_Cycles_On_Min;
                        }
                        else
                        {
                            Ch2_Pulse_Output_Active = 1; /* Channel 1 and 2 Pule Output on */
                            Ch2_Pulse_Counter = Pulse_Cycles_On_Min;   /* start with both at 0 */
                        }
                    }
                    controlData.UI_Update_Display = true;
                    CF_PULSE_ON();
                }
                else if  (Keypress_Read == Rot_Up)
                {
                    if (controlData.Data_Values[controlData.DDS_Channel].Pulse_On)
                        controlData.Data_Values[controlData.DDS_Channel].Pulse_On = 0;
                    else
                    {
                        controlData.Data_Values[controlData.DDS_Channel].Pulse_On = 1;
                        if (controlData.DDS_Channel == HardCode_Ch1)
                        {
                            Ch1_Pulse_Output_Active = 1;
                            Ch1_Pulse_Counter = controlData.Data_Values[HardCode_Ch1].Pulse_Cycles_On;
                        }
                        else
                        {
                            Ch2_Pulse_Output_Active = 1; /* Channel 1 and 2 Pule Output on */
                            Ch2_Pulse_Counter = controlData.Data_Values[HardCode_Ch1].Pulse_Cycles_On;   /* start with both at 0 */
                        }
                    }
                    controlData.UI_Update_Display = true;
                    CF_PULSE_ON();
                }
                else if (Keypress_Read == Exit)
                {
                    controlData.state = CS_CHOOSE;
                    /* put the right display up */
                    CF_CHOOSE();
                }
                else if (Keypress_Read == Sel)
                {
                    if (controlData.Data_Values[controlData.DDS_Channel].Pulse_On)
                    {
                    controlData.state = CS_PULSE_CYCLES_ON;
                    /* put the right display up */
                    CF_PULSE_ON();
                    }
                    else
                    {
                    controlData.state = CS_PHASE;
                    /* put the right display up */
                    CF_PHASE();                        
                    }
                }
                controlData.UI_Keypressed = false;
            }    

            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                controlData.state = CS_CHOOSE;
                /* put the right display up */
                CF_CHOOSE();            
            }
        }
        break;
        
        case CS_PULSE_CYCLES_ON:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
        
                /* run update to counters to see if rapid value change needed */
                CONTROL_UI_Fast_Slow(Pulse_Fast , Pulse_Normal);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On += controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On > Pulse_Cycles_On_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On = Pulse_Cycles_On_Max;
                    /* This function displays the save screen  */
                    CF_PULSE_ON();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On -= (controlData.UI_Speed);
                    if (controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On < Pulse_Cycles_On_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_On = Pulse_Cycles_On_Min;
                    /* This function displays the save screen  */
                    CF_PULSE_ON();
                }
                else if (Keypress_Read == Sel)
                {
                    controlData.state = CS_PULSE_CYCLES_OFF;
                    /* put update type in here */
                    CF_PULSE_ON();
                }
                else if (Keypress_Read == Exit)
                {
                    controlData.state = CS_PULSE_ON;
                    /* put the right display up */
                    CF_PULSE_ON();
                }
                controlData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                controlData.state = CS_CHOOSE;
                /* put the right display up */
                CF_CHOOSE();            
            }
        }
        break;
        
        case CS_PULSE_CYCLES_OFF:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
        
                /* run update to counters to see if rapid value change needed */
                CONTROL_UI_Fast_Slow(Time_Fast , Time_Normal);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off += controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off > Pulse_Cycles_Off_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off = Pulse_Cycles_Off_Max;
                    /* This function displays the save screen  */
                    CF_PULSE_ON();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off -= controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off < Pulse_Cycles_Off_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Pulse_Cycles_Off = Pulse_Cycles_Off_Min;
                    /* This function displays the save screen  */
                    CF_PULSE_ON();
                }
                else if (Keypress_Read == Sel)
                {
                    /* put update type in here */
                    CF_PHASE();
                    controlData.state = CS_PHASE;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO ATTEN STATE */        
                    controlData.state = CS_PULSE_ON;
                    CF_PULSE_ON();
                }
                controlData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                controlData.state = CS_CHOOSE;
                /* put the right display up */
                CF_CHOOSE();            
            }
        }
        break;

        case CS_PHASE:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;
        
                /* run update to counters to see if rapid value change needed */
                CONTROL_UI_Fast_Slow(Phase_Fast , Phase_Normal);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Phase_Shift += controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Phase_Shift >= Phase_Shift_Max)
                        controlData.Data_Values[controlData.DDS_Channel].Phase_Shift = Phase_Shift_Min;
                    CF_PHASE();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.DDS_Channel].Phase_Shift -= controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.DDS_Channel].Phase_Shift <= Phase_Shift_Min)
                        controlData.Data_Values[controlData.DDS_Channel].Phase_Shift = Phase_Shift_Max;
                    CF_PHASE();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO BACK TO ATTEN STATE */        
                    controlData.state = CS_CHOOSE;
                    CF_CHOOSE();
                }
                else if (Keypress_Read == Exit)
                {
                    controlData.state = CS_CHOOSE;
                    /* put the right display up */
                    CF_CHOOSE();
                }
                if (controlData.DDS_Channel == HardCode_Ch1)
                {
                    Ch1_Phase_Delta = (0xffffffff) / Phase_Shift_Max;
                    Ch1_Phase_Delta *= controlData.Data_Values[controlData.DDS_Channel].Phase_Shift;
                }
                else
                {
                    Ch2_Phase_Delta = (0xffffffff) / Phase_Shift_Max;
                    Ch2_Phase_Delta *= controlData.Data_Values[controlData.DDS_Channel].Phase_Shift;
                }
                controlData.UI_Keypressed = false;
                // no need to update the display
            }    
            /* if revert timer is out, then quit back to idle screen */
            if (controlData.Revert_To_Idle_Counter == 0)
            {
                /* GO BACK TO ATTEN STATE */        
                controlData.state = CS_PHASE;
                CF_PHASE();
            }
        }
        break;
        
        case CS_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(controlData.UI_Slow_Count > 0)
        controlData.UI_Slow_Count--;
}


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