/*

Giacomo Ortona
This program is running on the ATMEL AT90CAN128 and does the following:
-initialize the USART0 register allowing tx and rx of data
-depending on input data received by the USART0 can:
- read the ID and the the temperature from all the devices connected until a maximum number 
  (defined as 40 rigth now) and send those data as string through USART
-set the higher and lower temperature limit for the issuing of an alarm flag
-read if there is any device which has an alarm flag condition

*/


/*

$Id: temp.c,v 1.1.1.1 2009-09-25 13:06:24 hadaq Exp $
$Source: /misc/hadesprojects/daq/cvsroot/hadcon/CAN_API-Slave/temp.c,v $
$Header: /misc/hadesprojects/daq/cvsroot/hadcon/CAN_API-Slave/temp.c,v 1.1.1.1 2009-09-25 13:06:24 hadaq 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 "OWIDeviceSpecific.h"
#include "OWIHighLevelFunctions.h"
#include "OWIBitFunctions.h"
#include <util/delay.h>

#define BV(x)  (1<<x)
//#define BUSES   (/*OWI_PIN_1 |*/ 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
//protocols 48, b8, are still missing
//protocol b4 is not useful (parasite power)

//NUM-DEVICES is the maximum number of device which the user is allowed to read 
//a baud rate of 4800 produce an error of 0.2%. higher levels of baud rate 
//will produce a consistant increase of the error
#define NUM_DEVICES       40
#define BAUD               7
/*the formula for calculate the UBBR0 value is 
 *  UBBR0= F_CPU/(16*baud)-1
 *the error is given by the formula
 *  (1- closestmatchingbaud/baud)*100
 *
 *for F_CPU = 5000000 some possible baud rates are:
 * 4800 baud=> baud 64 error  0,2%
 * 9600 baud=> baud 32 error -1,4%, too high
 * 38400baud=> baud  7 working
 * 57600baud=> baud  4 not working
 *115200baud=> baud  2 
*/
char temp_str[80];
int break_point(int error_code, uint8_t *s) {
    int i;
    uint8_t *str;
    i = error_code;
    str = s;
    _delay_ms(10);

    return 1;
}

/*
 *this function initialize the USART 0 register needed to allow the at90can128 
 *USART transmissions
*/ 
void USART0_Init (unsigned int baud){
//no tx are possible when the inizialization is going on.
//if is possible, use TXC0 flag.
//interruption should be disabled (cli())
    uint8_t intstate = SREG;
    cli();
/*the TXC flag bit is set 1 when the entire frame in the Transmit Shift Register
 has been shifted out and there are no new data currently present in the transmit
 buffer*/
    while(0<<TXC0){
	}
/* set baud rate*/
    UBRR0H = (uint8_t)(baud>>8);
    UBRR0L = (uint8_t)(baud);
/* set frame format: I wil set it now as 8 bits, no parity 1 stop bit*/
    UCSR0C = (0<<UMSEL0)|(0<<UPM0)|(0<<USBS0)|(3<<UCSZ0);
/*enable transmitter*/
    UCSR0B = (1<<TXEN0)|(1<<RXEN0);
    SREG=intstate;
}

/*this function initialize the register 1 needed to allow the at90can128 USART 
transmissions*/ 
void USART1_Init (unsigned int baud){
//no tx are possible when the inizialization is going on.
//if is possible, use TXC0 flag.
//interruption should be disabled (cli())
    uint8_t intstate = SREG;
    cli();
/*the TXC flag bit is set 1 when the entire frame in the Transmit Shift Register
 has been shifted out and there are no new data currently present in the transmit
 buffer */
    while(0<<TXC1){
	}
/* set baud rate*/
    UBRR1H = (uint8_t)(baud>>8);
    UBRR1L = (uint8_t)(baud);
/* set frame format: I wil set it now as 8 bits, no parity 1 stop bit*/
    UCSR1C = (0<<UMSEL1)|(0<<UPM1)|(0<<USBS1)|(3<<UCSZ1);
/*enable transmitter*/
    UCSR1B = (1<<TXEN1)|(1<<RXEN1);
    SREG=intstate;
}



/* 
 *USART0 must be initialized befor using this function
 *for use this function, be sure that data is no longer then 8 bit 
 *(single character) this function will send  8 bits from the at90can128 
*/
void USART0_Transmit(uint8_t data){
/* wait for empty transmit buffer */
    while(!(UCSR0A & (1<<UDRE0))){
    }
/* put the data into the buffer */
    UDR0 = data;
}

/* 
 *USART1 must be initialized befor using this function
 *for use this function, be sure that data is no longer then 8 bit 
 *(single character) this function will send  8 bits from the at90can128 
*/
void USART1_Transmit(uint8_t data){
/* wait for empty transmit buffer */
    while(!(UCSR1A & (1<<UDRE1))){
    }
/* put the data into the buffer */
    UDR1 = data;
}

/*USART0 must be initialized befor using this function, if data is longer then 
8bit, properly working is not assured*/
uint8_t USART0_Receive (void)
{
  /* Wait for data to be received */
  while ( ! (UCSR0A & (1<<RXC0)));
  /* Get and return received data from buffer */
  return UDR0;
}

/*USART1 must be initialized befor using this function, if data is longer then 
8bit, properly working is not assured*/
uint8_t USART1_Receive (void)
{
  /* Wait for data to be received */
  while ( ! (UCSR1A & (1<<RXC1)));
  /* Get and return received data from buffer */
  return UDR1;
}

/* 
 *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 founded 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*/
    uint8_t onetemp[30];//27 should be enough

/*clean one IDS array*/
	for(int a=0; a<8;a++){
	    IDS[NUM_DEVICES-1][a]=0;
	}
    for(int b=0;b<3;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);
	    }

//this loop will record the IDS and the temperatures on regtemp
	    for(int q=0;q<countDEVbus;q++){
		t = ReadTemperature(pins[b],IDS[q]);
    
		sprintf(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);
/*send the data*/
		for(int j=0;j<strlen(onetemp);j++) {
		    if(onetemp[j]!=('\n'||'\0')) {
/*only non terminating characters have to be sent*/
			USART0_Transmit(onetemp[j]);
		    }
		}
	    }
	}
    }
    USART0_Transmit('\n');/*send a terminating character*/

    return countDEV;
}

/*
 *this function will read the IDÂ´s and temperature of all devices which have an  
 *Alarm Flag condition and will send the data through USART 
 *the function will return the number of devices on the bus with alrm flag
 *
 * 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 AlarmStored (uint8_t * pins) {
    uint16_t t; 
    char PD;
    uint8_t IDS[NUM_DEVICES][8];
    int countDEV = 0;
    int countDEVbus = 0;

    uint8_t res=1;
/*clean one IDS array*/
    for(int a=0; a<8;a++){
	IDS[NUM_DEVICES-1][a]=0;
    }
    for(int b=0;b<3;b++){
/*initialize the bus*/
	OWI_Init(pins[b]);
	countDEV = countDEV + countDEVbus;
	countDEVbus = 0;
	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
	    for(int q=0;q<NUM_DEVICES&&res!=(OWI_ROM_SEARCH_FINISHED||OWI_ROM_SEARCH_FAILED);q++){
		if(q==0){
		    res=0;
		}
		OWI_DetectPresence(pins[b]);
		res=OWI_SearchAlarm(IDS[NUM_DEVICES-1], res, pins[b]);
		for(int a=0;a<8;a++){
		    IDS[q][a]=IDS[NUM_DEVICES-1][a];
		}
		countDEVbus++;
	    }
	
//the number of devices with alarm flag is stored in countDEV
	    if(res!=OWI_ROM_SEARCH_FAILED) {
//this loop will record the IDS and the temperatures on regtemp
		for(int q=0;q<countDEVbus;q++){
		    t=ReadTemperature(pins[b],IDS[q]);
	    
		    char onetemp[50];
		    sprintf((char *)onetemp,"OVERTEMPERATURE %02X%02X%02X%02X%02X%02X%02X%02X %.4X ",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')) {
			    USART0_Transmit(onetemp[j]);
			}
		    }
		}
	    }
	    else {
		countDEVbus=0;
	    }
	}
    }
    USART0_Transmit('\n');
    return countDEV;
}





/*
 *USART0 must be initialized befor using this function
 *this function will transmit the data of the devices (ID and temperature).
 *it does by itself the search for ID's and reads-out the temperature values.
 *needs a pointer to an array in which the data will be stored
 *will return the number of devices connected
*/
int USART0SendData (uint8_t *regist, uint8_t *pin) {

    int numdevices;
    numdevices = TempStored(pin);
    int length = strlen((char *)regist);	     
    for(int q=0; q<=length;q++){
	if(q==length){
	    USART0_Transmit('\n');
	}
	else {
/*in this way the string will end as \n and not \n\0*/
	    USART0_Transmit(regist[q]);
	}
    }
    return numdevices;
}

/*
 *USART1 must be initialized befor using this function
 *this function will transmit the data of the devices (ID and temperature).
 *it does by itself the search for ID's and reads-out the temperature values.
 *needs a pointer to an array in which the data will be stored
 *will return the number of devices connected
*/
int USART1SendData (uint8_t *regist, uint8_t * pin) {

    int numdevices;
    numdevices = TempStored(pin);
    int length = strlen((char *)regist);	     
    for(int q=0; q<=length;q++){
	if(q==length){
	    USART1_Transmit('\n');
	}
	else {
/*in this way the string will end as \n and not \n\0*/
	    USART1_Transmit(regist[q]);
	}
    }
    return numdevices;
}


int main (void){
/* BUSES are the bitmasks of the pins on which the 1-wire buses are connected
   brate is the serial transmission baud rate
   regtemp is a string where the datas (Ids and temperatures) are stored
   usercommand is the command that defines what action to perform
*/
    uint8_t BUSES[3]={OWI_PIN_1,OWI_PIN_2,OWI_PIN_3};
    unsigned int brate = BAUD; //baud has to be defined, look at the definitions
                               // of signed int
    uint8_t usercommand;
    sprintf(temp_str, "baudrate: %d", brate);
    USART1_Transmit(temp_str);
//   uint8_t commandstring[120]="a: read temperature; b: set alarm flags"
    USART0_Init(brate);
    while(1)
    {
/*
  receive the order from the user:
  a: read the temperatures (and send datas)
  b: set alarm flag on 1 device
  c: scans for alarm conditions
  any other: error message
*/
	usercommand = /*USART0_Receive();*/'a';
	switch(usercommand) {
	    case 'a'|'A': {
		TempStored(BUSES);
	    }
		break;
	    case 'b'|'B': {
		/*set temperatures limits*/
		uint8_t thigh,tlow;
		uint8_t numdev[8];
		thigh=USART0_Receive();
		tlow=USART0_Receive();
		for(int w=0;w<8;w++) {
		    numdev[w]=USART0_Receive();
		    
		}


/*  countdet is used to scan on all the buses. at the end of scanning will keep 
  the value of the array position of the bus on which is placed the searched 
  device
*/
		int countdet;
/*search for the buses on which the sensor is placed*/
		for(countdet=0;countdet<3;countdet++) {
		    if(OWI_DetectPresence(BUSES[countdet])!=0) {

/*check if the given ID is known*/
			uint16_t t = ReadTemperature(BUSES[countdet],numdev);
			if(t!=0xffff) {
/*impose loop terminating condition*/
			    countdet = countdet + 20;
			}
		    }
		}
		countdet = countdet - 21;
		if(countdet<0) {// Error
		    uint8_t resultstring[55]="failed on setting temp limits, no bus detected"; 
		    int j;//loop counter
		    for(j=0;j<=strlen((char *)resultstring);j++) {
			if(j!=strlen((char *)resultstring)) {
			    USART0_Transmit(resultstring[j]);
			}
			else {
			    USART0_Transmit('\0');
			}
		    }
		}
		else {
/*device founded, overwrite the memory*/
		    OWI_MatchRom(numdev,BUSES[countdet]);
		    OWI_SendByte(DS1820_WRITE_SCRATCHPAD,BUSES[countdet]);
		    OWI_SendByte(thigh,BUSES[countdet]);
		    OWI_SendByte(tlow,BUSES[countdet]);
		    OWI_SendByte(DS1820_CONFIG_REGISTER,BUSES[countdet]);
		    uint8_t resultstring[35]="setted new temperatures limits";
		    int j;//loop counter
		    for(j=0;j<=strlen((char *)resultstring);j++) {
			if(j!=strlen((char *)resultstring)) {
			    USART0_Transmit(resultstring[j]);
			}
			else {
			    USART0_Transmit('\0');
			}
		    }
		}
	    }
		
		
		break;//end of set limits
	    case 'c'|'C': {
		if(AlarmStored(BUSES)!=0){
		    USART0_Transmit('\n');
		}
		
	    }
		break;
	    default: {
		int j;//loop counter
		uint8_t errorstring[35]="Error, unknown command received";
		for(j=0;j<=strlen((char *)errorstring);j++) {
		    if(j!=strlen((char *)errorstring)) {
			USART0_Transmit(errorstring[j]);
		    }
		    else {
			USART0_Transmit('\0');
		    }
		}
	    }
	} // end of switch
	
	break_point(1,"end of main\n");
	
    }
    
    return 0;
}

