/**
 *******************************************************************************
 * @file           : main.c
 * @author         : Ralf Jesse
 * @brief          : Implementierung des Beispielprojekts
 *
 * Daten, die unter Einsatz eines Terminal-Emulators, wie z.B. HTerm, an das
 * NUCLEO-Board gesendet werden, werden von diesem wieder an den Terminal-
 * Emulator zurueckgesendet.
 *
 * Das Beispielprojekt liegt ausschliesslich in der MCAL-Version vor, da die
 * allermeisten Funktionen (Auswahl und Konfiguration der GPIO-Pins und des
 * USARTs) bereits in frueheren Kapiteln beschrieben wurden. Sie koennen bei
 * Bedarf den Quelltext der MCAL untersuchen, wenn Sie erfahren moechten, wie
 * die Programmierung ueber direkten Zugriff auf die Peripherieregister erfolgt.
 *******************************************************************************
 */

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

#include <mcalGPIO.h>
#include <mcalUsart.h>
#include <mcalDMAC.h>

// Prototypen
void doErrorHandling(DMAC_RETURN_CODE_t dmaStatus);

// Globale Variablen
uint8_t  msg[128];
uint16_t numData  = sizeof(msg);
bool     done     = true;

int main(void)
{
    uint16_t count;

    DMA_Stream_TypeDef *stream = DMA1_Stream5;
    DMAC_RETURN_CODE_t  dmaStatus = DMAC_OK;

    // Initialisierung von PA2/PA3 fuer USART2
    gpioSelectPort(GPIOA);
    gpioSelectPinMode(GPIOA, PIN2, ALTFUNC);
    gpioSelectAltFunc(GPIOA, PIN2, AF7);            // PA2 : USART2 Tx
    gpioSelectPinMode(GPIOA, PIN3, ALTFUNC);
    gpioSelectAltFunc(GPIOA, PIN3, AF7);            // PA3 : USART2 Rx
    gpioSelectPinMode(GPIOA, PIN5, OUTPUT);         // PA5   : GPIO-Output fuer LED

    // Initialisierung von USART2. Aktiviert immer Receiver und Transmitter.
    // Aktiviert immer den Bustakt fuer den gewaehlten UART/USART.
    usartSelectUsart(USART2);
    usartEnableUsart(USART2);
    usartSetCommParams(USART2, 115200, NO_PARITY, LEN_8BIT, ONE_BIT);
    usartSetDmaRxMode(USART2, DMA_RECEIVE_ON);

    // Initialisierung des DMAC
    dmaStatus = dmacSelectDMAC(DMA1);
    if (DMAC_OK != dmaStatus)
    {
        doErrorHandling(dmaStatus);
    }

    // Alle Interrupt-Flags des Stream zuruecksetzen
    dmacClearAllStreamIrqFlags(DMA1, stream);

    // Interrupt aktivieren
    NVIC_EnableIRQ(DMA1_Stream5_IRQn);

    /**
     * Beginn der Endlosschleife
     */
    while(1)
    {
        done = false;

        /**
         * Stream deaktivieren. Die ist erforderlich, um den Stream und den
         * verwendeten Kanal konfigurieren zu können.
         */
        dmaStatus = dmacDisableStream(stream);
        if (DMAC_OK != dmaStatus)
        {
            doErrorHandling(dmaStatus);
        }

        // Stream und gewuenschten Kanal des Streams konfigurieren
        dmaStatus = dmacSetStreamAndChannel(stream,
                                            CHANNEL_4,
                                            (uint32_t) msg,
                                            (uint32_t) &(USART2->DR),
                                            numData,
                                            BYTE, BYTE,
                                            PER_2_MEM,
                                            TX_COMPLETE);
        if (DMAC_OK != dmaStatus)
        {
            doErrorHandling(dmaStatus);
        }

        // Nach erfolgter Konfiguration muss der Stream aktiviert werden.
        dmaStatus = dmacEnableStream(stream);
        if (DMAC_OK != dmaStatus)
        {
            doErrorHandling(dmaStatus);
        }

        while (done == false)
        {
            // TODO: Hier Geht's weiter
            // Warte, bis 'done' true ist.
        }

        // Jedes Byte des Textes wird einzeln uebertragen.
        for (count = 0; count < numData; count++)
        {
            // Warten, bis der Transfer zum USART abgeschlossen ist.
            while(!(USART2->SR & USART_SR_TC))
            {
            }
            USART2->DR = msg[count];
        }
    }
}

/**
 * @brief ISR fuer DMA1/Stream6
 */
void DMA1_Stream5_IRQHandler(void)
{
    // Hier wird nur "Transfer complete" ausgewertet.
    if (DMA1->HISR & DMA_HISR_TCIF5)
    {
        // "Transfer complete"-Flag zuruecksetzen
        DMA1->HIFCR |= DMA_HIFCR_CTCIF5;
    }
    done = true;
}

/**
 * @brief Fehlerbehandlung (nicht implementiert)
 */
void doErrorHandling(DMAC_RETURN_CODE_t dmaStatus)
{
    while(1)
    {
        ;
    }
}
