/**
 * Projekt Kap06-EXTI-03
 * =====================
 *
 * Beispiel zum Einsatz von EXTIs, die einen gemeinsamen IRQ-Handler verwenden.
 * Um herauszufinden, welcher EXTI angefordert wurde, ist das Register EXTI->PR
 * auszuwerten.
 */

/**
 ******************************************************************************
 * @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 "mcalSysTick.h"
#include "mcalGPIO.h"
#include "mcalEXTI.h"

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

/* Funktionsprototypen */
void UPDATETimers(void);
bool isSYSTICKExpired(uint32_t timer);
void SYSTICKSetMillis(uint32_t *timer, uint32_t millis);

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

int main(void)
{
    __disable_irq();

    systickInit(SYSTICK_1MS);  // Aus MCAL: SysTick initialisieren

    /* Clock der GPIOs + SYSCFG aktivieren */
    gpioInitPort(GPIOA);
    gpioInitPort(GPIOB);
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;

    /* MCAL: Konfiguration von PA4/PB8/PB9 */
    gpioSelectPinMode(GPIOA, PIN4, OUTPUT);
    gpioSetOutputType(GPIOA, PIN4, PUSHPULL);
    gpioSelectPushPullType(GPIOA, PIN4, PULLUP);

    gpioSelectPinMode(GPIOB, PIN8, INPUT);
    gpioSelectPinMode(GPIOB, PIN9, INPUT);

    // !!! ES WERDEN PIN8 und PIN9 VERWENDET !!!
    // --> SYSCFG->EXTICR[2] = xx
    extiInit();
    extiConfigIrq(GPIOB, PIN8);
    extiConfigIrq(GPIOB, PIN9);
    extiEnableIrq(EXTI_PIN8);
    extiEnableIrq(EXTI_PIN9);
    extiSetTriggerEdge(EXTI_PIN8, FALLING_EDGE);
    extiSetTriggerEdge(EXTI_PIN9, FALLING_EDGE);

    // NVIC aktivieren
    NVIC_EnableIRQ(EXTI9_5_IRQn);

    __enable_irq();

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

        if (isSYSTICKExpired(timerPA4))
        {
            gpioTogglePin(GPIOA, PIN4);
            SYSTICKSetMillis(&timerPA4, currentDelay);
            timerTrigger = false;
        }
    }
}

/**
 * External Interrupts Handler
 */
void EXTI9_5_IRQHandler(void)
{
    uint16_t pending = EXTI->PR;

    // Auswertung: Was hat den Interrupt ausgeloest?
    switch (pending)
    {
        case EXTI_PR_PR8:
            currentDelay = 200;
            EXTI->PR |= EXTI_PR_PR8;
            break;

        case EXTI_PR_PR9:
            currentDelay = 1000;
            EXTI->PR |= EXTI_PR_PR9;
            break;
    }
}

/**
 * Funktionsname in MCAL: isSystickExpired(uint32_t timer)
 */
bool isSYSTICKExpired(uint32_t timer)
{
	bool timerState = false;

	if (timer == 0)
	{
		timerState = true;
	}

	return timerState;
}

/**
 * Funktionsname in MCAL: systickSetMillis(uint32_t *timer, uint32_t millis)
 */
void SYSTICKSetMillis(uint32_t *timer, uint32_t millis)
{
	*timer = millis;
}

/**
 * Funktionsname in MCAL: updateTimers(uint32_t *timerList)
 */
void UPDATETimers(void)
{
    DECREMENT_TIMER(timerPA4);
    timerTrigger = false;
}
