/********************************************************************
 FileName:     generic_hid.c
 Dependencies: See INCLUDES section
 Processor:    PIC18 USB Microcontrollers
 Hardware:
 Complier:     Microchip C18
 Company:		Microchip Technology, Inc.

 Software License Agreement:

 The software supplied herewith by Microchip Technology Incorporated
 (the “Company”) for its PICmicro® Microcontroller is intended and
 supplied to you, the Company’s customer, for use solely and
 exclusively on Microchip PICmicro Microcontroller products. The
 software is owned by the Company and/or its supplier, and is
 protected under applicable copyright laws. All rights are reserved.
 Any use in violation of the foregoing restrictions may subject the
 user to criminal sanctions under applicable laws, as well as to
 civil liability for the breach of the terms and conditions of this
 license.

 THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
 WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.

********************************************************************
 File Description:

 Change History:
  Rev   Date         Description
 
  1.0   5/5/2008     Converted Microchip's mouse.c for use in a
                     generic HID (Jan Axelson)	
  1.1   6/21/08      Revised ReportLoopback routine.
  1.2   9/16/08      Revised for use with Microchip Framework V2.2
  1.3   9/30/08      Revised Set_Report code
  1.4   10/4/08      Upgraded for Microchip Framework V2.3. 
					 Required adding LSB macro to generic_hid.h
  1.5   12/24/08     Deleted unneeded edit to usb_device.c


********************************************************************/
/*
Handles application-specific tasks.

See the project's readme file for more information.
*/

/** INCLUDES *******************************************************/
//#include "GenericTypeDefs.h"
//#include "Compiler.h"
//#include "usb_config.h"
//#include "./USB/usb_device.h"
//#include "./USB/usb.h"
//#include "HardwareProfile.h"
#include "./USB/usb.h"
#include "HardwareProfile.h"
#include "./USB/usb_function_hid.h"
#include "generic_hid.h" 

/** CONFIGURATION **************************************************/
#if defined(PICDEM_FS_USB)      // PIC18F4550 is used
//    #pragma config PLLDIV = 5       // (20 MHz input)
//    #pragma config CPUDIV = OSC1_PLL2
//    #pragma config USBDIV = 2       // Clock source from 96MHz PLL/2
//    #pragma config FOSC = HSPLL_HS
    //#pragma config FCMEN = OFF
//    #pragma config IESO = OFF
//    #pragma config PWRT = ON
//    #pragma config BOR = ON
//    #pragma config BORV = 2
//    #pragma config VREGEN = ON
//    #pragma config WDT = OFF
    //#pragma config WDTPS = 32768
//    #pragma config MCLRE = ON
//    #pragma config LPT1OSC = OFF
//    #pragma config PBADEN = OFF
//    #pragma config STVREN = ON
//    #pragma config LVP = OFF
 //   #pragma config ICPRT = OFF      // Dedicated In-Circuit Debug/Programming
//    #pragma config XINST = OFF      // Extended Instruction Set
    //#pragma config XINST = ON      // Extended Instruction Set
//    #pragma config WRTC = OFF
//    #pragma config WRT0 = OFF
//    #pragma config WRT1 = OFF
//    #pragma config WRTB = OFF        // Boot Blok Write Protection
    /*
    #pragma config CP0 = ON
    #pragma config CP1 = ON
    #pragma config CPB = ON
    */
 //   #pragma config CP0 = OFF
//    #pragma config CP1 = OFF
//    #pragma config CPB = OFF

#elif defined(PIC18F87J50_PIM)
    #pragma config PLLDIV = 3       
    #pragma config CPUDIV = OSC1
    #pragma config FOSC = HSPLL
    //#pragma config FCMEN = OFF
    #pragma config IESO = OFF
    //#pragma config PWRT = ON
    //#pragma config BOR = ON
    //#pragma config BORV = 2
    //#pragma config VREGEN = ON
    #pragma config WDTEN = OFF
    //#pragma config WDTPS = 32768
    //#pragma config MCLRE = ON
    //#pragma config LPT1OSC = OFF
    //#pragma config PBADEN = OFF
    //#pragma config STVREN = ON
    //#pragma config LVP = OFF
    //#pragma config ICPRT = OFF      // Dedicated In-Circuit Debug/Programming
    #pragma config XINST = OFF      // Extended Instruction Set
    //#pragma config WRTC = OFF
    //#pragma config WRT0 = OFF
    //#pragma config WRT1 = OFF
    //#pragma config WRTB = OFF        // Boot Blok Write Protection
    /*
    #pragma config CP0 = ON
    #pragma config CP1 = ON
    #pragma config CPB = ON
    */
    #pragma config CP0 = OFF
    //#pragma config CP1 = OFF
    //#pragma config CPB = OFF
    #pragma config MODE = MM

#elif defined(EXPLORER_16)
    #ifdef __PIC24FJ256GB110__ //Defined by MPLAB when using 24FJ256GB110 device
        _CONFIG1( JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx2 & IOL1WAY_ON) 
        _CONFIG2( 0xF7FF & IESO_OFF & FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMOD_HS & FNOSC_PRIPLL & PLLDIV_DIV2)
    #else
        #error No hardware board defined, see "HardwareProfile.h" and __FILE__
    #endif
#elif defined(UBW)
#elif defined(UBW32)
#else
    #error No hardware board defined, see "HardwareProfile.h" and __FILE__
#endif


/** VARIABLES ******************************************************/
#pragma udata 
BYTE oldSW;
BYTE wCount;

USB_HANDLE lastTransmission = 0;
USB_HANDLE lastOutTransmission = 0;
char usb_state = 'r';

BYTE hid_report_feature[HID_FEATURE_REPORT_BYTES];

/** PRIVATE PROTOTYPES *********************************************/
void BlinkUSBStatus(void);
BOOL Switch2IsPressed(void);
BOOL Switch3IsPressed(void);
static void InitializeSystem(void);


/** VARIABLES ******************************************************/
#pragma udata
extern USB_HANDLE USBGenericOutHandle;
extern USB_HANDLE USBGenericInHandle;
//extern DATA_PACKET  INPacket;
//extern DATA_PACKET  OUTPacket;


/** PRIVATE PROTOTYPES *********************************************/
static void InitializeSystem(void);
void USBDeviceTasks(void);
void YourHighPriorityISRCode(void);
void YourLowPriorityISRCode(void);


/** VECTOR REMAPPING ***********************************************/
#if defined(__18CXX)
	//On PIC18 devices, addresses 0x00, 0x08, and 0x18 are used for
	//the reset, high priority interrupt, and low priority interrupt
	//vectors.  However, the current Microchip USB bootloader 
	//examples are intended to occupy addresses 0x00-0x7FF or
	//0x00-0xFFF depending on which bootloader is used.  Therefore,
	//the bootloader code remaps these vectors to new locations
	//as indicated below.  This remapping is only necessary if you
	//wish to program the hex file generated from this project with
	//the USB bootloader.  If no bootloader is used, edit the
	//usb_config.h file and comment out the following defines:
	//#define PROGRAMMABLE_WITH_USB_HID_BOOTLOADER
	//#define PROGRAMMABLE_WITH_USB_LEGACY_CUSTOM_CLASS_BOOTLOADER
	
	#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
		#define REMAPPED_RESET_VECTOR_ADDRESS			0x1000
		#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x1008
		#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x1018
	#elif defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)	
		#define REMAPPED_RESET_VECTOR_ADDRESS			0x800
		#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x808
		#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x818
	#else	
		#define REMAPPED_RESET_VECTOR_ADDRESS			0x00
		#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x08
		#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x18
	#endif
	
	#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
	extern void _startup (void);        // See c018i.c in your C18 compiler dir
	#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
	void _reset (void)
	{
	    _asm goto _startup _endasm
	}
	#endif
	#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
	void Remapped_High_ISR (void)
	{
	     _asm goto YourHighPriorityISRCode _endasm
	}
	#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
	void Remapped_Low_ISR (void)
	{
	     _asm goto YourLowPriorityISRCode _endasm
	}
	
	#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
	//Note: If this project is built while one of the bootloaders has
	//been defined, but then the output hex file is not programmed with
	//the bootloader, addresses 0x08 and 0x18 would end up programmed with 0xFFFF.
	//As a result, if an actual interrupt was enabled and occured, the PC would jump
	//to 0x08 (or 0x18) and would begin executing "0xFFFF" (unprogrammed space).  This
	//executes as nop instructions, but the PC would eventually reach the REMAPPED_RESET_VECTOR_ADDRESS
	//(0x1000 or 0x800, depending upon bootloader), and would execute the "goto _startup".  This
	//would effective reset the application.
	
	//To fix this situation, we should always deliberately place a 
	//"goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS" at address 0x08, and a
	//"goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS" at address 0x18.  When the output
	//hex file of this project is programmed with the bootloader, these sections do not
	//get bootloaded (as they overlap the bootloader space).  If the output hex file is not
	//programmed using the bootloader, then the below goto instructions do get programmed,
	//and the hex file still works like normal.  The below section is only required to fix this
	//scenario.
	#pragma code HIGH_INTERRUPT_VECTOR = 0x08
	void High_ISR (void)
	{
	     _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
	}
	#pragma code LOW_INTERRUPT_VECTOR = 0x18
	void Low_ISR (void)
	{
	     _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
	}
	#endif	//end of "#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_LEGACY_CUSTOM_CLASS_BOOTLOADER)"

	#pragma code
	
	
	//These are your actual interrupt handling routines.
	#pragma interrupt YourHighPriorityISRCode
	void YourHighPriorityISRCode()
	{
		//Check which interrupt flag caused the interrupt.
		//Service the interrupt
		//Clear the interrupt flag
		//Etc.
	
	}	//This return will be a "retfie fast", since this is in a #pragma interrupt section 
	#pragma interruptlow YourLowPriorityISRCode
	void YourLowPriorityISRCode()
	{
		//Check which interrupt flag caused the interrupt.
		//Service the interrupt
		//Clear the interrupt flag
		//Etc.
	
	}	//This return will be a "retfie", since this is in a #pragma interruptlow section 

#elif defined(__C30__)
    #if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
        /*
         *	ISR JUMP TABLE
         *
         *	It is necessary to define jump table as a function because C30 will
         *	not store 24-bit wide values in program memory as variables.
         *
         *	This function should be stored at an address where the goto instructions 
         *	line up with the remapped vectors from the bootloader's linker script.
         *  
         *  For more information about how to remap the interrupt vectors,
         *  please refer to AN1157.  An example is provided below for the T2
         *  interrupt with a bootloader ending at address 0x1400
         */
//        void __attribute__ ((address(0x1404))) ISRTable(){
//        
//        	asm("reset"); //reset instruction to prevent runaway code
//        	asm("goto %0"::"i"(&_T2Interrupt));  //T2Interrupt's address
//        }
    #endif
#endif //of "#if defined(__18CXX)"


/** DECLARATIONS ***************************************************/
#pragma code

/******************************************************************************
 * Function:        void UserInit(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This routine should take care of all of the demo code
 *                  initialization that is required.
 *
 * Note:            
 *
 *****************************************************************************/
void UserInit(void)
{
    //Initialize all of the LED pins
    mInitAllLEDs();
    
    //Initialize all of the push buttons
#if defined (UBW)
    mInitSwitch();
	oldSW = UserSW;
#elif defined (UBW32)
	mInitAllSwitches();
	oldSW = swUser;
#endif


}//end UserInit

/******************************************************************************
 * Function:        BOOL Switch2IsPressed(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          TRUE - pressed, FALSE - not pressed
 *
 * Side Effects:    None
 *
 * Overview:        Indicates if the switch is pressed.  
 *
 * Note:            
 *
 *****************************************************************************/
BOOL SwitchIsPressed(void)
{
    if(UserSW != oldSW)
    {
        oldSW = UserSW;                  // Save new value
        if(UserSW == 0)                    // If pressed
            return TRUE;                // Was pressed
    }//end if
    return FALSE;                       // Was not pressed
}//end Switch2IsPressed


/********************************************************************
 * Function:        void BlinkUSBStatus(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        BlinkUSBStatus turns on and off LEDs 
 *                  corresponding to the USB device state.
 *
 * Note:            mLED macros can be found in HardwareProfile.h
 *                  USBDeviceState is declared and updated in
 *                  usbd.c.
 *******************************************************************/
void BlinkUSBStatus(void)
{
    static WORD led_count=0;
    
    if(led_count == 0)led_count = 10000U;
    led_count--;

    if(USBSuspendControl == 1)
    {
        if(led_count==0)
        {
            mLED_1_Toggle();
            mLED_2 = mLED_1;        // Both blink at the same time
        }//end if
    }
    else
    {
        if(USBDeviceState == DETACHED_STATE)
        {
            mLED_1_Off(); mLED_2_Off();
        }
        else if(USBDeviceState == ATTACHED_STATE)
        {
            mLED_1_On(); mLED_1_On();
        }
        else if(USBDeviceState == POWERED_STATE)
        {
            mLED_1_On(); mLED_2_Off();
        }
        else if(USBDeviceState == DEFAULT_STATE)
        {
            mLED_1_Off(); mLED_2_On();
        }
        else if(USBDeviceState == ADDRESS_STATE)
        {
            if(led_count == 0)
            {
                mLED_1_Toggle();
                mLED_2_Off();
            }//end if
        }
        else if(USBDeviceState == CONFIGURED_STATE)
        {
            if(led_count==0)
            {
                mLED_1_Toggle();
                mLED_2 = !mLED_1;       // Alternate blink                
            }//end if
        }//end if(...)
    }//end if(UCONbits.SUSPND...)

}//end BlinkUSBStatus

/********************************************************************
 * Function:        void ProcessIO(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This function is a place holder for other user
 *                  routines. It is a mixture of both USB and
 *                  non-USB tasks.
 *
 * Note:            None
 *******************************************************************/
void ProcessIO(void)
{   
    //Blink the LEDs according to the USB device status
    BlinkUSBStatus();

    // User Application USB tasks

    if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return;

   	// Send and receive HID reports.

	ReportLoopBack();
    
}//end ProcessIO

/********************************************************************
 * Function:        static void InitializeSystem(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        InitializeSystem is a centralize initialization
 *                  routine. All required USB initialization routines
 *                  are called from here.
 *
 *                  User application initialization routine should
 *                  also be called from here.                  
 *
 * Note:            None
 *******************************************************************/
static void InitializeSystem(void)
{
    #if (defined(__18CXX) & !defined(PIC18F87J50_PIM))
        ADCON1 |= 0x0F;                 // Default all pins to digital
    #elif defined(__C30__)
        AD1PCFG = 0xFFFF;
    #endif

    #if defined(PIC18F87J50_PIM)
	//On the PIC18F87J50 Family of USB microcontrollers, the PLL will not power up and be enabled
	//by default, even if a PLL enabled oscillator configuration is selected (such as HS+PLL).
	//This allows the device to power up at a lower initial operating frequency, which can be
	//advantageous when powered from a source which is not gauranteed to be adequate for 48MHz
	//operation.  On these devices, user firmware needs to manually set the OSCTUNE<PLLEN> bit to
	//power up the PLL.
    {
        unsigned int pll_startup_counter = 600;
        OSCTUNEbits.PLLEN = 1;  //Enable the PLL and wait 2+ms until the PLL locks before enabling USB module
        while(pll_startup_counter--);
    }
    //Device switches over automatically to PLL output after PLL is locked and ready.

	//Configure all I/O pins to use digital input buffers.  The PIC18F87J50 Family devices
	//use the ANCONx registers to control this, which is different from other devices which
	//use the ADCON1 register for this purpose.
    WDTCONbits.ADSHR = 1;			// Select alternate SFR location to access ANCONx registers
    ANCON0 = 0xFF;                  // Default all pins to digital
    ANCON1 = 0xFF;                  // Default all pins to digital
    WDTCONbits.ADSHR = 0;			// Select normal SFR locations

    #endif
    
//	The USB specifications require that USB peripheral devices must never source
//	current onto the Vbus pin.  Additionally, USB peripherals should not source
//	current on D+ or D- when the host/hub is not actively powering the Vbus line.
//	When designing a self powered (as opposed to bus powered) USB peripheral
//	device, the firmware should make sure not to turn on the USB module and D+
//	or D- pull up resistor unless Vbus is actively powered.  Therefore, the
//	firmware needs some means to detect when Vbus is being powered by the host.
//	A 5V tolerant I/O pin can be connected to Vbus (through a resistor), and
// 	can be used to detect when Vbus is high (host actively powering), or low
//	(host is shut down or otherwise not supplying power).  The USB firmware
// 	can then periodically poll this I/O pin to know when it is okay to turn on
//	the USB module/D+/D- pull up resistor.  When designing a purely bus powered
//	peripheral device, it is not possible to source current on D+ or D- when the
//	host is not actively providing power on Vbus. Therefore, implementing this
//	bus sense feature is optional.  This firmware can be made to use this bus
//	sense feature by making sure "USE_USB_BUS_SENSE_IO" has been defined in the
//	usbcfg.h file.    
    #if defined(USE_USB_BUS_SENSE_IO)
    tris_usb_bus_sense = INPUT_PIN; // See io_cfg.h
    #endif
    
//	If the host PC sends a GetStatus (device) request, the firmware must respond
//	and let the host know if the USB peripheral device is currently bus powered
//	or self powered.  See chapter 9 in the official USB specifications for details
//	regarding this request.  If the peripheral device is capable of being both
//	self and bus powered, it should not return a hard coded value for this request.
//	Instead, firmware should check if it is currently self or bus powered, and
//	respond accordingly.  If the hardware has been configured like demonstrated
//	on the PICDEM FS USB Demo Board, an I/O pin can be polled to determine the
//	currently selected power source.  On the PICDEM FS USB Demo Board, "RA2" 
//	is used for	this purpose.  If using this feature, make sure "USE_SELF_POWER_SENSE_IO"
//	has been defined in usbcfg.h, and that an appropriate I/O pin has been mapped
//	to it in io_cfg.h.
    #if defined(USE_SELF_POWER_SENSE_IO)
    tris_self_power = INPUT_PIN;
    #endif
    
    USBDeviceInit();
    UserInit();

}//end InitializeSystem

/********************************************************************
 * Function:        void main(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Main program entry point.
 *
 * Note:            None
 *******************************************************************/
#if defined(__18CXX)
void main(void)
#else
int main(void)
#endif
{   
    InitializeSystem();

    while(1)
    {
		// Check bus status and service USB interrupts.
        USBDeviceTasks();     // Interrupt or polling method
        
		// Application-specific tasks.
        ProcessIO();        
    }//end while
}//end main

void USBCBSuspend(void)
{
    #if defined(__C30__)
    #if 0
        U1EIR = 0xFFFF;
        U1IR = 0xFFFF;
        U1OTGIR = 0xFFFF;
        IFS5bits.USB1IF = 0;
        IEC5bits.USB1IE = 1;
        U1OTGIEbits.ACTVIE = 1;
        U1OTGIRbits.ACTVIF = 1;
        TRISA &= 0xFF3F;
        LATAbits.LATA6 = 1;
        Sleep();
        LATAbits.LATA6 = 0;
    #endif
    #endif
}

#if 0
void __attribute__ ((interrupt)) _USB1Interrupt(void)
{
    #if !defined(self_powered)
        if(U1OTGIRbits.ACTVIF)
        {
            LATAbits.LATA7 = 1;
        
            IEC5bits.USB1IE = 0;
            U1OTGIEbits.ACTVIE = 0;
            IFS5bits.USB1IF = 0;
        
            //USBClearInterruptFlag(USBActivityIFReg,USBActivityIFBitNum);
            USBClearInterruptFlag(USBIdleIFReg,USBIdleIFBitNum);
            //USBSuspendControl = 0;
            LATAbits.LATA7 = 0;
        }
    #endif
}
#endif

void USBCBWakeFromSuspend(void)
{
}

/********************************************************************
 * Function:        void USBCB_SOF_Handler(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        The USB host sends out a SOF packet to full-speed
 *                  devices every 1 ms. This interrupt may be useful
 *                  for isochronous pipes. End designers should
 *                  implement callback routine as necessary.
 *
 * Note:            None
 *******************************************************************/
void USBCB_SOF_Handler(void)
{
    // No need to clear UIRbits.SOFIF to 0 here.
    // Callback caller is already doing that.
}

/*******************************************************************
 * Function:        void USBCBErrorHandler(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        The purpose of this callback is mainly for
 *                  debugging during development. Check UEIR to see
 *                  which error causes the interrupt.
 *
 * Note:            None
 *******************************************************************/
void USBCBErrorHandler(void)
{
    // No need to clear UEIR to 0 here.
    // Callback caller is already doing that.
}

/*******************************************************************
 * Function:        void USBCBCheckOtherReq
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Check for vendor- or class-specific control requests.
 *
 * Note:            None
 *******************************************************************/
void USBCBCheckOtherReq(void)
{
     USBCheckHIDRequest();
}//end

void USBCBStdSetDscHandler(void)
{
    // Must claim session ownership if supporting this request
}//end

/*******************************************************************
 * Function:        void USBCBInitEP(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This function is called when the device becomes
 *                  initialized.  This should initialize the endpoints
 *                  for the device's usage according to the current
 *                  configuration.
 *
 * Note:            None
 *******************************************************************/
void USBCBInitEP(void)
{
    //enable the HID endpoint
    USBEnableEndpoint(HID_EP,USB_IN_ENABLED|USB_OUT_ENABLED | USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
}

/********************************************************************
 * Function:        void USBCBSendResume(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This callback should send a RESUME signal that
 *                  has the period of 1-15ms.
 *
 * Note:            Interrupt vs. Polling
 *                  -Primary clock
 *                  -Secondary clock ***** MAKE NOTES ABOUT THIS *******
 *                   > Can switch to primary first by calling USBCBWakeFromSuspend()
 
 *                  The modifiable section in this routine should be changed
 *                  to meet the application needs. Current implementation
 *                  temporary blocks other functions from executing for a
 *                  period of 1-13 ms depending on the core frequency.
 *
 *                  According to USB 2.0 specification section 7.1.7.7,
 *                  "The remote wakeup device must hold the resume signaling
 *                  for at lest 1 ms but for no more than 15 ms."
 *                  The idea here is to use a delay counter loop, using a
 *                  common value that would work over a wide range of core
 *                  frequencies.
 *                  That value selected is 1800. See table below:
 *                  ==========================================================
 *                  Core Freq(MHz)      MIP         RESUME Signal Period (ms)
 *                  ==========================================================
 *                      48              12          1.05
 *                       4              1           12.6
 *                  ==========================================================
 *                  * These timing could be incorrect when using code
 *                    optimization or extended instruction mode,
 *                    or when having other interrupts enabled.
 *                    Make sure to verify using the MPLAB SIM's Stopwatch
 *                    and verify the actual signal on an oscilloscope.
 *******************************************************************/
void USBCBSendResume(void)
{
    static WORD delay_count;
    
    USBResumeControl = 1;                // Start RESUME signaling
    
    delay_count = 1800U;                // Set RESUME line for 1-13 ms
    do
    {
        delay_count--;
    }while(delay_count);
    USBResumeControl = 0;
}

/******************************************************************************
 * Function:        void mySetReportHandler(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Checks to see if an Output or Feature report has arrived
 *         			on the control pipe. If yes, extracts and uses the data.
 *
 * Note:            None
 *****************************************************************************/

void mySetReportHandler(void)
{
	BYTE count = 0;

	// Find out if an Output or Feature report has arrived on the control pipe.
	// Get the report type from the Setup packet.

	switch (MSB(SetupPkt.W_Value))
    {
		case 0x02: // Output report 
		{	
    		switch(LSB(SetupPkt.W_Value))
		    {
				case 0: // Report ID 0

					// This example application copies the Output report data 
					// to hid_report_in. 
					// (Assumes Input and Output reports are the same length.)
					// A "real" application would do something more useful with the data.

				    // wCount holds the number of bytes read in the Data stage.
					// This example assumes the report fits in one transaction.									
		
					for(count=0; count <= HID_OUTPUT_REPORT_BYTES - 1; count++)
    				{   										
						hid_report_in[count] = hid_report_out[count] ;
    				}
					break;		
			} // end switch(LSB(SetupPkt.W_Value))
			break;
		}

		case 0x03: // Feature report 
		{
			// Get the report ID from the Setup packet.

    		switch(LSB(SetupPkt.W_Value))
		    {
				case 0: // Report ID 0

				// The Feature report data is in hid_report_feature.
				// This example application just sends the data back in the next
				// Get_Report request for a Feature report.			
			
			    // wCount holds the number of bytes read in the Data stage.
				// This example assumes the report fits in one transaction.	
		
				// The Feature report uses a single buffer so to send the same data back
				// in the next IN Feature report, there is nothing to copy.
				// The data is in hid_report_feature[HID_FEATURE_REPORT_BYTES]													
						
				break;

			} // end switch(LSB(SetupPkt.W_Value))	
			break;	
		}
		
	} // end switch(MSB(SetupPkt.W_Value))

} // end mySetReportHandler

/******************************************************************************
 * Function:        BOOL ReportSupported(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          2 if it's a supported Output report
 *                  3 if it's a supported Feature report
 *                  0 for all other cases
 *
 * Side Effects:    None
 *
 * Overview:        Checks to see if the HID supports a specific Output or Feature
 *				    report. 
 *
 * Note:            None
 *****************************************************************************/

BYTE ReportSupported(void)
{
	// Find out if an Output or Feature report has arrived on the control pipe.

	USBDeviceTasks();
	switch (MSB(SetupPkt.W_Value))
    {
		case 0x01: // Input report 
		{	
    		switch(LSB(SetupPkt.W_Value))
		    {
				case 0x00: // Report ID 0
				{
					return 1;		
				}
				default:
				{
					// Other report IDs not supported.

					return 0;				
				}			
			} // end switch(LSB(SetupPkt.W_Value))					
		}

		case 0x02: // Output report 
		{	
    		switch(LSB(SetupPkt.W_Value))
		    {
				case 0x00: // Report ID 0
				{
					return 2;		
				}
				default:
				{
					// Other report IDs not supported.

					return 0;				
				}			
			} // end switch(LSB(SetupPkt.W_Value))					
		}

		case 0x03: // Feature report 
		{
    		switch(LSB(SetupPkt.W_Value))
		    {
				case 0x00: // Report ID 0
				{
					return 3;					
				}
				default:
				{
					// Other report IDs not supported.

					return 0;					
				}
			} // end switch(LSB(SetupPkt.W_Value))
		}			
		default:
		{
			return 0;	
		}			
	} // end switch(MSB(SetupPkt.W_Value))

} // end ReportSupported

/******************************************************************************
 * Function:        void ReportLoopback(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    The ownership of the USB buffers will change according
 *                  to the required operation
 *
 * Overview:        This routine will send a received Input report back 
 *                  to the host in an Output report.
 *                  Both directions use interrupt transfers.
 *
 * Note:            
 *
 *****************************************************************************/
void ReportLoopBack(void)
{  
	BYTE count = 0;

	switch (usb_state)
    {
		case 'r':
		{
		   	if(HIDRxHandleBusy(lastOutTransmission) == 0)
	    	{		
				// The CPU owns the endpoint. Check for received data.

				lastOutTransmission = HIDRxPacket(HID_EP, (BYTE*)&hid_report_out, 64);
				
				usb_state = 'p';
			}
			break;
		}

		case 'p':
		{
			if(HIDRxHandleBusy(lastOutTransmission) == 0)
			{
				// The CPU owns the endpoint. 

				if (((BDT_ENTRY*)lastOutTransmission)->CNT > 0)
				{	
					// Data was received. Copy it to the output buffer for sending.							
	
					for (count; count <= HID_OUTPUT_REPORT_BYTES - 1; count++)
					{
						hid_report_in[count] = hid_report_out[count];				
					}
					// Ready to transmit the received data back to the host.
	
					usb_state = 't';	
				}		
				else
				{
					// No data was received. Return to checking for new received data.

					usb_state = 'r';						
					}
			}
			break;
		}

		case 't':
		{
			if (HIDTxHandleBusy(lastTransmission) == 0)		 
			{
				// The CPU owns the endpoint.
				// Prepare to send data.
	
				lastTransmission = HIDTxPacket(HID_EP, (BYTE*)&hid_report_in, HID_INPUT_REPORT_BYTES);
				
				// Return to checking for new received data.

				usb_state = 'r';					
			}
			break;
		}

		default:
		{	
			break;
		}
	}

}//end ReportLoopback

/*******************************************************************
 * Function:        BOOL USER_USB_CALLBACK_EVENT_HANDLER(
 *                        USB_EVENT event, void *pdata, WORD size)
 *
 * PreCondition:    None
 *
 * Input:           USB_EVENT event - the type of event
 *                  void *pdata - pointer to the event data
 *                  WORD size - size of the event data
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This function is called from the USB stack to
 *                  notify a user application that a USB event
 *                  occured.  This callback is in interrupt context
 *                  when the USB_INTERRUPT option is selected.
 *
 * Note:            None
 *******************************************************************/
BOOL USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, WORD size)
{
    switch(event)
    {
        case EVENT_TRANSFER:
            //Add application specific callback task or callback function here if desired.
            break;
        case EVENT_SOF:
            USBCB_SOF_Handler();
            break;
        case EVENT_SUSPEND:
            USBCBSuspend();
            break;
        case EVENT_RESUME:
            USBCBWakeFromSuspend();
            break;
        case EVENT_CONFIGURED: 
            USBCBInitEP();
            break;
        case EVENT_SET_DESCRIPTOR:
            USBCBStdSetDscHandler();
            break;
        case EVENT_EP0_REQUEST:
            USBCBCheckOtherReq();
            break;
        case EVENT_BUS_ERROR:
            USBCBErrorHandler();
            break;
        case EVENT_TRANSFER_TERMINATED:
            //Add application specific callback task or callback function here if desired.
            //The EVENT_TRANSFER_TERMINATED event occurs when the host performs a CLEAR
            //FEATURE (endpoint halt) request on an application endpoint which was 
            //previously armed (UOWN was = 1).  Here would be a good place to:
            //1.  Determine which endpoint the transaction that just got terminated was 
            //      on, by checking the handle value in the *pdata.
            //2.  Re-arm the endpoint if desired (typically would be the case for OUT 
            //      endpoints).
            break;
        default:
            break;
    }      
    return TRUE; 
}

/** EOF generic_hid.c *************************************************/

