#include <p18cxxx.h>
#include <delays.h>
#include <math.h>

#pragma config WDT = OFF


////----------------------------------------------------------------------------
///*** START: USB BOOTLOADER CODE ******
////---------------------------------------------------------------------------

///** V A R I A B L E S ********************************************************/
//#pragma udata
//
///** P R I V A T E  P R O T O T Y P E S ***************************************/
//
///** V E C T O R  R E M A P P I N G *******************************************/
//
//extern void _startup (void);        // See c018i.c in your C18 compiler dir
//
//#pragma code _RESET_INTERRUPT_VECTOR = 0x000800
//    void _reset (void)
//    {
//        _asm goto _startup _endasm
//    }
//#pragma code
//
//#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808
//    void _high_ISR (void)
//    {
//        ;
//    }
//
//    #pragma code _LOW_INTERRUPT_VECTOR = 0x000818
//        void _low_ISR (void)
//        {
//            ;
//        }
//    #pragma code
//
//#pragma code

////----------------------------------------------------------------------------
////** END:  USB BOOTLOADER CODE **
////----------------------------------------------------------------------------


//----------------------------------------------------------------------------
// ** START:  ASHRAE Defs **
//----------------------------------------------------------------------------

////function declaration
//float calc_temp(float RH, unsigned char PPD_level, unsigned char hc);
//
//clothing parameter, normally in between .5 for summer clothing and 1 for winter clothing
//metabolic rate, for this study was 1.1
#define MET	1.1
//external work, normally around 0
#define WME 0
//relative air velocity
#define VEL .10

//globals
//clothing parameter which depends on
float CLO;
//outside ambient temperature
float TA;
float TEMPA;
float PA;
float TR;
//saturated vapor pressure
float FNPS;
//thermal insulation of clothes
float ICL;
//metabolic rate
float M;
//external work
float WO;
//internal heat
float MW;
//clothing area factor
float FCL;
//heat transfer
float HCF;
//air temperature
float TAA;
float TRA;
float TCLA;
float P1,P2,P3,P4,P5;
float XN;
float XF;
float EPS;	
float TCL, HCN, HC, HL1, HL2, HL3, HL4, HL5, HL6, TS, PMV, PPD;
int loop, ashcount, ashcountcounter;

unsigned char hc;



//----------------------------------------------------------------------------
// ** END:  ASHRAE Defs **
//----------------------------------------------------------------------------


//----------------------------------------------------------------------------
// ** START:  SHT10 Delay Defs **
//----------------------------------------------------------------------------

//
// *	Delay functions for C18 version 2.40 on the PIC
//prama config
//#pragma config PLLDIV = 5			// This value has to be 5 for 20Mhz xtal as PLL accepts fixed input of 4MHz only
//#pragma config USBDIV = 2			// Clock source from 96MHz PLL/2, therefore USB clock is 48MHz in full speed
//#pragma config FOSC   = HSPLL_HS	// HS oscillator, PLL enabled
//#pragma config CPUDIV = OSC4_PLL6	// 96MHz PLL Src/6 => a CPU clock of 16MHz achieved for Vdd=3.3V
//#pragma config PWRT   = ON			// PowerUp timer ON
////#pragma config WDT    = OFF			// watchdog timer off
//#pragma config LVP    = OFF			// low level voltage progamming OFF
//#pragma config BOR    = OFF			// brown out detect off
//#pragma config DEBUG  = ON			// Debug ON
//#pragma config PBADEN = OFF 		// PORTB<4:0> as digital IO on reset
//#pragma config STVREN = ON  		// Stack overflow reset ON
//#pragma config VREGEN = OFF			// Disable internal 3.3V regulator!
// *	Functions available:
// *		DelayUs(x)	Delay specified number of microseconds
// *		DelayMs(x)	Delay specified number of milliseconds
// *
// *	Note that there are range limits: x must not exceed 255 - for xtal
// *	frequencies > 12MHz the range for DelayUs is even smaller.
// *	To use DelayUs it is only necessary to include this file; to use
// *	DelayMs you must include delay.c in your project.
// *
// */


unsigned char tempdata[4];
unsigned char humidata[4];
unsigned char ashdata[4];





#ifndef	XTAL_FREQ
#define	XTAL_FREQ	16MHZ		/* Crystal frequency in MHz */
#endif


#define	MHZ	*1000L			/* number of kHz in a MHz */
#define	KHZ	*1				/* number of kHz in a kHz */

#if	XTAL_FREQ >= 12MHZ

#define	DelayUs(x)	{ unsigned char _dcnt; \
			  _dcnt = (x)*((XTAL_FREQ)/(12MHZ)); \
			  while(--_dcnt != 0) \
				  continue; }
#else

#define	DelayUs(x)	{ unsigned char _dcnt; \
			  _dcnt = (x)/((12MHZ)/(XTAL_FREQ))|1; \
			  while(--_dcnt != 0) \
				  continue; }
#endif

extern void DelayMs(unsigned char);

//    ---delays.c

void DelayMs(unsigned char cnt)
{
#if	XTAL_FREQ <= 2MHZ
	do {
		DelayUs(996);
	} while(--cnt);
#endif

#if    XTAL_FREQ > 2MHZ	
	unsigned char	i;
	do {
		i = 4;
		do {
			DelayUs(250);
		} while(--i);
	} while(--cnt);
#endif
}

// *** sht10.c

typedef union
{
	unsigned int i;
	float f;
} value;

//globals
value humi_val, temp_val;

//port definitions
#define DATA_WR		LATAbits.LATA2
#define	DATA_RD   	PORTAbits.RA2
#define	SCK   		LATAbits.LATA0
#define DATA_TRIS	TRISAbits.TRISA2
#define SCK_TRIS	TRISAbits.TRISA0

//enumeration for holding data
enum {TEMP,HUMI};

//function prototypes
char s_softreset(void);
char s_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode);
char s_write_statusreg(unsigned char *p_value);
char s_read_statusreg(unsigned char *p_value, unsigned char *p_checksum);
void s_transstart(void);
void s_connectionreset(void);
char s_read_byte(unsigned char ack);
char s_write_byte(unsigned char value);
void SHT10_Get(void);
void ftoa(unsigned char *buf, float f);

void Delay_1sec(void);
void Delay_250ms(void);
void Delay_30ms(void);
void XLCDCommand(unsigned char cmd);
void XLCD_Init(void);
void XLCD_Put(char data);
void LCD_Menus(char menu);
void Menu_Select(void);
void Version_Display(void);

float calc_temp(float RH, unsigned char PPD_level, unsigned char hc);

void control_devices();

void LCD_Menu_Execute(char menu);

void Show_Values();



//address definitions to control device
                            //adr  command  r/w
#define STATUS_REG_W 0x06   //000   0011    0
#define STATUS_REG_R 0x07   //000   0011    1
#define MEASURE_TEMP 0x03   //000   0001    1
#define MEASURE_HUMI 0x05   //000   0010    1
#define RESET        0x1e   //000   1111    0

#define noACK 			0
#define ACK   			1



//function prototypes
//function: char s_softreset(void)
//purpose: to soft reset the device
//receive: void
//return: void
char s_softreset(void)
{ 
  	unsigned char error=0;  
  	s_connectionreset();              //reset communication
	error+=s_write_byte(RESET);       //send RESET-command to sensor
	return error;                     //error=1 in case of no response from the sensor
}

//function: char s_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode)
//purpose: to measure the data from the device depending on operation
//receive: data pointers, a mode for either temperature or humidity measurement
//return: void
char s_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode)
{ 
	unsigned error=0;
 	unsigned int i;

 	s_transstart();                   //transmission start
  
	switch(mode)
	{                     //send command to sensor
    	case TEMP	: error+=s_write_byte(MEASURE_TEMP); break;
    	case HUMI	: error+=s_write_byte(MEASURE_HUMI); break;
    	default     : break;	 
  	}
  
	(mode==HUMI)?DelayMs(55):DelayMs(210);
  
	for (i=0;i<65535;i++) 
		if(DATA_RD==0) break;	//wait until sensor has finished the measurement
  
	if(DATA_RD) 
		error+=1; 						//or timeout (~2 sec.) is reached

  	*(p_value+1)  = s_read_byte(ACK);    		//read the first byte (MSB)
  	*(p_value)	= s_read_byte(ACK);    	 	//read the second byte (LSB)
  	*p_checksum 	= s_read_byte(noACK);  		//read checksum

  	return error;
}

//function: void s_transstart(void)
//purpose: to start a transmission with the device
//receive: void
//return: void
void s_transstart(void)
{  
	SCK=0;                   //Initial state
   	DATA_TRIS = 1;			//pullup resistor brings DATA pin high
  	DelayUs(1);
  	SCK=1;
   	DelayUs(1);
   	DATA_WR=0; DATA_TRIS=0;
   	DelayUs(1);
   	SCK=0;  
   	DelayUs(5);
   	SCK=1;
   	DelayUs(1);
   	DATA_TRIS=1;		   		//pullup resistor brings DATA pin high
   	DelayUs(1);
   	SCK=0;	   
}

//function: void s_connectionreset(void)
//purpose: to reset the connection with the device
//receive: void
//return: void
void s_connectionreset(void)
{  
 	unsigned char i;
	DATA_WR     = 1;			//set data pin high
	DATA_TRIS 	= 0; 			//set data pin an output
	SCK			= 0; 
	SCK_TRIS	= 0;			//set CLK pin an output low

  	for(i=0;i<9;i++)             	//9 SCK cycles for connection reset sequence
  	{ 
		SCK=1;
		DelayUs(1);
    	SCK=0;
		DelayUs(1);
  	}
  
	s_transstart();            	//transmission start
}

//function: char s_read_byte(unsigned char ack)
//purpose: to read a byte of data from the DATA line
//receive: an acknowledge char
//return: the data
char s_read_byte(unsigned char ack)
{ 
 	unsigned char i,val=0;
  	DATA_TRIS = 1;                    //set DATA line an input
  	SCK = 0;
  
	for (i=0x80;i>0;i/=2)             //shift bit for masking
  	{ 
		SCK=1;                          //clk for SENSI-BUS
		DelayUs(2);
    	
		if (DATA_RD) 
			val=(val | i);        //read bit  
    
		SCK=0;  					 
		DelayUs(2);
  	}
	
	if(ack==ACK)
	{
		DATA_TRIS = 0; 
		DATA_WR = 0;
	}
  	
	SCK=1;                          //clk #9 for ack
	DelayUs(5);						//pulse-width approx. 5 us         	
  	SCK=0;					    
  	DATA_TRIS = 1;                  //release DATA-line
  	
	return val;
}

//function: char s_write_byte(unsigned char value) 
//purpose: to write a byte of data to the device, a command
//receive: a value to write, the command
//return: a char, describing any error during transmission
char s_write_byte(unsigned char value) 
{ 
  	unsigned char i,error=0;  

  	DATA_TRIS = 0;
  
	for (i=0x80;i>0;i/=2)             			//shift bit for masking
  	{ 
		if (i & value) 
			DATA_WR=1;          			//masking value with i , write to SENSI-BUS
    	else 
			DATA_WR=0;                        
    
		SCK=1;                          			//clk for SENSI-BUS
		DelayUs(5);	   								//pulse-width approx. 5 us 
    	SCK=0;
		DelayUs(5);
  	}
  	
	DATA_TRIS=1;                           		//release DATA-line, let SHT10 sensor controls DATA line
  	SCK=1;                            			//clk #9 for ack 
  	error=DATA_RD;                       			//check ack (DATA will be pulled down by SHT11)
  	SCK=0;        
  
	return error;                     			//error=1 in case of no acknowledge
}

//other functions
//function: void calc_sht1x(float *p_humidity ,float *p_temperature)
//purpose: to convert the data stream from the device into a real-life value
//receive: humidity and temperature data garnered from the device
//return: void
void calc_sht1x(float *p_humidity ,float *p_temperature)
// calculates temperature [°C] and humidity [%RH] 
// input :  humi [Ticks] (12 bit) 
//          temp [Ticks] (14 bit)
// output:  humi [%RH]
//          temp [deg Cel]
{ float rh=*p_humidity;             				// rh:      Humidity [Ticks] 12 Bit 
  float t=*p_temperature;           				// t:       Temperature [Ticks] 14 Bit
  float rh_lin;                     				// rh_lin:  Humidity linear
  float rh_true;                    				// rh_true: Temperature compensated humidity
  float t_C;                        				// t_C   :  Temperature [°C]

  t_C=t*0.01 - 40;                  				//calc. temperature from ticks to [deg Cel]	
  rh_lin=0.0405*rh - 0.0000028*rh*rh - 4.0;     	//calc. humidity from ticks to [%RH]
  rh_true=(t_C-25)*(0.01+0.00008*rh)+rh_lin;   		//calc. temperature compensated humidity [%RH]
  if(rh_true>100)rh_true=100;       				//cut if the value is outside of
  if(rh_true<0.1)rh_true=0.1;       				//the physical possible range

  *p_temperature=t_C;               				//return temperature [deg Cel]
  *p_humidity=rh_true;              				//return humidity[%RH]
}

//function: void ftoa(unsigned char *buf, float f)
//purpose: to convert the float into a string with one decimal precision
//receive: the float
//return: void
void ftoa(unsigned char *buf, float f) 
{
	unsigned int rem;
	unsigned char *s,length=0;
	int i;

	i = (int)((float)f*10);

	s = buf;
	if (i == 0){ 		//print 0.0 with null termination here
		*s++ = '0';
		*s++ = '.';
		*s++ = '0'; 
		*s=0; 			//null terminate the string
	} else {	
		if (i < 0) {
			*buf++ = '-';
			s = buf;
			i = -i;
		}
		//while-loop to "decode" the long integer to ASCII by append '0', string in reverse manner
		//If it is an integer of 124 -> string = {'4', '2', '1'}
		while (i) {
			++length;
			rem = i % 10;
			*s++ = rem + '0';
			i /= 10;
		}
		//reverse the string in this for-loop, string became {'1', '2', '4'} after this for-loop
		for(rem=0; ((unsigned char)rem)<length/2; rem++) {
			*(buf+length) = *(buf+((unsigned char)rem));
			*(buf+((unsigned char)rem)) = *(buf+(length-((unsigned char)rem)-1));
			*(buf+(length-((unsigned char)rem)-1)) = *(buf+length);
		}

		/* Take care of the special case of 0.x if length ==1*/	
		if(length==1) {
			*(buf+2) = *buf;
			*buf = '0';
			*(buf+1) = '.';
			*(s+2)=0; 			//null terminate
		} else {
			*(buf+length) = *(buf+length-1);
			*(buf+length-1)='.';
			*(s+1)=0; 			//null terminate
		}
	}
}

void SHT10_Get(void)
{
	unsigned char error, checksum;
	unsigned char x;

	unsigned char s[6];
    unsigned char h[6];

    
   

	ADCON1 = 0x0F;					//All digital operation	for RA2 & RA0 pins being digital for SHT10 sensor

	s_softreset();														//reset the SHT10 sensor
    DelayMs(20);

	
	
//	for(;;)
//	{
        error=0;
    	error+=s_measure((unsigned char*)&humi_val.i,&checksum,HUMI);  	//measure humidity
    	error+=s_measure((unsigned char*)&temp_val.i,&checksum,TEMP);  	//measure temperature
    	
		if(error!=0) 
			s_connectionreset();								//in case of an error: connection reset               
    	else
		{
      		
            humi_val.f=(float)humi_val.i;								//converts integer to float
      		temp_val.f=(float)temp_val.i;								//converts integer to float
      		calc_sht1x(&humi_val.f,&temp_val.f);						//calculate humidity, temperature
		    ftoa(tempdata, (temp_val.f*1.8 + 32));						//convert floating point to string in 1 dec place
			ftoa(humidata, humi_val.f);									//convert floating point to string in 1 dec place
           
  //  }
      //----------wait approx. 1s to avoid heating up SHTxx--------------    
	  for(x=0;x<5;x++) DelayMs(200);       
	}

}


//----------------------------------------------------------------------------
//** END:  SHT10 Delay Defs **
//----------------------------------------------------------------------------



//----------------------------------------------------------------------------
// ** START:  DEFINTIONS FOR LCD CODE **
//----------------------------------------------------------------------------

#define 	LCD_DDR		TRISD					// define DDR of LCD port
#define 	LCD_DATA	PORTD					// define Data port for LCD

#define 	RS_PIN		PORTBbits.RB0			// define RS Pin
#define 	RS_PIN_DDR	TRISBbits.TRISB0		// define DDR of RS Pin

#define 	ENABLE		PORTBbits.RB1			// define ENABLE pin
#define 	ENABLE_DDR	TRISBbits.TRISB1		// define DDR of ENABLE

#define    	XLCD_DISPLAYON
#define   	XLCD_CURSORON
#define   	XLCD_BLINKON

//#define    XLCD_1LINE							// COMMENT IF YOU WANT 2 LINE MODE
#define   	XLCD_2LINE							// COMMENT IF YOU WANT 1 LINE MODE

#define   	XLCD_CURSOR_INCREMENT				// CURSOR WILL INCREMENT
#define   	XLCD_DISPLAY_NOSHIFT				// NON-SHIFTING MODE

//#define   	XLCD_DISPLAYON						
//#define   	XLCD_CURSORON
//#define   	XLCD_BLINKON

#define 	XLCD_DELAYMODE
#define   	XLCD_BLOCK 

//#define		XLCD__GROUND
//#define    	RW_PIN		PORTBbits.RB2
//#define		RW_PIN_DDR	TRISBbits.TRISB2

//----------------------------------------------------------------------------
// ** END: DEFINTIONS FOR LCD CODE **
//----------------------------------------------------------------------------


//********************************************************************
// ** BEGIN Global Variable Declarations **
//********************************************************************
char Menu_Position = 48;				// Intialize the Menu Function

char _vXLCDreg = 0;          			// Used as a flag to check
										// if from XLCDInit()

int counter;

//********************************************************************
// ** END Global Variable Declarations **
//********************************************************************


//********************************************************************
// ** BEGIN Function Prototypes Section **
//********************************************************************
//void Delay_1sec(void);
//void Delay_250ms(void);
//void Delay_30ms(void);
//void XLCDCommand(unsigned char cmd);
//void XLCD_Init(void);
//void XLCD_Put(char data);
//void LCD_Menus(char menu);
//void Menu_Select(void);
//void Version_Display(void);
//void LCD_Menu_Execute(char menu);

//********************************************************************
// ** END Function Prototypes Section **
//********************************************************************


//********************************************************************
// ** BEGIN LCD Functions **
//********************************************************************

/*********************************************************************
 * Function         : void XLCDInit(void)
 * PreCondition     : None
 * Input            : None
 * Output           : None
 * Side Effects     : None
 * Overview         : LCD is intialized
 * Note             : This function will work with all Hitachi HD447780
 *                    LCD controller.
 ********************************************************************/

void XLCD_Init(void)
{
    /*This parT of the code is initialization by instruction*/
    _vXLCDreg = 1; 


    // PORT initialization //
    // 4-bit mode, using upper bits

    LCD_DDR &= 0x0F;             				// make DDR outputs
    LCD_DATA &= 0x0F;							// set DATA lines to 0
                	
    // end of data port initialization //

    // control port initialization //

    RS_PIN_DDR = 0;                         	// make control ports output
    ENABLE_DDR = 0;

    //	RW_PIN_DDR = 0;							// make R/W* pin 0 (write only)
    //	RW_PIN = 0;

    //    #ifndef XLCD_RW_GROUND
    //        RW_PIN_DDR = 0;                   // if RW pin grounded
    //    #endif

    RS_PIN  = 0;                             	// clear control ports
    ENABLE  = 0;

    //    #ifndef XLCD_RW_GROUND
    //    RW_PIN = 0;                         	// if RW pin grounded
    //    #endif

    // initialization by instruction

    Delay_30ms(); 
                
    // 4-bit mode interface
    
    LCD_DATA &= 0x0F;   						// Function set cmd(4-bit interface)
    LCD_DATA |= 0b00110000;

    ENABLE = 1;                 				// Clock the cmd in 
    Delay_30ms();
    ENABLE = 0;
    Delay_30ms();

    /////////////////////////////////////////////////////////////////////////
        
    // 4-bit mode interface
    
    LCD_DATA &= 0x0F;   						// Function set cmd(4-bit interface)
    LCD_DATA |= 0b00110000;   

    ENABLE = 1;                 				// Clock the cmd in  
    Delay_30ms(); 
    ENABLE = 0;
    Delay_30ms();

    //////////////////////////////////////////////////////////////////////////
    // XLCDDelay100us();
    
    // 4-bit mode interface
    
    LCD_DATA &= 0x0F;   						// Function set cmd(4-bit interface)
    LCD_DATA |= 0b00110000;
 

    ENABLE = 1;                 				// Clock the cmd in  
    Delay_30ms();
    ENABLE = 0;
    Delay_30ms();

    LCD_DATA &= 0x0F;
    LCD_DATA |= 0b00100000;

    ENABLE = 1;
    Delay_30ms();
    ENABLE = 0;
    
    //-----------------------------------------------------------------------
    //function set command "0 0 1 DL N F X X"
    //-----------------------------------------------------------------------

    #ifdef XLCD_1LINE
        XLCDCommand(0b00100000);    // 1-Line 5x8
    #else
        XLCDCommand(0b00101000);    // 2-Line 5x8
    #endif
        
    XLCDCommand(0b00001000);        // display off
    XLCDCommand(0b00000001);        // display clear

    /////////////////////////////////////////////////////////////////////////////////
    //Entry mode setting
    ////////////////////////////////////////////////////////////////////////////////
    //Entry mode command " 0 0 0 0 0 1 ID S "
    //ID =0 no cursor increment during read and write
    //ID =1 cursor increment during read and write
    //S =0 no display during read and write
    //S =1 display shift 
       
    #ifdef XLCD_CURSOR_INCREMENT
        #ifdef XLCD_DISPLAY_SHIFT
            XLCDCommand(0b00000111);    // if cursor inc and display shift
        #endif
        #ifdef XLCD_DISPLAY_NOSHIFT
            XLCDCommand(0b00000110);    // if cursor inc and no display shift
        #endif
    #endif

    #ifdef  XLCD_CURSOR_NOINCREMENT
        #ifdef XLCD_DISPLAY_SHIFT
            XLCDCommand(0b00000101);    // if no cursor increment, but with display shift
        #endif
        #ifdef XLCD_DISPLAY_NOSHIFT
            XLCDCommand(0b00000100);    // if no cursor increment, and no display shift
        #endif
    #endif 

    ///////////////////////////////////////////////////////////////////////////////////
    //Display on off ,Blink ,cursor command set 
    // ///////////////////////////////////////////////////////////////////////////////
    //"0 0 0 0 1 D C B "
    //D=1 dislay on, C=1 cursor on, B=1 blink on

    #ifdef  XLCD_DISPLAYON

        #ifdef XLCD_CURSORON
            #ifdef XLCD_BLINKON
                XLCDCommand(0b00001111);    //display on cursor on blink on
            #else
                XLCDCommand(0b00001110);    //display on cursor on blink off
            #endif
        #endif    
   
        #ifdef XLCD_CURSOROFF
            #ifdef XLCD_BLINKON
                //XLCDCommand(0b00001001);    //display on cursor off blink on
            #else
                XLCDCommand(0b00001100);    // display on cursor off blink off
            #endif
        #endif

    #endif


    #ifdef  XLCD_DISPLAYOFF
        XLCDCommand(0b00001000);        //display off
    #endif   
         
    _vXLCDreg = 0;
    
    // end of initialization
      
    return;
}

/*********************************************************************
 * Function         : void XLCDCommand(unsigned char cmd)
 * PreCondition     : None
 * Input            : cmd - Command to be set to LCD.
 * Output           : None
 * Side Effects     : None
 * Overview         : None
 * Note             : None
 ********************************************************************/
void XLCDCommand(unsigned char cmd)
{

    if(_vXLCDreg==1)                            // if  called from XLCDinit routine is always Blocking
    {
        #ifdef  XLCD_DELAYMODE
            Delay_30ms();
        #endif
    }


    if(_vXLCDreg==0)                            // if not called from XLCDinit routine
    {                                           // if NON Block the user need to call XLCDIsBusy 
        #ifdef  XLCD_BLOCK                      // and check the w reg status to check if the
            #ifdef  XLCD_DELAYMODE              // module is free
                Delay_30ms(); 
            #endif
        #endif
    }

    RS_PIN = 0;
    ENABLE = 0;

    //    #ifndef XLCD_RW_GROUND
    //        RW_PIN = 0;
    //    #endif
	
    LCD_DATA &= 0x0F;                    		// Write command to data port
    LCD_DATA |= cmd&0xF0;
    
    ENABLE = 1;                         		// Clock the cmd in
    Delay_30ms();   
    ENABLE = 0;
    
    LCD_DATA &= 0x0F;
    LCD_DATA |= (cmd<<4)&0xF0;

    ENABLE = 1;
    Delay_30ms();
    ENABLE = 0;
	
    return;
}

/*********************************************************************
 * Function         :XLCDPut()
 * PreCondition     :None
 * Input            :cmd - Command to be set to LCD.
 * Output           :None
 * Side Effects     :None
 * Overview         :None
 * Note             :None
 ********************************************************************/
void XLCD_Put(char data)
{

    RS_PIN = 1;
    ENABLE = 0;

    LCD_DATA &= 0x0F;
    LCD_DATA |= data&0xF0;

    ENABLE = 1;
    Delay_30ms();
    ENABLE  = 0;

    LCD_DATA &= 0x0F;
    LCD_DATA |= (data<<4)&0xF0;

    ENABLE = 1;
    Delay_30ms();
    ENABLE = 0;

   return;
}

//********************************************************************
// ** END LCD Functions **
//********************************************************************


//********************************************************************
// ** BEGIN: Delay Functions **
//********************************************************************

void Delay_30ms(void)
{
    // ** This delay can be used for all LCD Delays without problems
    // ** It should be about 30ms
    // ** Its slower than necessary, but works well

    Delay1KTCYx(60); 	
    
    // Delay Formula, 15 ms as example:
    // Delay of 15ms
    // Cycles = (TimeDelay * Fosc) / 4
    // Cycles = (15ms * 16MHz) / 4
    // Cycles = 60,000

    return;
}

void Delay_1sec(void)
{
    Delay10KTCYx(0); 	
    Delay10KTCYx(0);
    Delay10KTCYx(0);
    Delay10KTCYx(0);

    return;
}

void Delay_250ms(void)
{
	Delay10KTCYx(0); 	

    return;
}

//********************************************************************
// ** END: Delay Functions **
//********************************************************************


//--------------------------------------------------------------------------
// ***** BEGIN:  LCD Menu Selector Function *****
//--------------------------------------------------------------------------
// ** This Function decodes the Rotary Encoder switch to cycle the menus

void Menu_Select(void)
{
    if( PORTBbits.RB2 && !PORTBbits.RB5 )
    {
        if( Menu_Position == 52 )
        {
            Menu_Position = 48;
        }

        Menu_Position = Menu_Position + 1;

        XLCDCommand(0x01);
        Delay_30ms();

        LCD_Menus( Menu_Position );
        Delay_30ms();

//        while( !(PORTBbits.RB2 && PORTBbits.RB5) )
//        {
//            Delay_30ms();
//        }
    }

    if( !PORTBbits.RB2 && PORTBbits.RB5 )
    {   
        if( Menu_Position == 49 )
            {
                Menu_Position = 53;
            }

        if( Menu_Position == 48)
            {
                Menu_Position = 50;
            }

        Menu_Position = Menu_Position - 1;

        XLCDCommand(0x01);
        Delay_30ms();

        LCD_Menus( Menu_Position );
        Delay_30ms();

//        while( !(PORTBbits.RB2 && PORTBbits.RB5) )
//        {
//            Delay_30ms();
//        }
    }        
}

//--------------------------------------------------------------------------
// ***** END:  LCD Menu Selector Function *****
//--------------------------------------------------------------------------


//--------------------------------------------------------------------------
// ** START: LCD Menu Display Function *****
//--------------------------------------------------------------------------
// ** This the Menu Display Function
// ** It has all Menu Words in it
// ** Call with particular menu opcode to display it
//---------------------------------------------------------------------------

void LCD_Menus(char menu)
{
//    if (menu == 49)
//    {
//            XLCDCommand(0x01);
//            Delay_30ms();
//
//            XLCD_Put('S'); 
//	    	XLCD_Put('e'); 
//	    	XLCD_Put('t'); 
//	    	XLCD_Put(' ');
//	    	XLCD_Put('E'); 
//	    	XLCD_Put('c'); 
//	    	XLCD_Put('o'); 
//	    	XLCD_Put('n');
//	    	XLCD_Put('o');
//	    	XLCD_Put('m');
//	    	XLCD_Put('y');
//	    	XLCD_Put(' ');
//	    	XLCD_Put('M');
//	    	XLCD_Put('o');
//	    	XLCD_Put('d');
//	    	XLCD_Put('e');
//
//		    Delay_30ms();
//    }
//
//    else if(menu == 50)
//    {
//            XLCDCommand(0x01);
//            Delay_30ms();
//
//            XLCD_Put('O'); 
//	    	XLCD_Put('v'); 
//	    	XLCD_Put('e'); 
//	    	XLCD_Put('r');
//	    	XLCD_Put('r'); 
//	    	XLCD_Put('i'); 
//	    	XLCD_Put('d'); 
//    		XLCD_Put('e');
//    		XLCD_Put(' ');
//    		XLCD_Put('S');
//    		XLCD_Put('e');
//    		XLCD_Put('t');
//    		XLCD_Put('t');
//    		XLCD_Put('i');
//	    	XLCD_Put('n');
//	    	XLCD_Put('g');
//            XLCD_Put('s');
//
//	    	Delay_30ms();
//
//    }
//
//    else if(menu == 51)
//    {
//            XLCDCommand(0x01);
//            XLCDCommand(0x01);
//            Delay_30ms();
//
//            XLCD_Put('S'); 
//	    	XLCD_Put('e'); 
//	    	XLCD_Put('t'); 
//	    	XLCD_Put(' ');
//	    	XLCD_Put('S'); 
//	    	XLCD_Put('e'); 
//	    	XLCD_Put('a'); 
//    		XLCD_Put('s');
//    		XLCD_Put('o');
//    		XLCD_Put('n');
//
//	    	Delay_30ms();
//
//    }
//
//	else if(menu == 52)
//    {
//            XLCDCommand(0x01);
//            Delay_30ms();
//
//            XLCD_Put('D'); 
//	    	XLCD_Put('i'); 
//	    	XLCD_Put('s'); 
//	    	XLCD_Put('p');
//	    	XLCD_Put('l'); 
//	    	XLCD_Put('a'); 
//	    	XLCD_Put('y'); 
//    		XLCD_Put(' ');
//    		XLCD_Put('S');
//    		XLCD_Put('o');
//    		XLCD_Put('f');
//    		XLCD_Put('t');
//    		XLCD_Put('w');
//    		XLCD_Put('a');
//	    	XLCD_Put('r');
//	    	XLCD_Put('e');
//
//            XLCDCommand(0xA8);
//
//			XLCD_Put('V');
//	    	XLCD_Put('e'); 
//	    	XLCD_Put('r'); 
//	    	XLCD_Put('s'); 
//    		XLCD_Put('i');
//    		XLCD_Put('o');
//    		XLCD_Put('n');
//
//	    	Delay_30ms();
//
//    }


    switch (menu)
    {
        case 49:
	    	XLCDCommand(0x01);
            Delay_30ms();

            XLCD_Put('S'); 
	    	XLCD_Put('e'); 
	    	XLCD_Put('t'); 
	    	XLCD_Put(' ');
	    	XLCD_Put('E'); 
	    	XLCD_Put('c'); 
	    	XLCD_Put('o'); 
	    	XLCD_Put('n');
	    	XLCD_Put('o');
	    	XLCD_Put('m');
	    	XLCD_Put('y');
	    	XLCD_Put(' ');
	    	XLCD_Put('M');
	    	XLCD_Put('o');
	    	XLCD_Put('d');
	    	XLCD_Put('e');

		    Delay_30ms();
	     	break;

        case 50:
            XLCDCommand(0x01);
            Delay_30ms();

            XLCD_Put('O'); 
	    	XLCD_Put('v'); 
	    	XLCD_Put('e'); 
	    	XLCD_Put('r');
	    	XLCD_Put('r'); 
	    	XLCD_Put('i'); 
	    	XLCD_Put('d'); 
    		XLCD_Put('e');
    		XLCD_Put(' ');
    		XLCD_Put('S');
    		XLCD_Put('e');
    		XLCD_Put('t');
    		XLCD_Put('t');
    		XLCD_Put('i');
	    	XLCD_Put('n');
	    	XLCD_Put('g');
            XLCD_Put('s');

	    	Delay_30ms();
	    	break;

        case 51:
            XLCDCommand(0x01);
            Delay_30ms();

            XLCD_Put('S'); 
	    	XLCD_Put('e'); 
	    	XLCD_Put('t'); 
	    	XLCD_Put(' ');
	    	XLCD_Put('S'); 
	    	XLCD_Put('e'); 
	    	XLCD_Put('a'); 
    		XLCD_Put('s');
    		XLCD_Put('o');
    		XLCD_Put('n');

	    	Delay_30ms();
	    	break;

        case 52:
            XLCDCommand(0x01);
            Delay_30ms();

            XLCD_Put('D'); 
	    	XLCD_Put('i'); 
	    	XLCD_Put('s'); 
	    	XLCD_Put('p');
	    	XLCD_Put('l'); 
	    	XLCD_Put('a'); 
	    	XLCD_Put('y'); 
    		XLCD_Put(' ');
    		XLCD_Put('S');
    		XLCD_Put('o');
    		XLCD_Put('f');
    		XLCD_Put('t');
    		XLCD_Put('w');
    		XLCD_Put('a');
	    	XLCD_Put('r');
	    	XLCD_Put('e');

            XLCDCommand(0xA8);

			XLCD_Put('V');
	    	XLCD_Put('e'); 
	    	XLCD_Put('r'); 
	    	XLCD_Put('s'); 
    		XLCD_Put('i');
    		XLCD_Put('o');
    		XLCD_Put('n');

	    	Delay_30ms();
	    	break;

        default:
            break;
    }
}
//********************************************************************
// ** END: LCD Menu Display Function **
//********************************************************************

//--------------------------------------------------------------------------
// ** START: LCD Menu Execute *****
//--------------------------------------------------------------------------
// ** Here we execute the Menu chosed
//---------------------------------------------------------------------------

void LCD_Menu_Execute(char menu)
{
    switch (menu)
    {
        case 49:
	    	
	     	break;

        case 50:
            
	    	break;

        case 51:

			XLCDCommand(0x01);
            Delay_30ms();

            XLCD_Put('S'); 
	    	XLCD_Put('e'); 
	    	XLCD_Put('l'); 
	    	XLCD_Put('e');
	    	XLCD_Put('c'); 
	    	XLCD_Put('t'); 
	    	XLCD_Put(' '); 
    		XLCD_Put('S');
    		XLCD_Put('u');
    		XLCD_Put('m');
    		XLCD_Put('m');
    		XLCD_Put('e');
    		XLCD_Put('r');
            
	    	break;

        case 52:
           Version_Display();

        default:
            break;
    }
    return;
   
}



//********************************************************************
// ** END: LCD Menu Execute **
//********************************************************************

//********************************************************************
// ** START: Software Version Display Function **
//********************************************************************
void Version_Display(void)
{
    XLCD_Put('T');
    XLCD_Put('e');
    XLCD_Put('a');
    XLCD_Put('m');
    XLCD_Put(' ');
    XLCD_Put('1');
    XLCD_Put('0');
    XLCD_Put(' ');
    XLCD_Put('T');
	XLCD_Put('h');
	XLCD_Put('e');
	XLCD_Put('r');
	XLCD_Put('m');
	XLCD_Put('o');
	XLCD_Put('s');
	XLCD_Put('t');
	XLCD_Put('a');
	XLCD_Put('t');
    Delay_30ms();
}
//********************************************************************
// ** END: Software Version Display Function **
//********************************************************************

////********************************************************************
//// ** START: Number to char routine **
////********************************************************************
//void Num_to_Char(int num2conv )
//{
//    10_x_num2conv = 10 * num2conv;
//    
//}
////********************************************************************
//// ** END: Number to char routine **
////********************************************************************


////********************************************************************
//// ** START: ASHRAE routine **
////********************************************************************
//if hc=1, summer mode
//if hc=0, winter mode
//function: float calc_temp(float RH, unsigned char PPD_level, unsigned char hc)
//purpose: to calculate the temperature that the home needs to be maintained at using ASHRAE standards
//receive: the humidity of the air, the comfort index percentile, hot or cold mode
//return: a float describing the temperature the home
float calc_temp(float RH, unsigned char PPD_level, unsigned char hc)
{
	
	//lighter summer clothing
	if (hc==1)
		CLO = .5;
	//heavier winter clothing
	else if (hc==0)
		CLO = 1.0;
	
	TEMPA = 0.0;

	PA = 0;
		
	//from 40.0 to 90.0 degrees Farenheit
	for (TA=4.444;TA<=32.222;TA+=.1)
	{
		//radiant temperature, equal to ambient temperature
		TR = TA;

		FNPS = exp(16.6536-4030.183/(TA+235));
		//water vapor pressure
		if (PA==0)
			PA = RH*10*FNPS;

		ICL = .155 * CLO;

		M = MET * 58.15;

		WO = WME * 58.15;

		MW = M - WO;

		if (ICL<.078)
			FCL = 1 + 1.29 * ICL;
		else
			FCL = 1.05 + .645 * ICL;

		HCF = 12.1 * sqrt(VEL);

		TAA = TA + 273;
		TRA = TR + 273;

		//calculate surface temperature of clothing by iteration
		TCLA = TAA + (35.5-TA)/(3.5*(6.45*ICL+.1));
		P1 = ICL * FCL;
		P2 = P1 * 3.96;
		P3 = P1 * 100;
		P4 = P1 * TAA;
		P5 = 308.7 - .028 * MW + P2 * pow((TRA/100),4);
		
		XN = TCLA / 100;
		XF = XN;
		EPS = .00015;

		for (loop=0;loop<152;loop++)
		{
			XF = (XF+XN) / 2;
			HCN = 2.38 * pow(2.38*fabs(100*XF-TAA),.25);
			if (HCF>HCN)
				HC = HCF;
			else
				HC = HCN;
			XN = (P5 + P4*HC - P2*pow(XF,4))/(100 + P3*HC);
			if (loop>150)
			{
				break;
			}
			if (fabs(XN-XF)<=EPS)
			{
				TCL = 100*XN - 273;
				HL1 = 3.05 * .001 * (5733-6.99*MW-PA);
				if (MW>58.15)
					HL2 = .42 * (MW-58.15);
				else
					HL2 = 1;
				HL3 = 1.7 * .00001 * M * (5867-PA);
				HL4 = .0014 * M * (34-TA);
				HL5 = 3.96*FCL*(pow(XN,4)-pow((TRA/100),4));
				HL6 = FCL * HC * (TCL - TA);
				TS = .303 * exp(-.036 * M) + .028;
				PMV = TS * (MW-HL1-HL2-HL3-HL4-HL5-HL6);
				PPD = 100 - 95*exp(-.03353*pow(PMV,4) - .2179*pow(PMV,2));
				if ((PPD_level>=PPD-.5) && (PPD_level<=PPD+.5))
				{	
					if (TEMPA==0)
						TEMPA = TA;
					else if (hc==1)
					{
						if (TA>TEMPA)
							TEMPA = TA;
					}
					else if (hc==0)
					{
						if (TA<TEMPA)
							TEMPA = TA;
					}
				}
				break;
			}
		}
	}
	ftoa(ashdata,(TEMPA*1.8 + 32));	
	
	return TEMPA;
}
//********************************************************************
// ** END: ASHRAE routine **
//********************************************************************

//********************************************************************
// ** START: CONTROL DEVICES routine **
//********************************************************************
void control_devices()
{	
	//summer mode
	if (hc==1)
	{
		//orange is fan and RD1
		//cool the house down if it has gotten too hot

		//using the hysteresis model of +-2 degrees
		//turn on ac and fan
		if ( temp_val.f >= TEMPA + 1 )
		{
			PORTDbits.RD2 = 1;
			PORTDbits.RD1 = 1;
			PORTDbits.RD3 = 0;
		}

		//let the house warm up a bit from its cooler state before requesting AC services again
		else if ( temp_val.f < TEMPA - 1 )
		{
			PORTDbits.RD2 = 0;
			PORTDbits.RD1 = 0;
			PORTDbits.RD3 = 0;
		}
	}
	
	//winter mode
	else
	{
		//warm the house up if it has gotten too cold
		if ( temp_val.f <= (TEMPA - 1) )
		{
				PORTDbits.RD3 = 1;
				PORTDbits.RD1 = 1;
				PORTDbits.RD2 = 0;
		}

		//let the house cool off a bit before warming it back up with heating services
		else if ( temp_val.f > (TEMPA + 1) )
		{
				PORTDbits.RD3 = 0;
				PORTDbits.RD1 = 0;
				PORTDbits.RD2 = 0;
		}
	}
}
//********************************************************************
// ** END: Control Devices **
//********************************************************************



//********************************************************************
// ** START: Show Humidity and Temp function **
//********************************************************************
void Show_Values()
{
        XLCDCommand(0x01);
        Delay_30ms();

        XLCD_Put(tempdata[0]);
   		XLCD_Put(tempdata[1]);
  	    XLCD_Put(tempdata[2]);
  	    XLCD_Put(tempdata[3]);
        XLCD_Put(' ');
        XLCD_Put('d');
        XLCD_Put('e');
        XLCD_Put('g');
		XLCD_Put(' ');
        XLCD_Put('F');
		XLCD_Put(' ');
		XLCD_Put('c');
		XLCD_Put('u');
		XLCD_Put('r');
		XLCD_Put('r');
		XLCD_Put('e');
		XLCD_Put('n');
		XLCD_Put('t');

		XLCDCommand(0xA8);
		Delay_30ms();

        XLCD_Put(humidata[0]);
   		XLCD_Put(humidata[1]);
  	    XLCD_Put(humidata[2]);
  	    XLCD_Put(humidata[3]);
        XLCD_Put(' ');
        XLCD_Put('%');
        XLCD_Put('R');
		XLCD_Put('H');

        XLCDCommand(0x94);
		Delay_30ms();

        XLCD_Put(ashdata[0]);
   		XLCD_Put(ashdata[1]);
  	    XLCD_Put(ashdata[2]);
  	    XLCD_Put(ashdata[3]);
        XLCD_Put(' ');
        XLCD_Put('d');
        XLCD_Put('e');
		XLCD_Put('g');
		XLCD_Put(' ');
		XLCD_Put('F');
		XLCD_Put(' ');
		XLCD_Put('o');
		XLCD_Put('p');
		XLCD_Put('t');
		XLCD_Put('i');
		XLCD_Put('m');
		XLCD_Put('a');
		XLCD_Put('l');
		
//		for(counter = 1; counter < 2; counter++) 
//        {
//            Delay_1sec();
//        }
}
//********************************************************************
// ** END: Show Humidity and Temp function **
//********************************************************************


//********************************************************************
// ** START: main function **
//********************************************************************
void main()
{
    ADCON1 = 0x0F;								// SET PORTB as digital
    TRISC &= ~0x07;
    TRISB = 0x6C;
	TRISD &= ~0x0F;

	PORTDbits.RD0 = 0;							// set the output lights as 0
	PORTDbits.RD1 = 0;
	PORTDbits.RD2 = 0;
	PORTDbits.RD3 = 0;


    XLCD_Init();								// initalize the LCD Display

    Version_Display();							// display upon reset
    Delay_1sec();

	ashcount = 0; 								// keeping track of when to calculate ashrae temp
	ashcountcounter = 0;						// nested loop track
	hc = 1;										// set the weather mode initally
	PORTDbits.RD0 = 1;
 	SHT10_Get();								// make the initial reading
	calc_temp(humi_val.f,10,hc);
	PORTDbits.RD0 = 0;
    Show_Values();

    while(1)									// main program loop
   	{
        Menu_Select();
       
		if (PORTBbits.RB3 == 1)
		{
			if (hc==1)
			{
                XLCDCommand(0x01);
                Delay_30ms();

				XLCD_Put('w');
				XLCD_Put('i');
				XLCD_Put('n');
				XLCD_Put('t');	
				XLCD_Put('e');
				XLCD_Put('r');
				hc = 0;
			}
			else if (hc==0)
			{

                XLCDCommand(0x01);
                Delay_30ms();
				XLCD_Put('s');
				XLCD_Put('u');
				XLCD_Put('m');
				XLCD_Put('m');	
				XLCD_Put('e');
				XLCD_Put('r');
				hc = 1;
			}
		}
				
		if (ashcount==32767)
        {
			PORTDbits.RD0 = 1;
			SHT10_Get();
			calc_temp(humi_val.f,10,hc);
			control_devices();
			Show_Values();
			PORTDbits.RD0 = 0;
			ashcount = -1;
		}
		
		if (ashcountcounter == 300)
		{
			ashcount++;
			ashcountcounter = -1;
		}
		
		ashcountcounter++;

//        if(PORTBbits.RB6)
//        {
//            LCD_Menu_Execute(Menu_Position);
//
//            XLCDCommand(0x01);
//            Delay_30ms();
//
//            SHT10_Get();
//
//    		Delay_30ms();
//        }
    }

}
//********************************************************************
// ** END: main function **
//********************************************************************
