// STM32F103xx: only high density
#if ! ( defined(STM32F103xB) || defined(STM32F103x6) || defined (STM32G0) )
//-----------------------------------------------------------------------------
///
/// \brief  DAC line with DMA
///
///         Blah blah blub
///
/// \date   20230826
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//-----------------------------------------------------------------------------


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


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

#include <biwak/dac_line_dma.hpp>
#include <biwak/dma_channel.hpp>
#include <biwak/exception.h>
#include <HALWrapper/stm32_hal.h>

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


CDacLineDma::CDacLineDma( CDacChannel &dacChannel,
                         CDmaChannel& dmaChannel, CTimer &timer )
    :m_dacChannel( dacChannel )
    ,m_dmaChannel( dmaChannel )
    ,m_timer( timer )
{
   linkDma( m_dmaChannel );
   
   m_timer.setMasterConfig();
   m_timer.updateFrequency(4000);

   #pragma GCC diagnostic push
   #pragma GCC diagnostic ignored "-Wvolatile"
   
   // STM32F303
   #if defined( HAL_REMAPDMA_TIM6_DAC1_CH1_DMA1_CH3 )
      // Well, thats pretty hardcoded, DMA/TIM/DAC..., ok!
      if ( ( dmaChannel.channel() == eDma1Channel3 ) && ( timer.getHandler()->Instance == TIM6 ) )
      {
         __HAL_DMA_REMAP_CHANNEL_ENABLE(HAL_REMAPDMA_TIM6_DAC1_CH1_DMA1_CH3);
      }
   #endif
      
   // STM32F303
   #if defined(HAL_REMAPDMA_TIM7_DAC1_CH2_DMA1_CH4)
      if( ( dmaChannel.channel() == eDma1Channel4 ) && ( timer.getHandler()->Instance == TIM7 ) )
      {
         __HAL_DMA_REMAP_CHANNEL_ENABLE(HAL_REMAPDMA_TIM7_DAC1_CH2_DMA1_CH4);
      }
   #endif
      
   #pragma GCC diagnostic pop
}


void CDacLineDma::linkDma( CDmaChannel &dmaChannel )
{
   if( m_dacChannel.getChannel() == eDacChannel1 )
   {
      m_dacChannel.dac().getHandle()->DMA_Handle1=dmaChannel.getDmaHandler();
      __HAL_LINKDMA(m_dacChannel.dac().getHandle(), DMA_Handle1, *dmaChannel.getDmaHandler());
   }
   else if( m_dacChannel.getChannel() == eDacChannel2 )
   {
      m_dacChannel.dac().getHandle()->DMA_Handle2=dmaChannel.getDmaHandler();
      __HAL_LINKDMA(m_dacChannel.dac().getHandle(), DMA_Handle2, *dmaChannel.getDmaHandler());
   }
   else
   {
      exception( );
   }
}


void CDacLineDma::startDma(void *buf, int size)
{
   HAL_StatusTypeDef status;
   
   int trigger;
   switch( (uint32_t)m_timer.getHandler()->Instance )
   {
      case (uint32_t)TIM2_BASE:
         trigger=DAC_TRIGGER_T2_TRGO;
         break;
      case (uint32_t)TIM6_BASE:
         trigger=DAC_TRIGGER_T6_TRGO;
         break;
      case (uint32_t)TIM7_BASE:
         trigger=DAC_TRIGGER_T7_TRGO;
         break;
      default:
         // unknown timer, (uint32_t)m_timer.getHandler()->Instance
         exception( );
         break;
   }

   (void)trigger;
   m_dacChannel.init(trigger);
   
   status=HAL_DAC_Start_DMA( m_dacChannel.dac().getHandle()
                              , m_dacChannel.getChannel() ==
                                    eDacChannel1 ? DAC_CHANNEL_1:DAC_CHANNEL_2
                              , (uint32_t *)buf, size
                              , DAC_ALIGN_12B_R);
   (void)status;
   bDebugAssert( status == HAL_OK, status );
   
   m_timer.start();
   
   return;
}


void CDacLineDma::stopDma( )
{
   HAL_StatusTypeDef status;
   
   m_timer.stop();
   status=HAL_DAC_Stop_DMA( m_dacChannel.dac().getHandle()
                              , m_dacChannel.getChannel() ==
                                      eDacChannel1 ? DAC_CHANNEL_1:DAC_CHANNEL_2
                              );
   //(void)status;
   bAssert( status == HAL_OK, status );
}

void CDacLineDma::stopTimer( )
{
   m_timer.stop();
}


//---fin-----------------------------------------------------------------------
#endif // ? ! defined(STM32F103xB)
