/*
  * stm32f4_pwm.c
 *
 *  Created on: Aug 9, 2016
 *      Author: tkl
 */
#include <stdint.h>
#include <stddef.h>

#include "stm32f4xx.h"

#include "gpio.h"
#include "stm32f4_gpio.h"

#include "pwm.h"
#include "stm32f4_pwm.h"

#pragma pack(push)
#pragma pack(1)
struct stm32f4_pwm_object {
	uint8_t used_channels;
	uint32_t channel_1_max_period;
	uint32_t channel_2_max_period;
	uint32_t channel_3_max_period;
	uint32_t channel_4_max_period;
};
#pragma pack(pop)

int stm32f4_pwm_open(const void *pwm)
{
	if(NULL == pwm)
		return -1;
	struct stm32f4_pwm *this = (struct stm32f4_pwm *)pwm;
	stm32f4_gpio_open(this->pwm_gpio);
	if(this->timer_handle->Instance == TIM4) {
		__HAL_RCC_TIM4_CLK_ENABLE();
	}
	HAL_TIM_PWM_Init(this->timer_handle);
	HAL_TIM_PWM_ConfigChannel(this->timer_handle, this->output_compare_cfg, this->channel);

	TIM_MasterConfigTypeDef sMasterConfig;
	sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
	sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
	HAL_TIMEx_MasterConfigSynchronization(this->timer_handle, &sMasterConfig);

	TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
	sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
	sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
	sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
	sBreakDeadTimeConfig.DeadTime = 0;
	sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
	sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
	sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
	HAL_TIMEx_ConfigBreakDeadTime(this->timer_handle, &sBreakDeadTimeConfig);


	HAL_TIM_Base_Start(this->timer_handle);
	HAL_TIM_PWM_Start(this->timer_handle, this->channel);
	return 0;
}

int stm32f4_pwm_close(const void *pwm)
{
	if(NULL == pwm)
		return -1;
	stm32f4_pwm_set_duty_cycle(pwm, 0);
	struct stm32f4_pwm *this = (struct stm32f4_pwm *)pwm;
	HAL_TIM_Base_Stop(this->timer_handle);
	HAL_TIM_PWM_Stop(this->timer_handle, this->channel);

	return 0;
}

int stm32f4_pwm_set_duty_cycle(const void *pwm, unsigned int duty_cycle_percent)
{
	if(NULL == pwm)
		return -1;

	struct stm32f4_pwm *this = (struct stm32f4_pwm *)pwm;
	__HAL_TIM_SET_COMPARE(this->timer_handle, this->channel, this->timer_handle->Init.Period * duty_cycle_percent / 100);

	return 0;
}