/**
 * Projekt Kap10-BASTIM
 * ====================
 *
 * Verwendet den Basic Timer TIM6 und laesst eine an GPIO-Port A (PIN0)
 * angeschlossene LED blinken. Das Beispiel kombiniert die MCAL-Version
 * sowie die Bare-Metal-Version.
 */

#include <stm32f4xx.h>
#include <system_stm32f4xx.h>
#include <stdint.h>
#include <stdbool.h>

/**
 * Kommentar in Zeile 18 entfernen, wenn Sie die MCAL testen möchten.
 */
#define MCAL

#ifdef MCAL
#include <mcalGPIO.h>
#include <mcalTimer/mcalTimer.h>
#endif

/**
 * Funktionsprototypen
 */
void TIM6_DAC_IRQHandler(void);

/**
 * Globale Variablen
 */
bool tim6Trigger = false;

int main(void)
{
#ifdef MCAL     // Beginn der MCAL-Version
    // MCAL: GPIO-Funktionen
    gpioInitPort(GPIOA);
    gpioSelectPinMode(GPIOA, PIN0, OUTPUT);
    gpioSetOutputType(GPIOA, PIN0, PUSHPULL);
    gpioSelectPushPullMode(GPIOA, PIN0, PULLUP);
    gpioSetOutputSpeed(GPIOA, PIN0, HIGH_SPEED);

    // Konfiguration von TIM6. Funktionen der MCAL.
    timerSelectTimer(TIM6);                   // TIM6: Bustakt aktivieren
    timerSetPrescaler(TIM6, 1600);            // TIM6: Takt durch 1600 Dividieren
    timerSetAutoReloadValue(TIM6, 10000);     // TIM6: Autoreload-Wert = 10000
    timerEnableInterrupt(TIM6, TIM_IRQ_UIE);  // TIM6: Interrupt aktivieren
    timerStartTimer(TIM6);                    // TIM6: Timer starten
//    timerEnableOneShot(TIM6);                 // TIM6: One-Shot-Modus aktivieren

#else       // Ende der MCAL-Version, Beginn: Direkte Registerprogrammierung

    GPIO_TypeDef *port = GPIOA;

    // Aktivierung und Initialisierung von GPIOA / Pin0
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    port->MODER  &= ~GPIO_MODER_MODE0_Msk;      // PA0: Reset
    port->MODER  |= GPIO_MODER_MODE0_0;         // PA0: Ouput
    port->OTYPER &= ~GPIO_OTYPER_OT0_Msk;       // PA0: Push-Pull-Mode ein
    port->PUPDR  &= ~GPIO_PUPDR_PUPD0_Msk;      // PA0: Pullup/Pulldown Reset
    port->PUPDR  |= GPIO_PUPDR_PUPD0_0;         // PA0: Int. Pullup-Wid. ein

    // Aktivierung und Initialisierung von TIM6
    RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;         // TIM6: Bustakt aktivieren
    TIM6->PSC    = 1600-1;                      // TIM6: Takt durch 1600 dividieren
    TIM6->ARR    = 10000-1;                     // TIM6: Autoreload-Wert = 10000
    TIM6->DIER   |= TIM_DIER_UIE;               // TIM6: Interrupt aktivieren
//    TIM6->CR1    |= TIM_CR1_OPM;              // TIM6: One-Shot aktivieren
    TIM6->CR1    |= TIM_CR1_CEN;                // TIM6: Timer starten

#endif      // Ende: Direkte Registerprogrammierung

    NVIC_EnableIRQ(TIM6_DAC_IRQn);              // TIM6:

    while (1)
    {
#ifdef MCAL
        if (true == tim6Trigger)
        {
            gpioTogglePin(GPIOA, PIN0);
            tim6Trigger = false;
        }
#else
        if (true == tim6Trigger)
        {
            if (port->IDR & GPIO_IDR_ID0)
            {
                port->BSRR = GPIO_BSRR_BR0;
            }
            else
            {
                port->BSRR = GPIO_BSRR_BS0;
            }
            tim6Trigger = false;
        }
#endif
    }
}

/**
 * ISR f. Basic Timer TIM6
 */
void TIM6_DAC_IRQHandler(void)
{
    tim6Trigger = true;
    TIM6->SR = 0;                               // Wichtig: Muss per Software
                                                // zurueckgesetzt werden!
}
