// www.artem.ru
// (C)2008 Artem Kuchin
//

// ****************************************
// ***        SET FREQUENCY CORRECTLY    **

#define F_CPU 1000000UL

// ****************************************

#include <mega8.h>
#include <delay.h>
#include <stdlib.h>
#include <stdio.h>

#define _BV(bit) (1 << (bit))
#define X_XTAL1 0
#define X_OE 2
#define X_WR 3
#define X_BS1 4
#define X_XA0 5
#define X_XA1 6
#define X_BS2 7 

void main(void) 
{
	char i;
	unsigned char data[3];

        
	// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 4800
UCSRA=0x00;
UCSRB=0x08;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x0C;

        DDRC = 0xff;
	DDRD|=0b11111110;
        PORTC = 0x00;
	
	printf("rst->gnd\r\n");
	PORTC.5 = 1;
	PORTC.0 = 0;
	delay_ms(5000);

	// toggle xtal1 at lease 6 times
	for(i=0;i<8;i++){	
		PORTD|=_BV(X_XTAL1);
		delay_ms(10);
		PORTD&=~_BV(X_XTAL1);
		delay_ms(10);
	}
	// set prog enable pins (pagel is gnd, xa0, xa1, bs1 - zero)
	// PD4,PD5,PD6
	PORTD&=~(_BV(X_XA0)|_BV(X_XA1)|_BV(X_BS1));
	PORTD|=_BV(X_WR); // write disables
	
	
	printf("rst->12\r\n");
	PORTC.4 = 1;
	PORTC.0 = 1;
	delay_ms(5000);

	// read signature bytes

	// SET OE HIGH
	PORTD|=_BV(X_OE);

	DDRB=0xff;

	for(i=0;i<3;i++){
		// load command
		//Set XA1 to 1, XA0 to 0. This enables command loading.
		PORTD|=_BV(X_XA1);
		PORTD&=~_BV(X_XA0);
		// Set BS1 to “0”, BS1 - PD4
		PORTD&=~_BV(X_BS1);
		// Set DATA to command
		PORTB=0b00001000; // A: Load Command “0000 1000”.
		//Give XTAL1 a positive pulse. This loads the command., XTAL1 - PD1
		PORTD|=_BV(X_XTAL1);delay_ms(10);PORTD&=~_BV(X_XTAL1);delay_ms(10);
	
		//load address
		//Set XA1 to 0, XA0 to 0. This enables address loading.
		// XA1 - PD6, XA0 - PD5
		PORTD&=~_BV(X_XA1);
		PORTD&=~_BV(X_XA0);
		// Set BS1 to “0”, BS1 - PD4
		PORTD&=~_BV(X_BS1);
		// Set DATA to command
		PORTB=i; //  addr 0
		//Give XTAL1 a positive pulse. This loads the address low byte , pd1
		PORTD|=_BV(X_XTAL1);delay_ms(10);PORTD&=~_BV(X_XTAL1);delay_ms(10);

		// XA0=XA1=1
		//PORTD|=_BV(X_XA0)|_BV(X_XA1);
	
		DDRB=0;
		//Set OE to “0”  - OE - PD2
		//the selected Signature byte can now be read at DATA.
		PORTD&=~_BV(X_OE);
		delay_ms(10);
	
		// read data
		data[(int)i]=PINB;

		//Set OE to “1”.
		PORTD|=_BV(X_OE);

		DDRB=0xff;
	}

        
	//itoa(data[0],buf);
	printf(" Signature: %2X",data[0]);
	//itoa(data[1],buf);
	printf(" %2X",data[1]);
	//itoa(data[2],buf);
	printf(" %2X\r\n",data[2]);

	
	delay_ms(5000);

	// read fuses and lock bits
	// load command
	//Set XA1 to 1, XA0 to 0. This enables command loading.
	PORTD|=_BV(X_XA1);
	PORTD&=~_BV(X_XA0);
	// Set BS1 to “0”, BS1 - PD4
	PORTD&=~_BV(X_BS1);
	// Set DATA to command
	PORTB=0b00000100; // A: Load Command “0000 1000”.
	//Give XTAL1 a positive pulse. This loads the command., XTAL1 - PD1
	PORTD|=_BV(X_XTAL1);delay_ms(10);PORTD&=~_BV(X_XTAL1);delay_ms(10);
	

	i=0;

	DDRB=0;

	PORTD&=~_BV(X_OE);

	// fuse low byte
	PORTD&=~_BV(X_BS1);
	PORTD&=~_BV(X_BS2);
	delay_ms(10);
	// read data
	data[(int)i]=PINB;
	i++;

	// fuse high byte
	PORTD|=_BV(X_BS1);
	PORTD|=_BV(X_BS2);
	delay_ms(10);
	// read data
	data[(int)i]=PINB;
	i++;

	// lock bits
	PORTD|=_BV(X_BS1);
	PORTD&=~_BV(X_BS2);
	delay_ms(10);
	// read data
	data[(int)i]=PINB;

	// disable output
	PORTD|=_BV(X_OE);
	DDRB=0xff;
	
	//itoa(data[0],buf,16);
	printf("FUSE: %2X ",data[0]);
	//itoa(data[1],buf,16);
	printf("%2X ",data[1]);
	//itoa(data[2],buf,16);
	printf("%2X\r\n",data[2]);

	delay_ms(5000);
	printf("prog: ");
	for(i=10;i>0;i--){
		//itoa(i,buf);
		printf("%i ",i);
		delay_ms(1000);
	}
	
	DDRD|=0b11111110;

	// chip erase
	//Set XA1 to 1, XA0 to 0. This enables command loading.
	PORTD|=_BV(X_XA1);
	PORTD&=~_BV(X_XA0);
	// Set BS1 to “0”, BS1 - PD4
	PORTD&=~_BV(X_BS1);
	// Set DATA to command
	PORTB=0b10000000;
	//Give XTAL1 a positive pulse. This loads the command., XTAL1 - PD1
	PORTD|=_BV(X_XTAL1);delay_ms(10);PORTD&=~_BV(X_XTAL1);delay_ms(10);
	// Give WR a negative pulse. This starts the Chip Erase. RDY/BSY goes low.
	PORTD&=~_BV(X_WR);delay_ms(10);PORTD|=_BV(X_WR);delay_ms(10);
	// Wait until RDY/BSY goes high before loading a new command.



	// load default data for FUSE low byte		
	//Set XA1 to 1, XA0 to 0. This enables command loading.
	PORTD|=_BV(X_XA1);
	PORTD&=~_BV(X_XA0);
	// Set BS1 to “0”, BS1 - PD4
	PORTD&=~_BV(X_BS1);
	// Set DATA to command
	PORTB=0b01000000;
	//Give XTAL1 a positive pulse. This loads the command., XTAL1 - PD1
	PORTD|=_BV(X_XTAL1);delay_ms(10);PORTD&=~_BV(X_XTAL1);delay_ms(10);
	// load data
	PORTD&=~_BV(X_XA1);
	PORTD|=_BV(X_XA0);
	PORTB=0b11100001; // DEFAULT VALUE FOR LOW FUSE BYTE
	PORTD|=_BV(X_XTAL1);delay_ms(10);PORTD&=~_BV(X_XTAL1);delay_ms(10);
	// Set BS1 to “0” and BS2 to “0”.
	PORTD&=~_BV(X_BS1);
	PORTD&=~_BV(X_BS2);
	// Give WR a negative pulse. This starts the Chip Erase. RDY/BSY goes low.
	PORTD&=~_BV(X_WR);delay_ms(10);PORTD|=_BV(X_WR);delay_ms(10);


	// load default data for HIGH low byte
	//Set XA1 to 1, XA0 to 0. This enables command loading.
	PORTD|=_BV(X_XA1);
	PORTD&=~_BV(X_XA0);
	// Set BS1 to “0”, BS1 - PD4
	PORTD&=~_BV(X_BS1);
	// Set DATA to command
	PORTB=0b01000000;
	//Give XTAL1 a positive pulse. This loads the command., XTAL1 - PD1
	PORTD|=_BV(X_XTAL1);delay_ms(10);PORTD&=~_BV(X_XTAL1);delay_ms(10);
	// load data
	PORTD&=~_BV(X_XA1);
	PORTD|=_BV(X_XA0);
	PORTB=0b10011001; // DEFAULT VALUE FOR HIGH FUSE BYTE
	PORTD|=_BV(X_XTAL1);delay_ms(10);PORTD&=~_BV(X_XTAL1);delay_ms(10);
	// Set BS1 to “0” and BS2 to “0”.
	PORTD|=_BV(X_BS1);
	PORTD&=~_BV(X_BS2);
	// Give WR a negative pulse. This starts the Chip Erase. RDY/BSY goes low.
	PORTD&=~_BV(X_WR);delay_ms(10);PORTD|=_BV(X_WR);delay_ms(10);

	PORTC = 0x00;
	printf("\r\ndone\r\n");

	while(1);


}


