#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

typedef struct {
        long int mtype;
        int webflag;
        char mtext[300];
}MESSAGE;

typedef struct
{
  unsigned char NeFailures;
  unsigned char FeFailures;
  unsigned char NeTCA1;
  unsigned char FeTCA1;
  unsigned char NeTCA2;
  unsigned char FeTCA2;
}ipos_pm_trigger;

#define FIFO_VDSLD "/tmp/fifo.vdsld"
#define FIFO_VDSL "/tmp/fifo.vdsl"
#define BUFSIZ 100

void vdsl_help(void);

main(int argc, char **argv)
{
   int mq_id;
   key_t key;
   MESSAGE msg;
   int type, vdebug = 0;
   char reconfirm;
   char cmd[20];
   ipos_pm_trigger PmTrigger;

   if((key = ftok("/etc/",'4')) == -1)
   {
	perror("vdsl_cleint: ftok() error");
	exit(-1);
   }
   mq_id = msgget(key, IPC_CREAT | IPC_EXCL | 0660);
   if((mq_id == -1) && (errno != EEXIST))
   {
        printf("\nerror in creating a Message Queue\n");
        perror("vdsl_client: msgget()");
        exit(1);
   }
   else if(errno == EEXIST)
   {
//        perror("vdsl_client: msgget() -- 2");
        mq_id = msgget(key, 0660);
   }

   if((argc < 2) || ((!strcasecmp(argv[1],"lpbk"))&&(argc!=3)))
   {
     printf("insufficient number of arguments\n");
     vdsl_help();
     exit(1);
   }
   strcpy(cmd,argv[1]);
   if(!strcmp(cmd,"web"))
   {
        if(argc<3)
        {
          printf("\nwrong command:%s\n",cmd);
          vdsl_help();
          exit(1);
        }
        strcpy(cmd,argv[2]);
        argc--;
        msg.webflag = 1;
   }
   else
   {
     msg.webflag = 0;
   }

   bzero(msg.mtext, sizeof(msg.mtext));

   if(!strcmp(cmd,"help"))
   {
	vdsl_help();
	exit(0);
   }
   else if(!strcmp(cmd,"breset"))
   {
	type = 2;
   }
   else if(!strcmp(cmd,"sysprov"))
   {
	type = 3;
   }
   else if(!strcmp(cmd,"pprov"))
   {
	type = 4;
   }
   else if(!strcmp(cmd,"pstart"))
   {
        type = 5;
   }
   else if(!strcmp(cmd,"pstop"))
   {
        type = 7;
   }
   else if(!strcmp(cmd,"lpbk"))
   {
        if(msg.webflag)
        {
          strcpy(msg.mtext, argv[3]);
        }
        else
        {
	 if((argc != 3) || (strcasecmp(argv[2],"utopia") && strcasecmp(argv[2],"AFE")))
	 {
	   printf("\n insufficient arguments or wrong loopback type\n");
	   printf("Usage: vdsl lpbk utopia/AFE\n");
	   exit(1);
 	 }
          strcpy(msg.mtext, argv[2]);
        }
         type = 9;
	strcpy(msg.mtext, argv[2]);
   }
   else if(!strcmp(cmd,"logc"))
   {
	type = 16;
   }
   else if(!strcmp(cmd,"triggerpm"))
   {
	type = 58;
	printf ("\nEnter Trigger-Word for Near-End Failures (in U16 Hex):");
	scanf ("%hx", &PmTrigger.NeFailures);
	printf ("\nEnter Trigger-Word for Far-End Failures (in U16 Hex):");
	scanf ("%hx", &PmTrigger.FeFailures);
	printf ("\nEnter Trigger-Word for Near-End TCA1 (in U16 Hex):");
	scanf ("%hx", &PmTrigger.NeTCA1);
	printf ("\nEnter Trigger-Word for Far-End TCA1 (in U16 Hex):");
	scanf ("%hx", &PmTrigger.FeTCA1);
	printf ("\nEnter Trigger-Word for Near-End TCA2 (in U16 Hex):");
	scanf ("%hx", &PmTrigger.NeTCA2);
	printf ("\nEnter Trigger-Word for Far-End TCA2 (in U16 Hex):");
	scanf ("%hx", &PmTrigger.FeTCA2);
	memcpy(msg.mtext, (unsigned char *)&PmTrigger, sizeof(PmTrigger));
   }
   else if(!strcmp(cmd,"clrcntr"))
   {
        type = 114;
   }
   else if(!strcmp(cmd,"pstat"))
   {
        type = 10;
   }
   else if(!strcmp(cmd,"pstatex"))
   {
        type = 11;
   }
   else if(!strcmp(cmd,"perfcntrs"))
   {
        type = 12;
   }
   else if(!strcmp(cmd,"getsnr"))
   {
        type = 13;
   }
   else if(!strcmp(cmd,"logp"))
   {
        type = 15;
   }
   else if(!strcmp(cmd,"devver"))
   {
        type = 90;
   }
   else if(!strcmp(cmd,"ohm"))
   {
	int case1, option, datalen, count;
	char *str_temp;

	type = 141;
	printf("\n Overhead Command Menu \n") ;
	printf("\n     1) Update Test Parameters") ;
	printf("\n     3) Get Commands List") ;
	printf("\n     4) Set Commands List") ;
	printf("\n     5) Single Read Test Param List") ;
	printf("\n     99) Exit");
	printf("\n\nSelect an option: ");
	scanf("%d",&case1);
	
	switch(case1)
	{
	  case 1:
	    msg.mtext[0] = 1;
	    break;

	  case 3:
            msg.mtext[0] = 3;
            printf(" Available Get Commands: \n\n") ;
            printf(" 1) Management Counters Read    2) Inventory ID\n") ;
            printf(" 3) Auxiliary ID                4) Self Test Result\n") ;

        //not available for VDSL2
#ifdef ADSL2
            printf(" 5) PMD Capability              6) PMD-TC Capability\n") ;
            printf(" 7) TPS-TC Capability           8) PMD Control\n") ;
            printf(" 9) PMS-TC Control Params      10) TPS-TC Control Params\n");
#endif	//ADSL2 only

	    printf("\nEnter Option: ") ;
	    scanf("%x",&option);
	    switch(option)
	    {
              case 0x1:
              case 0x2:
              case 0x3:
              case 0x4:
#ifdef ADSL2
              case 0x5:
              case 0x6:
              case 0x7:
              case 0x8:
              case 0x9:
              case 0x10:
#endif  //ADSL2 only
		msg.mtext[1] = option;
		break;

              default:
                printf ("\n\r Invalid Get Option:0x%x\r", option) ;
		exit(1);
	    }//switch - case 3
	    break;
	
	  case 4:
            msg.mtext[0] = 4;
	    printf("\nAvailable get commands:");
	    printf("\n1.  Clear EoC");
	    printf("\n99. Exit");
	    printf("\nEnter option: \n");
	    scanf("%d",&option);
	    if(option != 1)
	    {
		if(option == 99)
		  printf("\nexiting\n");
		else
		  printf("\nWrong option\n");
		exit(0);
	    }

	    str_temp = (char *)&(msg.mtext[1]);
	    do 
	    {
	      	printf("\n Enter Data Length (1-200): ");
	      	scanf("%d",&datalen);
	    }while((datalen > 200) ||	(datalen < 1));

            for (count = 0 ; count < datalen ; count++)
            {
                 printf("Byte[%d] (hex) is :", count) ;
		 scanf("%x",&option);
                 if ((option < 0) || (option > 255))
                 {
                    printf("Invalid Data Entered") ;
                    break ;
                  }

                 sprintf(str_temp, "%02x", option) ;
                 str_temp += 2 ;
            }
	    *str_temp = '\0' ;
	    break;

	  case 5:
              msg.mtext[0] = 5;
   	      printf(" Test Parameter Read Commands: \n\n") ;
       	      printf(" 1) Line Attenuation (LATN)\n") ;
       	      printf(" 2) Signal Attenuation (SATN)\n") ;
       	      printf(" 3) Signal-to-Noise Margin (SNRM)\n") ;
              printf(" 4) Attainable Net Data Rate (ATTNDR)\n") ;
       	      printf(" 5) Near-end Actual Aggregate Transmit Power (ACTATP-ne)\n") ;
              printf(" 6) Far-end Actual Aggregate Transmit Power (ACTATP-fe)\n") ;
	      printf("Enter Option: ") ;
	      scanf("%x",&option);

	      switch(option)
	      {
		  case 0x1:
                  case 0x2:
                  case 0x3:
                  case 0x4:
                  case 0x5:
                  case 0x6:
		    msg.mtext[1] = option;
		    break;

	          default:
		    printf("\n\r Invalid Test Param Option\n\r") ;
		    exit(1);
	      }
	      break;

	    default:
	      printf("\nwrong option\n");
	      exit(1);

	} //switch OHM
   }
   else if(!strcmp(cmd,"elm"))
   {
	type = 42;
	vdebug = 1;
   }
   else if(!strcmp(cmd,"70"))
   {
        type = 70;
        vdebug = 1;
   }
   else if(!strcmp(cmd,"678"))
   {
        type = 678;
        vdebug = 1;
   }
   else if(!strcmp(cmd,"679"))
   {
        type = 679;
        vdebug = 1;
   }
   else
   {
	printf("\nUnknown Command\n");
	vdsl_help();
	exit(1);
   }
   if(vdebug == 1)
   {
        int readfd, writefd, nread, nwrite;
        char buffer[BUFSIZ];

        bzero((void *)buffer, BUFSIZ);

        msg.mtype=type;
	if(msgsnd(mq_id, &msg, sizeof(msg.mtext), 0) < 0)
	{
	   perror("vdsl_client: vdebug = 1");
	   exit(-1);
	}

        sleep(1);
        if( (readfd = open(FIFO_VDSL,0)) < 0)
        {
          printf("\nVDSL: error in opening read FIFO\n");
          exit(0);
        }
        if( (writefd = open(FIFO_VDSLD,1)) < 0)
        {
          printf("\nVDSL: error in opening write FIFO\n");
          exit(0);
        }

        while(1)
        {
          if(nread = read(readfd, buffer, BUFSIZ) < 0)
          {
            printf("\nVDSL: Error in reading data from FIFO_VDSL: %d\n",errno);
            exit(0);
          }
          if(strcmp(buffer,"END")==0)
             exit(0);   //end of using 679 command; exit vdsl
          gets(buffer); //get the input from the STDIN from user

        /* write the command inputs to the FIFO_VDSLD */
          if(nwrite = write(writefd, buffer,BUFSIZ) < 0)
          {
            printf("\nVDSL: Error in writing data to FIFO_VDSLD: %d\n",errno);
            exit(0);
          }
        }

        close(readfd);
        close(writefd);
   }
   msg.mtype=type;
   if(msgsnd(mq_id, &msg, sizeof(msg.mtext), 0) < 0)
   {
	perror("vdsl_client: msgsnd()");
	exit(-1);
   }
   return;
}

void vdsl_help()
{
  printf("\nUsage:\nvdsl command [args]\n");
  printf("available options for command:\n");

  printf("breset        reset BME\n");
  printf("sysprov       BME System Provision\n");
  printf("pprov         BME Port Provision\n");
  printf("pstart        Port Start\n");
  printf("pstop         Port Stop\n");
  printf("pstat         Display Port Statistics briefly\n");
  printf("pstatex       Display Extended Port Statistics\n");
  printf("getsnr        print SNR (Signal-to-Noise Ratio)\n");
  printf("logp          Print Port Log Messages\n");
  printf("logc          Clear Port Log Messages\n");
  printf("perfcntrs     Print Performance Counters of the BME port\n");
  printf("clrcntr       Clear Performance Counters\n");
  printf("devver        Print BME Firmware Version\n");
  printf("triggerpm	Trigger PM Failures\n");
  printf("lpbk type     Start Loopback test where 'type' is utopia or AFE\n");
  printf("elm           Event Log Management\n");
  printf("70            Maintenance Mode\n");
  printf("678           BME Debug\n");
  printf("679           BME Ethernet Interface Debug\n");
  printf("help          Display help menu for vdsl command\n\n");
}
