#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_Timeout = 0;

volatile uint8_t PSX_Cnt = 0 ;

volatile uint8_t PSX_Dat = 0;
volatile uint8_t PSX_Cmd = 0;
volatile uint8_t PSX_Timer = 0 ;

//Für Das Ack Signal man könnte auch einfach das Register direkt auslesen aber ...
SIGNAL (SIG_INTERRUPT0) {
	PSX_Ack = 1;
}

SIGNAL (SIG_OVERFLOW0) {
	PSX_Timer = 1;
}

void Timer_an(){
	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
}

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


void SendPSX() {
	Timer_an();
	PSX_Timeout = 0;
	PSX_Cnt = 0;
	while (PSX_Cnt <= 16) {
		if (PSX_Cnt & 0x01) { //Data einlesen
			PORTD |= (1<<CLK); //Clock high
			if (PIND & (1<<DAT)) { //wenn der Pin high ist
				PSX_Dat |= (1<<8); // Bit 8 High
			} //else ist es ehe null
			PSX_Dat>>=1; // jetzt einen nach rechts 
		}else { //CMD ausgeben
			PORTD &= ~(1<<CLK); //CLk low
			if (PSX_Cmd & 0x01) { //Wenn das CMD aus Bit 1 = High
				PORTD |= (1<<CMD); // dann Port High
			} else {
				PORTD &= ~(1<<CMD); // else Low
			}
			PSX_Cmd>>=1; // ein nach Rechts
		}
		while (PSX_Timer == 0);
		PSX_Timer = 0;
		PSX_Cnt++;	
	}
	Timer_aus();
	// Jetzt auf das Ack warten ansonsten PSX_Timeout setzen
		PSX_Cnt = 0;
		PORTD |= (1<<CLK);
		int Temp;
		while(PSX_Ack == 0 && Temp < 16000) Temp++;
		if (Temp >= 1600) PSX_Timeout = 1;

}


int main(void){
	//Uart Init und  Interrups an
	uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU));
	sei();
	uart_puts("Start\n");

	//Ext. Interrupt 0 (Ack) ein
	GIMSK |= (1<<INT0); //Ext. Interrupt 0 AN
	TIMSK |= (1<<TOIE0); // Timer 0 An
	MCUCR |= (1<<ISC01); //ISCO1 = 1, ISC00 standart = 0 ergibt Interrupt bei fallender flanke
	
	//PD2 und 3 Eingang mit Pullups
	DDRD &= ~((1<<ACK) | (1<<DAT)); // Eingang = 0
	PORTD |= (1<<ACK) | (1<<DAT);//Pullups an = 1
	
	//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


	// TESTEn von senden und Empfangen zum PSX Controller
	PORTD &= ~(1<<ATT); //ATT = 0
	
	PSX_Cmd = 0x01;
	uart_puts("Cmd");
	uart_putc(PSX_Cmd);
	SendPSX();
	uart_puts("Cmd");
	uart_putc(PSX_Cmd);
	uart_puts("Data");
	uart_putc(PSX_Dat);
	uart_puts("Timeout");
	uart_putc(PSX_Timeout);
	uart_puts("\n");	
	
	PSX_Cmd = 0x42;
	uart_puts("Cmd");
	uart_putc(PSX_Cmd);
	SendPSX();
	uart_puts("Cmd");
	uart_putc(PSX_Cmd);
	uart_puts("Data");
	uart_putc(PSX_Dat);
	uart_puts("Timeout");
	uart_putc(PSX_Timeout);
	uart_puts("\n");

	PSX_Cmd = 0x00;
	SendPSX();
	uart_puts("Cmd");
	uart_putc(PSX_Cmd);
	uart_puts("Data");
	uart_putc(PSX_Dat);
	uart_puts("Timeout");
	uart_putc(PSX_Timeout);
	uart_puts("\n");

	PSX_Cmd = 0x00;
	SendPSX();
	uart_puts("Cmd");
	uart_putc(PSX_Cmd);
	uart_puts("Data");
	uart_putc(PSX_Dat);
	uart_puts("Timeout");
	uart_putc(PSX_Timeout);
	uart_puts("\n");

	PSX_Cmd = 0x00;
	SendPSX();
	uart_puts("Cmd");
	uart_putc(PSX_Cmd);
	uart_puts("Data");
	uart_putc(PSX_Dat);
	uart_puts("Timeout");
	uart_putc(PSX_Timeout);
	uart_puts("\n");
	
	PORTD |= (1<<ATT);
}
