/****************************************************************************
 Title	:	TERMINAL FOR VISUALIZATION AND CONTROL CONDITIONS IN HOUSE
 Author	:	Patrik Szalay <xszala01@stud.feec.vutbr.cz>
 File	:	main.c
 Software:	CodeWarrior Development Studio Version: 10.6 Build Id:140329
 Target	:	MC9S08LH64

 DESCRIPTION
       Main code for the terminal

 USAGE
       
*****************************************************************************/

#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
#include "IO.h" /* include all IO declarations */
#include <string.h> 
#include <stdio.h>
#include "serial.h" /* include serial interface driver library*/
#include "UI.h" /* include user interface driver library */
#include "regulation.h" /* include regulation algorithms library */

//#define _DEBUG


/*************************************************************************
Load the Trim Value for Internal Clock Source 
*************************************************************************/
void InitTrimICS(void)
	{
	ICSTRM = NVICSTRM;
	ICSSC_FTRIM = 1;
	}

/*************************************************************************
Initialise FLL for Bus Clock, set for 4.194MHz 
*************************************************************************/
void vfnClock_Init(void)
{

   /* ICSC2: BDIV=0:1 (Divide by 2) FLL Freq = (XTAL * 512)/BDIV = 8.388MHz (Bus ~4.194MHz)
      HGO = 1, LP = 0 FLL not Disabled in Stop modes, High Gain On
      EREFS = 1, ERCLKEN = 1, EREFSTEN = 1, Extenal Reference Enabled in all modes
   */
   ICSC2 = 0x47;

   /* Wait until the initialization of the external crystal oscillator is completed */
   while(!ICSSC_OSCINIT)
   {
     __RESET_WATCHDOG();
   }

   /*  ICSC1:
       CLKS=0 Clock Source is Output of the FLL
       RDIV=0 Reference Divider = 1, 32.768 External Crystal
       IREFS=0,IRCLKEN=0,IREFSTEN=0 Internal Reference Disabled in All Modes
   */
   ICSC1 = 0x00;

   /*  ICSSC
       DRST = 0:0  Low Range
       DMX32 = 0 Do not *set the max frequency from the 32KHz XTAL
   */
   ICSSC &= (unsigned char)~0xE0;
   /* Wait until the DCO locks  in a low-range mode */
   while((ICSSC & 0xC0) != 0x00)
   {
     __RESET_WATCHDOG();
   }
}

/*************************************************************************
Interrupt routine for TOD module 
*************************************************************************/
interrupt VectorNumber_Vtod void ISR_TOD (void) { 
	if(TODSC_QSECF)
		{
			TOD_tick++;
			
			
			TOD_TODQSEC = 1;
			if(TOD_tick % 2 == 0) TOD_TODHSEC = 1;
			if(TOD_tick % 4 == 0) TOD_TODSEC = 1;
			if(TOD_tick % 8 == 0) TOD_TOD2SEC = 1;
			if(TOD_tick % 20 == 0) TOD_TOD5SEC = 1;
			if(TOD_tick % 40 == 0) TOD_TOD10SEC = 1;
			if(TOD_tick % 120 == 0) TOD_TOD30SEC = 1;
			if(TOD_tick >= 240)
			{
				TOD_TOD1MIN = 1;
				TOD_tick = 0;
			}
			
		
			TODSC = TODSC & (~(unsigned char)TODSC_SECF_MASK);
		}
		if(TODSC_SECF)
		{
			TODSC = TODSC & (~(unsigned char)TODSC_QSECF_MASK);
		} 
	
	
	
}

/*************************************************************************
Interrupt routine for the IRQ pin (used for the UP button)
*************************************************************************/
interrupt VectorNumber_Virq void ISR_IRQ (void) {
	IRQSC_IRQACK = 1; /* Clear interrupt request */
	if( !SW_UP ){
		cursor(UP);
	}
}

/*************************************************************************
Interrupt routine for the KBI interrupts (used for the navigation buttons)
*************************************************************************/
interrupt VectorNumber_Vkeyboard void ISR_KBI (void) {	
	KBISC_KBACK = 1; /* Clear interrupt request */

	if( !SW_DN ){
		cursor(DOWN);
	}
	if( !SW_RGHT ){
		cursor(RIGHT);
	}
	if( !SW_LEFT ){
		cursor(LEFT);
	}
	if( !SW_ENT ){
		cursor(ENTER);
	}

}

/*********************************************************************************************
Routine for provide measurements for the regulation algorithms, calls the temp_meas.h library
**********************************************************************************************/
void measValues(void)
{
	decimal measValue;
	
				 measValue = measure(MCP9808_2);
				 if(measValue != MEAS_ERROR)
				 {
					 setRoom_Temp(measValue);
					 MeasError.roomTemp = false;
				 }
				 else
				 {
					 MeasError.roomTemp = true;
				 }
				 measValue = measure(LM75_1);
				 if(measValue != MEAS_ERROR)
				 {
					 setWater_Out_Temp(measValue);
					 MeasError.waterOutTemp = false;
				 }
				 else
				 {
					 MeasError.waterOutTemp = true;
				 }
				 measValue = measure(LM75_2);
				 if(measValue != MEAS_ERROR)
				 {
					 setWater_Return_Temp(measValue);
					 MeasError.waterReturnTemp = false;
				 }
				 else
				 {
					 MeasError.waterReturnTemp = true;
				 }
				 measValue = measure(HTU21D_TEMP);
				 if(measValue != MEAS_ERROR)
				 {
					 setOutDoor_Temp(measValue);
					 MeasError.outdoorTemp = false;
				 }
				 else
				 {
					 MeasError.outdoorTemp = true;
				 }
				 measValue = measure(HTU21D_HUM);
				 if(measValue != MEAS_ERROR)
				 {
					 setOutDoor_Hum(measValue);
					 MeasError.outdoorHum = false;
				 }
				 else
				 {
					 MeasError.outdoorHum = true; 
				 }
			 
}

/*************************************************************************
Main routine
*************************************************************************/
void main(void) {
  /* Variables declarations */
  int i = 0; 

  static const unsigned char LCDchars[] =	/* LCD display custom symbols */
  {
		  connected_char,
		  connected_A_char, 
		  connected_B_char,
		  connected_left_char,
		  connected_right_char,
		  heat_char,
		  pump_char,
		  up_arrow_char,
		  down_arrow_char
  };	

  /* Modules initialisation */
	vfnClock_Init(); /* Init the FLL */
  	InitTrimICS(); /* Set Trim value */
  	Init_Peripheral; /* Init peripherals */
    Init_clock(); /* Init clock for the LCD display */
  	Init_LCD(); /* Init Tower LCD display */
  
  	HOLD_blink_on; /* Show HOLD symbol */
  	Write_string("RDY",1); /* Write RDY on the display */ 
  	Num_aux_hex(ICSTRM); /* Write the Internal Clock Source Trim value on display */
  	RE_Init; /* Init the relays */
  	SW_Init; /* Init the buttons */
  	
  	/* Ready for startup, waiting for pressing the Enter button */
  	while(SW_ENT)__RESET_WATCHDOG();
  	
  	/* System started, continue initialising */
    EnableInterrupts;
  	HOLD_off; /* Hide the HOLD symbol */
  	Write_string("RUN",1); /* Write RUN on the display */ 
  	IICInit(); /* Init the IIC module */
  	KBI_Init; /* Enable the KBI interrupts */
  	IRQI_Init; /* Enable the IRQ interrupt */
  	TOD_Init; /* Init the TOD module */
  	InitSCI(); /* Init the SCI module */
  	setHeater_State(false); /* Set Heater Relay off */
  	setPump_State(false); /* Set Pump Relay off */

#ifndef _DEBUG
  	lcd_init(LCD_DISP_ON); /* Init the external alphanumeric LCD display */ 
  	lcd_command(_BV(LCD_CGRAM)); /* Set the pointer to the CGRAM */
  	for(i=0; i<72; i++) /* Load LCD special chars */
  	{	
  	  	lcd_data(LCDchars[i]);
  	}

  	lcd_clrscr(); /* Clear the LCD */
  	lcd_Bcklght_on(); /* Turn the LCD backlight on */
#endif
  	
  	clockRefreshFromRTC(); /* Refresh the system clock from the RTC */
  	InitAverages(); /* Measure the Average temperatures for the first time */
  	measValues(); /* Measure values for the terminal initialisation */
  	setRegulateToTemp(); /* Set the temperature to regulate to based on the System Time */
  	Thermostat(); /* Run the thermostat algorithm */
  	

  	/* Main routine */
 for(;;) {
	 
	 if(SCIS_SCISDRX) SCIRead();  /* Read the serial port if data arrived */
	 
	 if(refreshTime) /* Set the RTC if Time update is received from the serial port */
	 {
		 clockSetRTC();
		 refreshTime = false;
	 }
	 
	 /* clock interrupts */
	 if(TOD_TODQSEC) /* Quarter-second flag */
	 {
		 TOD_TODQSEC = 0;
#ifndef _DEBUG
	 	 refreshUI(); /* Refresh the user interface */
#endif	 
	 	UIenableNavigate(); /* Enable navigation */
	 }
	 if(TOD_TODHSEC) /* Half-second flag */
	 {
	 	 TOD_TODHSEC = 0;
	 	 clockRefreshFromRTC(); /* Refresh the system clock from the RTC */
	 	 
	 	 // remaining code here
	 }
	 if(TOD_TODSEC) /* Second flag */
	 {
		 TOD_TODSEC = 0; 
#ifndef _DEBUG
		 if(disp_Bcklght_en) /* LCD backlight switching off */
		 {
			 disp_timer++;
			 if(disp_timer >= LCD_DISP_BCKLGHT_TIME)
			 {
				 lcd_Bcklght_off();
			 }
		 }
#endif
		 if(pumpDelayEnable) /* Pump delay timer */
		 {
			if(!SCIConnCheck(MATLAB))
			{
			 pumpDelayTimer++;
			 if(pumpDelayTimer >= (int)pumpDelayTime*60)
			 {
				 pumpDelayTimer = 0;
				 pumpDelayEnable = false;
			 }
			}
			else
			{
				pumpDelayTimer = 0;
				pumpDelayEnable = false;
			}
		 }
		 else
		 {
			 pumpDelayTimer = 0;
		 }
	 	 // remaining code here
	 }
	 if(TOD_TOD2SEC) /* 2 seconds flag */
	 {
	 	 TOD_TOD2SEC = 0;
	 	
	 	if(SCIS_SCISACKRQ) /* Serial port timeout handling */
	 	{
	 		if(SCIACKRQ_TOut == 0)
	 		{
	 			SCIACKRQ_TOut++;
	 		}
	 		if(SCIACKRQ_TOut == 1)
	 	 	{
	 	 	 	SCIRetransmit(); /* Retransmit the data */
	 	 	 	SCIACKRQ_TOut++;
	 	 	}
	 		else if(SCIACKRQ_TOut >= 2)
	 		{
	 			Write_string("Tou",1); /* Write Timeout to the display */
	 			SCIDisconnect(SCIGetACKAddress()); /* solve timeout problem */
	 			SCIACKRQ_TOut = false; /* Clear TOut flag */
	 			SCIS_SCISACKRQ = false; /* Clear ACKRQ flag */
	 		}	
	 	}
	 	else
	 	{
	 		SCIACKRQ_TOut = false; /* Clear the TOut Flag */
	 	}
	 }
	 if(TOD_TOD5SEC) /* 5 seconds flag */
	 {
	 	 TOD_TOD5SEC = 0;
	 	if(!SCIConnCheck(MATLAB)) /* Refresh the measured values and run the thermostat algorithm, only if MATLAB is not connected */
	 	{
	 		 measValues();
	 		 Thermostat();
	 	}
	 }
	 if(TOD_TOD10SEC) /* 10 seconds flag */
	 {
	 	 TOD_TOD10SEC = 0;
	 	 /* remaining code here */
	 }
	 if(TOD_TOD30SEC) /* 30 seconds flag */
	 {
	 	 TOD_TOD30SEC = 0;

	 	 /* remaining code here */
	 }
	 if(TOD_TOD1MIN) /* 1 minute flag */
	 {
	 	 TOD_TOD1MIN = 0;
	 	 setAverageTemp(); /* Measure the outdoor temperature average */
	 	 /* remaining code here */
	 }
	
	 if(SCIConnCheck(MATLAB)) /* Run the thermostat algoritm in every cycle if MATLAB is connected */
	 {
		 Thermostat();
	 }
	 

	 if(getHeater_State()) /* Set Heater Relay */
		 {
		 	 HEAT_on;
		 	 HEATER_RE1 = 1;
		 }
	 else 
		 {
		 	 HEAT_off;
		 	 HEATER_RE1 = 0;
		 }
	 if(getPump_State()) /* Set Pump Relay */
		 {
			 FLTR_on;
			 PUMP_RE2 = 1;
		 }
	 	 else
	 	 {
	 		 FLTR_off;
	 		 PUMP_RE2 = 0;
	 	 }
	 

	 if(getOutDoor_Temp() < 300 && getOutDoor_Temp() > 0) /* Show the * mark if the temperatures are colder than 3C */
	 {
		 COLD_blink_on;
	 }
	 else if (getOutDoor_Temp() <= 0)
	 {
		 COLD_on;
	 }
	 else
	 {
		 COLD_off;
	 }
		 
	  __RESET_WATCHDOG();	/* feeds the dog */
  } /* loop forever */
  /* please make sure that you never leave main */
} 
