/********************************************************************
 * FileName:        mouse_demo.c
 * Dependencies:    see "Includes Section"
 * Processor:       PIC32F4xx FAMILY
 *
 * Hardware:        Explorer 16 or PIC32 USB Starter Board
 *                  MPLAB IDE v8.15 or later
 * Company:         Microchip Technology, Inc.
 *
 * Copyright (c) 2008 Microchip Technology, Inc.
 * Software License Agreement
 *
 * 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:
 *
 * USB Device HID Mouse Demo
 *
 * Change History:
 * Name         Date            Changes
 ********************************************************************/
 
// Includes Section
#include <plib.h>
#include "HardwareProfile.h"
#include "USB/usb.h"
#include "USB/usb_device_hid.h"
#include "ex16lcd.h"


// Configuration Section

#ifndef OVERRIDE_CONFIG_BITS
        
    #pragma config UPLLEN   = ON            // USB PLL Enabled
    #pragma config FPLLMUL  = MUL_20        // PLL Multiplier
    #pragma config UPLLIDIV = DIV_2         // USB PLL Input Divider
    #pragma config FPLLIDIV = DIV_2         // PLL Input Divider
    #pragma config FPLLODIV = DIV_1         // PLL Output Divider
    #pragma config FPBDIV   = DIV_1         // Peripheral Clock divisor
    #pragma config FWDTEN   = OFF           // Watchdog Timer 
    #pragma config WDTPS    = PS1           // Watchdog Timer Postscale
    #pragma config FCKSM    = CSDCMD        // Clock Switching & Fail Safe Clock Monitor
    #pragma config OSCIOFNC = OFF           // CLKO Enable
    #pragma config POSCMOD  = HS            // Primary Oscillator
    #pragma config IESO     = OFF           // Internal/External Switch-over
    #pragma config FSOSCEN  = OFF           // Secondary Oscillator Enable
    #pragma config FNOSC    = PRIPLL        // Oscillator Selection
    #pragma config CP       = OFF           // Code Protect
    #pragma config BWP      = OFF           // Boot Flash Write Protect
    #pragma config PWP      = OFF           // Program Flash Write Protect
    #pragma config ICESEL   = ICS_PGx2      // ICE/ICD Comm Channel Select
    #pragma config DEBUG    = OFF           // Debugger Disabled for Starter Kit
                
#endif // OVERRIDE_CONFIG_BITS


/*************************************************************************
 Global Data
 *************************************************************************/

volatile unsigned int   EmulateMouseTimer;
volatile unsigned int   MouseXTimer;
volatile unsigned int   MouseYTimer;
volatile unsigned int   MouseLeftTimer;

volatile BOOL           EmulateMousePressed;
volatile BOOL           MouseXPressed;
volatile BOOL           MouseYPressed;
volatile BOOL           MouseLeftPressed;

volatile BOOL           AnyKeyPressed;

volatile unsigned int   LEDTimer;

volatile BOOL           Attached;
volatile PRIVATE BOOL   Suspended;
volatile BOOL           RemoteWakeEnabled;
         BOOL           Emulate;
         BOOL           PreviousEmulatePressed;


/*************************************************************************
 UpdateStatus
 *************************************************************************/
void UpdateStatus(void)
{
    // Update the emulation status
    if (EmulateMousePressed && !PreviousEmulatePressed)
        Emulate = !Emulate;
    PreviousEmulatePressed = EmulateMousePressed;

    // Display the updated status
    if (LEDTimer > LED_BLINK_INTERVAL)
    {
        LEDTimer = 0;
        if( Emulate )
        {
            // Change switch description on the LCD
            mSendMessage3();

            if ( Attached && !Suspended )
            {
                mToggleONOff();
            }
            else
            {
                mTurnON();
            }
        }
        else
        {
            mTurnOFF();
            mSendMessage2();
        }
    }

}//end UpdateStatus


/***********************************************************
 * void MOUSEInit(void)
 ***********************************************************/
void MOUSEInit(void)
{
    unsigned int temp;

    // Configure cache, wait states and peripheral bus clock
    SYSTEMConfig(SYS_CLOCK, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

    // Initialize Data
    EmulateMouseTimer       = 0;
    MouseXTimer             = 0;
    MouseYTimer             = 0;
    MouseLeftTimer          = 0;
                            
    EmulateMousePressed     = FALSE;
    MouseXPressed           = FALSE;
    MouseYPressed           = FALSE;
    MouseLeftPressed        = FALSE;
                            
    AnyKeyPressed           = FALSE;
                            
    LEDTimer                = 0;
                            
    Attached                = FALSE;
    Suspended               = FALSE;
    RemoteWakeEnabled       = FALSE;

    Emulate                 = STARTUP_EMULATION_STATE;

    // Initialize buttons & LEDs
    mInitAllLEDs();
    mInitializeEmulateMouse();
    mInitializeMouseY();
    mInitializeMouseX();
    mInitializeMouseLeftButton();

    // Set up the debounce timer interrupt with a priority of 2
    OpenTimer3(T3_ON | T3_SOURCE_INT | T3_PS_1_16, TIMER_PERIOD);
    ConfigIntTimer3(T3_INT_ON | T3_INT_PRIOR_2);

    // Initialize change-notice for remote wake up 
    mCNOpen(CONFIG, PINS, PULLUPS);
    temp = mPORTDRead();
    ConfigIntCN(INTERRUPT);

    // Set priority and enable USB interrupt
    IFS1CLR     = 0x02000000;
    IPC11SET    = 0x00001000;
    IEC1SET     = 0x02000000;

    // Enable multi-vector interrupts
    INTEnableSystemMultiVectoredInt();

    // Initialize the LCD
    mInitMessage();
    mSendMessage1();
    mSendMessage2();

}


/***********************************************************
 * void MOUSETask(void)
 ***********************************************************/
void MOUSETask(void)
{
    BYTE report[3];

    // Watch for wake from suspend
    if (Suspended && RemoteWakeEnabled && AnyKeyPressed)
    {
        Suspended = FALSE;
        HIDSignalResume();
    }
    AnyKeyPressed = FALSE;

    // Watch for mouse buttons
    if( Emulate )
    {
        if ( Attached && !Suspended )
        {
            report[0] = 0;
            report[1] = 0;
            report[2] = 0;

            if(MouseYPressed)
            {
                if(MouseLeftPressed)
                    report[1] = 4;
                else
                    report[1] = -4;
            }

            if(MouseXPressed)
            {
                if(MouseLeftPressed)
                    report[2] = 4;
                else
                    report[2] = -4;
            }

            HIDSendReport(0, report, 3, TRUE);
        }
    }

}


/*************************************************************************
 SuspendHandler
 *************************************************************************/
void SuspendHandler ( void )
{
    if (Attached)
    {
        Suspended = TRUE;

        #ifdef SLEEP_WHEN_SUSPENDED
        
            mSuspended();

            ConfigIntTimer3(T3_INT_OFF | T3_INT_PRIOR_2);

            if (RemoteWakeEnabled)
                ConfigIntCN(CHANGE_INT_ON|CHANGE_INT_PRI_3);

            U1OTGIRbits.ACTVIF = 1;
            PowerSaveSleep();

            if (RemoteWakeEnabled)
                ConfigIntCN(CHANGE_INT_OFF|CHANGE_INT_PRI_3);

            ConfigIntTimer3(T3_INT_ON | T3_INT_PRIOR_2);

            mNotSuspended();

        #endif
    }
}


/*************************************************************************
 HidMouseDemoEventHandler
 
 This routine is called by the HID driver when an event has occured.
 *************************************************************************/

BOOL HidMouseDemoEventHandler (  USB_EVENT event, void *data, unsigned int size  )
{
    switch (event)
    {
    case EVENT_ATTACH:
        Attached          = TRUE;
        Suspended         = FALSE;
        RemoteWakeEnabled = FALSE;
        mWakeDisabled();
        break;

    case EVENT_RESUME:
        Suspended = FALSE;
        break;

    case EVENT_SET_WAKE_UP:
        RemoteWakeEnabled = TRUE;
        mWakeEnabled();
        break;

    case EVENT_CLEAR_WAKE_UP:
        RemoteWakeEnabled = FALSE;
        mWakeDisabled();
        break;

    case EVENT_SUSPEND:
        SuspendHandler();
        break;

    case EVENT_DETACH:
        Attached          = FALSE;
        Suspended         = FALSE;
        RemoteWakeEnabled = FALSE;
        mWakeDisabled();
        break;

    default:
        return FALSE;
    }

    return TRUE;

} // HidMouseDemoEventHandler


/*************************************************************************
 Main entry point
 *************************************************************************/

int main(void)
{
/* 	
	PIC32 Peripheral Library functions SYSTEMConfigPerformance() and SYSTEMConfig()
	configures system parameters, such as Flash wait states, RAM wait states, 
	enable cache and set Peripheral Bus Clock (PBCLK) frequency for optimal
	system performance based on the system clock frequency argument.
	
	SYSTEMConfigPerformance() ignores the PBCLK fuse selection FPBDIV and calculates
	the fastest possible PBCLK based on the system clock frequency parameter.
	Use this function if you want to set the fastest PBCLK frequency.
	Example: SYSTEMConfigPerformance(80000000);  //@80MHz PBCLK ratio = 1:1

	SYSTEMConfig() uses the PBCLK defined by configuration fuse selection FPBDIV 
	set in code or from the MPLAB IDE Configuration Bits menu.
	Use this function if you want to maintain the PBCLK frequency set by FPBDIV.
	Example: SYSTEMConfig(80000000, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
*/
   	SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
	
    MOUSEInit();

    USBInitialize(0);

    while(1)
    {
        // Maintain the USB stack operation
        USBTasks();

        // Maintain mouse operation
        MOUSETask();

        // Update & display the status of the demo
        UpdateStatus();
    }

} // main


/*************************************************************************
 Timer 3 ISR
 
 Used to de-bounce buttons
 *************************************************************************/

void __ISR(_TIMER_3_VECTOR, ipl2) _T3Interrupt(void)
{
     BOOL NewState;

     LEDTimer++;

     // Clear the interrupt flag
     mT3ClearIntFlag();

    // Debounce Emulate Mouse Button
     NewState = mGetEmulateMouse() ? FALSE : TRUE;
     if (NewState == EmulateMousePressed)
         EmulateMouseTimer   = 0;
     else
         EmulateMouseTimer++;
     if (EmulateMouseTimer > BUTTON_DEBOUNCE_LIMIT)
     {
         EmulateMousePressed = NewState;
         AnyKeyPressed       = TRUE;
     }

     // Debounce Mouse X Button
     NewState = mGetMouseX() ? FALSE : TRUE;
     if (NewState == MouseXPressed)
         MouseXTimer   = 0;
     else
         MouseXTimer++;
     if (MouseXTimer > BUTTON_DEBOUNCE_LIMIT)
     {
         MouseXPressed = NewState;
         AnyKeyPressed = TRUE;
     }

     // Debounce Mouse Y Button
     NewState = mGetMouseY() ? FALSE : TRUE;
     if (NewState == MouseYPressed)
         MouseYTimer   = 0;
     else
         MouseYTimer++;
     if (MouseYTimer > BUTTON_DEBOUNCE_LIMIT)
     {
         MouseYPressed = NewState;
         AnyKeyPressed = TRUE;
     }

     // Debounce Mouse Left Button
     NewState = mGetMouseLeftButton() ? FALSE : TRUE;
     if (NewState == MouseLeftPressed)
         MouseLeftTimer   = 0;
     else
         MouseLeftTimer++;
     if (MouseLeftTimer > BUTTON_DEBOUNCE_LIMIT)
     {
         MouseLeftPressed = NewState;
         AnyKeyPressed    = TRUE;
     }
}


/*************************************************************************
 Change Notice ISR
 
 Used for remote wake up
 *************************************************************************/
void __ISR(_CHANGE_NOTICE_VECTOR, ipl3) ChangeNotice_Handler(void)
{
    unsigned int temp;

    // clear the mismatch condition
    temp = mPORTDRead();

    // clear the interrupt flag
    mCNClearIntFlag();

    // Clear the suspended state
    if ( Suspended && RemoteWakeEnabled )
    {
        Suspended = FALSE;
        HIDSignalResume();

    }
}

/*************************************************************************
 USB ISR
 
 Necessary to wake up device when sleeping
 *************************************************************************/
#ifdef SLEEP_WHEN_SUSPENDED
    void __ISR(_USB1_VECTOR, ipl4) _USB1Interrupt(void)
    {
        U1OTGIRbits.ACTVIF = 1;
        U1OTGIEbits.ACTVIE = 0;
        IFS1CLR = 0x02000000; // USBIF
    }
#endif

