
// ***********************************************************
// Project: TWSUIO USB IO Interface
// Author: Dr. Simon Schroedle
// Module description: Basic USB handler
// Command line module
// This version: TIC4 Logger5
// ***********************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <time.h>

// this is libusb, see http://libusb.sourceforge.net/
#include <usb.h>

//twsuio functions
#define USB_INFOMSG 0

#define USB_RTIC 60
#define USB_RTIC1 60  //for debug

#define USB_RDPK 64 //read last datapack


#define USB_BMP085GETR 70

#define USB_BMP085INIT 71
#define USB_BMP085GETT 72
#define USB_BMP085GETP 73

#define USB_GTIME 80

#define USB_TSET1 81
#define USB_TSET2 82
#define USB_TSET3 83
#define USB_TSET  84 //set time based on values transfered by tset1...tset3

// used to get descriptor strings for device identification
static int usbGetDescriptorString(usb_dev_handle *dev, int index, int langid,
                                  char *buf, int buflen) {
    char buffer[256];
    int rval, i;

	// make standard request GET_DESCRIPTOR, type string and given index
    // (e.g. dev->iProduct)
	rval = usb_control_msg(dev,
        USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid,
        buffer, sizeof(buffer), 1000);

    if(rval < 0) // error
		return rval;

    // rval should be bytes read, but buffer[0] contains the actual response size
	if((unsigned char)buffer[0] < rval)
		rval = (unsigned char)buffer[0]; // string is shorter than bytes read

	if(buffer[1] != USB_DT_STRING) // second byte is the data type
		return 0; // invalid return type

	// we're dealing with UTF-16LE here so actual chars is half of rval,
	// and index 0 doesn't count
	rval /= 2;

	// lossy conversion to ISO Latin1
	for(i = 1; i < rval && i < buflen; i++) {
		if(buffer[2 * i + 1] == 0)
			buf[i-1] = buffer[2 * i];
		else
			buf[i-1] = '?'; // outside of ISO Latin1 range
	}
	buf[i-1] = 0;

	return i-1;
}

static usb_dev_handle * usbOpenDevice(int vendor, char *vendorName,
                                      int product, char *productName) {
	struct usb_bus *bus;
	struct usb_device *dev;
	char devVendor[256], devProduct[256];

	usb_dev_handle * handle = NULL;

	usb_init();
	usb_find_busses();
	usb_find_devices();

	for(bus=usb_get_busses(); bus; bus=bus->next) {
		for(dev=bus->devices; dev; dev=dev->next) {
			if(dev->descriptor.idVendor != vendor ||
               dev->descriptor.idProduct != product)
                continue;

            // we need to open the device in order to query strings
            if(!(handle = usb_open(dev))) {
                fprintf(stderr, "Warning: cannot open USB device: %s\n",
                    usb_strerror());
                continue;
            }

            // get vendor name
            if(usbGetDescriptorString(handle, dev->descriptor.iManufacturer, 0x0409, devVendor, sizeof(devVendor)) < 0) {
                fprintf(stderr,
                    "Warning: cannot query manufacturer for device: %s\n",
                    usb_strerror());
                usb_close(handle);
                continue;
            }

            // get product name
            if(usbGetDescriptorString(handle, dev->descriptor.iProduct,
               0x0409, devProduct, sizeof(devVendor)) < 0) {
                fprintf(stderr,
                    "Warning: cannot query product for device: %s\n",
                    usb_strerror());
                usb_close(handle);
                continue;
            }

            if(strcmp(devVendor, vendorName) == 0 &&
               strcmp(devProduct, productName) == 0)
                return handle;
            else
                usb_close(handle);
		}
	}

	return NULL;
}



const char *byte_to_binary(int x)
{
    static char b[9];
    b[0] = '\0';

    int z;
    for (z = 128; z > 0; z >>= 1)
    {
        strcat(b, ((x & z) == z) ? "1" : "0");
    }

    return b;
}

void wait_s01(int s01) //wait 100 ms intervals
{

	   clock_t ticks1, ticks2;

  ticks1=clock();
  ticks2=ticks1;
  while((ticks2/(CLOCKS_PER_SEC/10)-ticks1/(CLOCKS_PER_SEC/10))<s01)
    ticks2=clock();

}

usb_dev_handle *handle = NULL;
unsigned int datac,datax,datay,dataz;
int datac16;
long int datac32;
long int datab;
int nBytes = 0;
char buffer[256];
signed int mag_x,mag_y,mag_z;
double mx,my,mz,mphi,mag_scale;

unsigned long long datau64;

signed int unsigned_to_signed(unsigned int d_t)
{
    signed int datat;

    datat=d_t&0x7fff;
    if (d_t&0x8000)
    {
      datat=datat^0x7fff;
      datat=-datat;
    }
    return datat;
}

time_t my_timegm(register struct tm * t)
/* struct tm to seconds since Unix epoch */
{
    register long year;
    register time_t result;
#define MONTHSPERYEAR   12      /* months per calendar year */
    static const int cumdays[MONTHSPERYEAR] =
        { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };

    /*@ +matchanyintegral @*/
    year = 1900 + t->tm_year + t->tm_mon / MONTHSPERYEAR;
    result = (year - 1970) * 365 + cumdays[t->tm_mon % MONTHSPERYEAR];
    result += (year - 1968) / 4;
    result -= (year - 1900) / 100;
    result += (year - 1600) / 400;
    if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) &&
        (t->tm_mon % MONTHSPERYEAR) < 2)
        result--;
    result += t->tm_mday - 1;
    result *= 24;
    result += t->tm_hour;
    result *= 60;
    result += t->tm_min;
    result *= 60;
    result += t->tm_sec;
    if (t->tm_isdst == 1)
        result -= 3600;
    /*@ -matchanyintegral @*/
    return (result);
}

int main(int argc, char **argv) {

    unsigned char cbuffer[256], cdatas[16], cdatas2[16];
    int s_cnt,i;
    double mx_s,my_s,mz_s;
    time_t currenttime, timertc;
    struct tm * ptm;
    struct tm tinfo;
    char kc;


    double time_1,time_c, time_l, mul_t;
    double fadj;//time per tick

    double tdelta, tdelta1, tevents, tevent_base, tmean, n_event, mean_n;
    unsigned char tb, mreset,reset1;
    unsigned long long ltb,ltime_c,lmul_t, ltime_l;

    FILE *fd=NULL;
    FILE *fdev=NULL;

    char filename[256]="c:\\werkstatt\\ticdata.dat";
    char filenamedev[256]="c:\\werkstatt\\ticdev.dat";


	if(argc < 2) {
		printf("LOG5USB [Port/INF?] [Value/NONE]");
			exit(1);
	}

	handle = usbOpenDevice(0x16C0, "TWS@schroedle.de", 0x05DC, "TWSUIO R01");

	if(handle == NULL) {
		fprintf(stderr, "Could not find USB device!\n");
		exit(1);
	}

    datab=atoi(argv[2]);

    if(strcmp(argv[1], "INF?") == 0) {
		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_INFOMSG, 0, 0, (char *)buffer, sizeof(buffer), 5000);
        printf("INFOMSG Msg (%d bytes): %s\n", nBytes, buffer);
	} else
	 if(strcmp(argv[1], "RTIC") == 0) {
		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_RTIC, 0, 0, (char *)buffer, sizeof(buffer), 5000);
        printf("RTIC Msg (%d bytes): ", nBytes);
        for (i=0;i<nBytes;i++)
        {
          printf("%02x ",(unsigned char)buffer[i]);
        }
        printf("\n");
	} else
	 if(strcmp(argv[1], "RDPK") == 0) {
		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_RDPK, 0, 0, (char *)cbuffer, sizeof(cbuffer), 5000);
        printf("RDPK Msg (%d bytes):\n", nBytes);
        for (i=0;i<nBytes;i++)
        {
          printf("%02x",(unsigned char)cbuffer[i]);
        }
        printf("\n");

       if (nBytes==30)
       {


           datac16=0;
           datac16|=cbuffer[25];
           datac16=datac16<<8;
           datac16|=cbuffer[26];
           printf("Data set #%d\n",datac16);

           if (cbuffer[0]=='R')
           {
               printf("Re-transmitted dataset!\n");
           }

           printf("DS1302 UTC Time h:m:sec  : %02d:%02d:%02d\n", cbuffer[9],cbuffer[10],cbuffer[11]);
           printf("DS1302 UTC Date dd.mm.yy : %02d.%02d.%02d\n", cbuffer[12],cbuffer[13],cbuffer[14]);

           datac16=0;
           datac16|=cbuffer[3];
           datac16=datac16<<8;
           datac16|=cbuffer[4];

           printf("Temperature       [degC] : %0.1f\n", ((double)datac16)/10.0);

           datac32=0;
           datac32|=cbuffer[5];
           datac32=datac32<<8;
           datac32|=cbuffer[6];
           datac32=datac32<<8;
           datac32|=cbuffer[7];
           datac32=datac32<<8;
           datac32|=cbuffer[8];

		   printf("Pressure           [hPa] : %0.2f\n", ((double)datac32)/100.0);

           datau64=0;
		   datau64|=cbuffer[15];
		   datau64=datau64<<8;
		   datau64|=cbuffer[16];
		   datau64=datau64<<8;
		   datau64|=cbuffer[17];
		   datau64=datau64<<8;
		   datau64|=cbuffer[18];
		   datau64=datau64<<8;
		   datau64|=cbuffer[19];
		   datau64=datau64<<8;
		   datau64|=cbuffer[20];
		   datau64=datau64<<8;
		   datau64|=cbuffer[21];
		   datau64=datau64<<8;
		   datau64|=cbuffer[22];

           printf("Timestamp [counts] [sec] : %I64d %0.7f\n", datau64, ((double)datau64)/16e6);


       } else
        {
            printf("Datapackage has incorrect length!\n");

            printf("Received Msg (%d bytes):\n", nBytes);
            for (i=0;i<nBytes;i++)
            {
              printf("%02x",(unsigned char)cbuffer[i]);
            }
             printf("\n");
        }

	} else
	 if(strcmp(argv[1], "RDPKR") == 0) {
       time_1=-100.0;
       fadj=1/16e6;
       mean_n=5; //how many averages for running mean?
       tmean=0.0;
       tevent_base=1.0/6.0; //prox time per event - for counting

       mreset=1;//resets mean calc

       tevents=0.0;

       kc='a';
       printf("press <x> to end, <r> to reset averaging\n");
       printf("Intervals: itime ravg%0.0f ppm s/day\n",mean_n);


       fd = fopen(filename,"w");
       fdev = fopen(filenamedev,"w"); //time and frequency


       while(kc!='x')
       {

		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_RDPK, 0, 0, (char *)cbuffer, sizeof(cbuffer), 5000);
       /* printf("RDPK Msg (%d bytes):\n", nBytes);
        for (i=0;i<nBytes;i++)
        {
          printf("%02x",(unsigned char)cbuffer[i]);
        }
        printf("\n");*/

       if (nBytes==30)
       {

           if (cbuffer[0]=='R')
           {
               //printf("Already captured!");
           } else
           {


           datac16=0;
           datac16|=cbuffer[25];
           datac16=datac16<<8;
           datac16|=cbuffer[26];
           printf("%d ",datac16);
           fprintf(fd,"%d ",datac16);



           printf("%02d:%02d:%02d ", cbuffer[9],cbuffer[10],cbuffer[11]);
           printf("%02d.%02d.%02d ", cbuffer[12],cbuffer[13],cbuffer[14]);

           fprintf(fd,"%02d:%02d:%02d ", cbuffer[9],cbuffer[10],cbuffer[11]);
           fprintf(fd,"%02d.%02d.%02d ", cbuffer[12],cbuffer[13],cbuffer[14]);

           tinfo.tm_year = 2000+cbuffer[14] - 1900;
           tinfo.tm_mon = cbuffer[13]-1;
           tinfo.tm_mday = cbuffer[12];
           tinfo.tm_hour = cbuffer[9];
           tinfo.tm_min = cbuffer[10];
           tinfo.tm_sec = cbuffer[11];
           tinfo.tm_isdst = 0; //utc basis

           timertc = my_timegm(&tinfo); //utc

           //printf("%d %d\n",timertc);
           fprintf(fd,"%d ",timertc);//unix utc time stamp


           datac16=0;
           datac16|=cbuffer[3];
           datac16=datac16<<8;
           datac16|=cbuffer[4];

           printf("%0.1f ", ((double)datac16)/10.0);
           fprintf(fd,"%0.1f ", ((double)datac16)/10.0);

           datac32=0;
           datac32|=cbuffer[5];
           datac32=datac32<<8;
           datac32|=cbuffer[6];
           datac32=datac32<<8;
           datac32|=cbuffer[7];
           datac32=datac32<<8;
           datac32|=cbuffer[8];

		   printf("%0.2f ", ((double)datac32)/100.0);
		   fprintf(fd,"%0.2f ", ((double)datac32)/100.0);

           datau64=0;
		   datau64|=cbuffer[15];
		   datau64=datau64<<8;
		   datau64|=cbuffer[16];
		   datau64=datau64<<8;
		   datau64|=cbuffer[17];
		   datau64=datau64<<8;
		   datau64|=cbuffer[18];
		   datau64=datau64<<8;
		   datau64|=cbuffer[19];
		   datau64=datau64<<8;
		   datau64|=cbuffer[20];
		   datau64=datau64<<8;
		   datau64|=cbuffer[21];
		   datau64=datau64<<8;
		   datau64|=cbuffer[22];

           printf("%I64d %0.7f\n", datau64, ((double)datau64)/16e6);
           fprintf(fd,"%I64d %0.7f\n", datau64, ((double)datau64)/16e6);


           //time and drift calc
           time_c=((double)datau64);
           if (time_1<0.0) {time_1=time_c;}
           if (reset1) {
              time_1=time_c;
              mreset=1;
              tevents=0;
              reset1=0;
           }
           tdelta=(time_c-time_l)*fadj;


           if (time_c>time_1) {
            n_event=round(tdelta/tevent_base); //determine number of events

            if (n_event<1)
            {
               printf("Error! Interval was too short!\n");
            } //else {printf("%f events\n",n_event);}

            tevents+=n_event;
            if (mreset) {tmean=tdelta/n_event; mreset=0;}

            tmean=(tmean*mean_n+tdelta/n_event)/(mean_n+1.0);  //running mean

            if (((tmean/tevent_base)<0.9)||((tmean/tevent_base)>1.1)||(tmean!=tmean) )
            {
                mreset=1;
                tmean=-9999.0;
            }

            printf("%8.0f: %12.7f ** %12.7f  %8.3f %8.3f \n", tevents, tdelta/n_event, tmean, ((tmean-tevent_base)/tevent_base)*1e6,((tmean-tevent_base)/tevent_base)*24*3600/1.0);
            //fprintf(fdev,"%0.7f %0.7f\n", tdelta, tdelta-(n_event*tevent_base)); //sampling interval, phase deviation
            fprintf(fdev,"%0.0f %0.7f\n",tevents, (time_c-time_1)*fadj-(tevents*tevent_base)); //sampling interval, phase deviation

           }
             time_l=time_c;



           //end time and drift calc



           }

       } else
        {
            printf("*** Datapackage has incorrect length!\n");
            printf("Received Msg (%d bytes):\n", nBytes);
            for (i=0;i<nBytes;i++)
            {
              printf("%02x",(unsigned char)cbuffer[i]);
            }
             printf("\n");
            if(nBytes < 0)
            {
		        fprintf(stderr, "USB error: %s\n", usb_strerror());

	           usb_close(handle);

            }

             if (nBytes==-5)
             {
                 Sleep(2000);
                 printf("*** Trying to reconnect!\n");
                 handle == NULL;
                 printf("*** Trying to reconnect!  1\n");
                 handle = usbOpenDevice(0x16C0, "TWS@schroedle.de", 0x05DC, "TWSUIO R01");
                 printf("*** Trying to reconnect!  2\n");
	             if(handle == NULL) {
		             fprintf(stderr, "Could not find USB device!\n");

	              }
	             printf("*** Trying to reconnect!  3\n");
             }
        }

        if (kbhit()) { kc=getch();  if (kc=='r') {reset1=1;} }
          Sleep(100); //wait 100 ms

       }

       fclose(fd);
       fclose(fdev);


	}
	else
	 if(strcmp(argv[1], "RTIC1") == 0) {
		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_RTIC1, 0, 0, (char *)buffer, sizeof(buffer), 5000);
        printf("RTIC1 Msg (%d bytes): %s\n", nBytes, buffer);
	} else
	 if(strcmp(argv[1], "TSET") == 0) {

         //get current time


         time ( &currenttime );
         ptm = gmtime ( &currenttime );


         printf ("UTC Time h:m:sec  : %02d:%02d:%02d\n", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
         printf ("UTC Date dd.mm.yy : %02d.%02d.%02d\n", ptm->tm_mday, (ptm->tm_mon)+1, ptm->tm_year-100);

         //set time if RTC DS1302



		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_TSET1, (ptm->tm_hour<<8)| ptm->tm_min , 0, (char *)buffer, sizeof(buffer), 5000);
        printf("TSET1 done.\n");
        nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_TSET2, (ptm->tm_sec<<8)|ptm->tm_mday, 0, (char *)buffer, sizeof(buffer), 5000);
        printf("TSET2 done.\n");
        nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_TSET3,(((ptm->tm_mon)+1)<<8)| (ptm->tm_year-100), 0, (char *)buffer, sizeof(buffer), 5000);
        printf("TSET3 done.\n");
        nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_TSET, 0, 0, (char *)buffer, sizeof(buffer), 5000);
        printf("TSET done. Time has been set!\n");

	} else
    if(strcmp(argv[1], "GTIME") == 0) {
		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_GTIME, 0, 0, (char *)buffer, sizeof(buffer), 5000);

        printf("GTIME Msg (%d bytes): ", nBytes);
        for (i=0;i<6;i++)
        {
            printf("%d ",buffer[i]);
        }
        printf("\n");
        printf ("DS1302 UTC Time h:m:sec  : %02d:%02d:%02d\n", buffer[0],buffer[1],buffer[2]);
        printf ("DS1302 UTC Date dd.mm.yy : %02d.%02d.%02d\n", buffer[3],buffer[4],buffer[5]);

	} else

    if(strcmp(argv[1], "GETR") == 0) {

		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_BMP085GETR, 0, 0, (char *)cbuffer, sizeof(cbuffer), 5000);
			//printf("Msg (%d bytes): >%s<\n", nBytes, cbuffer);

            datac16=(int) cbuffer[0];
            datac16=datac16<<8;
            datac16+=((int) cbuffer[1]);

			printf("GETR read (%d bytes): >%d<  0x%x\n", nBytes, datac,datac);
     }

     else if(strcmp(argv[1], "BINIT") == 0) {

		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_BMP085INIT, 0, 0, (char *)cbuffer, sizeof(cbuffer), 5000);
			//printf("Msg (%d bytes): >%s<\n", nBytes, cbuffer);

            datac=(int) cbuffer[0];
            datac=datac<<8;
            datac+=((int) cbuffer[1]);

			printf("BINIT read (%d bytes): >%d<  0x%x\n", nBytes, datac,datac);

			if (datac==0x4041)
            {
                printf("BMP085 initialized OK!\n");
            } else
            {
                printf("BMP085 init error!\n");
            }
     }
     else if(strcmp(argv[1], "GETT") == 0) {

		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_BMP085GETT, 0, 0, (char *)cbuffer, sizeof(cbuffer), 5000);
			//printf("Msg (%d bytes): >%s<\n", nBytes, cbuffer);

            datac16=(int) cbuffer[0];
            datac16=datac16<<8;
            datac16+=((int) cbuffer[1]);

			printf("GETT read (%d bytes): >%d<  0x%x\n", nBytes, datac16,datac16);
            printf("Temperature [degC]: %0.1f\n", ((double)datac16)/10.0);
     }
     else if(strcmp(argv[1], "GETP") == 0) {

		nBytes = usb_control_msg(handle,
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
			USB_BMP085GETP, 0, 0, (char *)cbuffer, sizeof(cbuffer), 5000);
			//printf("Msg (%d bytes): >%s<\n", nBytes, cbuffer);

            datac32=(int) cbuffer[0];
            datac32=datac32<<8;
            datac32+=((int) cbuffer[1]);
            datac32=datac32<<8;
            datac32+=((int) cbuffer[2]);
            datac32=datac32<<8;
            datac32+=((int) cbuffer[3]);

			printf("GETP read (%d bytes): >%d<  0x%x\n", nBytes, datac32,datac32);
		    printf("Pressure [hPa]: %0.2f\n", ((double)datac32)/100.0);
     }
      else

    {
       printf("\nError! Unknown command!\n");

    }

	if(nBytes < 0)
		fprintf(stderr, "USB error: %s\n", usb_strerror());

	usb_close(handle);

	return 0;
}
