/**
  ******************************************************************************
  * @file    main.c
  *
  * @brief   Простой тест передачи и приема без прерываний через DMA.
  *
  *          UART0 подключен к UART2:
  *          C[3](UART0 TX) -> F[11](UART2 RX)
  *
  *          Все модули настраиваются на скорость 57600, fifo включен.
  *          С помощью dma передается через UART0 13 байт. Данные, принятые
  *          UART2 сохраняются через DMA в массив.
  *          Если полученный в конце пакет байтов соответсвует ожиданиям,
  *          то тест прошел.
  *
  *          Компилятор: GCC ARM 4.9.3
  *          Среда: Qt Creator 3.4.2
  *
  * @author  НИИЭТ
  *             - Богдан Колбов (bkolbov), kolbov@niiet.ru
  * @date    03.12.2015
  *
  ******************************************************************************
  * @attention
  *
  * ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО
  * ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ
  * ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ
  * НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
  * ПРЕДНАЗНАЧЕНО ДЛЯ ОЗНАКОМИТЕЛЬНЫХ ЦЕЛЕЙ И НАПРАВЛЕНО ТОЛЬКО НА
  * ПРЕДОСТАВЛЕНИЕ ДОПОЛНИТЕЛЬНОЙ ИНФОРМАЦИИ О ПРОДУКТЕ, С ЦЕЛЬЮ СОХРАНИТЬ ВРЕМЯ
  * ПОТРЕБИТЕЛЮ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ
  * ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА ПРЯМОЙ ИЛИ КОСВЕННЫЙ УЩЕРБ, ИЛИ
  * ПО ИНЫМ ТРЕБОВАНИЯМ, ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ
  * ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
  *
  * <h2><center>&copy; 2015 ОАО "НИИЭТ"</center></h2>
  ******************************************************************************
  */

#include "niietcm4.h"

// общее количество байт на пересылку
#define TRANSFERS_TOTAL    13

// статусный вывод
#define STATUS_PORT        NT_GPIOE
#define STATUS_PIN         GPIO_Pin_8       // начинает переключаться,
                                            // если принятые данные совпадают с отправленными

// килобайт управляющих структур DMA
DMA_ConfigData_TypeDef DMA_CONFIGDATA __attribute__ ((aligned (1024)));

// массив на передачу
uint32_t uart0_tx_arr[TRANSFERS_TOTAL] = {0xDE, 0xAD, 0xC0, 0xDE,
                                          0xBE, 0xEF, 0xCA, 0xFE,
                                          0xBA, 0xBE, 0xB0, 0x0B, 0x55};
// массив для приема
uint32_t uart2_rx_arr[TRANSFERS_TOTAL];

void SystemInit()
{
    // инициализация служебных GPIO
    GPIO_Init_TypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Dir = GPIO_Dir_Out;
    GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
    GPIO_InitStruct.GPIO_Pin = STATUS_PIN;
    GPIO_Init(STATUS_PORT, &GPIO_InitStruct);

    // инициализация UART

    // настройка портов UART 0
    // хак, необходимый, чтобы была возможность использовать вывоводы со 2 функцией
    GPIO_AltFuncConfig(NT_GPIOD, GPIO_Pin_11, GPIO_AltFunc_3); // uart0 tx
    GPIO_AltFuncConfig(NT_GPIOE, GPIO_Pin_0, GPIO_AltFunc_3); // uart0 rx
    // rx
    GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_2;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
    GPIO_Init(NT_GPIOC, &GPIO_InitStruct);
    // tx
    GPIO_InitStruct.GPIO_Dir = GPIO_Dir_Out;
    GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(NT_GPIOC, &GPIO_InitStruct);

    // настройка портов UART 2
    // rx
    GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_1;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
    GPIO_Init(NT_GPIOF, &GPIO_InitStruct);
    // tx
    GPIO_InitStruct.GPIO_Dir = GPIO_Dir_Out;
    GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(NT_GPIOF, &GPIO_InitStruct);

    // настройка тактирования и сброса UART
    RCC_UARTClkCmd(NT_UART0, ENABLE);
    RCC_UARTClkCmd(NT_UART2, ENABLE);
    RCC_PeriphRstCmd(RCC_PeriphRst_UART0, ENABLE);
    RCC_PeriphRstCmd(RCC_PeriphRst_UART2, ENABLE);

    // настройка блоков UART
    UART_Init_TypeDef UART_InitStruct;
    UART_StructInit(&UART_InitStruct);
    UART_InitStruct.UART_BaudRate = 57600;
    UART_InitStruct.UART_ClkFreq = EXT_OSC_VALUE;
    UART_InitStruct.UART_DataWidth = UART_DataWidth_8;
    UART_InitStruct.UART_FIFOEn = ENABLE;

    UART_Init(NT_UART0, &UART_InitStruct);
    UART_Init(NT_UART2, &UART_InitStruct);

    UART_Cmd(NT_UART0, ENABLE);
    UART_Cmd(NT_UART2, ENABLE);

    // Инцииализация DMA
    // Базовый указатель
    DMA_BasePtrConfig((uint32_t)(&DMA_CONFIGDATA));
    // Инициализация каналов
    DMA_ChannelInit_TypeDef DMA_ChannelInitStruct;
    DMA_ChannelStructInit(&DMA_ChannelInitStruct);
    DMA_ChannelInitStruct.DMA_SrcDataSize = DMA_DataSize_32;
    DMA_ChannelInitStruct.DMA_DstDataSize = DMA_DataSize_32;
    DMA_ChannelInitStruct.DMA_TransfersTotal = TRANSFERS_TOTAL;
    DMA_ChannelInitStruct.DMA_Mode = DMA_Mode_Basic;

    // DMA0 - UART0 TX
    DMA_ChannelInitStruct.DMA_SrcDataInc = DMA_DataInc_32;
    DMA_ChannelInitStruct.DMA_DstDataInc = DMA_DataInc_Disable;
    DMA_ChannelInitStruct.DMA_SrcDataEndPtr = &(uart0_tx_arr[TRANSFERS_TOTAL-1]);
    DMA_ChannelInitStruct.DMA_DstDataEndPtr = (uint32_t *)(&NT_UART0->DR);
    DMA_ChannelInit(&DMA_CONFIGDATA.PRM_DATA.CH[0], &DMA_ChannelInitStruct);

    // DMA6 - UART2 RX
    DMA_ChannelInitStruct.DMA_SrcDataInc = DMA_DataInc_Disable;
    DMA_ChannelInitStruct.DMA_DstDataInc = DMA_DataInc_32;
    DMA_ChannelInitStruct.DMA_SrcDataEndPtr = (uint32_t *)(&NT_UART2->DR);
    DMA_ChannelInitStruct.DMA_DstDataEndPtr = &(uart2_rx_arr[TRANSFERS_TOTAL-1]);
    DMA_ChannelInit(&DMA_CONFIGDATA.PRM_DATA.CH[6], &DMA_ChannelInitStruct);

    // Инциализация контроллера DMA
    DMA_Init_TypeDef DMA_InitStruct;
    DMA_StructInit(&DMA_InitStruct);
    DMA_InitStruct.DMA_Channel = DMA_Channel_UART0_TX | DMA_Channel_UART2_RX;
    DMA_InitStruct.DMA_ChannelEnable = ENABLE;
    DMA_Init(&DMA_InitStruct);
    DMA_MasterEnableCmd(ENABLE);
}

int main()
{
    uint32_t status = 0;

    // передаем из UART0 в UART2
    UART_DMACmd(NT_UART2, UART_Dir_Rx, ENABLE);
    UART_DMACmd(NT_UART0, UART_Dir_Tx, ENABLE);

    // ждем пока передача завершится
    while((uint32_t)(UART_FlagStatus(NT_UART0, UART_Flag_TxFIFOEmpty)));
    while((uint32_t)(UART_FlagStatus(NT_UART0, UART_Flag_Busy)));
    while((uint32_t)(UART_FlagStatus(NT_UART2, UART_Flag_Busy)));

    // отключаем запросы DMA
    UART_DMACmd(NT_UART0, UART_Dir_Tx, DISABLE);
    UART_DMACmd(NT_UART2, UART_Dir_Rx, DISABLE);

    // проверка результатов
    for (uint32_t i = 0; i < TRANSFERS_TOTAL; i++)
    {
        if (uart0_tx_arr[i] != uart2_rx_arr[i])
        {
            status = 1;
            break;
        }
    }

    while(1)
    {
        // бесконечно переключаем порт если все ок
        if (status == 0)
        {
            GPIO_ToggleBits(STATUS_PORT, STATUS_PIN);
        }
    }
}
