#include "h/p33FJ64GP802.h"
#include "h/common.h"
#include "h/sd.h"
#include "h/crc.h"
#include "h/spi.h"
#include "h/show.h"

int sendCommandSDCardSPI(BYTE cmd, BYTE response_type, BYTE* response, BYTE *argument)
{
	int i;
	int response_length;
	BYTE tmp;
	BYTE ibuffer[6];

	//setcursor_ezlcd(0,140);
	//writestring_ezlcd((BYTE*)"Sending: ");
	//writestring_ezlcd((BYTE*)"Sending: ");
#if (USE_DEBUG)
	sendStringUART((BYTE*)"CMD");
	disAUART(cmd);
	sendUART(0x0A);
	sendUART(0x0D);
#endif
	ibuffer[0]=((cmd & 0x3F) | 0x40);
	ibuffer[1]=argument[0];
	ibuffer[2]=argument[1];
	ibuffer[3]=argument[2];
	ibuffer[4]=argument[3];
	ibuffer[5]=CRC7(&ibuffer[0], 5);
	//for(i=0; i<6; i++)
	//{
	//	disafree(ibuffer[i]);
	//	writec_ezlcd('.');
	//}
	SDCS=0;
	/* All data is sent MSB first, and MSb first */
	/* Send the header/command */
	/* Format:
	cmd[7:6] : 01
	cmd[5:0] : command 
	*/
	for (i=0; i<=5; i++)
	{
	WriteSPI(ibuffer[i]);
	}
	response_length = 0;

	switch (response_type)
	{

		case R1:
		case R1B:
			response_length = 1;
		break;

		case R2:
			response_length = 2;
		break;

		case R3:
			response_length = 5;
		break;

		case R7:
			response_length = 5;
		break;

		case R1X18:
			response_length = 18;
		break;

		case R2X64:
			response_length = 67;
		break;
		
		default:
		break;
	}
	/* Wait for a response. A response can be recognized by the
	start bit (a zero) */

	for(i=0; i<response_length; i++)response[i]=0xFF;
	i=0;
	do
	{
	tmp = WriteSPI(0xFF);
	i++;
	}
	while (((tmp & 0x80) != 0) && (i < SDMMC_CMD_TIMEOUT));

	/* Just bail if we never got a response */
	if (i >= SDMMC_CMD_TIMEOUT)
	{
	SDCS=1;
	return 0;
	}

	if(response_type==R1X18)
	{
	// this type of response is for SPI Mode only and only for CMD9 and CMD10 that
	// send the CID and CSD registers back in a 16 byte + 2 byte packet
	// the 16 byte packet contains the register while the 2 byte suffix is the CRC16 field.
	// the first response is a R1 type, then we wait for the card to response by polling
	// bit 0.
	response[0]=tmp;
	i=0;
	do
	{
	tmp=WriteSPI(0xFF);
	i++;
	}
	while ((tmp & 1) && (i < SDMMC_CMD_TIMEOUT));
	tmp=WriteSPI(0xFF);
    for (i=1; i<=response_length; i++)
	{
	response[i] = tmp;
	/* This handles the trailing-byte requirement. */
	tmp = WriteSPI(0xFF);
	}
    }
	else
	if(response_type==R2X64)
	{
		// for the ACMD13 response which is R2+64 bytes long!
		response[0]=tmp;
		response[1]=WriteSPI(0xFF);
		i=0;
		do
		{
		tmp=WriteSPI(0xFF);
		i++;
		}
		while ((tmp & 1) && (i < SDMMC_CMD_TIMEOUT));
			tmp=WriteSPI(0xFF);
   			for (i=2; i<=response_length; i++)
			{
			response[i] = tmp;
			/* This handles the trailing-byte requirement. */
			tmp = WriteSPI(0xFF);
			}
	} 
	else
	{
	// for all other responses
	 for (i=0; i< response_length; i++)
	 {
	 response[i] = tmp;
	 /* This handles the trailing-byte requirement. */
	 tmp = WriteSPI(0xFF);
	 }
	}
	/* If the response is a "busy" type (R1B), then there's some
	* special handling that needs to be done. The card will
	* output a continuous stream of zeros, so the end of the BUSY
	* state is signaled by any nonzero response. The bus idles
	* high.
	*/
	i=0;
	if (response_type == R1B)
	{
	do	
	{
	i++;
	tmp = WriteSPI(0xFF);
	}
	/* This should never time out, unless SDI is grounded.
	* Don't bother forcing a timeout condition here. */
	while (tmp != 0xFF);
	WriteSPI(0xFF);
	}
	SDCS=1;

#if (USE_DEBUG)
	showBuffer(0, response, response_length);
#endif
	return 1;
}

unsigned long readSingleBlockSDCardSPI(CARD_INFO* thisCard, unsigned long blockaddr, unsigned long response_length, BYTE* data, BYTE* response)
{
	// returns the number of bytes read...
	unsigned long i;
	BYTE tmp;
	BYTE ibuffer[5];
	unsigned int CRCResult;
	unsigned int CRCReceived;
	BYTE* dataIn;
	int retries = 3;

	dataIn=data;
	do {
		ibuffer[1]=(blockaddr>>24);
		ibuffer[2]=(blockaddr>>16);
		ibuffer[3]=(blockaddr>>8);
		ibuffer[4]=blockaddr;
		sendCommandSDCardSPI(CMD17, CMD17_R, &ibuffer[0], &ibuffer[1]);
	} while( ibuffer[0] != 0 && retries-- );
	*response++=ibuffer[0];

	i=0;
	do {
		tmp=WriteSPI(0xFF);
		i++;
	} while ((tmp!=0xFE) && (i<SDMMC_READ_TIMEOUT));
	
	if(i>=SDMMC_READ_TIMEOUT)
	{
		i=response_length;
		while(i)
		{
		*data++=0xFF;
		i--;
		}
		*response++=0xFF;
		*response++=0xFF;
		*response++=0xFF;
		*response++=0xFF;
		return 0;
	}

	i=response_length;
	while(i)
	{
	tmp=WriteSPI(0xFF);
	*data++=tmp;
	i--;
	}
	tmp=WriteSPI(0xFF);
	CRCReceived=WriteSPI(0xFF);			// CRC16
	CRCReceived+=(tmp<<8);
	CRCResult=CRC16(dataIn, response_length);
	*response++=(CRCResult>>8);
	*response++=(CRCResult);
	*response++=(CRCReceived>>8);
	*response++=(CRCReceived);

	// the following "fixes" the 2Gb card problems since all 2Gb SD cards report 1024 block size instead of 512.
	if(thisCard->csd.READ_BL_LEN!=0x09)
	{
	ibuffer[1]=0;
	ibuffer[2]=0;
	ibuffer[3]=0;
	ibuffer[4]=0;
	sendCommandSDCardSPI(CMD12, CMD12_R, &ibuffer[0], &ibuffer[1]);
	}
	return response_length;
}

unsigned long readMultipleBlockSDCardSPI(CARD_INFO* thisCard, unsigned long blockaddr, unsigned long response_length, BYTE* data, BYTE* response, unsigned int numBlocks)
{
	// returns the number of bytes read...
	unsigned long i;
	BYTE tmp;
	BYTE ibuffer[5];
	unsigned long bytesRead;
	unsigned int CRCResult;
	unsigned int CRCReceived;
	unsigned int good, bad;
	BYTE* dataIn;
	int retries = 3;

	dataIn=data;
	do {
		ibuffer[1]=(blockaddr>>24);
		ibuffer[2]=(blockaddr>>16);
		ibuffer[3]=(blockaddr>>8);
		ibuffer[4]=blockaddr;
		sendCommandSDCardSPI(CMD18, CMD18_R, &ibuffer[0], &ibuffer[1]);
	} while( ibuffer[0] != 0 && retries-- );
	*response++=ibuffer[0];

	good=0;
	bad=0;
	bytesRead=0;
	while(numBlocks)
	{
	i=0;
	do
	{
	tmp=WriteSPI(0xFF);
	i++;
	}
	// 0xFE= start token
	while ((tmp!=0xFE) && (i<SDMMC_READ_TIMEOUT));
	
	if(i>=SDMMC_READ_TIMEOUT)
	{
		while(numBlocks)
		{
		 i=response_length;
		 while(i)
		 {
		 *data++=0xFF;
		 i--;
		 }
		numBlocks--;
		}
		*response++=0xFF;
		*response++=0xFF;
		*response++=0xFF;
		*response++=0xFF;
		return 0;
	}
		i=response_length;
		while(i)
		{
		tmp=WriteSPI(0xFF);
		*data++=tmp;
		i--;
		}
		tmp=WriteSPI(0xFF);
		CRCReceived=WriteSPI(0xFF);			// CRC16
		CRCReceived+=(tmp<<8);
		CRCResult=CRC16(dataIn, response_length);
		if(CRCResult==CRCReceived)good++; else bad++;
		dataIn+=response_length;
		numBlocks--;
		bytesRead+=response_length;
	}
	ibuffer[1]=0;
	ibuffer[2]=0;
	ibuffer[3]=0;
	ibuffer[4]=0;
	sendCommandSDCardSPI(CMD12, CMD12_R, &ibuffer[0], &ibuffer[1]);
	*response++=(good>>8);
	*response++=(good);
	*response++=(bad>>8);
	*response++=(bad);
	return (bytesRead);
}

unsigned long writeSingleBlockSDCardSPI(CARD_INFO* thisCard, unsigned long blockaddr, unsigned long response_length, BYTE* data, BYTE* response)
{
	// returns the number of bytes written
	unsigned long i;
	BYTE tmp;
	BYTE ibuffer[5];
	unsigned int CRCResult;
	int retries = 3;

	CRCResult=CRC16(data, response_length);
	do {
		ibuffer[1]=(blockaddr>>24);
		ibuffer[2]=(blockaddr>>16);
		ibuffer[3]=(blockaddr>>8);
		ibuffer[4]=blockaddr;
		sendCommandSDCardSPI(CMD24, CMD24_R, &ibuffer[0], &ibuffer[1]);
	} while( ibuffer[0] != 0 && retries-- );
	*response++=ibuffer[0];

	if((ibuffer[0] & 1)==0)
	{
	WriteSPI(0xFF);					// one byte gap!
	WriteSPI(0xFE);			// start token!
	i=response_length;
	while(i)
	{
	tmp=WriteSPI(*data);
	data++;
	i--;
	}
	WriteSPI(CRCResult>>8);
	WriteSPI(CRCResult);	// CRC16
	tmp=WriteSPI(0xFF);		// get data response token into tmp
	// the data response token has the following format:
	// bit 	7	6	5	4	3	2	1	0
	// 		X	X	X 	0	S2	S1	S0	1	where S2, S1, S0 = 	010 = Data Accepted
	//															101	= Data Rejected due to CRC error
	//															110 = Data Rejected due to a Write Error
	*response++=tmp;
	*response++=(CRCResult>>8);
	*response++=(CRCResult);
	i=0;
	do
	{
	tmp=WriteSPI(0xFF);				// initiate the writing... wait till the card is finished, ie not busy!
									// busy is a trailing 0 stream whereas not busy is a trailing 1 stream of bits
	i++;
	}
	while ((tmp==0) && (i<SDMMC_WRITE_TIMEOUT));
	WriteSPI(0xFF);
    if(i>=SDMMC_WRITE_TIMEOUT)
    {
    	return 0;
	}
	return response_length;
	} else
	return 0;
}

unsigned long writeMultipleBlockSDCardSPI(CARD_INFO* thisCard, unsigned long blockaddr, unsigned long response_length, BYTE* data, BYTE* response, unsigned int numBlocks)
{
	// returns the number of bytes written
	unsigned long i;
	unsigned long bytesWritten;
	unsigned int good, bad;
	BYTE tmp;
	BYTE ibuffer[5];
	unsigned int CRCResult;
	int retries = 3;

	do {
		ibuffer[1]=(blockaddr>>24);
		ibuffer[2]=(blockaddr>>16);
		ibuffer[3]=(blockaddr>>8);
		ibuffer[4]=blockaddr;
		sendCommandSDCardSPI(CMD25, CMD25_R, &ibuffer[0], &ibuffer[1]);
	} while( ibuffer[0] != 0 && retries-- );
	*response++=ibuffer[0];

	if((ibuffer[0] & 1)==0)
	{
		WriteSPI(0xFF);			// one byte gap!
		good=0;
		bad=0;
		bytesWritten=0;
		while(numBlocks)
		{
		WriteSPI(0xFF);
		WriteSPI(0xFC);			// START MULTIPLE BLOCK WRITE token!
		CRCResult=CRC16(data, response_length);
		i=response_length;
		while(i)
		{
		tmp=WriteSPI(*data);
		data++;
		i--;
		}
		WriteSPI(CRCResult>>8);
		WriteSPI(CRCResult);	// CRC16
		tmp=WriteSPI(0xFF);		// get data response token into tmp
		// the data response token has the following format:
		// bit 	7	6	5	4	3	2	1	0
		// 		X	X	X 	0	S2	S1	S0	1	where S2, S1, S0 = 	010 = Data Accepted
		//															101	= Data Rejected due to CRC error
		//															110 = Data Rejected due to a Write Error
		if((tmp & 0x0F)==0x05)good++; else bad++;
		i=0;
		do
		{
		tmp=WriteSPI(0xFF);				// initiate the writing... wait till the card is finished, ie not busy!
										// busy is a trailing 0 stream whereas not busy is a trailing 1 stream of bits
		i++;
		}
		while ((tmp==0) && (i<SDMMC_WRITE_TIMEOUT));
   		if(i>=SDMMC_WRITE_TIMEOUT)
   		{
    		return 0;
		}
		bytesWritten+=response_length;
		numBlocks--;
		}
		WriteSPI(0xFD);					// STOP TRANSFER TOKEN
		WriteSPI(0xFF);
		i=0;
		do
		{
		tmp=WriteSPI(0xFF);				// initiate the writing... wait till the card is finished, ie not busy!
										// busy is a trailing 0 stream whereas not busy is a trailing 1 stream of bits
		i++;
		}
		while ((tmp==0) && (i<SDMMC_WRITE_TIMEOUT));
		WriteSPI(0xFF);
   		if(i>=SDMMC_WRITE_TIMEOUT)
   		{
    		return 0;
		}
		*response++=(good>>8);
		*response++=(good);
		*response++=(bad>>8);
		*response++=(bad);
		return bytesWritten;
	} else
	return 0;
}

int getCIDRegister(CARD_INFO* thisCard)
{
	int i, j;

	for(i=0; i<16; i++)
	receiveBuffer[i]=0;
	sendCommandSDCardSPI(CMD10, CMD10_R, &receiveBuffer[0], &commandBuffer[0]);
	// now receiveBuffer[1]-receiveBuffer[16] contains the CID register 128 bits...
	if(thisCard->CARD_TYPE & 6)
	{
		// SD Cards
		thisCard->cid.MID=receiveBuffer[1];
		thisCard->cid.OID=(receiveBuffer[2]<<8) + receiveBuffer[3];
		thisCard->cid.PNM[0]=receiveBuffer[4];
		thisCard->cid.PNM[1]=receiveBuffer[5];
		thisCard->cid.PNM[2]=receiveBuffer[6];
		thisCard->cid.PNM[3]=receiveBuffer[7];
		thisCard->cid.PNM[4]=receiveBuffer[8];
		thisCard->cid.PNM[5]='\0';
		thisCard->cid.PRV=receiveBuffer[9];
		thisCard->cid.PSN[0]=receiveBuffer[10];
		thisCard->cid.PSN[1]=receiveBuffer[11];
		thisCard->cid.PSN[2]=receiveBuffer[12];
		thisCard->cid.PSN[3]=receiveBuffer[13];
		thisCard->cid.MDT=(receiveBuffer[14]<<8)+receiveBuffer[15];
	} else
	if(thisCard->CARD_TYPE==1)
	{
		// MMC
		thisCard->cid.MID=receiveBuffer[1];
		thisCard->cid.OID=(receiveBuffer[2]<<8) + receiveBuffer[3];
		thisCard->cid.PNM[0]=receiveBuffer[4];
		thisCard->cid.PNM[1]=receiveBuffer[5];
		thisCard->cid.PNM[2]=receiveBuffer[6];
		thisCard->cid.PNM[3]=receiveBuffer[7];
		thisCard->cid.PNM[4]=receiveBuffer[8];
		thisCard->cid.PNM[5]=receiveBuffer[9];
		thisCard->cid.PNM[6]='\0';

		thisCard->cid.PRV=receiveBuffer[10];
		thisCard->cid.PSN[0]=receiveBuffer[11];
		thisCard->cid.PSN[1]=receiveBuffer[12];
		thisCard->cid.PSN[2]=receiveBuffer[13];
		thisCard->cid.PSN[3]=receiveBuffer[14];
		// now MMC dates are in the form MM (high nibble: month) YY (low nibble: year offset from 1997)
		// so we convert to a SD card date that is YYM (YY: year offset from 2000, M: month nibble)
		i=receiveBuffer[15]>>4;			// i contains the month
		j=(receiveBuffer[15] & 0x0F)-3; // -3 to offset to 2000 instead...
		thisCard->cid.MDT=i + (j<<4);
	} else
	{
		// unknown!
		thisCard->cid.MID=0;
		thisCard->cid.OID=0;
		thisCard->cid.PNM[0]=0;
		thisCard->cid.PNM[1]=0;
		thisCard->cid.PNM[2]=0;
		thisCard->cid.PNM[3]=0;
		thisCard->cid.PNM[4]=0;
		thisCard->cid.PNM[5]='\0';
		thisCard->cid.PRV=0;
		thisCard->cid.PSN[0]=0;
		thisCard->cid.PSN[1]=0;
		thisCard->cid.PSN[2]=0;
		thisCard->cid.PSN[3]=0;
		thisCard->cid.MDT=0;
	}
	return 1;
}

int getCSDRegister(CARD_INFO* thisCard)
{
	// Now we read the CSD register
	int i, j;

	for(i=0; i<16; i++)
	receiveBuffer[i]=0;
	sendCommandSDCardSPI(CMD9, CMD9_R, &receiveBuffer[0], &commandBuffer[0]);
	// now receiveBuffer[1]-receiveBuffer[16] contains the CSD register 128 bits
	if((receiveBuffer[1] & 0xC0)==0)
	{
		// for Ver 1.0 SD or Ver 2. SD Card (<=2Gb) ie, not SDHC card
		// this shows a 00b in the first two bits (bit 7 and bit 6 of receiveBuffer[1]) of the CSD register
		thisCard->csd.TAAC=receiveBuffer[2];
		thisCard->csd.NSAC=receiveBuffer[3];
		thisCard->csd.TRAN_SPEED=receiveBuffer[4];
		thisCard->csd.CCC=(receiveBuffer[5]<<4)+(receiveBuffer[6]>>4);
		thisCard->csd.READ_BL_LEN= receiveBuffer[6] & 0x0F;
		thisCard->csd.C_SIZE=((receiveBuffer[7] & 0x03)<<10) + (receiveBuffer[8]<<2) + (receiveBuffer[9]>>6);
		thisCard->csd.C_SIZE_MULT=((receiveBuffer[10] & 0x03)<<1) + (receiveBuffer[11]>>7);
		thisCard->csd.SECTOR_SIZE=((receiveBuffer[11] & 0x3F)<<1) + (receiveBuffer[12]>>7);
		thisCard->csd.FILE_FORMAT=(receiveBuffer[15]);
		thisCard->csd.WRITE_BL_PARTIAL=((receiveBuffer[14] & 0x20)>>5);
		thisCard->csd.READ_BL_PARTIAL=((receiveBuffer[7] & 0x80)>>7);
		// now we compute the size in KB = 1024 bytes
		// for this version of the CSD register (ver 1.0) we compute the size in BYTES as follows:
		// size (BYTES) = (C_SIZE+1)* 2^(C_SIZE_MULT+2) * 2^(READ_BL_LEN)

		// since READ_BL_LEN>=9 and we add 2 then minus 10 for the KB!
		thisCard->SIZE=(1<<((thisCard->csd.READ_BL_LEN)+(thisCard->csd.C_SIZE_MULT)-8))*(thisCard->csd.C_SIZE+1);
	} else
	if((receiveBuffer[1] & 0xC0)==0x40)
	{
		// for Ver 2.0 SDHC Card shows a 01b in the first two bits of the CSD register
		thisCard->csd.WRITE_BL_PARTIAL=0;
		thisCard->csd.READ_BL_PARTIAL=0;

		thisCard->csd.TAAC=receiveBuffer[2];	
		thisCard->csd.NSAC=receiveBuffer[3];
		thisCard->csd.TRAN_SPEED=receiveBuffer[4];
		thisCard->csd.CCC=(receiveBuffer[5]<<4)+(receiveBuffer[6]>>4);
		thisCard->csd.READ_BL_LEN= receiveBuffer[6] & 0x0F;	
		thisCard->csd.C_SIZE= ((unsigned long)(receiveBuffer[8] & 0x3F)<<16)+(receiveBuffer[9]<<8)+receiveBuffer[10];
		thisCard->csd.C_SIZE_MULT=0x07;			// hard coded
		thisCard->csd.SECTOR_SIZE=((receiveBuffer[11] & 0x3F)<<1) + (receiveBuffer[12]>>7);
		thisCard->csd.FILE_FORMAT=(receiveBuffer[15]);

		// now we compute the size in KB = 1024 bytes
		// for this version of the CSD register (ver 2.0) we compute the size in BYTES as follows:
		// size (BYTES) = (C_SIZE+1) * 512 * 1024
		thisCard->SIZE=(thisCard->csd.C_SIZE + 1)*512;
	}
	else
	if((receiveBuffer[1] & 0xC0)==0x80)
	{	
		// MMC cards
		thisCard->csd.WRITE_BL_PARTIAL=0;
		thisCard->csd.READ_BL_PARTIAL=0;

		thisCard->csd.TAAC=receiveBuffer[2];	
		thisCard->csd.NSAC=receiveBuffer[3];
		thisCard->csd.TRAN_SPEED=receiveBuffer[4];
		thisCard->csd.CCC=(receiveBuffer[5]<<4)+(receiveBuffer[6]>>4);
		thisCard->csd.READ_BL_LEN= receiveBuffer[6] & 0x0F;	
		thisCard->csd.C_SIZE=((receiveBuffer[7] & 0x03)<<10) + (receiveBuffer[8]<<2) + (receiveBuffer[9]>>6);
		thisCard->csd.C_SIZE_MULT=((receiveBuffer[10] & 0x03)<<1) + (receiveBuffer[11]>>7);
		i=(receiveBuffer[11]>>2) & 0x1F;							// i represents the 5 bit structure ERASE_GRP_SIZE
		j=((receiveBuffer[11] & 0x03)<<3)+(receiveBuffer[12]>>5);	// j represents the 5 bit structure ERASE_GRP_MULT
		thisCard->csd.SECTOR_SIZE=(i+1)*(j+1);						// how it works out for MMC
		thisCard->csd.FILE_FORMAT=(receiveBuffer[15]);
		// now we compute the size in KB = 1024 bytes
		// for this version of the CSD register (MMC card) we compute the size in BYTES as follows:
		// size (BYTES) = (C_SIZE+1) * 2^(C_SIZE_MULT+2) * 2^(READ_BL_LEN)
		thisCard->SIZE=(1<<((thisCard->csd.READ_BL_LEN)+(thisCard->csd.C_SIZE_MULT)-8))*(thisCard->csd.C_SIZE+1); 
	} else
	{
		// unknown CSD 2 bit header = 11b (?!)
		thisCard->csd.WRITE_BL_PARTIAL=0;
		thisCard->csd.READ_BL_PARTIAL=0;

		thisCard->csd.TAAC=0;	
		thisCard->csd.NSAC=0;
		thisCard->csd.TRAN_SPEED=0;
		thisCard->csd.CCC=0;
		thisCard->csd.READ_BL_LEN=0;	
		thisCard->csd.C_SIZE=0;
		thisCard->csd.C_SIZE_MULT=0;
		thisCard->csd.SECTOR_SIZE=0;
		thisCard->csd.FILE_FORMAT=0;
		thisCard->SIZE=0;
	}
	return 1;
}

int getCIDCSDRegisters(CARD_INFO* thisCard)
{
	getCIDRegister(thisCard);
	getCSDRegister(thisCard);
	return 1;
}

int InitSDMMCCardSPI(CARD_INFO* thisCard)
{
	int i;
	BYTE response;

	//setcursor_ezlcd(0, 0);
	//writestring_ezlcd((BYTE*)"Initialising SD Card v.2");
	InitSPI(0x00);
	SDCS=0;
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	SDCS=1;
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	WriteSPIWithoutSS(0xFF);
	commandBuffer[0]=0;
	commandBuffer[1]=0;
	commandBuffer[2]=0;
	commandBuffer[3]=0;
	sendCommandSDCardSPI(CMD0, CMD0_R, &receiveBuffer[0], &commandBuffer[0]);
	//showReceiveBuffer(10, 1);
	delayMs(200);
	commandBuffer[0]=0x00;
	commandBuffer[1]=0x00;
	commandBuffer[2]=0x01;	// [11:8]=VHS   0001b = 2.7 - 3.6V voltage range from Host
	commandBuffer[3]=0xAA;	// check Pattern
	sendCommandSDCardSPI(CMD8, CMD8_R, &receiveBuffer[0], &commandBuffer[0]);
	//setcursor_ezlcd(0, 30);
	//writestring_ezlcd((BYTE*)"Sent CMD8.");
	//showReceiveBuffer(40, 5);
	if(receiveBuffer[0] & 4)
	{
		thisCard->CARD_TYPE=2;			// assume SD v1 first
		// Now Follow Version 1 branch of initialisation procedure
		//setcursor_ezlcd(0, 50);
		//writestring_ezlcd((BYTE*)"Reading OCR.");
		commandBuffer[0]=0;
		commandBuffer[1]=0;
		commandBuffer[2]=0;
		commandBuffer[3]=0;
		// read OCR command CMD58 (while not mandatory, it is recommended to do this)
		sendCommandSDCardSPI(CMD58, CMD58_R, &receiveBuffer[0], &commandBuffer[0]);
		thisCard->ocr.OCR[0]=receiveBuffer[1];
		thisCard->ocr.OCR[1]=receiveBuffer[2];
		thisCard->ocr.OCR[2]=receiveBuffer[3];
		thisCard->ocr.OCR[3]=receiveBuffer[4];
		//showReceiveBuffer(60,5);
		if(receiveBuffer[0] & 4)
		{	
			// illegal command response, so it is not an SD or MMC Card!
			thisCard->CARD_TYPE=0;
			thisCard->ERROR=ERROR_NOT_SDMMC_CARD;
			// abort!
			return 0;
		}
		//setcursor_ezlcd(0, 70);
		//writestring_ezlcd((BYTE*)"Checking 3.3V Operation");
		if(thisCard->ocr.OCR[1] & 0x10)thisCard->VOLTAGE_RANGE=1;
		else
		{
			// this card does not support the 3.3V voltage range
			thisCard->VOLTAGE_RANGE=0;
			thisCard->ERROR=ERROR_BAD_VOLTAGE_RANGE;
			// abort!
			return 0;
		}
	
		i=0;
		do
		{
		sendCommandSDCardSPI(CMD55,  CMD55_R,  &receiveBuffer[0], &commandBuffer[0]);
		commandBuffer[0]=0;
		commandBuffer[1]=0;
		commandBuffer[2]=0;
		commandBuffer[3]=0;
		sendCommandSDCardSPI(ACMD41, ACMD41_R, &receiveBuffer[0], &commandBuffer[0]);
		if(receiveBuffer[0] & 4)thisCard->CARD_TYPE=0;
		//delayMs(5);
		i++;
		} while ((receiveBuffer[0] & 1) && (i<SDMMC_IDLE_WAIT_MAX));

		if(i>=SDMMC_IDLE_WAIT_MAX)
		{
			// MMC cards should end up here!
			thisCard->CARD_TYPE=1;			// MMC
			//setcursor_ezlcd(0, 80);
			//writestring_ezlcd((BYTE*)"Not an SD Card. Sending CMD1");
			i=0;
			do
			{
			commandBuffer[0]=0x00;
			commandBuffer[1]=0x00;
			commandBuffer[2]=0x00;
			commandBuffer[3]=0x00;
			sendCommandSDCardSPI(CMD1, CMD1_R, &receiveBuffer[0], &commandBuffer[0]);
			//showReceiveBuffer(90, 1);
			delayMs(5);
			i++;
			} while((receiveBuffer[0] & 1) && (i<SDMMC_IDLE_WAIT_MAX));
			
			if(i>=SDMMC_IDLE_WAIT_MAX)
			{
				// initialization timed out!
				thisCard->VOLTAGE_RANGE=0;	
				thisCard->ERROR=ERROR_NOT_SDMMC_CARD;
				return 0;
			}
		
			//setcursor_ezlcd(0, 100);
			//writestring_ezlcd((BYTE*)"Reading OCR.");
			commandBuffer[0]=0;
			commandBuffer[1]=0;
			commandBuffer[2]=0;
			commandBuffer[3]=0;
			// read OCR command CMD58 (while not mandatory, it is recommended to do this)
			sendCommandSDCardSPI(CMD58, CMD58_R, &receiveBuffer[0], &commandBuffer[0]);
			thisCard->ocr.OCR[0]=receiveBuffer[1];
			thisCard->ocr.OCR[1]=receiveBuffer[2];
			thisCard->ocr.OCR[2]=receiveBuffer[3];
			thisCard->ocr.OCR[3]=receiveBuffer[4];
			//showReceiveBuffer(110,5);
			if(thisCard->ocr.OCR[1] & 0x10)thisCard->VOLTAGE_RANGE=1;
			else
			{
			// this card does not support the 3.3V voltage range
			thisCard->VOLTAGE_RANGE=0;
			thisCard->ERROR=ERROR_BAD_VOLTAGE_RANGE;
			// abort!
			return 0;
			}
			getCIDCSDRegisters(thisCard);
			thisCard->ERROR=ERROR_ALL_OK;
			InitSPI(SPI_SPEED);
			// abort!
			return 1;			
		}

		getCIDCSDRegisters(thisCard);
		thisCard->ERROR=ERROR_ALL_OK;
		InitSPI(SPI_SPEED);
		return 1;
	} else
	if(receiveBuffer[0]==0x01)
	{
		thisCard->CARD_TYPE=4;				// SD v 2
		thisCard->VOLTAGE_RANGE=1;
		if(receiveBuffer[3]!=0x01)
		{
			// no echo back from CMD8 so voltage range is not compatible!
			thisCard->VOLTAGE_RANGE=0;
			thisCard->ERROR=ERROR_BAD_VOLTAGE_RANGE;
			// abort!
			return 0;
		}
		
		//setcursor_ezlcd(0, 50);
		//writestring_ezlcd((BYTE*)"Reading OCR.");
		commandBuffer[0]=0;
		commandBuffer[1]=0;
		commandBuffer[2]=0;
		commandBuffer[3]=0;
		// read OCR command CMD58 (while not mandatory, it is recommended to do this)
		sendCommandSDCardSPI(CMD58, CMD58_R, &receiveBuffer[0], &commandBuffer[0]);
		thisCard->ocr.OCR[0]=receiveBuffer[1];
		thisCard->ocr.OCR[1]=receiveBuffer[2];
		thisCard->ocr.OCR[2]=receiveBuffer[3];
		thisCard->ocr.OCR[3]=receiveBuffer[4];

		//showReceiveBuffer(60,5);
		if(receiveBuffer[0] & 4)
		{	
			// illegal command response, so it is not an SD Card!
			thisCard->ERROR=ERROR_NOT_SDMMC_CARD;
			// abort!
			return 0;
		}
		//setcursor_ezlcd(0, 70);
		//writestring_ezlcd((BYTE*)"Checking 3.3V Operation: ");
		if(thisCard->ocr.OCR[1] & 0x10)thisCard->VOLTAGE_RANGE=1;
		else
		{
			// this card does not support the 3.3V voltage range
			thisCard->VOLTAGE_RANGE=0;
			thisCard->ERROR=ERROR_BAD_VOLTAGE_RANGE;
			// abort!
			return 0;
		}
		i=0;
		do
		{
		sendCommandSDCardSPI(CMD55,  CMD55_R,  &receiveBuffer[0], &commandBuffer[0]);
		response=receiveBuffer[0];
		commandBuffer[0]=0x40;			// HCS (bit 30)=1 if host supports High Capacity >2Gb - 32Gb
		commandBuffer[1]=0x0;
		commandBuffer[2]=0x0;
		commandBuffer[3]=0x0;
		sendCommandSDCardSPI(ACMD41, ACMD41_R, &receiveBuffer[0], &commandBuffer[0]);
		response=receiveBuffer[0];
		//setcursor_ezlcd(0, 80);
		//writestring_ezlcd((BYTE*)"Reading OCR (CCS).");
		commandBuffer[0]=0;
		commandBuffer[1]=0;
		commandBuffer[2]=0;
		commandBuffer[3]=0;
		sendCommandSDCardSPI(CMD58, CMD58_R, &receiveBuffer[0], &commandBuffer[0]);
		thisCard->ocr.OCR[0]=receiveBuffer[1];
		thisCard->ocr.OCR[1]=receiveBuffer[2];
		thisCard->ocr.OCR[2]=receiveBuffer[3];
		thisCard->ocr.OCR[3]=receiveBuffer[4];
		//showReceiveBuffer(90, 5);
		if(receiveBuffer[0] & 4)thisCard->CARD_TYPE=0;
		//delayMs(5);
		i++;
		} while ((response & 1) && (i<SDMMC_IDLE_WAIT_MAX));

		if(i>=SDMMC_IDLE_WAIT_MAX)
		{
			thisCard->ERROR=ERROR_SDMMC_CARD_TIMEOUT;
			// abort!
			return 0;			
		}
		if(thisCard->ocr.OCR[0] & 0x40)thisCard->CARD_TYPE=6;			// this is a High Capacity SD Card! ie. CCS (bit 30 of OCR) = 1
		getCIDCSDRegisters(thisCard);
		thisCard->ERROR=ERROR_ALL_OK;
		InitSPI(SPI_SPEED);
		return 1;
	}
	return 0;
}

