#include <stdint.h>
#include <stdio.h>
#include <ftd2xx.h>
#include <libftdi/ftdi.h>
#include <signal.h>

#define DOT_DIV 100
int run =1;
void ctrl_c(int sig)
{
  run = 0;
}

int main(int argc, char **args)
{
  char const *desc    = 0;
  char const *serial  = 0;
  int vendor    = 0;
  int product   = 0;
  DWORD read;
  DWORD written;
  int nr_tests= 1;
  int latency = 1;
  int i;
  int res;
  int tms_bits;
  FT_HANDLE ftdi;   
  uint16_t value;
  uint8_t  buf[256]={ SET_BITS_LOW, 0x00, 0x0b,
		      TCK_DIVISOR,  0x00, 0x00 ,
		      SET_BITS_HIGH, ~0x84, 0x84};

  while(1) 
    {
      switch(getopt(argc, args, "?hD:L:P:s:V:t:T:")) 
	{
	case -1:
	  goto args_done;
	  
	case 'D':
	  desc = optarg;
	  break;
	  
	case 'V':
	  value = strtol(optarg, NULL, 0);
	  vendor = value;
	  break;
	  
	case 'L':
	  value = strtol(optarg, NULL, 0);
	  latency = value;
	  break;

	case 'P':
	  value = strtol(optarg, NULL, 0);
	  product = value;
	  break;
	  
	case 's':
	  serial = optarg;
	  break;
	
	case 't':
	  tms_bits = strtol(optarg, NULL, 0);
	  break;

	case 'T':
	  nr_tests = strtol(optarg, NULL, 0);
	  break;
	
	case '?':
	case 'h':
	default:
	  fprintf
	    ( stderr,
	      "\nUsage:\t%s [-D Product string] [-s SerialNumber string] [-V VID] [-P PID]\n", args[0]);
	  exit(255);
	}
    }
 args_done:

  if (vendor == 0)
    vendor = 0x403;
  if(product == 0)
    product = 0x6010;
  if (tms_bits >7)
    tms_bits = 7;
  else if (tms_bits < 1)
    tms_bits = 1;

  signal (SIGINT, ctrl_c);
  if (FT_SetVIDPID(vendor, product) !=  FT_OK)
       fprintf(stderr,"FT_SetVIDPID\n");
  else if(serial)
    res = FT_OpenEx((void*)serial, FT_OPEN_BY_SERIAL_NUMBER, &ftdi);
  else if(desc)
    res = FT_OpenEx((void*)desc, FT_OPEN_BY_DESCRIPTION, &ftdi);
  else
    res = FT_Open (0, &ftdi);
  if (res != FT_OK)
	fprintf(stderr,"Open FTDI failed\n");
  else if (FT_ResetDevice(ftdi) != FT_OK)
    fprintf(stderr,"Reset FTDI failed\n");
   
  else if (FT_SetBitMode(ftdi, 0x0b, 0x02) != FT_OK)
      fprintf(stderr,"Set Bitmode failed\n");
  else if(FT_SetLatencyTimer(ftdi,1) != FT_OK)
    fprintf(stderr,"FT_SetLatencyTimer failed\n");
  else if(FT_SetTimeouts(ftdi, 1000, 1000) != FT_OK)
    fprintf(stderr,"FT_SetTimeouts failed\n");

  if(FT_Write(ftdi, buf, 9, &written) != FT_OK)
    {
      fprintf(stderr,"FT_WRITE: Short write %ld vs %d\n", 
	      written, 9);
      goto err_exit;
    }
  buf[0] = 0x4b;
  buf[1] = (tms_bits-1);
  buf[2] = 0x85;
  buf[3] = 0x19;
  buf[4] = 0;
  buf[5] = 0;
  buf[6] = 0;
  buf[7] = 0x81;

  i =0;
  while(run && (i < nr_tests))
    {
      if(FT_Write(ftdi, buf, 8, &written) != FT_OK)
	{
	  fprintf(stderr,"\nShort write %ld vs %d at run %8d\n", 
		  written, 8, i);
	  goto err_exit;
	}
      if(i%DOT_DIV == (DOT_DIV-1))
	{
	  fprintf(stderr,".");
	  fflush(stderr);
	}
      i++;
      usleep(10000);
      if (FT_Read(ftdi, (void*)buf+10, 1, &read) != FT_OK)
	{
	  fprintf(stderr,"Short read at run %d %ld vs %d requested\n", 
		  i, read, 1);
	  //goto err_exit;
	}
    }
  fprintf(stderr,"\n");
  if (buf[10] & 0x08)
    fprintf(stdout,"Unexpected TMS value due to chip bug with %d tms_bits, Low Byte 0x%02x\n",
	    tms_bits, buf[10]);
  else
    fprintf(stdout,"All fine for  %d tms_bits!\n", tms_bits);
 err_exit:
  buf[0] = SET_BITS_LOW;
  buf[1] = 0x00;
  buf[2] = 0x00;
  FT_Write(ftdi, buf, 3, &written);
  FT_ResetDevice(ftdi);
  FT_Close(ftdi);
  return 0;
  }

