#include "bsp.h"
#include "sd_diskio.h"


#define SDIOC_SD_UINT										SDIOC_UNIT
#define SDIOC_SD_CLK 										(PWC_FCG1_SDIOC1)
/* Local pre-processor symbols/macros ('#define') */


/* Block size is 512 bytes */
#define SD_DEFAULT_BLOCK_SIZE (512U)
/* SD read/write timeout time */
#define SD_RW_TIMEOUT_TIME (30000UL)
/* Local variable definitions ('static') */

static volatile DSTATUS SdStat = (DSTATUS)STA_NOINIT;

/**
* @brief Get SD card insert status.
* @param None
* @retval An en_flag_status_t enumeration value:
* - Set: SD card inserted
* - Reset: No SD card insert
*/
//static en_flag_status_t SDCard_GetInsertStatus(void)
//{ 
//// en_flag_status_t enFlagSta = Set;
//// /* Check SD card detect pin */
//// if (0U != BSP_IO_ReadPortPin(EIO_PORT0, EIO_SDIC1_CD)) 
//// { 
//// enFlagSta = Reset;
//// } 
//// return enFlagSta;
//	return Set;
//} 

/**
* @brief SD card configuration.
* @param None
* @retval An en_result_t enumeration value:
* - Ok: Configuration success
* - Error: Configuration failed 
*/
static en_result_t SDCard_Config(void)
{ 
	return SdioInit();
}

/**
* @brief Get SD card state.
* @param None
* @retval An en_result_t enumeration value:
* - Ok: Data transfer is acting
* - Error: No data transfer is acting
*/
static en_result_t SDCard_GetCardTransState(void)
{ 
	en_result_t enRet;
	en_sd_card_state_t enCardState;
	
	enRet = SD_GetCardState(&stcSdhandle, &enCardState);
	
	if (Ok == enRet) { 
		if (SD_CARD_STAT_TRANS == enCardState) { 
			enRet = Ok;
		} 
	} 
	
	return enRet;
} 

/**
* @brief Check the SD card status.
* @param lun: Not used
* @retval DSTATUS: Operation status
*/
static DSTATUS SD_CheckStatus(BYTE lun)
{ 
	SdStat = (DSTATUS)STA_NOINIT;
	en_result_t enRet;
	
	enRet = SDCard_GetCardTransState();
	if (Ok == enRet) { 
		SdStat &= (DSTATUS)(~(DSTATUS)STA_NOINIT); 
	} 
	return SdStat;
} 

/**
* @brief Gets Disk Status
* @param lun: Not used
* @retval DSTATUS: Operation status
*/
DSTATUS SD_Status(BYTE lun)
{ 
	return SD_CheckStatus(lun);
} 

/**
* @brief Initializes a Drive
 * @param lun: Not used
* @retval DSTATUS: Operation status
*/
DSTATUS SD_Initialize(BYTE lun)
{ 
	SdStat = (DSTATUS)STA_NOINIT;
	if (Ok == SDCard_Config()) { 
		SdStat = SD_CheckStatus(lun);
	} 
	return SdStat;
} 

/**
* @brief Reads Sector(s)
* @param lun: Not used
* @param buff: Pointer to data buffer used to store read data
* @param sector: Sector address (LBA)
* @param count: Number of sectors to read (1..128)
* @retval DRESULT: Operation result
*/
DRESULT SD_Read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{ 
	DRESULT res = RES_ERROR;

	if (Ok == SDCARD_ReadBlocks(&stcSdhandle, (uint32_t)sector, (uint16_t)count, (uint8_t *)buff, SD_RW_TIMEOUT_TIME)) { 
		/* Wait until the read operation is finished */
		while (Ok != SDCard_GetCardTransState()){ 
		} 
		res = RES_OK;
	} 
	
	return res;
} 

/**
* @brief Writes Sector(s)
* @param lun: Not used
* @param buff: Pointer to data to be written
* @param sector: Sector address (LBA)
 * @param count: Number of sectors to write (1..128)
* @retval DRESULT: Operation result
*/
DRESULT SD_Write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{ 
	DRESULT res = RES_ERROR;
	if (Ok == SDCARD_WriteBlocks(&stcSdhandle, (uint32_t)sector, (uint16_t)count, (uint8_t *)buff, SD_RW_TIMEOUT_TIME)) { 
	/* Wait until the Write operation is finished */
		while (Ok != SDCard_GetCardTransState()) { 
		} 
		res = RES_OK;
	} 
	return res;
} 

/**
* @brief I/O control operation
* @param lun: Not used
* @param cmd: Control code
* @param buff: Pointer to buffer used to send/receive data
* @retval DRESULT: Operation result
*/
DRESULT SD_Ioctl(BYTE lun, BYTE cmd, void *buff)
{ 
	DRESULT res;
	//stc_sd_card_info_t stcCardInfo;
	if (0U != (SdStat & (DSTATUS)STA_NOINIT)) { 
		res = RES_NOTRDY;
	}
	else
	{ 
		switch (cmd) { 
		/* Make sure that no pending write process */
			case CTRL_SYNC :
				res = RES_OK;
				break;
			
			/* Get number of sectors on the disk (DWORD) */
			case GET_SECTOR_COUNT :
				SDCARD_GetCardCSD(&stcSdhandle);
				*(DWORD*)buff =stcSdhandle.stcSdCardInfo.u32LogBlockNbr;
				res = RES_OK;
				break;
			
			/* Get R/W sector size (WORD) */
			case GET_SECTOR_SIZE :
				SDCARD_GetCardCSD(&stcSdhandle);
				*(WORD*)buff = (uint16_t)stcSdhandle.stcSdCardInfo.u32LogBlockSize;
				res = RES_OK;
				break;
			
			/* Get erase block size in unit of sector (DWORD) */
			case GET_BLOCK_SIZE :
				SDCARD_GetCardCSD(&stcSdhandle);
				*(DWORD*)buff = stcSdhandle.stcSdCardInfo.u32LogBlockSize / SD_DEFAULT_BLOCK_SIZE;
				res = RES_OK;
				break;
			
			default:
				res = RES_PARERR;
				break;
		} 
	} 
	return res;
}
