/*******************************************************************************
  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
 *    - Fix R and L being swapped on the DAC
 *    - Allow up to 20 dB gain
 *    - Implement Bridge Mode
 *    - Removal of "inappropriate" error messages 
 * Ver 8 08 Jun 2019
 *   - Address startup initialisation allowing Fl to be negtive
 *   - Disable interrupts in ISR!
 *******************************************************************************/


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

#include "control.h"
#include "delay.h"
#include "KS0108-PIC16.h"
#include "KS0108.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;
Para_EQ_struct *EQ_Values_Pointer, *Temp_EQ_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 Input_Mute;         /* used to mute input */
int New_a0 = 0, New_a1 = 0, New_a2 = 0, New_b0 = 0, New_b1 = 0, New_b2 = 0;       /* Biquad filter coefficients to update */

int F0_a0 = 0, F0_a1 = 0, F0_a2 = 0, F0_b0 = 0, F0_b1 = 0, F0_b2 = 0;             /* Biquad filter coefficients 0 */
int F1_a0 = 0, F1_a1 = 0, F1_a2 = 0, F1_b0 = 0, F1_b1 = 0, F1_b2 = 0;             /* Biquad filter coefficients 1 */
int F2_a0 = 0, F2_a1 = 0, F2_a2 = 0, F2_b0 = 0, F2_b1 = 0, F2_b2 = 0;             /* Biquad filter coefficients 2 */
int F3_a0 = 0, F3_a1 = 0, F3_a2 = 0, F3_b0 = 0, F3_b1 = 0, F3_b2 = 0;             /* Biquad filter coefficients 3 */
int F4_a0 = 0, F4_a1 = 0, F4_a2 = 0, F4_b0 = 0, F4_b1 = 0, F4_b2 = 0;             /* Biquad filter coefficients 4 */
int F5_a0 = 0, F5_a1 = 0, F5_a2 = 0, F5_b0 = 0, F5_b1 = 0, F5_b2 = 0;             /* Biquad filter coefficients 5 */
int F6_a0 = 0, F6_a1 = 0, F6_a2 = 0, F6_b0 = 0, F6_b1 = 0, F6_b2 = 0;             /* Biquad filter coefficients 6 */
int F7_a0 = 0, F7_a1 = 0, F7_a2 = 0, F7_b0 = 0, F7_b1 = 0, F7_b2 = 0;             /* Biquad filter coefficients 7 */
int F8_a0 = 0, F8_a1 = 0, F8_a2 = 0, F8_b0 = 0, F8_b1 = 0, F8_b2 = 0;             /* Biquad filter coefficients 2 */
int F9_a0 = 0, F9_a1 = 0, F9_a2 = 0, F9_b0 = 0, F9_b1 = 0, F9_b2 = 0;             /* Biquad filter coefficients 3 */
int Fa_a0 = 0, Fa_a1 = 0, Fa_a2 = 0, Fa_b0 = 0, Fa_b1 = 0, Fa_b2 = 0;             /* Biquad filter coefficients 4 */
int Fb_a0 = 0, Fb_a1 = 0, Fb_a2 = 0, Fb_b0 = 0, Fb_b1 = 0, Fb_b2 = 0;             /* Biquad filter coefficients 5 */
int Fc_a0 = 0, Fc_a1 = 0, Fc_a2 = 0, Fc_b0 = 0, Fc_b1 = 0, Fc_b2 = 0;             /* Biquad filter coefficients 6 */
int Fd_a0 = 0, Fd_a1 = 0, Fd_a2 = 0, Fd_b0 = 0, Fd_b1 = 0, Fd_b2 = 0;             /* Biquad filter coefficients 7 */
int Fe_a0 = 0, Fe_a1 = 0, Fe_a2 = 0, Fe_b0 = 0, Fe_b1 = 0, Fe_b2 = 0;             /* Biquad filter coefficients 7 */

int dummy;

int Xn_L, Xn_R;         /* input current sample*/
int Xn1_L, Xn1_R;       /* Previous input current sample*/
int Xn2_L, Xn2_R;       /* second prvious input current sample*/
int Yn_L, Yn_R;         /* Output current sample*/
int Yn1_L, Yn1_R;       /* Previous output current sample*/
int Yn2_L, Yn2_R;       /* second previous output current sample*/

int X1n_L, X1n_R;       /* input current sample*/
int X1n1_L, X1n1_R;     /* Previous input current sample*/
int X1n2_L, X1n2_R;     /* second prvious input current sample*/
int Y1n_L, Y1n_R;       /* Output current sample*/
int Y1n1_L, Y1n1_R;     /* Previous output current sample*/
int Y1n2_L, Y1n2_R;     /* second previous output current sample*/

int X2n_L, X2n_R;       /* input current sample*/
int X2n1_L, X2n1_R;     /* Previous input current sample*/
int X2n2_L, X2n2_R;     /* second prvious input current sample*/
int Y2n_L, Y2n_R;       /* Output current sample*/
int Y2n1_L, Y2n1_R;     /* Previous output current sample*/
int Y2n2_L, Y2n2_R;     /* second previous output current sample*/

int X3n_L, X3n_R;       /* input current sample*/
int X3n1_L, X3n1_R;     /* Previous input current sample*/
int X3n2_L, X3n2_R;     /* second prvious input current sample*/
int Y3n_L, Y3n_R;       /* Output current sample*/
int Y3n1_L, Y3n1_R;     /* Previous output current sample*/
int Y3n2_L, Y3n2_R;     /* second previous output current sample*/

int X4n_L, X4n_R;       /* input current sample*/
int X4n1_L, X4n1_R;     /* Previous input current sample*/
int X4n2_L, X4n2_R;     /* second prvious input current sample*/
int Y4n_L, Y4n_R;       /* Output current sample*/
int Y4n1_L, Y4n1_R;     /* Previous output current sample*/
int Y4n2_L, Y4n2_R;     /* second previous output current sample*/

int X5n_L, X5n_R;       /* input current sample*/
int X5n1_L, X5n1_R;     /* Previous input current sample*/
int X5n2_L, X5n2_R;     /* second prvious input current sample*/
int Y5n_L, Y5n_R;       /* Output current sample*/
int Y5n1_L, Y5n1_R;     /* Previous output current sample*/
int Y5n2_L, Y5n2_R;     /* second previous output current sample*/

int X6n_L, X6n_R;       /* input current sample*/
int X6n1_L, X6n1_R;     /* Previous input current sample*/
int X6n2_L, X6n2_R;     /* second prvious input current sample*/
int Y6n_L, Y6n_R;       /* Output current sample*/
int Y6n1_L, Y6n1_R;     /* Previous output current sample*/
int Y6n2_L, Y6n2_R;     /* second previous output current sample*/

int X7n_L, X7n_R;       /* input current sample*/
int X7n1_L, X7n1_R;     /* Previous input current sample*/
int X7n2_L, X7n2_R;     /* second prvious input current sample*/
int Y7n_L, Y7n_R;       /* Output current sample*/
int Y7n1_L, Y7n1_R;     /* Previous output current sample*/
int Y7n2_L, Y7n2_R;     /* second previous output current sample*/

int X8n_L, X8n_R;       /* input current sample*/
int X8n1_L, X8n1_R;     /* Previous input current sample*/
int X8n2_L, X8n2_R;     /* second prvious input current sample*/
int Y8n_L, Y8n_R;       /* Output current sample*/
int Y8n1_L, Y8n1_R;     /* Previous output current sample*/
int Y8n2_L, Y8n2_R;     /* second previous output current sample*/

int X9n_L, X9n_R;       /* input current sample*/
int X9n1_L, X9n1_R;     /* Previous input current sample*/
int X9n2_L, X9n2_R;     /* second prvious input current sample*/
int Y9n_L, Y9n_R;       /* Output current sample*/
int Y9n1_L, Y9n1_R;     /* Previous output current sample*/
int Y9n2_L, Y9n2_R;     /* second previous output current sample*/

int Xan_L, Xan_R;       /* input current sample*/
int Xan1_L, Xan1_R;     /* Previous input current sample*/
int Xan2_L, Xan2_R;     /* second prvious input current sample*/
int Yan_L, Yan_R;       /* Output current sample*/
int Yan1_L, Yan1_R;     /* Previous output current sample*/
int Yan2_L, Yan2_R;     /* second previous output current sample*/

int Xbn_L, Xbn_R;       /* input current sample*/
int Xbn1_L, Xbn1_R;     /* Previous input current sample*/
int Xbn2_L, Xbn2_R;     /* second prvious input current sample*/
int Ybn_L, Ybn_R;       /* Output current sample*/
int Ybn1_L, Ybn1_R;     /* Previous output current sample*/
int Ybn2_L, Ybn2_R;     /* second previous output current sample*/

int Xcn_L, Xcn_R;       /* input current sample*/
int Xcn1_L, Xcn1_R;     /* Previous input current sample*/
int Xcn2_L, Xcn2_R;     /* second prvious input current sample*/
int Ycn_L, Ycn_R;       /* Output current sample*/
int Ycn1_L, Ycn1_R;     /* Previous output current sample*/
int Ycn2_L, Ycn2_R;     /* second previous output current sample*/

int Xdn_L, Xdn_R;       /* input current sample*/
int Xdn1_L, Xdn1_R;     /* Previous input current sample*/
int Xdn2_L, Xdn2_R;     /* second prvious input current sample*/
int Ydn_L, Ydn_R;       /* Output current sample*/
int Ydn1_L, Ydn1_R;     /* Previous output current sample*/
int Ydn2_L, Ydn2_R;     /* second previous output 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 CH1_Invert, CH2_Invert; /* exactly that*/
int CH1_L_Bridge;        /* if TRUE then invert channel 1 LEFT only to create a bridged output*/
unsigned int CH1_Delay_Offset, CH2_Delay_Offset; /* Offset from input write pointer to implement delay*/
unsigned int Write_Pointer_Offset, Ch1_Rd_Offset, Ch2_Rd_Offset; /* location at which input data is written into a cyclical buffer */
int Delay_Buffer_Ch1_L[Delay_Buf_Size];  /* cyclic buffer to implement delay for L channel*/
int Delay_Buffer_Ch1_R[Delay_Buf_Size];  /* cyclic buffer to implement delay for R channel*/
int Delay_Buffer_Ch2_L[Delay_Buf_Size];  /* cyclic buffer to implement delay for L channel*/
int Delay_Buffer_Ch2_R[Delay_Buf_Size];  /* cyclic buffer to implement delay for R channel*/
int Out_Test_Temp;                       /* used for output clipping to 24 bits */



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


/****************************************************************************/
/* Uses the following globals                                               */
/*                                                                          */
/* YES I KNOW - THE GLOBALS ARE HARD CODED                                    */
/*                                                                          */
/* If you play with the number of FIR filters, you need to change the hard coded */
/* IIR variables                                                            */
// disable interrupts
//intStatus = INTDisableSystemMultiVectoredInt();
// do some critical code here
// restore interrupts to the previous state
//INTRestoreInterrupts(intStatus);
/*                                                                          */
/* This sets is the ISR that deals with the I2S interface                   */
/* It ultimately needs to generate DAC data at the sample rate              */

//int F0_a0, F0_a1, F0_a2, F0_b0, F0_b1, F0_b2;/* Biquad filter coefficients 0 */
//int F1_a0, F1_a1, F1_a2, F1_b0, F1_b1, F1_b2;/* Biquad filter coefficients 1 */
//int F2_a0, F2_a1, F2_a2, F2_b0, F2_b1, F2_b2;/* Biquad filter coefficients 2 */
// ....
//int Fd_a0, Fd_a1, Fd_a2, Fd_b0, Fd_b1, Fd_b2;/* Biquad filter coefficients 7 */

//int Xn_L, Xn_R;           /* input current sample*/
//int Xn1_L, Xn1_R;         /* Previous input current sample*/
//int Xn2_L, Xn2_R;         /* second prvious input current sample*/
//int Yn_L, Yn_R;           /* Output current sample*/
//int Yn1_L, Yn1_R;         /* Previous output current sample*/
//int Yn2_L, Yn2_R;         /* second previous output current sample*/

//Structure of filters is:
//  INPUT --> GEN1 --> GEN2 --> GEN3 --> GEN4 --|---> HPF1 --> LPF1  --> CH1_1 ---> CH1_2 --->Delay1 --> INV1 --> OUT1
//            F0       F1        F8       F9    |     F2, F3   F4, F5     Fa          Fb
//                                              |
//                                              |---> HPF2 ---> CH2_1 ---> CH2_2-- Delay2 --> INV2 --> OUT2
//                                                  F6, F7        Fc        Fd
/****************************************************************************/
//__attribute__((vector(v), interrupt(ipl), nomips16))
void __ISR(_SPI1_TX_VECTOR, ipl4AUTO) IntHandlerSPITx(void)
{
    //DEBUG
    /*************************************************************************/
//            SYS_PORTS_PinToggle(PORTS_ID_0, APP_HEARTBEAT_PORT,
//                            APP_HEARTBEAT_PIN);
//            SYS_PORTS_Set(PORTS_ID_0, APP_HEARTBEAT_PORT, APP_HEARTBEAT_PIN, APP_HEARTBEAT_PIN);
    /*************************************************************************/

    SYS_INT_SourceDisable(INT_SOURCE_SPI_1_TRANSMIT);

    /* if filters have not changed then jump past the checks...*/
    if (!New_Filter_Vals)
        {}
    else
        {
        if(New_Filter_Vals == Para_Update_Base)
            {
                F0_a0 = New_a0;
                F0_a1 = New_a1;
                F0_a2 = New_a2;
                F0_b0 = New_b0;
                F0_b1 = New_b1;
                F0_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == (Para_Update_Base +1))
            {
                F1_a0 = New_a0;
                F1_a1 = New_a1;
                F1_a2 = New_a2;
                F1_b0 = New_b0;
                F1_b1 = New_b1;
                F1_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == (Para_Update_Base +2))
            {
                F8_a0 = New_a0;
                F8_a1 = New_a1;
                F8_a2 = New_a2;
                F8_b0 = New_b0;
                F8_b1 = New_b1;
                F8_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == (Para_Update_Base +3))
            {
                F9_a0 = New_a0;
                F9_a1 = New_a1;
                F9_a2 = New_a2;
                F9_b0 = New_b0;
                F9_b1 = New_b1;
                F9_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == (Para_Update_Base +4))
            {
                Fa_a0 = New_a0;
                Fa_a1 = New_a1;
                Fa_a2 = New_a2;
                Fa_b0 = New_b0;
                Fa_b1 = New_b1;
                Fa_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == (Para_Update_Base +5))
            {
                Fb_a0 = New_a0;
                Fb_a1 = New_a1;
                Fb_a2 = New_a2;
                Fb_b0 = New_b0;
                Fb_b1 = New_b1;
                Fb_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == (Para_Update_Base +6))
            {
                Fc_a0 = New_a0;
                Fc_a1 = New_a1;
                Fc_a2 = New_a2;
                Fc_b0 = New_b0;
                Fc_b1 = New_b1;
                Fc_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == (Para_Update_Base +7))
            {
                Fd_a0 = New_a0;
                Fd_a1 = New_a1;
                Fd_a2 = New_a2;
                Fd_b0 = New_b0;
                Fd_b1 = New_b1;
                Fd_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == 3)
            {
                F2_a0 = New_a0;
                F2_a1 = New_a1;
                F2_a2 = New_a2;
                F2_b0 = New_b0;
                F2_b1 = New_b1;
                F2_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == 4)
            {
                F3_a0 = New_a0;
                F3_a1 = New_a1;
                F3_a2 = New_a2;
                F3_b0 = New_b0;
                F3_b1 = New_b1;
                F3_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == 5)
            {
                F4_a0 = New_a0;
                F4_a1 = New_a1;
                F4_a2 = New_a2;
                F4_b0 = New_b0;
                F4_b1 = New_b1;
                F4_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == 6)
            {
                F5_a0 = New_a0;
                F5_a1 = New_a1;
                F5_a2 = New_a2;
                F5_b0 = New_b0;
                F5_b1 = New_b1;
                F5_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else if (New_Filter_Vals == 7)
            {
                F6_a0 = New_a0;
                F6_a1 = New_a1;
                F6_a2 = New_a2;
                F6_b0 = New_b0;
                F6_b1 = New_b1;
                F6_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
         else if (New_Filter_Vals == 8)
            {
                F7_a0 = New_a0;
                F7_a1 = New_a1;
                F7_a2 = New_a2;
                F7_b0 = New_b0;
                F7_b1 = New_b1;
                F7_b2 = New_b2;
                New_Filter_Vals = 0; /* clear the flag */
            }
        else;
    }

    /* read the data */
    Yn2_L = Yn1_L;          /* store the old value, you will need it!*/
    Yn1_L = Yn_L;           /* store the old value, you will need it!*/
    Xn2_L = Xn1_L;          /* store the old value, you will need it!*/
    Xn1_L = Xn_L;           /* store the old value, you will need it!*/
    Xn_L = Chan_1_Port_RW;
    dummy = Chan_2_Port_RW;

            
    /* convert the 24 bit data into an integer */
    /* the pic32MZ in i2s 32 bit mode reads the data as i2s LJ*/
    /* different to the MX using the 24 bit audio mode which aligned data at */
    /* bit 23.  Go figure*/
    Xn_L = Xn_L/256;

    Yn2_R = Yn1_R;          /* store the old value, you will need it!*/
    Yn1_R = Yn_R;           /* store the old value, you will need it!*/
    Xn2_R = Xn1_R;          /* store the old value, you will need it!*/
    Xn1_R = Xn_R;           /* store the old value, you will need it!*/
    Xn_R = Chan_1_Port_RW;
    dummy = Chan_2_Port_RW;
    /* convert the 24 bit data into an integer */
    Xn_R = Xn_R/256;

    /* implement filter 0  --  This is GENERAL Filter 1 G1*/
    Acc_Reg =  (long long) F0_b0*Xn_L;
    Acc_Reg += (long long) F0_b1*Xn1_L;
    Acc_Reg += (long long) F0_b2*Xn2_L;
    Acc_Reg += (long long) F0_a1*Yn1_L;
    Acc_Reg += (long long) F0_a2*Yn2_L;
    /* rescale */
    Acc_Reg_Shift;
    Yn_L_Assignment;

    Acc_Reg =  (long long) F0_b0*Xn_R;
    Acc_Reg += (long long) F0_b1*Xn1_R;
    Acc_Reg += (long long) F0_b2*Xn2_R ;
    Acc_Reg += (long long) F0_a1*Yn1_R ;
    Acc_Reg += (long long) F0_a2*Yn2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Yn_R_Assignment;


    /* copy and create history for data */
    Y1n2_L = Y1n1_L;          /* store the old value, you will need it!*/
    Y1n1_L = Y1n_L;           /* store the old value, you will need it!*/
    X1n2_L = X1n1_L;          /* store the old value, you will need it!*/
    X1n1_L = X1n_L;           /* store the old value, you will need it!*/
    X1n_L = Yn_L;             /* this filter takes input from the output of F0 */

    Y1n2_R = Y1n1_R;          /* store the old value, you will need it!*/
    Y1n1_R = Y1n_R;           /* store the old value, you will need it!*/
    X1n2_R = X1n1_R;          /* store the old value, you will need it!*/
    X1n1_R = X1n_R;           /* store the old value, you will need it!*/
    X1n_R = Yn_R;             /* this filter takes input from the output of F0 */

    /* implement filter 1  --- THIS IS General Filter 2 G2*/
    Acc_Reg = (long long) F1_b0*X1n_L;
    Acc_Reg += (long long) F1_b1* X1n1_L;
    Acc_Reg += (long long) F1_b2*X1n2_L;
    Acc_Reg += (long long) F1_a1*Y1n1_L;
    Acc_Reg += (long long) F1_a2*Y1n2_L;
    /* rescale */
    Acc_Reg_Shift;
    Y1n_L_Assignment;

    Acc_Reg = (long long) F1_b0*X1n_R;
    Acc_Reg += (long long) F1_b1* X1n1_R;
    Acc_Reg += (long long) F1_b2*X1n2_R ;
    Acc_Reg += (long long) F1_a1*Y1n1_R ;
    Acc_Reg += (long long) F1_a2*Y1n2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Y1n_R_Assignment;

    /* copy and create history for data */
    Y8n2_L = Y8n1_L;          /* store the old value, you will need it!*/
    Y8n1_L = Y8n_L;           /* store the old value, you will need it!*/
    X8n2_L = X8n1_L;          /* store the old value, you will need it!*/
    X8n1_L = X8n_L;           /* store the old value, you will need it!*/
    X8n_L  = Y1n_L;             /* this filter takes input from the output of F0 */

    Y8n2_R = Y8n1_R;          /* store the old value, you will need it!*/
    Y8n1_R = Y8n_R;           /* store the old value, you will need it!*/
    X8n2_R = X8n1_R;          /* store the old value, you will need it!*/
    X8n1_R = X8n_R;           /* store the old value, you will need it!*/
    X8n_R = Y1n_R;             /* this filter takes input from the output of F0 */

    /* implement filter 2  --- THIS IS General Filter 3 G3*/
    Acc_Reg = (long long)  F8_b0*X8n_L;
    Acc_Reg += (long long) F8_b1*X8n1_L;
    Acc_Reg += (long long) F8_b2*X8n2_L;
    Acc_Reg += (long long) F8_a1*Y8n1_L;
    Acc_Reg += (long long) F8_a2*Y8n2_L;
    /* rescale */
    Acc_Reg_Shift;
    Y8n_L_Assignment;

    Acc_Reg = (long long)  F8_b0*X8n_R;
    Acc_Reg += (long long) F8_b1*X8n1_R;
    Acc_Reg += (long long) F8_b2*X8n2_R ;
    Acc_Reg += (long long) F8_a1*Y8n1_R ;
    Acc_Reg += (long long) F8_a2*Y8n2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Y8n_R_Assignment;

    
        /* copy and create history for data */
    Y9n2_L = Y9n1_L;          /* store the old value, you will need it!*/
    Y9n1_L = Y9n_L;           /* store the old value, you will need it!*/
    X9n2_L = X9n1_L;          /* store the old value, you will need it!*/
    X9n1_L = X9n_L;           /* store the old value, you will need it!*/
    X9n_L  = Y8n_L;             /* this filter takes input from the output of F0 */

    Y9n2_R = Y9n1_R;          /* store the old value, you will need it!*/
    Y9n1_R = Y9n_R;           /* store the old value, you will need it!*/
    X9n2_R = X9n1_R;          /* store the old value, you will need it!*/
    X9n1_R = X9n_R;           /* store the old value, you will need it!*/
    X9n_R =  Y8n_R;             /* this filter takes input from the output of F0 */

    /* implement filter 2  --- THIS IS General Filter 4 G4*/
    Acc_Reg = (long long)  F9_b0*X9n_L;
    Acc_Reg += (long long) F9_b1*X9n1_L;
    Acc_Reg += (long long) F9_b2*X9n2_L;
    Acc_Reg += (long long) F9_a1*Y9n1_L;
    Acc_Reg += (long long) F9_a2*Y9n2_L;
    /* rescale */
    Acc_Reg_Shift;
    Y9n_L_Assignment;

    Acc_Reg = (long long)  F9_b0*X9n_R;
    Acc_Reg += (long long) F9_b1*X9n1_R;
    Acc_Reg += (long long) F9_b2*X9n2_R ;
    Acc_Reg += (long long) F9_a1*Y9n1_R ;
    Acc_Reg += (long long) F9_a2*Y9n2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Y9n_R_Assignment;

   
    /* copy and create history for data  --- This is HPF1, first Para*/
    Y2n2_L = Y2n1_L;          /* store the old value, you will need it!*/
    Y2n1_L = Y2n_L;           /* store the old value, you will need it!*/
    X2n2_L = X2n1_L;          /* store the old value, you will need it!*/
    X2n1_L = X2n_L;           /* store the old value, you will need it!*/
    X2n_L =  Y9n_L;           /* this filter takes input from the output of F1 */

    Y2n2_R = Y2n1_R;          /* store the old value, you will need it!*/
    Y2n1_R = Y2n_R;           /* store the old value, you will need it!*/
    X2n2_R = X2n1_R;          /* store the old value, you will need it!*/
    X2n1_R = X2n_R;           /* store the old value, you will need it!*/
    X2n_R =  Y9n_R;           /* this filter takes input from the output of F1 */

    /* implement filter 1 */
    /* this is Channel 1 Crossover Filter 1*/
    Acc_Reg = (long long) F2_b0*X2n_L;
    Acc_Reg += (long long) F2_b1* X2n1_L;
    Acc_Reg += (long long) F2_b2*X2n2_L;
    Acc_Reg += (long long) F2_a1*Y2n1_L;
    Acc_Reg += (long long) F2_a2*Y2n2_L;
    /* rescale */
    Acc_Reg_Shift;
    Y2n_L_Assignment;

    Acc_Reg = (long long) F2_b0*X2n_R;
    Acc_Reg += (long long) F2_b1* X2n1_R;
    Acc_Reg += (long long) F2_b2*X2n2_R ;
    Acc_Reg += (long long) F2_a1*Y2n1_R ;
    Acc_Reg += (long long) F2_a2*Y2n2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Y2n_R_Assignment;

    /* coy and create history for data --- This is HPF1, Second Para */
    Y3n2_L = Y3n1_L;          /* store the old value, you will need it!*/
    Y3n1_L = Y3n_L;           /* store the old value, you will need it!*/
    X3n2_L = X3n1_L;          /* store the old value, you will need it!*/
    X3n1_L = X3n_L;           /* store the old value, you will need it!*/
    X3n_L =  Y2n_L;           /* this filter takes input from the output of F2 */

    Y3n2_R = Y3n1_R;          /* store the old value, you will need it!*/
    Y3n1_R = Y3n_R;           /* store the old value, you will need it!*/
    X3n2_R = X3n1_R;          /* store the old value, you will need it!*/
    X3n1_R = X3n_R;           /* store the old value, you will need it!*/
    X3n_R =  Y2n_R;           /* this filter takes input from the output of F2 */

    /* implement filter 1 */
    /* this is Channel 1 Crossover Filter 2*/
    Acc_Reg = (long long) F3_b0*X3n_L;
    Acc_Reg += (long long) F3_b1* X3n1_L;
    Acc_Reg += (long long) F3_b2*X3n2_L;
    Acc_Reg += (long long) F3_a1*Y3n1_L;
    Acc_Reg += (long long) F3_a2*Y3n2_L;
    /* rescale */
    Acc_Reg_Shift;
    Y3n_L_Assignment;

    Acc_Reg = (long long) F3_b0*X3n_R;
    Acc_Reg += (long long) F3_b1* X3n1_R;
    Acc_Reg += (long long) F3_b2*X3n2_R ;
    Acc_Reg += (long long) F3_a1*Y3n1_R ;
    Acc_Reg += (long long) F3_a2*Y3n2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Y3n_R_Assignment;

    /* copy and create history for data --- This is LPF1, first Para*/
    Y4n2_L = Y4n1_L;          /* store the old value, you will need it!*/
    Y4n1_L = Y4n_L;           /* store the old value, you will need it!*/
    X4n2_L = X4n1_L;          /* store the old value, you will need it!*/
    X4n1_L = X4n_L;           /* store the old value, you will need it!*/
    X4n_L =  Y3n_L;           /* this filter takes input from the output of F3 */

    Y4n2_R = Y4n1_R;          /* store the old value, you will need it!*/
    Y4n1_R = Y4n_R;           /* store the old value, you will need it!*/
    X4n2_R = X4n1_R;          /* store the old value, you will need it!*/
    X4n1_R = X4n_R;           /* store the old value, you will need it!*/
    X4n_R =  Y3n_R;           /* this filter takes input from the output of F3 */

    /* implement filter 1 */
    /* this is Channel 1 Crossover Filter 3*/
    Acc_Reg = (long long) F4_b0*X4n_L;
    Acc_Reg += (long long) F4_b1* X4n1_L;
    Acc_Reg += (long long) F4_b2*X4n2_L;
    Acc_Reg += (long long) F4_a1*Y4n1_L;
    Acc_Reg += (long long) F4_a2*Y4n2_L;
    /* rescale */
    Acc_Reg_Shift;
    Y4n_L_Assignment;

    Acc_Reg = (long long) F4_b0*X4n_R;
    Acc_Reg += (long long) F4_b1* X4n1_R;
    Acc_Reg += (long long) F4_b2*X4n2_R ;
    Acc_Reg += (long long) F4_a1*Y4n1_R ;
    Acc_Reg += (long long) F4_a2*Y4n2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Y4n_R_Assignment;

    /* copy and create history for data --- This is LPF1, Second Para */
    Y5n2_L = Y5n1_L;          /* store the old value, you will need it!*/
    Y5n1_L = Y5n_L;           /* store the old value, you will need it!*/
    X5n2_L = X5n1_L;          /* store the old value, you will need it!*/
    X5n1_L = X5n_L;           /* store the old value, you will need it!*/
    X5n_L =  Y4n_L;           /* this filter takes input from the output of F4 */

    Y5n2_R = Y5n1_R;          /* store the old value, you will need it!*/
    Y5n1_R = Y5n_R;           /* store the old value, you will need it!*/
    X5n2_R = X5n1_R;          /* store the old value, you will need it!*/
    X5n1_R = X5n_R;           /* store the old value, you will need it!*/
    X5n_R =  Y4n_R;           /* this filter takes input from the output of F4 */

    /* implement filter 1 */
    /* this is Channel 1 Crossover Filter 4*/
    Acc_Reg = (long long)  F5_b0*X5n_L;
    Acc_Reg += (long long) F5_b1*X5n1_L;
    Acc_Reg += (long long) F5_b2*X5n2_L;
    Acc_Reg += (long long) F5_a1*Y5n1_L;
    Acc_Reg += (long long) F5_a2*Y5n2_L;
    /* rescale */
    Acc_Reg_Shift;
    Y5n_L_Assignment;

    Acc_Reg  = (long long) F5_b0*X5n_R;
    Acc_Reg += (long long) F5_b1*X5n1_R;
    Acc_Reg += (long long) F5_b2*X5n2_R ;
    Acc_Reg += (long long) F5_a1*Y5n1_R ;
    Acc_Reg += (long long) F5_a2*Y5n2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Y5n_R_Assignment;
       
        /* copy and create history for data */
    Yan2_L = Yan1_L;          /* store the old value, you will need it!*/
    Yan1_L = Yan_L;           /* store the old value, you will need it!*/
    Xan2_L = Xan1_L;          /* store the old value, you will need it!*/
    Xan1_L = Xan_L;           /* store the old value, you will need it!*/
    Xan_L  = Y5n_L;             /* this filter takes input from the output of F5 */

    Yan2_R = Yan1_R;          /* store the old value, you will need it!*/
    Yan1_R = Yan_R;           /* store the old value, you will need it!*/
    Xan2_R = Xan1_R;          /* store the old value, you will need it!*/
    Xan1_R = Xan_R;           /* store the old value, you will need it!*/
    Xan_R =  Y5n_R;             /* this filter takes input from the output of F5 */

    /* implement filter 2  --- THIS IS General Filter 4 G4*/
    Acc_Reg = (long long)  Fa_b0*Xan_L;
    Acc_Reg += (long long) Fa_b1*Xan1_L;
    Acc_Reg += (long long) Fa_b2*Xan2_L;
    Acc_Reg += (long long) Fa_a1*Yan1_L;
    Acc_Reg += (long long) Fa_a2*Yan2_L;
    /* rescale */
    Acc_Reg_Shift;
    Yan_L_Assignment;

    Acc_Reg = (long long)  Fa_b0*Xan_R;
    Acc_Reg += (long long) Fa_b1*Xan1_R;
    Acc_Reg += (long long) Fa_b2*Xan2_R ;
    Acc_Reg += (long long) Fa_a1*Yan1_R ;
    Acc_Reg += (long long) Fa_a2*Yan2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Yan_R_Assignment;
        
    /* copy and create history for data */
    Ybn2_L = Ybn1_L;          /* store the old value, you will need it!*/
    Ybn1_L = Ybn_L;           /* store the old value, you will need it!*/
    Xbn2_L = Xbn1_L;          /* store the old value, you will need it!*/
    Xbn1_L = Xbn_L;           /* store the old value, you will need it!*/
    Xbn_L  = Yan_L;             /* this filter takes input from the output of Fa */

    Ybn2_R = Ybn1_R;          /* store the old value, you will need it!*/
    Ybn1_R = Ybn_R;           /* store the old value, you will need it!*/
    Xbn2_R = Xbn1_R;          /* store the old value, you will need it!*/
    Xbn1_R = Xbn_R;           /* store the old value, you will need it!*/
    Xbn_R =  Yan_R;             /* this filter takes input from the output of Fa */

    /* implement filter 2  --- THIS IS General Filter 4 G4*/
    Acc_Reg = (long long)  Fb_b0*Xbn_L;
    Acc_Reg += (long long) Fb_b1*Xbn1_L;
    Acc_Reg += (long long) Fb_b2*Xbn2_L;
    Acc_Reg += (long long) Fb_a1*Ybn1_L;
    Acc_Reg += (long long) Fb_a2*Ybn2_L;
    /* rescale */
    Acc_Reg_Shift;
    Ybn_L_Assignment;

    Acc_Reg = (long long)  Fb_b0*Xbn_R;
    Acc_Reg += (long long) Fb_b1*Xbn1_R;
    Acc_Reg += (long long) Fb_b2*Xbn2_R ;
    Acc_Reg += (long long) Fb_a1*Ybn1_R ;
    Acc_Reg += (long long) Fb_a2*Ybn2_R ;
    /* rescale */
    Acc_Reg_Shift;
    Ybn_R_Assignment;
    
    /* copy and create history for data --- This is HPF2, first Para*/
    Y6n2_L = Y6n1_L;          /* store the old value, you will need it!*/
    Y6n1_L = Y6n_L;           /* store the old value, you will need it!*/
    X6n2_L = X6n1_L;          /* store the old value, you will need it!*/
    X6n1_L = X6n_L;           /* store the old value, you will need it!*/
    X6n_L =  Y9n_L;           /* this filter takes input from the output of F1 */
                              /* in output of GEN2 para */

    Y6n2_R = Y6n1_R;          /* store the old value, you will need it!*/
    Y6n1_R = Y6n_R;           /* store the old value, you will need it!*/
    X6n2_R = X6n1_R;          /* store the old value, you will need it!*/
    X6n1_R = X6n_R;           /* store the old value, you will need it!*/
    X6n_R =  Y9n_R;           /* this filter takes input from the output of F1 */
                              /* in output of GEN2 para */

    /* implement filter 1 */
    /* this is Channel 2 Crossover Filter 1*/
    Acc_Reg = (long long)  F6_b0*X6n_L;
    Acc_Reg += (long long) F6_b1*X6n1_L;
    Acc_Reg += (long long) F6_b2*X6n2_L;
    Acc_Reg += (long long) F6_a1*Y6n1_L;
    Acc_Reg += (long long) F6_a2*Y6n2_L;
    /* rescale */
    Acc_Reg_Shift;
    Y6n_L_Assignment;

    Acc_Reg  = (long long) F6_b0*X6n_R;
    Acc_Reg += (long long) F6_b1*X6n1_R;
    Acc_Reg += (long long) F6_b2*X6n2_R;
    Acc_Reg += (long long) F6_a1*Y6n1_R;
    Acc_Reg += (long long) F6_a2*Y6n2_R;
    /* rescale */
    Acc_Reg_Shift;
    Y6n_R_Assignment;

    /* copy and create history for data  --- This is HPF2, second Para*/
    Y7n2_L = Y7n1_L;          /* store the old value, you will need it!*/
    Y7n1_L = Y7n_L;           /* store the old value, you will need it!*/
    X7n2_L = X7n1_L;          /* store the old value, you will need it!*/
    X7n1_L = X7n_L;           /* store the old value, you will need it!*/
    X7n_L =  Y6n_L;           /* this filter takes input from the output of F6 */

    Y7n2_R = Y7n1_R;          /* store the old value, you will need it!*/
    Y7n1_R = Y7n_R;           /* store the old value, you will need it!*/
    X7n2_R = X7n1_R;          /* store the old value, you will need it!*/
    X7n1_R = X7n_R;           /* store the old value, you will need it!*/
    X7n_R =  Y6n_R;           /* this filter takes input from the output of F6 */

    /* implement filter 1 */
    /* this is Channel 2 Crossover Filter 2*/
    Acc_Reg = (long long)  F7_b0*X7n_L;
    Acc_Reg += (long long) F7_b1*X7n1_L;
    Acc_Reg += (long long) F7_b2*X7n2_L;
    Acc_Reg += (long long) F7_a1*Y7n1_L;
    Acc_Reg += (long long) F7_a2*Y7n2_L;
    /* rescale */
    Acc_Reg_Shift;
    Y7n_L_Assignment;

    Acc_Reg  = (long long) F7_b0*X7n_R;
    Acc_Reg += (long long) F7_b1*X7n1_R;
    Acc_Reg += (long long) F7_b2*X7n2_R;
    Acc_Reg += (long long) F7_a1*Y7n1_R;
    Acc_Reg += (long long) F7_a2*Y7n2_R;
    /* rescale */
    Acc_Reg_Shift;
    Y7n_R_Assignment;
    
    /* copy and create history for data  --- This is HPF2, third Para*/
    Ycn2_L = Ycn1_L;          /* store the old value, you will need it!*/
    Ycn1_L = Ycn_L;           /* store the old value, you will need it!*/
    Xcn2_L = Xcn1_L;          /* store the old value, you will need it!*/
    Xcn1_L = Xcn_L;           /* store the old value, you will need it!*/
    Xcn_L =  Y7n_L;           /* this filter takes input from the output of F7 */

    Ycn2_R = Ycn1_R;          /* store the old value, you will need it!*/
    Ycn1_R = Ycn_R;           /* store the old value, you will need it!*/
    Xcn2_R = Xcn1_R;          /* store the old value, you will need it!*/
    Xcn1_R = Xcn_R;           /* store the old value, you will need it!*/
    Xcn_R =  Y7n_R;           /* this filter takes input from the output of F7 */

    /* implement filter */
    /* this is Channel 2 Para 1 Filter 2*/
    Acc_Reg = (long long)  Fc_b0*Xcn_L;
    Acc_Reg += (long long) Fc_b1*Xcn1_L;
    Acc_Reg += (long long) Fc_b2*Xcn2_L;
    Acc_Reg += (long long) Fc_a1*Ycn1_L;
    Acc_Reg += (long long) Fc_a2*Ycn2_L;
    /* rescale */
    Acc_Reg_Shift;
    Ycn_L_Assignment;

    Acc_Reg  = (long long) Fc_b0*Xcn_R;
    Acc_Reg += (long long) Fc_b1*Xcn1_R;
    Acc_Reg += (long long) Fc_b2*Xcn2_R;
    Acc_Reg += (long long) Fc_a1*Ycn1_R;
    Acc_Reg += (long long) Fc_a2*Ycn2_R;
    /* rescale */
    Acc_Reg_Shift;
    Ycn_R_Assignment;

    /* copy and create history for data  --- This is HPF2, fourth Para*/
    Ydn2_L = Ydn1_L;          /* store the old value, you will need it!*/
    Ydn1_L = Ydn_L;           /* store the old value, you will need it!*/
    Xdn2_L = Xdn1_L;          /* store the old value, you will need it!*/
    Xdn1_L = Xdn_L;           /* store the old value, you will need it!*/
    Xdn_L =  Ycn_L;           /* this filter takes input from the output of Fc */

    Ydn2_R = Ydn1_R;          /* store the old value, you will need it!*/
    Ydn1_R = Ydn_R;           /* store the old value, you will need it!*/
    Xdn2_R = Xdn1_R;          /* store the old value, you will need it!*/
    Xdn1_R = Xdn_R;           /* store the old value, you will need it!*/
    Xdn_R =  Ycn_R;           /* this filter takes input from the output of Fc */

    /* implement filter */
    /* this is Channel 2 Para 2 Filter 2*/
    Acc_Reg = (long long)  Fd_b0*Xdn_L;
    Acc_Reg += (long long) Fd_b1*Xdn1_L;
    Acc_Reg += (long long) Fd_b2*Xdn2_L;
    Acc_Reg += (long long) Fd_a1*Ydn1_L;
    Acc_Reg += (long long) Fd_a2*Ydn2_L;
    /* rescale */
    Acc_Reg_Shift;
    Ydn_L_Assignment;

    Acc_Reg  = (long long) Fd_b0*Xdn_R;
    Acc_Reg += (long long) Fd_b1*Xdn1_R;
    Acc_Reg += (long long) Fd_b2*Xdn2_R;
    Acc_Reg += (long long) Fd_a1*Ydn1_R;
    Acc_Reg += (long long) Fd_a2*Ydn2_R;
    /* rescale */
    Acc_Reg_Shift;
    Ydn_R_Assignment;

    /* 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 = Ybn_L & DAC_Valid_BitMask;
    if (Out_Test_Temp & 0x80000000)
        {
            if (!(Out_Test_Temp ^ 0xff800000))
                CH1_Output_Data_L = Ybn_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 = Ybn_L;


    Out_Test_Temp = Ybn_R & DAC_Valid_BitMask;
    if (Out_Test_Temp & 0x80000000)
        {
            if (!(Out_Test_Temp ^ 0xff800000))
                CH1_Output_Data_R = Ybn_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 = Ybn_R;

    /* now channel 2 */
    Out_Test_Temp = Ydn_L & DAC_Valid_BitMask;
    if (Out_Test_Temp & 0x80000000)
        {
            if (!(Out_Test_Temp ^ 0xff800000))
                CH2_Output_Data_L = Ydn_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 = Ydn_L;


    Out_Test_Temp = Ydn_R & DAC_Valid_BitMask;
    if (Out_Test_Temp & 0x80000000)
        {
            if (!(Out_Test_Temp ^ 0xff800000))
                CH2_Output_Data_R = Ydn_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 = Ydn_R;

    /* cheat here and do not mask off the top bits - as they have been cleared above */
    *(Delay_Buffer_Ch1_L + Write_Pointer_Offset) = CH1_Output_Data_L;
    *(Delay_Buffer_Ch1_R + Write_Pointer_Offset) = CH1_Output_Data_R;
    /* point the write pointers at the right spot*/
    *(Delay_Buffer_Ch2_L + Write_Pointer_Offset) = CH2_Output_Data_L;
    *(Delay_Buffer_Ch2_R + Write_Pointer_Offset) = CH2_Output_Data_R;

    Write_Pointer_Offset++;
    Write_Pointer_Offset = Write_Pointer_Offset & Delay_Buf_Size_Mask;

    //***********************************************************************
    // Left and Right on the DAC are back to front! 
    // Thus flip R and L here
    Chan_1_Port_RW = (*(Delay_Buffer_Ch1_R + Ch1_Rd_Offset))*256;
    if(CH1_L_Bridge)    /* then want to invert Ch 1 Left*/
        Chan_1_Port_RW = -(*(Delay_Buffer_Ch1_L + Ch1_Rd_Offset))*256;
    else
        Chan_1_Port_RW = (*(Delay_Buffer_Ch1_L + Ch1_Rd_Offset))*256;

    Chan_2_Port_RW = (*(Delay_Buffer_Ch2_R + Ch2_Rd_Offset))*256;
    Chan_2_Port_RW = (*(Delay_Buffer_Ch2_L + Ch2_Rd_Offset))*256;

    /* increment read pointers */
    Ch1_Rd_Offset++;
    Ch2_Rd_Offset++;
    Ch1_Rd_Offset = Ch1_Rd_Offset & Delay_Buf_Size_Mask;
    Ch2_Rd_Offset = Ch2_Rd_Offset & Delay_Buf_Size_Mask;

    
    DRV_SPI_Tasks(sysObj.spiObjectIdx1);
    PLIB_INT_SourceFlagClear(INT_ID_0,_SPI1_TX_VECTOR); 
    
    //DEBUG
    /*************************************************************************/
//            SYS_PORTS_PinToggle(PORTS_ID_0, APP_HEARTBEAT_PORT,
//                            APP_HEARTBEAT_PIN);
//            SYS_PORTS_Clear(PORTS_ID_0, APP_HEARTBEAT_PORT, 0x0100);
    /*************************************************************************/
    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 stored Temp Set for app */
    HDWordReadSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Volume_Offset), &controlData.Atten_Set, 4 );
    if (controlData.Atten_Set > Atten_Max)
        controlData.Atten_Set = Atten_Default;
    else if (controlData.Atten_Set < Atten_Min)
        controlData.Atten_Set = Atten_Default;
    
    /* Read in stored Temp Offset for input selection */
    HDWordReadSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Input_Selected_Offset), &controlData.Input_Sel, 4 );
    if (controlData.Input_Sel > Input_ADC)
        controlData.Input_Sel = Input_ADC;
    else if (controlData.Input_Sel < Input_SPDIF)
        controlData.Input_Sel = Input_SPDIF;
    
    controlData.Atten_Set_Backup = controlData.Atten_Set;

/* Read in the parameters for crossover points from default bank of EEPROM */
for (loop=Min_XO_Band; loop <= Max_XO_Band; 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 + Fl_Offset),       &(Data_Values_Pointer->Fl), 4 );
    if (Data_Values_Pointer->Fl < Fl_Min)
        Data_Values_Pointer->Fl = Fl_Min;
    else if (Data_Values_Pointer->Fl > Fl_Max)
        Data_Values_Pointer->Fl = Fl_Max;
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Fu_Offset),       &(Data_Values_Pointer->Fu), 4 );
    if (Data_Values_Pointer->Fu < Fu_Min)
        Data_Values_Pointer->Fu = Fu_Min;
    else if (Data_Values_Pointer->Fu > Fu_Max)
        Data_Values_Pointer->Fu = Fu_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Sl_Offset),       &(Data_Values_Pointer->Sl), 4 );
    if (Data_Values_Pointer->Sl < Sl_Min)
        Data_Values_Pointer->Sl = Sl_Min;
    else if (Data_Values_Pointer->Sl > Sl_Max)
        Data_Values_Pointer->Sl = Sl_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Su_Offset),       &(Data_Values_Pointer->Su), 4 );
    if (Data_Values_Pointer->Su < Su_Min)
        Data_Values_Pointer->Su = Su_Min;
    else if (Data_Values_Pointer->Su > Su_Max)
        Data_Values_Pointer->Su = Su_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Atten_Offset),    &(Data_Values_Pointer->Atten), 4 );
    if (Data_Values_Pointer->Atten < Gain_Atten_Min)
        Data_Values_Pointer->Atten = Gain_Atten_Min;
    else if (Data_Values_Pointer->Atten > Gain_Atten_Max)
        Data_Values_Pointer->Atten = Gain_Atten_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Delay_mm_Offset), &(Data_Values_Pointer->Delay_mm), 4 );
    if (Data_Values_Pointer->Delay_mm < Delay_mm_Min)
        Data_Values_Pointer->Delay_mm = Delay_mm_Min;
    else if (Data_Values_Pointer->Delay_mm > Delay_mm_Max)
        Data_Values_Pointer->Delay_mm = Delay_mm_Max;    
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Invert_Offset),   &(Data_Values_Pointer->Invert), 4 );
    if (Data_Values_Pointer->Invert != Invert_False)
        Data_Values_Pointer->Invert = Invert_True;
    HDWordReadSPI((controlData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Bridge_Offset),   &(Data_Values_Pointer->Bridge), 4 );
    if (Data_Values_Pointer->Bridge != Bridge_True)
        Data_Values_Pointer->Bridge = Bridge_False;
	};

    
/* Read in the parameters for crossover points from default bank of EEPROM */
for (loop=Min_EQ_Band; loop <= Max_EQ_Band; loop++)
    {
    EQ_Values_Pointer = &(controlData.EQ_Values[loop]);
    HDWordReadSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size)+ Para_Gen_Base + loop*Para_Set_Size +  Para_CF_Offset), &(EQ_Values_Pointer->CF), 4 );
        if (EQ_Values_Pointer->CF < EQ_Min)
            EQ_Values_Pointer->CF = EQ_Min;
        else if (EQ_Values_Pointer->CF > EQ_Max)
            EQ_Values_Pointer->CF = EQ_Max;
    HDWordReadSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size +  Para_Q_Offset), &(EQ_Values_Pointer->Q), 4 );
        if (EQ_Values_Pointer->Q < EQ_Q_Min)
            EQ_Values_Pointer->Q = EQ_Q_Min;
        else if (EQ_Values_Pointer->Q > EQ_Q_Max)
            EQ_Values_Pointer->Q = EQ_Q_Max;
    HDWordReadSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size +   Para_Gain_Offset), &(EQ_Values_Pointer->Gain), 4 );
        if (EQ_Values_Pointer->Gain < EQ_Gain_Min)
            EQ_Values_Pointer->Gain = EQ_Gain_Min;
        else if (EQ_Values_Pointer->Gain > EQ_Gain_Max)
            EQ_Values_Pointer->Gain = EQ_Gain_Max;
    HDWordReadSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size +   Para_Type_Offset), (int*) &(EQ_Values_Pointer->Type), 4 );
        if (EQ_Values_Pointer->Type < EQ_TYPE_MIN)
            EQ_Values_Pointer->Type = EQ_TYPE_MIN;
        else if (EQ_Values_Pointer->Type > EQ_TYPE_MAX)
            EQ_Values_Pointer->Type =  EQ_TYPE_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, "DXO   ");

    /* write TGM splash to screen buffer */
    WriteBMP(ScreenBuff, SC_Logo_Full, 0, 0, 128, 64);
    Refresh_LCD;
    DelayMs(1500);
    /* write version to screen buffer*/
    WriteBMP(ScreenBuff, Solder, 0, 0, 128, 64);
    GLCD_WriteString_16x11_buf(ScreenBuff,&(Splash_line_1[0]),Splash_L1x, Splash_L1y);
    Write_Boot_Ver();
    Refresh_LCD;
    DelayMs(1500);
    Idle_Screen();
    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_XO_Band ( void )
  Remarks:
 * Presents screen for which band to be used to select XO band to change
******************************************************************************/
void CONTROL_XO_Band(void)
{   
    char XO_line_1[20];
    int tx, ty;
    
    /* write XO screen (CH_SELECT bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

    controlData.UI_Display_Lockout = true;

    /* Write Band Number to Screen */
    sprintf(XO_line_1, "Crossover Band %d", (controlData.XO_Band +1));
    if(controlData.XO_Band ==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,&(XO_line_1[0]),BandXO_X, BandXO_Y);
    }
    else if(controlData.XO_Band ==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_16x11_buf(ScreenBuff,&(XO_line_1[0]),BandXO_X1, BandXO_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(XO_line_1[0]),BandXO_X, BandXO_Y);
    }
    else if(controlData.XO_Band ==2) 
    {
        WriteBMP(ScreenBuff, CH_SELECT_B3, 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);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(XO_line_1[0]),BandXO_X, BandXO_Y);
    }
    else if(controlData.XO_Band ==3) 
    {
        WriteBMP(ScreenBuff, CH_SELECT_B4, 0, 0, 128, 64);
        WriteBMP_Buf(ScreenBuff, TGM_MED, BandXO_TGM_X3, BandXO_TGM_Y, 43, 16);
        //GLCD_WriteString_16x11_buf(ScreenBuff,&(XO_line_1[0]),BandXO_X3, BandXO_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(XO_line_1[0]),BandXO_X, BandXO_Y);
    }
    
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
        
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CONTROL_EQ_Band ( void )
  Remarks:
 * Presents screen for which EQ is to be used 
******************************************************************************/
void CONTROL_EQ_Band(void)
{   
    char EQ_line_1[20];
    char EQ_line_2[20];
    
    /* write EQ screen (CH_SELECT bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

    controlData.UI_Display_Lockout = true;

    /* Write Band Number to Screen */
    if(controlData.EQ_Band <= (Min_EQ_Band + 3))
    {
    WriteBMP(ScreenBuff, Choose_Para_EQ, 0, 0, 128, 64);
    sprintf(EQ_line_2, "No:%d", (controlData.EQ_Band + 1));
    GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),Para_Comm_X, Para_Comm_Y);
    }
    
    else if((controlData.EQ_Band > (Min_EQ_Band + 3)) && (controlData.EQ_Band <= (Min_EQ_Band + 5))) 
    {
    WriteBMP(ScreenBuff, Choose_Para_EQ, 0, 0, 128, 64);
    sprintf(EQ_line_2, "No:%d", (controlData.EQ_Band -3));
    GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),Para_CH1_X, Para_CH1_Y);
    }
    else if((controlData.EQ_Band > (Min_EQ_Band + 5)) && (controlData.EQ_Band <= (Min_EQ_Band + 7))) 
    {
    WriteBMP(ScreenBuff, Choose_Para_EQ, 0, 0, 128, 64);
    sprintf(EQ_line_2, "No:%d", (controlData.EQ_Band -5));
    GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),Para_CH2_X, Para_CH2_Y);
    }
    else
    {
        sprintf(EQ_line_1, "Oops Error");
    }

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

/*******************************************************************************
  Function:
    void CONTROL_EQ_Gain ( void )
  Remarks:
 * Presents screen for Selection of Gain for EQ
******************************************************************************/
void CONTROL_EQ_Gain(void)
{   
    char EQ_line_1[20];
    char EQ_line_2[20];
    
    /* write EQ Gain screen (///EQ_GAIN bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

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

    /* put up the eq band and number */
    /* Write Band Number to Screen */
    if((controlData.EQ_Band >=Min_EQ_Band) &&(controlData.EQ_Band <= 3)) 
    {
        sprintf(EQ_line_1, "Common");
        sprintf(EQ_line_2, "Para %d", (controlData.EQ_Band + 1));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else if((controlData.EQ_Band >3) &&(controlData.EQ_Band <= 5)) 
    {
        sprintf(EQ_line_1, "Band 1");
        sprintf(EQ_line_2, "Para %d", (controlData.EQ_Band -3));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else if((controlData.EQ_Band >5) &&(controlData.EQ_Band <= 7)) 
    {
        sprintf(EQ_line_1, "Band 2");
        sprintf(EQ_line_2, "Para %d", (controlData.EQ_Band -5));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else if((controlData.EQ_Band >7) &&(controlData.EQ_Band < 12)) 
    {
        sprintf(EQ_line_1, "OOPS");
        sprintf(EQ_line_2, "Error %d", (controlData.EQ_Band - 8));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else if((controlData.EQ_Band >=12) &&(controlData.EQ_Band < 15)) 
    {
        sprintf(EQ_line_1, "Damn");
        sprintf(EQ_line_2, "Error %d", (controlData.EQ_Band - 11));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else
    {
        sprintf(EQ_line_1, "Oops Error");
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
    }
    
        /* Write Frequency to Screen */
    sprintf(EQ_line_1, "GAIN:");
    GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaNote_X, ParaNote_Y);
    
    /* Write Frequency to Screen */
    sprintf(EQ_line_1, "%2ddB", (controlData.EQ_Values[controlData.EQ_Band].Gain));
    GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaG_X, ParaG_Y);
//    sprintf(LO_line_2, "Band %d", (controlData.XO_Band +1));
//    GLCD_WriteString_8x5_buf(ScreenBuff,&(LO_line_2[0]),XO_Band_X, XO_Band_Y);

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

/*******************************************************************************
  Function:
    void CONTROL_EQ_Q ( void )
  Remarks:
 * Presents screen for Selection of Q for EQ
******************************************************************************/
void CONTROL_EQ_Q(void)
{   
    char EQ_line_1[20];
    char EQ_line_2[20];
    
    /* write EQ Gain screen (///EQ_Q bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

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

    /* put up the eq band and number */
    /* Write Band Number to Screen */
    if((controlData.EQ_Band >=Min_EQ_Band) &&(controlData.EQ_Band <= 3)) 
    {
        sprintf(EQ_line_1, "Common");
        sprintf(EQ_line_2, "Para %d", (controlData.EQ_Band + 1));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else if((controlData.EQ_Band >3) &&(controlData.EQ_Band <= 5)) 
    {
        sprintf(EQ_line_1, "Band 1");
        sprintf(EQ_line_2, "Para %d", (controlData.EQ_Band -3));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else if((controlData.EQ_Band >5) &&(controlData.EQ_Band <= 7)) 
    {
        sprintf(EQ_line_1, "Band 2");
        sprintf(EQ_line_2, "Para %d", (controlData.EQ_Band -5));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else if((controlData.EQ_Band >7) &&(controlData.EQ_Band < 12)) 
    {
        sprintf(EQ_line_1, "Damn!");
        sprintf(EQ_line_2, "Oops %d", (controlData.EQ_Band - 8));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else if((controlData.EQ_Band >=12) &&(controlData.EQ_Band < 15)) 
    {
        sprintf(EQ_line_1, "Damn!");
        sprintf(EQ_line_2, "Oops %d", (controlData.EQ_Band - 11));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else
    {
        sprintf(EQ_line_1, "Oops Error");
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
    }
    
        /* Write Frequency to Screen */
    sprintf(EQ_line_1, "Filt Q:");
    GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaNote_X, ParaNote_Y);
    
    /* Write Q to Screen */
    sprintf(EQ_line_1, "%2.1f", (float)(controlData.EQ_Values[controlData.EQ_Band].Q)/10);
    GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaG_X, ParaG_Y);
//    sprintf(LO_line_2, "Band %d", (controlData.XO_Band +1));
//    GLCD_WriteString_8x5_buf(ScreenBuff,&(LO_line_2[0]),XO_Band_X, XO_Band_Y);

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

/*******************************************************************************
  Function:
    void CONTROL_EQ_Freq ( void )
  Remarks:
 * Presents screen for Selection of  Frequency for EQ
******************************************************************************/
void CONTROL_EQ_Freq(void)
{   
    char EQ_line_1[20];
    char EQ_line_2[20];
    char EQ_line_3[20];
    
    /* write EQ Freq screen (///eq_FREQ bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

    controlData.UI_Display_Lockout = true;

    /* put up the eq band and number */
    /* Write Band Number to Screen */
    if((controlData.EQ_Band >=Min_EQ_Band) &&(controlData.EQ_Band <= 3)) 
    {
        WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
        sprintf(EQ_line_1, "Common");
        sprintf(EQ_line_2, "Para %d", (controlData.EQ_Band + 1));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
        sprintf(EQ_line_1, "FREQ:");
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaNote_X, ParaNote_Y);
    
        /* Write Frequency to Screen */
        sprintf(EQ_line_1, "%5dHz", (controlData.EQ_Values[controlData.EQ_Band].CF));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaF_X, ParaF_Y);
    }
    else if((controlData.EQ_Band >3) &&(controlData.EQ_Band <= 5)) 
    {
        WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
        sprintf(EQ_line_1, "Band 1");
        sprintf(EQ_line_2, "Para %d", (controlData.EQ_Band - 3));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
        sprintf(EQ_line_1, "FREQ:");
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaNote_X, ParaNote_Y);
    
        /* Write Frequency to Screen */
        sprintf(EQ_line_1, "%5dHz", (controlData.EQ_Values[controlData.EQ_Band].CF));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaF_X, ParaF_Y);
    }
    else if((controlData.EQ_Band >5) &&(controlData.EQ_Band <= 7)) 
    {
        WriteBMP(ScreenBuff, EQ_FREQ, 0, 0, 128, 64);
        sprintf(EQ_line_1, "Band 2");
        sprintf(EQ_line_2, "Para %d", (controlData.EQ_Band - 5));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
        sprintf(EQ_line_1, "FREQ:");
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaNote_X, ParaNote_Y);
    
        /* Write Frequency to Screen */
        sprintf(EQ_line_1, "%5dHz", (controlData.EQ_Values[controlData.EQ_Band].CF));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaF_X, ParaF_Y);
   }
    else if((controlData.EQ_Band >7)) 
    {
        sprintf(EQ_line_1, "Damn");
        sprintf(EQ_line_2, "Oops %d", (controlData.EQ_Band - 8));
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_2[0]),ParaNo_X, ParaNo_Y);
    }
    else
    {
        sprintf(EQ_line_1, "Oops Error");
        GLCD_WriteString_12x7_buf(ScreenBuff,&(EQ_line_1[0]),ParaB_X, ParaB_Y);
    }
   
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}


/******************************************************************************/
//  Function:
//    void CONTROL_Choose_eq ( void )
//    
// AIm
//     - PResent options to user for choice of other functions
/*******************************************************************************/
void CONTROL_Choose_EQ( void )
{
    /* write Lo Freq screen (LOW_FREQ bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    switch (controlData.EQ_Values[controlData.EQ_Band].Type)
    {
        case EQ_TYPE_NONE:
        {
            WriteBMP(ScreenBuff, EQ_CHOOSE, 0, 0, 128, 64);
            WriteBMP_Buf(ScreenBuff, EQ_CHOOSE_INV_NONE, L_Graphic_x, L_Graphic_y, 61, 64);
            Refresh_LCD;
        }
        break;
       
        case EQ_TYPE_PARA:
        {
            WriteBMP(ScreenBuff, EQ_CHOOSE, 0, 0, 128, 64);
            WriteBMP_Buf(ScreenBuff, EQ_CHOOSE_INV_PARA, R_Double_Graphic_x, R_Double_Graphic_y, 63, 64);
            Refresh_LCD;
        }
        break;
        
        case EQ_TYPE_LPF:
        {
            WriteBMP(ScreenBuff, EQ_CHOOSE, 0, 0, 128, 64);
            WriteBMP_Buf(ScreenBuff, EQ_CHOOSE_INV_CD, R_Graphic_x, R_Graphic_y, 41, 64);
            Refresh_LCD;
        }
        break;
    }
controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CONTROL_XO_Lo_Freq ( void )
  Remarks:
 * Presents screen for Selection of Low Frequency for XO
******************************************************************************/
void CONTROL_XO_LO_Freq(void)
{   
    char LO_line_1[20];
    char LO_line_2[20];
    
    /* write Lo Freq screen (LOW_FREQ bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */
    controlData.UI_Display_Lockout = true;
    WriteBMP(ScreenBuff, LOW_FREQ, 0, 0, 128, 64);

    /* Write Frequency to Screen */
    sprintf(LO_line_1, "%5dHz", (controlData.Data_Values[controlData.XO_Band].Fl));
    GLCD_WriteString_16x11_buf(ScreenBuff,&(LO_line_1[0]),BandLO_X, BandLO_Y);
    sprintf(LO_line_2, "Band %d", (controlData.XO_Band +1));
    GLCD_WriteString_8x5_buf(ScreenBuff,&(LO_line_2[0]),XO_Band_X, XO_Band_Y);

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

/*******************************************************************************
  Function:
    void CONTROL_XO_Hi_Freq ( void )
  Remarks:
 * Presents screen for Selection of High Frequency for XO
******************************************************************************/
void CONTROL_XO_Hi_Freq(void)
{   
    char Hi_line_1[20];
    
    /* write Hi Freq screen (HIGH_FREQ bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

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

    /* Write Frequency to Screen */
    sprintf(Hi_line_1, "%5dHz", (controlData.Data_Values[controlData.XO_Band].Fu));
    GLCD_WriteString_16x11_buf(ScreenBuff,&(Hi_line_1[0]),BandHi_X, BandHi_Y);
    sprintf(Hi_line_1, "Band %d", (controlData.XO_Band +1));
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Hi_line_1[0]),XO_Band_X, XO_Band_Y);
    
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CONTROL_XO_Lo_Slope ( void )
  Remarks:
 * Presents screen for Selection of slopes for Lo Frequency of band
 ******************************************************************************/
void CONTROL_XO_Lo_Slope(void)
{   
    char Los_line_1[20];
    
    /* write Low Feeq XO screen (LOW_SLOPE bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

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

    /* Write Frequency to Screen */
    if ((controlData.Data_Values[controlData.XO_Band].Sl) == NoFilter)
        sprintf(Los_line_1, "None      ");
    else if ((controlData.Data_Values[controlData.XO_Band].Sl) == SixdB)
        sprintf(Los_line_1, "6dB BW    ");
    else if ((controlData.Data_Values[controlData.XO_Band].Sl) == TwelvedB)
        sprintf(Los_line_1, "12dB BW   ");
    else if ((controlData.Data_Values[controlData.XO_Band].Sl) == TwentyFourdB)
        sprintf(Los_line_1, "24dB LR   ");
    else 
        sprintf(Los_line_1, "OOPS - ERROR");
    
    GLCD_WriteString_16x10_buf(ScreenBuff,&(Los_line_1[0]),SlopeLo_X, SlopeLo_Y);
    sprintf(Los_line_1, "Band %d", (controlData.XO_Band +1));
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Los_line_1[0]),XO_Band_X, XO_Band_Y);
    
    controlData.UI_Update_Display = true;
    /* Clear the lock */
    Refresh_LCD;
    controlData.UI_Display_Lockout = false;
}

/*******************************************************************************
  Function:
    void CONTROL_XO_Hi_Slope ( void )
  Remarks:
 * Presents screen for Selection of slopes for Hi Frequency of band
 ******************************************************************************/
void CONTROL_XO_Hi_Slope(void)
{   
    char His_line_1[20];
    
    /* write Low Feeq XO screen (HI_SLOPE bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

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

    /* Write Frequency to Screen */
    if ((controlData.Data_Values[controlData.XO_Band].Su) == NoFilter)
        sprintf(His_line_1, "None      ");
    else if ((controlData.Data_Values[controlData.XO_Band].Su) == SixdB)
        sprintf(His_line_1, "6dB BW    ");
    else if ((controlData.Data_Values[controlData.XO_Band].Su) == TwelvedB)
        sprintf(His_line_1, "12dB BW   ");
    else if ((controlData.Data_Values[controlData.XO_Band].Su) == TwentyFourdB)
        sprintf(His_line_1, "24dB LR   ");
    else 
        sprintf(His_line_1, "OOPS - ERROR");
    
    GLCD_WriteString_16x10_buf(ScreenBuff,&(His_line_1[0]),SlopeHi_X, SlopeHi_Y);
        sprintf(His_line_1, "Band %d", (controlData.XO_Band +1));
    GLCD_WriteString_8x5_buf(ScreenBuff,&(His_line_1[0]),XO_Band_X, XO_Band_Y);

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

/*******************************************************************************
  Function:
    void CONTROL_XO_Hi_Freq ( void )
  Remarks:
 * Presents screen for Selection of High Frequency for XO
******************************************************************************/
void CONTROL_XO_Delay(void)
{   
    char Delay_line_1[20];
    
    /* write Delay screen (CH_DELAY bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

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

    /* Write Frequency to Screen */
    sprintf(Delay_line_1, "%5dmm", (controlData.Data_Values[controlData.XO_Band].Delay_mm*SpeedOfSound/Sample_Rate));
    GLCD_WriteString_16x11_buf(ScreenBuff,&(Delay_line_1[0]),BandDelay_X, BandDelay_Y);
    sprintf(Delay_line_1, "Band %d", (controlData.XO_Band +1));
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Delay_line_1[0]),XO_Band_X, XO_Band_Y);

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

/*******************************************************************************
  Function:
    void CONTROL_XO_Gain ( void )
  Remarks:
 * Presents screen for Selection of gain for band
******************************************************************************/
void CONTROL_XO_Gain(void)
{   
    char Gain_line_1[20];
    
    /* write Delay screen (CH_GAIN bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

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

    /* Write Frequency to Screen */
    sprintf(Gain_line_1, "%5.1fdB", ((float)(-controlData.Data_Values[controlData.XO_Band].Atten)/2));
    GLCD_WriteString_16x11_buf(ScreenBuff,&(Gain_line_1[0]),BandDelay_X, BandDelay_Y);
    sprintf(Gain_line_1, "Band %d", (controlData.XO_Band +1));
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Gain_line_1[0]),XO_Band_X, XO_Band_Y);

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

/*******************************************************************************
  Function:
    void CONTROL_XO_Invert ( void )
  Remarks:
 * Presents screen for Selection of inverting the audio output for band
******************************************************************************/
void CONTROL_XO_Invert(void)
{   
    char Invert_line_1[20];
    
    /* write Delay screen (CH_INVERT bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

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

    /* Write Frequency to Screen */
    if(controlData.Data_Values[controlData.XO_Band].Invert == Invert_True)
        sprintf(Invert_line_1, "Inverted");
    else if(controlData.Data_Values[controlData.XO_Band].Invert == Invert_False)
        sprintf(Invert_line_1, "Normal");
    else 
        sprintf(Invert_line_1, "Oops error");
    
    GLCD_WriteString_16x11_buf(ScreenBuff,&(Invert_line_1[0]),BandInvert_X, BandInvert_Y);
    sprintf(Invert_line_1, "Band %d", (controlData.XO_Band +1));
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Invert_line_1[0]),XO_Band_X, XO_Band_Y);

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

/*******************************************************************************
  Function:
    void CONTROL_XO_Bridge ( void )
  Remarks:
 * Presents screen for Selection of inverting the
 * LEFT output on Channel 1, and MONO for this band to create 
 * a bridged output for BAND 1
******************************************************************************/
void CONTROL_XO_Bridge(void)
{   
    char Bridge_line_1[20];
    
    /* write Delay screen (CH_BRIDGE bitmap) to screen buffer */
    /* use this lock to stop changing display strings half way through */

    controlData.UI_Display_Lockout = true;
    /* Write Frequency to Screen */
    if(controlData.Data_Values[controlData.XO_Band].Bridge == Bridge_True)
    {
        WriteBMP(ScreenBuff, CH_BRIDGE, 0, 0, 128, 64);
        sprintf(Bridge_line_1, "Bridged");
    }
    else if(controlData.Data_Values[controlData.XO_Band].Bridge == Bridge_False)
    {
        sprintf(Bridge_line_1, "Stereo");
        WriteBMP(ScreenBuff, CH_BRIDGE_STEREO, 0, 0, 128, 64);
    }
    else 
    {
        sprintf(Bridge_line_1, "Oops error");
        WriteBMP(ScreenBuff, CH_BRIDGE_STEREO, 0, 0, 128, 64);
    }
    
//    GLCD_WriteString_16x11_buf(ScreenBuff,&(Bridge_line_1[0]),BandBridge_X, BandBridge_Y);
    sprintf(Bridge_line_1, "Band %d", (controlData.XO_Band +1));
    GLCD_WriteString_8x5_buf(ScreenBuff,&(Bridge_line_1[0]),XO_Bridge_X, XO_Bridge_Y);

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



/*******************************************************************************
  Function:
    void Idle_Screen ( void )
  Remarks:
 * PResents strart up screen, initialises display for idle state
******************************************************************************/
void Idle_Screen(void)
{   
    int vol_x, x, y;
    
    /* 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, SC_MAIN_VOL, 0, 0, 128, 64);

    /* fill in the bar graph... */
    vol_x = (((Atten_Max-(controlData.Atten_Set)) * (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.Atten_Set);
    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 = CONTROL_STATE_INIT;
    controlData.UI_Timer = DRV_HANDLE_INVALID;
    controlData.UI_Count = 3;
    controlData.UI_Update_Counter = 0;
    controlData.UI_Speed = Speed_Init;
    controlData.UI_Update_Display = true;
    controlData.UI_Display_Lockout = false;
    controlData.UI_Keypressed = false;
    controlData.UI_Action = CONTROL_STATE_SAVE;
    controlData.heartbeatTimer = DRV_HANDLE_INVALID;
    controlData.heartbeatCount = 0;
    controlData.heartbeatToggle = false;
    controlData.MemoryBankSelected = 0;
    controlData.Atten_Set = 0;        /* update in CONTROL_EEPROM_Initialise */
    controlData.Atten_Last_Update = 0;        
    controlData.Revert_To_Idle_Counter = Revert_To_Idle;
    controlData.Atten_Set_Backup = Atten_Default;
    controlData.UI_Fast_Count = Fast_Counter_Init;
    controlData.UI_Slow_Count = Slow_Counter_Init;
    controlData.XO_Band = Min_XO_Band;
    controlData.EQ_Band = Min_EQ_Band;
    controlData.Input_Sel = Input_ADC;
    
    /* 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 */
    HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Volume_Offset), controlData.Atten_Set);
    HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Input_Selected_Offset), controlData.Input_Sel);

    for (loop = Min_XO_Band; loop <= Max_XO_Band; loop++)
        {
       	Data_Values_Pointer = &(controlData.Data_Values[loop]);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Fl_Offset), Data_Values_Pointer->Fl);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Fu_Offset), Data_Values_Pointer->Fu);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Sl_Offset), Data_Values_Pointer->Sl);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Su_Offset), Data_Values_Pointer->Su);
        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 + Delay_mm_Offset), Data_Values_Pointer->Delay_mm);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Invert_Offset), Data_Values_Pointer->Invert);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + loop*Channel_Set_Array_Size + Bridge_Offset), Data_Values_Pointer->Bridge);
        };

    /* Write Data for each Para Set from EEPROM */
    for (loop = Min_EQ_Band; loop <= Max_EQ_Band; loop++)
        {
        EQ_Values_Pointer = &(controlData.EQ_Values[loop]);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size + Para_CF_Offset), EQ_Values_Pointer->CF);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size+ Para_Q_Offset), EQ_Values_Pointer->Q);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size+ Para_Gain_Offset), EQ_Values_Pointer->Gain);
        HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size)+ Para_Gen_Base  + loop*Para_Set_Size+ Para_Type_Offset), EQ_Values_Pointer->Type);
        }
    DelayMs(Delay_After_Save_Ms);
    WriteBMP(ScreenBuff, Solder, 0, 0, 128, 64);
    Update_Atten_Set((int)controlData.Atten_Set);
    controlData.UI_Update_Display = true;
    Refresh_LCD;
}

/******************************************************************************/
//  Function:
//    void CONTROL_Choose_Fucntion ( void )
//    
// AIm
//     - PResent options to user for choice of other functions
/*******************************************************************************/
void CONTROL_Choose_Function( 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_EQ:
        {
            WriteBMP(ScreenBuff, Choose_Function, 0, 0, 128, 64);
            WriteBMP_Buf(ScreenBuff, Choose_Parametric, Q3_Graphic_x, Q3_Graphic_y, 63, 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_XO:
        {
            WriteBMP(ScreenBuff, Choose_Function, 0, 0, 128, 64);
            WriteBMP_Buf(ScreenBuff, Choose_Crossover, Q2_Graphic_x, Q2_Graphic_y, 63, 32);
            Refresh_LCD;
        }
        break;
    }
}

/******************************************************************************/
/*       this function updates filters in a sensible manner                   */
/* The __Optimise__ attribute is there to stop the do - while function being  */
/* reordered - the damn thing does not work if the function is optimised!!!   */
/******************************************************************************/
__attribute__((optimize("-O0"))) Filter_Parm_Update(int Channel_To_Update)
{
int Temp_Ch1_Gain, Temp_Ch2_Gain;


//you need to use these to update the filter parameters
//int New_Filter_Vals;    /* use to flag new filter parms */
//int New_a0, New_a1, New_a2, New_b0, New_b1, New_b2;       /* Biquad filter coefficients to update */


/* Set up Temp variable for volumes... Remember these are in half dB steps*/
Temp_Ch1_Gain = -(controlData.Data_Values[0].Atten + controlData.Atten_Set);
Temp_Ch2_Gain = -(controlData.Data_Values[1].Atten + controlData.Atten_Set);

/* for 4th order butterworth, need to cascade two filters	*/
/*					1st Q = 0.54		*/
/*					2nd Q = 1.31		*/
/* for 4th order LR, need to cascade two butterworth filters	*/
/*					1st Q = 0.707		*/
/*					2nd Q = 0.707		*/
/* for 2nd order butterworth, need one filter		*/
/*                                      1st Q = 1/SQRT(2)  = 0.707*/
/*                                      2nd passthrough*/
if (Channel_To_Update == Ch_1_Mode)
{
    if(controlData.Data_Values[0].Sl == NoFilter)
    {
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[0].Sl, controlData.Data_Values[0].Fl, Q_BW, 0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 3;            /* set to the bank number plus 1*/
        do { } while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[0].Sl, controlData.Data_Values[0].Fl, Q_BW, 0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 4;            /* set to the bank number plus 1*/
        do { } while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else if(controlData.Data_Values[0].Sl == SixdB)
    {
        Calc_DSP_Parms(F2_Type,  controlData.Data_Values[0].Sl, controlData.Data_Values[0].Fl, Q_BW, 0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 3;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[0].Sl, controlData.Data_Values[0].Fl, Q_BW, 0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 4;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else if(controlData.Data_Values[0].Sl == TwelvedB)
    {
        Calc_DSP_Parms(F2_Type, controlData.Data_Values[0].Sl, controlData.Data_Values[0].Fl,  Q_BW,0 ,0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 3;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[0].Sl, controlData.Data_Values[0].Fl, Q_BW,0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 4;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else if(controlData.Data_Values[0].Sl == TwentyFourdB)
    {
        Calc_DSP_Parms(F2_Type, TwelvedB, controlData.Data_Values[0].Fl, Q_BW, 0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 3;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(F3_Type, TwelvedB, controlData.Data_Values[0].Fl, Q_BW, 0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 4;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else;

    
    if(controlData.Data_Values[0].Su == NoFilter)
    {
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[0].Su, controlData.Data_Values[0].Fu, Q_BW, Temp_Ch1_Gain , 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        /* implement channel inversion*/
        if (CH1_Invert == -1)
        {
            New_b0 = - New_b0;
            New_b1 = - New_b1;
            New_b2 = - New_b2;
        }
        else;
        New_Filter_Vals = 5;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[0].Su, controlData.Data_Values[0].Fu, Q_BW, 0,              0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 6;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else if(controlData.Data_Values[0].Su == SixdB)
    {
        Calc_DSP_Parms(F4_Type, controlData.Data_Values[0].Su, controlData.Data_Values[0].Fu,  Q_BW, Temp_Ch1_Gain, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        /* implement channel inversion*/
        if (CH1_Invert == -1)
        {
            New_b0 = - New_b0;
            New_b1 = - New_b1;
            New_b2 = - New_b2;
        }
        else;
        New_Filter_Vals = 5;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[0].Su, controlData.Data_Values[0].Fu, Q_BW, 0,             0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 6;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else if(controlData.Data_Values[0].Su == TwelvedB)
    {
        Calc_DSP_Parms(F4_Type, controlData.Data_Values[0].Su, controlData.Data_Values[0].Fu, Q_BW, Temp_Ch1_Gain, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        /* implement channel inversion*/
        if (CH1_Invert == -1)
        {
            New_b0 = - New_b0;
            New_b1 = - New_b1;
            New_b2 = - New_b2;
        }
        else;
        New_Filter_Vals = 5;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[0].Su, controlData.Data_Values[0].Fu, Q_BW,            0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 6;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else if(controlData.Data_Values[0].Su == TwentyFourdB)
    {
        Calc_DSP_Parms(F4_Type, TwelvedB                , controlData.Data_Values[0].Fu, Q_BW, Temp_Ch1_Gain, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        /* implement channel inversion*/
        if (CH1_Invert == -1)
        {
            New_b0 = - New_b0;
            New_b1 = - New_b1;
            New_b2 = - New_b2;
        }
        else;
        New_Filter_Vals = 5;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(F5_Type, TwelvedB                , controlData.Data_Values[0].Fu, Q_BW,             0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 6;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
}
else if (Channel_To_Update == Ch_2_Mode)
{
    if(controlData.Data_Values[1].Sl == NoFilter)
    {
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[1].Sl, controlData.Data_Values[1].Fl, Q_BW, Temp_Ch2_Gain, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        /* implement channel inversion*/
        if (CH2_Invert == -1)
        {
            New_b0 = - New_b0;
            New_b1 = - New_b1;
            New_b2 = - New_b2;
        }
        else;
        New_Filter_Vals = 7;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[1].Sl, controlData.Data_Values[1].Fl, Q_BW,             0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 8;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else if(controlData.Data_Values[1].Sl == SixdB)
    {
        Calc_DSP_Parms(F6_Type, controlData.Data_Values[1].Sl, controlData.Data_Values[1].Fl, Q_BW, Temp_Ch2_Gain, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        /* implement channel inversion*/
        if (CH2_Invert == -1)
        {
            New_b0 = - New_b0;
            New_b1 = - New_b1;
            New_b2 = - New_b2;
        }
        else;
        New_Filter_Vals = 7;            /* set to the bank number plus 1*/
        do { } while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[1].Sl, controlData.Data_Values[1].Fl, Q_BW,            0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 8;            /* set to the bank number plus 1*/
        do {   } while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else if(controlData.Data_Values[1].Sl == TwelvedB)
    {
        Calc_DSP_Parms(F6_Type, controlData.Data_Values[1].Sl, controlData.Data_Values[1].Fl, Q_BW, Temp_Ch2_Gain, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        /* implement channel inversion*/
        if (CH2_Invert == -1)
        {
            New_b0 = - New_b0;
            New_b1 = - New_b1;
            New_b2 = - New_b2;
        }
        else;
        New_Filter_Vals = 7;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(NoFilter, controlData.Data_Values[1].Sl, controlData.Data_Values[1].Fl, Q_BW,            0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 8;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
    else if(controlData.Data_Values[1].Sl == TwentyFourdB)
    {
        Calc_DSP_Parms(F6_Type, TwelvedB, controlData.Data_Values[1].Fl, Q_BW, Temp_Ch2_Gain, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        /* implement channel inversion*/
        if (CH2_Invert == -1)
        {
            New_b0 = - New_b0;
            New_b1 = - New_b1;
            New_b2 = - New_b2;
        }
        else;
        New_Filter_Vals = 7;            /* set to the bank number plus 1*/
        do { } while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        Calc_DSP_Parms(F7_Type, TwelvedB, controlData.Data_Values[1].Fl, Q_BW,             0, 0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
        New_Filter_Vals = 8;            /* set to the bank number plus 1*/
        do {} while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
    }
}
else if (Channel_To_Update == Gen_Para_Mode)
{
    for (loop=Min_EQ_Band; loop <= Max_EQ_Band; loop++)
    {
        if(controlData.EQ_Values[loop].Type == EQ_TYPE_NONE)
        {
            Calc_DSP_Parms(EQ_TYPE_NONE, controlData.EQ_Values[loop].Type, controlData.EQ_Values[loop].CF,                                   0, 0,                                    0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
            New_Filter_Vals = Para_Update_Base + loop;            /* set to the bank number plus 1*/
            do { } while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        }
        else if(controlData.EQ_Values[loop].Type == EQ_TYPE_PARA)
        {
            Calc_DSP_Parms(EQ_TYPE_PARA, controlData.EQ_Values[loop].Type, controlData.EQ_Values[loop].CF, (double)(controlData.EQ_Values[loop].Q), 0, (double)(controlData.EQ_Values[loop].Gain), &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
            New_Filter_Vals = Para_Update_Base + loop;            /* set to the bank number plus 1*/
            do { } while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        }
        else if(controlData.EQ_Values[loop].Type == EQ_TYPE_LPF)
        {
            Calc_DSP_Parms(LowPass, controlData.EQ_Values[loop].Type, controlData.EQ_Values[loop].CF,                              Q_BW, 0,                                    0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
            New_Filter_Vals = Para_Update_Base + loop;            /* set to the bank number plus 1*/
            do { } while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        }
        else   /* just to catch errors - should never be this value as only have 1 biquad*/
        {
            Calc_DSP_Parms(NoFilter, controlData.EQ_Values[loop].Type, controlData.EQ_Values[loop].CF,                                   0, 0,                                    0, &New_a0, &New_a1, &New_a2, &New_b0, &New_b1, &New_b2);
            New_Filter_Vals = Para_Update_Base + loop;            /* set to the bank number plus 1*/
            do { } while(New_Filter_Vals);     /* then wait till the ISR picks up the values, and clears the flag */
        }
    }
}

}


/****************************************************************************/
/*       CALCULATE THE IIR FILTER PARAMETERS                                */
/* filter type, filter Rate, freq, Q, GainGen, Gain, A0, A1, A2, B0, B1, B2*/
/****************************************************************************/
void Calc_DSP_Parms(int FilterType, int FilterRate, int FilterFreq, double FilterQ, int GainGen, int Gain, int *A0, int *A1, int *A2, int *B0, int *B1, int *B2)
{
    double W0, Alpha;
    double gainLinear;
    double A_gain;

    gainLinear = pow(10,(double)GainGen/40);  /* remember that filter gain is in half dB steps*/
                                              /* and this is in fact an attenuation...*/
    W0 = 2*Pi* (double)FilterFreq/ (double)Sample_Rate;
    Alpha = sin(W0)/(2*(double)FilterQ/10);      /* alpha = sin(?0)/(2*Q)*/
    A_gain = pow(10, (double)Gain/40);


    if ((FilterType == LowPass) && ((FilterRate == TwelvedB) || ((FilterRate == EQ_TYPE_LPF)))) 
    {
     /*     a0 = 1 + alpha
            a1 = -2*cos(?0)
            a2 = 1 - alpha
            b0 = (1 - cos(?0)) * gainLinear / 2
            b1 = (1 - cos(?0)) * gainLinear
            b2 = (1 - cos(?0)) * gainLinear / 2*/
        *A0 = (int)(IIR_Scaling);
        *A1 = (int) IIR_Scaling*((2 * cos(W0))/(1 + Alpha)); /* change sign */
        *A2 = (int) IIR_Scaling*(-(1 - Alpha)/(1 + Alpha));  /* change sign */
        *B0 = (int) IIR_Scaling*(((1 - cos(W0)) * gainLinear / 2)/(1 + Alpha));
        *B1 = (int) IIR_Scaling*(((1 - cos(W0)) * gainLinear)/(1 + Alpha));
        *B2 = (int) IIR_Scaling*(((1 - cos(W0)) * gainLinear / 2)/(1 + Alpha));
    }
    else if ((FilterType == LowPass) && (FilterRate == SixdB))
    {
    /*      Coefficients
            a1 = 2.7^-?0
            b0 = gainLinear * (1.0 - a1)
            b1 = 0  */
        *A0 = (int)(IIR_Scaling);
        *A1 = (int) IIR_Scaling*pow((double)2.7, -W0);
        *A2 = (int) 0;
        *B0 = (int) IIR_Scaling*(gainLinear * (1 - pow((double)2.7, -W0)));
        *B1 = (int) 0;
        *B2 = (int) 0;
    }
    else if ((FilterType == HighPass)  && (FilterRate == TwelvedB))
    {
        /* A0 = 1 + alpha
           A1 = -2*cos(?0)
           A2 = 1 - alpha
           B0 = (1 + cos(?0)) * gainLinear / 2
           B1 = -(1 + cos(?0)) * gainLinear
           B2 = (1 + cos(?0)) * gainLinear / 2
        */
        *A0 = (int) (IIR_Scaling);
        *A1 = (int) (IIR_Scaling*((2 * cos(W0))/(1 + Alpha))); /* change sign */
        *A2 = (int) (IIR_Scaling*(-(1 - Alpha)/(1 + Alpha)));  /* change sign */
        *B0 = (int) (IIR_Scaling*(((1 + cos(W0)) * gainLinear / 2)/(1 + Alpha)));
        *B1 = (int) (IIR_Scaling*((-(1 + cos(W0)) * gainLinear)/(1 + Alpha)));
        *B2 = (int) (IIR_Scaling*(((1 + cos(W0)) * gainLinear / 2)/(1 + Alpha)));
    }
    else if ((FilterType == HighPass) && (FilterRate == SixdB))
    {
    /*
     Coefficients   a1 = 2.7^-?0
                    b0 = gainLinear * a1
                    b1 = -a1 * gainLinear
             */
        *A0 = (int)(IIR_Scaling);
        *A1 = (int) IIR_Scaling * pow((double)2.7,-W0);
        *A2 = (int) 0;
        *B0 = (int) (gainLinear * (*A1));     /* remember A1 is already scales by IIR_Scaling....*/
        *B1 = (int) (-gainLinear * (*A1));    /* remember A1 is already scales by IIR_Scaling....*/
        *B2 = (int) 0;
    }
    else if (FilterType == EQ_TYPE_PARA)
    {
        /*  A = 10^(Gain/40)
            a0 = 1 + alpha/A
            a1 = -2 * cos(?0)
            a2 = 1 - alpha/A
            b0 = (1 + alpha*A) * gainLinear
            b1 = -(2 * cos(?0)) * gainLinear
            b2 = (1 - alpha*A) * gainLinear
         */
        *A0 = (int)(IIR_Scaling);
        *A1 = (int) IIR_Scaling*((2 * cos(W0))/(1 + Alpha/A_gain)); /* change sign */
        *A2 = (int) IIR_Scaling*(((Alpha/A_gain) -1)/(1 + Alpha/A_gain));  /* change sign */
        *B0 = (int) IIR_Scaling*(((1 + Alpha*A_gain) * gainLinear)/(1 + Alpha/A_gain));
        *B1 = (int) IIR_Scaling*((-2*cos(W0) * gainLinear)/(1 + Alpha/A_gain));
        *B2 = (int) IIR_Scaling*(((1 - Alpha*A_gain) * gainLinear)/(1 + Alpha/A_gain));
    }
    else /* filtertype = none*/
    {
        *A0 = 0;
        *A1 = 0;
        *A2 = 0;
        *B0 = (int) IIR_Scaling * gainLinear;
        *B1 = 0;
        *B2 = 0;
    };
}



/********************************************************************************/
/* Call this to update all Atten settings etc 									*/
/*	inputs																		*/
/*		DAC_Attenuation - attenution sought in 0.5dB steps							*/
/*		Data_Values  with band attenuation in 0.5dB steps		*/
/*	Outputs																		*/
/*		None																	*/
/*	Calls Write Atten Loop with required attentaion in o.5dB steps				*/
/********************************************************************************/
Update_Atten_Set(int DAC_Attenuation)
{
int temp_atten;

    /* write value to screen buffer */
    sprintf(line1, "%5.1fdB", ((float)(-DAC_Attenuation)/2));
    GLCD_WriteString_16x11_buf(ScreenBuff,&(line1[0]),UI_Vol_X, UI_Vol_Y);

/* you might need to add something in here... */
    Filter_Parm_Update(Ch_1_Mode);
    Filter_Parm_Update(Ch_2_Mode);
}


/******************************************************************************/
//  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;


    /* 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;
    }

//    do {SYS_PORTS_PinToggle(PORTS_ID_0, PORT_CHANNEL_F,
//                            PORTS_BIT_POS_3); } while(1);
    
    /* Check the application's current state. */
    switch ( controlData.state )
    {
        /* Application's initial state. */
        case CONTROL_STATE_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 = CONTROL_STATE_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);
                
            /*****************************************************************/
            /*                    enable things                              */
            /*****************************************************************/
            PLIB_SPI_Enable(I2S_CH1);
            PLIB_SPI_Enable(I2S_CH2);
            /* reset interrupt status */        
            SYS_INT_Enable();


            /* 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);

            /* Kick start the Audio SPI transmission */
            Chan_1_Port_RW = I2S_DummyDat; 
            Chan_1_Port_RW = I2S_DummyDat; 
            Chan_2_Port_RW = I2S_DummyDat; 
            Chan_2_Port_RW = I2S_DummyDat;         
        }
        break;

        /* Application's initial state. */
        case CONTROL_STATE_LCDINIT:
        {
            for(jl = 0; jl < KS0108_SCREEN_HEIGHT/8; jl++)
            {
                for(il = 0; (il < (int)(KS0108_SCREEN_WIDTH)); il++)
                {
                    ScreenBuff[il][jl] = 0;
                    ScreenBuff1[il][jl] = 0;
                }
            }
            /* Function Select */  /* Display On */

            GLCD_Initalize();
            /* Display Clear */
            GLCD_ClearScreen();

            GLCD_WriteCommand(DISPLAY_ON_CMD | DISPLAY_ON, 0);
            GLCD_WriteCommand(DISPLAY_ON_CMD | DISPLAY_ON, 1);
            // Splash Start Up Screen
            Splash_Screen();
            controlData.state = CONTROL_STATE_IDLE;
            /* start with input muted */
            Input_Mute = 0;
            /* set invert variables*/
            if(controlData.Data_Values[Min_XO_Band].Invert == Invert_True)
               CH1_Invert = 1; /* OK this is untidy */ 
            else 
               CH1_Invert = 0; /* OK this is untidy */ 
            if(controlData.Data_Values[Min_XO_Band +1].Invert == Invert_True)
               CH2_Invert = 1; /* OK this is untidy */ 
            else 
               CH2_Invert = 0; /* OK this is untidy */ 
            if(controlData.Data_Values[Min_XO_Band].Bridge == Bridge_True)
               CH1_L_Bridge = 1; /* This says Channel 1 is bridged at startup */ 
            else 
               CH1_L_Bridge = 0; /* This says Channel 1 is NOT bridged at startup */ 
            Update_Atten_Set((int)Mute);
            /* Update Filters*/
            Filter_Parm_Update(Gen_Para_Mode);
            Filter_Parm_Update(Ch_1_Mode);
            Filter_Parm_Update(Ch_2_Mode);
            /* and then unmute the input */
            Input_Mute = 1;
            /* update delay offset value */
                Write_Pointer_Offset = 0;
                Ch1_Rd_Offset = (Write_Pointer_Offset - controlData.Data_Values[Ch1_Band_No].Delay_mm) & Delay_Buf_Size_Mask ;
                Ch2_Rd_Offset = (Write_Pointer_Offset - controlData.Data_Values[Ch2_Band_No].Delay_mm) & Delay_Buf_Size_Mask ;
            Update_Atten_Set(controlData.Atten_Set);	/* Load Attenuator Settings including volume */
            /* let things settle*/
            DelayMs(100);
            Key_Just_Pressed = 0;
        }        
        break;

        /* we are just sitting there at the "normal" screen */        
        case CONTROL_STATE_IDLE:
        {
            /* 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);
            /* reset the set temperature */
            controlData.Atten_Set = controlData.Atten_Set_Backup;

                if (Keypress_Read == Rot_Down)
                {
                    controlData.Atten_Set += Atten_Step * controlData.UI_Speed;
                    if (controlData.Atten_Set > Atten_Max)
                        controlData.Atten_Set = Atten_Max;
                    controlData.UI_Update_Display = true;
   					Update_Atten_Set(controlData.Atten_Set);
                    controlData.Atten_Set_Backup = controlData.Atten_Set;
                }
                else if  (Keypress_Read == Rot_Up)
                {
                    controlData.Atten_Set -= Atten_Step  * controlData.UI_Speed;
                    if (controlData.Atten_Set < Atten_Min)
                        controlData.Atten_Set = Atten_Min;
                    controlData.UI_Update_Display = true;
   					Update_Atten_Set(controlData.Atten_Set);
                    controlData.Atten_Set_Backup = controlData.Atten_Set;
                }
                else if (Keypress_Read == Exit)
                {
                    controlData.UI_Action = CONTROL_ACTION_SAVE;
                    controlData.state = CONTROL_STATE_CHOOSING;
                    HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Volume_Offset), controlData.Atten_Set);
                    /* put the right display up */
                    CONTROL_Choose_Function();
                }
                else if (Keypress_Read == Sel)
                {
                    controlData.UI_Action = CONTROL_ACTION_SAVE;
                    controlData.state = CONTROL_STATE_CHOOSING;
                    HDWordWriteSPI(((controlData.MemoryBankSelected*ParmSet_Array_Size) + Volume_Offset), controlData.Atten_Set);
                    /* put the right display up */
                    CONTROL_Choose_Function();
                }
                controlData.UI_Keypressed = false;
            }    

            if (Update_UI_Timer && controlData.UI_Update_Display) 
            {
                Idle_Screen();
                Reset_UI_Timer;
                controlData.UI_Update_Display = false;
            }
        }
        break;
               
        case CONTROL_STATE_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 IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case CONTROL_STATE_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((int)Mute);
                    if (controlData.Atten_Set < Atten_On_Loading_Min)
                        controlData.Atten_Set = Atten_On_Loading_Min;	/* limit things just in case there is a massive error by the user... */
                    /* Update Filters*/
                    Filter_Parm_Update(Gen_Para_Mode);
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    /* and then unmute the input */
                    Input_Mute = 1;
                    /* update delay offset value */
                        Ch1_Rd_Offset = (Write_Pointer_Offset - controlData.Data_Values[Ch1_Band_No].Delay_mm) & Delay_Buf_Size_Mask ;
                        Ch2_Rd_Offset = (Write_Pointer_Offset - controlData.Data_Values[Ch2_Band_No].Delay_mm) & Delay_Buf_Size_Mask ;
                    Update_Atten_Set(controlData.Atten_Set);	/* Load Attenuator Settings including volume */

                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
        
        case CONTROL_STATE_EQ_BAND:
        {
            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.EQ_Band++;
                    if (controlData.EQ_Band > (Max_EQ_Band))
                        controlData.EQ_Band = Min_EQ_Band;
                    /* This function displays the save screen  */
                    CONTROL_EQ_Band();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.EQ_Band--;
                    if (controlData.EQ_Band < Min_EQ_Band)
                        controlData.EQ_Band = Max_EQ_Band;
                    /* This function displays the save screen  */
                    CONTROL_EQ_Band();
                }
                else if (Keypress_Read == Sel)
                {
                    /* put update type in here */
                    CONTROL_Choose_EQ();
                    controlData.state = CONTROL_STATE_EQ_TYPE;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
       
        case CONTROL_STATE_EQ_GAIN:
        {
            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.EQ_Values[controlData.EQ_Band].Gain += controlData.UI_Speed;
                    if (controlData.EQ_Values[controlData.EQ_Band].Gain > EQ_Gain_Max)
                        controlData.EQ_Values[controlData.EQ_Band].Gain = EQ_Gain_Max;
                    /* Update Filters for PARA mode (not the crossovers)*/
                    Filter_Parm_Update(Gen_Para_Mode);
                    CONTROL_EQ_Gain();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.EQ_Values[controlData.EQ_Band].Gain -= controlData.UI_Speed;
                    if (controlData.EQ_Values[controlData.EQ_Band].Gain < EQ_Gain_Min)
                        controlData.EQ_Values[controlData.EQ_Band].Gain = EQ_Gain_Min;
                    /* Update Filters for PARA mode (not the crossovers)*/
                    Filter_Parm_Update(Gen_Para_Mode);
                    CONTROL_EQ_Gain();
                }
                else if (Keypress_Read == Sel)
                {
                    /* put update EQ Q in here */
                    CONTROL_EQ_Q();
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_EQ_Q;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case CONTROL_STATE_EQ_Q:
        {
            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(Q_Speed , Q_Normal_Speed);
        
                if (Keypress_Read == Rot_Up)
                {
                    controlData.EQ_Values[controlData.EQ_Band].Q += controlData.UI_Speed;
                    if (controlData.EQ_Values[controlData.EQ_Band].Q > EQ_Q_Max)
                        controlData.EQ_Values[controlData.EQ_Band].Q = EQ_Q_Max;
                    /* Update Filters for PARA mode (not the crossovers)*/
                    Filter_Parm_Update(Gen_Para_Mode);
                    CONTROL_EQ_Q();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.EQ_Values[controlData.EQ_Band].Q -= controlData.UI_Speed;
                    if (controlData.EQ_Values[controlData.EQ_Band].Q < EQ_Q_Min)
                        controlData.EQ_Values[controlData.EQ_Band].Q = EQ_Q_Min;
                    /* Update Filters for PARA mode (not the crossovers)*/
                    Filter_Parm_Update(Gen_Para_Mode);
                    CONTROL_EQ_Q();
                }
                else if (Keypress_Read == Sel)
                {
                    controlData.EQ_Band++;
                    if (controlData.EQ_Band > Max_EQ_Band)
                        controlData.EQ_Band = Min_EQ_Band;

                    controlData.state = CONTROL_STATE_EQ_BAND;
                    /* This function displays the appropriate screen  */
                    CONTROL_EQ_Band();
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
        
        case CONTROL_STATE_EQ_FREQ:
        {
            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(EQ_Speed , EQ_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.EQ_Values[controlData.EQ_Band].CF += EQ_Normal_Speed * controlData.UI_Speed;
                    if (controlData.EQ_Values[controlData.EQ_Band].CF > EQ_Max)
                        controlData.EQ_Values[controlData.EQ_Band].CF = EQ_Max;
                    /* Update Filters for PARA mode (not the crossovers)*/
                    Filter_Parm_Update(Gen_Para_Mode);
                    CONTROL_EQ_Freq();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.EQ_Values[controlData.EQ_Band].CF -= EQ_Normal_Speed * controlData.UI_Speed;
                    if (controlData.EQ_Values[controlData.EQ_Band].CF < EQ_Min)
                        controlData.EQ_Values[controlData.EQ_Band].CF = EQ_Min;
                    /* Update Filters for PARA mode (not the crossovers)*/
                    Filter_Parm_Update(Gen_Para_Mode);
                    CONTROL_EQ_Freq();
                }
                else if (Keypress_Read == Sel)
                {
                    /* GO BACK TO IDLE STATE */        
                    
                    if (controlData.EQ_Values[controlData.EQ_Band].Type == EQ_TYPE_LPF)
                    {
                        controlData.EQ_Band++;
                        if (controlData.EQ_Band >= Max_EQ_Band)
                            controlData.EQ_Band = Min_EQ_Band;

                        controlData.state = CONTROL_STATE_EQ_BAND;
                        /* This function displays the appropriate screen  */
                        CONTROL_EQ_Band();
                    }
                    else
                    {
                        /* put update EQ GAIN in here */
                        CONTROL_EQ_Gain();
                        controlData.state = CONTROL_STATE_EQ_GAIN;
                    }
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
        
        case CONTROL_STATE_EQ_TYPE:
        {
            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 = EQ_Normal_Speed;

                if (Keypress_Read == Rot_Up)
                {
                    if (controlData.EQ_Values[controlData.EQ_Band].Type < EQ_TYPE_MAX)
                        controlData.EQ_Values[controlData.EQ_Band].Type += 1;
                    else if (controlData.EQ_Values[controlData.EQ_Band].Type == EQ_TYPE_MAX)
                        controlData.EQ_Values[controlData.EQ_Band].Type = EQ_TYPE_MIN;
                       else  /* catch errors */ 
                        controlData.EQ_Values[controlData.EQ_Band].Type = EQ_TYPE_MIN;
                    /* Update Filters for PARA mode (not the crossovers)*/
                    Filter_Parm_Update(Gen_Para_Mode);
                    CONTROL_Choose_EQ();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    if (controlData.EQ_Values[controlData.EQ_Band].Type > EQ_TYPE_MIN)
                        controlData.EQ_Values[controlData.EQ_Band].Type -= 1;
                    else if (controlData.EQ_Values[controlData.EQ_Band].Type == EQ_TYPE_MIN)
                        controlData.EQ_Values[controlData.EQ_Band].Type = EQ_TYPE_MAX;
                       else  /* catch errors */ 
                        controlData.EQ_Values[controlData.EQ_Band].Type = EQ_TYPE_MIN;
                    /* Update Filters for PARA mode (not the crossovers)*/
                    Filter_Parm_Update(Gen_Para_Mode);
                    CONTROL_Choose_EQ();
                }
                else if (Keypress_Read == Sel)
                {
                    if (controlData.EQ_Values[controlData.EQ_Band].Type == EQ_TYPE_NONE)
                        {
                        /* then jumpo to next EQ */
                        controlData.EQ_Band++;
                        if (controlData.EQ_Band > Max_EQ_Band)
                            controlData.EQ_Band = Min_EQ_Band;
                        /* Update Filters for PARA mode (not the crossovers)*/
                        Filter_Parm_Update(Gen_Para_Mode);
                        controlData.state = CONTROL_STATE_EQ_BAND;
                        /* This function displays the appropriate screen  */
                        CONTROL_EQ_Band();
                    }
                    else if (controlData.EQ_Values[controlData.EQ_Band].Type == EQ_TYPE_PARA)
                    {
                        /* then jumpo to next EQ Freq */
                        controlData.state = CONTROL_STATE_EQ_FREQ;
                        controlData.UI_Action = CONTROL_ACTION_EQ_FREQ;
                        CONTROL_EQ_Freq();
                    }
                    else if (controlData.EQ_Values[controlData.EQ_Band].Type == EQ_TYPE_LPF)
                    {
                        controlData.state = CONTROL_STATE_EQ_FREQ;
                        /* This function displays the appropriate screen  */
                        CONTROL_EQ_Freq();                    }
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
        
        case CONTROL_STATE_XO_BAND:
        {
            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.XO_Band++;
                    if (controlData.XO_Band > Max_XO_Band)
                        controlData.XO_Band = Min_XO_Band;
                    /* This function displays the appropriate screen  */
                    CONTROL_XO_Band();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.XO_Band--;
                    if (controlData.XO_Band < Min_XO_Band)
                        controlData.XO_Band = Max_XO_Band;
                    /* This function displays the save screen  */
                    CONTROL_XO_Band();
                }
                else if (Keypress_Read == Sel)
                {
                    /* This function displays the save logo and writes the data to EEPROM */
                    /* put update FL in here */
                    CONTROL_XO_LO_Freq();
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_LO_FREQ;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case CONTROL_STATE_LO_FREQ:
        {
            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(FL_Speed , FL_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.XO_Band].Fl += FL_Step * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.XO_Band].Fl > Fl_Max)
                        controlData.Data_Values[controlData.XO_Band].Fl = Fl_Max;
                    /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_LO_Freq();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.XO_Band].Fl -= FL_Step * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.XO_Band].Fl < Fl_Min)
                        controlData.Data_Values[controlData.XO_Band].Fl = Fl_Min;
                    /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_LO_Freq();
                }
                else if (Keypress_Read == Sel)
                {
                    if (controlData.XO_Band < Max_XO_Band)
                    {
                        /* This function displays the save logo and writes the data to EEPROM */
                        /* put update FL in here */
                        CONTROL_XO_Hi_Freq();
                        /* GO BACK TO IDLE STATE */        
                        controlData.state = CONTROL_STATE_HI_FREQ;
                    }
                    else if (controlData.XO_Band == Max_XO_Band)
                    {
                        /* the top band does not have a LPF.....*/
                        /* put update FL in here */
                        CONTROL_XO_Lo_Slope();
                        /* GO BACK TO IDLE STATE */        
                        controlData.state = CONTROL_STATE_LO_SLOPE;
                    }
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case CONTROL_STATE_HI_FREQ:
        {
            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(FH_Speed , FH_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.XO_Band].Fu += FH_Step * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.XO_Band].Fu > Fu_Max)
                        controlData.Data_Values[controlData.XO_Band].Fu = Fu_Max;
                    /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_Hi_Freq();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.XO_Band].Fu -= FH_Step * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.XO_Band].Fu < Fu_Min)
                        controlData.Data_Values[controlData.XO_Band].Fu = Fu_Min;
                    /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_Hi_Freq();
                }
                else if (Keypress_Read == Sel)
                {
                    /* This function displays the save logo and writes the data to EEPROM */
                    /* put update FL in here */
                    CONTROL_XO_Lo_Slope();
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_LO_SLOPE;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

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

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.XO_Band].Sl += SL_Step;
                    if (controlData.Data_Values[controlData.XO_Band].Sl > Sl_Max)
                        controlData.Data_Values[controlData.XO_Band].Sl = Sl_Min;
                    /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_Lo_Slope();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.XO_Band].Sl -= SL_Step;
                    if (controlData.Data_Values[controlData.XO_Band].Sl < Sl_Min)
                        controlData.Data_Values[controlData.XO_Band].Sl = Sl_Max;
                    /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_Lo_Slope();
                }
                else if (Keypress_Read == Sel)
                {
                    if (controlData.XO_Band < Max_XO_Band)
                    {
                        /* put update FL in here */
                        CONTROL_XO_Hi_Slope();
                        /* GO BACK TO IDLE STATE */        
                        controlData.state = CONTROL_STATE_HI_SLOPE;
                    }
                    else if (controlData.XO_Band == Max_XO_Band)
                    {
                        /* the top band does not have a LPF therefore not slope...*/
                        /* put update FL in here */
                        CONTROL_XO_Delay();
                        /* GO BACK TO Delay STATE */        
                    controlData.state = CONTROL_STATE_DELAY;
                    }
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

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

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.XO_Band].Su += Su_Step;
                    if (controlData.Data_Values[controlData.XO_Band].Su > Su_Max)
                        controlData.Data_Values[controlData.XO_Band].Su = Su_Min;
                    /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_Hi_Slope();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.XO_Band].Su -= Su_Step;
                    if (controlData.Data_Values[controlData.XO_Band].Su < Su_Min)
                        controlData.Data_Values[controlData.XO_Band].Su = Su_Max;
                     /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_Hi_Slope();
                }
                else if (Keypress_Read == Sel)
                {
                    /* This function displays the save logo and writes the data to EEPROM */
                    /* put update FL in here */
                    CONTROL_XO_Delay();
                    /* GO BACK TO Delay STATE */        
                    controlData.state = CONTROL_STATE_DELAY;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

        case CONTROL_STATE_DELAY:
        {
            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(Delay_Speed , Delay_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.XO_Band].Delay_mm += Delay_Step * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.XO_Band].Delay_mm > Delay_Max)
                        controlData.Data_Values[controlData.XO_Band].Delay_mm = Delay_Max;
                    /* update delay offset value */
                    Ch1_Rd_Offset = (Write_Pointer_Offset - controlData.Data_Values[Ch1_Band_No].Delay_mm) & Delay_Buf_Size_Mask ;
                    Ch2_Rd_Offset = (Write_Pointer_Offset - controlData.Data_Values[Ch2_Band_No].Delay_mm) & Delay_Buf_Size_Mask ;
                    CONTROL_XO_Delay();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.XO_Band].Delay_mm -= Delay_Step * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.XO_Band].Delay_mm < Delay_Min)
                        controlData.Data_Values[controlData.XO_Band].Delay_mm = Delay_Min;
                    /* update delay offset value */
                    Ch1_Rd_Offset = (Write_Pointer_Offset - controlData.Data_Values[Ch1_Band_No].Delay_mm) & Delay_Buf_Size_Mask ;
                    Ch2_Rd_Offset = (Write_Pointer_Offset - controlData.Data_Values[Ch2_Band_No].Delay_mm) & Delay_Buf_Size_Mask ;
                    CONTROL_XO_Delay();
                }
                else if (Keypress_Read == Sel)
                {
                    CONTROL_XO_Gain();
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_GAIN;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
 
        case CONTROL_STATE_GAIN:
        {
            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(Gain_Speed , Gain_Normal_Speed);

                if (Keypress_Read == Rot_Up)
                {
                    controlData.Data_Values[controlData.XO_Band].Atten += Gain_Step * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.XO_Band].Atten > Gain_Atten_Max)
                        controlData.Data_Values[controlData.XO_Band].Atten = Gain_Atten_Max;
                    /* This function displays the save screen  */
       				Update_Atten_Set(controlData.Atten_Set);
                    CONTROL_XO_Gain();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    controlData.Data_Values[controlData.XO_Band].Atten -= Gain_Step * controlData.UI_Speed;
                    if (controlData.Data_Values[controlData.XO_Band].Atten < Gain_Atten_Min)
                        controlData.Data_Values[controlData.XO_Band].Atten = Gain_Atten_Min;
                    /* This function displays the save screen  */
       				Update_Atten_Set(controlData.Atten_Set);
                    CONTROL_XO_Gain();
                }
                else if (Keypress_Read == Sel)
                {
                    /* This function displays the save logo and writes the data to EEPROM */
                    /* put update FL in here */
                    CONTROL_XO_Invert();
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_INVERT;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;

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

                if (Keypress_Read == Rot_Up)
                {
                    if (controlData.Data_Values[controlData.XO_Band].Invert == Invert_True)
                        controlData.Data_Values[controlData.XO_Band].Invert = Invert_False;
                    else 
                        controlData.Data_Values[controlData.XO_Band].Invert = Invert_True;

                    /* I really need to roll invert intot he controlData variable*/
                    if(controlData.XO_Band == Min_XO_Band )  /*yes - need to roll into controlData */
                    {
                        /* set up invert variables */
                        if (controlData.Data_Values[controlData.XO_Band].Invert == Invert_True)
                            CH1_Invert = -1;
                        else
                            CH1_Invert = 1;                  
                    }
                    else if (controlData.XO_Band == (Min_XO_Band +1))  /*yes - need to roll into controlData */
                    {
                        /* set up invert variables */
                        if (controlData.Data_Values[controlData.XO_Band].Invert == Invert_True)
                            CH2_Invert = -1;
                        else
                            CH2_Invert = 1;                  
                    }
                    /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_Invert();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    if (controlData.Data_Values[controlData.XO_Band].Invert == Invert_True)
                        controlData.Data_Values[controlData.XO_Band].Invert = Invert_False;
                    else 
                        controlData.Data_Values[controlData.XO_Band].Invert = Invert_True;

                    /* I really need to roll invert intot he controlData variable*/
                    if(controlData.XO_Band == Min_XO_Band )  /*yes - need to roll into controlData */
                    {
                        /* set up invert variables */
                        if (controlData.Data_Values[controlData.XO_Band].Invert == Invert_True)
                            CH1_Invert = -1;
                        else
                            CH1_Invert = 1;                  
                    }
                    else if (controlData.XO_Band == (Min_XO_Band +1))  /*yes - need to roll into controlData */
                    {
                        /* set up invert variables */
                        if (controlData.Data_Values[controlData.XO_Band].Invert == Invert_True)
                            CH2_Invert = -1;
                        else
                            CH2_Invert = 1;                  
                    }
                    /* Update Filters for Crossover mode */
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                   CONTROL_XO_Invert();
                }
                else if (Keypress_Read == Sel)
                {
                    if (controlData.XO_Band == Min_XO_Band)
                    {
                        CONTROL_XO_Bridge();
                        controlData.state = CONTROL_STATE_BRIDGE;
                    }
                    else
                    {
                        /* Increment the band, or roll around if MAX */
                        if (controlData.XO_Band < Max_XO_Band)
                            controlData.XO_Band++;
                        else
                            controlData.XO_Band = Min_XO_Band;
                        /* Then continue */
                        CONTROL_XO_LO_Freq();
                        /* GO BACK TO IDLE STATE */        
                        controlData.state = CONTROL_STATE_LO_FREQ;
                    }
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
        
        case CONTROL_STATE_BRIDGE:
        {
            if(controlData.UI_Keypressed)
            {
                /* reset the countdown timer */
                controlData.Revert_To_Idle_Counter = Revert_To_Idle;

                if (Keypress_Read == Rot_Up)
                {
                    if (controlData.Data_Values[controlData.XO_Band].Bridge == Bridge_True)
                        controlData.Data_Values[controlData.XO_Band].Bridge = Bridge_False;
                    else 
                        controlData.Data_Values[controlData.XO_Band].Bridge = Bridge_True;

                    /* I really need to roll invert into the controlData variable*/
                    if(controlData.XO_Band == Min_XO_Band )  /*yes - need to roll into controlData */
                    {
                        /* set up invert variables */
                        if (controlData.Data_Values[controlData.XO_Band].Bridge == Bridge_True)
                            CH1_L_Bridge = 1;
                        else
                            CH1_L_Bridge = 0;                  
                    }
                    /* Update Filters for Crossover mode - This is really nugatory as we have not changed them*/
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                    CONTROL_XO_Bridge();
                }
                else if  (Keypress_Read == Rot_Down)
                {
                    if (controlData.Data_Values[controlData.XO_Band].Bridge == Bridge_True)
                        controlData.Data_Values[controlData.XO_Band].Bridge = Bridge_False;
                    else 
                        controlData.Data_Values[controlData.XO_Band].Bridge = Bridge_True;

                    /* I really need to roll invert intot he controlData variable*/
                    if(controlData.XO_Band == Min_XO_Band )  /*yes - need to roll into controlData */
                    {
                        /* set up invert variables */
                        if (controlData.Data_Values[controlData.XO_Band].Bridge == Bridge_True)
                            CH1_L_Bridge = 1;
                        else
                            CH1_L_Bridge = 0;                  
                    }
                    /* Update Filters for Crossover mode - again nugatory*/
                    Filter_Parm_Update(Ch_1_Mode);
                    Filter_Parm_Update(Ch_2_Mode);
                   CONTROL_XO_Bridge();
                }
                else if (Keypress_Read == Sel)
                {
                    /* Increment the band, or roll around if MAX */
                    if (controlData.XO_Band < Max_XO_Band)
                        controlData.XO_Band++;
                    else
                        controlData.XO_Band = Min_XO_Band;
                    /* Then continue */
                    CONTROL_XO_LO_Freq();
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_LO_FREQ;
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
        
        case CONTROL_STATE_CHOOSING:
        {
            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)
                {
                    if (controlData.UI_Action == CONTROL_ACTION_SAVE)
                        controlData.UI_Action = CONTROL_ACTION_XO;
                    else if (controlData.UI_Action == CONTROL_ACTION_LOAD)
                        controlData.UI_Action = CONTROL_ACTION_SAVE;
                    else if (controlData.UI_Action == CONTROL_ACTION_XO)
                        controlData.UI_Action = CONTROL_ACTION_EQ;
                    else if (controlData.UI_Action == CONTROL_ACTION_EQ)
                        controlData.UI_Action = CONTROL_ACTION_LOAD;
                    /* This function displays the choose function screen  */
                    CONTROL_Choose_Function();
                }
                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_EQ)
                        controlData.UI_Action = CONTROL_ACTION_XO;
                    else if (controlData.UI_Action == CONTROL_ACTION_XO)
                        controlData.UI_Action = CONTROL_ACTION_SAVE;
                    else if (controlData.UI_Action == CONTROL_ACTION_LOAD)
                        controlData.UI_Action = CONTROL_ACTION_EQ;
                    /* This function displays the choose function screen  */
                    CONTROL_Choose_Function();
                }
                else if (Keypress_Read == Sel)
                {
                    if (controlData.UI_Action == CONTROL_ACTION_SAVE)
                    {
                        controlData.state = CONTROL_STATE_SAVE;
                        Save_Screen();
                    }
                    else if (controlData.UI_Action == CONTROL_ACTION_EQ)
                    {
                        controlData.UI_Action = CONTROL_ACTION_EQ_BAND;
                        CONTROL_EQ_Band();
                        controlData.state = CONTROL_STATE_EQ_BAND;
                    }
                    else if (controlData.UI_Action == CONTROL_ACTION_XO)
                    {
                        controlData.UI_Action = CONTROL_ACTION_XO_BAND;
                        CONTROL_XO_Band();
                        controlData.state = CONTROL_STATE_XO_BAND;
                    }
                    else if (controlData.UI_Action == CONTROL_ACTION_LOAD)
                    {
                        /* start with no */
                        controlData.state = CONTROL_STATE_LOAD;
                        Load_Screen();
                    }
                    /* This function displays the choose function screen  */
                }
                else if (Keypress_Read == Exit)
                {
                    /* GO BACK TO IDLE STATE */        
                    controlData.state = CONTROL_STATE_IDLE;
                    Idle_Screen();
                }
                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 IDLE STATE */        
                controlData.state = CONTROL_STATE_IDLE;
                Idle_Screen();
            }
        }
        break;
        
        case CONTROL_STATE_SERVICE_TASKS:
        {
        
        }
        break;


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

 

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