/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2007        */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/

#include "h/diskio.h"
#include "h/sd.h"
#include "h/ir.h"
#include "h/clock.h"

BYTE 		commandBuffer[6];
BYTE 		receiveBuffer[80];
CARD_INFO	cardInfo;
DSTATUS 	Stat;		

/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
DWORD get_fattime(void)
{
	// returns the following 32 bit DWORD
	//
	//	bits 31:25: (7 bits) year from 1980 (0-127)
	//	bits 24:21: (4 bits) month (1-12)
	//  bits 20:16: (5 bits) day (1-31)
	//	bits 15:11: (5 bits) hour (0-23)
	//  bits 10:5:  (6 bits) minutes (0-59)
	//  bits 4:0 :  (5 bits) seconds/2 (0-29)
	//
	TIMET time;
	unsigned long result;

	time=getTime();
	result=(unsigned long)((time.year+2000)-1980)<<25;
	result+=((unsigned long)time.month<<21);
	result+=((unsigned long)time.day<<16);
	result+=((unsigned long)time.hours<<11);
	result+=((unsigned long)time.minutes<<5);
	result+=((unsigned long)time.seconds>>1);
	return result;
}

/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive                                                 */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (BYTE drv)
{
	int i;
	BYTE ibuffer[5];

	Stat=STA_NOINIT;
	i=InitSDMMCCardSPI(&cardInfo);
	if(i) 
	{								/* Initialization succeded */
		Stat &= ~STA_NOINIT;		/* Clear STA_NOINIT */
		ibuffer[1]=0x00;
		ibuffer[2]=0x00;
		ibuffer[3]=0x02;
		ibuffer[4]=0x00;				// set BLOCK size to 512 bytes also known as SECTOR size in FAT Context
		sendCommandSDCardSPI(CMD16, CMD16_R, &ibuffer[0], &ibuffer[1]);
	}
	return Stat;
}

/*-----------------------------------------------------------------------*/
/* Get Disk Status                                                       */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (BYTE drv)
{
	if (drv) return STA_NOINIT;		/* Supports only single drive */
	return Stat;
}

/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE drv,			/* Physical drive number (from 0) */
	BYTE *buff,			/* Pointer to the data buffer to store read data */
	DWORD sector,		/* Start sector number (LBA) */
	BYTE count			/* Sector count (1..255) */
)
{
	BYTE ibuffer[6];
	unsigned long n;


	if (drv || !count) return RES_PARERR;
	if (Stat & STA_NOINIT) return RES_NOTRDY;
	
	if ((cardInfo.CARD_TYPE & 6)!=6)sector *=512;	/* Convert to byte address if needed. Not done for SDHC Cards! (added by M.G.) */
	if (count == 1)
	{	
		/* Single block read */
	#if(USE_DEBUG)
		sendStringUART((BYTE*)"Read Sector: ");
		disIntUART(sector);
		sendUART(0x0A);
		sendUART(0x0D);
	#endif
		n=readSingleBlockSDCardSPI(&cardInfo, sector, 512, (BYTE*)buff, &ibuffer[0]);
	#if (USE_DEBUG)
		showBuffer(0, buff, 512);
	#endif

	}
	else 
	{				
		/* Multiple block read */
	#if(USE_DEBUG)
		sendStringUART((BYTE*)"Read Multiple Sector: ");
		disIntUART(sector);
		sendUART(0x0A);
		sendUART(0x0D);
	#endif
		n=readMultipleBlockSDCardSPI(&cardInfo, sector, 512, (BYTE*)buff, &ibuffer[0], count);
	#if (USE_DEBUG)
		showBuffer(0, buff, 512);
	#endif
		if(((ibuffer[1]<<8)+ibuffer[2])!=count)return RES_ERROR;	// CRC errors
	}
	if(n==0)return RES_ERROR; else return RES_OK;
}

/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if _READONLY == 0
DRESULT disk_write (
	BYTE drv,			/* Physical drive nmuber (0) */
	const BYTE *buff,	/* Pointer to the data to be written */
	DWORD sector,		/* Start sector number (LBA) */
	BYTE count			/* Sector count (1..255) */
)
{
	BYTE ibuffer[6];
	unsigned long n;

	if (drv || !count) return RES_PARERR;
	if (Stat & STA_NOINIT) return RES_NOTRDY;
	if (Stat & STA_PROTECT) return RES_WRPRT;

	if ((cardInfo.CARD_TYPE & 6)!=6)sector *= 512;	/* Convert to byte address if needed. Not done for SDHC Cards! (added by M.G.) */

	if (count == 1)
	{	
		/* Single block write */
		n=writeSingleBlockSDCardSPI(&cardInfo, sector, 512, (BYTE*)buff, &ibuffer[0]);
	}
	else 
	{	
		/* Multiple block write */
		n=writeMultipleBlockSDCardSPI(&cardInfo, sector, 512, (BYTE*)buff, &ibuffer[0], count);
		if(((ibuffer[1]<<8)+ibuffer[2])!=count)return RES_ERROR;		// CRC errors
	}
	if(n==0)return RES_ERROR; else return RES_OK;
}
#endif /* _READONLY */

/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE drv,		/* Physical drive nmuber (0) */
	BYTE ctrl,		/* Control code */
	void *buff		/* Buffer to send/receive data block */
)
{
	DRESULT res;
	int i;
	BYTE ibuffer[17];

	if (drv) return RES_PARERR;
	if (Stat & STA_NOINIT) return RES_NOTRDY;
	res = RES_ERROR;
	switch (ctrl) {

		case CTRL_SYNC :		/* Flush dirty buffer if present */
				res = RES_OK;
			break;

		case GET_SECTOR_COUNT :	/* Get number of sectors on the disk (WORD) */
//			if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
//				if ((csd[0] >> 6) == 1) {	/* SDC ver 2.00 */
//					csize = csd[9] + ((WORD)csd[8] << 8) + 1;
//					*(DWORD*)buff = (DWORD)csize << 10;
//				} else {					/* MMC or SDC ver 1.XX */
//					n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
//					csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
//					*(DWORD*)buff = (DWORD)csize << (n - 9);
//				}
//				res = RES_OK;
//			}
			*(DWORD*)buff=(cardInfo.SIZE>>9);
			res = RES_OK;
			break;

		case GET_SECTOR_SIZE :	/* Get sectors on the disk (WORD) */
			*(WORD*)buff = 512;
			res = RES_OK;
			break;

		case GET_BLOCK_SIZE :	/* Get erase block size in unit of sectors (DWORD) */
			*(DWORD*)buff= 1UL << cardInfo.csd.READ_BL_LEN;
			res = RES_OK;
			break;
//			if (CardType & CT_SD2) {	/* SDC ver 2.00 */
//				sendCommandSDCardSPI(CMD55, CMD55_R, &ibuffer[0], &ibuffer[0]);
//				sendCommandSDCardSPI(ACMD13, ACMD13_R, &ibuffer[0], &ibuffer[0]);
//					rcvr_spi();
//					if (rcvr_datablock(csd, 16)) {				/* Read partial block */
//						for (n = 64 - 16; n; n--) rcvr_spi();	/* Purge trailing data */
//						*(DWORD*)buff = 16UL << (csd[10] >> 4);
//						res = RES_OK;
//					}
//				}
//			} else {					/* SDC ver 1.XX or MMC */
//				if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {	/* Read CSD */
//					if (CardType & CT_SD1) {		/* SDC ver 1.XX */
//						*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
//					} else {					/* MMC */
//						*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
//					}
//					res = RES_OK;
//				}
//			}

		case MMC_GET_TYPE :		/* Get card type flags (1 byte) */
			*(BYTE*)buff= cardInfo.CARD_TYPE;
			res = RES_OK;
			break;

		case MMC_GET_CSD :	/* Receive CSD as a data block (16 bytes) */
			if(sendCommandSDCardSPI(CMD9, CMD9_R, &ibuffer[0], &ibuffer[0]))
			{
			 for(i=0; i<16; i++)
			 {
				*(BYTE*)buff++=ibuffer[1+i];
			 }			
			 res= RES_OK;
			}
			break;

		case MMC_GET_CID :	/* Receive CID as a data block (16 bytes) */
			if(sendCommandSDCardSPI(CMD10, CMD10_R, &ibuffer[0], &ibuffer[0]))
			{
			 for(i=0; i<16; i++)
			 {
		 		*(BYTE*)buff++=ibuffer[1+i];
		  	 }
			 res= RES_OK;
			}
			break;

		case MMC_GET_OCR :	/* Receive OCR as an R3 resp (4 bytes) */
			for(i=0; i<4; i++)
			{
				*(BYTE*)buff++=cardInfo.ocr.OCR[i];
			}
			res = RES_OK;
			break;

		case MMC_GET_SDSTAT :	/* Receive SD statsu as a data block (64 bytes) */
//			if (send_cmd(ACMD13, 0) == 0) {	/* SD_STATUS */
//				rcvr_spi();
//				if (rcvr_datablock(buff, 64))
//					res = RES_OK;
//			}

			res = RES_OK;
			break;

		default:
			res = RES_PARERR;
			break;
	}
	return res;
}




