/**
 * Projekt: Kap08-SysTick-02
 * =========================
 *
 * Das Beispiel zeigt, dass mit nur einem Timer mehrere Aktionen gesteuert
 * werden können, wobei jede Aktion ein anderes Delay verwendet.
 *
 * Das Beispiel verwendet derzeit noch nicht die SysTick-Funktionen der MCAL-
 * Bibliothek. Die MCAL verwendet Parameter und Techniken, die zu diesem
 * Zeitpunkt noch nicht bekannt sind.
 */
/**
 ******************************************************************************
 * @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 <stdint.h>
#include <stdbool.h>

#include <stm32f4xx.h>
#include <mcalGPIO.h>

uint32_t getUptime(void);
void     UPDATETimers(void);
void     SysTick_Handler(void);

uint32_t tick = 0UL;
bool     pin0TimerStarted = false;
bool     pin1TimerStarted = false;
uint32_t pin0Timer = 0UL;
uint32_t pin1Timer = 0UL;
bool     timerCorrected = false;
bool     timerTrigger = false;

#define  SYSTICK_MAX  (2000)

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


    // 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)
    {
    	UPDATETimers();

    	// Wurde der Timer fuer Pin0 gestartet?
    	if (pin0TimerStarted == false)
    	{
    		pin0Timer = getUptime() + 200; // Delay = 200 ms
    		pin0TimerStarted = true;       // Verhindert, dass pin0Timer
    		                               // vor seinem Ablauf neu gesetzt
    		                               // wird.
    	}

    	// Wurde der Timer gestartet, wird geprueft, ob der Timer
    	// abgelaufen ist.
    	if (pin0TimerStarted == true && getUptime() > pin0Timer)
    	{
    		gpioTogglePin(GPIOA, PIN0);    // pin0Timer ist abgelaufen
    		pin0TimerStarted = false;      // Erlauben, dass pin0Timer
    		                               // neu geladen werden kann.
    	}

    	// Hier gelten die gleichen Kommentare wie fuer pin0Timer.
    	if (pin1TimerStarted == false)
    	{
    		pin1Timer = getUptime() + 400;
    		pin1TimerStarted = true;
    	}

    	if (pin1TimerStarted == true && getUptime() > pin1Timer)
    	{
    		gpioTogglePin(GPIOA, PIN1);
    		pin1TimerStarted = false;
    	}
    }
}

/**
 * @brief Interrupt-Service-Routine fuer den SysTick-Timer
 */
void SysTick_Handler (void)
{
    ++tick;

    // Durch den folgenden Test erreichen wir, dass der SysTick-Timer
    // beliebig lange laufen kann. Ein SysTick-Ueberlauf ist nun nicht
    // mehr relevant.
    if (tick > SYSTICK_MAX)
    {
    	tick = 0UL;
    	timerCorrected = true;
    }
}

/**
 * @brief Gibt den aktuellen Wert des Tick-Counters zurueck.
 *
 * @param[in]  none
 * @param[out] tick : Der aktuelle Wert des Zaehlers
 */
uint32_t getUptime(void)
{
	return tick;
}

/**
 * @brief Wurde der tick-Counter des SysTick-Timers korrigiert.
 *
 * @par   Die verwendeten Timer muessen korrigiert werden. Erfolgt
 *        dies nicht, waere das Toggle-Timing der Pins nicht mehr
 *        korrekt.
 */
void UPDATETimers(void)
{
	if (timerCorrected == true)
	{
		pin0Timer -= SYSTICK_MAX;
		pin1Timer -= SYSTICK_MAX;
		timerCorrected = false;
	}
}
