/*************************************************************************************
 * Nand_Flash
 *
 *Dexcel Electronics Designs PVT Ltd
 *
 * - File              : nandflash.c
 *
 * Description		:  . contains the functions for verifying the Actel Nand Flash IP core.
 *
 * (C) Copyright 2008 Dexcel Electronics Designs PVT Ltd.
 * $Revision: 0.4 $
 * $Date: Tuesday, December 08 2008 
 ************************************************************************************/

#include <8051.h>
#include<stdio.h>
#include"Nandflash.h"


unsigned char Data_Rcv, Data_Type, Data_Read;


/**
  * This function transmits a character through UART	
  *	
  * @param 	ch: data to be transmitted.

  * @return	 none 
  */
void Uart_Tx(unsigned char ch)
{
	 while(!(P3 & 0x01));
	 P0 = ch; 
  	 P3 = 0x00;
	 P3 = 0x01; 
}


/**
  * This function receives a character from UART
  *	
  * @param none.
  *  			
  * @return	 data_rx: Data read from UART.
  *
  */


unsigned char CheckUART()
{
	unsigned char data_rx;
	 while(!(P2 & 0x01));
	 P2 = 0x00;
	 P2 = 0x01;
	 data_rx=P1; 
	 return data_rx;
}

/**
  * This function Reads the status register of the NAND device by issuing a 0x70 command.
  *
  * @param none.
  *
  * @return	 
  *				NAND_IO_RC_PASS		=0 : The function completes operation successfully.
  *				NAND_IO_RC_FAIL		=1 : The function does not complete operation successfully.
  *				NAND_IO_RC_TIMEOUT	=2 : The function times out before operation completes.
  */
int NAND_ReadStatus(void)
{
	int nReadStatusCount;
	unsigned char ucStatus;


	//while(!*(Gpio_Port));						/*Check for Ready/Busy signal*/
	while(!(P0));
	
/* Issue command */
	NAND_WRITE_CMD(NAND_CMD_READ_STATUS);		
	nReadStatusCount = 0;

	while(nReadStatusCount < MAX_READ_STATUS_COUNT)
	{
		/* Read status byte */
		NAND_READ_DATA(&ucStatus);
		
		/* Check status */
		if((ucStatus & STATUS_BIT_6) == STATUS_BIT_6)  /* If status bit 6 = 1 device is ready */
		{
			if((ucStatus & STATUS_BIT_0) == 0)	/* If status bit 0 = 0 the last operation was succesful */
				return NAND_IO_RC_PASS;
			else
				return NAND_IO_RC_FAIL;
		}			
		nReadStatusCount++;
	}

	return NAND_IO_RC_TIMEOUT;
} /* NAND_ReadStatus */



/**
  * This function erases (returns all bytes in the block to 0xFF) a block of data in the NAND device	
  *
  * @param  a_uiBlockNum : Block number to be erased.
  * 
  * @return	 
  *				NAND_IO_RC_PASS		=0 : The function completes operation successfully.
  *				NAND_IO_RC_FAIL		=1 : The function does not complete operation successfully.
  *				NAND_IO_RC_TIMEOUT	=2 : The function times out before operation completes.
  */

int NAND_EraseBlock(unsigned long a_uiBlockNum)
{
	int rc;
	unsigned long a_uiShiftedBlockNum;
	a_uiShiftedBlockNum = a_uiBlockNum << 6;
	
	
	while(!(P0));								/*Check for Ready/Busy signal*/
	
	NAND_WRITE_CE(0x00);						/*make chip select low*/
	/* Issue command */
	NAND_WRITE_CMD(NAND_CMD_BLOCK_ERASE_CYCLE1);

	/* Issue address */
	NAND_WRITE_ADDR((unsigned char)(a_uiShiftedBlockNum & 0xFF));			/* Set page address byte 0 */
	NAND_WRITE_ADDR((unsigned char)((a_uiShiftedBlockNum >> 8) & 0xFF));	/* Set page address byte 1 */
	NAND_WRITE_ADDR((unsigned char)((a_uiShiftedBlockNum >> 16) & 0x0F));	/* Set page address byte 2 */
	/* Issue command */
	NAND_WRITE_CMD(NAND_CMD_BLOCK_ERASE_CYCLE2);

	rc = NAND_ReadStatus();		/* Wait for ready status */                                        

	return rc;
} /* NAND_EraseBlock */


/**
  * The NAND_ProgramPage function is used program a page of data into the NAND device.	
  *
  * @param 	
  *  			a_uiPageNum : Programming will occur at this page address.
  *  			a_usColNum :  Programming will begin at this column address.
  *	 			a_usReadSizeByte : Number of bytes to program.
  *	 			a_pucReadBuf : Data buffer with data which will be programmed to flash.
  * 
  * @return	 
  *				NAND_IO_RC_PASS		=0 : The function completes operation successfully.
  *				NAND_IO_RC_FAIL		=1 : The function does not complete operation successfully.
  *				NAND_IO_RC_TIMEOUT	=2 : The function times out before operation completes.
  */

int NAND_ProgramPage(
unsigned long a_uiPageNum,
unsigned short a_usColNum,
unsigned short a_usReadSizeByte,
unsigned char *a_pucReadBuf)
{

	int i=0, rc;
	unsigned short a;
	
	while(!(P0));											/*Check for Ready/Busy signal*/

	NAND_WRITE_CE(0x00);										/*make chip select low*/

	/* Issue command */
	NAND_WRITE_CMD(NAND_CMD_PAGE_PROGRAM_CYCLE1);					/* Issue 0x80 command */

	/* Issue Address */
	NAND_WRITE_ADDR((unsigned char)(a_usColNum & 0xFF));			/* Set column address byte 0 */
	NAND_WRITE_ADDR((unsigned char)((a_usColNum >> 8) & 0x0F));		/* Set column address byte 1 */
	NAND_WRITE_ADDR((unsigned char)(a_uiPageNum & 0xFF));			/* Set page address byte 0 */ 
	NAND_WRITE_ADDR((unsigned char)((a_uiPageNum >> 8) & 0xFF));	/* Set page address byte 1 */ 
	NAND_WRITE_ADDR((unsigned char)((a_uiPageNum >> 16) & 0x0F));	/* Set page address byte 2 */
	
	//WRITE_NAND_ARRAY(a_pucReadBuf,a_usReadSizeByte );					/* Input data to NAND device */	
	while(a_usReadSizeByte)
	{
		if(Count_flag)
		{  
			  NAND_WRITE_DATA(counter++);
			  if(counter==0xff)
			  counter=0;
		}
		else
		{
			NAND_WRITE_DATA(Data_Rd);
		}
		a_usReadSizeByte--;
	}

	NAND_WRITE_CMD(NAND_CMD_PAGE_PROGRAM_CYCLE2);					/* Issue 0x10 command */

	rc = NAND_ReadStatus();										/* Wait for status */                                        
	return rc;													/* Wait for status */                                        

} 
/**
  * This function reads data from the input page a_uiPageNum and column a_usColNum number into the 
  *	buffer a_pucReadBuf for a_usReadSizeByte number of bytes.	
  *	
  *
  * @param 	
  *  			a_uiPageNum : Page number for reading
  *  			a_usColNum : Column number for reading
  *	 			a_usReadSizeByte : Number of byte to read
  *	 			a_pucReadBuf : Read data buffer
  * 
  * @return	 
  *				NAND_IO_RC_PASS		=0 : The function completes operation successfully.
  *				NAND_IO_RC_FAIL		=1 : The function does not complete operation successfully.
  *				NAND_IO_RC_TIMEOUT	=2 : The function times out before operation completes.
  */

int NAND_ReadPage(
unsigned long a_uiPageNum,
unsigned short a_usColNum,
unsigned short a_usReadSizeByte,
unsigned char *a_pucReadBuf)
{
	
	int rc;
	int i=0,j=0;
	unsigned int count=0;
	
	
	while(!(P0));											/*Check for Ready/Busy signal*/
	
	NAND_WRITE_CE(0x00);										/*make chip select low*/

	NAND_WRITE_CMD(NAND_CMD_PAGE_READ_CYCLE1);

	NAND_WRITE_ADDR((unsigned char)(a_usColNum & 0xFF));
	NAND_WRITE_ADDR((unsigned char)((a_usColNum >> 8) & 0x0F));
	NAND_WRITE_ADDR((unsigned char)(a_uiPageNum & 0xFF));
	NAND_WRITE_ADDR((unsigned char)((a_uiPageNum >> 8) & 0xFF));
	NAND_WRITE_ADDR((unsigned char)((a_uiPageNum >> 16) & 0x0F));
	
	NAND_WRITE_CMD(NAND_CMD_PAGE_READ_CYCLE2);
		while(!(P0));
	rc = NAND_ReadStatus();										                                      
	if(rc != NAND_IO_RC_PASS)
	{
		return rc;
	}

	NAND_WRITE_CMD(NAND_CMD_PAGE_READ_CYCLE1);	

	while(a_usReadSizeByte)
	{
		NAND_READ_DATA(&Data_Rd);
		Uart_Tx(Data_Rd);
		a_usReadSizeByte--;
		i++;
	}
	return 0;
}

/***************************************************************
 MAIN ROUTINE 
****************************************************************/
int main()
{
	unsigned long i,rc,k,j;
	static unsigned int xdata bb[NAND_BLOCK_COUNT];
	unsigned char xdata ucPageReadBuf[2112]; 
	unsigned char xdata ucPageProgBuf[2112]; 
	unsigned short count;
	unsigned char bank1, bank2;	
	unsigned long bank_addr=0;
	
	while(1)
	{
		counter=0;
		Data_Rcv=CheckUART();
		if(Data_Rcv==1)
		{
			bank1=CheckUART();
			bank2=CheckUART();
			Block_No=(bank1 + (bank2 <<8));
			rc =NAND_EraseBlock(Block_No);
			if(rc!=NAND_IO_RC_PASS)
			{
				Uart_Tx(0xff);
			}
			else
			{
				Uart_Tx(0x01);

				Data_Type=CheckUART();
				if(Data_Type==1)
				{
					Data_Rd=CheckUART();
					for (j=0; j<NAND_PAGE_SIZE_BYTE; j++)
					{
						ucPageProgBuf[j] =0x01;
					}
				}
				else
				if(Data_Type==2)
				{
					Count_flag=1;
				}
				bank_addr=(Block_No*64);
				for(i=0;i<NAND_PAGE_COUNT_PER_BLOCK;i++)
				{
					NAND_ProgramPage((bank_addr+i), 0, 2112, ucPageProgBuf);
				}
				Uart_Tx(0x0A);
				Count_flag=0;
			}
		}
		else
		if(Data_Rcv==2)
		{
			bank1=CheckUART();
			bank2=CheckUART();
			Block_No=(bank1 + (bank2 <<8));
			bank_addr=Block_No*64;
			for(i=0;i<NAND_PAGE_COUNT_PER_BLOCK;i++)
			{
				NAND_ReadPage((bank_addr+i), 0, 2112, ucPageReadBuf);
			}
			Uart_Tx(0x0A);
		}
	}
}