/*
 * leds.c
 *
 *  Created on: 28.4.2014
 *      Author: Stefan
 */

/* Includes ------------------------------------------------------------------*/
#include "leds.h"

#include <stm32f4xx_gpio.h>

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Public variables ----------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/
void leds_init(
    void
)
{
    /* configure pins for gpio */
    GPIO_InitTypeDef gpio;


    /* Enable clock in TIM8 */
    RCC->APB2ENR |= RCC_APB2ENR_TIM8EN;
    __DSB();

    /* Reset TIM8 */
    RCC->APB2RSTR |= RCC_APB2RSTR_TIM8RST;
    __DSB();
    RCC->APB2RSTR &= ~RCC_APB2RSTR_TIM8RST;
    __DSB();

    /* Turn of write protection */
    TIM8->BDTR &= ~TIM_BDTR_LOCK;
    __DSB();
    /* Disable timer */
    TIM8->CR1 &= ~TIM_CR1_CEN;
    __DSB();
    /* Enable auto-reload */
    TIM8->CR1 |= TIM_CR1_ARPE;
    /* Set Upcounting mode */
    TIM8->CR1 &= ~TIM_CR1_DIR;
    /* Update event can be generated by all supported sources */
    TIM8->CR1 &= ~TIM_CR1_URS;
    /* Do not stop the Timer at update event */
    TIM8->CR1 &= ~TIM_CR1_OPM;
    /* Turn channels off */
    TIM8->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E |
            TIM_CCER_CC4E | TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE);
    __DSB();

    #define TIM_CCMR1_CC1S_OFFSET   0
    #define TIM_CCMR1_CC2S_OFFSET   8
    #define TIM_CCMR1_OC1M_OFFSET   4
    #define TIM_CCMR1_OC2M_OFFSET   12
    /* Configure capture/compare mode channel 1 */
    /* Channel is output */
    TIM8->CCMR1 &= ~TIM_CCMR1_CC1S;
    TIM8->CCMR1 |= ((0 << TIM_CCMR1_CC1S_OFFSET) & TIM_CCMR1_CC1S);
    /* Disable fast mode */
    TIM8->CCMR1 &= ~TIM_CCMR1_OC1FE;
    /* Enable Preload register */
    TIM8->CCMR1 |= TIM_CCMR1_OC1PE;
    /* Configure PWM2 mode */
    TIM8->CCMR1 &= ~TIM_CCMR1_OC1M;
    TIM8->CCMR1 |= ((7 << TIM_CCMR1_OC1M_OFFSET) & TIM_CCMR1_OC1M);
    /* Disable clear on ETRF */
    TIM8->CCMR1 &= ~TIM_CCMR1_OC1CE;
    /* Configure capture/compare mode channel 2 */
    /* Channel is output */
    TIM8->CCMR1 &= ~TIM_CCMR1_CC2S;
    TIM8->CCMR1 |= ((0 << TIM_CCMR1_CC2S_OFFSET) & TIM_CCMR1_CC2S);
    /* Disable fast mode */
    TIM8->CCMR1 &= ~TIM_CCMR1_OC2FE;
    /* Enable Preload register */
    TIM8->CCMR1 |= TIM_CCMR1_OC2PE;
    /* Configure PWM2 mode */
    TIM8->CCMR1 &= ~TIM_CCMR1_OC2M;
    TIM8->CCMR1 |= ((7 << TIM_CCMR1_OC2M_OFFSET) & TIM_CCMR1_OC2M);
    /* Disable clear on ETRF */
    TIM8->CCMR1 &= ~TIM_CCMR1_OC1CE;

    #define TIM_CCMR2_CC3S_OFFSET   0
    #define TIM_CCMR2_CC4S_OFFSET   8
    #define TIM_CCMR2_OC3M_OFFSET   4
    #define TIM_CCMR2_OC4M_OFFSET   12
    /* Configure capture/compare mode channel 3 */
    /* Channel is output */
    TIM8->CCMR2 &= ~TIM_CCMR2_CC3S;
    TIM8->CCMR2 |= ((0 << TIM_CCMR2_CC3S_OFFSET) & TIM_CCMR2_CC3S);
    /* Disable fast mode */
    TIM8->CCMR2 &= ~TIM_CCMR2_OC3FE;
    /* Enable Preload register */
    TIM8->CCMR2 |= TIM_CCMR1_OC1PE;
    /* Configure PWM2 mode */
    TIM8->CCMR2 &= ~TIM_CCMR2_OC3M;
    TIM8->CCMR2 |= ((7 << TIM_CCMR2_OC3M_OFFSET) & TIM_CCMR2_OC3M);
    /* Disable clear on ETRF */
    TIM8->CCMR2 &= ~TIM_CCMR2_OC3CE;
    /* Configure capture/compare mode channel 4 */
    /* Channel is output */
    TIM8->CCMR2 &= ~TIM_CCMR2_CC4S;
    TIM8->CCMR2 |= ((0 << TIM_CCMR2_CC4S_OFFSET) & TIM_CCMR2_CC4S);
    /* Disable fast mode */
    TIM8->CCMR2 &= ~TIM_CCMR2_OC4FE;
    /* Enable Preload register */
    TIM8->CCMR2 |= TIM_CCMR2_OC4PE;
    /* Configure PWM2 mode */
    TIM8->CCMR2 &= ~TIM_CCMR2_OC4M;
    TIM8->CCMR2 |= ((7 << TIM_CCMR2_OC4M_OFFSET) & TIM_CCMR2_OC4M);
    /* Disable clear on ETRF */
    TIM8->CCMR2 &= ~TIM_CCMR2_OC4CE;

    /* Main Output Enable can be set only b software */
    TIM8->BDTR &= ~TIM_BDTR_AOE;
    /* Disable break */
    TIM8->BDTR &= ~TIM_BDTR_BKE;

    /* Zero counter */
    TIM8->CNT = 0;
    /* Set prescaler value, owerflow at rate of ~512Hz */
    TIM8->PSC = 5;
    /* Set Auto-reload value */
    TIM8->ARR = 0xFFFE;
    #define TIM_RCR_REP_OFFSET  0
    /* Set number of overflows to generate update event */
    TIM8->RCR &= ~TIM_RCR_REP;
    TIM8->RCR |= ((5 << TIM_RCR_REP_OFFSET) & TIM_RCR_REP);
    /* Disable all interrupts and DMA requests for this timer */
    TIM8->DIER &= ~(TIM_DIER_TDE | TIM_DIER_COMDE | TIM_DIER_CC4DE |
            TIM_DIER_CC3DE | TIM_DIER_CC2DE | TIM_DIER_CC1DE | TIM_DIER_UDE |
            TIM_DIER_BIE | TIM_DIER_TIE | TIM_DIER_COMIE | TIM_DIER_CC4IE |
            TIM_DIER_CC3IE | TIM_DIER_CC2IE | TIM_DIER_CC1IE | TIM_DIER_UIE);
    __DSB();
    /* Set active LOW polarity */
    TIM8->CCER |= (TIM_CCER_CC1P | TIM_CCER_CC2P |
            TIM_CCER_CC3P | TIM_CCER_CC4P);
    /* Turn on channels */
    TIM8->CCER |= (TIM_CCER_CC1E | TIM_CCER_CC2E |
            TIM_CCER_CC3E | TIM_CCER_CC4E);
    __DSB();
    /* Enable Output */
    TIM8->BDTR |= TIM_BDTR_MOE;
    /* Enable Update event */
    TIM8->CR1 &= ~TIM_CR1_UDIS;
    __DSB();
    /* Before starting timer, generate an Update event, so new configuration
     * gets copied into shadow registers */
    TIM8->EGR |= TIM_EGR_UG;
    __DSB();
    /* Enable Timer */
    TIM8->CR1 |= TIM_CR1_CEN;
    __DSB();
    /* Do not stop this timer during debug */
    #define DBGMCU_APB2_FZ_DBG_TIM8_STOP ((uint32_t)0x00000002)
    DBGMCU->APB2FZ &= ~DBGMCU_APB2_FZ_DBG_TIM8_STOP;



    GPIO_StructInit(&gpio);
    gpio.GPIO_Mode = GPIO_Mode_AF;      /* < Alternate function */
    gpio.GPIO_OType = GPIO_OType_PP;    /* < Push-Pull */
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;  /* < No pull-up, pull-down */
    gpio.GPIO_Speed = GPIO_Speed_2MHz;  /* < Output speed */

    /* GPIOI */
    /* Enable clock to GPIOI */
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOIEN;
    __DSB();
    /* Configure pins 2, 5, 6, 7 as TIM8 PWM channels */
    gpio.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init(GPIOI, &gpio);
    GPIO_PinAFConfig(GPIOI, GPIO_PinSource2, GPIO_AF_TIM8);
    GPIO_PinAFConfig(GPIOI, GPIO_PinSource5, GPIO_AF_TIM8);
    GPIO_PinAFConfig(GPIOI, GPIO_PinSource6, GPIO_AF_TIM8);
    GPIO_PinAFConfig(GPIOI, GPIO_PinSource7, GPIO_AF_TIM8);
}

bool_t leds_set(
    leds_en_t led,
    uint16_t intensity
)
{
    bool_t response = FALSE;
    static __IO uint32_t* ccrs[4] = {
        &(TIM8->CCR1),
        &(TIM8->CCR2),
        &(TIM8->CCR3),
        &(TIM8->CCR4)
    };

    if(led >= 0 && led < 4)
    {
        *(ccrs[led]) = intensity;
        response = TRUE;
    }
    return response;
}

