/**
  **********************************************************************************
  * @file    dma_hal.c
  * @author  Product application department
  * @version V1.0
  * @date    2020.02.19
  * @brief   DMA模块HAL层驱动.
  * @note 这个文件为应用层提供了操作CPM的接口:
  *     - dma初始化接口
  *     - 设置DMA传输参数接口
  *     - 开启，挂起，终止DMA传输接口.
  *     + 轮询传输完成和DMA中断服务函数接口.
  *
  @verbatim
  ===================================================================================
                                  ##### 更新 #####
  ===================================================================================
  [..] 更新时间:
  [..] 更新人:
  [..] 更新内容:
        1. nothing.
  @endverbatim
  */

#include <string.h>
#include "dma_hal.h"
#include "spi_drv.h"
#include "hal.h"


/*** 全局变量定义 ***************************************************************/
/** @
  * @{volatile
  */
/** @ 
  * @}
  */
/** @ 
  * @{static
  */
 static uint8_t dmac_isr_flag = 0;
/** @ 
  * @}
  */
/*** 常量定义 *******************************************************************/
/** @
  * @{const
  */
/** @ 
  * @}
  */

/*** 函数定义 *******************************************************************/
static void DMAC_SetConfig(DMAC_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);

/**
 * @brief 获取DMAC空闲通道.
 *
 * @param[out] pres：通道数据指针.
 * @return
 * - HAL_OK;
 * - HAL_ERROR;
 */
HAL_StatusTypeDef HAL_DMAC_GetFreeChannel(DMAC_TypeDef *pdmac,uint8_t *pres)
{
    uint8_t  loop=0;
	//uint32_t tmp = _damc_get_ch_en;

    for(loop=0; loop < DMAC_NUMBER_CHANNELS; loop++)
    {
        /*The ChEnReg.CH_EN bit is automatically cleared by hardware to disable the
        channel after the last AMBA transfer of the DMA transfer to the destination has
        completed. Software can therefore poll this bit to determine when this channel is
        free for a new DMA transfer*/

        if(_damc_get_ch_en(pdmac,loop)== 0)
        {
            *pres = loop;
            
            return HAL_OK;
        }
    }

    return HAL_ERROR;
}
/*** 函数定义 *******************************************************************/

/**
  * @brief dmac初始化.
  *
  * @param [in] hdmac DMAC句柄指针
  * @return
  * - HAL_OK;
  * - HAL_ERROR;
  */
HAL_StatusTypeDef HAL_DMAC_Init(DMAC_HandleTypeDef *hdma)
{
    //uint32_t tmp = 0;
	
	/* Check the DMA handle allocation */
	if(hdma == NULL)
	{
	    return HAL_ERROR;
	}

	if (hdma->init.channel_num > HAL_DMAC_CHANNEL_3)
		return HAL_ERROR;

    if(hdma->state == HAL_DMA_STATE_RESET)
    {  
        /* Allocate lock resource and initialize it */
        hdma->lock = HAL_UNLOCKED;
    }
	
	/* Change DMA peripheral state */
	hdma->state = HAL_DMA_STATE_BUSY;

    /* Clear SRC_MSIZE, DEST_MSIZE, SINC, DINC, SRC_TR_WIDTH, DST_TR_WIDTH bits */
	_dmac_clr_dmac_ctrln(hdma->instance,hdma->init.channel_num);

	DRV_DMAC_CtrlRegConfig(hdma->instance,
	                       hdma->init.channel_num,  \
		                   hdma->init.transfer_type,\
		                   hdma->init.src_msize,    \
		                   hdma->init.dst_msize,    \
		                   hdma->init.src_inc,      \
		                   hdma->init.dst_inc,      \
		                   hdma->init.src_tr_width, \
		                   hdma->init.dst_tr_width);

    DMAC_SetConfig(hdma,hdma->init.src_addr,hdma->init.dst_addr,hdma->init.transfer_size);
	
    /* Initialize the DMA state*/
    hdma->state = HAL_DMA_STATE_READY;

	return HAL_OK;
}

/**
  * @brief 复位dmac.
  *
  * @param [in] hdmac DMAC句柄指针
  * @return
  * - HAL_OK;
  * - HAL_ERROR;
  */
HAL_StatusTypeDef HAL_DMAC_Deinit(DMAC_HandleTypeDef *hdma)
{
    /* Check the DMA handle allocation */
    if(hdma == NULL)
    {
      return HAL_ERROR;
    }
	
	/* Check the DMA peripheral state */
	if(hdma->state == HAL_DMA_STATE_BUSY)
	{
	   return HAL_ERROR;
	}

	/* Disable the selected DMA Channelx */
	_dmac_ch_dis(hdma->instance,hdma->init.channel_num);

	/* Reset DMA Channel control register */
	_dmac_clr_dmac_ctrln(hdma->instance,hdma->init.channel_num);

	/* Clear all flags */	
	/* Clear raw interrupt status flag */
	_dmac_clr_raw_interrupt_status(hdma->instance,hdma->init.channel_num);
	
	/* Clear block interrupt status flag */
	_dmac_clr_block_interrupt_status(hdma->instance,hdma->init.channel_num);
	
	/* Clear error interrupt status flag */

	/* Initialize the DMA state */
    hdma->state = HAL_DMA_STATE_RESET;

	/* Release lock */
    __HAL_UNLOCK(hdma);
	
	return HAL_OK;
	
}
/**
  * @brief  设置DMA传输参数
  *
  * @param [in] hedmac DMAC句柄指针
  * @param [in] SrcAddress DMA的源地址
  * @param [in] DstAddress DMA的目的地址
  * @param [in] DataLength 传输的数据长度
  * @retval 无
  */
static void DMAC_SetConfig(DMAC_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
    if(hdma->init.transfer_lli == HAL_DMAC_LLP_DIS)
    {
	    /* Configure DMA Channel data length */
        _dmac_set_transfer_length(hdma->instance,hdma->init.channel_num, DataLength);
	
        /* Configure DMA Channel source address */
	    _dmac_set_source_address(hdma->instance,hdma->init.channel_num, SrcAddress);

	    /* Configure DMA Channel destination address */
	    _dmac_set_destination_address(hdma->instance,hdma->init.channel_num, DstAddress);
    }
	else
	{
		DMAC_LLITypeDef pdma_lli;

		pdma_lli.dst_addr = DstAddress;
		pdma_lli.src_addr = SrcAddress;
		pdma_lli.len      = DataLength;
		
		DRV_DMAC_LliRegInit(hdma->instance,hdma->init.channel_num, &pdma_lli);
	}
    
    /*memory to peripheral, dmac controller*/
	if(hdma->init.transfer_type == HAL_DMAC_TRANSFERTYPE_M2P_CONTROLLER_DMA)
	{
	    /*硬件握手*/
        _dmac_src_hs_soft(hdma->instance,hdma->init.channel_num);
        _dmac_dst_hs_hard(hdma->instance,hdma->init.channel_num);
		
	    /*目标外围设备*/
        _dmac_set_dst_peripheral(hdma->instance,hdma->init.channel_num, hdma->init.peripheral_type);
	}
	/*peripheral to memory, dmac controlller*/
	else if(hdma->init.transfer_type == HAL_DMAC_TRANSFERTYPE_P2M_CONTROLLER_DMA)
	{
		 /*硬件握手*/
        _dmac_src_hs_hard(hdma->instance,hdma->init.channel_num);
        _dmac_dst_hs_soft(hdma->instance,hdma->init.channel_num);
		
	    /*目标外围设备*/
        _dmac_set_src_peripheral(hdma->instance,hdma->init.channel_num, hdma->init.peripheral_type);
	}
	/*memory to memory, dmac controller*/
	else if(hdma->init.transfer_type == HAL_DMAC_TRANSFERTYPE_M2M_CONTROLLER_DMA)
	{
	    /*硬件握手*/
        _dmac_src_hs_soft(hdma->instance,hdma->init.channel_num);
        _dmac_dst_hs_soft(hdma->instance,hdma->init.channel_num);
	}
	else
	{
		;
	}
}
/**
  * @brief 开启非中断模式DMA传输.
  *
  * @param [in] hedmac DMAC句柄指针
  * @return
  * - HAL_OK;
  * - HAL_ERROR;
  */
HAL_StatusTypeDef HAL_DMAC_StartPolling(DMAC_HandleTypeDef *hdma)
{
	/*Enable DMAC*/
	_dmac_en(hdma->instance);

	/* Disable the selected DMA Channelx */
	_dmac_ch_dis(hdma->instance,hdma->init.channel_num);

    /*采用查询的方式*/
    DRV_DMAC_DisTfrIt(hdma->instance,hdma->init.channel_num);
	//_dmac_raw_interrupt_dis(hdma->init.channel_num);
	
    /* Enable the selected DMA Channelx */
	_dmac_ch_en(hdma->instance,hdma->init.channel_num);

	return HAL_OK; 
}

HAL_StatusTypeDef HAL_DMAC_StartPolling_test(DMAC_HandleTypeDef *hdma)
{
	/*Enable DMAC*/
	_dmac_en(hdma->instance);

	/* Disable the selected DMA Channelx */
	_dmac_ch_dis(hdma->instance,hdma->init.channel_num);

    /*采用查询的方式*/
    DRV_DMAC_DisTfrIt(hdma->instance,hdma->init.channel_num);
	//_dmac_raw_interrupt_dis(hdma->init.channel_num);
	
    /* Enable the selected DMA Channelx */
	_dmac_ch_en(hdma->instance,hdma->init.channel_num);
//	DMAC2->CHEN |= (1<<0)|(1<<8);

	return HAL_OK; 
}

/**
  * @brief 开启中断模式DMA传输.
  *
  * @param [in] hedmac DMAC句柄指针
  * @param [in] SrcAddress DMA的源地址
  * @param [in] DstAddress DMA的目的地址
  * @param [in] DataLength 传输的数据长度
  * @return
  * - HAL_OK;
  * - HAL_ERROR;
  */
HAL_StatusTypeDef HAL_DMAC_StartIT(DMAC_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
    /* Process locked */
    __HAL_LOCK(hdma);

    /* Change DMA peripheral state */
    hdma->state = HAL_DMA_STATE_BUSY;	

	/*Enable DMAC*/
	_dmac_en(hdma->instance);

	/* Disable the selected DMA Channelx */
	_dmac_ch_dis(hdma->instance,hdma->init.channel_num);

	/* Enable the transfer complete flag*/
    _dmac_raw_interrupt_en(hdma->instance,hdma->init.channel_num);
    /*DMAC interrupt enable*/
	_dmac_int_en_en(hdma->instance,hdma->init.channel_num);
	
    /* Enable the selected DMA Channelx */
	_dmac_ch_en(hdma->instance,hdma->init.channel_num);


	return HAL_OK; 
}
/**
  * @brief 挂起DMA传输.
  *
  * @param [in] hdmac DMAC句柄指针
  * @return
  * - HAL_OK;
  * - HAL_ERROR;
  */
HAL_StatusTypeDef HAL_DMAC_Suspend(DMAC_HandleTypeDef *hdma)
{

	return HAL_OK;
}
/**
  * @brief 恢复DMA传输.
  *
  * @param [in] hdmac DMAC句柄指针
  * @return
  * - HAL_OK;
  * - HAL_ERROR;
  */
HAL_StatusTypeDef HAL_DMAC_Resume(DMAC_HandleTypeDef *hdma)
{

	return HAL_OK;
}
/**
  * @brief 中止DMA传输.
  *
  * @param [in] hdmac DMAC句柄指针
  * @return
  * - HAL_OK;
  * - HAL_ERROR;
  */
HAL_StatusTypeDef HAL_DMAC_Abort(DMAC_HandleTypeDef *hdma)
{
	uint32_t tickstart = 0;

    if (hdma->state == HAL_DMA_STATE_BUSY)
    {		
		/* Get tick */
		tickstart = HAL_GetTick();

		/*中止之前查询完成状态*/
		while(DRV_DMAC_GetRawStatus(hdma->instance,hdma->init.channel_num) !=  BIT_SET)
		{
			/* Check for the Timeout */
			if((HAL_GetTick() - tickstart) > HAL_TIMEOUT_DMA_ABORT)
			{
			  /* Change the DMA state */
			  hdma->state = HAL_DMA_STATE_TIMEOUT;

			  /* Process Unlocked */
			  __HAL_UNLOCK(hdma);

			  return HAL_TIMEOUT;
			}
		}
	    /* Clear the transfer complete flag */
        DRV_DMAC_ClearRawStatus(hdma->instance,hdma->init.channel_num);	
    }

	/* Disable the selected DMA Channelx */
	_dmac_ch_dis(hdma->instance,hdma->init.channel_num);

	/* Change the DMA state */
	hdma->state = HAL_DMA_STATE_READY;

	/* Process Unlocked */
	__HAL_UNLOCK(hdma);

    return HAL_OK;
}
void HAL_DMAC_ClearRawStatus(DMAC_HandleTypeDef *hdma,uint32_t ch)
{
	DRV_DMAC_ClearRawStatus(hdma->instance,ch);
}
/**
  * @brief 轮询普通模式传输完成.
  *
  * @param [in] hdmac EDMAC句柄指针
  * @param [in] CompleteLevel DMA完成级别
  * @param [in] Timeout 超时时间
  * @return
  * - HAL_OK;
  * - HAL_ERROR;
  *-
  */
HAL_StatusTypeDef HAL_DMAC_PollForTransfer(DMAC_HandleTypeDef *hdma, uint32_t CompleteLevel, uint32_t Timeout)
{
	uint32_t tickstart = 0x00;
	BitActionTypeDef raw_status;

	/* Transfer Complete flag */
    raw_status = DRV_DMAC_GetRawStatus(hdma->instance,hdma->init.channel_num);
	
	/* Get tick */
	tickstart = HAL_GetTick();
	while(raw_status == BIT_RESET)
    {
        raw_status = DRV_DMAC_GetRawStatus(hdma->instance,hdma->init.channel_num);
        /* Check for the Timeout */
        if(Timeout != HAL_MAX_DELAY)
        {
			
            if((Timeout == 0) || ((HAL_GetTick() - tickstart) > Timeout))
            {       
                /* Change the DMA state */
                hdma->state = HAL_DMA_STATE_TIMEOUT;

                /* Process Unlocked */
                __HAL_UNLOCK(hdma);
				
                return HAL_TIMEOUT;
            }
        }
    }

    /* Clear the transfer complete flag */
    DRV_DMAC_ClearRawStatus(hdma->instance,hdma->init.channel_num);

    /* The selected Channelx EN bit is cleared (DMA is disabled and 
    all transfers are complete) */
    hdma->state = HAL_DMA_STATE_READY;

    /* Process unlocked */
    __HAL_UNLOCK(hdma);

	return HAL_OK;
}

u16 count_test=0;
HAL_StatusTypeDef HAL_DMAC_PollForTransfer_test(DMAC_HandleTypeDef *hdma, uint32_t CompleteLevel, uint32_t Timeout)
{
	
	uint32_t tickstart = 0x00;
	BitActionTypeDef raw_status;

	/* Transfer Complete flag */
//    raw_status = DRV_DMAC_GetRawStatus(hdma->instance,hdma->init.channel_num);
////	printf("s:%d\r\n",raw_status);
//	/* Get tick */
//	tickstart = HAL_GetTick();
//	printf("sta1:%d\r\n",raw_status);
////	printf("count:%d\r\n",count_test++);
//	while(raw_status == BIT_RESET)
//    {
//		
//        raw_status = DRV_DMAC_GetRawStatus(hdma->instance,hdma->init.channel_num);
////		printf("sta2:%d\r\n",raw_status);
//		
//        /* Check for the Timeout */
//        if(Timeout != HAL_MAX_DELAY)
//        {
//            if((Timeout == 0) || ((HAL_GetTick() - tickstart) > Timeout))
//            {       
//                /* Change the DMA state */
//                hdma->state = HAL_DMA_STATE_TIMEOUT;

//                /* Process Unlocked */
//                __HAL_UNLOCK(hdma);
//        
//                return HAL_TIMEOUT;
//            }
//        }
//    }

    /* Clear the transfer complete flag */
//    DRV_DMAC_ClearRawStatus(hdma->instance,hdma->init.channel_num);
	
//	printf("test\r\n");
	count_test=0;
	while(DMAC2->CHEN & (1<<0))	
	{
		count_test++;
//		printf("count_test:%d\r\n",count_test);
	}
	
	DMAC2->CHEN &= ~(1<<0);		

    /* The selected Channelx EN bit is cleared (DMA is disabled and 
    all transfers are complete) */
//    hdma->state = HAL_DMA_STATE_READY;

//    /* Process unlocked */
//    __HAL_UNLOCK(hdma);

	return HAL_OK;
}

/**
  * @brief 轮询中断模式传输完成.
  *
  * @param [in] hdmac EDMAC句柄指针
  * @param [in] CompleteLevel DMA完成级别
  * @param [in] Timeout 超时时间
  * @return
  * - HAL_OK;
  * - HAL_ERROR;
  */
HAL_StatusTypeDef HAL_DMAC_PollForTransfer_IT(DMAC_HandleTypeDef *hdma, uint32_t CompleteLevel, uint32_t Timeout)
{
	uint32_t tickstart = 0x00;
	uint8_t  raw_status;

	/* Transfer Complete flag */
    raw_status = dmac_isr_flag;
	
	/* Get tick */
	tickstart = HAL_GetTick();
	
	while((raw_status&(1<<hdma->init.channel_num)) != (1<<hdma->init.channel_num))
    {
        raw_status = dmac_isr_flag;
		
        /* Check for the Timeout */
        if(Timeout != HAL_MAX_DELAY)
        {
            if((Timeout == 0) || ((HAL_GetTick() - tickstart) > Timeout))
            {       
                /* Change the DMA state */
                hdma->state = HAL_DMA_STATE_TIMEOUT;

                /* Process Unlocked */
                __HAL_UNLOCK(hdma);
        
                return HAL_TIMEOUT;
            }
        }
    }

    /* Clear the transfer complete flag */
    dmac_isr_flag &= ~(1<<hdma->init.channel_num);

    /* The selected Channelx EN bit is cleared (DMA is disabled and 
    all transfers are complete) */
    hdma->state = HAL_DMA_STATE_READY;

    /* Process unlocked */
    __HAL_UNLOCK(hdma);

	return HAL_OK;
}
/**
  * @brief  获取 the DMA 状态.
  *
  * @param  hdma: hdma DMAC句柄指针
  * @retval HAL state
  */
DMAC_StateTypeDef HAL_DMA_Getstate(DMAC_HandleTypeDef *hdma)
{
    return hdma->state;
}
/**
  * @brief DMA中断服务函数.
  *
  * @param [in] hdmac DMAC句柄指针
  * @return
  * - NONE
  * @note
  * @warning
  */
void HAL_DMAC_IRQHandler(DMAC_HandleTypeDef *hdma)
{
    /*dmac complete intrrupt*/
    if (_dmac_get_raw_interrupt_en(hdma->instance,hdma->init.channel_num))//dma channel raw intrrupt ie enable;
    {
        if (_dmac_get_raw_interrupt_status(hdma->instance,hdma->init.channel_num))
        {
            if (hdma->dma_raw_callback != NULL)
				hdma->dma_raw_callback();

			dmac_isr_flag |= (1<<hdma->init.channel_num);

			/*清除raw中断状态标志*/
			_dmac_clr_raw_interrupt_status(hdma->instance,hdma->init.channel_num);
        }
    }
	/*dmac block interrupt*/
    if (_dmac_get_block_interrupt_en(hdma->instance,hdma->init.channel_num))//dma channel raw intrrupt ie enable;
    {
        if (_dmac_get_block_interrupt_status(hdma->instance,hdma->init.channel_num))
        {
            if (hdma->dma_block_callback != NULL)
				hdma->dma_block_callback();

			dmac_isr_flag |= (0x10<<hdma->init.channel_num);

			/*清除block中断状态标志*/
			_dmac_clr_block_interrupt_status(hdma->instance,hdma->init.channel_num);
        }
    }
	/*dmac error interrupt*/
}

DMAC_StateTypeDef HAL_DMAC_ConfigLLi(DMAC_HandleTypeDef *hdma,DMAC_LLITypeDef* lli)
{
  DRV_DMAC_LliRegInit(hdma->instance,hdma->init.channel_num, lli);
}
