/**
 * \file   hs_mmcsd_fs.c
 *
 * \brief  FS support for HS MMCSD Sample Application
 *
*/

/*
* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 
*/
/* 
*  Redistribution and use in source and binary forms, with or without 
*  modification, are permitted provided that the following conditions 
*  are met:
*
*    Redistributions of source code must retain the above copyright 
*    notice, this list of conditions and the following disclaimer.
*
*    Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the 
*    documentation and/or other materials provided with the   
*    distribution.
*
*    Neither the name of Texas Instruments Incorporated nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#include <ti/sysbios/fatfs/ff.h>
#include "cmdline.h"
#include "consoleUtils.h"
#include "string.h"
#include "stdio.h"
#include "soc_AM335x.h"


/*****************************************************************************
A structure that holds a mapping between an FPGA register address,
and a string representation.

******************************************************************************/
typedef struct	{
				volatile unsigned short	*address;
				const char				*pcFpgaRegStr;
} tFpgaRegister;
/*****************************************************************************
A macro to make it easy to add FPGA codes to the table.
******************************************************************************/
#define FPGA_ENTRY(f)        { ((unsigned short *)f), (#f) }
tFpgaRegister FpgaRegister[] =
{
/*		FPGA_ENTRY(STAT_REG),
		FPGA_ENTRY(CTRL_REG),
		FPGA_ENTRY(SETP_HI_REG),
		FPGA_ENTRY(ENABLE_LENGTH_REG),
		FPGA_ENTRY(ACT_REG),
		FPGA_ENTRY(LEAD_REG),
		FPGA_ENTRY(PER_REG),
		FPGA_ENTRY(DEADTIME_REG),
		FPGA_ENTRY(DUTYCYCLE_REG),
		FPGA_ENTRY(PEAK_MEMORY_REG),
		FPGA_ENTRY(FIRMWARE_REV),
		FPGA_ENTRY(OSCILLATOR_RUNNING),
		FPGA_ENTRY(LCD_DISPLAY_REG),
		FPGA_ENTRY(OVER_FREQUENCY_REG),
		FPGA_ENTRY(PWM_IN_TON_LO_REG),
		FPGA_ENTRY(PWM_IN_TON_HI_REG),
		FPGA_ENTRY(PWM_IN_TOFF_LO_REG),
		FPGA_ENTRY(PWM_IN_TOFF_HI_REG),*/
		FPGA_ENTRY(0)
};

/*****************************************************************************
A structure that holds a mapping between an FRESULT numerical code,
and a string representation.  FRESULT codes are returned from the FatFs
FAT file system driver.

******************************************************************************/
typedef struct
{
    FRESULT fresult;
    char *pcResultStr;
}
tFresultString;
/*****************************************************************************
A macro to make it easy to add result codes to the table.
******************************************************************************/
#define FRESULT_ENTRY(f)        { (f), (#f) }

/*****************************************************************************
A table that holds a mapping between the numerical FRESULT code and
it's name as a string.  This is used for looking up error codes for
printing to the console.
******************************************************************************/
tFresultString g_sFresultStrings[] =
{
    FRESULT_ENTRY(FR_OK),
    FRESULT_ENTRY(FR_NOT_READY),
    FRESULT_ENTRY(FR_NO_FILE),
    FRESULT_ENTRY(FR_NO_PATH),
    FRESULT_ENTRY(FR_INVALID_NAME),
    FRESULT_ENTRY(FR_INVALID_DRIVE),
    FRESULT_ENTRY(FR_DENIED),
    FRESULT_ENTRY(FR_EXIST),
    FRESULT_ENTRY(FR_INVALID_OBJECT),
    FRESULT_ENTRY(FR_WRITE_PROTECTED),
    FRESULT_ENTRY(FR_NOT_ENABLED),
    FRESULT_ENTRY(FR_NO_FILESYSTEM),
    FRESULT_ENTRY(FR_INVALID_OBJECT),
    FRESULT_ENTRY(FR_MKFS_ABORTED)
};

char 	tmp_str[2048];

/*****************************************************************************
A macro that holds the number of result codes.
******************************************************************************/
#define NUM_FRESULT_CODES (sizeof(g_sFresultStrings) / sizeof(tFresultString))

/*-----------------------------------------------------------------------------
 * 	function prototypes
 ----------------------------------------------------------------------------*/
int Cmd_get		(int argc, char *argv[]);
int Cmd_list	(int argc, char *argv[]);
int Cmd_set		(int argc, char *argv[]);

/*******************************************************************************
**
** This function append data to the telnet_str.
**
*******************************************************************************/
extern int ConPrintf(const char *format, ...);
#define TelnetUtilsPrintf ConPrintf


/*******************************************************************************
**
** This function implements the "help" command.  It prints a simple list of the
** available commands with a brief description.
**
*******************************************************************************/
int Cmd_help(int argc, char *argv[])
{
    tCmdLineEntry *pEntry;

    /*
    ** Print some header text.
    */
    sprintf(tmp_str, "\nAvailable commands\n\r");
    TelnetUtilsPrintf(tmp_str);
    sprintf(tmp_str,"------------------\n\r");
    TelnetUtilsPrintf(tmp_str);

    /*
    ** Point at the beginning of the command table.
    */
    pEntry = &g_sCmdTable[0];

    /*
    ** Enter a loop to read each entry from the command table.  The end of the
    ** table has been reached when the command name is NULL.
    */
    while(pEntry->pcCmd)
    	{
        /*
        ** Print the command name and the brief description.
        */
    	if (pEntry->visible)
    		{
    		sprintf(tmp_str,"%s \t %s\n\r", pEntry->pcCmd, pEntry->pcHelp);
    		TelnetUtilsPrintf(tmp_str);
    		}

        /*
        ** Advance to the next entry in the table.
        */
        pEntry++;
    	}

    /*
    ** Return success.
    */
    return(0);
	}

/*******************************************************************************
**
** This is the table that holds the command names, implementing functions, and
** brief description.
**
*******************************************************************************/
tCmdLineEntry g_sCmdTable[] =
{
    { "help",   Cmd_help,   " : Display list of commands", 1},
    { "h",      Cmd_help,   " : alias for help", 0},
    { "?",      Cmd_help,   " : alias for help", 0 },
    { "get",  	Cmd_get,   	" : Get", 1 },
    { "set",  	Cmd_set,    " : Set", 1},
    { "list",  	Cmd_list,   " : List FPGA register", 1 },
	{ 0, 0, 0 }
};

/******************************************************************************
**																			  *
** This is the table that holds the memory type, used in GET and SET command  *
**																			  *
******************************************************************************/
typedef enum
{
	null_element=0,
	mem16,
	mem32,
	fpga,
	cpu_adc,
	ups
} memory_enumT;

typedef struct
{
	const char 	   *pname;
	memory_enumT	num;
} memory_typeT;

memory_typeT memory[] =
{
		{ "mem16"		, mem16 },
		{ "mem32"		, mem32 },
		{ "fpga"		, fpga },
		{ "fpga"		, fpga },
		{ "cpu_adc" 	, cpu_adc },
		{ "ups" 		, ups },
		{ 0				, null_element }
};

/*******************************************************************************
**
** This function implements the "get" command.
**
*******************************************************************************/
int Cmd_get(int argc, char *argv[])
	{
	volatile unsigned short int	*p_data16;
	volatile unsigned int		*p_data32;
	volatile unsigned short int	data16;
	volatile unsigned int		data32;
	int							return_value;
    int							i;
    int							address;
    memory_typeT   				*pEntry;

    /*
    ** Print some header text.
    */
    sprintf(tmp_str, "\r\nGET command\n\r");
    TelnetUtilsPrintf(tmp_str);
    sprintf(tmp_str,"------------------\n\r");
    TelnetUtilsPrintf(tmp_str);

    if (argc<2)
    	{
        sprintf(tmp_str, "\r\nGET command: too few arguments\n\r");
        TelnetUtilsPrintf(tmp_str);
        return (0);
    	}

    /*
    ** Enter a loop to read each entry from the command table.  The end of the
    ** table has been reached when the command name is NULL.
    */
    i = 0;
    pEntry = &memory[0];

    while(argc)
    	{
        /*
        ** Print the command line.
        */
    	sprintf(tmp_str,"%d \t %s\n\r", i, argv[i]);
        TelnetUtilsPrintf(tmp_str);

        /*
        ** Advance to the next entry in the table.
        */
        argc--;
        i++;
    	}

    while(pEntry->pname)
    {
        if(!strcmp((const char *)argv[1], (const char *)pEntry->pname))
        {
        	switch (pEntry->num)
        	{
        		case mem16:
					sscanf(argv[2], "%x", &address);
					p_data16=(volatile unsigned short int*)address;
					sprintf(tmp_str, " [0x%08x]=0x%04x", (unsigned int)p_data16,(unsigned short int)(*p_data16));
				    TelnetUtilsPrintf(tmp_str);
        			break;

        		case mem32:
					sscanf(argv[2], "%x", &address);
					p_data32=(volatile unsigned int*)address;
					sprintf(tmp_str, " [0x%08x]=0x%08x", (unsigned int)p_data32, (unsigned int)(*p_data32));
				    TelnetUtilsPrintf(tmp_str);
        			break;

        		case fpga:
					return_value = sscanf(argv[2], "%x", &address);
					if ( return_value != 1 || address < 0 || address>32767 )
						{
						strcpy( tmp_str, " invalid syntax" );
					    TelnetUtilsPrintf(tmp_str);
						break;
						}
					address*=2;
					address+=0x09000000;
					p_data16=(volatile unsigned short int*)address;
					data16 = (unsigned short int) *p_data16;
					address-=0x09000000;
					address/=2;
					sprintf(tmp_str, "reg 0x%04x@[0x%04x]=0x%04x", (unsigned int)address, (unsigned int)p_data16, data16);
				    TelnetUtilsPrintf(tmp_str);
        			break;

        		case	cpu_adc:
        		{
  /*      			extern int							adc_data_mv[8];

        			sprintf(tmp_str, "\r\nadc 0 = %04d"
							"\r\nadc 1 = %04d"
							"\r\nadc 2 = %04d"
							"\r\nadc 3 = %04d"
							"\r\nadc 4 = %04d"
        					"\r\nadc 5 = %04d"
        					"\r\nadc 6 = %04d"
        					"\r\nadc 7 = %04d\r\n",
        					adc_data_mv[0],
        					adc_data_mv[1],
        					adc_data_mv[2],
        					adc_data_mv[3],
        					adc_data_mv[4],
        					adc_data_mv[5],
        					adc_data_mv[6],
        					adc_data_mv[7] );
				    TelnetUtilsPrintf(tmp_str);*/
        		}
        			break;
        		case	ups:
        		{
/*        			extern float ups_voltage[8];
        			sprintf(tmp_str,
        					"\r\n+24     = %#2.2f"
        					"\r\n+15Vg   = %#2.2f"
        					"\r\n+15V    = %#2.2f"
        					"\r\n +5Va   = %#2.2f"
        					"\r\n +5Vd   = %#2.2f"
        					"\r\n Vbakup = %#2.2f"
        					"\r\n",
        					ups_voltage[0],
							ups_voltage[1],
							ups_voltage[2],
							ups_voltage[3],
							ups_voltage[5],
							ups_voltage[7] );
				    TelnetUtilsPrintf(tmp_str);*/
        		}
        			break;
        	}
            break;
        }

        /* Not found, so advance to the next entry. */
        pEntry++;
    }

    /*
    ** Return success.
    */
    return(0);
}

/******************************************************************************/

/*******************************************************************************
**
** This function implements the "set" command.
**
*******************************************************************************/
int Cmd_set(int argc, char *argv[])
	{
	volatile unsigned short int	*p_data16;
	volatile unsigned int		*p_data32;
	volatile unsigned short int	data16;
	volatile unsigned int		data32;
	int							return_value;
    int				i;
    int				address;
    memory_typeT   *pEntry;

    /*
    ** Print some header text.
    */
    sprintf(tmp_str, "\nSET command\n\r");
    TelnetUtilsPrintf(tmp_str);
    sprintf(tmp_str,"------------------\n\r");
    TelnetUtilsPrintf(tmp_str);

    if (argc>4)
    	{
        sprintf(tmp_str, "\nSET command: too may arguments\n\r");
        TelnetUtilsPrintf(tmp_str);
        return (0);
    	}
    if (argc<4)
    	{
        sprintf(tmp_str, "\nSET command: too few arguments\n\r");
        TelnetUtilsPrintf(tmp_str);
        return (0);
    	}

    /*
    ** Enter a loop to read each entry from the command table.  The end of the
    ** table has been reached when the command name is NULL.
    */
    i = 0;
    pEntry = &memory[0];

    while(argc)
    	{
        /*
        ** Print the command line
        */
    	sprintf(tmp_str,"%d \t %s\n\r", i, argv[i]);
        TelnetUtilsPrintf(tmp_str);

        /*
        ** Advance to the next entry in the table.
        */
        argc--;
        i++;
    	}

    while(pEntry->pname)
    	{
        if(!strcmp((const char *)argv[1], (const char *)pEntry->pname))
        	{
        	switch (pEntry->num)
        		{
        		case mem16:
					sscanf(argv[2], "%x", &address);
					sscanf(argv[3], "%hx", &data16);

					p_data16=(volatile unsigned short int*)address;
					*p_data16=data16;
					sprintf (tmp_str, " [0x%08x]=0x%04x", (unsigned int)p_data16, (unsigned short int)(*p_data16));
				    TelnetUtilsPrintf(tmp_str);
        			break;
        		case mem32:
					sscanf(argv[2], "%x", &address);
					sscanf(argv[3], "%x", &data32);
					p_data32=(volatile unsigned int*)address;
					*p_data32=data32;
					sprintf (tmp_str, " [0x%08x]=0x%08x", (unsigned int)p_data32, (unsigned short int)(*p_data32));
				    TelnetUtilsPrintf(tmp_str);
        			break;
        		case fpga:
					sscanf(argv[3], "%hx", &data16);
					return_value = sscanf(argv[2], "%x", &address);
					if ( return_value != 1 || address < 0 || address>32767 )
						{
						strcpy( tmp_str, " invalid syntax" );
					    TelnetUtilsPrintf(tmp_str);
						break;
						}
					address*=2;
					address+=0x09000000;
					p_data16=(volatile unsigned short int*)address;
					*p_data16 = data16;
					address-=0x09000000;
					address/=2;
					sprintf (tmp_str, "reg 0x%04x@[0x%08x]=0x%04x", (unsigned int)address,(unsigned int)p_data16, (unsigned short int)(*p_data16));
				    TelnetUtilsPrintf(tmp_str);
        			break;

        		case	cpu_adc:
        		case	ups:
        			sprintf(tmp_str, "read only!");
        			TelnetUtilsPrintf(tmp_str);
        			break;
        		}
            break;
        	}

        /* Not found, so advance to the next entry. */
        pEntry++;
    	}

    /*
    ** Return success.
    */
    return(0);
	}
/******************************************************************************/


/*******************************************************************************
**
** 	This function implements the "list" command.  It prints a list of the
** 	FPGA REGISTER
**
*******************************************************************************/
int Cmd_list(int argc, char *argv[])
	{
    unsigned int   address;
    int				i;

    /*
    ** Print some header text.
    */
    sprintf(tmp_str, "\nList of FPGA registers \n\r");
    TelnetUtilsPrintf(tmp_str);
    sprintf(tmp_str,"----------------------------------------\n\r");
    TelnetUtilsPrintf(tmp_str);

    /*
    ** Enter a loop to read each entry from the command table.  The end of the
    ** table has been reached when the command name is NULL.
    */
    i = 0;
    while (FpgaRegister[i].address)
		{
        /*
        ** Print the register name
        */
    	address = ((unsigned int) FpgaRegister[i].address) -0x09000000;
    	address /= 2;

    	if (strlen (FpgaRegister[i].pcFpgaRegStr)>14)
    		sprintf(tmp_str,"%s \t %04X \t %08X\n\r", FpgaRegister[i].pcFpgaRegStr, address, FpgaRegister[i].address);
    	else
    		sprintf(tmp_str,"%s \t\t %04X \t %08X\n\r", FpgaRegister[i].pcFpgaRegStr, address, FpgaRegister[i].address);
        TelnetUtilsPrintf(tmp_str);
        i++;
    	}

    /*
    ** Return success.
    */
    return(0);
	}
/******************************************************************************/



