
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/delay.h>

#include "uart.h"


#define UART_BAUD_RATE 57600
#define F_CPU 16000000UL

#define ACK 2
#define DAT 3
#define CLK 4
#define CMD 5
#define ATT 6

volatile uint8_t PSX_Ack = 0; //bräuchte ja eigetnlich nur ein Bit und nicht ein byte aber ...
volatile uint8_t PSX_Timer = 0;

uint8_t Timeout = 0;

SIGNAL (SIG_INTERRUPT0) {
	PSX_Ack = 1;
}

SIGNAL (SIG_OVERFLOW0) {
	PSX_Timer = 1;
}

int low(int Pin) {
	PORTD &= ~(1<<Pin);
}
	
int high(int Pin) {
	PORTD |= (1<<Pin);
}

int Timer_an(void){
	PSX_Timer = 0;
	TCNT0 = 0x00; // TIMER auf Null
	//TCCR0 = (1<<CS01); // AUF 8 fach Setzen das wären bis überlauf 16MHZ/8=2MHZ/256= 8KHZ *2=16khz wegen 8khz pro wechsel warten
	// Das mit dem Teiler auf 8 ist ein zu hoher Takt ;) deswegen wollte es bestimmt nicht aber keine sau im Inet schreibt wie schnell es geht aber jetzt klappt es ja.
	TCCR0 = (1<<CS01) | (1<<CS00); // 16/63=256/256*2=2 KHz
}	

int Timer_aus(void) {
	TCCR0 = ~((1<<CS01) | (1<<CS00)); // Timer aus
}

int wait() {
	while (PSX_Timer == 0);
	PSX_Timer = 0;
}

int cmd(int p) {
if (p==1) high(CMD); else low(CMD);
}

int PSX_Wait_Ack(int Timeout) {
	int Temp;
	PSX_Ack = 0;
	while(PSX_Ack == 0 && Temp < Timeout) Temp++;
	if (Temp >= Timeout) return 0; else return 1;
}

int PSX_Com(uint8_t Command) {
// Ma So testen
	Timer_an();
	uint8_t Data=0;
	
	low(ATT);
	//1
	low(CLK); //clock low
	cmd(Command & 0x01);
		Command>>=1;
	wait();
	high(CLK); //Clock high
	if (PIND & (1<<DAT)) Data |= (1<<7);
		Data >>= 1;
	wait();
	//2
	low(CLK); //clock low
	cmd(Command & 0x01);
		Command>>=1;
	wait();
	high(CLK); //Clock high
	if (PIND & (1<<DAT)) Data |= (1<<7);
		Data >>= 1;
	wait();
	//3
	low(CLK); //clock low
	cmd(Command & 0x01);
		Command>>=1;
	wait();
	high(CLK); //Clock high
	if (PIND & (1<<DAT)) Data |= (1<<7);
		Data >>= 1;
	wait();
	//4
	low(CLK); //clock low
	cmd(Command & 0x01);
		Command>>=1;
	wait();
	high(CLK); //Clock high
	if (PIND & (1<<DAT)) Data |= (1<<7);
		Data >>= 1;
	wait();
	//5
	low(CLK); //clock low
	cmd(Command & 0x01);
		Command>>=1;
	wait();
	high(CLK); //Clock high
	if (PIND & (1<<DAT)) Data |= (1<<7);
		Data >>= 1;
	wait();
	//6
	low(CLK); //clock low
	cmd(Command & 0x01);
		Command>>=1;
	wait();
	high(CLK); //Clock high
	if (PIND & (1<<DAT)) Data |= (1<<7);
		Data >>= 1;
	wait();
	//7
	low(CLK); //clock low
	cmd(Command & 0x01);
		Command>>=1;
	wait();
	high(CLK); //Clock high
	if (PIND & (1<<DAT)) Data |= (1<<7);
		Data >>= 1;
	wait();
	//8
	low(CLK); //clock low
	cmd(Command & 0x01);
		Command>>=1;
	wait();
	high(CLK); //Clock high
	if (PIND & (1<<DAT)) Data |= (1<<7);
		//Data >>= 1;
	//wait();
	
	Timer_aus();
	
	
	// Auf Ack Warten
	if (PSX_Wait_Ack(16000) == 1) {
		uart_puts("ACK\n");
	} else {
		uart_puts("NoACK\n");
	}
	return Data;
}



int main(void){
	//Uart Init und  Interrups an
	uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU));
	sei();
	uart_puts("Start\n");
	
	
	DDRD &= ~(1<<ACK); // eingang =0
	PORTD &= ~( (1<<ACK) );//Pullups aus = 0	
	GIMSK |= (1<<INT0); //Ext. Interrupt 0 AN
	MCUCR |= (1<<ISC01); //ISCO1 = 1, ISC00 standart = 0 ergibt Interrupt bei fallender flanke

	TIMSK |= (1<<TOIE0); // Timer 0 enabled
	

	DDRD &= ~(1<<DAT); // Dat eingang =0
	PORTD &= ~( (1<<DAT) );//Pullups aus = 0
	
	//PD4 (Cmd) = 0 PD6 (Att),PD5(Clk) = 1
	DDRD |= (1<<CLK) | (1<<ATT) | (1<<CMD); //Ausgang = 1
	PORTD |= (1<<CLK) | (1<<ATT); // und zustand 1
	PORTD &= ~(1<<CMD); //Zustand 0
	
	uint8_t Id,Ok,Daten1,Daten2,Daten3,Daten4,Daten5,Daten6;

	PSX_Com(0x01); // DA? / Nix zurück
	Id= PSX_Com(0x42); //Schick ma / ID zurück
	Ok= PSX_Com(0xff); //nix /0x5a zurück
	
	if ( Id == 0x041) {  // Normalers Pad
		Daten1= PSX_Com(0xff);// nix / daten zurück
		Daten2= PSX_Com(0xff);// nix /daten zurück
	}
	
	if (Id == 0x73 || Id == 0x53) { //Digital Pad mehr Daten holen
		Daten1= PSX_Com(0xff);// nix / daten zurück
		Daten2= PSX_Com(0xff);// nix /daten zurück
		Daten3 = PSX_Com(0xff);// nix / daten zurück
		Daten4 = PSX_Com(0xff);// nix /daten zurück
		Daten5 = PSX_Com(0xff);// nix /daten zurück
		Daten6 = PSX_Com(0xff);// nix /daten zurück
	}	
	high(ATT);

	uart_puts("Data:\n");
	uart_putc(Id);
	uart_puts("\n");
	uart_puts("OK");
	uart_puts("\n");
	uart_putc(Daten1);
	uart_puts("\n");
	uart_putc(Daten2);
	uart_puts("\n");
	if (Id == 0x73 || Id == 0x53) { //Digital Pad mehr Daten holen
	uart_putc(Daten3);
	uart_puts("\n");
	uart_putc(Daten4);
	uart_puts("\n");
	uart_putc(Daten5);
	uart_puts("\n");
	uart_putc(Daten6);
	}
	// jetzt auslesen cmd 0x42 schicken	



}


