#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <util/delay.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/iocan128.h>

#include "gas_temp_monitor.h"
#include "canapi_define.h"
#include "canapi.h"
#include "can.h"
#include "canapi_global.h"
#include "led.h"

#include "OWIDeviceSpecific.h"
#include "OWIHighLevelFunctions.h"
#include "OWIBitFunctions.h"
#include <util/delay.h>

#define BV(x)  (1<<x)
#define BIT(x)  (1<<x)

volatile uint16_t thigh = 900; /*the maximum gas pressure*/
volatile uint16_t tlow = 100;  /*the minimum gas pressure*/
uint16_t Voltages[8];          /* current supply voltages of the board*/
uint8_t res0, res1, res2, res3;/*parameter back to reading the voltage on ADC-channel*/
uint8_t StartValue;            /*variable to differentiate reading writing*/
uint8_t *Ptr_Reg;              /*pointer to the contents of the register*/
uint8_t *Adr_Reg, *Val_Reg;    /*pointer on the address and value of the register*/

enum states {idle, below_low_thres, in_between , above_high_thres };
uint8_t cur_state;
uint8_t usercommand;
/*variable to store values*/
char tmp_str[BUFFER_SIZE];


volatile unsigned char timer0Ready;/*variable for Timer0  Interrupt*/
volatile unsigned char timer0AReady;/*variable for Timer0 Output Compare A  Interrupt*/
volatile unsigned char canReady;/*variable for can interrupt*/
volatile unsigned char uartReady;/*variable for Uart interrupt*/
char uartString[BUFFER_SIZE]; /* variable for storage received a complete string via UART */ 
char decrypt_uartString[BUFFER_SIZE]; 
char tempstr[BUFFER_SIZE];/*variable for debug*/
char ring_buffer[MAX_INPUT][MAX_LENGTH_CAN_DATA]; /*buffer to store CAN data*/
char setParameter[MAX_PARAMETER][MAX_LENGTH_PARAMETER];
char canString[MAX_LENGTH_CAN_DATA];
unsigned char nextCharPos; /*pointer of the variable uartString  */
uint8_t can_errorCode; /* error code for CAN-communication */
uint8_t uart_errorCode; /* error code for UART-communication */
uint8_t mailbox_errorCode; /* error code for Message Object Block */
uint8_t general_errorCode; /*  general error code */
uint8_t ptr_subscribe;/* pointer of variable subscribe_ID and subscribe_mask */
uint8_t mob;  /*variable  for Message Object Block in the interrupt routine*/
int8_t can_init; /* variable to call CAN_Init function*/
int8_t timer0_init; /* variable to call Timer0_Init function*/
int8_t timer0A_init;/* variable to call Timer0A_Init function*/
uint8_t ptr_buffer_in; /*pointer to write CAN data in buffer_ring*/
uint8_t ptr_buffer_out; /*pointer to read CAN data in buffer_ring*/

/*define UART-structur */
struct uartStruct uartFrame;
struct uartStruct *ptr_uartStruct;
/*define CAN-structur */
struct canStruct canFrame;
struct canStruct *ptr_canStruct;

int main (void) {
	ptr_uartStruct = &uartFrame;  /* initialize pointer for CPU-struct */
	ptr_canStruct = &canFrame;  /* initialize pointer for CAN-struct */
	/* initialize flag */
	StartValue = 0;
	nextCharPos = 0;
	uartReady = 0;
	canReady = 0;
	timer0Ready = 0;
	timer0AReady = 0;
	ptr_subscribe = 2; /*start value of pointer*/
	ptr_buffer_in = 0; /*initialize pointer for write in buffer_ring*/
	ptr_buffer_out = 0;  /*initialize pointer for read in  buffer_ring*/
	res0 = 0, res1 = 0, res2 = 0, res3 = 0;
	decrypt_uartString[BUFFER_SIZE] = '\0';
	setParameter[MAX_PARAMETER][MAX_LENGTH_PARAMETER]='\0';
	ring_buffer[MAX_INPUT][MAX_LENGTH_CAN_DATA]= '\0';
	
	
	uint8_t i;
	cur_state = idle;

	cli();  /* disable interrupts*/
	UART0_Init();
	init ();
	can_init = CAN_Init(TWOHUNDERTFIFTY_KPS);   /* initialize can-contoller with a baudrate 250kps */
	
	if(-1 == can_init)
	{
		
		general_errorCode = General_Communication_Error(G_ERROR3,G_ERROR3_NO);
		exit(0);	
	}
	else
	{
		timer0_init =Timer0_Init(); /* initialize first timer */
	
	}
	if( 1!= timer0_init )
	{
		general_errorCode = General_Communication_Error(G_ERROR0,G_ERROR0_NO);
		exit(0);
	}
	else
	{
		timer0A_init = Timer0A_Init(); /* initialize second timer*/
		
	}
	if(1!= timer0A_init)
	{
		general_errorCode = General_Communication_Error(G_ERROR1,G_ERROR1_NO);
		exit(0);
	}


	sei();  /* enable interrupts*/
	
	/*pressure is checked only for channel 0*/
	res0 = GetVoltage (0);
	PORTA = PORTA | (0x2); // turn on lamp

	if(Voltages[0] < tlow) {
		cur_state = below_low_thres;
		PORTA = PORTA & (~0x1); // turn off relais
	}
	else if(Voltages[0] > thigh) {
		cur_state = above_high_thres;
		PORTA = PORTA & (~0x1); // turn off relais
	}
	else {
		cur_state = in_between;
		PORTA = PORTA | (0x1); // turn on relais
	}
	
	while(1){
 
		if( 1 == uartReady )/* of the ISR was completely receive a string */
		{  

			cli();
			strncpy( decrypt_uartString, uartString,sizeof(decrypt_uartString));
 			snprintf(tempstr,BUFFER_SIZE-1,"command:%s",decrypt_uartString);
 			UART0_Send_Message_String(tempstr);
			memset(uartString,0,sizeof(uartString));
			Decrypt_Uart_String(decrypt_uartString); 
			uartReady = 0; /* restore flag */
			sei();
		}
	
		if( 1 == canReady  ) /* of the ISR data has been fully received */
		{   

			cli();
			Convert_pack_canFrame_to_UartFormat(ptr_canStruct);
			canReady = 0; /* restore flag */
			sei();
		}

		if(1 == timer0Ready )
		{
                       	cli();
			Get_BusState();
			timer0Ready = 0;
			sei();
		}
	                
		if(1 == timer0AReady )
		{
			cli();
			Get_CanError();
			timer0AReady =0; /* restore flag */
			sei();
		}
	
		res0 = GetVoltage (0);
		switch (cur_state) {
			case in_between: 	  
			{
				if(Voltages[0] > thigh) {

					/*turn off relais*/
					PORTA = PORTA & (~0x1);
					cur_state = above_high_thres;
				}
				if(Voltages[0] < tlow) {
					/*turn off relais*/
					PORTA = PORTA & (~0x1);
					cur_state = below_low_thres;
				}
			}
			break;
			case below_low_thres: 	  
			{
				_delay_ms(100);
				_delay_ms(100);
				PINA = 0x2; // toggle LED

				if(Voltages[0] > tlow +2) {
					/*turn on relais*/
					PORTA = PORTA | (0x3);
					cur_state = in_between;
				}
			}
			break;
			case above_high_thres:
			{

				_delay_ms(100);
				_delay_ms(100);
				PINA = 0x2; // toggle LED

 
				if(Voltages[0] < thigh -2) {
					/* turn on relais and lamp*/
					PORTA = PORTA | (0x3);
					cur_state = in_between;
				}
			}
			break;
			default:
			{
				cur_state = below_low_thres;

			}
		}

		i = i*2;
	
	}/* end of while*/

	
} /* end of main*/
