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

 Digital Preamp State Machine and Control
 *
  Company:
    TGM.

  File Name:
    Digital_Preamp.c

  Summary:
    This file contains the core preamp functionality and state machine
 *
 * V0.2     - LCD working.
 *          - Main UI functioning menus channel and EQ
 *          - EEPROM load and save works
 * V0.4     - DSP clock and I/O to ADC and DACS running
 *          - Loading code - is going from PIC to ADAU
 *          - ISSUES:  No data out from ADAU (minor one!)
 * V0.4     - gets through boot and reset ADAU toggle SS
 *          - Check input switching:   
 *                  Input_Sel_MCH_SPDIF_ADC --> OK data
 *                  check writes to right memory:
 *          - Check DC block:
 *                  DCB1 OK data
 *                  DCB2 OK data
 *          - Check monitor Select switching
 *                  Monitor_Sel_SPDIF_ADC  
 *          - Check monitor output:
 *          - Check Comm :
 *                  COMM_FILT0
 *                  COMM_FILT1
 *                  COMM_FILT2
 *          - Check XO train
 *                  B0_HPF0
 *                  B0_HPF1
 *                  B0_HPF2
 *                  B0_HPF2
 *                  B0_LPF0
 *                  B0_LPF1
 *                  B0_LPF2
 *                  B0_LPF3
 *                  B0_GEN0
 *                  B0_GEN1
 *                  B0_GEN2
 *           - Check Volume  
 *                  B0_VOL
 *           - Check Delay      
 *                  BO_DEL
 *           - Check Invert
 *                  B0_Inv_0
 *           - Checkk MONO ADD       
 *                  Add1
 *                  Bridge_Sw
 *           Check outputs!
 * 10 Mer 2025
 * -    Filters working
 * -    Minidsp input and output working
 * -    All channels working
 * -    Start final polish and removal of debug
 * 
 * 20 Apr 2025
 * - Reduced time between word writes to ADAU to 3uS (could still be faster I supppose)
 * - Tweak volume control speed
 * - final
 *            
 * 26 Apr 2025
 * - actually put code in to make mute work (oops)
 * - Extra delay on input switching
 * 
 * 15 Jan 2026
 * - update rev number - no other change
 * 
 *******************************************************************************/

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

#include <stddef.h>                     // Defines NULL
#include <stdbool.h>                    // Defines true
#include <stdlib.h>                     // Defines EXIT_FAILURE
#include "definitions.h"                // SYS function prototypes
#include "Digital_Preamp.h"
#include "LCD_lib_busy.h"
#include "LCD_config.h"
#include <xc.h>
#include <sys/attribs.h>
#include "interrupts.h"
#include "definitions.h"
#include "EEPROM.h"
#include "ADAU_DRV.h"
//#include "Digital_Preamp_IC_1.h"
#include "Digital_Preamp_IC_1_PARAM.h"
//#include "Digital_Preamp_IC_1_REG.h"
//#include "Digital_Preamp_Parm_Map.h"

/* This is where all the data is stored... */
Digital_Preamp_DATA PreampData;
data_val_struct *Data_Values_Pointer, *Temp_Data_Values_Pointer;
Para_EQ_struct *EQ_Values_Pointer, *Temp_EQ_Values_Pointer;

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

int loop, test_temp;
/* location at which input data is written into a cyclical buffer */
unsigned int Write_Pointer_Offset, Ch1_Rd_Offset, Ch2_Rd_Offset;
/* used for output clipping to 24 bits */
int Out_Test_Temp, Bit_Count;
void UI_InterruptHandler(uint32_t, uintptr_t);
void IR_InterruptHandler(uint32_t, uintptr_t);


/************************************************************/
/*       LCD Init                                           */
/************************************************************/
void LCD_Boot(void)
{
    LCD_Start();
    LCD_Clear_Line1();
    LCD_Clear_Line2();
    LCD_TextOut(0,0,(unsigned char *)"TGM Says: V1.2  ");   // could be optimized
    LCD_TextOut(1,0,(unsigned char *)"LCD Booted OK   ");   // could be optimized
    CORETIMER_DelayMs(Splash_Time_ms);
}

/*  Splash Screen */
void LCD_Splash_Screen(void)
{
    LCD_TextOut(1,0,Splash_String_1);
    LCD_TextOut(0,0,Splash_String_0);
    CORETIMER_DelayMs(Splash_Time_ms);                  // keep Splash screen 1s
    PreampData.UI_Update_Display = 1;  // flag display for update
}



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

    /* if fast counter is expired, then go max speed*/
    if (PreampData.UI_Fast_Count == 0)
        PreampData.UI_Speed = Fast;
    else
        PreampData.UI_Speed = Slow;
    /* reset slow counter to init value */
    PreampData.UI_Slow_Count = Slow_Counter_Init;
}


/******************************************************************************/
/*                             User Interface ISR                             */
/******************************************************************************/
void IR_InterruptHandler(uint32_t intCause, uintptr_t context)
{
    int Timer1_IntState = 0;

    /* Stop things being interrupted as the IR RX will be slower than 1ms*/
    GPIO_PinInterruptDisable(GPIO_PIN_RC7);
    /* check if timer Interrupt enabled, remember and disable it */
    Timer1_IntState = EVIC_SourceIsEnabled(INT_SOURCE_TIMER_1);
    if (Timer1_IntState)
        TMR1_InterruptDisable();

    /************************************************/
    // To decode IR..
    // Watch IR input
    //
    //State Machine:
    //
    // State 1: Input low (1 received)
    //  if goes high after a short time then the next character is a 1.  Wait until it goes low then back to state 1.
    //  else if the output stays low after a short time but goes high after a long time, then the next character is a 0, go to state 0
    //
    // State 0: Input high (0 received)
    //  if the output stays high after a short time, but goes low after a long time,  then the next character is a 1, Wait until it goes low then back to state 1.
    //  else if the output goes  low after a short time then the next character is a 0, wait until it goes high then go to state 0
    //
    //  event	ideal	min	max
    //  short pulse	889?s	444?s	1333?s
    //  short space	889?s	444?s	1333?s
    //  long pulse	1778?s	1334?s	2222?s
    //  long space	1778?s	1334?s	2222?s
    // #define RC5_Short_Short 600
    // #define RC5_Short_Long 1333
    // #define RC5_Long_Short 1334
    // #define RC5_Long_Long  2222
    /************************************************/
    PreampData.Time_Out = 0;  /* clear timeout */
    PreampData.Timer_Time = CORETIMER_CounterGet();     /* current time */
    PreampData.Timer_Temp = PreampData.Timer_Time;      /* remember this time */

    /* note that at the start we miss the first "low" part */
    Bit_Count = 1;                  /* bit counter for reading word */
    PreampData.IR_RX = 1;           /* always starts with a 1 */
    PreampData.IR_State = Out_1;    /* always starts with a 1 */

    do
    {
        PreampData.Timer_Time = CORETIMER_CounterGet();     /* get time for loop */
        PreampData.Interval = (PreampData.Timer_Time - PreampData.Timer_Temp)/CoreTimer_To_Us;
        switch (PreampData.IR_State )
        {
            // Measure the time until the IR stops.
            // if this is too short, then this is noise ? end.
            // if the time is ?short? then we have just received another ?1? ?
            //     Output this and go to Mid_out_1 and wait until IR comes back.
            // if the time is ?long? then we are receiving a ?0? ?
            //     Output this and go to State Mid_Out_0.
            // if the time is ?longer than long? then this is noise - end
            case Out_1:   //0x10
            {
                if((!IR_IN) && (PreampData.Interval <= RC5_Short_Short))
                {
                    PreampData.Time_Out = 1;
                } /* been too fast */
                else if ((!IR_IN) && (PreampData.Interval <= RC5_Short_Long))
                {
                    PreampData.IR_State = Mid_Out_1;                /* next character is a 1 but need to wait until it returns low*/
                    PreampData.Timer_Temp = PreampData.Timer_Time;  /* reset timer marker */
                    PreampData.IR_RX = 1 + (PreampData.IR_RX<<1);   /* shift one place and add 1 */
                    Bit_Count++;  /* increment bits read */
                }
                else if ((!IR_IN) && (PreampData.Interval <= RC5_Long_Long))
                {
                    // OK we received a 1 and also saw a 0 come in
                    PreampData.IR_State = Out_0;                    /* next character is a 0*/
                    PreampData.Timer_Temp = PreampData.Timer_Time;  /* reset timer marker */
                    PreampData.IR_RX =  PreampData.IR_RX<<1;        /* shift one place and add 0 */
                    Bit_Count++;  /* increment bits read */
                }
                else if (PreampData.Interval >= RC5_Long_Long)
                {
                    PreampData.Time_Out = 1;
                } /* been waiting too long */
                else /* we will never be here */
                {
                };
            }
            break;
                // Measure time until we we IR again
                // If we see it too soon, this is noise ? end
                // If the time was ?short? OK, - go back to State 1.
                // If the time was more than ?short? then this is noise ? end.
            case Mid_Out_1:  //0x20
            {
                if((IR_IN) && (PreampData.Interval <= RC5_Short_Short))
                {
                    PreampData.Time_Out = 1;
                } /* too short */
                else if ((IR_IN) && (PreampData.Interval <= RC5_Short_Long))
                {
                    PreampData.Timer_Temp = PreampData.Timer_Time;      /* reset timer marker */
                    PreampData.IR_State = Out_1;                        /* next character is a 1 */
                } /* this is what we have been looking for*/
                else if (PreampData.Interval > RC5_Short_Long)
                {
                    PreampData.Time_Out = 1;
                }; /* too long is bad */
            }
            break;
            // Wait until the IR starts again.
            // If we see no IR for too short a rime, then this is noise ? end.
            // if we see no IR for ?short? time then we have just received another ?0? ? Output this and go to State 3.
            // if we see no IR for a ?long? time then we are receiving a ?1? ? Output this and go to State 1.
            // if there was no IR for ?longer than long? then this is noise - end
            case Out_0:    //0x30
            {
                if((IR_IN) && (PreampData.Interval <= RC5_Short_Short))
                {
                    PreampData.Time_Out = 1;
                } /* been too fast */
                else if ((IR_IN) && (PreampData.Interval <= RC5_Short_Long))
                {
                    PreampData.IR_State = Mid_Out_0;                /* next character is a 0 but need to clear the low*/
                    PreampData.Timer_Temp = PreampData.Timer_Time;  /* reset timer marker */
                    PreampData.IR_RX =  (PreampData.IR_RX<<1);      /* shift one place */
                    Bit_Count++;                                    /* increment bits read */
                }
                else if ((IR_IN) && (PreampData.Interval <= RC5_Long_Long))
                {
                    PreampData.IR_State = Out_1;                    /* next character is a 1*/
                    PreampData.Timer_Temp = PreampData.Timer_Time;  /* reset timer marker */
                    PreampData.IR_RX =  1+ (PreampData.IR_RX<<1);    /* shift one place and add 1 */
                    Bit_Count++;                                    /* increment bits read */
                }
                else if (PreampData.Interval >= RC5_Long_Long)
                {
                    PreampData.Time_Out = 1;
                } /* been waiting too long */
            }
            break;
            // Measure time until we see no IR again
            // If we see no IR too soon, this is noise ? end
            // If we see no IR for a ?short? time OK, - go back to out0.
            // If we see no IR for more than a ?short time? then this is noise ? end.
            case Mid_Out_0:  //0x40
            {
                if((!IR_IN) && (PreampData.Interval <= RC5_Short_Short))
                {
                    PreampData.Time_Out = 1;
                } /* too short */
                else if ((!IR_IN) && (PreampData.Interval <= RC5_Short_Long))
                {
                    PreampData.Timer_Temp = PreampData.Timer_Time;  /* reset timer marker */
                    PreampData.IR_State = Out_0;                    /* next character is a 1 */
                } /* this is what we have been looking for*/
                else if (PreampData.Interval > RC5_Short_Long)
                {
                    PreampData.Time_Out = 1;
                }; /* too long is bad */
            }
            break;
            default:
            {
                PreampData.Time_Out = 1;
            }
        }

    }    while ((!PreampData.Time_Out) && (Bit_Count < RC5_Bits));

    if ((Bit_Count == RC5_Bits) && (!PreampData.Time_Out))
    {
        // I2C_Volume_Word((unsigned char) (Volume_Data.Toggle));
        PreampData.IR_Toggle = (PreampData.IR_RX & 0x800)>>11;
        /* now read the Address Field                           */
        /* this is five bits, which will be found in bits       */
        /* 6-10 of the IR Rx data                               */
        /* need to mask the toggle bit                          */
        PreampData.IR_Address = ((PreampData.IR_RX & 0x7C)>>6);
        /* now read the command Field                           */
        /* this is six bits, which will be found in bits        */
        /* 0-6 of the IR Rx data                                */
        /* need to mask the toggle bit and command              */
        PreampData.IR_Command = ((PreampData.IR_RX & 0x3F));

        if ((PreampData.IR_Address == PreampData.IR_Addr ) &&
                (PreampData.IR_Command == Volume_Down_IR))
        {
            PreampData.UI_Action = UIAction_ROT_Down;
            PreampData.UI_Keypressed = 1;
        }
        else if ((PreampData.IR_Address == PreampData.IR_Addr ) &&
                (PreampData.IR_Command == Volume_Up_IR))
        {
            PreampData.UI_Action = UIAction_ROT_Up;
            PreampData.UI_Keypressed = 1;
        }
        else if ((PreampData.IR_Address == PreampData.IR_Addr ) &&
                (PreampData.IR_Command == Preamp_Up_Input_IR))
        {
            PreampData.UI_Action = UIAction_Input_Up;
            PreampData.UI_Keypressed = 1;
        }
        else if ((PreampData.IR_Address == PreampData.IR_Addr ) &&
                (PreampData.IR_Command == Preamp_Down_Input_IR))
        {
            PreampData.UI_Action = UIAction_Input_Down;
            PreampData.UI_Keypressed = 1;
        }
        else if ((PreampData.IR_Address == PreampData.IR_Addr ) &&
                (PreampData.IR_Command == Volume_Mute_IR))
        {
            {
                PreampData.UI_Action = UIAction_Input_Mute;
                if(PreampData.Output_Mute == 0)
                {
                    PreampData.Output_Mute = 1;
                }
                else
                {
                    PreampData.Output_Mute = 0;
                }
                PreampData.UI_Keypressed = 1;
            }
        }
        else PreampData.UI_Action = No_Action;
        PreampData.IR_Current_Port = IR_IN;
        PreampData.IR_Temp_Port = PreampData.IR_Current_Port;
    }
    Bit_Count = 0;
    /* if we previously disables the interrupt then re-enable it */
    if (Timer1_IntState)
        TMR1_InterruptEnable();
    GPIO_PinInterruptEnable(GPIO_PIN_RC7);
}


/******************************************************************************/
/*                             User Interface ISR                             */
/******************************************************************************/
void UI_InterruptHandler(uint32_t intCause, uintptr_t context)
{
    /* Stop things being interrupted as the IR RX will be slower than 1ms*/
    TMR1_InterruptDisable();
    /* grab the time */
    PreampData.Timer_Time = TMR2_CounterGet();
    /* this is here for debug - to convince me I am visiting the ISR */
//    PreampData.UI_Update_Counter++;
    PreampData.UI_CurrentPortB = PORTB & (PortB_Bits);
    PreampData.UI_CurrentPortC = PORTC & (PortC_Bits);

    /* lets start with the rotary encoder */
    /* The rotary encoder bits are on port B */
    if (PreampData.UI_CurrentPortB != PreampData.UI_TempPortB )
    {
        /* get current ROT state */
        PreampData.ROT_State = PORTB & (ROT_A + ROT_B);
        /* see if it is the rotary Encoder */
        if (PreampData.ROT_State != Phase0)
        {
            /* CW 11 -> 10  - mid click remember */
            /* CCW 11-> 01  - mid click remember */
            if(PreampData.ROT_State_Prev  == Phase0)
            {
                CORETIMER_DelayUs(ROTARY_ENC_SETTLE);   /* let things settle on initial switch */
                PreampData.UI_Action = UIAction_NULL;
            }
            /* CW 11 -> 10 -> 00    i.e. phase 0 to phase 1*/
            else if (PreampData.ROT_State_Prev  == Phase1)
            {
                if(PreampData.ROT_State == Phase2)
                {
                    PreampData.UI_Action = UIAction_ROT_Down;
                    PreampData.UI_Keypressed = 1;
                }
                else
                {
                    PreampData.UI_Action = UIAction_NULL;
                }
            }
            /* CW 11 -> 10 -> 00    i.e. phase 0 to phase 1*/
            else if (PreampData.ROT_State_Prev  == Phase2)
            {
                PreampData.UI_Action = UIAction_NULL;
            }
            /* CCW 11 -> 01-> 00    i.e. phase 0 to phase 3*/
            else if (PreampData.ROT_State_Prev  == Phase3)
            {
                if(PreampData.ROT_State == Phase2)
                {
                    PreampData.UI_Action = UIAction_ROT_Up;
                    PreampData.UI_Keypressed = 1;
                }
                else
                {
                    PreampData.UI_Action = UIAction_NULL;
                }
            }
        }
    }
    /* Now lets check the Exit key*/
    else if (Exit_Key_Pressed)
    {
        PreampData.UI_Action = UIAction_ROT_Exit;
        PreampData.UI_Keypressed = 1;
    }
    /* Now lets check the Enter key */
    else if (Enter_Key_Pressed)
    {
        PreampData.UI_Action = UIAction_ROT_Enter;
        PreampData.UI_Keypressed = 1;
    }
    /* Now lets check the Input Up key */
    else if (Input_Select_Up_Key)
    {
        PreampData.UI_Action = UIAction_Input_Up;
        PreampData.UI_Keypressed = 1;
    }
    /* Now lets check the Input Down key */
    else if (Input_Select_Down_Key)
    {
        PreampData.UI_Action = UIAction_Input_Down;
        PreampData.UI_Keypressed = 1;
    }
    else
    {
//        PreampData.UI_Action = UIAction_NULL;
    }

    PreampData.ROT_State_Prev  = PreampData.ROT_State;
//    PreampData.IR_State_Prev   = Volume_Data.IR_State;
    PreampData.UI_TempPortB = PreampData.UI_CurrentPortB;
    PreampData.UI_TempPortC = PreampData.UI_CurrentPortC;

    TMR1_InterruptEnable();
}


/*******************************************************************************
  Function:
    void REFLOW_Initialize ( void )

  Remarks:
    See prototype in weller.h.
******************************************************************************/
void Preamp_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    PreampData.UI_Fast_Count = Fast_Counter_Init;
    PreampData.UI_Slow_Count = Slow_Counter_Init;
    PreampData.UI_Update_Counter = 0;
    PreampData.UI_Speed = 1;
    PreampData.UI_CurrentPortB = 0;
    PreampData.UI_TempPortB = 0;
    PreampData.UI_CurrentPortC = 0;
    PreampData.UI_TempPortC = 0;
    PreampData.heartbeatToggle = 1;
    PreampData.Revert_To_Idle_Counter = Revert_To_Idle;
    PreampData.Number_Of_Writes = 1;
    PreampData.UI_Update_Display = 0;
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_Volume;
    PreampData.UI_Keypressed = 0;
    PreampData.UI_Keypressed_Enter = 0;
    PreampData.UI_Keypressed_Select = 0;
    PreampData.UI_Input_Select_Up = 0;
    PreampData.UI_Input_Select_Down = 0;
    PreampData.UI_Action = UIAction_NULL;
    PreampData.Settings = Digital_Preamp_SAVE;
    PreampData.Atten_Set = Atten_Default;
    PreampData.Input_Sel = Input_Tuner;
    PreampData.Monitor_Sel = Input_Tuner;
    PreampData.Channel_Selected = 0;       /* Start with Channel 0 (1) */
    PreampData.Channel_Parm_Selected = Sel_Sl;  /* Start lower Slope */
    PreampData.EQ_Selected = 0;            /* Start with this at zero */
    PreampData.EQ_Parm_Selected = Sel_Type; /* Start with type */
    PreampData.Timer_Time = 0;             /* just as a matter of course */
    PreampData.Timer_Temp = 0;             /* just as a matter of course */
    PreampData.Time_Out = 0 ;              /* just as a matter of course */
    PreampData.ROT_State = Phase0;         /* initialise for rotary encoder */
    PreampData.ROT_State_Prev = Phase0;    /* initialise for rotary encoder */
    PreampData.IR_State = Out_1;           /* initialise used for IR RX */
    PreampData.IR_RX = 0;                  /* initialise for rotary encoder */
    PreampData.IR_Addr = Volume_Address_IR;/* IR RX address  - usually TV or RCVR */
    PreampData.IR_Current_Port = 0;        /* Initialise this */
    PreampData.IR_Temp_Port = 0;           /* Initialise this */
    PreampData.IR_Command = 0;             /* Initialise this */
    PreampData.Output_Mute = 0;            /* Initialise this to not muted*/
    PreampData.Interval = RC5_Short_Long;  /* just inintialise this */
    PreampData.Time_Out = 0;               /* initialise me */
    PreampData.TEMP_DATA = 0;              /* init scratch */
    PreampData.MemoryBankSelected = Default_Mem_Bank; /* initialise me */

//    EEPROM_Disable_Hold;
}


/****************************************************************************/
/* Lets save relevant data to EEPROM                                      	*/
/****************************************************************************/
void Save_Data_To_Memory()
{
    /* Attenuation */
    HDWordWriteSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Volume_Offset), PreampData.Atten_Set);
    /* Input */
    HDWordWriteSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Input_Selected_Offset), PreampData.Input_Sel);
    /* Monitor selection */
    HDWordWriteSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Monitor_Offset), PreampData.Monitor_Sel);

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

    /* Write parameters for crossover points to EEPROM */
    for (loop=Min_EQ_Band; loop <= Max_EQ_Band; loop++)
    {
        EQ_Values_Pointer = &(PreampData.EQ_Values[loop]);
        HDWordWriteSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size)+ Para_Gen_Base + loop*Para_Set_Size +  Para_CF_Offset), (EQ_Values_Pointer->CF));
        HDWordWriteSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size +  Para_Q_Offset), (EQ_Values_Pointer->Q));
        HDWordWriteSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size +   Para_Gain_Offset), (EQ_Values_Pointer->Gain));
        HDWordWriteSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size +   Para_Type_Offset), (EQ_Values_Pointer->Type));
        HDWordWriteSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size +   Para_HF_Offset), (EQ_Values_Pointer->HF_Gain));
    }
}

    /* need to make sure that monitor is displayed appropriately */
    /* this can get funky f the user changes the input           */
    /*                                                           */
    /* if PreampData.Monitor_Sel == Input_SPDIF_Coax
     *                                 then it cannot be TOSLINK */
    /* if PreampData.Monitor_Sel == Input_SPDIF_TOSLINK
     *                                 then it cannot be Coax */
    /* if PreampData.Monitor_Sel == any of the analogue ins
     *                                 then it cannot be any other*/
void handle_Change_InputSel()
{
    if((PreampData.Input_Sel == Input_SPDIF_Coax) && (PreampData.Monitor_Sel == Input_SPDIF_TOSLINK))
        PreampData.Monitor_Sel = Input_SPDIF_Coax;
    else if((PreampData.Input_Sel == Input_SPDIF_TOSLINK) && (PreampData.Monitor_Sel == Input_SPDIF_Coax))
        PreampData.Monitor_Sel = Input_SPDIF_TOSLINK;
    else if((PreampData.Input_Sel == Input_AUX1) && ((PreampData.Monitor_Sel == Input_AUX2) ||
        (PreampData.Monitor_Sel == Input_Tuner) || (PreampData.Monitor_Sel == Input_Bluetooth)))
        PreampData.Monitor_Sel = Input_AUX1;
    else if((PreampData.Input_Sel == Input_AUX2) && ((PreampData.Monitor_Sel == Input_AUX1) ||
        (PreampData.Monitor_Sel == Input_Tuner) || (PreampData.Monitor_Sel == Input_Bluetooth)))
        PreampData.Monitor_Sel = Input_AUX2;
    else if((PreampData.Input_Sel == Input_Tuner) && ((PreampData.Monitor_Sel == Input_AUX1) ||
        (PreampData.Monitor_Sel == Input_AUX2) || (PreampData.Monitor_Sel == Input_Bluetooth)))
        PreampData.Monitor_Sel = Input_Tuner;
    else if((PreampData.Input_Sel == Input_Bluetooth) && ((PreampData.Monitor_Sel == Input_AUX1) ||
        (PreampData.Monitor_Sel == Input_AUX2) || (PreampData.Monitor_Sel == Input_Tuner)))
        PreampData.Monitor_Sel = Input_Bluetooth;

}


/****************************************************************************/
/* Enter_From _Idle saves data                                             	*/
/****************************************************************************/
void Handle_Enter_From_Idle()
{
    char Temp_String[20], Temp_String2[20];

    Save_Data_To_Memory();   // do the save
    sprintf(Temp_String,"Saving To Bank %d", (PreampData.MemoryBankSelected +1));
    if (PreampData.Output_Mute == 0)
        sprintf(Temp_String2,"Atten %5.1f dB  ",((float)PreampData.Atten_Set /2));
    else
        sprintf(Temp_String2,"Output Muted    ");
    LCD_TextOut(1,0,(unsigned char *)Temp_String2);
    LCD_TextOut(0,0,(unsigned char *)Temp_String);
    while (Enter_Key_Pressed)    //wait for use to take finger off enter
        CORETIMER_DelayMs(UI_Delay_Ms_General);
    CORETIMER_DelayMs(UI_Delay_Ms_Mute_Time);    // make sure the message is on the screen for a decent time
    PreampData.UI_Update_Display = 1;  // Set flag for display update
}


/****************************************************************************/
/* 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(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Volume_Offset), &PreampData.Atten_Set, 1 );
    if (PreampData.Atten_Set > Atten_Max)
        PreampData.Atten_Set = Atten_Default;
    else if (PreampData.Atten_Set < Atten_Min)
        PreampData.Atten_Set = Atten_Default;

    /* Read in stored Temp Offset for input selection */
    HDWordReadSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Input_Selected_Offset), &PreampData.Input_Sel, 4 );
    if (PreampData.Input_Sel > Input_Bluetooth)
        PreampData.Input_Sel = Input_Tuner;
    else if (PreampData.Input_Sel < Input_MiniDSP)
        PreampData.Input_Sel = Input_Tuner;

    /* Read in stored Temp Offset for input selection */
    HDWordReadSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Monitor_Offset), &PreampData.Monitor_Sel, 4 );
    if (PreampData.Monitor_Sel > Input_Bluetooth)
        PreampData.Monitor_Sel = Input_Tuner;
    else if (PreampData.Monitor_Sel < Input_SPDIF_Coax)
        PreampData.Monitor_Sel = Input_Tuner;


/* 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 = &(PreampData.Data_Values[loop]);
    HDWordReadSPI((PreampData.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((PreampData.MemoryBankSelected*ParmSet_Array_Size + loop*Channel_Set_Array_Size + Fu_Offset),       &(Data_Values_Pointer->Fu), 4 );
    if (Data_Values_Pointer->Fl < Fu_Min)
        Data_Values_Pointer->Fl = Fu_Min;
    else if (Data_Values_Pointer->Fl > Fu_Max)
        Data_Values_Pointer->Fl = Fu_Max;
    HDWordReadSPI((PreampData.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((PreampData.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((PreampData.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((PreampData.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((PreampData.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((PreampData.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 = &(PreampData.EQ_Values[loop]);
    HDWordReadSPI(((PreampData.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(((PreampData.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(((PreampData.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(((PreampData.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_NONE)
            EQ_Values_Pointer->Type = EQ_TYPE_NONE;
        else if (EQ_Values_Pointer->Type > EQ_TYPE_PARA)
            EQ_Values_Pointer->Type =  EQ_TYPE_NONE;
    HDWordReadSPI(((PreampData.MemoryBankSelected*ParmSet_Array_Size) + Para_Gen_Base + loop*Para_Set_Size +   Para_HF_Offset), (int*) &(EQ_Values_Pointer->HF_Gain), 4 );
        if (EQ_Values_Pointer->HF_Gain < EQ_Gain_Min)
            EQ_Values_Pointer->HF_Gain = EQ_Gain_Min;
        else if (EQ_Values_Pointer->HF_Gain > EQ_Gain_Max)
            EQ_Values_Pointer->HF_Gain =  EQ_Gain_Max;
    }
}

/* sets input switches to required values   */
/*                                          */
/* Call this to set relays                  */
/* Reads PreampData.Input_Sel and           */
/*       PreampData.Monitor_Sel             */
//Switching for Input_Sel
// Input_Null - default to Tuner In, Input_4_Sel = 0, Input_3_Sel = 0, Input_2_Sel = 1, Input_1_Sel = 0 
// Input_MiniDSP - Copy Monitor on Analogue and SPDIF
// Input_SPDIF_Coax - Copy Monitor on Analogue, TOSLINK_Sel = 1
// Input_SPDIF_TOSLINK - Copy Monitor on Analogue, TOSLINK_Sel = 0
// Input_AUX2,Input_4_Sel = 1, Input_3_Sel = 0, Input_2_Sel = 0, Input_1_Sel = 0
// Input_AUX1,Input_4_Sel = 0, Input_3_Sel = 1, Input_2_Sel = 0, Input_1_Sel = 0
// Input_Tuner, Input_4_Sel = 0, Input_3_Sel = 0, Input_2_Sel = 1, Input_1_Sel = 0
// Input_Bluetooth, Input_4_Sel = 0, Input_3_Sel = 0, Input_2_Sel = 0, Input_1_Sel = 1

//Switching for Monitor_Sel
// Input_SPDIF_Coax - Copy Monitor on Analogue, TOSLINK_Sel = 1
// Input_SPDIF_TOSLINK - Copy Monitor on Analogue, TOSLINK_Sel = 0
// Input_AUX2,Input_4_Sel = 1, Input_3_Sel = 0, Input_2_Sel = 0, Input_1_Sel = 0
// Input_AUX1,Input_4_Sel = 0, Input_3_Sel = 1, Input_2_Sel = 0, Input_1_Sel = 0
// Input_Tuner, Input_4_Sel = 0, Input_3_Sel = 0, Input_2_Sel = 1, Input_1_Sel = 0
// Input_Bluetooth, Input_4_Sel = 0, Input_3_Sel = 0, Input_2_Sel = 0, Input_1_Sel = 1
void Set_Input_Switching()
{
    int Data_RX[4];
    
    // switch everything off
    Clear_Analog_SW;
    
    if (PreampData.Input_Sel == Input_Null) {
        Tuner_Sel_Switch;
        ADAU_Select_ADC_In;
    }
    else if (PreampData.Input_Sel == Input_MiniDSP) {
        Clear_Analog_SW;
        ADAU_Select_MCH_In;
    }
    else if (PreampData.Input_Sel == Input_SPDIF_Coax) {
        Clear_Analog_SW;
        TOSLINK_SEL_Set();
        ADAU_Select_SPDIF_In;
    }
    else if (PreampData.Input_Sel == Input_SPDIF_TOSLINK) {
        Clear_Analog_SW;
        TOSLINK_SEL_Clear();
        ADAU_Select_SPDIF_In;
    }
    else if (PreampData.Input_Sel == Input_AUX2) {
        Aux2_Sel_Switch;
        ADAU_Select_ADC_In;
    }
    else if (PreampData.Input_Sel == Input_AUX1) {
        Aux1_Sel_Switch;
        ADAU_Select_ADC_In;
    }
    else if (PreampData.Input_Sel == Input_Tuner) {
        Tuner_Sel_Switch;
        ADAU_Select_ADC_In;
    }
    else if (PreampData.Input_Sel == Input_Bluetooth) {
        Bluetooth_Sel_Switch;
        ADAU_Select_ADC_In;
    }
    else;    

    /* now the monitor */
    if (PreampData.Monitor_Sel == Input_Null) {
        ADAU_MON_Select_ADC_In;
    }
    else if (PreampData.Monitor_Sel == Input_MiniDSP) {
        ADAU_MON_Select_SPDIF_In;
        /* Need to add in ADAU command to select SDATA_1 input */
    }
    else if (PreampData.Monitor_Sel == Input_SPDIF_Coax) {
        ADAU_MON_Select_SPDIF_In;
    }
    else if (PreampData.Monitor_Sel == Input_AUX2) {
        if ((PreampData.Input_Sel == Input_MiniDSP) || 
            (PreampData.Input_Sel == Input_SPDIF_Coax)||
            (PreampData.Input_Sel == Input_SPDIF_TOSLINK)) {
        Aux2_Sel_Switch;
        ADAU_MON_Select_ADC_In;
        if (PreampData.Input_Sel == Input_SPDIF_Coax) {
            TOSLINK_SEL_Set(); }
        else if (PreampData.Input_Sel == Input_SPDIF_TOSLINK) {
            TOSLINK_SEL_Clear();}
        }
        else;
    }
    /* Need to add in MINIDSP command to select SDATA input 0 */
    else if (PreampData.Monitor_Sel == Input_AUX1) {
        if ((PreampData.Input_Sel == Input_MiniDSP) || 
            (PreampData.Input_Sel == Input_SPDIF_Coax)||
            (PreampData.Input_Sel == Input_SPDIF_TOSLINK)) {
        Aux1_Sel_Switch;
        ADAU_MON_Select_ADC_In;
        if (PreampData.Input_Sel == Input_SPDIF_Coax) {
            TOSLINK_SEL_Set(); }
        else if (PreampData.Input_Sel == Input_SPDIF_TOSLINK) {
            TOSLINK_SEL_Clear();}
        }
        else;
        /* Need to add in MINIDSP command to select SDATA input 0 */
    }
    else if (PreampData.Monitor_Sel == Input_Tuner) {
        if ((PreampData.Input_Sel == Input_MiniDSP) || 
            (PreampData.Input_Sel == Input_SPDIF_Coax)||
            (PreampData.Input_Sel == Input_SPDIF_TOSLINK)) {
        Tuner_Sel_Switch;
        ADAU_MON_Select_ADC_In;
        if (PreampData.Input_Sel == Input_SPDIF_Coax) {
            TOSLINK_SEL_Set(); }
        else if (PreampData.Input_Sel == Input_SPDIF_TOSLINK) {
            TOSLINK_SEL_Clear();}
        }
        else;
        /* Need to add in MINIDSP command to select SDATA input 0 */
    }
    else if (PreampData.Monitor_Sel == Input_Bluetooth) {
        if ((PreampData.Input_Sel == Input_MiniDSP) || 
            (PreampData.Input_Sel == Input_SPDIF_Coax)||
            (PreampData.Input_Sel == Input_SPDIF_TOSLINK)) {
        Bluetooth_Sel_Switch;
        ADAU_MON_Select_ADC_In;
        if (PreampData.Input_Sel == Input_SPDIF_Coax) {
            TOSLINK_SEL_Set(); }
        else if (PreampData.Input_Sel == Input_SPDIF_TOSLINK) {
            TOSLINK_SEL_Clear();}
        }
        else;
        /* Need to add in MINIDSP command to select SDATA input 0 */
    }
    else;    
}


void handleState_INIT() {
//    char Temp_String[20],Temp_String2[20] ;
    /* Put ADAU and Digital Stuff in RESET */
    RESET_DSP_Subsys;
    ADC_RESET_Clear();

    // Heartbeat ISR Timer - add later phil
    // User Interface ISR Timer
    /* get user interface ISR timer running*/
    TMR1_Initialize();
    TMR1_CallbackRegister( UI_InterruptHandler, 0 );
    TMR1_InterruptEnable();
    TMR1_Start();
    /* set up Timer 2*/
    TMR2_Initialize();
    TMR2_Start();
    /* initialise data array and check */
    Preamp_Initialize ();
    /* go to LCD Init */
    PreampData.state = Digital_Preamp_STATE_LCDINIT;
    /* SPI2 is the EEPROM */
    SPI2_Initialize ();
    /* SPI1 is the ADAU1467 */
    SPI1_Initialize ();
    // callback for C7 change
    GPIO_PinInterruptCallbackRegister(GPIO_PIN_RC7, IR_InterruptHandler, 0);
    GPIO_PinInterruptEnable(GPIO_PIN_RC7);
    /* initialise the EEPROM */
    EEPROM_Init();   
    Load_From_Memory(PreampData.MemoryBankSelected);

    Set_Input_Switching();
    Init_DSP();
    
    /* now the dsp is running start the adc and dacs*/
    CORETIMER_DelayMs(30);										/* then wait 30ms */ 
    ADC_RESET_Clear();
    CORETIMER_DelayMs(30);										/* then wait 30ms */ 
    ADC_RESET_Set();

  // Now update DSP with loaded parameters
   Update_Delay_Set(ADAU_SR);
   Write_Mono_Sub(PreampData.Data_Values[PreampData.Channel_Selected].Bridge);
   Update_Atten_Set();
   Update_Invert_Set();
   Update_Filter_Set(ADAU_SR);
   Set_Input_Switching();
}


/******************************************************************************/
/*  Puts IDLE stuff on the screen                                             */
/******************************************************************************/
void Idle_Screen()
{
    char Temp_String[20],Temp_String2[20] ;

    switch (PreampData.Input_Sel)  {
        case Input_MiniDSP:
            sprintf(Temp_String,"Input: MiniDSP  ");  break;
        case Input_SPDIF_Coax:
            sprintf(Temp_String,"Input: Coax     ");  break;
        case Input_SPDIF_TOSLINK:
            sprintf(Temp_String,"Input: TOSLINK  ");  break;
        case Input_AUX2:
            sprintf(Temp_String,"Input: Aux 2    ");  break;
        case Input_AUX1:
            sprintf(Temp_String,"Input: Aux 1    ");  break;
        case Input_Tuner:
            sprintf(Temp_String,"Input: Tuner    ");  break;
        case Input_Bluetooth:
            sprintf(Temp_String,"Input: Bluetooth");  break;
        case Input_Null:    
            sprintf(Temp_String,"TGM Says Oops   ");  break;
    }
    if (PreampData.Output_Mute == 0)
        sprintf(Temp_String2,"Atten %5.1f dB  ",((float)PreampData.Atten_Set /2));
    else
        sprintf(Temp_String2,"Output Muted    ");

    LCD_TextOut(1,0,(unsigned char *)Temp_String2);  // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    LCD_TextOut(0,0,(unsigned char *)Temp_String);   // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    Clear_UI_Input;
    PreampData.UI_Update_Display = 0;  // clear flag display for update
}

/******************************************************************************/
/*  Puts Monitor stuff on the screen                                             */
/******************************************************************************/
void Monitor_Screen()
{
    char Temp_String[20],Temp_String2[20] ;
    //check monitor input displayed is consistent with the user input
    handle_Change_InputSel();

    switch (PreampData.Monitor_Sel)  {
        case Input_MiniDSP:
            sprintf(Temp_String,"Monitor: MiniDSP");  break;
        case Input_SPDIF_Coax:
            sprintf(Temp_String,"Monitor: Coax   ");  break;
        case Input_SPDIF_TOSLINK:
            sprintf(Temp_String,"Monitor: TOSLINK");  break;
        case Input_AUX2:
            sprintf(Temp_String,"Monitor: Aux 2  ");  break;
        case Input_AUX1:
            sprintf(Temp_String,"Monitor: Aux 1  ");  break;
        case Input_Tuner:
            sprintf(Temp_String,"Monitor: Tuner  ");  break;
        case Input_Bluetooth:
            sprintf(Temp_String,"Monitor: B'tooth");  break;
        case Input_Null:
            sprintf(Temp_String,"TGM Says Oops   ");  break;    
    }
    switch (PreampData.Input_Sel)  {
        case Input_MiniDSP:
            sprintf(Temp_String2,"Input: MiniDSP  ");  break;
        case Input_SPDIF_Coax:
            sprintf(Temp_String2,"Input: Coax     ");  break;
        case Input_SPDIF_TOSLINK:
            sprintf(Temp_String2,"Input: TOSLINK  ");  break;
        case Input_AUX2:
            sprintf(Temp_String2,"Input: Aux 2    ");  break;
        case Input_AUX1:
            sprintf(Temp_String2,"Input: Aux 1    ");  break;
        case Input_Tuner:
            sprintf(Temp_String2,"Input: Tuner    ");  break;
        case Input_Bluetooth:
            sprintf(Temp_String2,"Input: B'tooth  ");  break;
        case Input_Null:
            sprintf(Temp_String2,"TGM Says oops   ");  break;
    }

    LCD_TextOut(1,0,(unsigned char *)Temp_String);  // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    LCD_TextOut(0,0,(unsigned char *)Temp_String2);   // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    Clear_UI_Input;
    PreampData.UI_Update_Display = 0;  // clear flag display for update
}


/******************************************************************************/
/*  Puts SAVE stuff on the screen                                             */
/******************************************************************************/
void Save_Screen()
{
    char Temp_String[20],Temp_String2[20] ;

    sprintf(Temp_String,"Mem Page To Use ");
    if (PreampData.MemoryBankSelected == 0)
        sprintf(Temp_String2,"Bank: %d (Boot)  ", (PreampData.MemoryBankSelected +1));
    else
        sprintf(Temp_String2,"Bank: %d         ", (PreampData.MemoryBankSelected +1));

    LCD_TextOut(1,0,(unsigned char *)Temp_String2);  // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    LCD_TextOut(0,0,(unsigned char *)Temp_String);   // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    Clear_UI_Input;
    PreampData.UI_Update_Display = 0;  // clear flag display for update
}

/******************************************************************************/
/*  Puts SAVE stuff on the screen                                             */
/******************************************************************************/
void Load_Screen()
{
    char Temp_String[20],Temp_String2[20] ;

    sprintf(Temp_String,"Mem Page To Load");
    if (PreampData.MemoryBankSelected == 0)
        sprintf(Temp_String2,"Bank: %d (Boot)  ", (PreampData.MemoryBankSelected +1));
    else
        sprintf(Temp_String2,"Bank: %d         ", (PreampData.MemoryBankSelected +1));

    LCD_TextOut(1,0,(unsigned char *)Temp_String2);  // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    LCD_TextOut(0,0,(unsigned char *)Temp_String);   // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    Clear_UI_Input;
    PreampData.UI_Update_Display = 0;  // clear flag display for update
}

/******************************************************************************/
/*  Puts Channel to update data on screen                                     */
/******************************************************************************/
void Channel_Screen()
{
    char Temp_String[20],Temp_String2[20] ;

    sprintf(Temp_String, "Band: %d          ", (PreampData.Channel_Selected +1));
    sprintf(Temp_String2,"Setting Change  ");

    LCD_TextOut(1,0,(unsigned char *)Temp_String2);  // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    LCD_TextOut(0,0,(unsigned char *)Temp_String);   // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    Clear_UI_Input;
    PreampData.UI_Update_Display = 0;  // clear flag display for update
}

/******************************************************************************/
/*  actual channel update information on the screen                           */
/******************************************************************************/
void Channel_Update_Screen()
{
    char Temp_String[20],Temp_String2[20] ;

    switch (PreampData.Channel_Parm_Selected) {
        case Sel_Fl: {
            sprintf(Temp_String, "Band %d: Low Freq", (PreampData.Channel_Selected +1));
            sprintf(Temp_String2, "%*d Hz        ",5, (PreampData.Data_Values[PreampData.Channel_Selected].Fl));
            break;
        }
        case Sel_Fu: {
            sprintf(Temp_String, "Band %d: Hi Freq ", (PreampData.Channel_Selected +1));
            sprintf(Temp_String2, "%*d Hz       ",5, (PreampData.Data_Values[PreampData.Channel_Selected].Fu));
            break;
        }
        case Sel_Sl: {
            sprintf(Temp_String, "Band %d: XO Low  ", (PreampData.Channel_Selected +1));
            if      (PreampData.Data_Values[PreampData.Channel_Selected].Sl == NoFilter)
                sprintf(Temp_String2, "No filter       ");
            else if (PreampData.Data_Values[PreampData.Channel_Selected].Sl == SixdB)
                sprintf(Temp_String2, "6dB per octave  ");
            else if (PreampData.Data_Values[PreampData.Channel_Selected].Sl == TwelvedB)
                sprintf(Temp_String2, "12dB per octave ");
            else if (PreampData.Data_Values[PreampData.Channel_Selected].Sl == TwentyFourdB)
                sprintf(Temp_String2, "24dB per octave ");
            else if (PreampData.Data_Values[PreampData.Channel_Selected].Sl == FortyEightdB)
                sprintf(Temp_String2, "48dB per octave ");
            break;
        }
        case Sel_Su: {
            sprintf(Temp_String, "Band %d: XO High ", (PreampData.Channel_Selected +1));
            if      (PreampData.Data_Values[PreampData.Channel_Selected].Su == NoFilter)
                sprintf(Temp_String2, "No filter       ");
            else if (PreampData.Data_Values[PreampData.Channel_Selected].Su == SixdB)
                sprintf(Temp_String2, "6dB per octave  ");
            else if (PreampData.Data_Values[PreampData.Channel_Selected].Su == TwelvedB)
                sprintf(Temp_String2, "12dB per octave ");
            else if (PreampData.Data_Values[PreampData.Channel_Selected].Su == TwentyFourdB)
                sprintf(Temp_String2, "24dB per octave ");
            else if (PreampData.Data_Values[PreampData.Channel_Selected].Su == FortyEightdB)
                sprintf(Temp_String2, "48dB per octave ");
            break;
        }
        case Sel_Atten: {
            sprintf(Temp_String, "Band %d: Atten   ", (PreampData.Channel_Selected +1));
            sprintf(Temp_String2, "%4.1fdB         ", (float)(PreampData.Data_Values[PreampData.Channel_Selected].Atten)/2);
            break;
        }
        case Sel_Delay_mm: {
            sprintf(Temp_String, "Band %d: Delay   ", (PreampData.Channel_Selected +1));
            sprintf(Temp_String2, "%*dmm          ", 4, PreampData.Data_Values[PreampData.Channel_Selected].Delay_mm);
            break;
        }
        case Sel_Invert: {
            sprintf(Temp_String, "Band %d: Output  ", (PreampData.Channel_Selected +1));
            if (PreampData.Data_Values[PreampData.Channel_Selected].Invert == 1)
                sprintf(Temp_String2, "Inverted        ");
            else
                sprintf(Temp_String2, "Normal          ");
            break;
        }
        case Sel_Bridge: {
            sprintf(Temp_String, "Band %d: Bridging", (PreampData.Channel_Selected +1));
            if (PreampData.Data_Values[PreampData.Channel_Selected].Bridge == 1)
                sprintf(Temp_String2, "Mono            ");
            else
                sprintf(Temp_String2, "Stereo          ");
            break;
        }
    }


    LCD_TextOut(1,0,(unsigned char *)Temp_String2);  // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    LCD_TextOut(0,0,(unsigned char *)Temp_String);   // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    Clear_UI_Input;
    PreampData.UI_Update_Display = 0;  // clear flag display for update
}

/******************************************************************************/
/*  Puts STTINGS stuff on the screen                                             */
/******************************************************************************/
void SETTINGS_Screen()
{
    char Temp_String[20],Temp_String2[20] ;

    switch (PreampData.Settings)  {
        case Digital_Preamp_LOAD:
            sprintf(Temp_String2,"Load from memory");  break;
        case Digital_Preamp_SAVE:
            sprintf(Temp_String2,"Save to memory  ");  break;
        case Digital_Preamp_IDLE:
            sprintf(Temp_String2,"Return to Idle  ");  break;
        case Digital_Preamp_Monitor_Setup:
            sprintf(Temp_String2,"Monitor Setup   ");  break;
        case Digital_Preamp_Channel_Setup:
            sprintf(Temp_String2,"Channel Setup   ");  break;
        case Digital_Preamp_EQ_Setup:
            sprintf(Temp_String2,"Equaliser setup ");  break;
        case Digital_Preamp_ACTION_INIT:
            sprintf(Temp_String2,"TGM says WTF?   ");  break;
    }
    sprintf(Temp_String,"Push to select: ");


    LCD_TextOut(1,0,(unsigned char *)Temp_String2);  // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    LCD_TextOut(0,0,(unsigned char *)Temp_String);   // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    Clear_UI_Input;
    PreampData.UI_Update_Display = 0;  // clear flag display for update
}


/***************************************************************************/
/*      handles input rotation of the control in EQ State                  */
/***************************************************************************/
void EQ_Screen()
{
    char Temp_String[20],Temp_String2[20] ;

    if (PreampData.EQ_Selected <= Max_Common_EQ) // then we have a common EQ
    {
        sprintf(Temp_String2,"Common EQ set %d ", (PreampData.EQ_Selected) +1);
    }
    else if (PreampData.EQ_Selected <= (Max_Common_EQ + 1) + ((Max_EQ_Per_Channel + 1)* (Num_Bands_Of_EQ +1))) // then we have a channel EQ EQ
    {
        sprintf(Temp_String2,"Chan:%d EQ set %d ", ((PreampData.EQ_Selected - (Max_Common_EQ+1))/(Max_EQ_Per_Channel + 1) + 1),((PreampData.EQ_Selected - (Max_Common_EQ+1))%(Max_EQ_Per_Channel + 1) + 1));
    }
    else;  // oops - should never be able to get here

    sprintf(Temp_String,"Push to select: ");

    LCD_TextOut(1,0,(unsigned char *)Temp_String2);  // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    LCD_TextOut(0,0,(unsigned char *)Temp_String);   // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    Clear_UI_Input;
    PreampData.UI_Update_Display = 0;  // clear flag display for update
}

/***************************************************************************/
/*      handles input rotation of the control in EQ State                  */
/***************************************************************************/
void EQ_Update_Screen()
{
    char Temp_String[20],Temp_String2[20] ;


      // This is the top line - first three are common then three per channel for four channels
    if ((PreampData.EQ_Selected <= Max_Common_EQ) && (PreampData.EQ_Parm_Selected == Sel_Type))
        sprintf(Temp_String2,"Common EQ %d Type", (PreampData.EQ_Selected));
    else if ((PreampData.EQ_Selected <= Max_Common_EQ) && (PreampData.EQ_Parm_Selected == Sel_CF))
        sprintf(Temp_String2,"Common EQ %d Freq", (PreampData.EQ_Selected));
    else if ((PreampData.EQ_Selected <= Max_Common_EQ) && (PreampData.EQ_Parm_Selected == Sel_Gain))
        sprintf(Temp_String2,"Common EQ %d Gain", (PreampData.EQ_Selected));
    else if ((PreampData.EQ_Selected <= Max_Common_EQ) && (PreampData.EQ_Parm_Selected == Sel_Q))
        sprintf(Temp_String2,"Common EQ %d Q ", (PreampData.EQ_Selected));
    else if ((PreampData.EQ_Selected <= Max_EQ_Band) && (PreampData.EQ_Parm_Selected == Sel_Type))
        sprintf(Temp_String2,"Chan %d EQ %d Type", ((PreampData.EQ_Selected - (Max_Common_EQ+1))/(Max_EQ_Per_Channel + 1) + 1),((PreampData.EQ_Selected - (Max_Common_EQ+1))%(Max_EQ_Per_Channel + 1) + 1));
    else if ((PreampData.EQ_Selected <= Max_EQ_Band) && (PreampData.EQ_Parm_Selected == Sel_CF))
        sprintf(Temp_String2,"Chan %d EQ %d Freq", ((PreampData.EQ_Selected - (Max_Common_EQ+1))/(Max_EQ_Per_Channel + 1) + 1),((PreampData.EQ_Selected - (Max_Common_EQ+1))%(Max_EQ_Per_Channel + 1) + 1));
    else if ((PreampData.EQ_Selected <= Max_EQ_Band) && (PreampData.EQ_Parm_Selected == Sel_Gain))
        sprintf(Temp_String2,"Chan %d EQ %d Gain", ((PreampData.EQ_Selected - (Max_Common_EQ+1))/(Max_EQ_Per_Channel + 1) + 1),((PreampData.EQ_Selected - (Max_Common_EQ+1))%(Max_EQ_Per_Channel + 1) + 1));
    else if ((PreampData.EQ_Selected <= Max_EQ_Band) && (PreampData.EQ_Parm_Selected == Sel_Q))
        sprintf(Temp_String2,"Chan %d EQ %d Q", ((PreampData.EQ_Selected - (Max_Common_EQ+1))/(Max_EQ_Per_Channel + 1) + 1),((PreampData.EQ_Selected - (Max_Common_EQ+1))%(Max_EQ_Per_Channel + 1) + 1));
    else
        sprintf(Temp_String2,"Why am I here! 2");

    /* now the rest */
    if (PreampData.EQ_Parm_Selected == Sel_Type){
        if (PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_NONE)
            sprintf(Temp_String,"None            ");
        else if (PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_PARA)
            sprintf(Temp_String,"Para EQ         ");
        else
            sprintf(Temp_String,"Oops EQ set err.");
    }
    else if (PreampData.EQ_Parm_Selected == Sel_Gain){
        sprintf(Temp_String,"Gain %2ddB       ", PreampData.EQ_Values[PreampData.EQ_Selected].Gain);
    }
    else if ((PreampData.EQ_Parm_Selected == Sel_Q) && (PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_PARA)){
        sprintf(Temp_String,"Q %2.1f         ", (float)((float)PreampData.EQ_Values[PreampData.EQ_Selected].Q/10));
    }
    else if (PreampData.EQ_Parm_Selected == Sel_CF){
        sprintf(Temp_String,"Freq %5dHz    ", PreampData.EQ_Values[PreampData.EQ_Selected].CF);
    }
    else
        sprintf(Temp_String,"Why am I here! 1");

    LCD_TextOut(1,0,(unsigned char *)Temp_String);  // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    LCD_TextOut(0,0,(unsigned char *)Temp_String2);   // could be optimized//        LCD_TextOut(1,0,(unsigned char *)Temp_String);   // could be optimized
    Clear_UI_Input;
    PreampData.UI_Update_Display = 0;  // clear flag display for update
}

/***************************************************************************/
/*      handles input rotation of the control in Setting State             */
/***************************************************************************/
void Handle_Rot_From_Settings()
{
    /* handle input and cycle through setting options */
    if (PreampData.UI_Action == UIAction_ROT_Up)
    {
        PreampData.Settings--;
        if (PreampData.Settings < Digital_Preamp_LOAD)
            PreampData.Settings = Digital_Preamp_EQ_Setup;
    }
    else if (PreampData.UI_Action == UIAction_ROT_Down)
    {
        PreampData.Settings++;
        if (PreampData.Settings > Digital_Preamp_EQ_Setup)
            PreampData.Settings = Digital_Preamp_LOAD;
    }
    else;

    // Tell the system to update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}


/***************************************************************************/
/*      handles Enter pressed in the Settings State - ie select that choice*/
/***************************************************************************/
void Handle_Enter_From_Settings()
{
    //move to the appropriate state
    if (PreampData.Settings == Digital_Preamp_LOAD) {
        PreampData.state = Digital_Preamp_STATE_LOAD;
    }
    else if (PreampData.Settings == Digital_Preamp_SAVE) {
        PreampData.state = Digital_Preamp_STATE_SAVE;
    }
    else if (PreampData.Settings == Digital_Preamp_IDLE) {
        PreampData.state = Digital_Preamp_STATE_IDLE;
        PreampData.UI_Action = UIAction_NULL;
    }
    else if (PreampData.Settings == Digital_Preamp_Monitor_Setup)  {
        PreampData.state = Digital_Preamp_STATE_Monitor_Setup;
    }
    else if (PreampData.Settings == Digital_Preamp_Channel_Setup)  {
        PreampData.state = Digital_Preamp_STATE_Channel_Setup;
    }
    else if (PreampData.Settings == Digital_Preamp_EQ_Setup)  {
        PreampData.EQ_Selected = Min_EQ_Band;
        PreampData.state = Digital_Preamp_STATE_EQ_Setup;
        PreampData.EQ_Parm_Selected = Sel_Gain;
    }
    else;

    while (Enter_Key_Pressed)    //wait for use to take finger off enter
        CORETIMER_DelayMs(UI_Delay_Ms_General);

    // Tell the system to update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}


/***************************************************************************/
/*           handles Exit pressed in Settings State                        */
/*           used by                                                       */
/*                - Settings                                               */
/*                - Save                                                   */
/*                - Channel                                                */
/*                - EQ                                                     */
/***************************************************************************/
void Handle_Exit_From_Settings()
{
    /* this switches state to settings */
    PreampData.state = Digital_Preamp_STATE_IDLE; // jump to settings
    PreampData.UI_Action = UIAction_NULL;
    PreampData.UI_Update_Display = 1;  // flag display for update
    while (Exit_Key_Pressed)    //wait for use to take finger off exit
        CORETIMER_DelayMs(UI_Delay_Ms_General);
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_Exit;   // Use Input delay
}


/***************************************************************************/
/*      handles input up and down pressed in Idle State                    */
/***************************************************************************/
void Handle_Up_Down_From_Idle()
{
    /* handle input and cycle through inputs */
    if (PreampData.UI_Action == UIAction_Input_Up)
    {
        PreampData.Input_Sel++;
        if (PreampData.Input_Sel > Input_Bluetooth)
            PreampData.Input_Sel = Input_MiniDSP;
    }
    else if (PreampData.UI_Action == UIAction_Input_Down)
    {
        PreampData.Input_Sel--;
        if (PreampData.Input_Sel < Input_MiniDSP)
            PreampData.Input_Sel = Input_Bluetooth;
    }
    else;


    // Update the input switches
    Set_Input_Switching();

    //update the screen to provide immediate user feedback
    Idle_Screen();
    // delay after screen write so interface feels snappy
    CORETIMER_DelayMs(UI_Delay_Ms_Inputs);

    //wait until the button press is done
    while ((Input_Select_Up_Key) || (Input_Select_Down_Key))
        CORETIMER_DelayMs(UI_Delay_Ms_General);

    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_Inputs;   // Use Input delay
}


/***************************************************************************/
/*           handles MUTE                                                  */
/***************************************************************************/
void Handle_Mute()
{
    /* do not switch state to settings */

    Update_Atten_Set();
    
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_Mute;   // Put a reasonable delay as remote sends lots of commands
    CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
}



/***************************************************************************/
/*   Handles Settings state                                                */
/***************************************************************************/
void handleState_SETTINGS()
{
    /* Run the countdown timer - when zero go back to idle*/
    PreampData.Revert_To_Idle_Counter--;
    if (!PreampData.Revert_To_Idle_Counter){
        Handle_Exit_From_Settings();
    }

    if (PreampData.UI_Action)
    {
        Disable_Interrupts_During_Proc;
        PreampData.Revert_To_Idle_Counter = Revert_To_Idle;   // reset return to idle
        PreampData.UI_Update_Counter++;
        if((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            Handle_Rot_From_Settings();
        else if(PreampData.UI_Action == UIAction_ROT_Enter)
            Handle_Enter_From_Settings();
        else if(PreampData.UI_Action == UIAction_ROT_Exit)
            Handle_Exit_From_Settings();
        else if((PreampData.UI_Action == UIAction_Input_Up) || (PreampData.UI_Action == UIAction_Input_Down))
            Handle_Up_Down_From_Idle();                             // deal with button pressed
        else if (PreampData.UI_Action == UIAction_Input_Mute)
            Handle_Mute();
        else ;

        PreampData.UI_Action = UIAction_NULL;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Keypressed) {
        Disable_Interrupts_During_Proc;
        /* run update to counters to see if rapid value change needed */
        Digital_Preamp_UI_Fast_Slow(1, 1);   // fast, slow

        PreampData.UI_Keypressed = false;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Update_Display) {
        if (PreampData.state == Digital_Preamp_STATE_IDLE)
            Idle_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Monitor_Setup)
            Monitor_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SETTINGS)
            SETTINGS_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SAVE)
            Save_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_LOAD)
            Load_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Channel_Setup)
            Channel_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_EQ_Setup)
            EQ_Screen();
        CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
        PreampData.UI_Update_Display = false;
    }

}


/***************************************************************************/
/*      handles input rotation of the control in Idle State - ie volume    */
/***************************************************************************/
void Handle_Rot_From_Idle()
{
    // currently muted, but user wants to change volume
    if (PreampData.Output_Mute == 1)
    {
        PreampData.Output_Mute = 0;
    }

    /* handle input and cycle through inputs */
    if (PreampData.UI_Action == UIAction_ROT_Up)
    {
        Digital_Preamp_UI_Fast_Slow(3, 1); // Fast, slow
        PreampData.Atten_Set -= PreampData.UI_Speed;
        if (PreampData.Atten_Set < Atten_Min)
            PreampData.Atten_Set = Atten_Min;
    }
    else if (PreampData.UI_Action == UIAction_ROT_Down)
    {
        Digital_Preamp_UI_Fast_Slow(3, 1); // Fast, slow
        PreampData.Atten_Set += PreampData.UI_Speed;
        if (PreampData.Atten_Set > Atten_Max)
            PreampData.Atten_Set = Atten_Max;
    }
    else;

    // Do what it takes to update the ADAU1467 with new volume
    Update_Atten_Set();
    // update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_Volume;   // Use Volume delay
}


/***************************************************************************/
/*           handles Exit pressed in Idle State                            */
/***************************************************************************/
void Handle_Exit_From_Idle()
{
    /* this switches state to settings */
    PreampData.state = Digital_Preamp_STATE_SETTINGS; // jump to settings
    PreampData.UI_Update_Display = 1;  // flag display for update
    // update the screen to provide immediate user feedback
    SETTINGS_Screen();

    while (Exit_Key_Pressed)    //wait for use to take finger off exit
        CORETIMER_DelayMs(UI_Delay_Ms_General);
}

void handleState_LCDINIT() {
   
    /* get the LCD running as debug is nice to have */
    LCD_Boot();
    LCD_Splash_Screen();

    PreampData.state = Digital_Preamp_STATE_IDLE;
}

void handleState_IDLE() {

    /* reset the countdown timer */
    PreampData.Revert_To_Idle_Counter = Revert_To_Idle;

    if (PreampData.UI_Action)
    {
        Disable_Interrupts_During_Proc;
        PreampData.UI_Update_Counter++;
        if((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            Handle_Rot_From_Idle();                     // changes volume in IDLE
        else if(PreampData.UI_Action == UIAction_ROT_Enter)
            Handle_Enter_From_Idle();                   // Saves data
        else if(PreampData.UI_Action == UIAction_ROT_Exit)
            Handle_Exit_From_Idle();                    // Goes to settings menu
        else if((PreampData.UI_Action == UIAction_Input_Up) || (PreampData.UI_Action == UIAction_Input_Down))
            Handle_Up_Down_From_Idle();                 // Selects input
        else if (PreampData.UI_Action == UIAction_Input_Mute)
            Handle_Mute();                              // Mutes output
        else ;

        PreampData.UI_Action = UIAction_NULL;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Keypressed) {
        Disable_Interrupts_During_Proc;
        /* run update to counters to see if rapid value change needed */
        Digital_Preamp_UI_Fast_Slow(Atten_Speed, Atten_Step);    // fast, slow

        PreampData.UI_Keypressed = false;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Update_Display) {
        if (PreampData.state == Digital_Preamp_STATE_IDLE)
            Idle_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SETTINGS)
            SETTINGS_Screen();

        CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
        PreampData.UI_Update_Display = false;
    }
}

/***************************************************************************/
/*      handles input rotation of the control in Save State and Load       */
/***************************************************************************/
void Handle_Rot_From_Save_Load()
{
    /* handle input and cycle through save options */
    if (PreampData.UI_Action == UIAction_ROT_Up)
    {
        PreampData.MemoryBankSelected++;
        if (PreampData.MemoryBankSelected > Max_Mem_Banks)
            PreampData.MemoryBankSelected = Default_Mem_Bank;
    }
    else if (PreampData.UI_Action == UIAction_ROT_Down)
    {
        PreampData.MemoryBankSelected--;
        if (PreampData.MemoryBankSelected < Default_Mem_Bank)
            PreampData.MemoryBankSelected = Max_Mem_Banks;
    }
    else;

    // Tell the system to update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}

/**************************************************************************/
/*      handles Enter pressed in the Save State                           */
/*              Save data and return to idle                              */
/**************************************************************************/
void Handle_Enter_From_Save()
{
    char Temp_String[20], Temp_String2[20];

    Save_Data_To_Memory();   // do the save to currently selected memory bank
    sprintf(Temp_String2,"To Mem Bank: %d  ", (PreampData.MemoryBankSelected +1));
    sprintf(Temp_String,"Saving Settings ");
    LCD_TextOut(1,0,(unsigned char *)Temp_String2);
    LCD_TextOut(0,0,(unsigned char *)Temp_String);
    while (Enter_Key_Pressed)    //wait for use to take finger off enter
        CORETIMER_DelayMs(UI_Delay_Ms_General);
    // Tell the system to update display
    /* this switches state to settings */
    PreampData.state = Digital_Preamp_STATE_IDLE; // jump back to IDLE
    PreampData.UI_Action = UIAction_NULL;
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}

/*****************************************************************************/
/*  User wants to save data                                                  */
/*****************************************************************************/
void handleState_SAVE()
{
    /* Run the countdown timer - when zero return to idle*/
    PreampData.Revert_To_Idle_Counter--;
    if (!PreampData.Revert_To_Idle_Counter){
        Handle_Exit_From_Settings();   //this is a generic routine
    }

    if (PreampData.UI_Action)
    {
        Disable_Interrupts_During_Proc;
        PreampData.Revert_To_Idle_Counter = Revert_To_Idle;   // reset return to idle
        PreampData.UI_Update_Counter++;
        if((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            Handle_Rot_From_Save_Load();     // in this case choose the memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Enter)
            Handle_Enter_From_Save();   // in this case save to current memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Exit)
            Handle_Exit_From_Settings(); // uses Settings exit to Idle
        else if((PreampData.UI_Action == UIAction_Input_Up) || (PreampData.UI_Action == UIAction_Input_Down))
            Handle_Up_Down_From_Idle();                             // deal with button pressed
        else if (PreampData.UI_Action == UIAction_Input_Mute)
            Handle_Mute();
        else ;

        PreampData.UI_Action = UIAction_NULL;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Keypressed) {
        Disable_Interrupts_During_Proc;
        /* run update to counters to see if rapid value change needed */
        Digital_Preamp_UI_Fast_Slow(1, 1);     // fast, slow

        PreampData.UI_Keypressed = false;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Update_Display) {
        if (PreampData.state == Digital_Preamp_STATE_SAVE)
            Save_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_IDLE)
            Idle_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SETTINGS)
            SETTINGS_Screen();

        CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
        PreampData.UI_Update_Display = false;
    }
}


/**************************************************************************/
/*      handles Enter pressed in the Load State                           */
/*              Load data and return to idle                              */
/**************************************************************************/
void Handle_Enter_From_Load()
{
    char Temp_String[20], Temp_String2[20];

    Load_From_Memory((char)PreampData.MemoryBankSelected);
    sprintf(Temp_String2,"From Mem Bank: %d", (PreampData.MemoryBankSelected +1));
    sprintf(Temp_String,"Loaded Settings ");
    LCD_TextOut(1,0,(unsigned char *)Temp_String2);
    LCD_TextOut(0,0,(unsigned char *)Temp_String);
    Clear_UI_Input;
    while (Enter_Key_Pressed)    //wait for use to take finger off enter
        CORETIMER_DelayMs(UI_Delay_Ms_General);
    // Tell the system to update display
       /* this switches state to settings */
    CORETIMER_DelayMs(UI_Delay_Ms_Load);
    PreampData.state = Digital_Preamp_STATE_IDLE; // jump back to IDLE
    PreampData.UI_Action = UIAction_NULL;
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}


/*****************************************************************************/
/*  User wants to load data                                                  */
/*****************************************************************************/
void handleState_LOAD()
{
    /* Run the countdown timer - when zero return to idle*/
    PreampData.Revert_To_Idle_Counter--;
    if (!PreampData.Revert_To_Idle_Counter){
        Handle_Exit_From_Settings();   //this is a generic routine
    }

    if (PreampData.UI_Action)
    {
        Disable_Interrupts_During_Proc;
        PreampData.Revert_To_Idle_Counter = Revert_To_Idle;   // reset return to idle
        PreampData.UI_Update_Counter++;
        if((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            Handle_Rot_From_Save_Load();     // in this case choose the memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Enter)
            Handle_Enter_From_Load();   // in this case save to current memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Exit)
            Handle_Exit_From_Settings(); // uses Settings exit to Idle
        else if((PreampData.UI_Action == UIAction_Input_Up) || (PreampData.UI_Action == UIAction_Input_Down))
            Handle_Up_Down_From_Idle();                             // deal with button pressed
        else if (PreampData.UI_Action == UIAction_Input_Mute)
            Handle_Mute();
        else ;

        PreampData.UI_Action = UIAction_NULL;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Keypressed) {
        Disable_Interrupts_During_Proc;
        /* run update to counters to see if rapid value change needed */
        Digital_Preamp_UI_Fast_Slow(1, 1);    // fast, slow

        PreampData.UI_Keypressed = false;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Update_Display) {
        if (PreampData.state == Digital_Preamp_STATE_LOAD)
            Load_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SAVE)
            Save_Screen();
         else if (PreampData.state == Digital_Preamp_STATE_IDLE)
            Idle_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SETTINGS)
            SETTINGS_Screen();

        CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
        PreampData.UI_Update_Display = false;
    }
}

/****************************************************************************/
/*      handles input rotation of the control in Select Monitor State       */
/*  This is limited to:                                                     */
/*  - If the Preamp output is an Analogue signal, then                      */
/*          then the User can  monitor that, or                             */
/*          the user can monitor COAX SPDIF                                 */
/*          the user can monitor TOSLINK SPDIF                              */
/*          the user can monitor the MiniDSP output                         */
/* - If the Preamp output is COAX SPDIF, then                               */
/*          then the User can  monitor coax spdif, or                       */
/*          the user can monitor any of the Analogue inputs                 */
/*          the user can monitor the MiniDSP output                         */
/* - If the Preamp output is TOSLINK SPDIF, then                            */
/*          then the User can  monitor toslink spdif, or                    */
/*          the user can monitor any of the Analogue inputs                 */
/*          the user can monitor the MiniDSP output                         */
/* - If the Preamp output is the MINIDSP in, then                           */
/*          then the User can  monitor that, or                             */
/*          the user can monitor any of the Analogue inputs                 */
/*          the user can monitor the COAX SPDIF in                          */
/*          the user can monitor the TOSLINK SPDIF in                       */
/*                                                                          */
/*      TRUTH TABLE                                                         */
/*          OUTPUT      MiniDSP Coax    Toslink AUX2    AUX1    Tun BT      */
/*          MiniDSP     OK      OK      OK      OK      OK      OK  OK      */
/*          Coax        OK      OK      NO      OK      OK      OK  OK      */
/*          TOSLINK     OK      NO      OK      OK      OK      OK  OK      */
/*          AUX2        OK      OK      OK      OK      NO      NO  NO      */
/*          AUX1        OK      OK      OK      NO      OK      NO  NO      */
/*          Tuner       OK      OK      OK      NO      NO      OK  NO      */
/*          Bluetooth   OK      OK      OK      NO      NO      NO  OK      */
/*                                                                          */
/*  - Simply increment the Monitor input                                    */
/*  - then reconcile with logic limits of what the user is listening to     */
/****************************************************************************/
void Handle_Rot_From_Monitor()
{
    if (PreampData.UI_Action == UIAction_ROT_Up)
    {
        PreampData.Monitor_Sel++;
        if (PreampData.Monitor_Sel > Input_Bluetooth)  // this is up from analogue
            PreampData.Monitor_Sel = Input_SPDIF_Coax;

         switch (PreampData.Input_Sel) {
            case Input_SPDIF_Coax: {        // if coax seleted then jump TOSLINK
                if (PreampData.Monitor_Sel == Input_SPDIF_TOSLINK) PreampData.Monitor_Sel = Input_AUX2;
                break;
            }
            case Input_SPDIF_TOSLINK:{      // if TOSLINK selected then jump coax
                if (PreampData.Monitor_Sel == Input_SPDIF_Coax) PreampData.Monitor_Sel = Input_SPDIF_TOSLINK;
                break;
            }
            case Input_AUX2: {              // if AUX2 selected then jump all the other analogues
                if ((PreampData.Monitor_Sel == Input_AUX1) || (PreampData.Monitor_Sel == Input_Tuner)||
                (PreampData.Monitor_Sel == Input_Bluetooth))  PreampData.Monitor_Sel = Input_MiniDSP;
                break;
            }
            case Input_AUX1: {              // if AUX1 selected then jump all the other following analogues
                if ((PreampData.Monitor_Sel == Input_Tuner)|| (PreampData.Monitor_Sel == Input_Bluetooth))
                    PreampData.Monitor_Sel = Input_MiniDSP;
                else if ((PreampData.Monitor_Sel == Input_AUX2))
                    PreampData.Monitor_Sel = Input_AUX1;
                break;
            }
            case Input_Null: {              // if NULL selected there is an error but dont crash.
                if ((PreampData.Monitor_Sel == Input_Tuner)|| (PreampData.Monitor_Sel == Input_Bluetooth))
                    PreampData.Monitor_Sel = Input_MiniDSP;
                else if ((PreampData.Monitor_Sel == Input_AUX2))
                    PreampData.Monitor_Sel = Input_AUX1;
                break;
            }
            case Input_Tuner: {             // if Tuner selected then jump all the other following analogues
                if ((PreampData.Monitor_Sel == Input_Bluetooth))
                    PreampData.Monitor_Sel = Input_MiniDSP;
                else if ((PreampData.Monitor_Sel == Input_AUX2)|| (PreampData.Monitor_Sel == Input_AUX1))
                PreampData.Monitor_Sel = Input_Tuner;
                break;
            }
            case Input_Bluetooth: {         // if Bluetooth selected then jump all the other preceding analogues
                 if ((PreampData.Monitor_Sel == Input_AUX2) || (PreampData.Monitor_Sel == Input_AUX1)||
                (PreampData.Monitor_Sel == Input_Tuner))  PreampData.Monitor_Sel = Input_Bluetooth;
                 break;
            }
            case Input_MiniDSP: {         // if MinDSP then nothing special
                 break;
            }
        }
    }
    else if (PreampData.UI_Action == UIAction_ROT_Down)
    {
        PreampData.Monitor_Sel--;
        if (PreampData.Monitor_Sel < Input_SPDIF_Coax)  // this is up from analogue
            PreampData.Monitor_Sel = Input_Bluetooth;

        // now lets catch the exceptions for rotating down.
         switch (PreampData.Input_Sel) {
            case Input_SPDIF_Coax: {        // if coax seleted then jump TOSLINK
                if (PreampData.Monitor_Sel == Input_SPDIF_TOSLINK) PreampData.Monitor_Sel = Input_SPDIF_Coax;
                break;
            }
            case Input_SPDIF_TOSLINK:{      // if TOSLINK selected then jump coax
                if (PreampData.Monitor_Sel == Input_SPDIF_Coax) PreampData.Monitor_Sel = Input_SPDIF_TOSLINK;
                break;
            }
            case Input_AUX2: {              // if AUX2 selected then jump all the other analogues
                 if ((PreampData.Monitor_Sel == Input_AUX1) || (PreampData.Monitor_Sel == Input_Tuner)||
                    (PreampData.Monitor_Sel == Input_Bluetooth))  PreampData.Monitor_Sel = Input_AUX2;
                 break;
            }
            case Input_AUX1: {              // if AUX1 selected then jump all the other following analogues
                if ((PreampData.Monitor_Sel == Input_Tuner)|| (PreampData.Monitor_Sel == Input_Bluetooth))
                    PreampData.Monitor_Sel = Input_AUX1;
                else if ((PreampData.Monitor_Sel == Input_AUX2))
                    PreampData.Monitor_Sel = Input_SPDIF_TOSLINK;
                break;
            }
            case Input_Tuner: {             // if Tuner selected then jump all the other following analogues
                if ((PreampData.Monitor_Sel == Input_Bluetooth))
                    PreampData.Monitor_Sel = Input_Tuner;
                else if ((PreampData.Monitor_Sel == Input_AUX2) || (PreampData.Monitor_Sel == Input_AUX1))
                    PreampData.Monitor_Sel = Input_SPDIF_TOSLINK;
                break;
            }
            case Input_Bluetooth: {         // if Bluetooth selected then jump all the other preceding analogues
                if ((PreampData.Monitor_Sel == Input_AUX2) || (PreampData.Monitor_Sel == Input_AUX1)||
                    (PreampData.Monitor_Sel == Input_Tuner))  PreampData.Monitor_Sel = Input_SPDIF_TOSLINK;
                break;
            }
            case Input_Null: {         // if Null handle this error
                break;
            }        
            case Input_MiniDSP: {      // no action
                break;
            }            }
    }
    else;

    // Update the input switches
    Set_Input_Switching();
    
    // Tell the system to update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}


/**************************************************************************/
/*      handles Enter pressed in the Monitor State                        */
/*              Update display and return to idle                         */
/**************************************************************************/
void Handle_Enter_From_Monitor()
{
    Clear_UI_Input;
    Idle_Screen();              //update display so the user sees a response
    while (Enter_Key_Pressed)   //wait for use to take finger off enter
        CORETIMER_DelayMs(UI_Delay_Ms_General);
    // Tell the system to update display
       /* this switches state to settings */
    CORETIMER_DelayMs(UI_Delay_Ms_Load);
    PreampData.state = Digital_Preamp_STATE_IDLE; // jump back to IDLE
    PreampData.UI_Action = UIAction_NULL;
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}



/*****************************************************************************/
/*  User wants to change input to Monitor                                    */
/* lots of logic in the rotary switching function                            */
/*****************************************************************************/
void handleState_MONITOR() {
    /* Run the countdown timer - when zero return to idle*/
    PreampData.Revert_To_Idle_Counter--;
    if (!PreampData.Revert_To_Idle_Counter){
        Handle_Exit_From_Settings();   //this is a generic routine
    }

    if (PreampData.UI_Action)
    {
        Disable_Interrupts_During_Proc;
        PreampData.Revert_To_Idle_Counter = Revert_To_Idle;   // reset return to idle
        PreampData.UI_Update_Counter++;
        if((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            Handle_Rot_From_Monitor();     // in this case choose the memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Enter)
            Handle_Enter_From_Monitor();   // in this case save to current memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Exit)
            Handle_Exit_From_Settings(); // uses Settings exit to Idle
        else if((PreampData.UI_Action == UIAction_Input_Up) || (PreampData.UI_Action == UIAction_Input_Down))
            Handle_Up_Down_From_Idle();                             // deal with button pressed
        else if (PreampData.UI_Action == UIAction_Input_Mute)
            Handle_Mute();
        else ;

        PreampData.UI_Action = UIAction_NULL;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Keypressed) {
        Disable_Interrupts_During_Proc;
        /* run update to counters to see if rapid value change needed */
        Digital_Preamp_UI_Fast_Slow(1, 1);   // fast, slow

        PreampData.UI_Keypressed = false;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Update_Display) {
        if (PreampData.state == Digital_Preamp_STATE_Monitor_Setup)
            Monitor_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_LOAD)
            Load_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SAVE)
            Save_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_IDLE)
            Idle_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SETTINGS)
            SETTINGS_Screen();

        CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
        PreampData.UI_Update_Display = false;
    }

}

/***************************************************************************/
/*      handles input rotation of the control in Channel Change state      */
/***************************************************************************/
void Handle_Rot_From_Channel()
{
    /* handle input and cycle through save options */
    if (PreampData.UI_Action == UIAction_ROT_Up)
    {
        PreampData.Channel_Selected++;
        if (PreampData.Channel_Selected > Max_XO_Band)
            PreampData.Channel_Selected = Min_XO_Band;
    }
    else if (PreampData.UI_Action == UIAction_ROT_Down)
    {
        PreampData.Channel_Selected--;
        if (PreampData.Channel_Selected < Min_XO_Band)
            PreampData.Channel_Selected = Max_XO_Band;
    }
    else;

    // Tell the system to update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}

/***************************************************************************/
/*      handles ENTER being pressed in channel change selection            */
/***************************************************************************/
void Handle_Enter_From_Channel()
{
    // go straight to Digital_Preamp_STATE_Channel_Update
    Channel_Update_Screen();
    while (Enter_Key_Pressed)    //wait for use to take finger off enter
        CORETIMER_DelayMs(UI_Delay_Ms_General);
    // Tell the system to update display
    /* this switches state to settings */
    PreampData.state = Digital_Preamp_STATE_Channel_Update; // jump to channel update
    PreampData.UI_Action = UIAction_NULL;
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}


/*****************************************************************************/
/*  User wants to change channel settings                                    */
/*  Need to identify the channel to select.                                  */
/*****************************************************************************/
void handleState_CHANNEL_SETUP()
{
    /* Run the countdown timer - when zero return to idle*/
    PreampData.Revert_To_Idle_Counter--;
    if (!PreampData.Revert_To_Idle_Counter){
        Handle_Exit_From_Settings();   //this is a generic routine
    }

    PreampData.Channel_Parm_Selected = Sel_Sl; // always start with lower slope
    PreampData.Channel_Parm_Selected = Min_XO_Band; // and the first channel

    if (PreampData.UI_Action)
    {
        Disable_Interrupts_During_Proc;
        PreampData.Revert_To_Idle_Counter = Revert_To_Idle;   // reset return to idle
        PreampData.UI_Update_Counter++;
        if((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            Handle_Rot_From_Channel();     // in this case choose the channel we care to change
        else if(PreampData.UI_Action == UIAction_ROT_Enter)
            Handle_Enter_From_Channel();   // in this case save to current memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Exit)
            Handle_Exit_From_Settings(); // uses Settings exit to Idle
        else if((PreampData.UI_Action == UIAction_Input_Up) || (PreampData.UI_Action == UIAction_Input_Down))
            Handle_Up_Down_From_Idle();                             // deal with button pressed
        else if (PreampData.UI_Action == UIAction_Input_Mute)
            Handle_Mute();
        else ;

        PreampData.UI_Action = UIAction_NULL;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Keypressed) {
        Disable_Interrupts_During_Proc;
        /* run update to counters to see if rapid value change needed */
        Digital_Preamp_UI_Fast_Slow(1, 1);   // fast, slow

        PreampData.UI_Keypressed = false;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Update_Display) {
        if (PreampData.state == Digital_Preamp_STATE_Channel_Setup)
            Channel_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Channel_Update)
            Channel_Update_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Monitor_Setup)
            Monitor_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_LOAD)
            Load_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SAVE)
            Save_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_IDLE)
            Idle_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SETTINGS)
            SETTINGS_Screen();
        else;

        CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
        PreampData.UI_Update_Display = false;
    }
}

/*****************************************************************************/
/*  User driving rotary control to change channel settings                   */
/*  Need to respond to user input and update values                          */
/*****************************************************************************/
void Handle_Rot_From_Channel_Update()
{
    switch (PreampData.Channel_Parm_Selected) {
        case Sel_Fl: {
            if (PreampData.Data_Values[PreampData.Channel_Selected].Fl > 1000){
                PreampData.UI_Speed *= 10;
                PreampData.Data_Values[PreampData.Channel_Selected].Fl -= PreampData.Data_Values[PreampData.Channel_Selected].Fl % 10;
                }
            if (PreampData.UI_Action == UIAction_ROT_Up)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Fl += Fl_Step * PreampData.UI_Speed;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Fl > Fl_Max)
                    PreampData.Data_Values[PreampData.Channel_Selected].Fl = Fl_Max;
           	    Write_Filter_Parm(0x10 + PreampData.Channel_Selected, PreampData.Data_Values[PreampData.Channel_Selected].Fl, PreampData.Data_Values[PreampData.Channel_Selected].Sl,ADAU_SR,0,0); 
            }
            else if (PreampData.UI_Action == UIAction_ROT_Down)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Fl -= Fl_Step * PreampData.UI_Speed;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Fl < Fl_Min)
                    PreampData.Data_Values[PreampData.Channel_Selected].Fl = Fl_Min;
           	    Write_Filter_Parm(0x10 + PreampData.Channel_Selected, PreampData.Data_Values[PreampData.Channel_Selected].Fl, PreampData.Data_Values[PreampData.Channel_Selected].Sl,ADAU_SR,0,0); 
            }
            else;
            break;
        }
        case Sel_Fu: {
            if (PreampData.Data_Values[PreampData.Channel_Selected].Fu > 1000){
                PreampData.UI_Speed *= 10;
                PreampData.Data_Values[PreampData.Channel_Selected].Fu -= PreampData.Data_Values[PreampData.Channel_Selected].Fu % 10;
            }
            if (PreampData.UI_Action == UIAction_ROT_Up)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Fu += Fu_Step * PreampData.UI_Speed;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Fu > Fu_Max)
                    PreampData.Data_Values[PreampData.Channel_Selected].Fu = Fu_Max;
           	    Write_Filter_Parm(0x00 + PreampData.Channel_Selected, PreampData.Data_Values[PreampData.Channel_Selected].Fu, PreampData.Data_Values[PreampData.Channel_Selected].Su,ADAU_SR,0,0); 
            }
            else if (PreampData.UI_Action == UIAction_ROT_Down)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Fu -= Fu_Step * PreampData.UI_Speed;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Fu < Fu_Min)
                    PreampData.Data_Values[PreampData.Channel_Selected].Fu = Fu_Min;
           	    Write_Filter_Parm(0x00 + PreampData.Channel_Selected, PreampData.Data_Values[PreampData.Channel_Selected].Fu, PreampData.Data_Values[PreampData.Channel_Selected].Su,ADAU_SR,0,0); 
            }
            else;
            break;
        }
        case Sel_Sl: {
            if (PreampData.UI_Action == UIAction_ROT_Up)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Sl += Sl_Step;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Sl > Sl_Max)
                    PreampData.Data_Values[PreampData.Channel_Selected].Sl = Sl_Min;
           	    Write_Filter_Parm(0x10 + PreampData.Channel_Selected, PreampData.Data_Values[PreampData.Channel_Selected].Fl, PreampData.Data_Values[PreampData.Channel_Selected].Sl,ADAU_SR,0,0); 
            }
            else if (PreampData.UI_Action == UIAction_ROT_Down)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Sl -= Sl_Step;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Sl < Sl_Min)
                    PreampData.Data_Values[PreampData.Channel_Selected].Sl = Sl_Max;
           	    Write_Filter_Parm(0x10 + PreampData.Channel_Selected, PreampData.Data_Values[PreampData.Channel_Selected].Fl, PreampData.Data_Values[PreampData.Channel_Selected].Sl,ADAU_SR,0,0); 
            }         
            else;
            break;
        }
        case Sel_Su: {
            if (PreampData.UI_Action == UIAction_ROT_Up)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Su += Su_Step;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Su > Su_Max)
                    PreampData.Data_Values[PreampData.Channel_Selected].Su = Su_Min;
           	    Write_Filter_Parm(0x00 + PreampData.Channel_Selected, PreampData.Data_Values[PreampData.Channel_Selected].Fu, PreampData.Data_Values[PreampData.Channel_Selected].Su,ADAU_SR,0,0); 
            }
            else if (PreampData.UI_Action == UIAction_ROT_Down)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Su -= Su_Step;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Su < Su_Min)
                    PreampData.Data_Values[PreampData.Channel_Selected].Su = Su_Max;
           	    Write_Filter_Parm(0x00 + PreampData.Channel_Selected, PreampData.Data_Values[PreampData.Channel_Selected].Fu, PreampData.Data_Values[PreampData.Channel_Selected].Su,ADAU_SR,0,0); 
            }
            else;
            break;
        }
        case Sel_Atten: {
            if (PreampData.UI_Action == UIAction_ROT_Up)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Atten += Atten_Step;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Atten > Gain_Atten_Max)
                    PreampData.Data_Values[PreampData.Channel_Selected].Atten = Gain_Atten_Max;
            }
            else if (PreampData.UI_Action == UIAction_ROT_Down)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Atten -= Atten_Step;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Atten < Gain_Atten_Min)
                    PreampData.Data_Values[PreampData.Channel_Selected].Atten = Gain_Atten_Min;
            }
            else;
            Update_Atten_Set();
            break;
        }
        case Sel_Delay_mm: {
            if (PreampData.Data_Values[PreampData.Channel_Selected].Delay_mm > 1000){
                PreampData.UI_Speed *= 10;
            }
            if (PreampData.UI_Action == UIAction_ROT_Up)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Delay_mm += Delay_Step  * PreampData.UI_Speed;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Delay_mm > Delay_Max)
                    PreampData.Data_Values[PreampData.Channel_Selected].Delay_mm = Delay_Max;
            }
            else if (PreampData.UI_Action == UIAction_ROT_Down)
            {
                PreampData.Data_Values[PreampData.Channel_Selected].Delay_mm -= Delay_Step * PreampData.UI_Speed;
                if (PreampData.Data_Values[PreampData.Channel_Selected].Delay_mm < Delay_Min)
                    PreampData.Data_Values[PreampData.Channel_Selected].Delay_mm = Delay_Min;
            }
            else;
            Update_Delay_Set(ADAU_SR);
            break;
        }
        case Sel_Invert: {
            if ((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            {
                if(PreampData.Data_Values[PreampData.Channel_Selected].Invert)
                    PreampData.Data_Values[PreampData.Channel_Selected].Invert = 0;
                else
                    PreampData.Data_Values[PreampData.Channel_Selected].Invert = 1;
            }
            else;
            Update_Invert_Set();
            break;
        }
        case Sel_Bridge: {
            if ((PreampData.Channel_Selected == Min_XO_Band) && ((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down)))
            {
                if(PreampData.Data_Values[PreampData.Channel_Selected].Bridge)
                    PreampData.Data_Values[PreampData.Channel_Selected].Bridge = 0;
                else
                    PreampData.Data_Values[PreampData.Channel_Selected].Bridge = 1;
            }
            else;
            Write_Mono_Sub(PreampData.Data_Values[PreampData.Channel_Selected].Bridge);
            break;
        }
    }
    // Tell the system to update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}


/*****************************************************************************/
/*  User presses enter on a value they have changed                          */
/*  Keep the value and move to next value to alter                           */
/*****************************************************************************/
void Handle_Enter_From_Channel_Update()
{
    /* first - are we through the channel parameters*/
    if (PreampData.Channel_Parm_Selected == Sel_Sl)
        if (PreampData.Data_Values[PreampData.Channel_Selected].Sl > NoFilter)
        {
            PreampData.Channel_Parm_Selected = Sel_Fl;   //the next parameter we want to offer
        }
        else
        {
            PreampData.Channel_Parm_Selected = Sel_Su;  // if no filter jump to upper slope
        }
    else if (PreampData.Channel_Parm_Selected == Sel_Fl)
        PreampData.Channel_Parm_Selected = Sel_Su; // next from SL
    else if (PreampData.Channel_Parm_Selected == Sel_Su)
        if (PreampData.Data_Values[PreampData.Channel_Selected].Su > NoFilter)
        {
            PreampData.Channel_Parm_Selected = Sel_Fu;  // if there is an upper XO then sow freq
        }
        else
        {
            PreampData.Channel_Parm_Selected = Sel_Atten;  // else go to Atten
        }
    else if (PreampData.Channel_Parm_Selected == Sel_Fu)
        PreampData.Channel_Parm_Selected = Sel_Atten;
    else if (PreampData.Channel_Parm_Selected == Sel_Atten)
        PreampData.Channel_Parm_Selected = Sel_Delay_mm;
    else if (PreampData.Channel_Parm_Selected == Sel_Delay_mm)
        PreampData.Channel_Parm_Selected = Sel_Invert;
    else if ((PreampData.Channel_Selected == Min_XO_Band)&&(PreampData.Channel_Parm_Selected == Sel_Invert))
        PreampData.Channel_Parm_Selected = Sel_Bridge;
    /* now what of we are at the end of this channels parameters?*/
    else if (((PreampData.Channel_Selected > Min_XO_Band)&&(PreampData.Channel_Parm_Selected == Sel_Invert)) ||
            (PreampData.Channel_Parm_Selected == Sel_Bridge))   // OK we are thru the bands
    {
        PreampData.Channel_Parm_Selected = Sel_Sl;
        PreampData.Channel_Selected++;
        if (PreampData.Channel_Selected > Max_XO_Band)
        {
            PreampData.Channel_Selected = Min_XO_Band;
        }
    }

    Channel_Update_Screen();

    while (Enter_Key_Pressed)    //wait for use to take finger off exit
    CORETIMER_DelayMs(UI_Delay_Ms_General);

}

/*****************************************************************************/
/*  User presses exit (menu)                                                 */
/*  Move back to the channel select                                          */
/*****************************************************************************/
void Handle_Exit_From_Channel_Update()
{
    /* this switches state to settings */
    PreampData.state = Digital_Preamp_STATE_Channel_Setup; // jump to channel setup
    PreampData.UI_Update_Display = 1;  // flag display for update
    // update the screen to provide immediate user feedback
    Channel_Screen();
    PreampData.UI_Speed = 1;


    while (Exit_Key_Pressed)    //wait for use to take finger off exit
        CORETIMER_DelayMs(UI_Delay_Ms_General);
}



/*****************************************************************************/
/*  User wants to change channel settings                                    */
/*  Need to respond to user input and update values                          */
/*****************************************************************************/
void handleState_CHANNEL_SETUP_UPDATE()
{
    /* Run the countdown timer - when zero return to idle*/
    PreampData.Revert_To_Idle_Counter--;
    if (!PreampData.Revert_To_Idle_Counter){
        Handle_Exit_From_Settings();   //this is a generic routine
    }

    if (PreampData.UI_Action)
    {
        Disable_Interrupts_During_Proc;
        PreampData.Revert_To_Idle_Counter = Revert_To_Idle;   // reset return to idle
        PreampData.UI_Update_Counter++;
        if((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            Handle_Rot_From_Channel_Update();     // in this case choose the channel we care to change
        else if(PreampData.UI_Action == UIAction_ROT_Enter)
            Handle_Enter_From_Channel_Update();   // in this case save to current memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Exit)
            Handle_Exit_From_Channel_Update(); // uses Settings exits back to channel screen
        else if((PreampData.UI_Action == UIAction_Input_Up) || (PreampData.UI_Action == UIAction_Input_Down))
            Handle_Up_Down_From_Idle();                             // deal with button pressed
        else if (PreampData.UI_Action == UIAction_Input_Mute)
            Handle_Mute();
        else ;

        PreampData.UI_Action = UIAction_NULL;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Keypressed) {
        Disable_Interrupts_During_Proc;
        /* run update to counters to see if rapid value change needed */
        Digital_Preamp_UI_Fast_Slow(10, 1); // fast, slow

        PreampData.UI_Keypressed = false;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Update_Display) {
        if (PreampData.state == Digital_Preamp_STATE_Channel_Setup)
            Channel_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Channel_Update)
            Channel_Update_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Monitor_Setup)
            Monitor_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_LOAD)
            Load_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SAVE)
            Save_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_IDLE)
            Idle_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SETTINGS)
            SETTINGS_Screen();

        CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
        PreampData.UI_Update_Display = false;
    }
}


/***************************************************************************/
/*      handles Enter being pressed in EQ Change state                     */
/***************************************************************************/
void Handle_Enter_From_EQ_SETUP()
{
    PreampData.EQ_Parm_Selected = Sel_Type;

    // go straight to Digital_Preamp_STATE_EQ_Update
    EQ_Update_Screen();
    while (Enter_Key_Pressed)    //wait for use to take finger off enter
        CORETIMER_DelayMs(UI_Delay_Ms_General);
    // Tell the system to update display
    /* this switches state to settings */
    PreampData.state = Digital_Preamp_STATE_EQ_Update; // jump to EQ Change update
    PreampData.UI_Action = UIAction_NULL;
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}

/***************************************************************************/
/*      handles input rotation of the control in EQ Change state      */
/***************************************************************************/
void Handle_Rot_From_EQ_SETUP()
{
    /* handle input and cycle through save options */
    if (PreampData.UI_Action == UIAction_ROT_Up)
    {
        PreampData.EQ_Selected++;
        if (PreampData.EQ_Selected > Max_EQ_Band)
            PreampData.EQ_Selected = Min_EQ_Band;
    }
    else if (PreampData.UI_Action == UIAction_ROT_Down)
    {
        PreampData.EQ_Selected--;
        if (PreampData.EQ_Selected < Min_EQ_Band)
            PreampData.EQ_Selected = Max_EQ_Band;
    }
    else;

    // Tell the system to update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}

/********************************************************************/
/* We have the EQ selected PreampData.EQ_Selected                   */
/* NMeed to rotate through the parameters                           */
/* EQ types are:                                                    */
/*      None                                                        */
/*      Para                                                        */
/*      LPF                                                         */
/*      HPF                                                         */
/*                                                                  */
/* Need to handle parameters for each in a loop                     */
/********************************************************************/
void Handle_Rot_From_EQ_SETUP_UPDATE()
{
    //Deal with changing type
    if (PreampData.EQ_Parm_Selected == Sel_Type){
        if (PreampData.UI_Action == UIAction_ROT_Up){
            if (PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_PARA)
                PreampData.EQ_Values[PreampData.EQ_Selected].Type = EQ_TYPE_NONE;
            else 
                PreampData.EQ_Values[PreampData.EQ_Selected].Type = EQ_TYPE_PARA;
        }
        else if (PreampData.UI_Action == UIAction_ROT_Down) {
            if (PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_PARA)
                PreampData.EQ_Values[PreampData.EQ_Selected].Type = EQ_TYPE_NONE;
            else 
                PreampData.EQ_Values[PreampData.EQ_Selected].Type = EQ_TYPE_PARA;
        }
    }

    // Deal with CF
    else if (((PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_PARA)) && 
            (PreampData.EQ_Parm_Selected == Sel_CF)){
        if (PreampData.EQ_Values[PreampData.EQ_Selected].CF > 1000){
            PreampData.UI_Speed *= 10;
        PreampData.EQ_Values[PreampData.EQ_Selected].CF -= PreampData.EQ_Values[PreampData.EQ_Selected].CF % 10;
        }
        if (PreampData.UI_Action == UIAction_ROT_Up) {
            PreampData.EQ_Values[PreampData.EQ_Selected].CF += EQ_Step * PreampData.UI_Speed;
            if (PreampData.EQ_Values[PreampData.EQ_Selected].CF > EQ_Max)
                PreampData.EQ_Values[PreampData.EQ_Selected].CF = EQ_Max;
            Write_Filter_Parm(PreampData.EQ_Selected, PreampData.EQ_Values[PreampData.EQ_Selected].CF, PreampData.EQ_Values[PreampData.EQ_Selected].Type, ADAU_SR, PreampData.EQ_Values[PreampData.EQ_Selected].Q , PreampData.EQ_Values[PreampData.EQ_Selected].Gain); 
        }
        else if (PreampData.UI_Action == UIAction_ROT_Down)
        {
            PreampData.EQ_Values[PreampData.EQ_Selected].CF -= EQ_Step * PreampData.UI_Speed;
            if (PreampData.EQ_Values[PreampData.EQ_Selected].CF < EQ_Min)
                PreampData.EQ_Values[PreampData.EQ_Selected].CF = EQ_Min;
            Write_Filter_Parm(PreampData.EQ_Selected, PreampData.EQ_Values[PreampData.EQ_Selected].CF, PreampData.EQ_Values[PreampData.EQ_Selected].Type, ADAU_SR, PreampData.EQ_Values[PreampData.EQ_Selected].Q , PreampData.EQ_Values[PreampData.EQ_Selected].Gain); 
        }
    }
    // Deal with Q
    else if ((PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_PARA) && (PreampData.EQ_Parm_Selected == Sel_Q)){
        if (PreampData.UI_Action == UIAction_ROT_Up) {
            PreampData.EQ_Values[PreampData.EQ_Selected].Q += EQ_Q_Step * PreampData.UI_Speed;
            if (PreampData.EQ_Values[PreampData.EQ_Selected].Q > EQ_Q_Max)
                PreampData.EQ_Values[PreampData.EQ_Selected].Q = EQ_Q_Max;
            Write_Filter_Parm(PreampData.EQ_Selected, PreampData.EQ_Values[PreampData.EQ_Selected].CF, PreampData.EQ_Values[PreampData.EQ_Selected].Type, ADAU_SR, PreampData.EQ_Values[PreampData.EQ_Selected].Q , PreampData.EQ_Values[PreampData.EQ_Selected].Gain); 
        }
        else if (PreampData.UI_Action == UIAction_ROT_Down)
        {
            PreampData.EQ_Values[PreampData.EQ_Selected].Q -= EQ_Q_Step * PreampData.UI_Speed;
            if (PreampData.EQ_Values[PreampData.EQ_Selected].Q < EQ_Q_Min)
                PreampData.EQ_Values[PreampData.EQ_Selected].Q = EQ_Q_Min;
            Write_Filter_Parm(PreampData.EQ_Selected, PreampData.EQ_Values[PreampData.EQ_Selected].CF, PreampData.EQ_Values[PreampData.EQ_Selected].Type, ADAU_SR, PreampData.EQ_Values[PreampData.EQ_Selected].Q , PreampData.EQ_Values[PreampData.EQ_Selected].Gain); 
        }
    }
    // Deal with Gain
    else if ((PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_PARA) && (PreampData.EQ_Parm_Selected == Sel_Gain)){
        if (PreampData.UI_Action == UIAction_ROT_Up) {
            PreampData.EQ_Values[PreampData.EQ_Selected].Gain += EQ_Gain_Step_Size;
            if (PreampData.EQ_Values[PreampData.EQ_Selected].Gain > EQ_Gain_Max)
                PreampData.EQ_Values[PreampData.EQ_Selected].Gain = EQ_Gain_Max;
            Write_Filter_Parm(PreampData.EQ_Selected, PreampData.EQ_Values[PreampData.EQ_Selected].CF, PreampData.EQ_Values[PreampData.EQ_Selected].Type, ADAU_SR, PreampData.EQ_Values[PreampData.EQ_Selected].Q , PreampData.EQ_Values[PreampData.EQ_Selected].Gain); 
        }
        else if (PreampData.UI_Action == UIAction_ROT_Down)
        {
            PreampData.EQ_Values[PreampData.EQ_Selected].Gain -= EQ_Gain_Step_Size;
            if (PreampData.EQ_Values[PreampData.EQ_Selected].Gain < EQ_Gain_Min)
                PreampData.EQ_Values[PreampData.EQ_Selected].Gain = EQ_Gain_Min;
            Write_Filter_Parm(PreampData.EQ_Selected, PreampData.EQ_Values[PreampData.EQ_Selected].CF, PreampData.EQ_Values[PreampData.EQ_Selected].Type, ADAU_SR, PreampData.EQ_Values[PreampData.EQ_Selected].Q , PreampData.EQ_Values[PreampData.EQ_Selected].Gain); 
        }
    }


    // Tell the system to update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}


/****************************************************************************/
/*        This will be used a few times                                     */
/****************************************************************************/
void Increment_EQ_Band()
{
    // This simply cycles through the bands and
    // if the user never presses exit they go in circles for ever
    PreampData.EQ_Selected ++;
    if (PreampData.EQ_Selected > Max_EQ_Band)
        PreampData.EQ_Selected = Min_EQ_Band;

    if (PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_NONE){
        PreampData.EQ_Parm_Selected = Sel_Type; //put it here just to initialise it
    }
    else if (PreampData.EQ_Values[PreampData.EQ_Selected].Type == EQ_TYPE_PARA){
        PreampData.EQ_Parm_Selected = Sel_Type; //start with centre freq for para EQ
    }
}

/****************************************************************************/
/*  User presses ENTER                                                      */
/*  This needs to cycle through all EQ settings.                            */
/*          PreampData.EQ_Selected   : EQ from Comm 1-3 and CH 1-3    */
/*          PreampData.EQ_Values[PreampData.EQ_Selected].Type
                    needs to cycle through legal values                     */
/*          PreampData.EQ_Parm_Selected    : PArameter in the EQ (CF, Q etc)*/
/*                                                                          */
/****************************************************************************/
void Handle_Enter_From_EQ_SETUP_UPDATE()
{
    if(PreampData.EQ_Values[PreampData.EQ_Selected].Type  == EQ_TYPE_NONE){
        Increment_EQ_Band();

        // check all other stuff is sensibly set and increment
    }
    else if (PreampData.EQ_Values[PreampData.EQ_Selected].Type  == EQ_TYPE_PARA){
        if(PreampData.EQ_Parm_Selected == Sel_Type)
            PreampData.EQ_Parm_Selected = Sel_CF;
        else if(PreampData.EQ_Parm_Selected == Sel_CF)
            PreampData.EQ_Parm_Selected = Sel_Q;
        else if (PreampData.EQ_Parm_Selected == Sel_Q)
            PreampData.EQ_Parm_Selected = Sel_Gain;
        else if (PreampData.EQ_Parm_Selected == Sel_Gain)
            Increment_EQ_Band();
    }


    EQ_Update_Screen();
    while (Enter_Key_Pressed)    //wait for use to take finger off enter
       CORETIMER_DelayMs(UI_Delay_Ms_General);

    CORETIMER_DelayMs(UI_Delay_Ms_General);

    // Tell the system to update display
    PreampData.UI_Update_Display = 1;  // flag display for update
    PreampData.UI_Update_Display_Delay = UI_Delay_Ms_General;   // Use Volume delay
}

/*****************************************************************************/
/*  User wants to change EQ setting values                                   */
/*  Need to update values.                                                   */
/*****************************************************************************/
void handleState_EQ_SETUP_UPDATE()
{
    /* Run the countdown timer - when zero return to idle*/
    PreampData.Revert_To_Idle_Counter--;
    if (!PreampData.Revert_To_Idle_Counter){
        Handle_Exit_From_Settings();   //this is a generic routine
    }

    if (PreampData.UI_Action)
    {
        Disable_Interrupts_During_Proc;
        PreampData.Revert_To_Idle_Counter = Revert_To_Idle;   // reset return to idle
        PreampData.UI_Update_Counter++;
        if((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            Handle_Rot_From_EQ_SETUP_UPDATE();     // in this case choose the EQ we care to change
        else if(PreampData.UI_Action == UIAction_ROT_Enter)
            Handle_Enter_From_EQ_SETUP_UPDATE();   // in this case save to current memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Exit)
            Handle_Exit_From_Settings(); // uses Settings exit to Idle
        else if((PreampData.UI_Action == UIAction_Input_Up) || (PreampData.UI_Action == UIAction_Input_Down))
            Handle_Up_Down_From_Idle();                             // deal with button pressed
        else if (PreampData.UI_Action == UIAction_Input_Mute)
            Handle_Mute();
        else ;

        PreampData.UI_Action = UIAction_NULL;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Keypressed) {
        Disable_Interrupts_During_Proc;
        /* run update to counters to see if rapid value change needed */
        Digital_Preamp_UI_Fast_Slow(10, 1);   // fast, slow

        PreampData.UI_Keypressed = false;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Update_Display) {
        if (PreampData.state == Digital_Preamp_STATE_EQ_Update)
            EQ_Update_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_EQ_Setup)
            EQ_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Channel_Setup)
            Channel_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Channel_Update)
            Channel_Update_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Monitor_Setup)
            Monitor_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_LOAD)
            Load_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SAVE)
            Save_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_IDLE)
            Idle_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SETTINGS)
            SETTINGS_Screen();
        else;

        CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
        PreampData.UI_Update_Display = false;
    }
}


/*****************************************************************************/
/*  User wants to change EQ settings                                         */
/*  Need to identify the EQ to select.                                       */
/*****************************************************************************/
void handleState_EQ_SETUP()
{
    /* Run the countdown timer - when zero return to idle*/
    PreampData.Revert_To_Idle_Counter--;
    if (!PreampData.Revert_To_Idle_Counter){
        Handle_Exit_From_Settings();   //this is a generic routine
    }

    if (PreampData.UI_Action)
    {
        Disable_Interrupts_During_Proc;
        PreampData.Revert_To_Idle_Counter = Revert_To_Idle;   // reset return to idle
        PreampData.UI_Update_Counter++;
        if((PreampData.UI_Action == UIAction_ROT_Up) || (PreampData.UI_Action == UIAction_ROT_Down))
            Handle_Rot_From_EQ_SETUP();     // in this case choose the EQ we care to change
        else if(PreampData.UI_Action == UIAction_ROT_Enter)
            Handle_Enter_From_EQ_SETUP();   // in this case save to current memory bank
        else if(PreampData.UI_Action == UIAction_ROT_Exit)
            Handle_Exit_From_Settings(); // uses Settings exit to Idle
        else if((PreampData.UI_Action == UIAction_Input_Up) || (PreampData.UI_Action == UIAction_Input_Down))
            Handle_Up_Down_From_Idle();                             // deal with button pressed
        else if (PreampData.UI_Action == UIAction_Input_Mute)
            Handle_Mute();
        else ;

        PreampData.UI_Action = UIAction_NULL;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Keypressed) {
        Disable_Interrupts_During_Proc;
        /* run update to counters to see if rapid value change needed */
        Digital_Preamp_UI_Fast_Slow(1, 1);   // fast, slow

        PreampData.UI_Keypressed = false;
        Re_enable_Interrupts;
    }

    if (PreampData.UI_Update_Display) {
        if (PreampData.state == Digital_Preamp_STATE_EQ_Setup)
            EQ_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_EQ_Update)
            EQ_Update_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Channel_Setup)
            Channel_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Channel_Update)
            Channel_Update_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_Monitor_Setup)
            Monitor_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_LOAD)
            Load_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SAVE)
            Save_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_IDLE)
            Idle_Screen();
        else if (PreampData.state == Digital_Preamp_STATE_SETTINGS)
            SETTINGS_Screen();
        else;

        CORETIMER_DelayMs(PreampData.UI_Update_Display_Delay);
        PreampData.UI_Update_Display = false;
    }
}


// *****************************************************************************
// *****************************************************************************
// Section: Polled State Machine
// *****************************************************************************
// *****************************************************************************
void Digital_Preamp_Tasks(void)
{
do{
    /* keep track of how often we run through the loop */
//    PreampData.UI_Update_Counter++;

    /* Signal the application's heartbeat. */
    if (PreampData.heartbeatToggle == true)
    {
        PreampData.heartbeatToggle = false;
    }

        /* Check the application's current state. */
    switch ( PreampData.state )
    {
        /* Application's initial state. */
        case Digital_Preamp_STATE_INIT:
            handleState_INIT();
            break;
        case Digital_Preamp_STATE_LCDINIT:
            handleState_LCDINIT();
            break;
        case Digital_Preamp_STATE_IDLE:
            handleState_IDLE();
            break;
        case Digital_Preamp_STATE_SETTINGS:
            handleState_SETTINGS();
            break;
        case Digital_Preamp_STATE_SAVE:
            handleState_SAVE();
            break;
        case Digital_Preamp_STATE_LOAD:
            handleState_LOAD();
            break;
        case Digital_Preamp_STATE_Monitor_Setup:
            handleState_MONITOR();
            break;
        case Digital_Preamp_STATE_Channel_Setup:
            handleState_CHANNEL_SETUP();
            break;
        case Digital_Preamp_STATE_Channel_Update:
            handleState_CHANNEL_SETUP_UPDATE();
            break;
        case Digital_Preamp_STATE_EQ_Setup:
            handleState_EQ_SETUP();
            break;
        case Digital_Preamp_STATE_EQ_Update:
            handleState_EQ_SETUP_UPDATE();
            break;
         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(PreampData.UI_Slow_Count > 0)
        PreampData.UI_Slow_Count--;


  } while (1);
}



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

