/* PIC32 Solder                                                                */
/*                                                                          */
/* V0.1 Get ADC working first                                               */
/* Numerous tweaks to the HMI                                               */
/*****************************************************************************/
#define _SUPPRESS_PLIB_WARNING 1
#include <time.h>
#include "xc.h"
#include "plib.h"
#include "delay.h"
#include "dig_cross.h"
#include <math.h>
#include <p32mx450f256h.h>
#include "stdio.h"
#include "EEPROM.h"
#include <peripheral/int.h>
#include <peripheral/ports.h>
#include "Sine_Lookup.h"
#include "graphic.h"
#include "TGM_Logo.h"
#include "KS0108.h"
#include "KS0108-PIC16.h"

// Configuration Bit settings
// SYSCLK = 100 MHz (8MHz Crystal/ FPLLIDIV * FPLLMUL / FPLLODIV)
// PBCLK = 10 MHz
// Primary Osc w/PLL (XT+,HS+,EC+PLL)
// WDT OFF
// Other options are don't care
//
#pragma config FPLLMUL = MUL_24, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_1
#pragma config UPLLIDIV = DIV_2, UPLLEN = ON
#pragma config JTAGEN = OFF
#pragma config FSRSSEL =  PRIORITY_3


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


//ADC buffers and data
unsigned int channel6;    // conversion result as read from result buffer
unsigned int channel7;    // conversion result as read from result buffer
unsigned int offset;    // buffer offset to point to the base of the idle buffer
int Measured_Temp;      // MEasured Temperature

// Graphics Buffers
unsigned char ScreenBuff[KS0108_SCREEN_HEIGHT/8][KS0108_SCREEN_WIDTH] , ScreenBuff1[KS0108_SCREEN_HEIGHT][KS0108_SCREEN_WIDTH]; 



data_val_struct Data_Values;                            /* This is where all the data is stored... */
char loop, test_temp;

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

/* You might want to move these into the display LCD function - though it is really not a gut buster for these two */
char line1[] =   Line1_Init;
char line2[] =   Line2_Init;
char *line1_ptr, *line2_ptr;				/* use these to point into the arrays */

/* These are ROM constants used in bnuilding the display */
const char Blank_Char = Blank_Char_Init;            /* ROM */
unsigned int display_temp;


/****************************************************************************/
/* Initialise the PIC							    */
/****************************************************************************/
void Init_IO(void)
{

/* clear IO LOck bit */
    CFGCON = CFGCON  & (0xFFFF - 0x2000);


/* We will eventually want to be able to set the following: */
/* IEC0 bit 4, Timer1 */
/* IEC0 bit 9, Timer2 */
/* IEC1 bit 2, USB */
/* IEC1 bit 5, SPI1TX */
//    IEC0 = 0x0000;		// Disable interrupt register 0
//    IEC1 = 0x0000;		// Disable interrupt REGISTER 1
//    IEC2 = 0x0000;		// Disable interrupt REGISTER 2

/* ADCON setup */
    ANSELB = 0x00C0;            // A/D Port reconfiguration -  bits 6 and 7 Analogue, rest dig
    ANSELC = 0x0000;		// A/D Port reconfiguration - dig
    ANSELD = 0x0000;            // A/D Port reconfiguration - dig
    ANSELE = 0x0000;		// A/D Port reconfiguration - dig
    ANSELF = 0x0000;		// A/D Port reconfiguration - dig
    ANSELG = 0x0000;            // A/D Port reconfiguration - dig

/* set peripheral pin select pins*/
/* there are lits of these.      */

/* B0 = PGED1*/
/* B1 = PGEC1*/
/* B2  = REFCLKO */
PPSOutput(3,RPB2,REFCLKO); // Set RB2 pin as output for REFCLK
/* B3  =SPARE */
/* B4  =SPARE */
/* B5  =SPARE */
/* B6  Rotary_Encoder_Select_0 (input)*/
/* B7  Rotary_Encoder_Select_1 (input)*/

/* RB8 - LCD0 (output) */
/* RB9 - LCD1 (output) */
/* RB10 - LCD2 (output) */
//RPB10R = 0x0000;
/* RB11 - LCD3 (output) */
/* RB12 - LCD4 (output) */
/* RB13 - LCD5 (output) */
/* RB14 - LCD6 (output) */
/* RB15 - LCD7 (output) */

/* RC13 = OSCILLATOR */
/* RC14 = OSCILLATOR */
/* RC12 = OSCILLATOR */
/* RC15 = OSCILLATOR */

/* RD0 = SPARE*/
/* RD1 = SPI_CS1*/
/* RD2 = SPI_SCK1*/
/* RD3 = SPI_SDI1 = "0000" = input*/
//SDI1R = 0x0000;
    PPSInput(2,RPD3,SDI1);   //Set RD3 as input for SDI1
    PPSOutput(3,RPD4,SDO1); // Set RD4 pin as output for SDO1

/* RD5 = LCD_RW (output)*/
/* RD6 = LCD_RS (output)*/
/* RD7 = LCD_CS (output)*/

/* RD8 = DSP_RESET*/
/* RD9 = SPI_SS1 - "0111"*/
    PPSOutput(3,RPD9,SS1); // Set RD4 pin as output for SS1

/* RD10 = ANALOGUE_CD*/
/* RD11 = UNUSED (output)*/

/* RE0 = Drives logic 1 as output for test board. */
/* RE1 = MODE_SEL (input)*/
/* RE2 = FN_SEL (input)*/
/* RE3 = PHASEA (input)*/
/* RE4 = PHASEB (input)*/
/* RE5 = SPARE*/
/* RE6 = SPARE*/
/* RE7 = SPARE*/

/* RF0 EEPROM CS\ - active low (output)*/
/* RF1 EEPROM Hold\ - active low (output)*/
/* RF4 UNUSED (output)*/
/* RF5 UNUSED (output)*/

/* RG6 = SPI_SCK2 */
//    PPSOutput(3,RPG6,REFCLKO); // Set RG6 pin as output for REFCLKO

/* RG7 = SPI_SDI2 "0001" */
/* RG8 = SPI_SDO2 = "0110" */
    PPSInput(2,SDI2, RPG7);   //Set Rg7 as input for SDI2
    PPSOutput(1,RPG8,SDO2); // Set Rg8 pin as output for SDO2

/* RG9 = SPI_SS2 = "0001" */
    PPSOutput(4,RPG9,SS2); // Set RG9 pin as output for SS2

/* initialise IO */
/* B6,7 = input remainder = output */
/* C = output */
/* D3 = input 0x0008*/
/* E1,2,3,4 = input 0x001E*/
/* F = output */
/* G7 = input 0X0080*/
        TRISB=0X00C0; 
        TRISC=0X0000;
        TRISD=0X0008;
        TRISE=0x001E;
        TRISF=0x0000;
        TRISG=0x0080;

/* Set outputs to normal logic */
        ODCB = 0x0000;
        ODCC = 0x0000;
        ODCD = 0x0000;
        ODCE = 0x0000;
        ODCF = 0x0000;
        ODCG = 0x0000;

/* Write to ports */
/* need to update these to appropriate values */
        PORTB = 0x0000;
        PORTC = 0x0000;
        PORTD = 0x0000;
        PORTE = 0x0001;  /* drive logic high to E0*/
        PORTF = 0x0000;
        PORTG = 0x0000;

/* Change Notice Enable = OFF*/
        CNCONB = 0X0000;
        CNCONC = 0X0000;
        CNCOND = 0X0000;
        CNCONE = 0X0000;
        CNCONF = 0X0000;
        CNCONG = 0X0000;

//mPORTBSetPinsAnalogIn(BIT_7 | BIT_6);       //Set PortB pins as Analog Inputs, AN0 : AN15

CselClearEEPROM; /* Clear EEPROM Chip Select*/
HoldClearEEPROM; /* Clear EEPROM hold signal */

/* Initialise the SPI interface */
/*
 * Channel 1
 * Master
 * Positive Pol
 * No slave enable
 * Default clock edge
 * Sample phase control
 * 8 bit character mode (dont use 16 or 32)
 * SDO pin enable (default)
 * No idle functionality
 * No debug
 * Turn SPI On
 * No frame
 *
 * fpbDiv 64
*/
SpiChnOpen(1,SPICON_MSTEN | SPICON_CKP | SPICON_ON, 256);

}

void Load_From_Memory(char Mem_Bank)
{
unsigned int Data_Addr;          /* temp address counter */

/* Select EEPROM device */
CselEEPROM;
/* Read in the parameters for crossover points from default bank of EEPROM */

/* This is the base address of the channel's data in EEPROM*/
Data_Addr = (int)Mem_Bank * ParmSet_Array_Size;


/* Temperature at Temp_Offset */
HDWordReadSPI((Data_Addr + Temp_Offset), &(Data_Values.Temperature), 4 );
/* Check limits and fix if necessary*/
if (Data_Values.Temperature < Temp_Min)
    Data_Values.Temperature = Temp_Min;
else if (Data_Values.Temperature > Temp_Max)
    Data_Values.Temperature = Temp_Min;
/* On startup default to temp min if there is an error...*/

/* Snooze Time at Snooze_Offset */
HDWordReadSPI((Data_Addr + Snooze_Time_Offset), &(Data_Values.Snooze_Time), 4 );
/* Check limits and fix if necessary*/
if (Data_Values.Snooze_Time < Snooze_Time_Min)
    Data_Values.Snooze_Time = Snooze_Time_Min;
else if (Data_Values.Snooze_Time > Snooze_Time_Max)
    Data_Values.Snooze_Time = Snooze_Time_Max;

/* Sensor Tempco at Sensor Tempco_Offset */
HDWordReadSPI((Data_Addr + Tempco_Offset), &(Data_Values.Sensor_Tempco_Val), 4 );
/* Check limits and fix if necessary*/
if (Data_Values.Sensor_Tempco_Val < Tempco_Min)
    Data_Values.Sensor_Tempco_Val = Tempco_Min;
else if (Data_Values.Sensor_Tempco_Val > Tempco_Max)
    Data_Values.Sensor_Tempco_Val = Tempco_Max;

/* Tempco Offset  at Sensot Tempco Offset */
HDWordReadSPI((Data_Addr + Offset_Offset), &(Data_Values.Sensor_Offset_Val), 4 );
/* Check limits and fix if necessary*/
if (Data_Values.Sensor_Offset_Val < Temp_Offset_Min)
    Data_Values.Sensor_Offset_Val = Temp_Offset_Min;
else if (Data_Values.Sensor_Offset_Val > Temp_Offset_Max)
    Data_Values.Sensor_Offset_Val = Temp_Offset_Max;

/* deselect EEPROM*/
CselClearEEPROM;
}


/************************************************************************/
/* 	Write Line 1 and Line 2 of LCD					*/
/************************************************************************/
void Update_LCD(void)
{

/* Clear Screen */
GLCD_ClearScreen();

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

}


/************************************************************************/
/* 						Init  			*/
/*  This is for a standard 16 x 2 character LCD... 			*/
/************************************************************************/
void Init_LCD(void)
{
unsigned char i, j;
for(j = 0; j < KS0108_SCREEN_HEIGHT/8; j++)
  {
  for(i = 0; i < KS0108_SCREEN_WIDTH; i++)
    {
      ScreenBuff[i][j] = 0;
      ScreenBuff1[i][j] = 0;
    }
  }
 
sprintf(line1, "TGM WAS HERE    ");
sprintf(line2, "Version v0.2    ");

    
/* Function Select */
/* Display On */
GLCD_Initalize();
/* Display Clear */
GLCD_ClearScreen();

GLCD_WriteCommand(DISPLAY_ON_CMD | ON, 0);
GLCD_WriteCommand(DISPLAY_ON_CMD | ON, 1);

}




/************************************************************************/
/* Display relevant data on the LCD 			
Need to build display lies for:
Display_Fn = 
	Choosing_Fn	
	Volume_Mode
	XO_Mode 
	Save_Mode
	Load_Mode
	EQ_Mode
	Change_Mode							*/
/*
and the following explicit functions
	XO_Band_Sel_Fn
	XO_Parm_Sel
	XO_LF_Parm_Fn
	XO_HF_Parm_Fn
	XO_SL_Parm_Fn
	XO_SU_Parm_Fn
	XO_Del_Parm_Fn
	XO_Att_Parm_Fn

	Save_Sel_Fn

	Load_Sel_Fn							*/

/*
#define EQ_Sel_Fn 				
#define EQ_Freq_Sel_Fn 			
#define EQ_Q_Sel_Fn  	
#define EQ_Gain_Sel_Fn 	
#define EQ_Type_Sel_Fn 	
									*/
/************************************************************************/
void Display_Data(int Display_Fn, int Display_Value)
{

/************************************************************************/
/* Choosing Value - user selecting the fuinction to modify              */
/************************************************************************/
	if (Display_Fn == Choosing_Fn)
		{
            sprintf(line1,"Function select:");
            if (Display_Value == Set_Mode)
                sprintf(line2,"Set Values      ");
            else if (Display_Value == Save_Mode)
                sprintf(line2,"Save Values     ");
            else if (Display_Value == Load_Mode)
                sprintf(line2,"Load Values     ");
            else;
		}
/************************************************************************/
/* Set Mode - user selecting the fuinction to set                       */
/************************************************************************/
	if (Display_Fn == Set_Mode)
		{
            sprintf(line1,"Value to Set:   ");
            if (Display_Value == Temp_Set)
                sprintf(line2,"Set Temperature ");
            else if (Display_Value == Sleep_Time_Set)
                sprintf(line2,"Time to Sleep   ");
            else if (Display_Value == Sensor_Tempco)
                sprintf(line2,"Sensor Temp     ");
            else if (Display_Value == Sensor_Offset)
                sprintf(line2,"Sensor Offset   ");
            else;
		}
/************************************************************************/
/* Save Function display - for Normal Save functionality        	*/
/************************************************************************/
        else if ((Display_Fn == Save_Sel_Fn) && (Display_Value <= Max_Mem_Banks))
		{
		/* Build string */
        sprintf(line1,"Save to bank: %1d", Display_Value);
        sprintf(line2,"                ");
		}
/************************************************************************/
/*Load function display							*/
/************************************************************************/
	else if (Display_Fn == Load_Sel_Fn)
		{
		/* Build string */
        sprintf(line1,"Load From bank:%1d", Display_Value);
        sprintf(line2,"                ");
		}
/************************************************************************/
/* Temperature Select Function display                                  */
/************************************************************************/
    else if ((Display_Fn == Temp_Set))
		{
    	/* Build string */
        sprintf(line1,"Set Temp: %3d    ", Data_Values.Temperature);
        sprintf(line2,"Meas Temp: %3d   ", Measured_Temp);
        }
/************************************************************************/
/* Sleep Time                                                           */
/************************************************************************/
    else if (Display_Fn == Sleep_Time_Set)
		{
		/* Build string */
        sprintf(line1,"Time until sleep ");
        sprintf(line2,"Seconds: %4d     ", Display_Value);
		}
/************************************************************************/
/* Sensor Tempco                                                        */
/************************************************************************/
    else if (Display_Fn == Sensor_Tempco)
		{
		/* Build string */
        sprintf(line1,"Sensor Temp Coef");
        sprintf(line2,"Ohms/C: %4d     ", Display_Value);
		}
/************************************************************************/
/* Sensor Offset                                                        */
/************************************************************************/
    else if (Display_Fn == Sensor_Offset)
		{
		/* Build string */
        sprintf(line1,"Sensor Offset    ");
        sprintf(line2,"Ohms at 0C: %4d  ", Display_Value);
		}

Update_LCD();		/* Writes Line1 and Line2 Strings to LCD */
}



void PRINT_Display_Debug_Data(int Display_Value)
{
    sprintf(line1,"Int: %+4d       ", Display_Value);
    sprintf(line2,"Hex: %+4x       ", Display_Value);
            

Update_LCD();		/* Writes Line1 and Line2 Strings to LCD */
}

void PRINT_Offset_Display_Debug_Data(int Display_Value)
{
    sprintf(line1,"Offset: %+4d    ", Display_Value);
    sprintf(line2,"Offset: %+4x    ", Display_Value);
            

Update_LCD();		/* Writes Line1 and Line2 Strings to LCD */
}



/****************************************************************************/
/* Uses the following globals                                               */
/* s_count                                                                  */
/* Old_Rot_Status    Records state of rotary control                        */
/* Fast_Loop_Counter  Used to set Fast_Cnt                                  */
/* Slow_Loop_Counter  Used to see if user turning control continuously      */
/*                                                                          */
/*                                                                          */
/* This sets is the ISR that deals with key presses etc                     */
/****************************************************************************/
void __ISR(_TIMER_1_VECTOR, IPL3SRS) Timer1ISR(void)
{
    unsigned char Current_Rot_Status = 0;

    /* this is debug - toggles an IO to show ISR operation*/
    //mPORTBToggleBits(BIT_9);
        /*Read Rot Status and mask off bits of interest */
	Current_Rot_Status = HMI_Port & (Vals_0 + Vals_1 + Exit + Sel);
	Key_Just_Pressed = (Current_Rot_Status != Old_Rot_Status);

	/* Only do this if something has changed - but neither of the select or exit buttons are pressed */
	if (Key_Just_Pressed  && !(Current_Rot_Status & (Sel + Exit)))
	{
            /* Old Type Encoder is biphase input on two ports with */
            /*      Each detent click of the resolver being one change in phase*/
            /*      Thus one gray code change of the inputs occurs per click*/
            if Encoder_Type_Is_Old
            {
		if (Old_Rot_Status == Phase_0)  /* From here need to work out if going up or down */
		{
			if (Current_Rot_Status == Phase_1)
				Keypress_Read = Rot_Up;
			else
				Keypress_Read = Rot_Down;
		}
		else if (Old_Rot_Status == Phase_1)  /* From here need to work out if going up or down */
		{
			if (Current_Rot_Status == Phase_2)
				Keypress_Read = Rot_Up;
			else
				Keypress_Read = Rot_Down;
		}
		else if (Old_Rot_Status == Phase_2)  /* From here need to work out if going up or down */
		{
			if (Current_Rot_Status == Phase_3)
				Keypress_Read = Rot_Up;
			else
				Keypress_Read = Rot_Down;
		}
		else if (Old_Rot_Status == Phase_3)  /* From here need to work out if going up or down */
		{
			if (Current_Rot_Status == Phase_0)
				Keypress_Read = Rot_Up;
			else
				Keypress_Read = Rot_Down;
		}
            }
            /* Type A Encoder is biphase input on two ports with */
            /*      Each detent click of the resolver being four changes in phase*/
            /*      Thus one complete cycle of gray code occurs per click*/
            /*      Type A goes 11 -> 10 -> 00 -> 01 -> 11 and vice versa*/
            else if Encoder_Type_Is_TypeA
            {
                /* Phase_0 = 00*/
                /* From here need to work out if going up or down or reading crap*/
                /* CW 00 -> 01 */
                /* CCW 00-> 10 */
                /* But we do not want to act on these as it is mid-click*/
                if (Old_Rot_Status == Phase_0)
		{
                   /* Have read crap*/
                    Keypress_Read = 0;
		}
                /* From here need to work out if going up or down or reading crap*/
                /* CW 01 -> 11 */
                /* CCW 01-> 00 */
                /* But we do not want to act on these as it is mid-click*/
		else if (Old_Rot_Status == Phase_1)
		{
                   /* Have read crap*/
                    Keypress_Read = 0;
		}
                /* From here need to work out if going up or down or reading crap*/
                /* CW 11 -> 10 */
                /* CCW 11-> 01 */
                /* This is it... do something*/
		else if (Old_Rot_Status == Phase_2)
		{
			if (Current_Rot_Status == Phase_3)
				Keypress_Read = Rot_Down;
			else if (Current_Rot_Status == Phase_1)
				Keypress_Read = Rot_Up;
                        else Keypress_Read = 0;
		}
                /* From here need to work out if going up or down or reading crap*/
                /* CW 10 -> 00 */
                /* CCW 10-> 11 */
                /* But we do not want to act on these as it is mid-click*/
		else if (Old_Rot_Status == Phase_3)
		{
                   /* Have read crap*/
                    Keypress_Read = 0;
                }
            }
            /* Type B Encoder is biphase input on two ports with */
            /*      Each detent click of the resolver being three changes in phase*/
            /*      Thus one complete cycle of pseudo gray code occurs per click*/
            /*      Type B is asymetric for CW and CCW rotation*/
            /*      Type B goes 11 -> 00 -> 01 -> 11 for CW*/
            /*      Type B goes 00 -> 01 -> 00 -> 11 for CCW*/
            else if Encoder_Type_Is_TypeB
            {
                /* Phase_0 = 00*/
                /* From here need to work out if going up or down or reading crap*/
                /* CW 00 -> 01 */
                /* CCW 00-> 11 */
                /* But we do not want to act on these */
		if (Old_Rot_Status == Phase_0)
		{
                   /* Have read crap*/
                    Keypress_Read = 0;
		}
                /* Phase_1 = 01*/
                /* From here need to work out if going up or down or reading crap*/
                /* CW  01 -> 11 */
                /* CCW 01 -> 00 */
                /* But we do not want to act on these */
		else if (Old_Rot_Status == Phase_1)
		{
                   /* Have read crap*/
                    Keypress_Read = 0;
		}
                /* Phase_2 = 11*/
                /* OK This is it... */
                /* CW  11 -> 00 */
                /* CCW 11 -> 01 */
                /* But we do not want to act on these */
		else if (Old_Rot_Status == Phase_2)
		{
			if (Current_Rot_Status == Phase_0)
                            Keypress_Read = Rot_Up;
			else if (Current_Rot_Status == Phase_3)
                            Keypress_Read = Rot_Down;
                        else
                            Keypress_Read = 0;
		}
                /* Phase_3 = 10*/
                /* We are reading crap - illegal for this encoder*/
                /* We do not want to act on these */
		else if (Old_Rot_Status == Phase_3)  /* From here need to work out if going up or down */
		{
                   /* Have read crap*/
                    Keypress_Read = 0;
                }
                else
                {
                    Keypress_Read = 0;
                }
            }

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

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

	if (Slow_Loop_Counter == (unsigned int)0)
	{
		Fast_Change = 1;
		Fast_Loop_Counter = Fast_Counter_Init;
	}

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

	Old_Rot_Status = Current_Rot_Status;   /*Record Rot Status to allow comparison next ISR loop */

        /* This is debug */
//        mPORTBToggleBits(BIT_9);

        // set timer to zero then clear the interrupt flag
        TMR1 = 0x0000;
        mT1ClearIntFlag();
}


/****************************************************************************/
/****************************************************************************/
void main(void) {
char Update_Display = 1; 		/* Flag saying need to update display */
int Freq_Speed = 1; /* use this to keep track of How Fast to count Frequency */
long int Auto_Revert = Auto_Revert_Init_Val;
int Mode;           /* use to track mode */
					/* Use this as a counter - after 255 loops auto revert to volume mode */
char Band = 0;           		/* use to drive state machine band select */
int Step_Size = 0;        		/* Use this to implement push button steps */
int Display_Value = 0;                  /* use this to display the current value */
char Memory_Bank = Default_Mem_Bank;    /* use this to track which memory bank is in use */
unsigned int Channel_Mem_Offset;        /* used to implement channel 1 & 2 offset on save call */
int Sel_Fn = Choosing_Fn;		/* Use this to track current Selection */
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//STEP 1. Configure cache, wait states and peripheral bus clock
// Configure the device for maximum performance but do not change the PBDIV
// Given the options, this function will change the flash wait states, RAM
// wait state and enable prefetch cache but will not change the PBDIV.
// The PBDIV value is already set via the pragma FPBDIV option above..
SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);


// Configure ADC subsystem
// define setup parameters for OpenADC10
// Turn module on | ouput in integer | trigger mode auto | enable autosample
#define PARAM1  ADC_MODULE_ON | ADC_FORMAT_INTG32 | ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON
// define setup parameters for OpenADC10
// ADC ref external    | disable offset test    | disable scan mode | perform 2 samples | use dual buffers | use alternate mode
#define PARAM2  ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_2 | ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON
// define setup parameters for OpenADC10
// use ADC internal clock | set sample time
#define PARAM3  ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_12
// define setup parameters for OpenADC10
// do not assign channels to scan
#define PARAM5    SKIP_SCAN_ALL
// define setup parameters for OpenADC10
// set AN6 and AN7 as analog inputs
#define PARAM4    ENABLE_AN6_ANA | ENABLE_AN7_ANA
// use ground as neg ref for A | use AN6 for input A      |  use ground as neg ref for A | use AN7 for input B
// configure to sample AN6 & AN7
CloseADC10();    // ensure the ADC is off before setting the configuration
SetChanADC10( ADC_CH0_NEG_SAMPLEA_NVREF | ADC_CH0_POS_SAMPLEA_AN6 |  ADC_CH0_NEG_SAMPLEB_NVREF | ADC_CH0_POS_SAMPLEB_AN7); // configure to sample AN6 & AN7
OpenADC10( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5 ); // configure ADC using parameter define above
// Enable the ADC
EnableADC10(); // Enable the ADC

// configure for multi-vectored mode
INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);

/* intitialise the Micro I/O ports*/
Init_IO();
/*Allows LCD to settle*/
DelayMs(100);

CselClearEEPROM;        /* just to be clear on this for the EEPROM*/
Measured_Temp = 0;      /* initialise measured temp value */

Init_LCD();				/* initialise the LCD */
Update_LCD();			/* Writes Line1 and Line2 to LCD */
DelayMs(500);
/* Initialise and load parameters from EEPROM - we need these to load defaults & saved values */

Load_From_Memory(Default_Mem_Bank); /* Read Data from ROM */

/****************************************************************************/
/* Get reasonable initialisation, go straight to volume			*/
/****************************************************************************/
Sel_Fn = Temp_Set;
Display_Value = Data_Values.Temperature;
Display_Data(Sel_Fn, Display_Value);

/* give things a bit to settle */
Step_Size = 0;
Key_Just_Pressed = 0;

/****************************************************************************/
/* This sets up the test ISR 					  	    */
/* Should be about 500us cycle 						    */
/****************************************************************************/
/* We will eventually want to be able to set the following: */
/* IEC0 bit 4, Timer1 */
/* IEC0 bit 9, Timer2 */
/* IEC1 bit 2, USB */
/* IEC1 bit 5, SPI1TX */
//turn t1 off
T1CON = 0X0;
// Clear the timer
TMR1 = 0x0000;
//Sets period register
PR1 = 0xFFFF;
// Open the timer
// T1_TICK = 1/256 seconds - we want 500uS
// T1_TICK/4 is what we want...
//test undo me
OpenTimer1(T1_ON | T1_SOURCE_INT | T1_PS_1_8, (T1_TICK/4));
// set up the timer interrupt with a priority of 2
// set up the timer interrupt with a priority of 2
INTSetVectorPriority(INT_TIMER_1_VECTOR, INT_PRIORITY_LEVEL_3);
INTSetVectorSubPriority(INT_TIMER_1_VECTOR, INT_SUB_PRIORITY_LEVEL_3);
ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_3 | T1_INT_SUB_PRIOR_3);
INTClearFlag(INT_T1);
INTEnable(INT_T1, INT_ENABLED);

// enable interrupts
INTEnableInterrupts();

/* test code for ADC*/
Buffer_Refresh(TGM_Logo_Full, 0, 0, 128, 64)
DelayMs(1000);
// wait for the first conversion to complete so there will be vaild data in ADC result registers

while ( ! mAD1GetIntFlag() ){} // wait for the first conversion to complete so there will be vaild data in ADC result registers

// the results of the conversions are available in channel6 and channel7
//    offset = 8 * ((~ReadActiveBufferADC10() & 0x01));  // determine which buffer is idle and create an offset
//    offset = 0;
//        AcquireADC10();
//       channel6 = ReadADC10(offset);
//        PRINT_Offset_Display_Debug_Data(offset); 
//        PRINT_Display_Debug_Data(channel6); 

Update_Display = 1;
Display_Data(Sel_Fn, Display_Value);


do{
           offset = 8 * ((~ReadActiveBufferADC10() & 0x01));  // determine which buffer is idle and create an offset
           offset = 0;
           AcquireADC10();
           channel6 = ReadADC10(offset);
           //PRINT_Offset_Display_Debug_Data(offset); 
           PRINT_Display_Debug_Data(channel6);
           DelayMs(3000);
           channel6 = ReadADC10(offset+1);
           //PRINT_Offset_Display_Debug_Data(offset); 
           PRINT_Display_Debug_Data(channel6 + 10000);
           DelayMs(3000);}
while(1);

/* the main loop that runs the HMI - when it is not being interrupted!*/
do
{
/* Look after changing modes */

    mPORTBToggleBits(BIT_10);
    Nop();

	if (Key_Just_Pressed)
	{
		Update_Display = 1;
		Auto_Revert = Auto_Revert_Init_Val;		/* If key pressed, reset the counter */

		/********************************************************************/
		/* Currently in Change Mode - act on legal button presses 			*/
		/********************************************************************/
		if (Sel_Fn == Choosing_Fn)
		{
			/* Up or Down*/
			if (Up_Keys || Down_Keys)
			{
				if (Up_Keys)
					Mode += 1;
				else
					Mode -= 1;
				/* check for wrap around */
				if (Mode > Load_Mode)
					Mode = Set_Mode;
				if (Mode < Set_Mode)
					Mode = Load_Mode;
			}

			/* Select Key hit */
			else if Sel_Key
			{
				Sel_Fn = Mode;
			}
			/* Exit */
			else if Exit_Key
			{
				Sel_Fn = Choosing_Fn;
			}
			else;

			if (Sel_Fn == Choosing_Fn)
				Display_Value = Mode;
            else if (Sel_Fn == Set_Mode)
				Display_Value = Temp_Set;
            else if (Sel_Fn == Load_Sel_Fn)
				Display_Value = Memory_Bank;
            else if (Sel_Fn == Save_Sel_Fn)
				Display_Value = Memory_Bank;
			else;
        }

		/********************************************************************/
		/* Currently in Set Function - act on legal button presses          */
		/********************************************************************/
        else if (Sel_Fn == Set_Mode)
		{
			/* Down */
			if Down_Keys
			{
				Mode -= 1;
				if (Mode < Temp_Set)
                    Mode = Sensor_Offset;
                else if (Mode > Sensor_Offset)
                    Mode = Temp_Set;
			}
			/* Up */
			else if Up_Keys
			{
				Mode += 1;
				if (Mode > Sensor_Offset)
                    Mode = Temp_Set;
                else if (Mode < Temp_Set)
                    Mode = Sensor_Offset;
			}
			else if Sel_Key
			{
				Sel_Fn = Mode;
			}
			else if Exit_Key
			{
				Sel_Fn = Choosing_Fn;
				Display_Value = Mode;
			}
			else;
            
            if (Sel_Fn == Temp_Set)
				Display_Value = Data_Values.Temperature;
            else if (Sel_Fn == Sleep_Time_Set)
				Display_Value = Data_Values.Snooze_Time;
            else if (Sel_Fn == Sensor_Tempco)
				Display_Value = Data_Values.Sensor_Tempco_Val;
            else if (Sel_Fn == Sensor_Offset)
				Display_Value = Data_Values.Sensor_Offset_Val;
			else
                Display_Value = Mode;

        }

        /********************************************************************/
		/* Set Temp                                                         */
		/********************************************************************/
        else if (Sel_Fn == Temp_Set)
		{
                    if(Fast_Change > 1)
                        Freq_Speed =  10;  /* boost speed */
                    else
                        Freq_Speed = 1; /* reset it...*/

			/* Down */
			if Down_Keys
			{
				Data_Values.Temperature = Data_Values.Temperature - Freq_Speed;
				if ((Data_Values.Temperature) <  Temp_Min)
                    Data_Values.Temperature =  Temp_Min;
				Display_Value = Data_Values.Temperature;
			}
			/* Up */
			else if Up_Keys
			{
				Data_Values.Temperature = Data_Values.Temperature + Freq_Speed;
				if ((Data_Values.Temperature) >  Temp_Max)
                    Data_Values.Temperature =  Temp_Max;
				Display_Value = Data_Values.Temperature;
			}
			else if Sel_Key
			{
				Sel_Fn = Choosing_Fn;
				Display_Value = Set_Mode;
			}
			else if (Keypress_Read == Exit)
			{
				Sel_Fn = Choosing_Fn;
				Display_Value = Set_Mode;
			}
			else;
        }
       /********************************************************************/
		/* Set Sleep Time                                                   */
		/********************************************************************/
        else if (Sel_Fn == Sleep_Time_Set)
		{
            if(Fast_Change > 1)
                Freq_Speed =  10;  /* boost speed */
            else
                Freq_Speed = 1; /* reset it...*/

			/* Down */
			if Down_Keys
			{
				Data_Values.Snooze_Time = Data_Values.Snooze_Time - Freq_Speed*10;
				if ((Data_Values.Snooze_Time) <  Snooze_Time_Min)
                    Data_Values.Snooze_Time =  Snooze_Time_Min;
				Display_Value = Data_Values.Snooze_Time;
			}
			/* Up */
			else if Up_Keys
			{
				Data_Values.Snooze_Time = Data_Values.Snooze_Time + Freq_Speed*10;
				if ((Data_Values.Snooze_Time) >  Snooze_Time_Max)
                    Data_Values.Snooze_Time =  Snooze_Time_Max;
				Display_Value = Data_Values.Snooze_Time;
			}
			else if Sel_Key
			{
				Sel_Fn = Choosing_Fn;
				Display_Value = Set_Mode;
			}
			else if (Keypress_Read == Exit)
			{
				Sel_Fn = Choosing_Fn;
				Display_Value = Set_Mode;
			}
			else;
        }
        /********************************************************************/
		/* Set Sensor Tempco                                               */
		/********************************************************************/
        else if (Sel_Fn == Sensor_Tempco)
		{
			/* Down */
			if Down_Keys
			{
				Data_Values.Sensor_Tempco_Val = Data_Values.Sensor_Tempco_Val - 1;
				if ((Data_Values.Sensor_Tempco_Val) <  Tempco_Min)
                    Data_Values.Sensor_Tempco_Val =  Tempco_Min;
				Display_Value = Data_Values.Sensor_Tempco_Val;
			}
			/* Up */
			else if Up_Keys
			{
				Data_Values.Sensor_Tempco_Val = Data_Values.Sensor_Tempco_Val + 1;
				if ((Data_Values.Sensor_Tempco_Val) >  Tempco_Max)
                    Data_Values.Sensor_Tempco_Val =  Tempco_Max;
				Display_Value = Data_Values.Sensor_Tempco_Val;
			}
			else if Sel_Key
			{
				Sel_Fn = Sensor_Offset;
				Display_Value = Data_Values.Sensor_Offset_Val;
			}
			else if (Keypress_Read == Exit)
			{
				Sel_Fn = Choosing_Fn;
				Display_Value = Set_Mode;
			}
			else;
        }
        /********************************************************************/
		/* Set Sensor Offset                                               */
		/********************************************************************/
        else if (Sel_Fn == Sensor_Offset)
		{
			/* Down */
			if Down_Keys
			{
				Data_Values.Sensor_Offset_Val = Data_Values.Sensor_Offset_Val - 1;
				if ((Data_Values.Sensor_Offset_Val) <  Temp_Offset_Min)
                    Data_Values.Sensor_Offset_Val =  Temp_Offset_Min;
				Display_Value = Data_Values.Sensor_Offset_Val;
			}
			/* Up */
			else if Up_Keys
			{
				Data_Values.Sensor_Offset_Val = Data_Values.Sensor_Offset_Val + 1;
				if ((Data_Values.Sensor_Offset_Val) >  Temp_Offset_Max)
                    Data_Values.Sensor_Offset_Val =  Temp_Offset_Max;
				Display_Value = Data_Values.Sensor_Offset_Val;
			}
			else if Sel_Key
			{
				Sel_Fn = Temp_Set;
				Display_Value = Data_Values.Temperature;
			}
			else if (Keypress_Read == Exit)
			{
				Sel_Fn = Choosing_Fn;
				Display_Value = Set_Mode;
			}
			else;
        }

        /************************************************************************/
		/* Currently in SAVE Function, act on legal button presses				*/
		/************************************************************************/
		else if(Sel_Fn == Save_Sel_Fn)
		{
			/*		This section miplements the save function 					*/
			/* Up 																*/
			if Up_Keys
			{
				Memory_Bank += 1;
				if (Memory_Bank > Max_Mem_Banks)
					Memory_Bank = Default_Mem_Bank;
				Display_Value = Memory_Bank;
			}
			/* Down */
			else if Down_Keys
			{
				if (Memory_Bank == Default_Mem_Bank)
					Memory_Bank = Max_Mem_Banks;
				else
					Memory_Bank -= 1;
				Display_Value = Memory_Bank;
			}
			/* Select Key hit */
            /* write memory for normal save operations */
            else if (Sel_Key && (Memory_Bank <= Max_Mem_Banks))
			{

			/********************************************************************/
			/*		Save the data                                       */
			/********************************************************************/
                Channel_Mem_Offset =  Memory_Bank * ParmSet_Array_Size;
                HDWordWriteSPI(Channel_Mem_Offset + Temp_Offset, Data_Values.Temperature);
                HDWordWriteSPI(Channel_Mem_Offset + Snooze_Time_Offset, Data_Values.Snooze_Time);
                HDWordWriteSPI(Channel_Mem_Offset + Tempco_Offset, Data_Values.Sensor_Tempco_Val);
                HDWordWriteSPI(Channel_Mem_Offset + Offset_Offset, Data_Values.Sensor_Offset_Val);
                
                Sel_Fn = Choosing_Fn;
				Mode = Set_Mode;
				Display_Value = Mode;
			}
			/* Exit */
			else if Exit_Key
			{
				Step_Size = 1;
				Sel_Fn = Choosing_Fn;
				Mode = Set_Mode;
				Display_Value = Mode;
			}
			else;
		}

		/************************************************************************/
		/* Currently in LOAD Function, act on legal button presses 				*/
		/************************************************************************/
		else if(Sel_Fn == Load_Sel_Fn)
		{
			/********************************************************************/
			/*		This section miplements the load data function 				*/
			/********************************************************************/
			/* Up */
			if Up_Keys
			{
				Memory_Bank += 1;
				if (Memory_Bank > Max_Mem_Banks)
					Memory_Bank = Default_Mem_Bank;
				Display_Value = Memory_Bank;
			}
			/* Down */
			else if Down_Keys
			{
				if (Memory_Bank == Default_Mem_Bank)
					Memory_Bank = Max_Mem_Banks;
				else
					Memory_Bank -= 1;
				Display_Value = Memory_Bank;
			}
			/* Select Key hit */
			else if Sel_Key
			{
                /***********************************************/
				/*		Load the data                   */
				/***********************************************/
				Load_From_Memory(Memory_Bank); /* Read Data from ROM */
				Sel_Fn = Choosing_Fn;
				Display_Value = Set_Mode;
            }
            /************************************************************************/
           	/* Exit                                                                 */
           	/************************************************************************/
			else if Exit_Key
			{
				Step_Size = 0;
				Sel_Fn = Choosing_Fn;
				Display_Value = Set_Mode;
			}
                }


		/************************************************************************/
		/* Else key not pressed, and nothing to display                         */
		/************************************************************************/
		else
            Update_Display = 0;


		if (Update_Display)
			Display_Data(Sel_Fn, Display_Value);
		else;


	}  /* Done changing values for the user */


	/* Clears the flag saying that the push button press has been addressed */
	Step_Size = 0;

	Auto_Revert = Auto_Revert - 1;   /* If no key pressed, then decrement this counter */
	if 	(Auto_Revert <= 0)   	/* Then force the system to volume mode */
		{
                        /* If key pressed, reset the counter */
                        Auto_Revert = Auto_Revert_Init_Val;
			Band = 0;
                        Sel_Fn = Choosing_Fn;
			Display_Value = Mode;
			Display_Data(Sel_Fn, Display_Value);
		}

        /* delay in main loop to allow the HMI to work at a sane speed */
        DelayUs(Key_Press_Delay_Us);

	}
        /* and just stay in this loop till forever...*/
        while (1);
}
