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

         Microchip USB Generic Demo Firmware Version 1.0

********************************************************************
 FileName:        user.c
 Dependencies:    See INCLUDES section below
 Processor:       PIC18
 Compiler:        C18 2.30.01+
 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.

 Author               Date        Comment
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Rawin Rojvanit       11/19/04    Original.
 Bud Caldwell         03/19/07    Modified for PIC32
 ********************************************************************/


/** I N C L U D E S *************************************************/
#include <GenericTypeDefs.h>
#include <plib.h>
#include "HardwareProfile.h"
#include "USB/usb.h"
#include "USB/usb_device_generic.h"
#include "user.h"


/** LOCAL DEFINES ***************************************************/
#define TIMER_1_PERIOD  31250   // 100msec period @80MHz and 1:256 prescale
#define TIMER_3_PERIOD  50000   // 10msec period @80MHz and 1:16 prescale


/** LOCAL VARIABLES *************************************************/
DATA_PACKET dataPacket;

unsigned int dummy;
unsigned data_logging_flag = 0;

// Temperature Log Variables
BYTE pTemp = 0;                     // Pointer to current logging position, 
                                    //   will loop to zero once the max index is reached
BYTE valid_temp = 0;                // Keeps count of the valid data points
WORD temp_data[30];                 // 30 points of data
BYTE counter;
BYTE temp_mode = TEMP_REAL_TIME;
BYTE SW1_Timer = 0;
BOOL SW1Pressed = FALSE;
BYTE SW2_Timer = 0;
BOOL SW2Pressed = FALSE;
BYTE SW3_Timer = 0;
BOOL SW3Pressed = FALSE;
BOOL AnyKeyPressed = FALSE;
 
 
/** LOCAL PROTOTYPES  ***********************************************/
void SetTemperature(signed short);
void ChangeTemperature(signed short);
void ChangePot(signed short);
unsigned short GetTemperature(void);
unsigned short GetPot(void);


signed short   sim_temperature = 25;    // initial temperature expressed in degrees C
unsigned short sim_pot         = 5000;  // initial pot value expressed in ohms


/*************************************************************************
 Function:        void UserInit(void)
 
 Input:           none
 
 Output:          none
 
 Returns:         none
 
 Side Effects:    Initializes the "user" application
 
 Overview:        Initializes all LEDs, switches, and global variables
                  as well as timers used.
 
 Notes:          
 *************************************************************************/

void UserInit(void)
{
    // Init port pins to drive the LEDs
    mInitAllLEDs();
    
    // Init port pins for inputs and enable weak pullups
    mInitAllSwitches();
    
    // Init timer 1 for 100msec interrupt rate (data logging scheduler)
    OpenTimer1(T1_ON|T1_PS_1_256, TIMER_1_PERIOD);
    ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_2);
    
    // Init Timer 3 for 10msec interrupt rate for switch debounce
    OpenTimer3(T3_ON | T3_SOURCE_INT | T3_PS_1_16, TIMER_3_PERIOD);
    ConfigIntTimer3(T3_INT_ON | T3_INT_PRIOR_3);

} // UserInit


/******************************************************************************
 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)
{
#define TEMPERATURE_CHANGE_VALUE        1
#define POT_CHANGE_VALUE                100

    // Service the requests from the host
    ServiceRequests();

    // process the buttons
    if(AnyKeyPressed)
    {
        // Adjust temperature DOWN
        if(SW1Pressed && SW3Pressed)
        {
            ChangeTemperature(-TEMPERATURE_CHANGE_VALUE);
            SW1Pressed = FALSE;
            SW3Pressed = FALSE;
        }
        // Adjust temperature UP
        else if(SW3Pressed)
        {
            ChangeTemperature(TEMPERATURE_CHANGE_VALUE);
            SW1Pressed = FALSE;
        }
        
        // Adjust pot DOWN
        else if(SW1Pressed && SW2Pressed)
        {
            ChangePot(-POT_CHANGE_VALUE);
            SW2Pressed = FALSE;
            SW3Pressed = FALSE;
        }
        // Adjust pot UP
        else if (SW2Pressed)
        {
            ChangePot(POT_CHANGE_VALUE);
            SW2Pressed = FALSE;
        }
        
        AnyKeyPressed = FALSE;
    
     }// end if(AnyKeyPressed)
    
    
    /* If data logging is enabled, the process the event */
    if(temp_mode == TEMP_LOGGING)
    {
        // Watch for data logging flag
        if(data_logging_flag == 1)
        {
            data_logging_flag = 0;
            temp_data[pTemp] = GetTemperature();

            // First update valid_temp
            if(valid_temp < 30)         // 30 data points max
            {
                valid_temp++;
            }

            // Next update pTemp
            if(pTemp >= 29)
            {
                pTemp = 0;
            }
            else
            {
                pTemp++;
            }
         }
    }
  
} // ProcessIO


/******************************************************************************
 Function:        void ServiceRequests(void)
 
 PreCondition:    None
 
 Input:           None
 
 Output:          None
 
 Side Effects:    None
 
 Overview:        Service the HOST commands
 
 Note:            None
 *****************************************************************************/

void ServiceRequests(void)
{
    BYTE index;
    
    if(USBGenRead((BYTE*)&dataPacket, sizeof(dataPacket)))
    {
        counter = 0;
        switch(dataPacket.CMD)
        {
            case READ_VERSION:
                //dataPacket._byte[1] is len
                dataPacket._byte[3] = MAJOR_VERSION;
                dataPacket._byte[2] = MINOR_VERSION;
                counter=0x04;
                break;

            case UPDATE_LED:
                // LED2 & LED3 are used as USB event indicators.
                if(dataPacket.len == 3)
                {
                    mLED_2 = dataPacket._byte[2];
                    counter = 0x01;
                }//end if
                else if(dataPacket.len == 4)
                {
                    mLED_3 = dataPacket._byte[2];
                    counter = 0x01;
                }
                break;
                
            case SET_TEMP_REAL:
                temp_mode = TEMP_REAL_TIME;
                ResetTempLog();
                counter = 0x01;
                break;

            case RD_TEMP:
                // Simulated temperature
                dataPacket.word_data = GetTemperature();
                counter=0x03;
                break;

            case SET_TEMP_LOGGING:
                temp_mode = TEMP_LOGGING;
                ResetTempLog();
                counter=0x01;
                break;

            case RD_TEMP_LOGGING:
                counter = (valid_temp<<1)+2;  // Update count in byte
                dataPacket.len = (valid_temp<<1);

                for(index = valid_temp; index > 0; index--)
                {
                    if(pTemp == 0)
                        pTemp = 29;
                    else
                        pTemp--;
                    dataPacket._word[index] = temp_data[pTemp];
                }//end for
                
                ResetTempLog(); // Once read, log will restart
                break;

            case RD_POT:
                dummy = GetPot();
                dataPacket._byte[1] = (BYTE)(dummy &  0xFF);
                dataPacket._byte[2] = (BYTE)(dummy >> 8);
                counter=0x03;
                break;
                
            case RESET:
                break;
                
            default:
                break;

        } // end switch()


        if(counter != 0)
        {
            if(!mUSBGenTxIsBusy())
            {
                USBGenWrite((BYTE*)&dataPacket,counter);
            }
        }//end if

    }

} // ServiceRequests


/*************************************************************************
 Function:        _T1Interrupt(void)
 
 PreCondition:    None
 
 Input:           None
 
 Output:          None
 
 Side Effects:    None
 
 Overview:        Come here every 100msec.  After 10 iterations, set data
                  logging flag to enable new data point capture (if enabled)
 
 Note:            None
 *************************************************************************/

void __ISR(_TIMER_1_VECTOR, ipl2) _T1Interrupt(void)
{
     #define MAX_EVENT_CNT   10
     
     static unsigned int irq_event_cnt = 0;
     
     // Clear the interrupt flag
     mT1ClearIntFlag();
     
     // Increment the event count
     irq_event_cnt++;

     // Blink the attached status LED
     if( irq_event_cnt & 1 )
     {
         if ( USBGenIsAttached() )
         {
             mLED_1_Toggle();
         }
         else
         {
             mLED_1_Off();
         }
     }
     
     // Update the count & set the logging flag.
     if(irq_event_cnt == MAX_EVENT_CNT )
     {
         irq_event_cnt      = 0;
         data_logging_flag  = 1;
     }

} // _T1Interrupt


/*************************************************************************
 * Function:        _T3Interrupt(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Come here every 10msec
 *
 * Note:            None
 *************************************************************************/

void __ISR(_TIMER_3_VECTOR, ipl3) _T3Interrupt(void)
{
     #define NOT_PRESSED            1
     #define PRESSED                0
     #define MAX_LOOP_CNT           2
     
     BOOL ButtonState;
     static unsigned int irq_loop_cnt = 0;
     
     // Clear the interrupt flag
     mT3ClearIntFlag();
     
     if(irq_loop_cnt++ == MAX_LOOP_CNT)
     {
         // check SW1 status
        ButtonState = mGetSW1() ? NOT_PRESSED : PRESSED;
        if(ButtonState == PRESSED)
            SW1_Timer++;
        else
            SW1_Timer = 0, SW1Pressed = FALSE;
            
        if (SW1_Timer > BUTTON_DEBOUNCE_LIMIT)
        {
            SW1Pressed = TRUE;
            AnyKeyPressed = TRUE;
            SW1_Timer = 0;
        }
        
        // check SW2 status 
        ButtonState = mGetSW2() ? NOT_PRESSED : PRESSED;
        if(ButtonState == PRESSED)
            SW2_Timer++;
        else
            SW2_Timer = 0, SW2Pressed = FALSE;
        
        if (SW2_Timer > BUTTON_DEBOUNCE_LIMIT)
        {
            SW2Pressed = TRUE;
            AnyKeyPressed = TRUE;
            SW2_Timer = 0;
        } 
         
         // check SW3 status
        ButtonState = mGetSW3() ? NOT_PRESSED : PRESSED;
        if(ButtonState == PRESSED)
            SW3_Timer++;
        else
            SW3_Timer = 0, SW3Pressed = FALSE;
        
        if (SW3_Timer > BUTTON_DEBOUNCE_LIMIT)
        {
            SW3Pressed = TRUE;
            AnyKeyPressed = TRUE;
            SW3_Timer = 0;
        }
       
     irq_loop_cnt = 0;

    }

} // _T3Interrupt


/************************************************************************
  BELOW ARE THE HELPER FUNCTIONS FOR THIS DEMO APPLICATION
*************************************************************************/

/*************************************************************************
 Function:        unsigned short GetTemperature(void)
 
 PreCondition:    None
 
 Input:           None
 
 Output:          Simulated temperature (C) * 128 (converts to ADC counts)
                  expected by the HOST
 
 Side Effects:    None
 
 Overview:        PIC32 Starter Kit has no temperature.  Return the global
                  simulated temperature value instead.
 
 Note:            None
 *************************************************************************/

unsigned short GetTemperature(void)
{
    return ((sim_temperature * 128) | VALID_FLAG);
}


/*************************************************************************
 Function:        (void)
 
 PreCondition:    None
 
 Input:           delta: a value (expressed in degrees C) representing the
                  desired change in temperature.
 
 Output:          None
 
 Side Effects:    None
 
 Overview:        This function limits any changes to the simulated
                  temperature between 0 and 50 degrees C.      
 
 Note:            None
 *************************************************************************/

void ChangeTemperature(signed short delta)
{
    sim_temperature+=delta;

    if( sim_temperature > 50 )
    {
        sim_temperature = 50;
    }
    else if(sim_temperature < 0)
    {
        sim_temperature = 0;
    }
}


/*************************************************************************
 Function:        unsigned short GetPot(void)
 
 PreCondition:    None
 
 Input:           None
 
 Output:          Simulated pot value (ohms) converted to ADC counts.
 
 Side Effects:    None
 
 Overview:        PIC32 Starter Kit has no POT.  Return the global
                  simulated POT value instead. 
 
 Note:            None
 *************************************************************************/

unsigned short GetPot(void)
{
    return( (sim_pot * 1000) / 9775 );
}


/*************************************************************************
 Function:        void ChangePot(signed short delta)
 
 PreCondition:    None
 
 Input:           delta: a value (expressed in ohms) representing the
                  desired change in pot value.
 
 Output:          previous pot value plus delta.
 
 Side Effects:    None
 
 Overview:        This function limits any changes to the simulated pot
                  value between 0 and 10000 ohms.
 
 Note:            None
 *************************************************************************/

void ChangePot(signed short delta)
{
    sim_pot += delta;

    if( (signed short)sim_pot > 10000 )
    {
        sim_pot = 10000;
    }
    else if( (signed short) sim_pot < 0 )
    {
        sim_pot = 0;
    }
}


/******************************************************************************
 Function:        void ResetTempLog(void)
 
 PreCondition:    None
 
 Input:           None
 
 Output:          None
 
 Side Effects:    None
 
 Overview:        
 
 Note:            None
 *****************************************************************************/

void ResetTempLog(void)
{
    pTemp      = 0;
    valid_temp = 0;
}


/** EOF user.c ***************************************************************/

