#include "spi_mmc.h"
#include <p18f24k50.h>
// PORTB,0 sdi
// PORTB,1 clk
// PORTB,3 sdo
// PORTB,4 chip_enable select= 0 
// PORTB,5 sd kártya foglalatban/üres  
#define sel	{_asm  bcf LATB ,4,0  _endasm}
#define nsel {_asm bsf LATB ,4,0 _endasm}

//buffer foglalása

#pragma udata buff1				//linker fájl módosítva.
unsigned char buf1[512];	//SD kártya puffere
#pragma udata

#pragma udata buff
unsigned char buf2[512];	//2. puffer
#pragma udata

extern UINT8 *b0;
extern UINT8 *b1;

UINT8 MMCStatus, MMCCmd[6];

void SPI_Init( void )
{
	PORTA =0;
	ANSELA	&= 0b11111100;
	ANSELB	&= 0b11000000;
	TRISA	&= 0b11111100;
	TRISB	&= 0b11100101;
	nsel;
	SSP1CON1 = 0x30, //ckp=1
	SSP1STAT =0;
	SPI_ReceiveByte();
	
}
//******************************************
BYTE SPI_ReceiveByte()
{
	SSP1STATbits.BF=0;
	SSP1BUF=255;
	while (!SSP1STATbits.BF){};
	return SSP1BUF;	
}
//*******************************************
void SPI_Receive( BYTE *buf, DWORD Length )
{
	DWORD i;
	for ( i = 0; i < Length; i++ )
	{
		*buf = SPI_ReceiveByte();
		buf++;
	}
	return;
}
//********************************************
void SPI_Send( BYTE *buf, DWORD Length )
{
	BYTE Dummy;
	if ( Length == 0 )
	return;
	while ( Length != 0 )
	{
		SSP1STATbits.BF=0;
		SSP1BUF = *buf;
		while (!SSP1STATbits.BF){};
		Dummy = SSP1BUF; /* Flush the RxFIFO */
		Length--;
		buf++;
	}
return;	
}
//*********************************************
UINT8 mmc_init()
{
	UINT8 i,*mut;
	mut=b1;
	nsel;
	for(i=0; i<10; i++)
	{
		*mut = 0xFF;mut++;
	}
	SPI_Send( b1, 10 );
	sel;
	MMCCmd[0] = 0x40;
	MMCCmd[1] = 0x00;
	MMCCmd[2] = 0x00;
	MMCCmd[3] = 0x00;
	MMCCmd[4] = 0x00;
	MMCCmd[5] = 0x95;
	SPI_Send( MMCCmd, 6 );
	if( mmc_response(0x01) == 1 )
	{
		MMCStatus = IDLE_STATE_TIMEOUT;
		nsel; /* set SPI SSEL */
		return MMCStatus;
	}
	nsel; 
	SPI_ReceiveByte();
	sel;
	i = 0xff;
do
{
	/* send mmc CMD1(SEND_OP_COND) to bring out of idle state */
	/* all the arguments are 0x00 for command one */
	MMCCmd[0] = 0x41;
	MMCCmd[1] = 0x00;
	MMCCmd[2] = 0x00;
	MMCCmd[3] = 0x00;
	MMCCmd[4] = 0x00;
	/* checksum is no longer required but we always send 0xFF */
	MMCCmd[5] = 0xFF;
	SPI_Send( MMCCmd,6 );
	i--;
	} while ( (mmc_response(0x00) != 0) && (i>0) );
/* timeout waiting for 0x00 from the MMC */
	if ( i == 0 )
	{
		MMCStatus = OP_COND_TIMEOUT;
		nsel; /* set SPI SSEL */
		return MMCStatus;
	}
	/**/
	nsel; /* set SPI SSEL */
	SPI_ReceiveByte();
	sel; /* clear SPI SSEL */
/* send MMC CMD16(SET_BLOCKLEN) to set the block length */
	MMCCmd[0] = 0x50;
	MMCCmd[1] = 0x00; /* 4 bytes from here is the block length */
/* LSB is first */
/* 00 00 00 10 set to 16 bytes */
/* 00 00 02 00 set to 512 bytes */
	MMCCmd[2] = 0x00;
/* high block length bits - 512 bytes */
	MMCCmd[3] = 0x02;
/* low block length bits */
	MMCCmd[4] = 0x00;
/* checksum is no longer required but we always send 0xFF */
	MMCCmd[5] = 0xFF;
	SPI_Send( MMCCmd,6 );
	if( (mmc_response(0x00))==1 )
	{
		MMCStatus = SET_BLOCKLEN_TIMEOUT;
		nsel; /* set SPI SSEL */
		return MMCStatus;
	}
	nsel; /* set SPI SSEL */
	SPI_ReceiveByte();
	return 0;		
}
/*****************************************************/
UINT8 mmc_write_block(DWORD block_number)
{
	UINT8 status;
	UINT32_VAL val;	
	val.Val=block_number+135;	//135 a rejtett blokkok száma
	// 2gb SD kártyánál
	val.Val = val.Val<<1;;	
	sel;
	MMCCmd[0] = 0x58;
	MMCCmd[1] = val.byte.UB;
	MMCCmd[2] = val.byte.HB;
	MMCCmd[3] = val.byte.LB;	
	MMCCmd[4] =	0;
	MMCCmd[5] = 0xff;
	SPI_Send(MMCCmd,6 );
	if((mmc_response(0x00))==1)
	{
		MMCStatus = WRITE_BLOCK_TIMEOUT;
		nsel; /* set SPI SSEL */
		return MMCStatus;
	}
	MMCCmd[0] = 0xFE;
	SPI_Send( MMCCmd, 1 );
	/* send data, pattern as 0x00,0x01,0x02,0x03,0x04,0x05 ...*/
	SPI_Send( b1,512 );
	/* Send dummy checksum */
	/* when the last check sum is sent, the response should come back
	immediately. So, check the SPI FIFO MISO and make sure the status
	return 0xX5, the bit 3 through 0 should be 0x05 */
	MMCCmd[0] = 0xFF;
	MMCCmd[1] = 0xFF;
	SPI_Send( MMCCmd, 2 );
	status = SPI_ReceiveByte();
	if ( (status & 0x0F) != 0x05 )
	{
		MMCStatus = WRITE_BLOCK_FAIL;
		nsel; /* set SPI SSEL */
		return MMCStatus;
	}
	/* if the status is already zero, the write hasn't finished
	yet and card is busy */
	if(mmc_wait_for_write_finish()==1)
	{
		MMCStatus = WRITE_BLOCK_FAIL;
		nsel; /* set SPI SSEL */
		return MMCStatus;
	}
	nsel; /* set SPI SSEL */
	SPI_ReceiveByte();
	return 0;
}
/********************************************/
UINT8 mmc_read_block(DWORD block_number)
{
WORD Checksum;
	UINT32_VAL val;	
	val.Val=block_number+135;
	val.Val = val.Val<<1;;	
	sel;
	MMCCmd[0] = 0x51;
	MMCCmd[1] = val.byte.UB;
	MMCCmd[2] = val.byte.HB;
	MMCCmd[3] = val.byte.LB;	
	MMCCmd[4] =	0;
	MMCCmd[5] = 0xff;
	SPI_Send(MMCCmd, 6 );
	/* if mmc_response returns 1 then we failed to get a 0x00 response */
	if((mmc_response(0x00))==1)
	{
		MMCStatus = READ_BLOCK_TIMEOUT;
		nsel; /* set SPI SSEL */
		return MMCStatus;
	}
	/* wait for data token */
	if((mmc_response(0xFE))==1)
	{
		MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
		nsel;
		return MMCStatus;
	}
	/* Get the block of data based on the length */
	SPI_Receive( b1,512 );
	/* CRC bytes that are not needed */
	Checksum = SPI_ReceiveByte();
	Checksum = Checksum << 0x08 | SPI_ReceiveByte();
	nsel; /* set SPI SSEL */
	SPI_ReceiveByte();
	return 0;
}
/********************************************/
UINT8 mmc_response(BYTE response)
{
	DWORD count = 0xFFF;
	BYTE result;
	while( count > 0 )
	{
		result = SPI_ReceiveByte();
		if ( result == response )break;
		count--;
	}
	if ( count == 0 )return 1; /* Failure, loop was exited due to time*/
	return 0; /* Normal, loop was exited before timeout */
}
//*******************************************/
UINT8 mmc_wait_for_write_finish()
{
	DWORD count = 0xFFFF; /* The delay is set to maximum considering
							the longest data block length to handle */
	BYTE result = 0;
	while( (result == 0) && count )
	{
		result = SPI_ReceiveByte();
		count--;	
	}
	if ( count == 0 )return 1; /* Failure, loop was exited due to timeout */
	return 0; /* Normal, loop was exited before timeout */
}