/**
  ******************************************************************************
  * @file    main.c
  *
  * @brief   Тест режима авто-запрос работы DMA.
  *
  *          Пересылка 8-битных значений из массива в массив в режиме
  *          автозапроса по первым 4 каналам.
  *
  *          Компилятор: 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 CHANNELS_TOTAL     4
#define TRANSFERS_TOTAL    8

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

uint8_t array_src[CHANNELS_TOTAL][TRANSFERS_TOTAL];
uint8_t array_dst[CHANNELS_TOTAL][TRANSFERS_TOTAL];

volatile uint32_t irq_status = 0;

void SystemInit()
{
    /* DMA инициализация */
    /* Инициализация базового адреса */
    DMA_BasePtrConfig((uint32_t)(&DMA_CONFIGDATA));
    /* Инициализация каналов */
    DMA_ChannelInit_TypeDef DMA_ChannelInitStruct;
    DMA_ChannelStructInit(&DMA_ChannelInitStruct);
    DMA_ChannelInitStruct.DMA_SrcDataSize = DMA_DataSize_8;
    DMA_ChannelInitStruct.DMA_SrcDataInc = DMA_DataInc_8;
    DMA_ChannelInitStruct.DMA_DstDataSize = DMA_DataSize_8;
    DMA_ChannelInitStruct.DMA_DstDataInc = DMA_DataInc_8;
    DMA_ChannelInitStruct.DMA_ArbitrationRate = DMA_ArbitrationRate_1;
    DMA_ChannelInitStruct.DMA_TransfersTotal = TRANSFERS_TOTAL;
    DMA_ChannelInitStruct.DMA_Mode = DMA_Mode_AutoReq;
    for (uint32_t chan = 0; chan < CHANNELS_TOTAL; chan++)
    {
        DMA_ChannelInitStruct.DMA_SrcDataEndPtr = (uint32_t*)((uint32_t)(&array_src[chan][TRANSFERS_TOTAL-1]) | 0x3);
        DMA_ChannelInitStruct.DMA_DstDataEndPtr = (uint32_t*)((uint32_t)(&array_dst[chan][TRANSFERS_TOTAL-1]) | 0x3);
        DMA_ChannelInit(&DMA_CONFIGDATA.PRM_DATA.CH[chan], &DMA_ChannelInitStruct);
    }
    /* Иницализация контроллера */
    DMA_Init_TypeDef DMA_InitStruct;
    DMA_StructInit(&DMA_InitStruct);
    DMA_InitStruct.DMA_Channel = DMA_Channel_0 | DMA_Channel_1 | DMA_Channel_2 | DMA_Channel_3;
    DMA_InitStruct.DMA_ChannelEnable = ENABLE;
    DMA_Init(&DMA_InitStruct);
    DMA_MasterEnableCmd(ENABLE);

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

    /* NVIC init */
    NVIC_EnableIRQ(DMA_Stream0_IRQn);
    NVIC_EnableIRQ(DMA_Stream1_IRQn);
    NVIC_EnableIRQ(DMA_Stream2_IRQn);
    NVIC_EnableIRQ(DMA_Stream3_IRQn);

    __enable_irq();
}

int main()
{
    /* инициализация массивов */
    for (uint32_t chan = 0; chan < CHANNELS_TOTAL; chan++)
    {
        for (uint32_t elem = 0; elem < TRANSFERS_TOTAL; elem++)
        {
            array_src[chan][elem] = 0xA0 + chan;
            array_dst[chan][elem] = 0xE0 + chan;
        }
    }

    /* начинаем передачу */
    DMA_SWRequestCmd(DMA_Channel_0 | DMA_Channel_1 | DMA_Channel_2 | DMA_Channel_3);

    /* ждем пока dma выполняет запросы */
    while (irq_status != (DMA_Channel_0 | DMA_Channel_1 | DMA_Channel_2 | DMA_Channel_3));

    /* проверяем результаты */
    uint32_t check_error = 0;
    for (uint32_t chan = 0; chan < CHANNELS_TOTAL; chan++)
    {
        if (check_error) break;
        for (uint32_t elem = 0; elem < TRANSFERS_TOTAL; elem++)
        {
            if (check_error) break;
            if (array_src[chan][elem] != array_dst[chan][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_Stream0_IRQHandler()
{
    irq_status |= DMA_Channel_0;
}
void DMA_Stream1_IRQHandler()
{
    irq_status |= DMA_Channel_1;
}
void DMA_Stream2_IRQHandler()
{
    irq_status |= DMA_Channel_2;
}
void DMA_Stream3_IRQHandler()
{
    irq_status |= DMA_Channel_3;
}
