/**
 * Projekt Kap08-SysTick-03
 * ========================
 *
 * Das Projekt vermeidet die Gefahr eines SysTick-Ueberlaufes und der damit
 * verbundenen Korrekturen der Timer-Variablen.
 *
 * MCAL: Hier bitte noch nicht verwenden!
 */

/**
 ******************************************************************************
 * @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>

/* Definitionen */
#define DELAY_PIN0  (200)
#define DELAY_PIN1  (400)

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

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

/* Globale Variablen */
bool     timerTrigger = false;
uint32_t pin0Timer    = 0UL;
uint32_t pin1Timer    = 0UL;
uint32_t currentTicks = 0UL;

int main (void)
{
	// Initialisierung des SysTick-Timers
	SysTick_Config(SystemCoreClock / 1000);
	SystemCoreClockUpdate();

    SYSTICKSetMillis (&pin0Timer, DELAY_PIN0);  // Delay f. PA0
    SYSTICKSetMillis (&pin1Timer, DELAY_PIN1);  // Delay f. PA1

    // Aktivierung des Bustaktes von GPIOA
    gpioInitPort(GPIOA);

    // Konfiguration: PA0
    gpioSelectPinMode(GPIOA, PIN0, OUTPUT);
    gpioSetOutputType(GPIOA, PIN0, PUSHPULL);
    gpioSelectPushPullType(GPIOA, PIN0, PULLUP);

    // Konfiguration: PA1
    gpioSelectPinMode(GPIOA, PIN1, OUTPUT);
    gpioSetOutputType(GPIOA, PIN1, PUSHPULL);
    gpioSelectPushPullType(GPIOA, PIN1, PULLUP);

    while (1)
    {
        if (timerTrigger == true)             // Hat SysTick getickt?
        {
            UPDATETimers ();
        }

        if (isSYSTICKExpired (pin0Timer))
        {
            gpioTogglePin (GPIOA, PIN0);
            SYSTICKSetMillis (&pin0Timer, DELAY_PIN0);
        }

        if (isSYSTICKExpired (pin1Timer))
        {
            gpioTogglePin (GPIOA, PIN1);
            SYSTICKSetMillis (&pin1Timer, DELAY_PIN1);
        }
    }
}

/**
 * Aktualisiert alle verwendeten Timer
 */
void UPDATETimers (void)
{
    DECREMENT_TIMER(pin0Timer);
    DECREMENT_TIMER(pin1Timer);

    timerTrigger = false;
}

/**
 * @brief Stellt das Delay fuer den Timer ein
 *
 * @param[in]  *timer  : Pointer auf die Timer-Variable
 * @param[in]   millis : Tickzeit des SysTick-Timers in Millisekunden
 *
 * @param[out]  none
 */
void SYSTICKSetMillis (uint32_t *timer, uint32_t millis)
{
	*timer = millis;
}

/**
 * @brief Gibt 'true' zurueck, wenn der Timer abgelaufen ist, sonst 'false'.
 *
 * @param[in]  timer      : Variable, die von SysTick veraendert wird
 * @param[out] timerState : true, wenn Timer abgelaufen, sonst false
 */
bool isSYSTICKExpired(uint32_t timer)
{
	bool timerState = false;

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

	return timerState;
}

/**
 * @brief Interrupt service handler (ISR) for the SysTick timer
 *
 * @param[in]  none
 * @param[out] none
 */
void SysTick_Handler(void)
{
	timerTrigger = true;
}

void updateTimerList (uint32_t *list)
{
	uint8_t numTimers = sizeof(list)/sizeof(uint32_t);
	uint32_t *timer;

	for (uint8_t i = 0; i < (numTimers + 1); ++i)
	{
		timer = (uint32_t *) list[i];
		DECREMENT_TIMER(*timer);
		timerTrigger = false;
	}
}
