/**
 * Projekt Kap09-SysTick-01
 * ========================
 *
 * Erstes Beispiel zum Einsatz des SysTick-Timers (das teilweise aber im Vorgriff
 * auf dieses Kapitel bereits früher verwendet wurde).
 */

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

#include <stdint.h>
#include <stdbool.h>

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

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

void SysTick_Handler(void);

bool     timerTrigger = false;
uint16_t tick = 0;

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

    // Konfiguration des SysTick-Timers
    systickInit(SYSTICK_1MS);                   // SysTick = 1 ms

    // Konfiguration von GPIOA/Pin0
    gpioSelectPort(GPIOA);                      // GPIOA: Bustakt einschalten
    gpioSelectPinMode(GPIOA, PIN0, OUTPUT);
    gpioSetOutputType(GPIOA, PIN0, PUSHPULL);
    gpioSelectPushPullMode(GPIOA, PIN0, PULLUP);

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

    GPIO_TypeDef *port = GPIOA;

    SystemCoreClockUpdate();                    // SysTick: Konfig.
    SysTick_Config(SystemCoreClock / 1000);     // SysTick = 1 ms

    // Konfiguration von GPIOA
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;        // GPIOA: Bustakt einschalten
    port->MODER  &= ~GPIO_MODER_MODE0_Msk;      // PA0: Reset
    port->MODER  |= GPIO_MODER_MODE0_0;         // PA0: Ouput
    port->OTYPER &= ~GPIO_OTYPER_OT0_Msk;       // PA0: Push-Pull-Mode ein
    port->PUPDR  &= ~GPIO_PUPDR_PUPD0_Msk;      // PA0: Pullup/Pulldown Reset
    port->PUPDR  |= GPIO_PUPDR_PUPD0_0;         // PA0: Int. Pullup-Wid. ein

#endif          // Ende: Direkte Registerprogrammierung

    while(1)
    {
        if (timerTrigger == true)
        {
            ++tick;
            timerTrigger = false;
        }

    	if (tick > 499)
    	{
#ifdef MCAL
    		// Testet, ob PA0 auf High- oder auf Low-Level ist
    		if (gpioGetPinState(GPIOA, PIN0))
    		{
    			gpioResetPin(GPIOA, PIN0);
    		}
    		else
    		{
    			gpioSetPin(GPIOA, PIN0);
    		}
#else
    		if (port->IDR & GPIO_IDR_ID0)
    		{
    		    port->BSRR = GPIO_BSRR_BR0;
    		}
    		else
    		{
    		    port->BSRR = GPIO_BSRR_BS0;
    		}
#endif
    		tick = 0;
    	}
    }
}

#ifndef MCAL
/**
 * Interrupt-Service-Routine des SysTick-Timers. Wird nur in der
 * Bare-Metal-Version benoetigt.
 */
void SysTick_Handler(void)
{
    ++tick;
}
#endif
