/*
 * inverter.c
 *
 *  Created on: 25.10.2016
 *      Author: dehottgw
 */


#include <stdlib.h>
#include <stdbool.h>
#include <math.h>

#include "stm32f1xx_hal.h"
#include "inverter.h"


extern TIM_HandleTypeDef htim1;
extern TIM_HandleTypeDef htim2;
extern TIM_HandleTypeDef htim4;
extern TIM_HandleTypeDef htim5;


#define NUM_OF_SINE_SLOT 30
const uint32_t SLOT_WIDTH = 1500;
const uint32_t FREQ_IN = 1E6;
const float PI = 3.14159;
uint16_t IV[NUM_OF_SINE_SLOT];

volatile uint32_t timer1Cnt;

typedef struct {
	uint8_t slotCnt;
	bool running;
	GPIO_TypeDef *bridgePolarityPort;
	uint16_t bridgePolarityPin;
	GPIO_TypeDef *startMarkPort;
	uint16_t startMarkPin;
	IRQn_Type irqType;
	TIM_HandleTypeDef *handle;
	uint32_t channel;
} timerSupport_t;

#define NUM_OF_TIMER 3
volatile timerSupport_t timerSupport[NUM_OF_TIMER];
volatile uint8_t phaseOrder[NUM_OF_TIMER];



void inverterBegin() {
	for (uint8_t i = 0; i < NUM_OF_SINE_SLOT; i++) {
		float slotAngle = 180.0 / NUM_OF_SINE_SLOT;
		float angle = i * slotAngle;
		float sineValues = sinf(angle / 180 * PI);
		IV[i] = (uint16_t)(sineValues[i] * 0.9 * SLOT_WIDTH);
	}

	timerSupport[0].handle = &htim2;
	timerSupport[0].running = false;
	timerSupport[0].slotCnt = 0;
	timerSupport[0].bridgePolarityPort = BridgePolarity0_GPIO_Port;
	timerSupport[0].bridgePolarityPin = BridgePolarity0_Pin;
	timerSupport[0].irqType = TIM2_IRQn;
	timerSupport[0].channel = TIM_CHANNEL_1;
	timerSupport[0].startMarkPort = LED0_GPIO_Port;
	timerSupport[0].startMarkPin = LED0_Pin;
	__HAL_TIM_SET_AUTORELOAD(timerSupport[0].handle, SLOT_WIDTH);

	timerSupport[1].handle = &htim5;
	timerSupport[1].running = false;
	timerSupport[1].slotCnt = 0;
	timerSupport[1].bridgePolarityPort = BridgePolarity1_GPIO_Port;
	timerSupport[1].bridgePolarityPin = BridgePolarity1_Pin;
	timerSupport[1].irqType = TIM5_IRQn;
	timerSupport[1].channel = TIM_CHANNEL_2;
	timerSupport[1].startMarkPort = LED1_GPIO_Port;
	timerSupport[1].startMarkPin = LED1_Pin;
	__HAL_TIM_SET_AUTORELOAD(timerSupport[1].handle, SLOT_WIDTH);

	timerSupport[2].handle = &htim4;
	timerSupport[2].running = false;
	timerSupport[2].slotCnt = 0;
	timerSupport[2].bridgePolarityPort = BridgePolarity2_GPIO_Port;
	timerSupport[2].bridgePolarityPin = BridgePolarity2_Pin;
	timerSupport[2].irqType = TIM4_IRQn;
	timerSupport[2].channel = TIM_CHANNEL_1;
	timerSupport[2].startMarkPort = LED2_GPIO_Port;
	timerSupport[2].startMarkPin = LED2_Pin;
	__HAL_TIM_SET_AUTORELOAD(timerSupport[2].handle, SLOT_WIDTH);

	__HAL_TIM_SET_AUTORELOAD(&htim1, SLOT_WIDTH);
}

void inverterIncFrequency() {
	uint16_t currPsc = htim1->Instance->PSC;
	currPsc++;
	htim1->Instance->PSC = currPsc;
	for (uint8_t i = 0; i < NUM_OF_TIMER; i++) {
		timerSupport[i].handle->Instance->PSC = currPsc;
	}
}

void inverterDecFrequency() {
	uint16_t currPsc = htim1->Instance->PSC;
	currPsc--;
	htim1->Instance->PSC = currPsc;
	for (uint8_t i = 0; i < NUM_OF_TIMER; i++) {
		timerSupport[i].handle->Instance->PSC = currPsc;
	}
}

void inverterStart(direction_t direction) {
	inverterStop();

	if (direction == CLOCKWISE) {
		phaseOrder[0] = 0;
		phaseOrder[1] = 1;
		phaseOrder[2] = 2;
	} else {
		phaseOrder[0] = 0;
		phaseOrder[1] = 2;
		phaseOrder[2] = 1;
	}


	for (uint8_t i = 0; i < NUM_OF_TIMER; i++){
		timerSupport[i].slotCnt = 0;
		timerSupport[i].running = false;
		HAL_GPIO_WritePin(timerSupport[i].bridgePolarityPort, timerSupport[i].bridgePolarityPin, GPIO_PIN_RESET);
	}

	timer1Cnt = 0;
	HAL_TIM_Base_Start_IT(&htim1);
	__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
}

void inverterStop() {
	HAL_TIM_Base_Stop(&htim1);
	__HAL_TIM_DISABLE_IT(&htim1, TIM_IT_UPDATE);

	for (uint8_t i = 0; i < NUM_OF_TIMER; i++){
		HAL_TIM_PWM_Stop_DMA(timerSupport[i].handle, timerSupport[i].channel);
		__HAL_TIM_DISABLE_IT(timerSupport[i].handle, TIM_IT_UPDATE);
		HAL_GPIO_WritePin(timerSupport[i].startMarkPort, timerSupport[i].startMarkPin, GPIO_PIN_RESET);
	}
}


static void startPhase(uint8_t phaseIdx) {
	uint8_t timerIdx = phaseOrder[phaseIdx];
	if (! timerSupport[timerIdx].running) {
		HAL_GPIO_WritePin(timerSupport[timerIdx].startMarkPort,
				timerSupport[timerIdx].startMarkPin, GPIO_PIN_SET);
		HAL_TIM_PWM_Start_DMA(timerSupport[timerIdx].handle, timerSupport[timerIdx].channel,
				(uint32_t*)IV, NUM_OF_SINE_SLOT);
		__HAL_TIM_ENABLE_IT(timerSupport[timerIdx].handle, TIM_IT_UPDATE);
		timerSupport[timerIdx].running = true;
	}
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
	for (uint8_t i = 0; i < NUM_OF_TIMER; i++) {
		if (htim == timerSupport[i].handle) {
			timerSupport[i].slotCnt++;
			if (timerSupport[i].slotCnt == NUM_OF_SINE_SLOT + 2) {
				timerSupport[i].slotCnt = 2;
				HAL_GPIO_TogglePin(timerSupport[i].bridgePolarityPort, timerSupport[i].bridgePolarityPin);
			}
		}
	}

	if (htim == &htim1) {
		HAL_GPIO_TogglePin(Sync_GPIO_Port, Sync_Pin);

		if (timer1Cnt == 0) {
			startPhase(0);
		} else if (timer1Cnt == ((NUM_OF_SINE_SLOT * 2) / 3)) {
			startPhase(1);
		} else if (timer1Cnt == ((NUM_OF_SINE_SLOT * 2) * 2 / 3)) {
			startPhase(2);
		}

		timer1Cnt++;
	}
}

