


#include <stdint.h>
#include <stdbool.h>
#include "msp.h"
#include "diskio.h"
#include "pff.h"
#include "spi.h"




#define DELAY_100US() 	__delay_cycles(1600) 	/*(100us/(1/16MHz)) = 1600 TICKS*/
#define MMC_SEL 			!(P4->OUT & BIT6) 		/*CS STATUS  (TRUE:CS == LOW)*/
#define FORWARD(d) 0





/*DEFENITIONS TO MMC/SDC COMMAND*/
#define CMD0		(0x40+0)		/*GO_IDLE_STATE*/
#define CMD1		(0x40+1)		/*SEND_OP_COND (MMC)*/
#define CMD8		(0x40+8) 	/*SEND_IF_COND*/
#define CMD9		(0x40+9) 	/*SEND_CSD*/
#define CMD10	(0x40+10) 	/*SEND_CID*/
#define CMD12	(0x40+12) 	/*STOP_TRANSMISSION*/
#define CMD16	(0x40+16) 	/*SET_BLOCKLEN*/
#define CMD17	(0x40+17) 	/*READ_SINGLE_BLOCK*/
#define CMD18	(0x40+18) 	/*READ_MULTIPLE_BLOCK*/
#define CMD23	(0x40+23) 	/*SET_BLOCK_COUNT*/
#define CMD24	(0x40+24) 	/*WRITE_BLOCK*/
#define CMD25	(0x40+25) 	/*WRITE_MULTIPLE_BLOCK*/
#define CMD41	(0x40+41) 	/*APP_SEND_OP_COND (ACMD)*/
#define CMD55	(0x40+55) 	/*APP_CMD*/
#define CMD58	(0x40+58) 	/*READ_OCR*/

/*CARD TYPE FLAG'S (CARDTYPE)*/
#define CT_MMC		0X01			/*MMC VER 3*/
#define CT_SD1		0X02			/*SD VER 1*/
#define CT_SD2		0X04			/*SD VER 2*/
#define	CT_BLOCK 	0X08			/*BLOCK ADDRESSING*/

/*************************************************************
 * 				ASSERTS  THE CS OIN TO THE CARD 				*
 *************************************************************/

#define SELECT() 		P4->OUT &= ~BIT6 		/*CS = LOW*/
#define DESELECT() 		P4->OUT |= BIT6 			/*CS = HIGH*/

/*************************************************************
 * 					MODULE PRIVATE FUNCTIONS 				*
 *************************************************************/
static volatile DSTATUS Stat = STA_NOINIT; /*DISK STATUS*/

static volatile BYTE Timer1, Timer2; /*100Hz DECREMENT TIMMER*/

static BYTE CardType;/*B0:MMC, B1:SDC, B2:BLOCK ADDRESSING*/

static BYTE PowerFlag = 0;/*INDICATE IF "POWER" IS ON*/

/*************************************************************
 * 				TRANSMIT BYTE TO MMC VIA SPI 				*
 *************************************************************/
static void xmit_spi(BYTE dat){
	uint32_t ui32RcvDat = 0;

	/*SEND DATA*/
	SPI_transmitData(EUSCI_B0_BASE, dat);

	/*FLUSH DATA READ DURING THE WRITE*/
	ui32RcvDat = SPI_receiveData(EUSCI_B0_BASE);

	/*GET RID OF "VARIABLE SET, BUT UNUSED" WARNING*/

	ui32RcvDat =ui32RcvDat + 1;

}

/*************************************************************
 * 				 RECEIVE BYTE TO MMC VIA SPI 				*
 *************************************************************/

static BYTE rcvr_spi(void){
	uint32_t ui32RcvDat;

	/*SEND A DUMMY*/
	SPI_transmitData(EUSCI_B0_BASE, 0XFF);

	ui32RcvDat = SPI_receiveData(EUSCI_B0_BASE); //^M

	return (BYTE)ui32RcvDat;

}

static void rcvr_spi_m(BYTE *dst){

	*dst = rcvr_spi();
}

/*************************************************************
 * 				  WAIT FOR THE CARD READY 					*
 *************************************************************/
static BYTE wait_ready(void){
	BYTE res;
	Timer2 = 50; /*WAIT FOR TIMEOUT OF 500ms*/
	rcvr_spi();
	do
		res = rcvr_spi();

	while((res!=0xFF) && Timer2);

	return res;
}

/*************************************************************
 *SEND 80 OR SO CLOCK TRANSITIONS WITH CS AND DI HELD HIGH 	*
 *THIS IS REQUIRED AFTER CARD POWER UO TO GET IT INTO SPI		*
 *MODE														*
 *************************************************************/

static void send_initial_clock_train (void){
	unsigned int i;

	uint32_t ui32Dat = 0;

	/*ENSURE CS IS HELD HIGH*/
	DESELECT();

	for (i = 0;i < 10;i++){


		/*SEND DATA*/
			SPI_transmitData(EUSCI_B0_BASE, 0); // primer test to prueba de inicio de memoria


			ui32Dat = SPI_receiveData(EUSCI_B0_BASE); // Inicializando la variable
		/*GET RID OF "VARIABLE SET, BUT UNUSED" WARNING*/
		ui32Dat = ui32Dat + 1;

	}

}
/*************************************************************
 * 			POWER CONTROL (PLANTAFORM DEPENDENT) 			*
 *************************************************************/
/*WHEN THE TARGET SYSTEM DOES THE SUPPORT SOCKET POWER CONTROL,
 *THERE IS NOTHING TO DO IN THESE FUNCTIONS AND CHECK_POWER
 *THERE ALWAYS RETURNS 1*/

static void power_on(void){

	/*SET DI AND CS HIGH AND MORE THAN 74 PULSES TO SLCK FOR THE CARD
	 * TO BE ABLE TO ACCEPT A NATIVE COMMAND*/
	send_initial_clock_train();

	PowerFlag =	1;
}

/*SET THE SSI SPEED TO THE MAX SETTING*/

static void set_max_speed(void){	//^M

}

static void power_off(void){
	PowerFlag = 0;
}

/*SOCKET POWER STATE: 0 = OFF, 1 = ON*/
static int chk_power(void){
	return PowerFlag;
}
/*************************************************************
 * 				RECEIVE A DATA PACKET FROM MMC 				*
 *************************************************************/

/*DATA BUFFER TO STORE RECEIVED DATA
 *BYTE COUNT (MUST BE EVEN NUMBER)*/
static BOOL rcvr_datablock(BYTE *buff, UINT btr){
	BYTE token;
	/*WAIT FOR DATA PACKET IN TIMEOUT OF 100ms*/
	Timer1 = 100;
	do{
		token = rcvr_spi();
	}while((token == 0xFF) && Timer1);
	/*IF NOT VALID DATA TOKEN, RETURN WITH ERROR*/
	if(token != 0xFE) return FALSE;

	do{
		/*RECEIVE THE DATA BLOCK INTO BUFFER*/
		rcvr_spi_m(buff++);
		rcvr_spi_m(buff++);
	}while(btr -= 2);
		/*DISCARD CRC*/
		rcvr_spi();
		rcvr_spi();
		/*RETURN WITH SUCESS*/
		return TRUE;
}

/*************************************************************
 * 				 SEND A DATA PACKET TO MMC	 				*
 *************************************************************/

#if	_READONLY == 0

/*512 BYTE DATA BLOCK TO BE TRANSMITTED
 *DATA/STOP TOKEN*/

static BOOL xmit_datablock(const BYTE *buff, BYTE token){
	BYTE resp, wc;

		if(wait_ready()!=0xFF) return FALSE;
		/*XMIT DATA TOKEN*/
		xmit_spi(token);
		if(token!= 0xFD){
			wc = 0;
			do{
			/*XMIT THE 512 BYTE DATA BLOCK TO MMC*/
			xmit_spi(*buff++);
			xmit_spi(*buff++);
			}while(--wc);
			xmit_spi(0xFF);
			xmit_spi(0xFF);
			resp = rcvr_spi();
			if((resp & 0x1F) != 0x05)
				return FALSE;
		}
	return TRUE;
}
#endif	/*READ ONLY*/

/*************************************************************
 * 				 SEND A DATA PACKET TO MMC	 				*
 *************************************************************/

/*COMMAND BYTE*/
/*ARGUMENT*/
static BYTE send_cmd(BYTE cmd, DWORD arg){

	BYTE n, res;

	if(wait_ready()!=0xFF) return 0xFF;
		/*SEND COMMAND PACKET*/

		xmit_spi(cmd);					/*COMMAND*/
		xmit_spi((BYTE)(arg >> 24));		/*Argument[31..24]*/
		xmit_spi((BYTE)(arg >> 16));		/*Argument[23..16]*/
		xmit_spi((BYTE)(arg >> 8));		/*Argument[15..8]*/
		xmit_spi((BYTE)arg);				/*Argument[7..0]*/

		n = 0xFF;						/*DUMMY CRC + STOP*/

		if(cmd == CMD0) n = 0x95;		/*VALID CRC FOR CMD0(0)*/
		if(cmd == CMD8) n = 0x87;		/*VALID CRC FOR CMD8(0x1AA)*/

		xmit_spi(n);

		/*RECEIVE COMMAND RESPONSE*/
		if(cmd == CMD12) rcvr_spi();

		n = 10;							/*WAIT A VALID RESPONSE IN TIMEOUT OF 10 ATTEMPS*/

		do
			res = rcvr_spi();
		while ((res & 0x80) && --n);

		return res; /*RETURN WITH THE RESPONSE VALUE*/

}
/*************************************************************
 *SEND THE SPECIAL COMMAND USED TO TERMINAT A MULTI-SECTOR
 *
 *THIS IS THE ONLY COMMAND WHICH CAN BE SENT WHILE THE SDCARD
 *IS SENDING DATA. THE SDCARD SPEC INDICATES THAT THE DATA
 *TRANSFER WILL STOP 2 BYTES AFTER THE 6 BYTE CMD12 COMMAND
 *IS
 *************************************************************/


static BYTE send_cmd12(void){
 BYTE n, res, val;
/*FOR CMD12, WE DON'T WAIT FOR THE CARD TO BE IDLE BEFORE WE SEND
 *NEW COMMAND*/
 xmit_spi(CMD12);
 xmit_spi(0);
 xmit_spi(0);
 xmit_spi(0);
 xmit_spi(0);
 xmit_spi(0);

 /*READ UP TO 10 BYTES FROM THE CARD, REMEMBERING THE VALUE READ
  *IF IT'S NOT 0XFF */

 	 for(n = 0; n <10; n++){
 		 val = rcvr_spi();
 		 if (val != 0xFF){

 			 res = val;

 		 }
 	 }
 	 /*RETURN WITH RESPONSE VALUES*/
 	 return res;

}

/*************************************************************
* 						PUBLIC FUNCTIONS		 				*
*/


/*************************************************************
 * 					INITIALIZE DISK 	DRIVE	 				*
 *************************************************************/

DSTATUS disk_initialize(BYTE drv){
	/*PHISICAL DRIVE NUMBER (0)*/
	BYTE n, ty, ocr[4];

	if(drv) return STA_NOINIT;				/*SUPPORTS ONLY SINGLE DRIVE*/
	if(Stat & STA_NODISK) return Stat;		/*NO CARD IN THE SOCKET*/

	power_on();								/*FORCE SOCKET POWER ON*/
	send_initial_clock_train();				/*ENSURE THE CARD IS  IN SPI MODE*/

	SELECT();																	/*CS = L*/
	ty = 0;

	if(send_cmd(CMD0, 0) == 1){				/**/
		Timer1 = 100;															/*INITIALIZATION TIMEOUT OF 1000msec*/
		if(send_cmd(CMD8, 0x1AA) == 1){											/*SDC Ver2+*/
			for(n = 0;n < 4; n++) ocr[n] = rcvr_spi();
			if(ocr[2] == 0x01 && ocr[3] == 0xAA){
				do{
					if(send_cmd(CMD55,0) <= 1 && send_cmd(CMD41, 1UL << 30) == 0) break;
				}while(Timer1);
				if(Timer1 && send_cmd(CMD58, 0) == 0){ 							/*CHECK CSS BIT*/
					for(n = 0;n < 4; n++) ocr[n] = rcvr_spi();
					ty = (ocr[0] & 0x40) ? 6 : 2;
				}
			}
		}else{																	/*SDC Ver1 OR MMC*/
			ty = (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) <= 1 ) ? 2 : 1; 	/*SDC:MMC*/
			do{
				if(ty == 2){
					if(send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) == 0) break;
				}else{
					if(send_cmd(CMD1, 0) == 0) break;							/*CMD1*/
				}
			}while(Timer1);
			if(!Timer1 || send_cmd(CMD16, 512) != 0) 							/*SELECT R/W BLOCK LENGTH*/
				ty = 0;
		}
	}
	CardType = ty;
	DESELECT();																	/*CS = H*/
	rcvr_spi();																	/*IDLE (RELEASE DO)*/

	if(ty){																		/*INITIALIZATION SUCESSED*/
		Stat &= ~STA_NOINIT;														/*CLEAR STA_NOINIT*/
		set_max_speed();															/**/
	}else{																		/*INITIALIZATION FAILED*/
		power_off();
	}
	return  Stat;
}


/*************************************************************
 * 						GET DISK STATUS		 				*
 *************************************************************/

DSTATUS disk_status(BYTE drv){													/*PHISICAL DRIVE (0)*/
	if(drv) return STA_NOINIT;													/*SUPPORT ONLY SINGLE DRIVE*/
	return Stat;
}



/*************************************************************
 * 						 READ SECTOR			 				*
 *************************************************************/

/*1-PHISICAL DRIVE NUMBER (0)*/
/*2-POINTER TO THE  DATA BUFFER TO STORE READ DATA*/
/*3-START SECTOR NUMBER (LBA)*/
/*4-SECTOR COUNT (1... 255)*/

DRESULT disk_read(BYTE drv, BYTE *buff, DWORD sector, BYTE count){

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

	if(!(CardType & 4)) sector *= 512;											/*CONVERT TO BYTE ADDRESS IF NEED*/

	SELECT();																	/*CS = L*/
	if(count == 1){																/*SINGLE BLOCK READ*/
		if((send_cmd(CMD17, sector) == 0)										/*READ SINGLE BLOCK*/
			&& rcvr_datablock(buff, 512))
			count = 0;
	}else{																		/*MULTIPLE BLOCK READ*/
		if(send_cmd(CMD18, sector) == 0){
			do{
				if(!rcvr_datablock(buff, 512))break;
				buff += 512;
			}while(--count);
			send_cmd12();															/*STOP TRANSMISSION*/
		}
	}


	DESELECT();																	/*CS = H*/
	rcvr_spi();																	/*IDLE (RELEASE DO)*/

	return count ? RES_ERROR : RES_OK;
}

/*************************************************************
 * 						WRITE SECTOR 		 				*
 *************************************************************/
#if _READONLY == 0
	/**/
	/**/
	/**/
	/**/

	DRESULT disk_write(BYTE drv, const  BYTE *buff, DWORD sector, BYTE count){

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

		if (!(CardType & 4)) sector *= 512;									/*CONVERT TO BYTE ADDRESS IF NEEDED*/

		SELECT();															/*CS = L*/

		if(count == 1){														/*SINGLE BLOCK WRITE*/
			if((send_cmd(CMD24, sector) == 0)									/*WRITE BLOCK*/
			&& xmit_datablock(buff, 0xFE))
			count = 0;
		}else{																/*MULTIPLE BLOCK WRITE*/
			if(CardType & 2){
				send_cmd(CMD55, 0); send_cmd(CMD23, count);					/*ACMD23*/
			}
			if(send_cmd(CMD25, sector) == 0){
				do{
					if(!xmit_datablock(buff, 0xFC)) break;
					buff +=512;

				}while(--count);
				if(!xmit_datablock(0, 0xFD))									/*STOP_TRAN TOKEN*/

					count = 1;
			}

		}

		DESELECT();															/*CS = H*/
		rcvr_spi();															/*IDLE (RELEADE DO)*/

		return count ? RES_ERROR : RES_OK;

	}
#endif/*READ ONLY*/

/*************************************************************
* 					MISCELANEOUS FUNCTIONS 		 			*
*************************************************************/

	/*FISICAL DRIVE NUMBER (0)*/
	/*CONTROL CODE*/
	/*BUFFER SEND/RECEIVE CONTROL DATA*/
	DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void *buff){

		DRESULT res;
		BYTE n, csd[16], *ptr = buff;
		WORD csize;

		if(ctrl == CTRL_POWER){
			switch(*ptr){
				case 0:														/*SUB CONTROL CODE == 0 (POWER OFF)*/
					if(chk_power())
						power_off();											/*POWER OFF*/
				break;
				case 1:														/*SUB CONTROL CODE == 1 (POWER ON)*/
					power_on();
					res = RES_OK;
				break;
				case 2:														/*SUB CONTROL CODE == 2 (POWER_GET)*/
					*(ptr+1) = (BYTE)chk_power();
					res = RES_OK;
				break;
				default:
					res =RES_PARERR;
			}

		}else{
			if(Stat & STA_NOINIT) return RES_NOTRDY;

			SELECT();														/*CS = L*/


			switch(ctrl){

				case GET_SECTOR_COUNT:												/*GET THE NUMBER SECTOR'S ON THE DISK)*/
					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 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[7] & 3) << 10) + 1;
							*(DWORD*)buff = (DWORD)csize << (n-9);
						}
						res = RES_OK;
					}
				break;

				case GET_SECTOR_SIZE:												/*SUB CONTROL CODE == 1 (POWER ON)*/
					*(DWORD*)buff = 512;
					res = RES_OK;
				break;

				case CTRL_SYNC:														/*SUB CONTROL CODE == 2 (POWER_GET)*/
					if(wait_ready() == 0xFF)
					res = RES_OK;
				break;

				case MMC_GET_CSD:													/*SUB CONTROL CODE == 2 (POWER_GET)*/
					if (send_cmd(CMD9, 0) == 0        								/* READ_CSD */
				    && rcvr_datablock(ptr, 16))
				    res = RES_OK;
				break;

				case MMC_GET_CID:													/*SUB CONTROL CODE == 2 (POWER_GET)*/
					if (send_cmd(CMD10, 0) == 0      								/* READ_CID */
		            	&& rcvr_datablock(ptr, 16))
			        res = RES_OK;
				break;

				case MMC_GET_OCR:													/*SUB CONTROL CODE == 2 (POWER_GET)*/
					if (send_cmd(CMD58, 0) == 0) {    								/* READ_OCR */
						for (n = 0; n < 4; n++)
						*ptr++ = rcvr_spi();
						res = RES_OK;
					}


				 default:
					res =RES_PARERR;
			}

			DESELECT();																/*CS = H*/
			rcvr_spi();																/*IDLE (RELEASE DO)*/

		}
		return res;
	}

/*************************************************************
*  					MISCELANEOUS FUNCTIONS 		 			*
**************************************************************/

void disk_timerproc(void){
	BYTE n;
n = Timer1;
 if (n) Timer1 =	--n;																	/*100Hz DECREMENT TIMER*/
 n = Timer2;
 if(n) Timer2 = --n;

}

/*************************************************************
*  				USER PROVIDER TIMER FUNCTION 				*
**************************************************************/
DWORD get_fattime (void)	{
return ((2007UL-1980) << 25) | (6UL << 21) | (5UL << 16)
		| (11U << 11) | (38U << 5) | (0U >> 1);
}








