/**
 * @brief Der STM32F4 empfaengt Daten von einem Terminal und sendet sie
 *        über die USART2-Komponente im Interruptbetrieb zurueck.
 *
 * @par
 * Einstellungen von USART2:
 * -------------------------
 * Baudrate  : 115200 bps
 * Wortlaenge: 8 Bit
 * Paritaet  : Keine
 * Stoppbits : 1
 *
 * Daten werden von einem Terminal-Emulator (unter Windows z.B. HTerm) an das
 * Nucleo-Board gesendet. Diese Daten werden anschliessend vom Nucleo-Board
 * wieder an HTerm zurueckgesendet.
 *
 * Dieses Beispiel ist eine Adaption eines Beispiels der Universitaet Ljubljana
 * und wurde geringfuegig modifiziert.
 */

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

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

/**
 * Immer aktiv, da die USART2-ISR MCAL-GPIO-Funktionen verwendet.
 */
#include <mcalGPIO.h>
#include <mcalUsart.h>

//void uartTest(void);
void USART2_IRQHandler(void);

uint8_t  *outString = (uint8_t *) "The quick brown fox jumps over the lazy dog. ";

int main(void)
{
    GPIO_TypeDef  *port = GPIOA;
    USART_TypeDef *usart = USART2;

#ifdef MCAL     // Beginn der MCAL-Version

    // Konfiguration + Initialisierung von GPIOA
    gpioSelectPort(port);                      // GPIOA : Bustakt aktivieren
    gpioSelectPinMode(port, PIN2, ALTFUNC);    // PA2   : Modus = Alt. Funktion
    gpioSelectAltFunc(port, PIN2, AF7);        // PA2   : AF7 = USART2 Rx
    gpioSelectPinMode(port, PIN3, ALTFUNC);    // PA3   : Modus = Alt. Funktion
    gpioSelectAltFunc(port, PIN3, AF7);        // PA3   : AF7 = USART2 Tx
    gpioSelectPinMode(port, PIN5, OUTPUT);     // PA5   : GPIO-Output fuer LED

    // Hier werden sämtliche Parameter (Baudrate, Wortlaenge, Paritaet und
    // Anzahl der Stoppbits eingestellt.
    usartSelectUsart(usart);
    usartStartUsart(usart);
    usartSetCommParams(usart, 115200, NO_PARITY, LEN_8BIT, ONE_BIT);
    usartEnableIrq(usart, USART_IRQ_RXNEIE);

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

    // Konfiguration von GPIOA Pin2 und Pin3
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;        // GPIOA: Bustakt aktivieren
    port->MODER  &= ~GPIO_MODER_MODER2_Msk;     // PA2  : Reset auf Default-Wert
    port->MODER  |= GPIO_MODER_MODER2_1;        // PA2  : Alt. Funk.
    port->AFR[0] &= ~GPIO_AFRL_AFRL2;           // PA2  : AF zuruecksetzen
    port->AFR[0] |= GPIO_AFRL_AFRL2_2 |         // PA2  : AF7 waehlen
                    GPIO_AFRL_AFRL2_1 |
                    GPIO_AFRL_AFRL2_0;

    port->MODER  &= ~GPIO_MODER_MODER3_Msk;     // PA3  : Reset auf Default-Wert
    port->MODER  |= GPIO_MODER_MODER3_1;        // PA3  : Alt. Funk.
    port->AFR[0] &= ~GPIO_AFRL_AFRL3;           // PA3  : AF zuruecksetzen
    port->AFR[0] |= GPIO_AFRL_AFRL3_2 |         // PA3  : AF7 waehlen
                    GPIO_AFRL_AFRL3_1 |
                    GPIO_AFRL_AFRL3_0;

    // GPIOA Pin 5 als Ausgang konfigurieren (Onboard-LED)
    port->MODER  &= ~GPIO_MODER_MODER5_Msk;     // PA5  : Reset auf Default-Wert
    port->MODER  |= GPIO_MODER_MODER5_0;        // PA5  : Output

    // Konfiguration von USART2
    // Hier wird nur die Baudrate eingestellt. Wortlaenge, Paritaet und Anzahl
    // der Stoppbits entsprechen den Default-Einstellungen nach einem Reset.
    RCC->APB1ENR |= RCC_APB1ENR_USART2EN;        // USART2: Bustakt aktivieren
    usart->BRR  = 0x8B;                          // USART2: Baudrate = 115200 bps
    usart->CR1 |= USART_CR1_UE;                  // USART2: Starte USART2
    usart->CR1 |= (USART_CR1_RE | USART_CR1_TE); // USART2: Aktiviere Receiver + Transmitter
    usart->CR1 |= USART_CR1_RXNEIE;              // USART2: Aktiviere Receiver-Interrupt

#endif      // Ende: Direkte Registerprogrammierung

    NVIC_EnableIRQ(USART2_IRQn);

    /* Loop forever */
    while(1)
    {

    }
}

/**
 * Die USART2-ISR verwendet mit Ausnahme der GPIO-Funktionen keine MCAL-
 * Funktionen.
 */
void USART2_IRQHandler(void)
{
    uint16_t received = 0;

    if (USART2->SR & USART_SR_RXNE)
    {
        received = USART2->DR & 0x01FF;
        if (received == 'a')
        {
            gpioSetPin(GPIOA, PIN5);
        }
        if (received == 'b')
        {
            gpioResetPin(GPIOA, PIN5);
        }
        if (((received >= 'A') && (received <= 'Z')) || (received == ' '))
        {
            USART2->DR = received;
        }
        if (received == 'c')
        {
            USART2->CR1 |= USART_CR1_TXEIE;
            USART2->DR   = *outString++;          // Liest alle Zeichen des vordefinierten Strings
        }
    }

    if (USART2->SR & USART_SR_TXE)
    {
        if (*outString != '\0')
        {
            USART2->DR = *outString++;
        }
        else
        {
            USART2->CR1 &= ~USART_CR1_TXEIE;
        }
    }
}
