//
#ifndef SPI_LIB
#define SPI_LIB

#define LED_FRAME_LENGTH 72
#define DEFAULT_STEP_MS 5.0

#include "descriptors.h"
//----------------------------------------------- LEDKY ---------------------------------------

volatile uint8_t SPI_ready;
volatile uint8_t SPI_flag;
volatile uint8_t SPI_sent = 0;
volatile uint8_t SPI_received = 0;


volatile uint8_t period_ms = 0;
volatile uint8_t frameNumber = 0;

volatile uint8_t SPI_message[80];
volatile uint8_t received[80];
volatile uint8_t bytesToSend = 0;

volatile uint8_t controlIndex = 0;
volatile uint8_t endPacket = 0;

uint8_t ledLength = 18;
uint8_t ledSent = 0;

uint8_t color[] = {224, 85 , 35, 95};  //&EO - Marker

LED_PATTERN* SPI_pattern;
volatile uint8_t isPatternActive = 0;
volatile uint8_t overallIntensity = 16;		//max31
volatile uint8_t intensity = 0x20;
volatile uint8_t intensityExp = 0x01;

volatile uint8_t currentFrameIndex;
volatile uint16_t partialFrameIndex;
volatile uint8_t nextFrameIndex;
volatile uint8_t patternStopped = 0;

void IO_init_SPIMaster(void){
	//SPI_init
	PORT->Group[1].DIRSET.reg = PORT_PB03;
	PORT->Group[1].DIRSET.reg = PORT_PB02;
	PORT->Group[1].PMUX[1].bit.PMUXE = 0x3;
	PORT->Group[1].PMUX[1].bit.PMUXO = 0x3;
	PORT->Group[1].PINCFG[2].bit.PMUXEN = 1;
	PORT->Group[1].PINCFG[3].bit.PMUXEN = 1;
	
}

void SPIMasterInit(void){
	IO_init_SPIMaster();
	
	MCLK->APBDMASK.reg |= MCLK_APBDMASK_SERCOM5;
	//Enable GCLK for TCC0 and link it to GCLK0 see "PCHCTRLm Mapping" from product datasheet
	GCLK->PCHCTRL[24].reg = (GCLK_PCHCTRL_CHEN|GCLK_PCHCTRL_GEN(0));		//16M
	// - Disable TC0
	
	while(SERCOM5->SPI.SYNCBUSY.bit.ENABLE);
	SERCOM5->SPI.CTRLA.bit.ENABLE = 0 ;
	while(SERCOM5->SPI.SYNCBUSY.bit.ENABLE);
	
	SERCOM5->SPI.CTRLA.bit.MODE = 0x3;	//Master 0x3
	SERCOM5->SPI.CTRLA.bit.FORM = 0x0;	//0x0 SPI without adress
	SERCOM5->SPI.CTRLA.bit.DIPO = 0x3;	//0x3 MISO pad[3]
	SERCOM5->SPI.CTRLA.bit.DOPO = 0x0;	//0x0 Master DO SCK SS DI
	SERCOM5->SPI.CTRLA.bit.CPOL = 0x0;
	SERCOM5->SPI.CTRLA.bit.CPHA = 0x0;
	SERCOM5->SPI.CTRLA.bit.DORD = 0x0; //MSB first
	SERCOM5->SPI.CTRLB.bit.CHSIZE = 0x0; //8bit
	SERCOM5->SPI.CTRLB.bit.RXEN = 0;	//receiver disabled
	SERCOM5->SPI.CTRLB.bit.SSDE = 0;	//Slave select detection
	SERCOM5->SPI.CTRLB.bit.PLOADEN = 0;	//Slave data preload
	SERCOM5->SPI.CTRLB.bit.MSSEN = 0;	//Master SS enable
	SERCOM5->SPI.INTENSET.reg = 0x0F;		//ERROR - - - SSL RXC TXC DRE
	SERCOM5->SPI.CTRLA.bit.RUNSTDBY = 0;
	
	SERCOM5->SPI.BAUD.reg = 11; //BAUD = (fosc/(2*fbaud))-1
	
	NVIC_EnableIRQ(SERCOM5_IRQn);
	
	SERCOM5->SPI.INTENSET.reg = SERCOM_SPI_INTFLAG_DRE;
	
	//SERCOM0->SPI.CTRLB.bit.RXEN = 1;
	
	//colors->u32[0] = 0x00000000;
	//colors->u32[18] = 0xFFFFFFFF;
	//for (int i = 1; i < 18; i ++) colors->u32[i] = 0xE0000000;
}

void SERCOM5_Handler(void){
	SPI_flag = SERCOM5->SPI.INTFLAG.reg;
	uint16_t value;
	uint16_t nextValue;
	
	if(SPI_flag & SERCOM_SPI_INTFLAG_DRE){
		if(ledSent < LED_FRAME_LENGTH){
			if(controlIndex < 4) {
				value = 0x00;
				controlIndex++;
			} else {
				if(isPatternActive < 2){
					 value = 0;
				} else {
					value = (uint16_t)((SPI_pattern->nonArray.FRAME.structFrame[currentFrameIndex].TIMEFRAME_ARRAY[ledSent]*
					SPI_pattern->nonArray.FRAME.structFrame[currentFrameIndex].TIMEFRAME_ARRAY[ledSent - ledSent % 4]) / 255.0);
					/*
					*
					SPI_pattern->nonArray.FRAME.structFrame[currentFrameIndex].TIMEFRAME_ARRAY[ledSent - ledSent % 4]) / 255.0);
					nextValue = (uint16_t)((SPI_pattern->nonArray.FRAME.structFrame[nextFrameIndex].TIMEFRAME_ARRAY[ledSent]*
					SPI_pattern->nonArray.FRAME.structFrame[nextFrameIndex].TIMEFRAME_ARRAY[ledSent - ledSent % 4]) / 255.0);
					ledSent++;
					value = value + partialFrameIndex*((nextValue - value)/(SPI_pattern->nonArray.STEP/DEFAULT_STEP_MS));
					*/
				}
				if(ledSent % 4 == 0){
					value = overallIntensity| 0xE0;
				} else {
					value = (value * intensity)/255;
				}
				ledSent++;
			} 
			
			SERCOM5->SPI.DATA.reg = value;
		} else {
			if(endPacket == 0) {
				controlIndex = 0;
				endPacket = 1;
			}
			
			if(controlIndex < 4) {
				SERCOM5->SPI.DATA.reg = 0xFF;
				controlIndex++;
			} else {
				controlIndex = 0;
				endPacket = 0;
				ledSent = 0;
				
				if(SPI_pattern->nonArray.FNUM > 1){
					if (isPatternActive == 0) {
						SERCOM5->SPI.CTRLA.bit.ENABLE = 0;
					}
					if (isPatternActive != 1) SERCOM5->SPI.INTENCLR.bit.DRE = 1;
					else {
						isPatternActive--;
						SERCOM5->SPI.INTENCLR.bit.DRE = 1;
					}
				}
			}
		}
	}
	
	
	
	SERCOM5->SPI.INTFLAG.reg |= SPI_flag;
}

void TCC0_init(){
	// - Enable TCC0 Bus clock (Timer counter control clock)
	MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC0;
	//Enable GCLK for TCC0 and link it to GCLK0 see "PCHCTRLm Mapping" from product datasheet
	GCLK->PCHCTRL[25].reg = (GCLK_PCHCTRL_CHEN|GCLK_PCHCTRL_GEN(0));
	// - Disable TCC0
	while(TCC0->SYNCBUSY.bit.ENABLE);
	TCC0->CTRLA.bit.ENABLE = 0;
	while(TCC0->SYNCBUSY.bit.ENABLE);
	
	TCC0->CTRLA.bit.PRESCALER = 0x06;	//0x06 pres 256
	// - Set TCC0 in waveform mode Normal PWM
	//TCC0->WAVE.bit.WAVEGEN = 0x2;
	TCC0->CTRLBCLR.bit.ONESHOT = 1;
	// - Set PER to maximum counter value (resolution : 0xFF)
	TCC0->PER.reg = 625;	//625 - 10 ms presc 256(0x6);
	TCC0->CTRLA.bit.RUNSTDBY = 1;
	// - Set WO[0] compare register to 0x7F (PWM duty cycle = 50%)
	//TCC0->CC[1].reg = 14000;		//400 = 1024	200 = 512	0 3E80	180 7D00
	//TCC0->WEXCTRL.bit.OTMX = 0x0;
	
	TCC0->INTENSET.bit.OVF = 1;
	NVIC_EnableIRQ(TCC0_IRQn);	
}

void TCC0_Handler(){
	
	/*
	partialFrameIndex = (partialFrameIndex + 1) % (uint16_t)(SPI_pattern->nonArray.STEP/DEFAULT_STEP_MS);
	if(partialFrameIndex == 0) {
		*/
	currentFrameIndex = ((currentFrameIndex + 1) % (SPI_pattern->nonArray.FNUM));
		/*
		nextFrameIndex = (currentFrameIndex + 1) % SPI_pattern->nonArray.FNUM;	
	}
	*/
		
	SERCOM5->SPI.INTENSET.bit.DRE = 1;
	TCC0->INTFLAG.reg |= TCC_INTFLAG_OVF;
}

uint8_t SPI_stopPattern(){
	if(isPatternActive > 1) TCC0->PER.reg = 62;
	
	isPatternActive = 1;
	
	
	SERCOM5->SPI.INTENSET.bit.DRE = 1;
	
	while(TCC0->SYNCBUSY.bit.ENABLE);
	TCC0->CTRLA.bit.ENABLE = 0;
	while(TCC0->SYNCBUSY.bit.ENABLE);
	
	return isPatternActive;
}

void SPI_playPattern(LED_PATTERN* activePattern){
	uint32_t count = 1;
	while(!isPatternActive && count++) {
		SPI_stopPattern();
	}
	
	isPatternActive = 2;
	SPI_pattern = activePattern;
	if(SPI_pattern->nonArray.FNUM > 1){
		
		
		TCC0->PER.reg = (uint32_t)(62.5*(activePattern->nonArray.STEP));
		
		while(TCC0->SYNCBUSY.bit.ENABLE);
		TCC0->CTRLA.bit.ENABLE = 1;
		while(TCC0->SYNCBUSY.bit.ENABLE);
	}
	
	currentFrameIndex = 0;
	
	SERCOM5->SPI.INTENSET.bit.DRE;
	
	while(SERCOM5->SPI.SYNCBUSY.bit.ENABLE);
	SERCOM5->SPI.CTRLA.bit.ENABLE = 1;
	while(SERCOM5->SPI.SYNCBUSY.bit.ENABLE);
}

void SPI_updateIntensity(uint16_t intensity){
	overallIntensity = intensity;
}

#endif