/***********************************************************

	PICSYS18 USB BOOTLOADER
	main.c

	Version 0.6: 2009/09/25

	Copyright (C) 2008-2009, MicroFan Div., PeopleMedia, Inc.
	All rights reserved.

***********************************************************/


/** I N C L U D E S **********************************************************/
#include <p18cxxx.h>
#include "typedefs.h"                   
#include "usb.h"                         
#include "io_cfg.h"                     

/** C O N F I G U R A T I O N ************************************************/
// Note: For a complete list of the available config pragmas and their values, 
// see the compiler documentation, and/or click "Help --> Topics..." and then 
// select "PIC18 Config Settings" in the Language Tools section.

#if defined(PICSYS18_SP) || defined(PIC18F_MOD_2553) || defined(PIC18_DEV_2550URL)

#include "BootPIC18NonJ.h"

        #pragma config PLLDIV   = 2         // (8 MHz crystal on PICSYS18-SP board)
        #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      = OFF
        #pragma config BORV     = 3
        #pragma config VREGEN   = ON		//USB Voltage Regulator
        #pragma config WDT      = OFF
        #pragma config WDTPS    = 32768
        #pragma config MCLRE    = ON
        #pragma config LPT1OSC  = OFF
        #pragma config PBADEN   = OFF		//NOTE: modifying this value here won't have an effect
        									//on the application.  See the top of the main() function.
        									//By default the RB4 I/O pin is used to detect if the
        									//firmware should enter the bootloader or the main application
        									//firmware after a reset.  In order to do this, it needs to
        									//configure RB4 as a digital input, thereby changing it from
        									//the reset value according to this configuration bit.
//      #pragma config CCP2MX   = ON
        #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 CP0      = OFF
        #pragma config CP1      = OFF
//      #pragma config CP2      = OFF
//      #pragma config CP3      = OFF
        #pragma config CPB      = OFF
//      #pragma config CPD      = OFF
        #pragma config WRT0     = OFF
        #pragma config WRT1     = OFF
//      #pragma config WRT2     = OFF
//      #pragma config WRT3     = OFF
        #pragma config WRTB     = ON       // Boot Block Write Protection
        #pragma config WRTC     = ON
//      #pragma config WRTD     = OFF
        #pragma config EBTR0    = OFF
        #pragma config EBTR1    = OFF
//      #pragma config EBTR2    = OFF
//      #pragma config EBTR3    = OFF
        #pragma config EBTRB    = OFF

#elif defined(PICSYS18_XBEE)

#include "Boot46J50Family.h"

     #pragma config WDTEN = OFF          //WDT disabled (enabled by SWDTEN bit)
     #pragma config PLLDIV = 2           //Divide by 3 (12 MHz oscillator input)
     #pragma config STVREN = ON            //stack overflow/underflow reset enabled
     #pragma config XINST = OFF          //Extended instruction set disabled
     #pragma config CPUDIV = OSC1        //No CPU system clock divide
     #pragma config CP0 = OFF            //Program memory is not code-protected
     #pragma config OSC = INTOSCPLL          //HS oscillator, PLL enabled, HSPLL used by USB
     #pragma config T1DIG = ON           //Sec Osc clock source may be selected
     #pragma config LPT1OSC = ON         //high power Timer1 mode
     #pragma config FCMEN = OFF          //Fail-Safe Clock Monitor disabled
     #pragma config IESO = OFF           //Two-Speed Start-up disabled
     #pragma config WDTPS = 32768        //1:32768
     #pragma config DSWDTOSC = INTOSCREF //DSWDT uses INTOSC/INTRC as clock
     #pragma config RTCOSC = T1OSCREF    //RTCC uses T1OSC/T1CKI as clock
     #pragma config DSBOREN = OFF        //Zero-Power BOR disabled in Deep Sleep
     #pragma config DSWDTEN = OFF        //Disabled
     #pragma config DSWDTPS = 8192       //1:8,192 (8.5 seconds)
     #pragma config IOL1WAY = OFF        //IOLOCK bit can be set and cleared
     #pragma config MSSP7B_EN = MSK7     //7 Bit address masking
     #pragma config WPFP = PAGE_3        //Write Protect Program Flash Page 0
     #pragma config WPEND = PAGE_0       //Start protection at page 0
     #pragma config WPCFG = ON          //Write/Erase last page protect Disabled
     #pragma config WPDIS = ON          //WPFP[5:0], WPEND, and WPCFG bits ignored 

#else
	#error Not a supported board (yet), make sure the proper board is selected in usbcfg.h, and if so, set configuration bits in __FILE__, line __LINE__
#endif


#if defined(PICSYS18_SP) || defined(PIC18F_MOD_2553) || defined(PIC18_DEV_2550URL)

/** V A R I A B L E S ********************************************************/
#pragma udata

/** P R I V A T E  P R O T O T Y P E S ***************************************/
static void InitializeSystem(void);
void USBTasks(void);
#if !defined(__18F14K50) && !defined(__18F13K50) && !defined(__18LF14K50) && !defined(__18LF13K50)
    void BlinkUSBStatus(void);
#else
    #define BlinkUSBStatus()
#endif

/** V E C T O R  R E M A P P I N G *******************************************/
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
    _asm goto 0x1008 _endasm
}
#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
    _asm goto 0x1018 _endasm
}

#elif defined(PICSYS18_XBEE)

/** V A R I A B L E S ********************************************************/
#pragma udata
word led_count;
unsigned int pll_startup_counter;	//Used for software delay while pll is starting up


/** P R I V A T E  P R O T O T Y P E S ***************************************/
static void InitializeSystem(void);
void USBTasks(void);
void BlinkUSBStatus(void);
void Main(void);
void _entry (void);
//externs
extern void LongDelay(void);

//Be careful if modifying the below code.  The below code is absolute address sensitive, since it contains
//the reset and high/low priority interrupt vectors, as well as the bootloader entry point "BootAppStart:" at address 0x001C.
//note: On PIC18, "goto" instructions take 4 byte of program memory, while most other instructions take only 2 bytes each
#pragma code _entry_scn=0x000000		//Reset vector is at 0x00.  Device begins executing code from 0x00 after a reset or POR event
void
_entry (void)
{
	_asm
	// PICSYS18-XBEEでは、アナログポートの設定の必要なし：アドレス合わせに残します
	movlb	0x0F				//Address: 0x00		//Will be checking RB2 pushbutton state, but need to set ANCON1<PCFG8> bit first. ANCON1 register is not in access bank
	bsf		ANCON1, 0, 1		//Address: 0x02		//Configure RB2/AN8 as digital input
	bra		BootEntryIOCheck	//Address: 0x04		//bra BootEntryIOCheck skips past the high-priority interrupt redirect
	nop							//Address: 0x06		//Filler to waste 2 byte of program memory

	//HIGH PRIORITY INTRRUPT VECTOR at address 0x08
    goto 0x1008					//Address: 0x08		//If a high priority interrupt occurs, PC first goes to 0x0008, then executes "goto 0x1008" redirect

BootEntryIOCheck:
	//Perform an I/O pin check to see if we should enter either the main application firmware, or this bootloader firmware.
	//Currently using RB5 I/O pin for this purpose.  If pushbutton pressed (RB5 = 5), enter bootloader firmware.
	//If not pressed (RB5 = 1, due to pull up resistor), enter the main application firmware instead.
    btfss	PORTB, 5, 0			//Address: 0x0C		//Check RB5 I/O pin state	
    bra		BootAppStart		//Address: 0x0E		//If pushbutton pressed, enter bootloader	

	//Otherwise, need to enter the main application firmware.
	//Should restore state of BSR and ANCON1 registers to default state first.
	bcf		ANCON1, 0, 1		//Address: 0x10		//Restore ANCON1<PCFG8> bit to default
	movlb	0x00				//Address: 0x12		//Restore BSR to POR default
    goto	0x1000				//Address: 0x14		//Goto the main application firmware, user was not pressing the pushbutton to enter bootloader
    
	//LOW PRIORITY INTERRUPT VECTOR at address 0x18    
    goto	0x1018				//Address: 0x18		//If a low-priority interrupt occurs, PC first goes to 0x0018, then executes "goto 0x1018" redirect
	_endasm

BootAppStart:					//Address: 0x1C		//If executing the main application firmware, and user wishes to enter the bootloader
    												//simply execute an "_asm goto 0x001C _endasm" instruction.  This will go to this BootAppStart section,
    												//which in turn will enter the bootloader firmware.
	Main();
}	

#endif

/** D E C L A R A T I O N S **************************************************/
#pragma code


/******************************************************************************
 * Function:        void main(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Main program entry point.
 *
 * Note:            None
 *****************************************************************************/
#if defined(PICSYS18_SP) || defined(PIC18F_MOD_2553) || defined(PIC18_DEV_2550URL)
void main(void)
{
    ADCON1 = 0b00011011;			//Need to make sure RB4 can be used as a digital input pin
 	//	TRISBbits.TRISB4 = 1;	//No need to explicitly do this since reset state is = 1 already.

	mInitAllSwitches() ;

    //Check Bootload Mode Entry Condition
	if(sw2 == 1)	//This example uses the sw2 I/O pin to determine if the device should enter the bootloader, or the main application code
	{
//       	ADCON1 = 0x07;		//Restore "reset value" of the ADCON1 register
		_asm
		goto 0x1000			//If the user is not trying to enter the bootloader, go straight to the main application remapped "reset" vector.
		_endasm
	}
#elif defined(PICSYS18_XBEE)
void Main(void)
{
	//NOTE: The c018.o file is not included in the linker script for this project.
	//The C initialization code in the c018.c (comes with C18 compiler in the src directory)
	//file is instead modified and included here manually.  This is done so as to provide
	//a more convenient entry method into the bootloader firmware.  Ordinarilyy the _entry_scn
	//program code section starts at 0x00 and is created by the code of c018.o.  However,
	//the linker will not work if there is more than one section of code trying to occupy 0x00.
	//Therefore, must not use the c018.o code, must instead manually include the useful code
	//here instead.

    // Initialize the C stack pointer, and other compiler managed items as normally done in the c018.c file.
	_asm
    lfsr 1, _stack
    lfsr 2, _stack
    clrf TBLPTRU, 0 
	_endasm
	// End of the important parts of the C initializer.  This bootloader firmware does not use
	// any C initialized user variables (idata memory sections).  Therefore, the above is all
	// the initialization that is required.
#endif

    InitializeSystem();
    while(1)
    {
		ClrWdt();	
	    USBTasks();         					// Need to call USBTasks() periodically
	    										// it handles SETUP packets needed for enumeration

		BlinkUSBStatus();
		
	    if((usb_device_state == CONFIGURED_STATE) && (UCONbits.SUSPND != 1))
	    {
 	       ProcessIO();   // This is where all the actual bootloader related data transfer/self programming takes place
 	    }				  // see ProcessIO() function in the Boot87J50Family.c file.
    }//end while
}//end main

/******************************************************************************
 * 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(PICSYS18_XBEE)
	OSCCON = 0x60;	//Clock switch to primary clock source.  May not have been running
					//from this if the bootloader is called from the application firmware.

	//On the PIC18F46J50 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.

    OSCTUNEbits.PLLEN = 1;  //Enable the PLL and wait 2+ms until the PLL locks before enabling USB module
    pll_startup_counter = 600;
    while(pll_startup_counter--);
    //Device switches over automatically to PLL output after PLL is locked and ready.

	//USB module may have already been on if the application firmware calls the bootloader
	//without first disabling the USB module.  If this happens, need
	//to temporarily soft-detach from the host, wait a delay (allows cable capacitance
	//to discharge, and to allow host software to recognize detach), then
	//re-enable the USB module, so the host knows to re-enumerate the
	//USB device.
	if(UCONbits.USBEN == 1)
	{
		UCONbits.SUSPND = 0;
		UCON = 0;
		LongDelay();
	}	

#endif

    mInitializeUSBDriver();         // See usbdrv.h
    
#if defined(PICSYS18_XBEE)
	led_count = 0;			//Initialize variable used to toggle LEDs
#endif

    UserInit();                     // See user.c & .h

}//end InitializeSystem

/******************************************************************************
 * Function:        void USBTasks(void)
 *
 * PreCondition:    InitializeSystem has been called.
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Service loop for USB tasks.
 *
 * Note:            None
 *****************************************************************************/
void USBTasks(void)
{
    /*
     * Servicing Hardware
     */
    USBCheckBusStatus();                    // Must use polling method
    USBDriverService();              	    // Interrupt or polling method

}// end USBTasks


/******************************************************************************
 * 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 io_cfg.h
 *                  usb_device_state is declared in usbmmap.c and is modified
 *                  in usbdrv.c, usbctrltrf.c, and usb9.c
 *****************************************************************************/
#if !defined(__18F14K50) && !defined(__18F13K50) && !defined(__18LF14K50) && !defined(__18LF13K50)
void BlinkUSBStatus(void)
{
#if !defined(PICSYS18_XBEE)
    static word led_count=0;
#endif

    if(led_count == 0)led_count = 10000U;
    led_count--;

	 if(usb_device_state < CONFIGURED_STATE)
	 {
		 mLED_1_On();
#if defined(mLED_2)
		 mLED_1_Off();
#endif
	 } 
	 else
     {
         if(led_count==0)
         {
             mLED_1_Toggle();
#if defined(mLED_2)
             mLED_2 = !mLED_1;       // Alternate blink
#endif
         }//end if
     }//end if(...)
}//end BlinkUSBStatus
#endif


#if defined(PICSYS18_XBEE)
//Placeholder code at address 0x1000 (the start of the non-bootloader firmware space)
//This gets overwritten when a real hex file gets programmed by the bootloader.
//If however no hex file has been programmed, might as well stay in the bootloader
//firmware, even if the RB2 pushbutton was not pressed after coming out of reset.
#pragma code user_app_vector=0x1000	
void userApp(void)
{
	_asm goto 0x001C _endasm 	//Goes to the "BootAppStart:" section which will enter the bootloader firmware				
}
#endif


/** EOF main.c ***************************************************************/
