#include "sd_mmc.h"
#include "sd_mmc_intf.h"
#include <assert.h>

static bool sd_mmc_check_cd(void)
{
	switch(SD_MMC_CD_MODE)
	{
		case SD_MMC_CD_MODE_UNUSED:
		{
			// Always assume the card is detected since we aren't using this function
			return true;
		}break;
		case SD_MMC_CD_MODE_SYNC:
		{
			return SD_MMC_INTF_CHECK_CD();
		}break;
		case SD_MMC_CD_MODE_ASYNC:
		{
			// Unimplemented
			return false;
		}break;
		default:
		{
			return false;
		}
	}
	return false;
}

// send 80 clock cycles
static void sd_mmc_send_clock()
{
	uint8_t i;
	uint8_t dummy = 0xFF;
	for(i = 0; i < 10; i++)
	{
		SD_MMC_INTF_WRITE(&dummy, 1);
	}
}

sd_mmc_err_t sd_mmc_init(void)
{
	sd_mmc_err_t ret = SD_MMC_SUCCESS;

	do
	{
		if(0 != SD_MMC_INTF_INIT())
		{
			ret = SD_MMC_INIT_FAILURE;
			break;
		}
		// power up sequence
		delay_ms(1);
		sd_mmc_send_clock();
		// go idle
		sd_mmc_select(0, 0, 0, true);
		if(0 != sd_mmc_send_command(CMD0, CMD0_ARG, CMD0_CRC))
		{
			ret = SD_MMC_ERR_COMM;
			break;
		}

		uint8_t res1_ret = 0xFF;
		if(0 != sd_mmc_read_res1(&res1_ret))
		{
			ret = SD_MMC_ERR_COMM;
			break;
		}
		sd_mmc_deselect(0);

		

		printf("res1: 0x%02x\n", res1_ret);
	}while(0);
	return ret;
}

sd_mmc_err_t sd_mmc_deselect(uint8_t slot)
{
	UNUSED(slot);
	sd_mmc_err_t ret = SD_MMC_SUCCESS;
	SD_MMC_INTF_DESELECT_DEVICE();
	return ret;
}
sd_mmc_err_t sd_mmc_select(uint8_t slot, uint32_t clock, uint8_t bus_width, bool high_speed)
{
	UNUSED(slot);
	UNUSED(clock);
	UNUSED(bus_width);
	UNUSED(high_speed);
	sd_mmc_err_t ret = SD_MMC_SUCCESS;
	SD_MMC_INTF_SELECT_DEVICE();
	return ret;

}

sd_mmc_err_t sd_mmc_send_command(uint8_t cmd, uint32_t arg, uint8_t crc)
{
	sd_mmc_err_t ret = SD_MMC_SUCCESS;
	uint8_t bytes[6];
	bytes[0] = cmd | 0x40;
	bytes[1] = ((uint8_t)(arg >> 24));
	bytes[2] = ((uint8_t)(arg >> 16));
	bytes[3] = ((uint8_t)(arg >> 8));
	bytes[4] = ((uint8_t)(arg));
	bytes[5] = crc | 0x01;
	if(6 != SD_MMC_INTF_WRITE(bytes, 6))
	{
		ret = SD_MMC_ERR_COMM;
	}
	return ret;
}


sd_mmc_err_t sd_mmc_read_res1(uint8_t* ret_byte)
{
	sd_mmc_err_t ret = SD_MMC_SUCCESS;

	uint8_t i = 0;
	do
	{
		i++;
		SD_MMC_INTF_READ(ret_byte, 1);
	}while(i <= 8 && *ret_byte == 0xFF);
	if(*ret_byte == 0xFF)
	{
		return SD_MMC_TIMEOUT;
	}
	return ret;
}
