#include "stm32f30x_conf.h"
#include <stdlib.h>
#include <stdio.h>
#include "thetable.c"

#define PI 3.14159265358979323846
#define BUFFERSIZE 64
#define UNCERT 20
#define PERIOD 20

// IN DIESEM PROJEKT GILT:
// PROZESSORTAKT = 72 MHz
// AHB  Prescaler = 1
// APB1 Prescaler = 2
// APB2 Prescaler = 1

volatile char buffer[BUFFERSIZE];
volatile int bufferread = 0;

volatile int vertstate = 0;
volatile int horistate = 0;

volatile int pos = 0;
volatile char directions = 0;

volatile char photo [4];

volatile double rps = 0;

void vertstep(int direction);
void horistep(int direction);

int main(void){
// ---------------------------------------------------------------------
//	Enabling clocks
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

	
// ---------------------------------------------------------------------
//	Init GPIO (A) for USART1 (Maya serial) and USART2 (PC serial)
	GPIO_InitTypeDef GPIO_Init_Struct;
	GPIO_Init_Struct.GPIO_Mode = GPIO_Mode_AF;
	GPIO_Init_Struct.GPIO_OType = GPIO_OType_PP;
	GPIO_Init_Struct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_Init_Struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init_Struct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA, &GPIO_Init_Struct);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_7);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_7);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_7);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_7);
// ---------------------------------------------------------------------
// Init GPIO (A) for debugging with LED2 and extra PA6 for osci
	
//	GPIO_Init_Struct.GPIO_Mode = GPIO_Mode_OUT;
//	GPIO_Init_Struct.GPIO_OType = GPIO_OType_PP;
//	GPIO_Init_Struct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
//	GPIO_Init_Struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
//	GPIO_Init_Struct.GPIO_Speed = GPIO_Speed_50MHz;
//	
//	GPIO_Init(GPIOA,&GPIO_Init_Struct);
	
// ---------------------------------------------------------------------
//	Init GPIO (B) for Vertical Stepper
	GPIO_Init_Struct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_Init_Struct.GPIO_OType = GPIO_OType_PP;
	GPIO_Init_Struct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8  | GPIO_Pin_9;
	GPIO_Init_Struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init_Struct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_Init_Struct);
	GPIOB->ODR &= 0xF<<6;
	
// ---------------------------------------------------------------------
//	Init GPIO (B) for Lichtschranken
	GPIO_Init_Struct.GPIO_Mode = GPIO_Mode_IN;
	GPIO_Init_Struct.GPIO_Pin =  GPIO_Pin_3  | GPIO_Pin_4;
	GPIO_Init_Struct.GPIO_PuPd = GPIO_PuPd_DOWN;
	
	GPIO_Init(GPIOB, &GPIO_Init_Struct);
	
// ---------------------------------------------------------------------
//	Init GPIO (C) for Horizontal Stepper
	GPIO_Init_Struct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_Init_Struct.GPIO_OType = GPIO_OType_PP;
	GPIO_Init_Struct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11  | GPIO_Pin_12;
	GPIO_Init_Struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init_Struct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOC, &GPIO_Init_Struct);
	GPIOC->ODR = 0;
	
// ---------------------------------------------------------------------
// Init TIM2 for Stepping every PERIOD ms
	TIM_TimeBaseInitTypeDef TIM_Init_Struct;
	TIM_Init_Struct.TIM_Prescaler = 7200 - 1; // 100 mcs per tick (0.1ms)
	TIM_Init_Struct.TIM_Period = PERIOD - 1;
	
	TIM_TimeBaseInit(TIM2, &TIM_Init_Struct);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //IT enable
	TIM_Cmd(TIM2,ENABLE);
// ---------------------------------------------------------------------
// Init TIM3 for rps calculation
	TIM_Init_Struct.TIM_Prescaler = 7200 - 1; // 100 mcs per tick (0.1ms)
	TIM_Init_Struct.TIM_Period = 0xFFFF;
	
	TIM_TimeBaseInit(TIM3, &TIM_Init_Struct);
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
	TIM_Cmd(TIM3,ENABLE);	
// ---------------------------------------------------------------------
//	Init USART1 (Maya serial)
	USART_InitTypeDef USART_Init_Struct;
	USART_Init_Struct.USART_BaudRate = 115200;
	USART_Init_Struct.USART_Parity = USART_Parity_No;
	USART_Init_Struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init_Struct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init_Struct.USART_StopBits = USART_StopBits_1;
	USART_Init_Struct.USART_WordLength = USART_WordLength_8b;
	
	USART_Init(USART1,&USART_Init_Struct);
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // RXNE = ReceiveDataRegister Not Empty
	USART_ITConfig(USART1, USART_IT_ORE, DISABLE);
	USART_Cmd(USART1,ENABLE);
// ---------------------------------------------------------------------
//	Init USART2 (PC serial)
	USART_Init_Struct.USART_BaudRate = 115200;
	USART_Init_Struct.USART_Parity = USART_Parity_No;
	USART_Init_Struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init_Struct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init_Struct.USART_StopBits = USART_StopBits_1;
	USART_Init_Struct.USART_WordLength = USART_WordLength_8b;
	
	USART_Init(USART2,&USART_Init_Struct);
	USART_ITConfig(USART2, USART_IT_TC, DISABLE);
	USART_Cmd(USART2,ENABLE);
	
// ---------------------------------------------------------------------
//	Init EXTI for Lichtschranke MAYA 
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource4);
	
	EXTI_InitTypeDef EXTI_Init_Struct;
	EXTI_Init_Struct.EXTI_Line = EXTI_Line4;
	EXTI_Init_Struct.EXTI_LineCmd = ENABLE;
	EXTI_Init_Struct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_Init_Struct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	
	EXTI_Init(&EXTI_Init_Struct);
	
// ---------------------------------------------------------------------
//	NVIC
	NVIC_InitTypeDef NVIC_Init_Struct;
// USART2 (PC serial)
	NVIC_Init_Struct.NVIC_IRQChannel = USART2_IRQn;
	NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = 4;
	NVIC_Init_Struct.NVIC_IRQChannelSubPriority = 4;
	NVIC_Init(&NVIC_Init_Struct);
// EXTI LICHTSCHRANKE
	NVIC_Init_Struct.NVIC_IRQChannel = EXTI4_IRQn;
	NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = 3;
	NVIC_Init_Struct.NVIC_IRQChannelSubPriority = 3;
	NVIC_Init(&NVIC_Init_Struct);
// TIM3 (rps measurement)
	NVIC_Init_Struct.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_Init_Struct.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&NVIC_Init_Struct);
// TIM2 (Stepping every PERIOD ms)
	NVIC_Init_Struct.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_Init_Struct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_Init_Struct);
// USART1 (Maya serial)
	NVIC_Init_Struct.NVIC_IRQChannel = USART1_IRQn;
	NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_Init_Struct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_Init_Struct);
	
// ---------------------------------------------------------------------
// Wrapup
//	GPIO_ResetBits(GPIOA, GPIO_Pin_5);
//	GPIO_ResetBits(GPIOA, GPIO_Pin_6);

	
// ---------------------------------------------------------------------
  /* Infinite loop */
  while (1);
}

void USART1_IRQHandler(void) {
//	GPIO_SetBits(GPIOA, GPIO_Pin_6);
	char recvd1 = USART_ReceiveData(USART1);
	photo[(int)recvd1>>0x6] = recvd1 & 0x3F; // recvd>>0x6 = 0b 0000 00xx // 0x3F = 0b 0011 1111
	
	USART_ClearFlag(USART1, USART_FLAG_ORE);
//	GPIO_ResetBits(GPIOA, GPIO_Pin_6);
}

void USART2_IRQHandler(void) {
	if (buffer[bufferread] == '\r') {
		bufferread = 0;
		USART_SendData(USART2, '\r');
		USART_ITConfig(USART2, USART_IT_TC, DISABLE);
	}else {
		USART_SendData(USART2, buffer[bufferread++]);
	}
}

void EXTI4_IRQHandler(void){
	//GPIO_SetBits(GPIOA, GPIO_Pin_5);
	int ls1 = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_3);
	int ls2 = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4);
	
	directions = directions<<1;
	
	if (ls1 == ls2) {
		pos++;
		directions |= 1;
	}
	else
		pos--;
	
	char last3 = directions & 7; // 7 = 0b0111
	if ((last3 == 5) || (last3 == 2)) { // 5 = 0b0101 // 2 = 0b0010 // if NULLPOSITION
		
		long temp = TIM_GetCounter(TIM3);
		if (temp != 0){
			rps = (10000) / (double)temp;
			TIM_SetCounter(TIM3, 0);
			sprintf(buffer, "%lf rps          \r", rps);
			USART_ITConfig(USART2, USART_IT_TC, ENABLE);
		}else {
			TIM_Cmd(TIM3, ENABLE);
			rps = 0;
			sprintf(buffer, "%lf rps          \r", rps);
			USART_ITConfig(USART2, USART_IT_TC, ENABLE);
		}
		
		if (pos >= 0)
			pos = 0;
		else
			pos = 229;
	}
	
	//GPIO_ResetBits(GPIOA, GPIO_Pin_5);
	EXTI_ClearITPendingBit(EXTI_Line4);
}

void TIM3_IRQHandler(void) {
	TIM_Cmd(TIM3, DISABLE);
	TIM_SetCounter(TIM3, 0);
	TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}

void TIM2_IRQHandler(void) {
//	GPIO_SetBits(GPIOA, GPIO_Pin_5);
	
//	int x = photo[0] + photo[1] - photo[2] - photo[3];
//	int y = photo[0] - photo[1] + photo[2] - photo[3];
//	
//	double abs = sqrt(x*x+y*y);
//	double angle = atan(y/x);
//	if (x < 0)
//		angle += PI;
//	double rot = -pos *  2 * PI / 230;
//	
//	x = (int)(abs * cos(angle + rot));
//	y = (int)(abs * sin(angle + rot));

	double x1 = photo[0] + photo[1] - photo[2] - photo[3];
	double y1 = photo[0] - photo[1] + photo[2] - photo[3];
	
	double x = x1 * cos_lookup[pos] + y1 * sin_lookup[pos];
	double y = y1 * cos_lookup[pos] - x1 * sin_lookup[pos];
	
	//INVERSION IS INSIDE HERE AS WELL
	if (x > UNCERT)
		horistep(1);
	else if (x < -UNCERT)
		horistep(-1);
		
	if (y > UNCERT)
			vertstep(1);
	else if (y < -UNCERT)
			vertstep(-1);
	
//	GPIO_ResetBits(GPIOA, GPIO_Pin_5);
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}



void vertstep(int direction){ // POSITIVE direction = DOWN
	vertstate += direction;
	
	if(vertstate > 7)
		vertstate = 0;
	if(vertstate < 0)
		vertstate = 7;
	
	switch(vertstate){
		 case 0:
			 GPIOB->ODR = 1<<9;
		 break; 
		 case 1:
			 GPIOB->ODR = 1<<9 | 1<<8;
		 break; 
		 case 2:
			 GPIOB->ODR = 1<<8;
		 break; 
		 case 3:
			 GPIOB->ODR = 1<<8 | 1<<7;
		 break; 
		 case 4:
			 GPIOB->ODR = 1<<7;
		 break; 
		 case 5:
			 GPIOB->ODR = 1<<7 | 1<<6;
		 break; 
			 case 6:
			 GPIOB->ODR = 1<<6;
		 break; 
		 case 7:
			 GPIOB->ODR = 1<<6 | 1<<9;
		 break; 
		 default:
			 GPIOB->ODR &= 0xF<<6;
		 break; 
	}
}


void horistep(int direction) {// POSITIVE direction = LEFT
	horistate += direction;
	
	if(horistate > 7)
		horistate = 0;
	if(horistate < 0)
		horistate = 7;
	
	switch(horistate){
		 case 0:
			 GPIOC->ODR = 1<<12;
		 break; 
		 case 1:
			 GPIOC->ODR = 1<<12 | 1<<11;
		 break; 
		 case 2:
			 GPIOC->ODR = 1<<11;
		 break; 
		 case 3:
			 GPIOC->ODR = 1<<11 | 1<<10;
		 break; 
		 case 4:
			 GPIOC->ODR = 1<<10;
		 break; 
		 case 5:
			 GPIOC->ODR = 1<<10 | 1<<9;
		 break; 
			 case 6:
			 GPIOC->ODR = 1<<9;
		 break; 
		 case 7:
			 GPIOC->ODR = 1<<9 | 1<<12;
		 break; 
		 default:
			 GPIOC->ODR &= 0xF<<9;
		 break; 
	}
}