/**
 * Projekt Kap07-EXTI-01
 * =====================
 *
 * Einfaches EXTI-Projekt mit einem Taster und einer LED.
 */

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

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

#ifdef MCAL
#include <mcalGPIO.h>
#include <mcalEXTI.h>
#endif

//void EXTIConfigIrq(GPIO_TypeDef *port, PIN_NUM pin);

int main(void)
{
#ifdef MCAL // Beginn der MCAL-Version

    // GPIOA: Bustakt aktivieren
    gpioInitPort(GPIOA);

    // SYSCFG: Bustakt aktivieren (noch keine MCAL-Funktion vorhanden)
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; /* SYSCFG: Clock an */

    /**
     * Konfiguration von GPIOA PA0 und PA4
     */
    gpioSelectPinMode(GPIOA, PIN0, INPUT);
    gpioSelectPinMode(GPIOA, PIN4, OUTPUT);
    gpioSetOutputType(GPIOA, PIN4, PUSHPULL);
    gpioSelectPushPullMode(GPIOA, PIN4, NO_PULLUP_PULLDOWN);

    extiInit();
    extiConfigIrq(GPIOA, PIN0);
    extiEnableIrq(EXTI_PIN0);
    extiSetTriggerEdge(EXTI_PIN0, FALLING_EDGE);


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

    __disable_irq();

    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; /* SYSCFG: Clock an */

    /**
     * Konfiguration von GPIOA PA0 und PA4
     */
    GPIOA->MODER &= ~(GPIO_MODER_MODE0_Msk | GPIO_MODER_MODE4_Msk);
    GPIOA->MODER |= GPIO_MODER_MODE4_0;

    // GPIO: Aufnahme in MCAL
    GPIOA->OTYPER &= ~(GPIO_OTYPER_OT0 | GPIO_OTYPER_OT4);
    GPIOA->PUPDR  &= ~(GPIO_PUPDR_PUPD0 | GPIO_PUPDR_PUPD4);

    // EXTI: Aufnahme in MCAL
    SYSCFG->EXTICR[0] &= ~0x000F;  /* EXTI0 f. GPIOA/Pin 0 an */
    EXTI->IMR  |= EXTI_IMR_IM0;    /* EXTI: PA0 Enable IRQ */
    EXTI->FTSR |= EXTI_FTSR_TR0;   /* EXTI: PA0 Fallende Flanke */

    __enable_irq();

#endif      // Ende: Direkte Registerprogrammierung

    // Generelle Aktivierung des Interrupts
    NVIC_EnableIRQ(EXTI0_IRQn);    /* EXTI0: Aktivieren    */

    while (1)
    {
        ;
    }
}

/**
 * EXTI0: Interrupt-Service-Routine
 */
void EXTI0_IRQHandler(void)
{
#ifdef MCAL // Beginn der MCAL-Version

    gpioTogglePin(GPIOA, PIN4); /* Toggle PA1 */
    EXTI->PR |= EXTI_PR_PR0;    /* Reset IRQ-Pending-Flag */

#else       // Ende der MCAL-Version + Beginn der Bare-Metal-Version

    if (GPIOA->IDR & GPIO_IDR_ID4)
    {
        GPIOA->BSRR = GPIO_BSRR_BR4;    // PA4 --> Low
    }
    else
    {
        GPIOA->BSRR = GPIO_BSRR_BS4;    // PA4 --> High
    }
    EXTI->PR |= EXTI_PR_PR0;    /* Reset IRQ-Pending-Flag */

#endif      // Ende der Bare-Metal-Version
}
