//-----------------------------------------------------------------------------
///
/// \brief  Dma
///
///         Blah blah blub
///
/// \date   20150208
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//-----------------------------------------------------------------------------


//---Includes------------------------------------------------------------------


//---Own------------------------------

//#include <biwak/config.h>
#include <biwak/biwak.h>         // exception
#include <biwak/dma.hpp>
#include <biwak/gpio.hpp>
#include <biwak/rcc.h>           // rccDmaClockEnable
#include <biwak/handler.h>           // __TIM6_Dma_IRQHandler()
#include <HALWrapper/stm32_dma.h>
#include <HALWrapper/stm32_hal.h>       // HAL_REMAPDMA_TIM6_DAC1_CH1_DMA1_CH3
#include <biwak/nvic.h>          // ePeripheral
#include <string.h>              // memset()
#include <biwak/exception.h>
#include <lepto/log.h>


//---Implementation------------------------------------------------------------


#define doDma 1

#ifdef STM32F407xx
   #define DMA_Channel_TypeDef DMA_Stream_TypeDef
#endif

struct{
   //DMA_HandleTypeDef handler;
   DMA_TypeDef *dma;
   DMA_Channel_TypeDef *DmaChannel;
   // Channel stucks in handler
   IRQn_Type irq;
   uint32_t channel;
   /*
   EGpioPeripheral _eGpioPeripheral;
   EGpioPin _eGpioPin;
   EAltFunc _eAltFunc;
   */

} const static dmaStaticChannelData[]=
{
   #ifdef STM32L100xC
   //[eDma1]={ {},Dma, Dma_IRQn, eGpioPeripheralA, eGpioPin4, eAltFunCDmaChannel1},
   [eDma1Channel1]={ DMA1, DMA1_Channel1, DMA1_Channel1_IRQn  },
   [eDma1Channel2]={ DMA1, DMA1_Channel2, DMA1_Channel2_IRQn  },
   [eDma1Channel3]={ DMA1, DMA1_Channel3, DMA1_Channel3_IRQn  },
   [eDma1Channel4]={ DMA1, DMA1_Channel4, DMA1_Channel4_IRQn  },
   [eDma1Channel5]={ DMA1, DMA1_Channel5, DMA1_Channel5_IRQn  },
   [eDma1Channel6]={ DMA1, DMA1_Channel6, DMA1_Channel6_IRQn  },
   [eDma1Channel7]={ DMA1, DMA1_Channel7, DMA1_Channel7_IRQn  },
   #elif defined (STM32F072xB)
   [eDma1Channel1]={ DMA1, DMA1_Channel1, DMA1_Channel1_IRQn  },
   [eDma1Channel2]={ DMA1, DMA1_Channel2, DMA1_Channel2_3_IRQn  },
   [eDma1Channel3]={ DMA1, DMA1_Channel3, DMA1_Channel2_3_IRQn  },
   [eDma1Channel4]={ DMA1, DMA1_Channel4, DMA1_Channel4_5_6_7_IRQn  },
   [eDma1Channel5]={ DMA1, DMA1_Channel5, DMA1_Channel4_5_6_7_IRQn  },
   [eDma1Channel6]={ DMA1, DMA1_Channel6, DMA1_Channel4_5_6_7_IRQn  },
   [eDma1Channel7]={ DMA1, DMA1_Channel7, DMA1_Channel4_5_6_7_IRQn  },
   #elif defined(STM32F103xB)
   [eDma1Channel1]={ DMA1, DMA1_Channel1, DMA1_Channel1_IRQn  },
   [eDma1Channel2]={ DMA1, DMA1_Channel2, DMA1_Channel2_IRQn  },
   [eDma1Channel3]={ DMA1, DMA1_Channel3, DMA1_Channel3_IRQn  },
   [eDma1Channel4]={ DMA1, DMA1_Channel4, DMA1_Channel4_IRQn  },
   [eDma1Channel5]={ DMA1, DMA1_Channel5, DMA1_Channel5_IRQn  },
   [eDma1Channel6]={ DMA1, DMA1_Channel6, DMA1_Channel6_IRQn  },
   [eDma1Channel7]={ DMA1, DMA1_Channel7, DMA1_Channel7_IRQn  },
   #elif defined (STM32F4)
   [eDma1Channel1]={ DMA1, DMA1_Stream1, DMA1_Stream1_IRQn, DMA_CHANNEL_1 },
   [eDma1Channel2]={ DMA1, DMA1_Stream2, DMA1_Stream2_IRQn, DMA_CHANNEL_2 },
   [eDma1Channel3]={ DMA1, DMA1_Stream3, DMA1_Stream3_IRQn, DMA_CHANNEL_3 },
   [eDma1Channel4]={ DMA1, DMA1_Stream4, DMA1_Stream4_IRQn, DMA_CHANNEL_4 },
   [eDma1Channel5]={ DMA1, DMA1_Stream5, DMA1_Stream5_IRQn, DMA_CHANNEL_5 },
   [eDma1Channel6]={ DMA1, DMA1_Stream6, DMA1_Stream6_IRQn, DMA_CHANNEL_6 },
   [eDma1Channel7]={ DMA1, DMA1_Stream7, DMA1_Stream7_IRQn, DMA_CHANNEL_7 },
   #elif defined (STM32F3)
   [eDma1Channel1]={ DMA1, DMA1_Channel1, DMA1_Channel1_IRQn, 0 },
   [eDma1Channel2]={ DMA1, DMA1_Channel2, DMA1_Channel2_IRQn, 1 },
   [eDma1Channel3]={ DMA1, DMA1_Channel3, DMA1_Channel3_IRQn, 2 },
   [eDma1Channel4]={ DMA1, DMA1_Channel4, DMA1_Channel4_IRQn, 3 },
   [eDma1Channel5]={ DMA1, DMA1_Channel5, DMA1_Channel5_IRQn, 4 },
   [eDma1Channel6]={ DMA1, DMA1_Channel6, DMA1_Channel6_IRQn, 5 },
   [eDma1Channel7]={ DMA1, DMA1_Channel7, DMA1_Channel7_IRQn, 6 },
   #elif defined (STM32F042x6)
      [eDma1Channel1]={ DMA1, DMA1_Channel1, DMA1_Channel1_IRQn  },
      [eDma1Channel2]={ DMA1, DMA1_Channel2, DMA1_Channel2_3_IRQn  },
      [eDma1Channel3]={ DMA1, DMA1_Channel3, DMA1_Channel2_3_IRQn  },
   #endif
};


struct{
   DMA_HandleTypeDef *pHandler;
} dmaDynamicChannelData[eDma1ChannelMax]=
{
   nullptr,
   nullptr,
   nullptr,
   nullptr,
   nullptr,
   nullptr,
   nullptr,
};


CDma::CDma( const SDmaConfig &dmaConfig )
{
   m_dma=DMA1;
   init();
}

CDmaChannel::CDmaChannel( EDmaChannel _eDmaChannel, CDma &dma )
   :eDmaChannel(_eDmaChannel)
   ,m_dma(dma)
{
   bAssertIndexInArray(eDmaChannel, dmaStaticChannelData);

   m_pHandler=new DMA_HANDLE_TYPE;
   dmaDynamicChannelData[eDmaChannel].pHandler=m_pHandler;

   memset(m_pHandler, 0, sizeof(DMA_HANDLE_TYPE) );

   #if defined ( STM32F4 ) || defined ( STM32G0 )
   // TBD
   //m_pHandler->StreamBaseAddress=dma;
   //m_pHandler->StreamIndex = dmaStaticChannelData[eDmaChannel].channel;
   #else
   // m_pHandler->DmaBaseAddress=dma;
   // m_pHandler->ChannelIndex = dmaStaticChannelData[eDmaChannel].channel;
   m_pHandler->DmaBaseAddress=dma.m_dma;
   //m_pHandler->ChannelIndex = dmaStaticChannelData[eDmaChannel].channel;
   #endif
   m_pHandler->Instance=dmaStaticChannelData[eDmaChannel].DmaChannel;
   m_pHandler->ChannelIndex=1;

   init();
}

CDmaChannel::~CDmaChannel()
{

}

void CallBack1(struct __DMA_HandleTypeDef * hdma)
{
   exception( );
   // Yeah, this works
}


void CDma::init()
{
   rccDmaClockEnable(m_dma);
}

void CDmaChannel::init()
{
   HAL_StatusTypeDef status __attribute ( (unused) );
   // Wen need high priority because timer might be used in ISRs.
   setNVInterrupt(dmaStaticChannelData[eDmaChannel].irq, true, NVI_DEFAULT_PRIORITY);

   // DMA1_Stream[67] channel7 configuration

   // Need to deinit DMA first
   //m_pHandler->State = HAL_DMA_STATE_READY;
   //HAL_DMA_DeInit(m_pHandler);
   //m_pHandler->State = HAL_DMA_STATE_RESET;

#if defined( STM32F4 ) || defined( STM32F4 )
   //pHandler->Init.Channel = dmaChannelData[eDmaChannel].channel;
   m_pHandler->Init.Channel = DMA_CHANNEL_7;
   asdasd
#else
   // has no channel
#endif
   //m_pHandler->ChannelIndex=5<<2;
   m_pHandler->Init.Direction = DMA_MEMORY_TO_PERIPH;
   m_pHandler->Init.PeriphInc = DMA_PINC_DISABLE;
   m_pHandler->Init.MemInc = DMA_MINC_ENABLE;

#if 1
   // 16Bit Timer
   m_pHandler->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
   m_pHandler->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
#else
   // 32Bit Timer
   m_pHandler->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
   m_pHandler->Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
#endif

   // m_pHandler->Init.Mode = DMA_CIRCULAR;
   m_pHandler->Init.Mode = DMA_NORMAL;
   m_pHandler->Init.Priority = DMA_PRIORITY_MEDIUM;

   m_pHandler->XferCpltCallback=CallBack1;
   m_pHandler->XferErrorCallback=CallBack1;
   m_pHandler->XferHalfCpltCallback=CallBack1;

/*
   m_pHandler->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
   m_pHandler->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
   m_pHandler->Init.MemBurst = DMA_MBURST_SINGLE;
   m_pHandler->Init.PeriphBurst = DMA_PBURST_SINGLE;
*/

   status=HAL_DMA_Init(m_pHandler);
   bDebugAssert( status == HAL_OK, status );
}


extern "C"
{
   //void                  TIM_DMADelayPulseCplt( struct __DMA_HandleTypeDef * hdma);
   //void                  TIM_DMAError( struct __DMA_HandleTypeDef * hdma);
   //void HAL_TIM_ErrorCallback(TIM_HandleTypeDef *htim)
}

void XX_TIM_DMADelayPulseCplt( struct __DMA_HandleTypeDef * hdma)
{
   lInfo("TIM_DMADelayPulseCplt");
}
void XX_TIM_DMAError( struct __DMA_HandleTypeDef * hdma)
{
   lInfo("TIM_DMAError");
}

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes"

#if defined ( STM32F3 ) || defined ( STM32F0 )

IRQ_Funcion_imp( DMA1_Channel1_IRQHandler )
{
   exception( );

   if( dmaDynamicChannelData[eDma1Channel1].pHandler )
      HAL_DMA_IRQHandler( dmaDynamicChannelData[eDma1Channel1].pHandler );
   else
      exception( );
}

#endif

#if defined ( STM32F3 )

IRQ_Funcion_imp( DMA1_Channel2_IRQHandler )
{
   if( dmaDynamicChannelData[eDma1Channel2].pHandler )
      HAL_DMA_IRQHandler( dmaDynamicChannelData[eDma1Channel2].pHandler );
   else
      exception( );
}

IRQ_Funcion_imp( DMA1_Channel3_IRQHandler )
{
   if( dmaDynamicChannelData[eDma1Channel3].pHandler )
      HAL_DMA_IRQHandler( dmaDynamicChannelData[eDma1Channel3].pHandler );
   else
      exception( );
}

IRQ_Funcion_imp( DMA1_Channel4_IRQHandler )
{
   if( dmaDynamicChannelData[eDma1Channel4].pHandler )
      HAL_DMA_IRQHandler( dmaDynamicChannelData[eDma1Channel4].pHandler );
   else
      exception( );
}

IRQ_Funcion_imp( DMA1_Channel5_IRQHandler )
{
   exception( );
   if(doDma)
   if( dmaDynamicChannelData[eDma1Channel5].pHandler )
      HAL_DMA_IRQHandler( dmaDynamicChannelData[eDma1Channel5].pHandler );
}

IRQ_Funcion_imp( DMA1_Channel6_IRQHandler )
{
   exception( );
   if(doDma)
   if( dmaDynamicChannelData[eDma1Channel6].pHandler )
      HAL_DMA_IRQHandler( dmaDynamicChannelData[eDma1Channel6].pHandler );
}

IRQ_Funcion_imp( DMA1_Channel7_IRQHandler )
{
   exception( );
   if(doDma)
   if( dmaDynamicChannelData[eDma1Channel7].pHandler )
      HAL_DMA_IRQHandler( dmaDynamicChannelData[eDma1Channel7].pHandler );
}


#elif defined(STM32F0XX)


IRQ_Funcion_imp( DMA1_Channel2_3_IRQHandler )
{
   if( dmaDynamicChannelData[eDma1Channel2].pHandler )
      HAL_DMA_IRQHandler( dmaDynamicChannelData[eDma1Channel2].pHandler );

   if( dmaDynamicChannelData[eDma1Channel3].pHandler )
      HAL_DMA_IRQHandler( dmaDynamicChannelData[eDma1Channel3].pHandler );
}

IRQ_Funcion_imp( DMA1_Channel4_5_6_7_IRQHandler )
{
   for(int i1=eDma1Channel4; i1<=eDma1Channel7; i1++)
   {
      if(dmaDynamicChannelData[i1].pHandler)
      {
         HAL_DMA_IRQHandler( dmaDynamicChannelData[i1].pHandler );
      }
   }

   return;
}

#elif defined (STM32F4) || defined (STM32F3)


void DMA1_Stream1_IRQHandler(void)
{
   HAL_DMA_IRQHandler(dmaDynamicChannelData[eDma1Channel1].pHandler);
}


void DMA1_Stream2_IRQHandler(void)
{
   HAL_DMA_IRQHandler(dmaDynamicChannelData[eDma1Channel2].pHandler);
}


void DMA1_Stream3_IRQHandler(void)
{
   HAL_DMA_IRQHandler(dmaDynamicChannelData[eDma1Channel3].pHandler);
}


void DMA1_Stream4_IRQHandler(void)
{
   HAL_DMA_IRQHandler(dmaDynamicChannelData[eDma1Channel4].pHandler);
}


void DMA1_Stream5_IRQHandler(void)
{
   HAL_DMA_IRQHandler(dmaDynamicChannelData[eDma1Channel5].pHandler);
}


void DMA1_Stream6_IRQHandler(void)
{
   HAL_DMA_IRQHandler(dmaDynamicChannelData[eDma1Channel6].pHandler);
}


void DMA1_Stream7_IRQHandler(void)
{
   HAL_DMA_IRQHandler(dmaDynamicChannelData[eDma1Channel7].pHandler);
}


#endif


#pragma GCC diagnostic pop


//---fin-----------------------------------------------------------------------
