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

#include "niietcm4.h"
#include "retarget.h"

#define __NOP10()   __NOP();\
                    __NOP();\
                    __NOP();\
                    __NOP();\
                    __NOP();\
                    __NOP();\
                    __NOP();\
                    __NOP();\
                    __NOP();\
                    __NOP()

#define __NOP100()  __NOP10();\
                    __NOP10();\
                    __NOP10();\
                    __NOP10();\
                    __NOP10();\
                    __NOP10();\
                    __NOP10();\
                    __NOP10();\
                    __NOP10();\
                    __NOP10()

/* настройка теста */
#define TRANSFERS_TOTAL    16

DMA_ConfigData_TypeDef DMA_CONFIGDATA __attribute__ ((aligned (1024)));

uint32_t array0[TRANSFERS_TOTAL];
uint32_t array1[TRANSFERS_TOTAL];
uint32_t array2[TRANSFERS_TOTAL];
uint32_t array3[TRANSFERS_TOTAL];

volatile uint32_t irq_status = 0;
DMA_ChannelInit_TypeDef DMA_ChannelInitStruct;

void SystemInit()
{
    /* DMA инициализация */
    /* Базовый указатель */
    DMA_BasePtrConfig((uint32_t)(&DMA_CONFIGDATA));
    /* Инициализация канала */
    DMA_ChannelStructInit(&DMA_ChannelInitStruct);
    DMA_ChannelInitStruct.DMA_SrcDataSize = DMA_DataSize_32;
    DMA_ChannelInitStruct.DMA_SrcDataInc = DMA_DataInc_32;
    DMA_ChannelInitStruct.DMA_DstDataSize = DMA_DataSize_32;
    DMA_ChannelInitStruct.DMA_DstDataInc = DMA_DataInc_32;
    DMA_ChannelInitStruct.DMA_ArbitrationRate = DMA_ArbitrationRate_8;
    DMA_ChannelInitStruct.DMA_TransfersTotal = TRANSFERS_TOTAL;
    DMA_ChannelInitStruct.DMA_Mode = DMA_Mode_PingPong;

    /* инициализация первичных данных для 1 этапа */
    DMA_ChannelInitStruct.DMA_SrcDataEndPtr = &array0[TRANSFERS_TOTAL-1];
    DMA_ChannelInitStruct.DMA_DstDataEndPtr = &array1[TRANSFERS_TOTAL-1];
    DMA_ChannelInit(&DMA_CONFIGDATA.PRM_DATA.CH[13], &DMA_ChannelInitStruct);
    /* инициализация альтернативных данных для 2 этапа */
    DMA_ChannelInitStruct.DMA_SrcDataEndPtr = &array1[TRANSFERS_TOTAL-1];
    DMA_ChannelInitStruct.DMA_DstDataEndPtr = &array2[TRANSFERS_TOTAL-1];
    DMA_ChannelInit(&DMA_CONFIGDATA.ALT_DATA.CH[13], &DMA_ChannelInitStruct);

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

    /* инициализация printf */
    retarget_init();

    /* NVIC init */
    NVIC_EnableIRQ(DMA_Stream13_IRQn);

    __enable_irq();
}

int main()
{
    /* инициализация массивов */
    for (uint32_t elem = 0; elem < TRANSFERS_TOTAL; elem++)
    {
        array0[elem] = 0xDEADDEAD;
        array1[elem] = 0xBEEFBEEF;
        array2[elem] = 0xCAFECAFE;
        array3[elem] = 0xBABEBABE;
    }

    /* старт 1 этапа */
    DMA_SWRequestCmd(DMA_Channel_13);   /* передаем первую половину данных */
    __NOP100(); /* при переарбитрации нет прерывания, поэтому стоит немного подождать */
    DMA_SWRequestCmd(DMA_Channel_13);   /* передаем вторую половину данных */
    while (irq_status != DMA_Channel_13);
    irq_status = 0;
    /* инициализация первичных данных для 3 этапа */
    DMA_ChannelInitStruct.DMA_SrcDataEndPtr = &array2[TRANSFERS_TOTAL-1];
    DMA_ChannelInitStruct.DMA_DstDataEndPtr = &array3[TRANSFERS_TOTAL-1];
    DMA_ChannelInit(&DMA_CONFIGDATA.PRM_DATA.CH[13], &DMA_ChannelInitStruct);

    /* старт 2 этапа */
    DMA_SWRequestCmd(DMA_Channel_13);   /* передаем первую половину данных */
    __NOP100();
    DMA_SWRequestCmd(DMA_Channel_13);   /* передаем вторую половину данных */
    while (irq_status != DMA_Channel_13);
    irq_status = 0;

    /* старт 3 этапа */
    DMA_SWRequestCmd(DMA_Channel_13);   /* передаем первую половину данных */
    __NOP100();
    DMA_SWRequestCmd(DMA_Channel_13);   /* передаем вторую половину данных */
    while (irq_status != DMA_Channel_13);
    irq_status = 0;

    /* завершение цикла пинг-понг считыванием неверной структуры */
    DMA_SWRequestCmd(DMA_Channel_13);

    /* проверяем результаты */
    uint32_t check_error = 0;
    for (uint32_t elem = 0; elem < TRANSFERS_TOTAL; elem++)
    {
        if (check_error) break;
        if (array0[elem] != array3[elem])
        {
            check_error = 1;
        }
    }

    if (check_error)
    {
        printf("Check results error.\n");
        printf("Test failed!\n");
    }
    else
    {
        printf("All transfers done and checked. Test success!\n");
    }

    while(1);
}

void DMA_Stream13_IRQHandler()
{
    irq_status |= DMA_Channel_13;
}
