#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include "_mpusbapi.h"

#define EPSIZE 64               // endpoint packet size in bytes
#define USBTIMEOUT 200          // in milliseconds...
#define BOOT_EP_SIZE 64

DWORD temp;
// Global Vars
char vid_pid[]= "vid_04d8&pid_000b";    // Default Demo Application Firmware
char out_pipe[]= "\\MCHP_EP1";
char in_pipe[]= "\\MCHP_EP1";
HANDLE myOutPipe;
HANDLE myInPipe;

tm* theLocalTime;

typedef enum{
            READ_VERSION            = 0x00,
            READ_FLASH              = 0x01,
            WRITE_FLASH             = 0x02,
            ERASE_FLASH             = 0x03,
            READ_EEDATA             = 0x04,
            WRITE_EEDATA            = 0x05,
            READ_CONFIG             = 0x06,
            WRITE_CONFIG            = 0x07,
            UPDATE_LED              = 0x32,
			WINPIC_GETOKBUTTON 		= 0x50,
			WINPIC_GETDATAINBIT 	= 0x51,
			WINPIC_SETLEDS			= 0x52,
			WINPIC_SETVPP			= 0x53,
			WINPIC_SETVDD			= 0x54,
			WINPIC_SETCLOCKANDDATA	= 0x55,
			WINPIC_SETCLOCKENABLE	= 0x56,
			WINPIC_SETDATAENABLE	= 0x57,
			WINPIC_PULLMCLRTOGND	= 0x58,
			WINPIC_CONNECTTARGET	= 0x59,
			USB_CLOCK_SET = 0x70,
            RESET           = 0xFF
			
        }CMD;

typedef struct
            {
                byte low;                   //Little-endian order
                byte high;
                byte upper;
            }ADR;
        
typedef union _BOOT_DATA_PACKET
{
    byte _byte[64];  // For Byte Access
    struct
    {
        
        byte cmd;
        byte len;
        ADR pAdr;
        byte data[EPSIZE-5];
    };
    
    // for UPDATE_LEDS command
    struct
    {
        unsigned :8;
        byte led_num;
        byte led_status;
    };
        
    // for WINPIC_GETOKBUTTON COMMAND
	struct
	{
		unsigned :8;
		byte ok_button;
	};

	// for WINPIC_DATAINBIT COMMAND
	struct
	{
		unsigned :8;
		byte	data_in_bit;
	};

	// for WINPIC_SETLEDS COMMAND
	struct
	{
		unsigned :8;
		byte led_bank;
	};

	// for WINPIC_SETVPP COMMAND
	struct
	{
		byte 	vpp_level;
		float	vpp_voltage;
	};

	// for WINPIC_SETVDD COMMAND

	struct
	{
		byte	vdd_level;
		float	vdd_voltage;
	};

	// for WINPIC_SETCLOCKANDDATA COMMAND

	struct
	{
		unsigned :8;
		byte	pgc;
		byte	pgd;
	};

	// for WINPIC_SETCLOCKENABLE COMMAND

	struct
	{
		unsigned :8;
		byte	clockenable;
	};

	// for WINPIC_SETDATAENABLE COMMAND

	struct
	{
		unsigned :8;
		byte	dataenable;
	};

	// for WINPIC_PULLMCLRTOGND COMMAND

	struct
	{
		unsigned :8;
		byte 	mclr;
	};

	// for WINPIC_CONNECTTARGET COMMAND

	struct
	{
		unsigned :8;
		byte	connection;
	};

	// for USB_CLOCK_SET

	struct
	{
		unsigned :8;
		byte 	hours;
		byte	minutes;
		byte 	seconds;
		byte	day;
		byte	month;
		byte	year;
	};
        
} BOOT_DATA_PACKET;

void GetSummary(void)
{
    HANDLE tempPipe = INVALID_HANDLE_VALUE;
    DWORD count = 0;
    DWORD max_count;

    max_count = MPUSBGetDeviceCount(vid_pid);

    printf("\r\n%d device(s) with %s currently attached\r\n",max_count,vid_pid);

    // Note:
    // The total number of devices using the generic driver could be
    // bigger than max_count. They could have different vid & pid numbers.
    // This means if max_count is 2, the valid instance index do not
    // necessary have to be '0' and '1'.
    //
    // Below is a sample code for searching for all valid instance indexes.
    // MAX_NUM_MPUSB_DEV is defined in _mpusbapi.h
    
    count = 0;
    for(int i = 0; i < MAX_NUM_MPUSB_DEV; i++)
    {
        tempPipe = MPUSBOpen(i,vid_pid,NULL,MP_READ,0);
        if(tempPipe != INVALID_HANDLE_VALUE)
        {
            printf("Instance Index # %d\r\n",i);
            MPUSBClose(tempPipe);
            count++;
        }
        if(count == max_count) break;
    }//end for
    printf("\r\n");
}//end GetSummary

void
hex_print(byte* data, int length)
{
	int ptr = 0;
	for(;ptr < length;ptr++)
	{
		printf("0x%02x ",(unsigned char)*(data+ptr));
	}
}

void showPacket(byte *pp, int total)
{
 int u, v;
     for(u=0; u<total; u++)
     {
     printf(" "); 
     hex_print(pp, 1); 
     pp++;
     if((u & 0x0007)==0x0007){
                pp-=8;
                printf("  ");
                for(v=0; v<8; v++)printf("%c",*pp++);
                printf("\n");
            }
     }  
}


int updateTime(void)
{

        time_t t;
        const time_t *ltm;
        char mystring[256];
        t=time(NULL);
        ltm=&t;
        theLocalTime=localtime(ltm);
//        printf("Hours: %d Minutes: %d Seconds: %d\r\n",theLocalTime->tm_hour, theLocalTime->tm_min, theLocalTime->tm_sec);
        return 0;
}

int main(int argc, char *argv[])
{
    byte current_command=UPDATE_LED;                   // default value...
    BOOLEAN bQuit;
    char selection;
    DWORD maxn;
    DWORD res;
    bQuit = false;
    DWORD nb;
    BOOT_DATA_PACKET datapacket;
    BOOT_DATA_PACKET indatapacket;
    int jj,j,i;
    int k=0;
    int open=0;
    byte ledcounter=0;
    byte pgccounter=0;
            
    open=0x00;
    printf("USB interface using MPUSB API.\nMauro Grassi, May 2008.\n");
    printf("Size of datapacket...... ");
    if(sizeof(datapacket)==EPSIZE)printf("Ok.\n"); else {
                                                        printf("Error.\n"); 
                                                        printf("Size is: %d.\nShould be: %d.\n", sizeof(datapacket), EPSIZE);
                                                        return -1; }
                                                        
    for(i=0; i<EPSIZE;i++){ datapacket._byte[i]=0xFF; indatapacket._byte[i]=0xFF; }
    datapacket.cmd=current_command;
    temp=MPUSBGetDLLVersion();
    printf("MPUSBAPI Version: %d.%d\r\n",HIWORD(temp),LOWORD(temp));
    myOutPipe= myInPipe = INVALID_HANDLE_VALUE;
    
    while(!bQuit)
    {
        printf("[1] Get MPUSBAPI Version\r\n");
        printf("[2] Summarize Instances\r\n");
        printf("[3] Open USB device\r\n");
        printf("[4] Send and Receive Command Packets\r\n");
        printf("[5] Set Command\r\n");
        printf("[6] Update Time\r\n");
        printf("[7] Update Time Continuous\r\n");
        printf("[X] Quit\r\n>>");
        fflush(stdin);
        scanf("%c",&selection);        
        switch(selection)
        {
            case '1':
                temp = MPUSBGetDLLVersion();
                printf("MPUSBAPI Version: %d.%d\r\n",HIWORD(temp),LOWORD(temp));
                break;
            case '2':
                GetSummary();
                break;
            case '3':
                if(open==0){
                maxn = MPUSBGetDeviceCount(vid_pid);
                myOutPipe = INVALID_HANDLE_VALUE;
                myOutPipe = MPUSBOpen(0,vid_pid,out_pipe,MP_WRITE,0);
                myInPipe  = INVALID_HANDLE_VALUE;
                myInPipe  = MPUSBOpen(0,vid_pid,in_pipe,MP_READ,0);
                printf("USB Device Open...... ");
                if((myInPipe!=INVALID_HANDLE_VALUE)&&(myOutPipe!=INVALID_HANDLE_VALUE))
                {
                 printf("Ok.\n");
                 open=1;
                 }
                 else
                 {
                 printf("Error.\n");
                 open=0;
                 }
                }
                else printf("Device is already open.\n");
                break;
            case '4':
                 if(open!=0)
                 {
                 datapacket.cmd=current_command;
                 printf("Write Data...... ");
                 res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                 
                 if(res==MPUSB_SUCCESS)
                 {
                     printf("Ok. Bytes written= %d.\n", nb);
                     showPacket(&datapacket._byte[0],nb);
                 }
                 else
                 {
                         printf("Error.\n");
                         break;
                 }
                 printf("Read Data...... ");
                 res=MPUSBRead(myInPipe, &indatapacket, 64, &nb, 500);
                 
                 if(res==MPUSB_SUCCESS)
                 { 
                     printf("OK. Bytes read= %d.\n", nb);
                     showPacket(&indatapacket._byte[0],nb);
                 }
                 else
                 {
                     printf("Error.\n");
                     break;      
                 }
                 }
                 else
                 {
                     printf("Device is not open!\n");
                 }
                 break;
            case '5':
                 printf(" [a] GET OK BUTTON  \r\n");
                 printf(" [b] GET DATA IN BIT \r\n");
                 printf(" [c] SET LEDS \r\n");
                 printf(" [d] SET VPP      \r\n");
                 printf(" [e] SET VDD \r\n");
                 printf(" [f] SET CLOCK AND DATA \r\n");
                 printf(" [g] SET CLOCK ENABLE \r\n");
                 printf(" [h] SET DATA ENABLE \r\n");
                 printf(" [i] PULL MCLR TO GND \r\n");
                 printf(" [j] CONNECT TARGET \r\n");
                 printf(" [k] USB_CLOCK_SET \r\n");
                 fflush(stdin);
                 scanf("%c",&selection);
                 switch(selection)
                 {
                  case 'a':
                       current_command=WINPIC_GETOKBUTTON;
                       break;
                  case 'b':
                       current_command=WINPIC_GETDATAINBIT;
                       break;
                  case 'c':
                       current_command=WINPIC_SETLEDS;
                       datapacket.led_bank=ledcounter;
                       ledcounter++;
                       break;
                  case 'd':
                       current_command=WINPIC_SETVPP;
                       datapacket.vpp_level=1;
                       datapacket.vpp_voltage=13.0;
                       break;
                  case 'e':
                       current_command=WINPIC_SETVDD;
                       datapacket.vdd_level=1;
                       datapacket.vdd_voltage=5.0;
                       break;
                  case 'f':
                       current_command=WINPIC_SETCLOCKANDDATA;
                       datapacket.pgc=(pgccounter & 0x01);
                       datapacket.pgd=(pgccounter & 0x02)>>1;
                       pgccounter++;
                       break;
                  case 'g':
                       current_command=WINPIC_SETCLOCKENABLE;
                       break;
                  case 'h':
                       current_command=WINPIC_SETDATAENABLE;
                       break;
                  case 'i':
                       current_command=WINPIC_PULLMCLRTOGND;
                       break;
                  case 'j':
                       current_command=WINPIC_CONNECTTARGET;
                       break;
                  case 'k':
                       current_command=USB_CLOCK_SET;
                       datapacket.minutes=0x13;
                       break;
                  default:
                       break;               
                 }
                 datapacket.cmd=current_command;
                 printf("Ready to send......\n");
                 showPacket(&datapacket._byte[0],8);
                 break;
            case '6':
                updateTime();
                current_command=USB_CLOCK_SET;
                datapacket.hours=theLocalTime->tm_hour;
                datapacket.minutes=theLocalTime->tm_min;
                datapacket.seconds=theLocalTime->tm_sec;
                printf("Updating Time...\r\n");
                printf("Hours: %d Minutes: %d Seconds: %d\r\n", datapacket.hours, datapacket.minutes, datapacket.seconds);
                if(open!=0)
                 {
                 datapacket.cmd=current_command;
                 printf("Write Data...... ");
                 res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                 
                 if(res==MPUSB_SUCCESS)
                 {
                     printf("Ok. Bytes written= %d.\n", nb);
                     showPacket(&datapacket._byte[0],nb);
                 }
                 else
                 {
                         printf("Error.\n");
                         printf("Closing ALL Handles.\n");
                         MPUSBClose(myInPipe);
                         MPUSBClose(myOutPipe);
                         open=0;
                         break;
                 }
                 printf("Read Data...... ");
                 res=MPUSBRead(myInPipe, &indatapacket, 64, &nb, 500);
                 
                 if(res==MPUSB_SUCCESS)
                 { 
                     printf("OK. Bytes read= %d.\n", nb);
                     showPacket(&indatapacket._byte[0],nb);
                 }
                 else
                 {
                     printf("Error.\n");
                     printf("Closing ALL Handles.\n");
                     MPUSBClose(myInPipe);
                     MPUSBClose(myOutPipe);
                     open=0; 
                     break;      
                 }
                 }
                 else
                 {
                     printf("Device is not open!\n");
                 }
               break;
           case '7':
                for(jj=0; jj<60;jj++)
                {
                                
                updateTime();
                current_command=USB_CLOCK_SET;
                datapacket.hours=theLocalTime->tm_hour;
                datapacket.minutes=theLocalTime->tm_min;
                while(datapacket.seconds==theLocalTime->tm_sec)updateTime();
                datapacket.seconds=theLocalTime->tm_sec;
                printf("Updating Time...\r\n");
                printf("Hours: %d Minutes: %d Seconds: %d\r\n", datapacket.hours, datapacket.minutes, datapacket.seconds);
                if(open!=0)
                 {
                 datapacket.cmd=current_command;
                 printf("Write Data...... ");
                 res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                 
                 if(res==MPUSB_SUCCESS)
                 {
                     printf("Ok. Bytes written= %d.\n", nb);
                     showPacket(&datapacket._byte[0],nb);
                 }
                 else
                 {
                         printf("Error.\n");
                 
                 }
                 printf("Read Data...... ");
                 res=MPUSBRead(myInPipe, &indatapacket, 64, &nb, 500);
                 
                 if(res==MPUSB_SUCCESS)
                 { 
                     printf("OK. Bytes read= %d.\n", nb);
                     showPacket(&indatapacket._byte[0],nb);
                 }
                 else
                 {
                     printf("Error.\n");
                 
                 }
                 }
                 else
                 {
                     printf("Device is not open!\n");
                 }
                   
                    
                }
               break;
            case 'X':
                bQuit = true;
                break;
            default:
                break;
        }// end switch

        fflush(stdin);printf("\r\n");
    }//end while
    // Always check to close all handles before exiting!
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    return 0;
}//end main

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

