/**
 * @file        board_sd.c
 *
 * @brief       SD card board driver
 *
 * @attention
 *
 *  Copyright (C) 2024 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 "board_sd.h"

/* Private includes *******************************************************/
#include "apm32f4xx_device_cfg.h"

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

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

/* Private variables ******************************************************/

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

/* External variables *****************************************************/
extern SD_HandleTypeDef hsd1;

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

/**
 * @brief  Initializes the SD card
 * 
 * @param  None
 * 
 * @retval None
 */
__weak uint8_t BOARD_SD_Init(void)
{
    /* Detect SD card plug status */
    if (BOARD_SD_IsDetected() != SD_PRESENT)
    {
        return SD_ERROR;
    }

    if(hsd1.State == DAL_SD_STATE_RESET)
    {
        if (DAL_SD_Init(&hsd1) == DAL_OK)
        {
            if (DAL_SD_ConfigWideBusOperation(&hsd1, SDIO_BUS_WIDE_4B) != DAL_OK)
            {
                return SD_ERROR;
            }
        }
        else
        {
            return SD_ERROR;
        }
    }

    return SD_OK;
}

/**
 * @brief   Writes block(s) to a specified address by polling mode in an SD card
 *
 * @param   buffer: Pointer to the data buffer
 *
 * @param   addr: Address from where data is to be written
 *
 * @param   blkNum: Number of blocks to write
 *
 * @param   timeout: Timeout for write operation
 *
 * @retval  SD status
 */
__weak uint8_t BOARD_SD_WriteBlocks(uint32_t *buffer, uint32_t addr, uint32_t blkNum, uint32_t timeout)
{
    if (DAL_SD_WriteBlocks(&hsd1, (uint8_t *)buffer, addr, blkNum, timeout) != DAL_OK)
    {
        return SD_ERROR;
    }
    else
    {
        return SD_OK;
    }
}

/**
 * @brief   Reads block(s) from a specified address by polling mode in an SD card
 *
 * @param   buffer: Pointer to the data buffer
 *
 * @param   addr: Address from where data is to be read
 *
 * @param   blkNum: Number of blocks to read
 *
 * @param   timeout: timeout for read operation
 *
 * @retval  SD status
 */
__weak uint8_t BOARD_SD_ReadBlocks(uint32_t *buffer, uint32_t addr, uint32_t blkNum, uint32_t timeout)
{
    if (DAL_SD_ReadBlocks(&hsd1, (uint8_t *)buffer, addr, blkNum, timeout) != DAL_OK)
    {
        return SD_ERROR;
    }
    else
    {
        return SD_OK;
    }
}

/**
 * @brief   Writes block(s) to a specified address by DMA mode in an SD card
 *
 * @param   buffer: Pointer to the data buffer
 *
 * @param   addr: Address from where data is to be written
 *
 * @param   blkNum: Number of SD blocks to write
 *
 * @retval  SD status
 */
__weak uint8_t BOARD_SD_WriteBlocks_DMA(uint32_t *buffer, uint32_t addr, uint32_t blkNum)
{ 
    if (DAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t *)buffer, addr, blkNum) != DAL_OK)
    {
        return SD_ERROR;
    }
    else
    {
        return SD_OK;
    }
}

/**
 * @brief   Reads block(s) from a specified address by DMA mode in an SD card
 *
 * @param   buffer: Pointer to the data buffer
 *
 * @param   addr: Address from where data is to be read
 *
 * @param   blkNum: Number of blocks to read
 *
 * @retval  SD status
 */
__weak uint8_t BOARD_SD_ReadBlocks_DMA(uint32_t *buffer, uint32_t addr, uint32_t blkNum)
{  
    if (DAL_SD_ReadBlocks_DMA(&hsd1, (uint8_t *)buffer, addr, blkNum) != DAL_OK)
    {
        return SD_ERROR;
    }
    else
    {
        return SD_OK;
    }
}

/**
 * @brief   Erases the specified memory area of the given SD card
 *
 * @param   startAddr: Start byte address
 *
 * @param   endAddr: End byte address
 *
 * @retval  SD status
 */
__weak uint8_t BOARD_SD_Erase(uint32_t startAddr, uint32_t endAddr)
{
    if (DAL_SD_Erase(&hsd1, startAddr, endAddr) != DAL_OK)
    {
        return SD_ERROR;
    }
    else
    {
        return SD_OK;
    }
}

/**
 * @brief   Reads the SD card data status
 *
 * @param   None
 *
 * @retval  Data transfer state
 */
__weak uint8_t BOARD_SD_ReadCardState(void)
{
    return((DAL_SD_GetCardState(&hsd1) == DAL_SD_CARD_TRANSFER ) ? \
            SD_XFER_OK : SD_XFER_BUSY);
}

/**
 * @brief  Read SD information about specific SD card
 *
 * @param  cardInfo: Pointer to DAL_SD_CardInfoTypedef structure
 *
 * @retval None
 */
__weak void BOARD_SD_ReadCardInfo(DAL_SD_CardInfoTypeDef *cardInfo)
{
    /* Read SD card information */
    DAL_SD_GetCardInfo(&hsd1, cardInfo);
}

/**
 * @brief   Detects if SD card is correctly plugged in the memory slot or not.
 *
 * @param   None
 *
 * @retval  SD status
 */
__weak uint8_t BOARD_SD_IsDetected(void)
{
    __IO uint8_t status = SD_PRESENT;

    return status;
}

/**
 * @brief   SD abort callback
 *
 * @param   None
 *
 * @retval  None
 */
__weak void BOARD_SD_AbortCallback(void)
{

}

/**
 * @brief   TX transfer completed callback
 *
 * @param   None
 *
 * @retval None
 */
__weak void BOARD_SD_WriteCpltCallback(void)
{

}

/**
 * @brief   Rx transfer completed callback
 *
 * @param   None
 *
 * @retval  None
 */
__weak void BOARD_SD_ReadCpltCallback(void)
{

}

/* Callback functions *****************************************************/

/**
 * @brief   SD abort callback
 *
 * @param   hsd: SD handle
 *
 * @retval  None
 */
void DAL_SD_AbortCallback(SD_HandleTypeDef *hsd)
{
    BOARD_SD_AbortCallback();
}

/**
 * @brief   TX transfer completed callback
 *
 * @param   hsd: SD handle
 *
 * @retval  None
 */
void DAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
    BOARD_SD_WriteCpltCallback();
}

/**
 * @brief   RX transfer completed callback
 *
 * @param   hsd: SD handle
 *
 * @retval  None
 */
void DAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
    BOARD_SD_ReadCpltCallback();
}
