/*
 * owdevice.c
 *
 * Created: 24.01.2012 14:11:43
 *  Author: Tobias Mueller, mail(at)tobynet.de
 * Bitte bei weiterer Verabeitung immer angeben
 */



#include <avr/io.h>
#include <avr/interrupt.h>
#ifdef __AVR_ATmega32__
#include "uart.h"
#include <util/delay.h>
#endif
//DEVICES 
#ifdef __AVR_ATtiny13A__ 

// OW_PORT Pin 6  - PB1

#define OW_PORT PORTB
#define OW_PIN PINB
#define OW_PORTN (1<<PINB1)
#define OW_PINN (1<<PINB1)
#define OW_DDR DDRB

#define SET_LOW OW_DDR|=OW_PINN;OW_PORT&=~OW_PORTN;
#define RESET_LOW {OW_DDR&=~OW_PINN;}
#define EN_OWINT {GIMSK|=(1<<INT0);GIFR|=(1<<INTF0);}
#define DIS_OWINT  GIMSK&=~(1<<INT0);
#define EN_TIMER {TIMSK0 |= (1<<TOIE0); TIFR0|=(1<<TOV0);}
#define DIS_TIMER TIMSK0  &= ~(1<<TOIE0); 

#define CHK_INT_EN (GIMSK&(1<<INT0))==(1<<INT0)


#define OWT_MAX_RESET 82
#define OWT_MIN_RESET 50

#define OWT_RESET_PRESENT 4
#define OWT_PRESENT 20 //144
#define OWT_READLINE 4
#define OWT_LOWTIME 4 //60 Gemessen 58


#define TIMER_INT ISR(TIM0_OVF_vect)
#define PIN_INT ISR(INT0_vect)

#define TCNT_R TCNT0

#define DBH PORTB|=(1<<PORTB4);
#define DBL PORTB&=~(1<<PORTB4);

#endif //ATtiny13


#ifdef __AVR_ATtiny25__ 

// OW_PORT Pin 7  - PB2

#define OW_PORT PORTB
#define OW_PIN PINB
#define OW_PORTN (1<<PINB2)
#define OW_PINN (1<<PINB2)
#define OW_DDR DDRB

#define SET_LOW OW_DDR|=OW_PINN;OW_PORT&=~OW_PORTN;
#define RESET_LOW {OW_DDR&=~OW_PINN;}
#define EN_OWINT {GIMSK|=(1<<INT0);GIFR|=(1<<INTF0);}
#define DIS_OWINT  GIMSK&=~(1<<INT0);
#define EN_TIMER {TIMSK |= (1<<TOIE0); TIFR|=(1<<TOV0);}
#define DIS_TIMER TIMSK  &= ~(1<<TOIE0); 

#define CHK_INT_EN (GIMSK&(1<<INT0))==(1<<INT0)


#define OWT_MAX_RESET 82
#define OWT_MIN_RESET 55

#define OWT_RESET_PRESENT 4
#define OWT_PRESENT 20 //144
#define OWT_READLINE 4
#define OWT_LOWTIME 4 //60 Gemessen 58


#define TIMER_INT ISR(TIM0_OVF_vect)
#define PIN_INT ISR(INT0_vect)

#define TCNT_R TCNT0

/*#define DBH PORTB|=(1<<PORTB4);
#define DBL PORTB&=~(1<<PORTB4);
*/
#endif //ATtiny25


#ifdef __AVR_ATmega32__
		
#define OW_PORT PORTD
#define OW_PIN PIND
#define OW_PORTN (1<<PIND2)
#define OW_PINN (1<<PIND2)
#define OW_DDR DDRD

#define SET_LOW OW_DDR|=OW_PINN;OW_PORT&=~OW_PORTN;
#define RESET_LOW {OW_DDR&=~OW_PINN;} //llastp=1;
#define EN_OWINT {GICR|=(1<<INT0);GIFR|=(1<<INTF0);} //INTF0 cleared by writing a logical one in it
#define DIS_OWINT GICR&=~(1<<INT0);
#define EN_TIMER {TIMSK |=(1<<TOIE1);TIFR|=(1<<TOV1);}
#define DIS_TIMER TIMSK &=~(1<<TOIE1);


#define CHK_INT_EN (GICR&(1<<INT0))==(1<<INT0)

#define OWT_MAX_RESET 660
#define OWT_MIN_RESET 400
#define OWT_RESET_PRESENT 30
#define OWT_PRESENT 160 //144
#define OWT_READLINE 25
#define OWT_LOWTIME 30 //60 Gemessen 58
#define OWT_HIGHTTIME 64
#define OWT_PAUSE 10

#define TIMER_INT ISR(TIMER1_OVF_vect) 
#define PIN_INT ISR(INT0_vect)

#define DBH PORTD|=(1<<PORTD4);
#define DBL PORTD&=~(1<<PORTD4);


#define TCNT_R TCNT1

#include <stdlib.h>
#include "uart.h"
volatile uint8_t dbbuf[256];
volatile uint8_t b1,b2;
#endif //ATmega32

volatile uint8_t cbuf; //Empfangspuffer fuer einen Befehl

const uint8_t owid[8]={0x1D,0xA2,0xD9,0x84,0x02,0x00,0x00,0xc4};;
volatile uint8_t bitp;  //Zeiger auf das aktuelle Byte
volatile uint8_t bytep; //Zeuger auf das aktuelle Bit

typedef union {
	volatile uint8_t bytes[13];//={1,1,2,0,0,0,0,0,0,0,0,5,5};
	struct {
		uint16_t addr;
		uint8_t read;
		uint32_t counter;
		uint32_t zero;
		uint16_t crc;
	};
} scratchpad_t;
scratchpad_t scratchpad;
volatile uint16_t scrc; //CRC berechnung

volatile uint8_t mode; //Zustand
volatile uint8_t wmode; //wenn 0 wird bei naechsten fallenden Flanke ein 0-Bit geschrieben
volatile uint8_t actbit; //aktuelles Bit
volatile uint8_t srcount; //Zaehler fur search rom und //Zaehler fuer die Pagebytes

volatile uint8_t lastcps;


volatile uint32_t Counter0;
volatile uint32_t Counter1;

volatile uint8_t istat;


#define OWM_CHK_RESET 8
#define OWM_SLEEP 0  
#define OWM_RESET 1
#define OWM_PRESENT 2
#define OWM_READ_COMMAND 3
#define OWM_SEARCH_ROM 4
#define OWM_MATCH_ROM 5
#define OWM_GET_ADRESS 6
#define OWM_READ_MEMORY_COUNTER 7



#define OWW_NO_WRITE 2
#define OWW_WRITE_1 1
#define OWW_WRITE_0 0


#define DBW(x) {dbbuf[b1]=x;b1++;}

//#undef DBW(x)
//#define DBW(x) 


PIN_INT {
	uint8_t lwmode=wmode;
	uint8_t lmode=mode;
	if ((lwmode==OWW_WRITE_0)) {SET_LOW;}   //Wenn notwenig 0-Bit setzten
	DIS_OWINT;
	switch (lmode) {
		case OWM_SLEEP: 
			TCNT_R=~(OWT_MIN_RESET);
			EN_OWINT; //Andere Flanken?
			break;
		case OWM_CHK_RESET:  //Steigende Flanke
			MCUCR&=~(1<<ISC00); //Fallende flanke=(1<<ISC01);
			TCNT_R=~(OWT_RESET_PRESENT);
			lmode=OWM_RESET;
			break;
		case OWM_MATCH_ROM:  //Fallende Flanke warten auf Empfang
		case OWM_GET_ADRESS:
		case OWM_READ_COMMAND:
			TCNT_R=~(OWT_READLINE); //Eine Zeit warten dann auslesen
			break;
		case OWM_SEARCH_ROM:   //Suchalgorithus entweder wurde gesendet oder warten auf Empfang#
			if (srcount<2) {
				TCNT_R=~(OWT_LOWTIME);
				lwmode=OWW_NO_WRITE;		
			} else 
				TCNT_R=~(OWT_READLINE);
			break;
		case OWM_READ_MEMORY_COUNTER:
			TCNT_R=~(OWT_LOWTIME);
			lwmode=OWW_NO_WRITE;
			break;
	}
	EN_TIMER;
	mode=lmode;
	wmode=lwmode;
	
}			

	

TIMER_INT {
	uint8_t lwmode=wmode;
	uint8_t lmode=mode;
	uint8_t lbytep=bytep;
	uint8_t lbitp=bitp;
	uint8_t lsrcount=srcount;
	uint8_t lactbit=actbit;
	uint16_t lscrc=scrc;
	//Abfrage Port
	uint8_t p=((OW_PIN&OW_PINN)==OW_PINN);
	//Interupt noch aktiv ?
	if (CHK_INT_EN) {
		//Wahrscheinlich Reset impuls im gange (Kein Interupt ausgeloest und signal noch Low)
		if (p==0) { 
			lmode=OWM_CHK_RESET;  //Warten auf steigende Flanke
			MCUCR|=(1<<ISC01)|(1<<ISC00); //Steigende Flanke
		}
		DIS_TIMER;
	} else {
		switch (lmode) {
			case OWM_RESET:
				lmode=OWM_PRESENT;
				SET_LOW;
				TCNT_R=~(OWT_PRESENT);
				DIS_OWINT;
				break;
			case OWM_PRESENT:
				RESET_LOW;
				lmode=OWM_READ_COMMAND;
				cbuf=0;lbitp=1;
				break;
			case OWM_READ_COMMAND:
				if (p) {
					cbuf|=lbitp;
				} 
				lbitp=(lbitp<<1);
				if (!lbitp) {
					lbitp=1;
					switch (cbuf) {
						case 0x55:lbytep=0;lmode=OWM_MATCH_ROM;break;
						case 0xF0:
							lmode=OWM_SEARCH_ROM;
							lsrcount=0;
							lbytep=0;
							lactbit=(owid[lbytep]&lbitp)==lbitp;
							lwmode=lactbit;
							break;
						case 0xA5:
							lmode=OWM_GET_ADRESS;
							lbytep=0;lscrc=0x7bc0; //CRC16 von 0xA5
							scratchpad.bytes[0]=0;
							break;
						default: lmode=OWM_SLEEP;
					}	
				}			
				break;
			case OWM_SEARCH_ROM:
				RESET_LOW;
				lsrcount++;
				switch (lsrcount) {
					case 1:lwmode=!lactbit;
						break;
					case 3:
						if (p!=(lactbit==1)) {
							lmode=OWM_SLEEP;
						} else {
							lbitp=(lbitp<<1);
							if (lbitp==0) {
								lbitp=1;
								lbytep++;
								if (lbytep>=8) {
									lmode=OWM_SLEEP;
									break;
								}
							}				
							lsrcount=0;
							lactbit=(owid[lbytep]&lbitp)==lbitp;
							lwmode=lactbit;
						}		
						break;			
				}
				break;
			case OWM_MATCH_ROM:
				if (p==((owid[lbytep]&lbitp)==lbitp)) {
					lbitp=(lbitp<<1);
					if (!lbitp) {
						lbytep++;
						lbitp=1;
						if (lbytep>=8) {
							lmode=OWM_READ_COMMAND;
						
							cbuf=0;
							break;			
						}
					} 
				} else {
					lmode=OWM_SLEEP;
				}
				break;
			case OWM_GET_ADRESS:  
				if (p) {
					scratchpad.bytes[lbytep]|=lbitp;
				}  
				if ((lscrc&1)!=p) lscrc=(lscrc>>1)^0xA001; else lscrc >>=1;
				lbitp=(lbitp<<1);
				if (!lbitp) {	
					lbytep++;
					lbitp=1;
					if (lbytep==2) {
						lmode=OWM_READ_MEMORY_COUNTER;
						lactbit=(lbitp&scratchpad.bytes[lbytep])==lbitp;
						lwmode=lactbit;
						lsrcount=(scratchpad.addr&0xfe0)+0x20-scratchpad.addr;
						break;
					} else scratchpad.bytes[lbytep]=0;
				}			
				break;	
			case OWM_READ_MEMORY_COUNTER:
				RESET_LOW;
				if ((lscrc&1)!=lactbit) lscrc=(lscrc>>1)^0xA001; else lscrc >>=1;
				p=lactbit;
				lbitp=(lbitp<<1);
				if (!lbitp) {		
					lbytep++;
					lbitp=1;
					if (lbytep==3) {
						lsrcount--;
						if (lsrcount) lbytep--;
						else  {
							switch (scratchpad.addr&0xFe0) {
							case 0x1E0:
								scratchpad.counter=Counter0;
								break;
							case 0x1C0:
								scratchpad.counter=Counter1;
								break;
							default: scratchpad.counter=0;
							} 
						}
					}
					if (lbytep>=13) {
						lmode=OWM_SLEEP;
						break;			
					}  		 
						if ((lbytep==11)&&(lbitp==1)) {
							scratchpad.crc=~lscrc;
					}			
					 
				}					
				lactbit=(lbitp&scratchpad.bytes[lbytep])==lbitp;
				lwmode=lactbit;
			
				break;
			}
		}			



		if (lmode==OWM_SLEEP) {DIS_TIMER;}
		if (lmode!=OWM_PRESENT)  { 
			TCNT_R=~(OWT_MIN_RESET-OWT_READLINE);  //OWT_READLINE ist ungefaehr OWT_LOWTIME
			EN_OWINT;
		}
		
		mode=lmode;
		wmode=lwmode;
		bytep=lbytep;
		bitp=lbitp;
		srcount=lsrcount;
		actbit=lactbit;
		scrc=lscrc;
		
			
}

#ifdef __AVR_ATtiny25__ ||  __AVR_ATtiny13A__

ISR(PCINT0_vect) {
	if (((PINB&(1<<PINB3))==0)&&((istat&(1<<PINB3))==(1<<PINB3))) {
		Counter0++;
	}		
	if (((PINB&(1<<PINB4))==0)&&((istat&(1<<PINB4))==(1<<PINB4))) {
		Counter1++;
	}		
	istat=PINB;
	
}	

#endif

#ifdef  __AVR_ATmega32__
ISR(INT1_vect) {
	if ((PIND&(1<<PIND3))==0) {
		scratchpad.counter++;
	}		
	DBW(0x11)
	
}	
#endif



int main(void) {
	mode=OWM_SLEEP;
	wmode=OWW_NO_WRITE;
	OW_DDR&=~OW_PINN;
	
	
	
	for(uint8_t i=0;i<sizeof(scratchpad);i++) scratchpad.bytes[i]=0;
	Counter0=0;
	Counter1=0;
#ifdef __AVR_ATtiny25__
	MCUCR=(1<<ISC01); //Fallende flanke
	CLKPR=(1<<CLKPCE);
	CLKPR=0; //8Mhz
	TIMSK=0;

	GIMSK=(1<<INT0)|(1<<PCIE);
	TCCR0B=(1<<CS00)|(1<<CS01); //8mhz /64 wegen 8 bit Timer also aller 8us
// Counter Interupt

	PCMSK=(1<<PCINT3)|(1<<PCINT4);
	DDRB &=~((1<<PINB3)|(1<<PINB4));
	istat=PINB;
#endif

#ifdef __AVR_ATtiny13A__
	MCUCR=(1<<ISC01); //Fallende flanke
	CLKPR=(1<<CLKPCE);
	CLKPR=0; //9.6Mhz
	TIMSK0=0;

	GIMSK=(1<<INT0)|(1<<PCIE);
	TCCR0B=(1<<CS00)|(1<<CS01); //9.6mhz /64 wegen 8 bit Timer also aller 6,666us
// Counter Interupt

	PCMSK=(1<<PCINT3);
	DDRB &=~(1<<PINB3);
#endif


#ifdef __AVR_ATmega32__
	MCUCR=(1<<ISC01)|(1<<ISC11); //Fallende flanke
	GICR=(1<<INT0)|(1<<INT1);
	TCCR1B=0x00;
	TCCR1B|=(1<<CS11); //Systemtackt durch 8 also 1 us
	TCNT_R=0;
	b1=b2=0;
	
	init_uart0(0);
	uart_puts("\nHallo\n");
	char s[16];
	b1=b2=0;
	DDRD|=(1<<PIND4);
	PORTD|=(1<<PORTD4);	
	
	//DDRD|=(1<<PIND3);
	PORTD|=(1<<PORTD3);	
	
	EN_OWINT;
	
		
#endif

	
	//DIS_TIMER;
	
	sei();
		
   
	while(1){
#ifdef __AVR_ATmega32__		
		while(b1!=b2) {
			uart_puts(utoa(dbbuf[b2],s,16));uart_puts(" ");
			b2++;
			
		}

#endif
	}

}	

