#include <stdbool.h>
#include "sam3x8e.h"
#include "system_sam3x.h"

volatile uint32_t systick = 0;

void BoardInit(void);

void delay_ms(uint32_t t) {
	uint32_t temp = systick;
	while(systick - temp < t)
		__WFI();
}

int main (void) {
	bool ledOn = false;
	uint32_t tickCount = 0;

	SystemInit();
	SystemCoreClockUpdate();

	// Systick-Timer auf 1ms einstellen
	SysTick_Config(SystemCoreClock / 1000);
	BoardInit();

	tickCount = systick;

	while(1) {
		// LED toggeln?
		if ((systick - tickCount) > 500) {
			tickCount = systick;

			if(ledOn) {
				ledOn = false;
				PIOB->PIO_CODR = PIO_SODR_P27;
			} else {
				ledOn = true;
				PIOB->PIO_SODR = PIO_SODR_P27;
			}
		}

		// Daten gesendet?
		if (!(SPI0->SPI_SR & SPI_SR_TDRE)) {
			// Byte für Übnertragung bereitstellen.
			SPI0->SPI_TDR = 0x5Aul | SPI_TDR_LASTXFER;
			// Warten bis alle Daten gesendet wurden.
			while ((SPI0->SPI_SR & SPI_SR_RDRF) == 0);
		}
	}

	return 0;
}

void BoardInit() {
	/* Disable Watchdog-Timer */
	WDT->WDT_MR |= WDT_MR_WDDIS;

	/* Clock für PIOB aktivieren. */
	// Schreibschutz ausschalten
	PMC->PMC_WPMR = PMC_WPMR_WPKEY(0x504D43ul);
	// Clock für PIOB und SPI0 aktivieren
	PMC->PMC_PCER0 |= (0x1u << ID_PIOB) | (0x1u << ID_SPI0);
	// Schreibschutz einschalten
	PMC->PMC_WPMR = PMC_WPMR_WPEN | PMC_WPMR_WPKEY(0x504D43ul);

	PMC->PMC_PCR = PMC_PCR_PID(ID_PIOB) | PMC_PCR_CMD | PMC_PCR_EN;
	PMC->PMC_PCR = PMC_PCR_PID(ID_SPI0) | PMC_PCR_CMD | PMC_PCR_EN;

	/* PIN PB27 als Ausgang konfigurieren*/
	// Schreibschutz deaktivieren
	PIOB->PIO_WPMR = PIO_WPMR_WPKEY(0x50494Ful);
	// Zugriff auf Pin 27 durch PIO
	PIOB->PIO_PER = PIO_PER_P27;
	// Als Ausgang konfigurieren
	PIOB->PIO_OER = PIO_OER_P27;
	// Schreibschutz aktivieren
	PIOB->PIO_WPMR = PIO_WPMR_WPEN | PIO_WPMR_WPKEY(0x50494Ful);

	// Pin 27 auf low ziehen
	PIOB->PIO_CODR = PIO_CODR_P27;

	/* SPI0 konfigurieren */
	// IO-Lines dem PIO_Controller entziehen.
	// Schreibschutz deaktivieren
	PIOA->PIO_WPMR = PIO_WPMR_WPKEY(0x50494Ful);
	// MISO, MOSI, SPCK uns SS0
	PIOA->PIO_PDR  = PIO_PA25A_SPI0_MISO | PIO_PA26A_SPI0_MOSI | PIO_PA27A_SPI0_SPCK | PIO_PA28A_SPI0_NPCS0;
	// Schreibschutz aktivieren
	PIOA->PIO_WPMR = PIO_WPMR_WPEN | PIO_WPMR_WPKEY(0x50494Ful);

	// SPI deaktivieren
	SPI0->SPI_CR = SPI_CR_SPIDIS;
	// SPI resetten
	SPI0->SPI_CR = SPI_CR_SWRST;
	// SPI Flag für letztes Byte/Word setzen
	SPI0->SPI_CR = SPI_CR_LASTXFER;

	// Schreibschutz deaktivieren
	SPI0->SPI_WPMR = SPI_WPMR_WPKEY(0x535049ul);
	// SPI0 als Master, Fixed Peripheral Select
	SPI0->SPI_MR = SPI_MR_MSTR | SPI_MR_MODFDIS;
	// NPCS0 als CS (PA28)
	SPI0->SPI_MR = (SPI0->SPI_MR & (~SPI_MR_PCS_Msk)) | SPI_MR_PCS(0x0ul);

	// SPI-Mode festlegen
	// CPOL = 0, NCPHA = 0, 8-Bit Transfer, 500kHz
	SPI0->SPI_CSR[0] = SPI_CSR_SCBR(SystemCoreClock / 500000ul) | SPI_CSR_DLYBS(0x40ul) | SPI_CSR_DLYBCT(0x10ul);
	// Schreibschutz aktivieren
	SPI0->SPI_WPMR = SPI_WPMR_WPEN | SPI_WPMR_WPKEY(0x535049ul);

	// SPI aktivieren
	SPI0->SPI_CR = SPI_CR_SPIEN;
}

void SysTick_Handler(void) {
	systick++;
}
