/*******************************************************************************
* File : pcie_appln_ctrlpln.c
*
* Description : Linux User Space Application to access SmartFusion2/IGLOO2 
* 		PCIe End Point
*
********************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include "../inc/board.h"

#define MAX_PCI_SBUF_SIZE 32   
#define DSN_BUFF_SIZE 32
#define LED_CONTROL 1
#define SRAM_WRITE 2
#define SRAM_READ 3
#define DIP_SWITCH 4
#define PCIE_DEVICE_INFO 5
#define INTERRUPT_CTRL 6
#define INTERRUPT_CNTR 7
#define DSN 8
#define OFF 1
#define ON 0

#ifdef DEBUG
	#define PRINTF printf
#else
	#define PRINTF 
#endif

unsigned int wr_buf[MAX_PCI_SBUF_SIZE];
unsigned int rd_buf[MAX_PCI_SBUF_SIZE];
char dsnBuff[DSN_BUFF_SIZE];

int main(int argc, char *argv[]) {

	int fd, i;
        unsigned int size;
	int SW1,SW2,SW3,SW4;
        int dipSwitchData;

#if defined(SF2)
	if((argc < 2) || ((atoi(argv[1]) != LED_CONTROL) && (atoi(argv[1]) != SRAM_WRITE) && (atoi(argv[1]) != SRAM_READ) && (atoi(argv[1]) != DIP_SWITCH))		 && (atoi(argv[1]) != PCIE_DEVICE_INFO) && (atoi(argv[1]) != INTERRUPT_CTRL) && (atoi(argv[1]) != INTERRUPT_CNTR)) 
#elif defined(IGL2)
	if((argc < 2) || ((atoi(argv[1]) != LED_CONTROL) && (atoi(argv[1]) != SRAM_WRITE) && (atoi(argv[1]) != SRAM_READ) && (atoi(argv[1]) != DIP_SWITCH))              && (atoi(argv[1]) != PCIE_DEVICE_INFO) && (atoi(argv[1]) != INTERRUPT_CTRL) && (atoi(argv[1]) != INTERRUPT_CNTR) && (atoi(argv[1]) != DSN))
#endif
	{
		 printf("\nDescription: LED Control [1], Led Data [0x0-0x000000FF]\n");
                 printf("Example: ./pcie_ctrlplane 1 0x000000FF\n");

#if defined(SF2)
		 printf("\nDescription: SRAM_WRITE [2], Write[1], SRAM Data [0x0-0xFFFFFFFF], SRAM Offset[0x0-0x3FFF]\n");
                 printf("Example: ./pcie_ctrlplane 2 1 0x12345678 0x10\n");
#elif defined(IGL2)
		 printf("\nDescription: SRAM_WRITE [2], Write[1], SRAM Data [0x0-0xFFFFFFFF], SRAM Offset[0x0-0x1FFF]\n");
                 printf("Example: ./pcie_ctrlplane 2 1 0x12345678 0x10\n");
#else
		 printf("Valid H/W board is not Selected\n");
#endif

#if defined(SF2)
                 printf("\nDescription: SRAM_READ [3], Read[0], SRAM Offset[0x0-0x1FFF]\n");
                 printf("Example : ./pcie_ctrlplane 3  0 0x10\n");
#elif defined(IGL2)
                 printf("\nDescription: SRAM_READ [3], Read[0], SRAM Offset[0x0-0x1FFF]\n");
                 printf("Example : ./pcie_ctrlplane 3  0 0x10\n");
#else
                 printf("Valid H/W board is not Selected\n");
#endif

		 printf("\nDescription: Dip Switch Status  [4]\n");
                 printf("Example: ./pcie_ctrlplane 4\n");

		 printf("\nDescription: PCIe Device Info [5], Display PCIe Configuration Space/PCIe Device Detailed Info[1/2] \n");
                 printf("Example: ./pcie_ctrlplane 5 1\n");

		 printf("\nDescription: PCIe Interrupt Control [6], Enable/(Clear/Disable)[1/0] \n");
                 printf("Example: ./pcie_ctrlplane 6 1\n");

		 printf("\nDescription: PCIe Interrupt Count [7] \n");
                 printf("Example: ./pcie_ctrlplane 7\n");
#if defined (SF2)
		printf("\n");
#endif

#if defined(IGL2)
		 printf("\nDescription: Read Device Serial Number [8] \n");
                 printf("Example: ./pcie_ctrlplane 8\n\n");
#endif

		 return 0;
	}

	if ((atoi(argv[1]) == LED_CONTROL))
	{
		if(argc != 3)
		{	
			 printf("Description: LED Control [1], Led Data [0x0-0x000000FF]\n");
                	 printf("Example : ./pcie_ctrlplane 1 0x000000FF\n");
			 return 0;
		}

		wr_buf[0] = atoi(argv[1]); /* LED Access */	

		unsigned long ledData = strtol(argv[2],NULL,0);

		if((ledData < 0) || (ledData > 0xFFFFFFFF))
		{
			printf("Enter Valid Data Range : 0x0 - 0xFFFFFFFF\n");
			return 0;
		}
	
		PRINTF("Led Data recvd from user : 0x%x\n", ledData);

                wr_buf[4] = ledData & 0xFF; /* 0 -7 */
                wr_buf[3] = ((ledData >>8) & 0xFF); /* 8 -15 */
                wr_buf[2] = ((ledData >>16) & 0xFF); /* 16 - 23 */
                wr_buf[1] = ((ledData >>24) & 0xFF); /* 24 -31   */

                PRINTF("LED : 0x%x Data[24-31] : 0x%x Data[16-23] : 0x%x Data[8-15] : 0x%x Data[0-7] : 0x%x\n", wr_buf[0],wr_buf[1], \
		wr_buf[2],wr_buf[3],wr_buf[4]);
	}	 
	else if ((atoi(argv[1]) == SRAM_WRITE))
        {
                if(argc != 5)
                {
#if defined(SF2)
                 printf("Description: SRAM_WRITE [2], Write[1], SRAM Data [0x0-0xFFFFFFFF], SRAM Offset[0x0-0x3FFF]\n");
                 printf("Example: ./pcie_ctrlplane 2 1 0x12345678 0x10\n");
#elif defined(IGL2)
                 printf("Description: SRAM_WRITE [2], Write[1], SRAM Data [0x0-0xFFFFFFFF], SRAM Offset[0x0-0x1FFF]\n");
                 printf("Example: ./pcie_ctrlplane 2 1 0x12345678 0x10\n");
#else
                 printf("Valid H/W board is not Selected\n");
#endif
		 return 0;	
                }

		wr_buf[0] = atoi(argv[1]); /* SRAM Access */	

		wr_buf[1] = atoi(argv[2]); /* SRAM write */
	
	        unsigned long sramData = strtol(argv[3],NULL,0);

		if( (sramData < 0) || (sramData > 0xFFFFFFFF))
		{
                        printf("Enter Valid Data[0x0 - 0xFFFFFFFF]\n");
                        return 0;
                }

                wr_buf[5] = sramData & 0xFF; /* 0 -7 */
                wr_buf[4] = ((sramData >>8) & 0xFF); /* 8 -15 */
                wr_buf[3] = ((sramData >>16) & 0xFF); /* 16 -23 */
                wr_buf[2] = ((sramData >>24) & 0xFF); /* 24 - 31*/

	        unsigned long sramWriteOffset = strtol(argv[4],NULL,0);

		if (sramWriteOffset < 0 || sramWriteOffset > 0x3FFF)
		{
			printf("Enter Valid SRAM offset[0x0 - 0x3FFF]\n");
			return 0;
		}
                wr_buf[6] = sramWriteOffset; /* SRAM Offset */
		
                PRINTF("SRAM : 0x%x Write : 0x%x Data[24-31] : 0x%x Data[16-23] :0x%x Data[8-15] : 0x%x Data[0-7]: 0x%x Write Offset : 0x%x\n",wr_buf[0],\
		wr_buf[1],wr_buf[2],wr_buf[3],wr_buf[4],wr_buf[5],wr_buf[6]);

        }else if(atoi(argv[1]) == SRAM_READ)
	{
		if(argc != 4)
                {
#if defined(SF2)
                         printf("Description: SRAM_READ [3], Read[0], SRAM Offset[0x0-0x1FFF]\n");
                         printf("Example : ./pcie_ctrlplane 3  0 0x10\n");
#elif defined(IGL2)
                         printf("Description: SRAM_READ [3], Read[0], SRAM Offset[0x0-0x1FFF]\n");
                         printf("Example : ./pcie_ctrlplane 3  0 0x10\n");
#else
	                 printf("Valid H/W board is not Selected\n");
#endif
                         return 0;
                }

                wr_buf[0] = atoi(argv[1]); /* SRAM Access */

                wr_buf[1] = atoi(argv[2]); /* SRAM Read */

                unsigned long sramReadOffset = strtol(argv[3],NULL,0);

                if (sramReadOffset < 0 || sramReadOffset > 0x3FFF)
                {
                        printf("Enter Valid SRAM offset[0x0 - 0x3FFF]\n");
                        return 0;
                }
                wr_buf[2] = sramReadOffset; /* SRAM Offset */

                PRINTF("SRAM_Read : 0x%x Read : 0x%x Read Offset : 0x%x\n",wr_buf[0],wr_buf[1],wr_buf[2]);
	}else if (atoi(argv[1]) == DIP_SWITCH)
	{
		if(argc != 2)
		{
			  printf("Description: Dip Switch Status  [4]\n");
                 	  printf("Example: ./pcie_ctrlplane 4\n");
		          return 0;
		}

		wr_buf[0] = atoi(argv[1]); /* Dip Switch Access */

	}else if(atoi(argv[1]) == PCIE_DEVICE_INFO)
	{
		if(argc != 3)
		{
			 printf("Description: PCIe Device Info [5], Display PCIe Configuration Space/PCIe Device Detailed Info[1/2] \n");
                	 printf("Example: ./pcie_ctrlplane 5 1\n");
			 return 0;
		}
		
		if(atoi(argv[2]) == 1)
		{
			system("sh pcie_config.sh");
		}else if(atoi(argv[2]) == 2)
		{
			system("lspci -vvv");
			printf("#########################################i###################################################\n");
			printf("NOTE :: PCIe Device Detailed Info :: Browse for Actel Device Content to get Link Width & Rate\n");
			printf("#############################################################################################\n");
		}else
		{
			printf("Enter valid PCIe option\n");
			return 0;	
		}
		return 0;	
	}else if (atoi(argv[1]) == INTERRUPT_CTRL)
	{
		if(argc != 3){
		 printf("Description: PCIe Interrupt Control [6], Enable/(Clear/Disable)[1/0] \n");
        	 printf("Example: ./pcie_ctrlplane 6 1\n");			
		 return 0;
		}

		wr_buf[0] = atoi(argv[1]);
		wr_buf[1] = atoi(argv[2]);

	}else if(atoi(argv[1]) == INTERRUPT_CNTR)
	{
		if(argc != 2)
		{
	          printf("Description: PCIe Interrupt Count [7] \n");
                  printf("Example: ./pcie_ctrlplane 7\n");
		  return 0;
		}
		wr_buf[0] = atoi(argv[1]); /* PCIe Interrupt Counter */
	}
#if defined (IGL2)
else if (atoi(argv[1]) == DSN)
        {
                if(argc != 2)
                {
			 printf("\nDescription: Read Device Serial Number [8] \n");
	                 printf("Example: ./pcie_ctrlplane 8\n\n");
                         return 0;
                }

                wr_buf[0] = atoi(argv[1]); /* Read Device Serial Number */
	}
#endif
	else
	{
		printf("Invalid argument recieved\n");
		return 0;
	}

        /*print data to be written*/
        for(i=0; i<MAX_PCI_SBUF_SIZE; i=i++) {
               	PRINTF("0x%x ", wr_buf[i]);
        }
	PRINTF("\n");
	 
    	fd = open("/dev/MS_PCI_DEV", O_RDWR);

    	if( fd < 0 ) {
          	printf("PCI Device[/dev/MS_PCI_DEV] not opened [%d] ::: Device Driver Not Inserted\n",fd);
		return -1;
    	}else
	{
    		PRINTF("PCI Device [/dev/MS_PCI_DEV] opened\n");
	}

	int retVal = write(fd, wr_buf, MAX_PCI_SBUF_SIZE);
	if (retVal == -1)
	{
		printf("Data write error\n");
	}else
	{
		PRINTF("Command write success\n");
	}
#if defined (SF2)
	if(atoi(argv[1]) == SRAM_READ || atoi(argv[1]) == DIP_SWITCH || atoi(argv[1]) == INTERRUPT_CNTR)
#elif defined (IGL2)
	if(atoi(argv[1]) == SRAM_READ || atoi(argv[1]) == DIP_SWITCH || atoi(argv[1]) == INTERRUPT_CNTR || atoi(argv[1]) == DSN)
#endif
	{
		/* read operation */
		memset((void *) rd_buf, 0, MAX_PCI_SBUF_SIZE);

		int readRetVal = read(fd, rd_buf, MAX_PCI_SBUF_SIZE); 
		if (readRetVal == -1)
		{
			printf("read error\n");
			return 0;
		}else
		{
			PRINTF("read success\n");
		}

		if (atoi(argv[1]) == SRAM_READ)
		{
			printf("SF2 SRAM data Read : ");
    			for(i=0; i<1; i++) {
				printf("0x%x ", rd_buf[i]);
		}
		}else if (atoi(argv[1]) == DIP_SWITCH)
		{
			printf("DIP Switch Data Register Value : ");
                        for(i=0; i<1; i++) {
                        	printf("0x%x ", rd_buf[i]);
			}

			dipSwitchData = rd_buf[0];

#if defined(SF2)
	        	dipSwitchData = dipSwitchData & 0X00000F00;
 		        dipSwitchData = dipSwitchData >>8;
#elif defined(IGL2)
		       	dipSwitchData = dipSwitchData & 0X0000000F;
#else
			printf("Valid H/W board is not Selected\n");
#endif

        		SW1 = (dipSwitchData & 0x1)?OFF:ON;
        		SW2 = (dipSwitchData >> 1 & 0x1)?OFF:ON;
        		SW3 = (dipSwitchData >> 2 & 0x1)?OFF:ON;
        		SW4 = (dipSwitchData >> 3 & 0x1)?OFF:ON;

        		PRINTF("SW1 = %d\nSW2 = %d\nSW3 = %d\nSW4 = %d\n",SW1,SW2,SW3,SW4);

        		if(SW1 == OFF)
        		{
                		printf("\nSW1 : OFF\n");
        		}else
        		{
                		printf("\nSW1 : ON\n");
        		}

        		if(SW2 == OFF)
        		{
                		printf("SW2 : OFF\n");
        		}else
        		{
                		printf("SW2 : ON\n");
        		}

        		if(SW3 == OFF)
        		{
                		printf("SW3 : OFF\n");
        		}else
        		{
                		printf("SW3 : ON\n");
        		}

        		if(SW4 == OFF)
        		{
                		printf("SW4 : OFF");
        		}else
        		{
                		printf("SW4 : ON");
        		}

		}else if (atoi(argv[1]) == INTERRUPT_CNTR)
		{
			printf("SF2 PCIe Interrupt Counter Value : ");
    			for(i=0; i<1; i++) {
				printf("%ld ", rd_buf[i]);
			}
		}
#if defined(IGL2)
else if (atoi(argv[1]) == DSN)
                {
                        printf("Device Serial Number:");
			for(i=3;i>=0;i--)
			{
				sprintf(dsnBuff,"%lX", rd_buf[i]);

				int dsnDataLen = strlen(dsnBuff);

				if(dsnDataLen < 8)
				{
					if (dsnDataLen == 0)
					{
						printf("%lX", rd_buf[i]);
					}else if(dsnDataLen == 1)
					{
						printf("0000000%lX", rd_buf[i]);
					}else if(dsnDataLen == 2)
					{
						printf("000000%lX", rd_buf[i]);
					}else if(dsnDataLen == 3)
					{
						printf("00000%lX", rd_buf[i]);
					}else if(dsnDataLen == 4)
                                        {
						printf("0000%lX", rd_buf[i]);
                                        }else if(dsnDataLen == 5)
                                        {
						printf("000%lX", rd_buf[i]);
                                        }else if(dsnDataLen == 6)
                                        {
						printf("00%lX", rd_buf[i]);
                                        }else if(dsnDataLen == 7)
                                        {
						printf("0%lX", rd_buf[i]);
					}else
					{
						/* Do Nothing */
					}	
				}else
				{
					printf("%lX", rd_buf[i]);
				}
			}
		}
#endif
else
		{	
			printf("Do Nothing\n");
		}
		printf("\n");
	}
 
	close(fd);
    	PRINTF("PCI Device [/dev/MS_PCI_DEV] closed\n");

	exit(0);
}
		
