/*
 * 
 * Author: Michael Traxler based on Giacomo Ortona's hadtempsens
 * 
 * This program is running on the ATMEL AT90CAN128 and does the following:
 * - initialize the USART0 register allowing tx and rx of data - depending
 * on the input data received by the USART0 one can set the threshold of
 * the ADC.
 * 
 * - If the ADC input voltage is larger than the value set, a digital
 * output is set from 3.3V to 0V 
 */


/*
 * $Id: gas_temp_monitor.c,v 1.2 2009-10-12 23:51:57 hadaq Exp $ $Source:
 * /home/giacomo/cvsroot/hadtempsens/tempsens2.c,v $ $Header:
 * /home/giacomo/cvsroot/hadtempsens/tempsens2.c,v 1.33 2006/09/22
 * 10:40:08 giacomo Exp $
 * 
 */

#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)

uint8_t BUSES[5] = { OWI_PIN_2 };

#define DS1820_START_CONVERSION         0x44
#define DS1820_READ_SCRATCHPAD          0xbe
#define DS1820_WRITE_SCRATCHPAD         0x4E
#define DS1820_CONFIG_REGISTER          0x7f
#define DS1820_READ_POWER               0xb4

#define NUM_DEVICES       20
#define TRUE   1
#define FALSE   0

#define ADC_CYCLES 3 /*the number of ADC conversions done to get an average voltage value*/


#define ADC_TIMEOUT 1000 /*wait ADC_TIMEOUT clock cycles for a single ADC conversion*/

enum states {idle, below_low_thres, in_between , above_high_thres };
//uint16_t Voltages[8];		/*current supply voltages of the board*/


 /*This function initializes all input /output of the microcontroller
 *the  function has no input and output variable
 */
 void init (void)
 {

	 uint8_t intstate = SREG; /* save global interrupt flag */
	 cli ();

	 /* use port A as output*/
	 DDRA = 0xFF;
	 PORTA = 0x00;


	 /* use port B as input with activated pullups*/
	 DDRB = 0x00;
	 PORTB = 0xFF;


	 DDRC = 0xff & (~0x4);
         //DDRC = 0x08;
	 PORTC = 0xff;
         //PORTC = 0x00;


	 /* use port E as input with activated pullups*/
	 DDRE = 0x00;
	 PORTE = 0xFF;

	 /* use port F as input with ctivated pullups*/
	 DDRF = 0x00;
	 PORTF = 0xFF;

	 /* enable ADC and set clock prescale factor to 64 (p.280)*/
	 ADCSRA = BIT (ADEN) | 0x06;
	 /* 0x80 => ADEN => enable ADC*/

	 /* low speed and manually triggered ADC conversion mode*/
	 ADCSRB = 0;

	 /* deactivate digital input buffer for used ADC pins*/
#ifdef DISABLE_JTAG
	 DIDR0 = 0xFF;
	 /*MCUCR |= 0x80;   // deactivate whole JTAG interface */
#else
	 DIDR0 = 0x0F;
#endif

	 /* enable only compare match interrupt on timer 1, channel A*/
	 TIMSK1 = 0x02;

	 /* normal counter mode (no wave and/or PWM stuff) for timer 1, channel A*/
	 TCCR1A = 0;
	 TCCR1C = 0;

	 SREG=intstate; /*restore global interrupt flag */

 }				

 
 /* 
 *this function will read the data conteined in the scratchpad of the device 
 *identified by the id ID number
 *will return the temperature value stored in the scratchpad
 *if an error occurs, this function will return a temp lower then -900 degrees
 */
 uint16_t ReadTemperature(unsigned char bus, unsigned char * id)
 {
	 uint16_t temperature;
    
	 /* Reset, presence.*/
    
	 if (OWI_DetectPresence(bus)==0)
	 {
		 return -999; // Error
	 }

	 /* Match id found earlier*/
	 OWI_MatchRom(id, bus);
	 /*Send READ SCRATCHPAD command.*/
	 OWI_SendByte(DS1820_READ_SCRATCHPAD, bus);
	 /* Read only two first bytes (temperature low, temperature high)*/
	 /* and place them in the 16 bit temperature variable.*/

	 temperature = OWI_ReceiveByte(bus); 
	 temperature |= (OWI_ReceiveByte(bus) << 8);
	 return temperature;
 }


 
 /*
 *  this function will read the IDÂ´s and temperatures of a certain number of 
 * devices limited between 1 and NUM-DEVICES and will send the data through 
 *  USART register 
 * the function will return the number of devices on the bus 
 * t is an array used for the storage of the temperatures values
 * IDS is a 2D array used for storage the sensors IDÂ´s 
 */
 int TempStored (uint8_t *pins) {

	 uint16_t t; 
	 char PD;
	 uint8_t IDS[NUM_DEVICES][8];
	 int countDEV = 0;/*number of devices*/
	 int countDEVbus = 0;/*number of devices on the current bus*/
	 /*on onetemp are written the data to be sent away*/
 	 char onetemp[60]; /*on onetemp are written the data to be sent away*/
	 //char pp[255];

	
//  	 strncat(pp,"RECV ",BUFFER_SIZE-1); 
//  	 snprintf(tempstr,BUFFER_SIZE-1,"%s",pp);
// 	 UART1_Send_Message_String(tempstr);
// 	 strncat(onetemp,pp,BUFFER_SIZE-1 ); 

	 // PORTC |= 0x8;// pin4 to high for power supply
	 /*clean one IDS array*/

	 for (int d=0; d<NUM_DEVICES; d++) {
	     for(int a=0; a<8;a++){
		 IDS[d][a]=0;
	     }
	 }
	 for(int b=0;b<1;b++) {
		 /*initialize the bus*/
		 OWI_Init(pins[b]);
		 uint8_t res=1;
		 countDEV = countDEV + countDEVbus;
		 countDEVbus=0;//reset number of devices on the bus

		 if((PD=OWI_DetectPresence(pins[b]))!=0) {
/*this will search the devices Id´s till the max number of devices is reached or
 *all the devices have been read out		
 */
			 while(countDEVbus<NUM_DEVICES&&res!=OWI_ROM_SEARCH_FINISHED){
				 if(countDEVbus==0){
					 res=0;
				 }
				 OWI_DetectPresence(pins[b]);
				 res=OWI_SearchRom(IDS[NUM_DEVICES-1], res, pins[b]);
				 for(int a=0;a<8;a++){
					 IDS[countDEVbus][a]=IDS[NUM_DEVICES-1][a];
				 }
				 countDEVbus++;
			 }

			 /*order to all the devices on the bus to perform a temp conversion*/
			 OWI_DetectPresence(pins[b]);
			 OWI_SendByte(OWI_ROM_SKIP, pins[b]);
			 OWI_SendByte(DS1820_START_CONVERSION, pins[b]);
			 while (OWI_ReadBit(pins[b])==0) {
			     _delay_us(100);
			     _delay_us(100);
			 }

			 /*this loop will record the IDS and the temperatures on regtemp*/
			 for(uint8_t q = 0; q < countDEVbus; q++){
				 t = ReadTemperature(pins[b],IDS[q]);
    
				 snprintf(onetemp,sizeof(onetemp),"%d: %02X%02X%02X%02X%02X%02X%02X%02X %.4X ",q+countDEV,IDS[q][0],IDS[q][1],IDS[q][2],IDS[q][3],IDS[q][4],IDS[q][5],IDS[q][6],IDS[q][7],t);
				

				 for(int j=0;j<strlen(onetemp);j++) {
					 if(onetemp[j]!=('\n'||'\0')) {
						 /*only non terminating characters have to be sent*/
						// strncat(onetemp[0],"RECV",BUFFER_SIZE-1); 
						 UART0_Transmit(onetemp[j]);
						
						 			
					 }
				 }
			 }
			 
		 }
	 }

	 UART0_Transmit ('\n');
	 memset(onetemp,0,sizeof(onetemp)); /*clear tempstr variable*/
	 return countDEV;
 }


 void toggle_pin (unsigned char pin_number)
 {
	 long int i, c, d;
	 _delay_ms (10);
	 for (i = 0; i <= 50; i++)
	 {
		 _delay_ms (10);
		 d = d + i * c;
		 c = d + i;
	 }
         /*toggle FrontLED*/
	 PINA = 0x3;
 }


 enum
 {
	 eNoError = 0,
	 eWrongCANAddress = 1,		// bogus address set on hex-switches
	 eCANDataSize = 2,		// bogus amount of bytes arrived
	 eI2CTimeout = 4,		// I²C problem
	 eI2CFatalError = 8,		// I²C problem
	 eI2CRetryFailed = 16,		// I²C problem
	 eADCTimeout = 32,		// ADC conversion failed
	 eCPLDAcknowledgeTimeout = 64	// CPLD communication problem
 } ErrorCodes;

 /*this function reads and converts the voltage of the ADC-4 channels
 * as input parameters the function needs number of channel to read a voltage
 * the value returned is the voltage read from the channel
 */

 int GetVoltage (unsigned int channel_nr)
 {
	 uint16_t Timeout;
	 uint16_t Value;
	 uint16_t iStep;
	 int16_t TotalValue;
//          snprintf (tmp_str,BUFFER_SIZE-1," channel_nr %d",channel_nr);
// 	 UART0_Send_Message_String (tmp_str);

#ifndef DISABLE_JTAG
  /* we need the JTAG interface, thus do not measure
   *the upper four ADC channels (used for JTAG, too)
  */
	 if (channel_nr > 3)
	 {
		 Voltages[channel_nr] = 0;
		 return eNoError;
	 }
#endif

  /*use 3.3V supply voltage as reference voltage 
  * and select the voltage to be measured*/
	 ADMUX = 0x40 | (unsigned char) channel_nr;
	 /*ADMUX = 0x40 | 0x1B;*/

	 TotalValue = 0;
	 for (iStep = 0; iStep < ADC_CYCLES; iStep++)
	 {
		 /* start a new single conversion*/
		 ADCSRA |= BIT (ADSC);

		 /* wait until conversion is complete*/
		 Timeout = ADC_TIMEOUT;
		 while (!(ADCSRA & BIT (ADIF)) && (--Timeout > 0));

		 /* clear interrupt flag from former conversion*/
		 ADCSRA |= BIT (ADIF);

		 if (Timeout == 0)
		 {
			 return eADCTimeout;
		 }

		 /*one must read ADCL before ADCH!*/
		 Value = ADCL;
		 Value |= (unsigned int) (ADCH & 0x03) << 8;

		 TotalValue += Value;
	 }
	
	 TotalValue = TotalValue /ADC_CYCLES;
	

	 /*save results*/
	 Voltages[channel_nr] = (uint16_t) TotalValue;

	 return eNoError;
 }



 /*this function reads the temperatur of sensor  
 * as input parameters the function needs only a keyword 
 * the function has no return parameter
 */

 void readTempSensor(struct uartStruct *ptr_uartStruct)
 {
	 uint8_t i;
	 for(i=0; i<=1;i++) {
		 _delay_ms (10);
	 }
	 res0 = GetVoltage (0);
	 res1 = GetVoltage (1);
	 if (res0 != 0 || res1 != 0)
	 {
		 snprintf (tmp_str,BUFFER_SIZE-1, "ERRG error in GetVoltage: res: %d", res0);
		 UART0_Send_Message_String(tmp_str);
	 }
		
	 TempStored(BUSES);
		
	 _delay_ms(100);
 }

 /*this function reads the pressure in the bus 
 * as input parameters the function needs only a keyword 
 * the function has no return parameter
 */
 void readStatus(struct uartStruct *ptr_uartStruct)
 {
	 char *tmp_str2;
	 switch (cur_state) {
		 case in_between: 
		 {
			 tmp_str2 = "Pressure is OK";
		 }
		 break;
		 default:
		 {
			 tmp_str2 = "Pressure not OK!" ;
		 }
	 }

	 snprintf(tmp_str,BUFFER_SIZE-1,"ERRG%s", tmp_str2);
	 UART0_Send_Message_String(tmp_str);

 }

 /*this function takes the value of the voltage read from the ADC-channel 
 * and convert it in the form of the API 
 * as input parameters the function needs a keyword and the number of channel
 * the function has no return parameter
 */
 
 void read_ADC(struct uartStruct *ptr_uartStruct)
 {	 
	
	 for( int i = 0; i <= 1; i++) 
	 {
		 _delay_ms (10);
	 }
	 res0 = GetVoltage (0);
	 res1 = GetVoltage (1);
	 res2 = GetVoltage (2);
	 res3 = GetVoltage (3);
	 if( 3 < ptr_uartStruct->Uart_Message_ID)
	 {      
		 snprintf (tmp_str ,BUFFER_SIZE-1,"ERRG channel undefined");
		 UART0_Send_Message_String (tmp_str);	 
	 }
	 if(0 == ptr_uartStruct->Uart_Message_ID)
	 {
		 snprintf (tmp_str,BUFFER_SIZE-1,"RECV %d voltage of channel 0", Voltages[0]);
		 UART0_Send_Message_String (tmp_str); 
	 }
	 if(1 == ptr_uartStruct->Uart_Message_ID)
	 {
		 snprintf (tmp_str,BUFFER_SIZE-1, "RECV %d voltage of channel 1", Voltages[1]);
		 UART0_Send_Message_String (tmp_str);
	 }
	 if(2 == ptr_uartStruct->Uart_Message_ID)
	 {
		 snprintf (tmp_str,BUFFER_SIZE-1, "RECV %d voltage of channel 2", Voltages[2]);
		 UART0_Send_Message_String (tmp_str);
	 }
	 if(3 == ptr_uartStruct->Uart_Message_ID)
	 {	
		 snprintf (tmp_str,BUFFER_SIZE-1, "RECV %d voltage of channel 3", Voltages[3]);
		 UART0_Send_Message_String (tmp_str);
	 }
         if ((res0 != 0) ||( res1 != 0) || (res2 != 0)  || (res3 != 0))
	 {
		 snprintf (tmp_str,BUFFER_SIZE-1, "ERRG error in GetVoltage: res: %d", res0);
		 UART0_Send_Message_String (tmp_str);
	 }

	 _delay_ms(100);

 }
 
 
//  /* this function writes a value the status in the register with the of his adress 
//  * as input parameters the function needs a keyword, an adress and a value
//  * the function has no return parameter
//  */
//  void writeRegister(struct uartStruct *ptr_uartStruct)
//  { 
// 	 
// 	 if(0XFF < ptr_uartStruct->Uart_Message_ID) 
// 	 { 
// 		 uart_errorCode = Communication_Error(S_ERROR9,S_ERROR9_NO, "erra");
// 	 }
// 	 else if(0XFF < ptr_uartStruct->Uart_Mask) 
// 	 {
// 		 uart_errorCode = Communication_Error(S_ERROR11,S_ERROR11_NO, "erra");
// 	 }
// 	 else
// 	 {
// 		 StartValue = 1;
// 		 Adr_Reg = ptr_uartStruct->Uart_Message_ID;
// 		 Val_Reg= ptr_uartStruct->Uart_Mask;
// 		 Ptr_Reg = Adr_Reg;
// 		 *Ptr_Reg = Val_Reg;
// 		 snprintf(tempstr,BUFFER_SIZE-1,"RECV the value %x has been written in adresse %x", Val_Reg,Adr_Reg);
// 		 UART0_Send_Message_String(tempstr);
// 	 }
// 	   
//  }
//  
//  /*this function reads the status of a register with the of his adress
//  * as input parameters the function needs a keyword and an adress
//  * the function has no return parameter
//  */
//  void readRegister(struct uartStruct *ptr_uartStruct)
//  { 
// 	 
// 	
// 	 if(0XFF < ptr_uartStruct->Uart_Message_ID) 
// 	 { 
// 		 uart_errorCode = Communication_Error(S_ERROR9,S_ERROR9_NO, "erra");
// 	 }
// 	 else if(0XFF < ptr_uartStruct->Uart_Mask) 
// 	 {
// 		 uart_errorCode = Communication_Error(S_ERROR11,S_ERROR11_NO, "erra");
// 	 } 
// 	 else{
// 		 uint8_t  *rAdr_Reg;
// 
// 		 if(0 == StartValue){
// 
// 			 rAdr_Reg = ptr_uartStruct->Uart_Message_ID;
// 			 snprintf(tempstr,BUFFER_SIZE-1,"RECV %x",*rAdr_Reg);
// 			 UART0_Send_Message_String(tempstr);	 
// 		 } 
// 		 
// 		 if(1 == StartValue)
// 		 {
// 			 snprintf(tempstr,BUFFER_SIZE-1,"RECV %x",Val_Reg);
// 			 UART0_Send_Message_String(tempstr);
// 			 StartValue = 0;
// 		 }	
// 	 }
// 	
//  }
//  

