/**
 * @file        apm32f4xx_dci_cfg.c
 *
 * @brief       This file provides configuration support for DCI
 *
 * @version     V1.0.0
 *
 * @date        2023-07-31
 *
 * @attention
 *
 *  Copyright (C) 2023 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
 *  and limitations under the License.
 */

/* Includes ***************************************************************/
#include "apm32f4xx_dci_cfg.h"

/* Private includes *******************************************************/

/* Private macro **********************************************************/

/* Private typedef ********************************************************/

/* Private variables ******************************************************/
DCI_HandleTypeDef hdci1;
DMA_HandleTypeDef hdma_dci1;

/* Private function prototypes ********************************************/

/* External variables *****************************************************/

/* External functions *****************************************************/

/**
 * @brief  Initializes the DCI MSP
 *
 * @param  hdci pointer to a DCI_HandleTypeDef structure that contains
 *                the configuration information for DCI
 *
 * @retval None
 */
void DAL_DCI_MspInit(DCI_HandleTypeDef* hdci)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    if(hdci->Instance == DCI)
    {
        /* Enable peripheral clock */
        __DAL_RCM_DCI_CLK_ENABLE();

        /* Enable peripheral GPIO clock */
        __DAL_RCM_GPIOA_CLK_ENABLE();
        __DAL_RCM_GPIOB_CLK_ENABLE();
        __DAL_RCM_GPIOC_CLK_ENABLE();
        __DAL_RCM_GPIOE_CLK_ENABLE();

        /* DCI pin configuration
           DCI HSYNC  ----> PA4
           DCI VSYNC  ----> PB7
           DCI PIXCLK ----> PA6
           DCI D0     ----> PC6
           DCI D1     ----> PC7
           DCI D2     ----> PC8
           DCI D3     ----> PC9
           DCI D4     ----> PE4
           DCI D5     ----> PB6
           DCI D6     ----> PE5
           DCI D7     ----> PE6
        */
        GPIO_InitStruct.Pin         = GPIO_PIN_4 | GPIO_PIN_6;
        GPIO_InitStruct.Mode        = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull        = GPIO_PULLUP;
        GPIO_InitStruct.Speed       = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate   = GPIO_AF13_DCI;
        DAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        GPIO_InitStruct.Pin         = GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_InitStruct.Mode        = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull        = GPIO_PULLUP;
        GPIO_InitStruct.Speed       = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate   = GPIO_AF13_DCI;
        DAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        GPIO_InitStruct.Pin         = GPIO_PIN_6 | GPIO_PIN_7 | \
                                      GPIO_PIN_8 | GPIO_PIN_9;
        GPIO_InitStruct.Mode        = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull        = GPIO_PULLUP;
        GPIO_InitStruct.Speed       = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate   = GPIO_AF13_DCI;
        DAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        GPIO_InitStruct.Pin         = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
        GPIO_InitStruct.Mode        = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull        = GPIO_PULLUP;
        GPIO_InitStruct.Speed       = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate   = GPIO_AF13_DCI;
        DAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

        /* DCI DMA init */
        hdma_dci1.Instance                  = DMA2_Stream1;
        hdma_dci1.Init.Channel              = DMA_CHANNEL_1;
        hdma_dci1.Init.Direction            = DMA_PERIPH_TO_MEMORY;
        hdma_dci1.Init.PeriphInc            = DMA_PINC_DISABLE;
        hdma_dci1.Init.MemInc               = DMA_MINC_ENABLE;
        hdma_dci1.Init.PeriphDataAlignment  = DMA_PDATAALIGN_WORD;
        hdma_dci1.Init.MemDataAlignment     = DMA_MDATAALIGN_WORD;
        hdma_dci1.Init.Mode                 = DMA_CIRCULAR;
        hdma_dci1.Init.Priority             = DMA_PRIORITY_HIGH;
        hdma_dci1.Init.FIFOMode             = DMA_FIFOMODE_ENABLE;
        hdma_dci1.Init.FIFOThreshold        = DMA_FIFO_THRESHOLD_FULL;
        hdma_dci1.Init.MemBurst             = DMA_MBURST_SINGLE;
        hdma_dci1.Init.PeriphBurst          = DMA_PBURST_SINGLE;
        if (DAL_DMA_Init(&hdma_dci1) != DAL_OK)
        {
            Error_Handler();
        }

        __DAL_LINKDMA(hdci,DMA_Handle,hdma_dci1);
    }
}

/**
 * @brief  DeInitializes the DCI MSP
 *
 * @param  hdci pointer to a DCI_HandleTypeDef structure that contains
 *                the configuration information for DCI
 *
 * @retval None
 */
void DAL_DCI_MspDeInit(DCI_HandleTypeDef* hdci)
{
    if(hdci->Instance == DCI)
    {
        /* Reset peripheral clock */
        __DAL_RCM_DCI_FORCE_RESET();
        __DAL_RCM_DCI_RELEASE_RESET();

        /* GPIO configuration */
        DAL_GPIO_DeInit(GPIOA, GPIO_PIN_4 | GPIO_PIN_6);
        DAL_GPIO_DeInit(GPIOB, GPIO_PIN_6 | GPIO_PIN_7);
        DAL_GPIO_DeInit(GPIOC, GPIO_PIN_6 | GPIO_PIN_7 | \
                               GPIO_PIN_8 | GPIO_PIN_9);
        DAL_GPIO_DeInit(GPIOE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6);

        /* Disable peripheral DMA */
        DAL_DMA_DeInit(hdci->DMA_Handle);

        /* Disable peripheral interrupt */
        DAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
    }
}

/**
 * @brief   DCI configuration
 *
 * @param   None
 *
 * @retval  Configure status
 */
DAL_StatusTypeDef DAL_DCI_Config(void)
{
    /* Configure the DCI */
    hdci1.Instance              = DCI;
    hdci1.Init.ExtendedDataMode = DCI_EXTEND_DATA_8B;
    hdci1.Init.SynchroMode      = DCI_SYNCHRO_HARDWARE;
    hdci1.Init.PCKPolarity      = DCI_PCKPOLARITY_RISING;
    hdci1.Init.VSPolarity       = DCI_VSPOLARITY_LOW;
    hdci1.Init.HSPolarity       = DCI_HSPOLARITY_LOW;
    hdci1.Init.CaptureRate      = DCI_CR_ALL_FRAME;
    hdci1.Init.JPEGMode         = DCI_JPEG_DISABLE;
    if (DAL_DCI_Init(&hdci1) != DAL_OK)
    {
        Error_Handler();
    }

    return DAL_OK;
}
