/**
 * Projekt Kap06-EXTI-02
 * =====================
 *
 * Beispiel zur Erkennung von zwei EXTIs (Pin0 und Pin1 von GPIOA). Das Projekt
 * verwendet bereits die neu eingefuehrten EXTI-Funktionen aus der MCAL-Bibliothek.
 */

/**
 ******************************************************************************
 * @file           : main.c
 * @author         : Auto-generated by STM32CubeIDE
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
#warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

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

#include <mcalGPIO.h>
#include <mcalSysTick.h>
#include <mcalEXTI.h>

/* Makros */
#define DECREMENT_TIMER( timer )   \
    ( {                            \
        if ( timer > 0 )           \
            --timer;               \
    } )

/* Funktionsprototypen */
void UPDATETimers(void);

/* Globale Variablen */
bool timerTrigger = FALSE;
uint32_t timerPA4 = 200UL;
uint32_t currentDelay = 200UL;

int main(void)
{
    __disable_irq();

    // SysTick-Konfiguration wird in MCAL aufgenommen.
    SysTick_Config(SystemCoreClock / SYSTICK_1MS);
    SystemCoreClockUpdate();

    /* GPIOA/SYSCFG: Takt aktivieren */
    gpioInitPort(GPIOA);
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;

    /* MCAL: Konfiguration von GPIOA */
    gpioSelectPinMode(GPIOA, PIN0, INPUT);
    gpioSelectPinMode(GPIOA, PIN1, INPUT);
    gpioSelectPinMode(GPIOA, PIN4, OUTPUT);

    gpioSelectPushPullType(GPIOA, PIN0, PULLUP);
    gpioSelectPushPullType(GPIOA, PIN1, PULLUP);

    /* GPIO-Pin als Output: Vorher entweder PUSHPULL oder OPENDRAIN aktivieren */
    gpioSetOutputType(GPIOA, PIN4, PUSHPULL);
    gpioSelectPushPullType(GPIOA, PIN4, PULLUP);

    /* EXTI konfigurieren */
    extiInit();
    extiConfigIrq(GPIOA, PIN0);
    extiConfigIrq(GPIOA, PIN1);
    extiEnableIrq(EXTI_PIN0);
    extiEnableIrq(EXTI_PIN1);
    extiSetTriggerEdge(EXTI_PIN0, FALLING_EDGE);
    extiSetTriggerEdge(EXTI_PIN1, FALLING_EDGE);

    NVIC_EnableIRQ(EXTI0_IRQn);
    NVIC_EnableIRQ(EXTI1_IRQn);

    __enable_irq();

    while (1)
    {
        if (timerTrigger == TRUE)
        {
            UPDATETimers();
        }

        if (isSystickExpired(timerPA4))
        {
            gpioTogglePin(GPIOA, PIN4);
            systickSetMillis(&timerPA4, currentDelay);
            timerTrigger = FALSE;
        }
    }
}

/**
 * External Interrupts Handler
 */
void EXTI0_IRQHandler(void)
{
	systickSetMillis(&timerPA4, 200);
    currentDelay = 200;
    EXTI->PR = EXTI_PR_PR0;
}

void EXTI1_IRQHandler(void)
{
	systickSetMillis(&timerPA4, 1000);
    currentDelay = 1000;
    EXTI->PR = EXTI_PR_PR1;
}

/**
 * Timer aktualisieren. In MCAL wird die optimierte Funktion später
 * als updateTimers(uint32_t *list) verfügbar sein.
 */
void UPDATETimers(void)
{
    DECREMENT_TIMER(timerPA4);
    timerTrigger = FALSE;
}

/**
 * Interrupt-Service-Routine fuer den SysTick-Timer
 */
void SysTick_IRQ_Handler(void)
{
    timerTrigger = true;
}
