/////////////////////////////////////////////////////////////////////////
////                                                                 ////
////                        ex_usb_hid.c                             ////
////                                                                 ////
//// A simple demo that shows how to use the HID class to send       ////
//// and receive custom data from the PC.  Normally HID is used      ////
//// with pre-defined classes, such as mice and keyboards, but       ////
//// can be used for vendor specific classes as shown in this        ////
//// example.                                                        ////
////                                                                 ////
//// The first byte sent by the PIC is the ADC reading               ////
//// on channel 0 (AN0), the second byte is the status of the        ////
//// pushbutton.  The two bytes sent by the PC are LED on/off        ////
//// toggle status.                                                  ////
////                                                                 ////
//// CCS has provided an example Windows program that reads / writes ////
//// to the HID device provided in this example.  This Windows       ////
//// example is called hiddemo.exe.                                  ////
////                                                                 ////
//// Normally this program sends and receives 2 bytes.  These        ////
//// sizes can be changed with USB_CONFIG_HID_TX_SIZE and            ////
//// USB_CONFIG_HID_RX_SIZE.  Changing these values will cause       ////
//// hiddemo.exe to not work.                                        ////
////                                                                 ////
//// This file is part of CCS's PIC USB driver code.  See USB.H      ////
//// for more documentation and a list of examples.                  ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////                                                                 ////
//// ABOUT HID:                                                      ////
////                                                                 ////
//// HID devices are useful because HID drivers are generally        ////
//// installed and supplied with modern operating systems.           ////
//// However, since HID is a general device with general drivers     ////
//// there are limitations to what a HID device can do:              ////
////                                                                 ////
//// - A report (message) can't be larger than 255 bytes.            ////
////  (A report or message != A packet)                              ////
////                                                                 ////
//// - On slow speed devices the max packet size is 8.               ////
////   On a full speed device the max packet size is 64.             ////
////                                                                 ////
//// - Data is obtained on the host / PC through polling the HID     ////
////   device (PC polls the PIC)                                     ////
////                                                                 ////
//// - On a full speed device, max polling rate is 1 transaction     ////
////   per 1ms. This is 64000 bytes per second (64 byte packets      ////
////   every 1ms).                                                   ////
////                                                                 ////
//// - On a slow speed device, max polling rate is 1 transaction     ////
////   per 10ms.  This is 800 bytes per second (8 byte packets every ////
////   10ms)                                                         ////
////                                                                 ////
//// - No guarantee that polls will happen at a guaranteed rate.     ////
////   If you want guaranteed transfer rate you must use Isochronous ////
////   transfers, which HID is not.                                  ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////                                                                 ////
////                      WINDOWS DRIVERS:                           ////
////                                                                 ////
//// USB HID drivers come included with all Windows, starting        ////
//// with Windows 98 and up.  Windows 95 does not include USB        ////
//// support, unless you are running Windows 95 Gold (aka OSR2, or   ////
//// Windows 95b).                                                   ////
////                                                                 ////
//// If you plug in the USB device, and it is working, a "Found new  ////
//// device" window should pop-up.  The Add Device wizard then will  ////
//// install the HID drivers automatically.                          ////
////                                                                 ////
//// If you plug in the USB device and do not get this window then   ////
//// the device is not working, or USB does not work on your         ////
//// computer.  Goto the Device Manager (Right Click on my Computer, ////
//// it is located under one of the Tabs.  It is located under the   ////
//// Hardware tab of Windows2000), and make sure that "Universal     ////
//// Serial Bus controllers" is installed.  Open "Universal Serial   ////
//// Bus controllers" and you should see 1 or more "USB Root Hubs".  ////
//// If you see these then that's a good indication that USB is      ////
//// working on your computer.  If you see a question mark and       ////
//// an unkown USB device then this is quite possibly your USB       ////
//// device that is not working.                                     ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////                                                                 ////
//// NOTE ABOUT ENDPOINT BUFFER SIZE:                                ////
////                                                                 ////
//// Although this application sends and receives only 2 bytes from  ////
//// the PC, this demo defines USB_EP1_TX_SIZE and USB_EP1_RX_SIZE   ////
//// to 8 to allocate 8 bytes for these endpoint.  These constants   ////
//// are also used in the endpoint descriptor to specify the         ////
//// endpoint max size.  If you were concious of RAM savings you     ////
//// could redefine these to 2 (or even 1!), but you would lose      ////
//// throughput. The reason for throughput loss is that if you send  ////
//// a packet that is the same size as the max packet size then      ////
//// you need to send a 0 len packet to specify end of message       ////
//// marker.  The routines usb_puts() and usb_gets() send and        ////
//// receive multiple packet message, waiting for a 0 len packet     ////
//// or a packet that is smaller than max-packet size.               ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////                                                                 ////
//// VERSION HISTORY                                                 ////
////                                                                 ////
//// March 5th, 2009:                                                ////
////   Cleanup for Wizard.                                           ////
////   PIC24 Initial release.                                        ////
////                                                                 ////
//// June 20th, 2005: 18fxx5x initial release.                       ////
////                                                                 ////
//// March 22nd, 2005: Cleanup to work with PIC18Fxx5x               ////
////                                                                 ////
//// June 24th, 2004:  Cleanup to work with updated USB API          ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2005 Custom Computer Services         ////
//// This source code may only be used by licensed users of the CCS  ////
//// C compiler.  This source code may only be distributed to other  ////
//// licensed users of the CCS C compiler.  No other use,            ////
//// reproduction or distribution is permitted without written       ////
//// permission.  Derivative programs created using this software    ////
//// in object code form are not restricted in any way.              ////
/////////////////////////////////////////////////////////////////////////

//set to 1 to use a PIC's internal USB Peripheral
//set to 0 to use a National USBN960x peripheral
#define __USB_PIC_PERIF__ 0

//if using a 16bit PIC on an Explorer 16 borad, set this to 1
#define __USB_PIC_EXPLORER16__   1

#if __USB_PIC_PERIF__
 #DEFINE LED1  PIN_A5
 #if defined(__PCM__)
    #include <16C765.h>
    #device *=16
    #device ADC=8
    #fuses HS,NOWDT,NOPROTECT
    #use delay(clock=24000000)
 #elif defined(__PCH__)
    #include <18F4550.h>
    #device ADC=8
    #fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
    #use delay(clock=48000000)
 #elif defined(__PCD__)
   #include <24FJ256GB110.h>
   #device ADC=8
   
   #fuses HS,PR_PLL,NOWDT,DISUVREG,ICSP2

   #if __USB_PIC_EXPLORER16__
    #use delay(clock=32M)  //8MHz clock is 4x because of PLL
    #fuses PLL2   //Divide 8MHz by 2 to get the 4MHz required for USB
    #pin_select U1TX = PIN_F5
    #pin_select U1RX = PIN_F4
   #endif
 #endif
#else //use the National USBN960x peripheral
 #DEFINE LED1  PIN_B3
 #if defined(__PCM__)
  #include <16F877A.h>
  #device ADC=8
  #device *=16
  #fuses HS,NOWDT,NOPROTECT,NOLVP
 #elif defined(__PCH__)
  #include <18F452.h>
  #device ADC=8
  #fuses HS,NOWDT,NOPROTECT,NOLVP
 #endif
 #use delay(clock=20000000)

#endif   //endif check to see which peripheral to use

#use rs232(baud=9600, UART1, errors)

// you can change the tx and rx packet sizes here.
// in order to be compatbile with hiddemo.exe, these values must be 2.
#define USB_CONFIG_HID_TX_SIZE   2
#define USB_CONFIG_HID_RX_SIZE   2

/////////////////////////////////////////////////////////////////////////////
//
// If you are using a USB connection sense pin, define it here.  If you are
// not using connection sense, comment out this line.  Without connection
// sense you will not know if the device gets disconnected.
//       (connection sense should look like this:
//                             100k
//            VBUS-----+----/\/\/\/\/\----- (I/O PIN ON PIC)
//                     |
//                     +----/\/\/\/\/\-----GND
//                             100k
//        (where VBUS is pin1 of the USB connector)
//
/////////////////////////////////////////////////////////////////////////////
///only the 18F4550 development kit has this pin
#if __USB_PIC_PERIF__ && defined(__PCH__)
 #define USB_CON_SENSE_PIN PIN_B2
#endif


/////////////////////////////////////////////////////////////////////////////
//
// Include the CCS USB Libraries.  See the comments at the top of these
// files for more information
//
/////////////////////////////////////////////////////////////////////////////
#if __USB_PIC_PERIF__
 #if defined(__PCM__)
  #include <pic_usb.h>   //Microchip PIC16C765 hardware layer for usb.c
 #elif defined(__PCH__)
  #include <pic18_usb.h>   //Microchip PIC18Fxx5x hardware layer for usb.c
 #elif defined(__PCD__)
  #include <pic24_usb.h>   //Microchip PIC24 hardware layer for usb.c
 #endif
#else
 #include <usbn960x.h>   //National 960x hardware layer for usb.c
#endif
#include <usb_desc_hid.h>   //USB Configuration and Device descriptors for this UBS device
#include <usb.c>        //handles usb setup tokens and get descriptor reports


/////////////////////////////////////////////////////////////////////////////
//
// Configure the demonstration I/O
//
/////////////////////////////////////////////////////////////////////////////
#if defined(__PCD__) && __USB_PIC_EXPLORER16__
 #undef  LED1
 #define LED1 PIN_A0
 #define LED2 PIN_A1
 #define LED3 PIN_A2
 #define LED_ON(x) output_high(x)
 #define LED_OFF(x) output_low(x)
 #define BUTTON_PRESSED() !input(PIN_D6)
 #define HW_ADC_PORTS  sAN5
 #define HW_ADC_CHANNEL 5
 #define HW_ADC_CONFIG  ADC_CLOCK_INTERNAL | ADC_TAD_MUL_31
#else
 #define LED2 PIN_B4
 #define LED3 PIN_B5
 #define LED_ON(x) output_low(x)
 #define LED_OFF(x) output_high(x)
 #define BUTTON_PRESSED() !input(PIN_A4)
 #if defined(AN0)
  #define HW_ADC_PORTS AN0
 #elif defined(AN0_AN1_AN3)
  #define HW_ADC_PORTS AN0_AN1_AN3
 #elif defined(sAN0)
  #define HW_ADC_PORTS sAN0
 #else
  #define define HW_ADC_PORTS for your hardware
 #endif
 #define HW_ADC_CONFIG  ADC_CLOCK_INTERNAL
 #define HW_ADC_CHANNEL 0
#endif


/////////////////////////////////////////////////////////////////////////////
//
// usb_debug_task()
//
// When called periodically, displays debugging information over serial
// to display enumeration and connection states.  Also lights LED1 based upon
// enumeration and status.
//
/////////////////////////////////////////////////////////////////////////////
void usb_debug_task(void) 
{
   static int8 last_connected;
   static int8 last_enumerated;
   int8 new_connected;
   int8 new_enumerated;

   new_connected=usb_attached();
   new_enumerated=usb_enumerated();

   if (new_enumerated)
      LED_ON(LED1);
   else
      LED_OFF(LED1);

   if (new_connected && !last_connected)
      printf("\r\n\nUSB connected, waiting for enumaration...");
   if (!new_connected && last_connected)
      printf("\r\n\nUSB disconnected, waiting for connection...");
   if (new_enumerated && !last_enumerated)
      printf("\r\n\nUSB enumerated by PC/HOST");
   if (!new_enumerated && last_enumerated)
      printf("\r\n\nUSB unenumerated by PC/HOST, waiting for enumeration...");

   last_connected=new_connected;
   last_enumerated=new_enumerated;
}

void main(void) 
{
   int8 out_data[2];
   int8 in_data[2];
   int8 send_timer=0;

   LED_OFF(LED1);
   LED_OFF(LED2);
   LED_OFF(LED3);

   printf("\r\n\nCCS Vendor Specific HID Example");

  #ifdef __PCH__
   printf("\r\nPCH: v");
   printf(__PCH__);
  #elif defined(__PCD__)
   printf("\r\nPCD: v");
   printf(__PCD__);
  #else
   printf("\r\nPCM: v");
   printf(__PCM__);
  #endif

   usb_init_cs();

  #if !(__USB_PIC_PERIF__)
   printf("\r\nUSBN: 0x%X", usbn_get_version());
  #endif
   printf("\r\n");

   setup_adc_ports(HW_ADC_PORTS);
   setup_adc(HW_ADC_CONFIG);
   set_adc_channel(HW_ADC_CHANNEL);

   while (TRUE) 
   {
      usb_task();
      usb_debug_task();
      if (usb_enumerated()) 
      {
         if (!send_timer) 
         {
            send_timer=250;
            out_data[0]=read_adc();
            out_data[1]=BUTTON_PRESSED();
            if (usb_put_packet(1, out_data, 2, USB_DTS_TOGGLE))
               printf("\r\n<-- Sending 2 bytes: 0x%X 0x%X", out_data[0], out_data[1]);
         }
         if (usb_kbhit(1)) 
         {
            usb_get_packet(1, in_data, 2);
            printf("\r\n--> Received data: 0x%X 0x%X",in_data[0],in_data[1]);
            if (in_data[0]) {LED_ON(LED2);} else {LED_OFF(LED2);}
            if (in_data[1]) {LED_ON(LED3);} else {LED_OFF(LED3);}
         }
         send_timer--;
         delay_ms(1);
      }
   }
}
