//bw_real.c 
//cypress FX2   68013   measure the real bandwidth of the USB interface
//

//             (C) Marko Cebokli S57UUU  Oct 2006 
//             GNU/GPL licence:  www.gnu.org/licences/licences.html#GPL

//compile:  gcc -lusb bw_real.c -o bw_real

#include <stdio.h>
#include <usb.h>

int main()
{
struct usb_bus *p;
struct usb_device *q;
struct usb_device *current_device;
usb_dev_handle *current_handle;

unsigned char reset[2]={1,0};
unsigned char buffer[20000];
int er[10];
int endpoint=8;
int i,j,tlen,povp,max;
FILE *f;
unsigned char s[1024];
int length;
int addr;
int type;
unsigned char data[256];
unsigned char checksum,a;
unsigned int b;
unsigned short twait[10000];

usb_init();
er[2]=usb_find_busses();
er[3]=usb_find_devices();

p=usb_busses;
current_device=NULL;
while(p!=NULL)			//find the CY7C68013
	{q=p->devices;
	while(q!=NULL)
		{if ((q->descriptor.idVendor==0x4b4)&&(q->descriptor.idProduct==0x8613))
			current_device=q;
		q=q->next;}
	p=p->next;}
if (current_device==NULL)
	{printf("\n\nCould not find a CY7C68013\n\n");exit(0);}
fflush(stdout);

current_handle=usb_open(current_device);

er[4]=usb_control_msg(current_handle, 0x40, 0xa0, 0xE600, 0, reset, 1, 1000);     //RESET
sleep(0.1);

f=fopen("bw_real_fw.ihx", "r");		//load firmware from intel hex file
if (f==NULL)
	{printf("\n\nCould not find file: bw_real_fw.ihx\n\n");exit(0);}
while(!feof(f)){
	fgets(s, 1024, f); /* we should not use more than 263 bytes normally */
	sscanf(s+1, "%02x", &length);
	sscanf(s+3, "%04x", &addr);
	sscanf(s+7, "%02x", &type);
	if(type==0){
		printf("Programming %3d byte%s starting at 0x%04x", length, length==1?" ":"s", addr);
		a=length+(addr &0xff)+(addr>>8)+type;
		for(i=0;i<length;i++){
			sscanf(s+9+i*2,"%02x", &b);
			data[i]=b;
			a=a+data[i];}
		sscanf(s+9+length*2,"%02x", &b);
		checksum=b; if(((a+checksum)&0xff)!=0x00) printf("  ** Checksum bad");
		for(i=addr;i<addr+length;i+=16)
			{tlen=addr+length-i;
			if(tlen>16) tlen=16;
			er[5]=usb_control_msg(current_handle, 0x40, 0xa0, i, 0, data+(i-addr), tlen, 1000);}
		} else 
	if(type==0x01){
		printf("End of file\n");
		} else
	if(type==0x02){
		printf("Extended address?\n"); continue;
		}
	}
fclose(f);

er[6]=usb_control_msg(current_handle, 0x40, 0xa0, 0xE600, 0, reset+1, 1, 1000);   //UNRESET
sleep(0.1);

er[7]=usb_claim_interface(current_handle, 0);
er[8]=usb_set_altinterface(current_handle, 1);


struct timeval tv1,tv2,tv3,tvx[200];		//measure transfer speed
int usec,usec2,k,stat[1000],chunk,count[200];
int l;
gettimeofday(&tv1,NULL);
chunk=8192;
j=0;l=0;
for (k=0;k<10000;k++) twait[k]=0;
for (k=0;k<20000;k++) buffer[k]=0;
for (k=0;k<200;k++) count[k]=0;
for (k=0;k<200;k++)
	{
	stat[k]=usb_bulk_read(current_handle, endpoint, buffer, chunk, 1000);
	count[k]=buffer[0];
	for (i=0;i<(chunk/512);i++)
		{	
		twait[l]=buffer[512*i+2]+256*buffer[512*i+3];	//FW mu posilja samo 8 bitov!!!
		l++;
		}
	gettimeofday(&tv3,NULL);
	tvx[k]=tv3;
	j=j+stat[k];
	}
gettimeofday(&tv2,NULL);
usec=(1E6*tv2.tv_sec+tv2.tv_usec)-(1E6*tv1.tv_sec+tv1.tv_usec);if (usec<0) usec=usec+1000000;

//for (i=0;i<512;i++) printf(" %02x", buffer[i]);
//printf("\n\n");

/*
printf("\n Packet counter, increments by chunk/512 = %d: \n",chunk/512);
for (i=0;i<200;i++) printf(" %4d", count[i]);
printf("\n");
*/

/*
printf("\n Bytes per chunk: \n");
for (i=0;i<200;i++) printf(" %4d", stat[i]);
printf("\n");
*/

/*
printf("\n Time between chunks, us: \n");
for (i=0;i<199;i++) 
	{
	usec2=tvx[i+1].tv_usec-tvx[i].tv_usec;if (usec2<0) usec2=usec2+1000000;
	printf(" %4d",usec2);
	}
printf("\n");
*/

printf("\nChunk: %d    ",chunk);
printf("  %d  usec,  %d  bytes",usec,j);
printf("  =  %3.3f bytes/usec",(float)j/(float)usec);
printf("\n");

povp=0;max=0;
for (i=0;i<199;i++) 
	{
	usec2=tvx[i+1].tv_usec-tvx[i].tv_usec;if (usec2<0) usec2=usec2+1000000;
	povp=povp+usec2;
	if (usec2>max) max=usec2;
	}
povp=povp/199;
printf("\n Time between chunks - avg: %d   max: %d us\n",povp,max);

/*
printf("\n Dead times: \n");
for (i=0;i<(chunk/512*200);i++) if (twait[i]!=0) printf(" %4d=%4d,",i, twait[i]);
printf("\n");
*/

povp=0;max=0;
for (i=1;i<(chunk/512*200);i++)		//prvega preskocim
	 if (twait[i]!=0) 
		{
		povp++;
		if (twait[i]>max) max=twait[i];
		}
printf("\n Lost packets: %d (%3.2f%%)  Max wait: %d units \n",povp,100.0*((float)povp)/((float)chunk/512.0*200.0),max);

printf("\n");
usb_release_interface(current_handle, 0);
usb_close(current_handle);

return 0;
}
