/***********************************************************************************************
* Company: Microsemi Corporation
*
* File: main.c
* File history:
*      Revision: 1.0 Date: November 8, 2012
*
* Description:
*
*	Program to do Read, Write and Verify operations on eNVM. This program interfaces
*	with the Serial Terminal running on the Host PC through MMUART_0.
*
* Author: Corporate Applications Engineering
*
************************************************************************************************/
#include <stdlib.h>
#include "mss_nvm.h"
#include "mss_uart.h"

/**************************************************************************/
/* Preprocessor definitions                                               */
/**************************************************************************/
#define DATA_LENGTH        1024u

/**************************************************************************/
/* Global data definitions                                                */
/**************************************************************************/
uint8_t g_data[DATA_LENGTH];
uint32_t addr,len;
const uint8_t ENVM_error_status[7][30] = {
											{"NVM_SUCCESS\n\r"},
											{"NVM_PROTECTION_ERROR\n\r"},
											{"NVM_VERIFY_FAILURE\n\r"},
											{"NVM_PAGE_LOCK_ERROR\n\r"},
											{"NVM_WRITE_THRESHOLD_ERROR\n\r"},
											{"NVM_IN_USE_BY_OTHER_MASTER\n\r"},
											{"NVM_INVALID_PARAMETER\n\r"}
										};
/**************************************************************************/
/* Private function declarations                                          */
/**************************************************************************/

void eNVM_write();
void eNVM_read();
void eNVM_verify();
int printnumber(int n);
int scannumber();
size_t UART_Polled_Rx
(
    mss_uart_instance_t * this_uart,
    uint8_t * rx_buff,
    size_t buff_size
);
/**************************************************************************/
/* main                                                                   */
/**************************************************************************/
int main(void)
{
    uint8_t ch;
    MSS_UART_init( &g_mss_uart1, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );

    while(1)
    {
    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"\n\rEnter your choice and press Enter\n\r 1. Read \n\r 2. Write \n\r 3. Verify \n\r" );
    ch = scannumber();

    if(ch==1)
      eNVM_read();
    else if(ch==2)
        eNVM_write();
    else if(ch==3)
        eNVM_verify();
    else
    	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter correct choice\n\r" );
    }
    return 0;
}
/**************************************************************************/
/* read                                                                   */
/**************************************************************************/
void eNVM_read()
    {
	uint16_t i;
    uint8_t outbuf[1024];
    nvm_status_t status;

    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the address (0 to 30000) to read and press Enter\n\r" );
    addr=scannumber();
    while(addr<0 || addr>30000)
    {
    	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter correct address (0 to 30000) to read and press Enter\n\r" );
    	addr=scannumber();
    }
    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the length (1 to 1024) of data to read and press Enter\n\r" );
    len=scannumber();
    while(len<1 || len>1024)
    {
    	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter correct length (1 to 1024) to read and press Enter\n\r" );
      	len=scannumber();
    }
    status = NVM_read( (uint8_t *)addr, outbuf, len );
    if(status==NVM_SUCCESS)
    {
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Read operation successful for\n\r" );
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"address = " );
        printnumber(addr);
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"length = " );
        printnumber(len);
    }
    else
    {
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Read operation failed\n\r" );
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Status: " );
		MSS_UART_polled_tx( &g_mss_uart1, ENVM_error_status[status], sizeof(ENVM_error_status[status]));
    }

    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Data:\n\r" );
    for(i=0;i<len;i++)
    	printnumber(outbuf[i]);
    }
/**************************************************************************/
/* write                                                                  */
/**************************************************************************/
void eNVM_write()
    {
	uint16_t i;
	uint8_t dtype,idata[1024];
	nvm_status_t status;

    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the address (0 to 30000) to write and press Enter\n\r" );
    addr=scannumber();
    while(addr<0 || addr>30000)
        {
        	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter correct address (0 to 30000) to write and press Enter\n\r" );
        	addr=scannumber();
        }
    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the length (1 to 1024) of data to write and press Enter\n\r" );
    len=scannumber();
    while(len<1 || len>1024)
        {
        	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter correct length (1 to 1024) to write and press Enter\n\r" );
          	len=scannumber();
        }
    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Select the data type to write and press enter:\n\r 1. Incremental pattern\n\r 2. Even numbers\n\r 3. User specific (two digit numbers)\n\r" );
    dtype = scannumber();
    while(dtype<1 || dtype>3)
            {
            	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter correct choice\n\r" );
            	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Select the data type to write and press enter:\n\r 1. Incremental pattern\n\r 2. Even numbers\n\r 3. User specific (two digit numbers)\n\r" );
            	dtype=scannumber();
            }
    switch(dtype)
		{
    case 1:
				for(i=0;i<len;i++)
					idata[i]=i;
				break;
    case 2:
				for(i=0;i<len;i++)
					idata[i]=i*2;
				break;
    case 3:
				MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the data\n\r" );
				for(i=0;i<len;i++)
				{
					idata[i] = scannumber();
					if(idata[i]<0 || idata[i]>99 )
					{
						MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter only two digit numbers\n\r" );
						i--;
					}
				}
				break;
    default:
				MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the correct choice \n\r" );
				return;
		}
    status = NVM_write( (uint32_t *)addr, idata, len, NVM_DO_NOT_LOCK_PAGE);
    if(status==NVM_SUCCESS)
		{
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Write operation successful for\n\r" );
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"address = " );
        printnumber(addr);
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"length = " );
        printnumber(len);
		}
    else
		{
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Write operation failed\n\r" );
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Status: " );
		MSS_UART_polled_tx( &g_mss_uart1, ENVM_error_status[status], sizeof(ENVM_error_status[status]));
		}
    }
/**************************************************************************/
/* verify                                                                 */
/**************************************************************************/
void eNVM_verify()
    {
	uint16_t i;
	uint8_t dtype,idata[1024];
	nvm_status_t status;

    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the address (0 to 30000) to verify and press Enter\n\r" );
    addr=scannumber();
    while(addr<0 || addr>30000)
         {
             MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter correct address (0 to 30000) to verify and press Enter\n\r" );
             addr=scannumber();
         }
    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the length (1 to 1024) of data to verify and press Enter\n\r" );
    len=scannumber();
    while(len<1 || len>1024)
        {
        	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter correct length (1 to 1024) to verify and press Enter\n\r" );
          	len=scannumber();
        }
    MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Select the data to verify:\n\r 1. Incremental pattern\n\r 2. Even numbers\n\r 3. User specific (two digit numbers)\n\r" );
    dtype = scannumber();
    while(dtype<1 || dtype>3)
        {
            MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter correct choice\n\r" );
            MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Select the data type to write and press enter:\n\r 1. Incremental pattern\n\r 2. Even numbers\n\r 3. User specific (two digit numbers)\n\r" );
            dtype=scannumber();
        }
    switch(dtype)
        {
        case 1:
    				for(i=0;i<len;i++)
    					idata[i]=i;
    				break;
        case 2:
    				for(i=0;i<len;i++)
    					idata[i]=i*2;
    				break;
        case 3:
    				MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the data\n\r" );
    				for(i=0;i<len;i++)
    				{
    					idata[i] = scannumber();
    					if(idata[i]<0 || idata[i]>99 )
    					{
    				    	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter only two digit numbers\n\r" );
    				    	i--;
    					}
    				}
    				break;
        default:
    				MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Enter the correct choice\n\r" );
    				return;
        }
    status = eNVM_verify( (uint8_t *)addr,idata,len );
    if(status==NVM_SUCCESS)
    {
    	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Verify operation successful\n\r" );
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"address = " );
        printnumber(addr);
        MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"length = " );
        printnumber(len);
    }
    else
    {
    	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Verify operation failed\n\r" );
    	MSS_UART_polled_tx_string( &g_mss_uart1,(const uint8_t*)"Status: " );
		MSS_UART_polled_tx( &g_mss_uart1, ENVM_error_status[status], sizeof(ENVM_error_status[status]));
    }
    }

/**************************************************************************/
/* UART Rx                                                                */
/**************************************************************************/

size_t
UART_Polled_Rx
    (
        mss_uart_instance_t * this_uart,
        uint8_t * rx_buff,
        size_t buff_size
    )
    {
        size_t rx_size = 0U;

        while( rx_size < buff_size )
        {
           while ( ((this_uart->hw_reg->LSR) & 0x1) != 0U  )
           {
               rx_buff[rx_size] = this_uart->hw_reg->RBR;
               ++rx_size;
           }
        }

        return rx_size;
    }
/**************************************************************************/
/* printing number on Serial Terminal                                     */
/**************************************************************************/
int printnumber(int n)
    {
    	char ret[100];
    	    int numChars = 0;
    	    int isNegative = 0;
    	    int temp;
    	    // Determine if integer is negative

    	    if (n < 0) {
    	        n = -n;
    	        isNegative = 1;
    	        numChars++;
    	    }
    	    // Count how much space we will need for the string
    	    temp = n;
    	    do {
    	        numChars++;
    	        temp /= 10;
    	    } while ( temp );
    	    ret[numChars] = 0;
    	    //Add the negative sign if needed
    	    if (isNegative) ret[0] = '-';
    	    // Copy digits to string in reverse order
    	    int i = numChars - 1;
    	    do {
    	        ret[i--] = n%10 + '0';
    	        n /= 10;
    	    } while (n);
    		MSS_UART_polled_tx( &g_mss_uart1, (const uint8_t*)ret,numChars);
    		MSS_UART_polled_tx( &g_mss_uart1, (const uint8_t*)"\r\n", 2 );
    		return 0;
    }
/**************************************************************************/
/* reading a number from Serial Terminal                                  */
/**************************************************************************/
int scannumber()
    {
    	uint8_t rxbuff,x[8]={0},i=0;//[8];
    	mss_uart_instance_t * this_uart = &g_mss_uart1;
    	int num;
    	while(i<8)
    	{
    	UART_Polled_Rx( &g_mss_uart1, &rxbuff, sizeof(rxbuff) );
    	if(rxbuff == '\n')
    	{
    		rxbuff= this_uart->hw_reg->RBR;
    		rxbuff= this_uart->hw_reg->RBR;
    		break;
    	}
    	else
    		x[i++]=rxbuff;
    	}
    	num = atoi(x);
    	return num;
    }

