/////////////////////////////////////////////////////////////////////////
////                                                                 ////
////                        ex_usb_serial2.c                         ////
////                                                                 ////
//// A demonstration of the USB CDC API that is provided by CCS.     ////
//// The USB CDC API that CCS provides will create a virtual UART    ////
//// port.  USB CDC drivers are included with most versions of       ////
//// Microsoft Windows, and when properly loaded will create a COMx  ////
//// port from which you can write and read to your PIC device       ////
//// like any serial device that has a COMx port.                    ////
////                                                                 ////
//// This example is a conversion of the original EX_INTEE.C to use  ////
//// the USB CDC API to read and display serial data over USB.       ////
////                                                                 ////
//// Only two lines were added to initialize USB:                    ////
////   usb_init() - init USB and enable USB interrupt.               ////
////   while(!usb_cdc_connected()) - wait until user opens           ////
////       Hyperterminal before displaying serial data.  This line   ////
////       is not necessary.                                         ////
////                                                                 ////
//// Two other changes were also made to convert to USB.  First,     ////
//// printf will call usb_cdc_putc() to put the character out USB    ////
//// instead of the normal RS232 stream.  Second, gethex() was       ////
//// replaced with gethex_usb().  All input functions normally found ////
//// in input.c have been converted to use the USB CDC API in        ////
//// usb_cdc.h, and gethex_usb() is one of these converted           ////
//// functions.                                                      ////
////                                                                 ////
//// See usb_cdc.h for API documentation.                            ////
////                                                                 ////
//// This file is part of CCS's PIC USB driver code.  See USB.H      ////
//// for more documentation and a list of examples.                  ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////                                                                 ////
//// VERSION HISTORY                                                 ////
////                                                                 ////
//// March 5th, 2009:                                                ////
////   Cleanup for Wizard.                                           ////
////   PIC24 Initial release.                                        ////
////                                                                 ////
//// July 1st, 2005: Initial Release.                                ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////        (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__ 1

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

#if !defined(__PCH__) && !defined(__PCD__)
 #error USB CDC Library requires PIC18 or 16bit PIC.
#endif

#if __USB_PIC_PERIF__
 #if defined(__PCH__)
  #include <18F4550.h>

  //configure a 20MHz crystal to operate at 48MHz
  #fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
  //#fuses   USBDIV, PLL1, CPUDIV1, PROTECT, NOCPD, noBROWNOUT,HSPLL,NOWDT,nolvp, VREGEN
  #use delay(clock=48000000)
  
  #define LED1 PIN_A5
 #else   //__PCD__ is defined
   #include <24FJ256GB110.h>
   
   #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
  #include <18F452.h>
  #fuses HS,NOWDT,NOPROTECT,NOLVP
  #use delay(clock=20000000)
  #define LED1 PIN_B3
#endif   //endif check to see which peripheral to use

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

/////////////////////////////////////////////////////////////////////////////
//
// 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)
//
/////////////////////////////////////////////////////////////////////////////
#if __USB_PIC_PERIF__ && defined(__PCH__)
 // the CCS 18F4550 development kit has this pin
 #define USB_CON_SENSE_PIN PIN_B2
#endif

/////////////////////////////////////////////////////////////////////////////
//
// 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)
#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)
#endif


/////////////////////////////////////////////////////////////////////////////
//
// BEGIN DEBUG PUTC BUFFER
//
// If you want to debug the USB stack, you cannot use printf() directly
// to the UART because it is too slow.  Instead you will need to buffer 
// the serial data and send it when the UART is free.  putc_tbe() will
// put a char into the buffer, task_tbe() will transmit a byte if the UART
// is free.
//
/////////////////////////////////////////////////////////////////////////////
char g_PutcBuffer[350];
int16 g_PutcNextIn=0, g_PutcNextOut=0;
void putc_tbe(char c)
{
   g_PutcBuffer[g_PutcNextIn++] = c;
   if (g_PutcNextIn >= sizeof(g_PutcBuffer))
      g_PutcNextIn = 0;
}
void task_tbe(void)
{
   if (interrupt_active(INT_TBE) && (g_PutcNextIn != g_PutcNextOut))
   {
      putc(g_PutcBuffer[g_PutcNextOut++]);
      if (g_PutcNextOut >= sizeof(g_PutcBuffer))
         g_PutcNextOut = 0;
   }
}
/////////////////////////////////////////////////////////////////////////////
//
//END DEBUG PUTC BUFFER
//
/////////////////////////////////////////////////////////////////////////////


// Includes all USB code and interrupts, as well as the CDC API
#include <usb_cdc.h>

#if (getenv("DATA_EEPROM") > 0)
 #define MY_READ_EEPROM(x)    read_eeprom(x)
 #define MY_WRITE_EEPROM(x, y)   write_eeprom(x, y)
#else
 // if chip doesn't have an eeprom, then simulate one in RAM
 char data[256];
 #define MY_READ_EEPROM(x)    data[x]
 #define MY_WRITE_EEPROM(x, y)   data[x] = y
#endif

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

   task_tbe();

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

   if (new_connected)
      LED_ON(LED2);
   else
      LED_OFF(LED2);

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

   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 un-enumerated by PC/HOST, waiting for enumeration...");

   last_connected=new_connected;
   last_enumerated=new_enumerated;
}

void main(void)
{
   BYTE i, j, address, value;

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

   printf("\r\n\nCCS USB Serial2 Example");
  #if defined(__PCH__)
   printf("\r\nPCH: v");
   printf(__PCH__);
  #elif defined(__PCD__)
   printf("\r\nPCD: v");
   printf(__PCD__);
  #else
   printf("\r\n\PCM: v");
   printf(__PCM__);
  #endif

   LED_ON(LED1);

   usb_init_cs();

   do 
   {
      usb_task();
      usb_debug_task();
      if (usb_enumerated()) 
      {
         if (usb_cdc_kbhit())
         {
            i = toupper(usb_cdc_getc());
            
            if (i == 'R')
            {
               printf(usb_cdc_putc, "\r\n\nEEPROM:\r\n");              // Display contents of the first 64
               for(i=0; i<=3; ++i) 
               {
                  for(j=0; j<=15; ++j) 
                  {
                     printf(usb_cdc_putc, "%2x ", MY_READ_EEPROM( i*16+j ) );
                  }
                  printf(usb_cdc_putc, "\n\r");
               }
            }
            
            if (i == 'W')
            {
               printf(usb_cdc_putc, "\r\n\nLocation to change: ");
               address = gethex_usb();
               
               printf(usb_cdc_putc, "\r\nNew value: ");
               value = gethex_usb();
      
               MY_WRITE_EEPROM(address, value);
               
               printf(usb_cdc_putc, "\r\n");
            }
            
            printf(usb_cdc_putc, "\r\nR)ead memory or W)rite Memory");            
         }
      }
   } while (TRUE);
}
