/*************************************************************************
 * DISCLAIMER *
 * Services performed by FREESCALE in this matter are performed          *
 * AS IS and without any warranty. CUSTOMER retains the final decision   *
 * relative to the total design and functionality of the end product.    *
 * FREESCALE neither guarantees nor will be held liable by CUSTOMER      *
 * for the success of this project. FREESCALE disclaims all warranties,  *
 * express, implied or statutory including, but not limited to,          *
 * implied warranty of merchantability or fitness for a particular       *
 * purpose on any hardware, software ore advise supplied to the project  *
 * by FREESCALE, and or any product resulting from FREESCALE services.   *
 * In no event shall FREESCALE be liable for incidental or consequential *
 * damages arising out of this agreement. CUSTOMER agrees to hold        *
 * FREESCALE harmless against any and all claims demands or actions      *
 * by anyone on account of any damage, or injury, whether commercial,    *
 * contractual, or tortuous, rising directly or indirectly as a result   *
 * of the advise or assistance supplied CUSTOMER in connection with      *
 * product, services or goods supplied under this Agreement.             *
 *************************************************************************/
/*************************************************************************************************
 * File name   : Hid.c
 *
 * Description : This file defines some routine for HID class standard 
 * History     :
 * 04/01/2007  : Initial Development
 * 
 *************************************************************************************************/
#include <MC9S08JM60.h>
#include "typedef.h"
#include "Bootloader_Config.h"
#include "Bootloader_Bdt.h"
#include "Bootloader_Ep0_Handler.h"
#include "Bootloader_Descriptor.h"
#include "Bootloader_Drv.h"

#include "Bootloader_tasks.h"


/* Local variable definition */
byte Current_Idle_Rate;
byte Current_Active_Protocol;               /* 0:Boot Protocol; 1:Report Protocol*/
char Rpt_Buf[64];       //star
char Rec_Buf[64];

/* Global function definition*/
void Init_EP_For_HID(void);

void HID_GetRptHandler(void);
void HID_SetRptHandler(void);

void HID_Transfer_Rpt(char *buffer, byte len);
byte HID_Receive_Rpt(char *buffer, byte len);


/******************************************************************************
 * Function:        void HID_InitEP(void)
 * Input:           None
 * Output:          None
 *
 * Overview:        This function initializes the endpoints assigned to HID, 
 *                  state-machine,etc.
 *                  It should be called when USB host has sent out a
 *                  SET_CONFIGURATION request.
 *****************************************************************************/
void Init_EP_For_HID(void)
{   
    HID_UEP_IN = EP_IN|HSHK_EN;                
    HID_UEP_OUT = EP_OUT|HSHK_EN;
    
    HID_BD_OUT.Cnt = sizeof(Hid_Report_Out);    
    HID_BD_OUT.Addr =  0x20;     //( (byte)( (&Hid_Report_Out) - 0x1860)  )>>2 ; //can be calculated out
    HID_BD_OUT.Stat._byte = _SIE|_DATA0|_DTS; 

    HID_BD_IN.Addr = 0x10;       //( (byte)( (&Hid_Report_In) - 0x1860) >> 2 );      // Set buffer address
    HID_BD_IN.Stat._byte = _CPU|_DATA1;       
    
    
    return;
}


/******************************************************************************
 * Function:        void Check_HIDClassRequest(void)
 * Input:           None
 * Output:          None
 * Overview:        This program checks the setup data packet to see if it
 *                  belong to HID standard request
 * Note:            None
 *****************************************************************************/
void HID_Class_Request_Handler(void)
{
    if( (Setup_Pkt.CtlReqT.Recipient != RCPT_INTF) && (Setup_Pkt.CtlIntf.bIntfID != HID_INTF_ID) )
        return;
    
    if(Setup_Pkt.StdCtl.bRequest == GET_DSC)
    {
        switch(Setup_Pkt.ReqWval.bDscType)
        {
            case DSC_HID:
                Transfer_Cnt = sizeof(USB_HID_DSC);
                USBGetHIDDscAddr(pSrc);        
                Ctrl_Trf_Session_Owner = HID_CLASS_ID;
                break;
                
            case DSC_RPT:
                USBGetHIDRptDscSize(Transfer_Cnt);
                USBGetHIDRptDscAddr(pSrc);     
                Ctrl_Trf_Session_Owner = HID_CLASS_ID;
                break;
                
            case DSC_PHY:
                /* Physical descriptor is optional in HID class specification*/
                /* It is not supported in this application*/
                /* See the HID class specification 1.1*/
                break;
                
            default: 
                break;
        }
        
    } 
    
    if(Setup_Pkt.CtlReqT.RequestType != CLASS) 
      return;
    
    Ctrl_Trf_Session_Owner = HID_CLASS_ID;
    


    switch(Setup_Pkt.StdCtl.bRequest)
    {
//        case GET_REPORT:
//            HID_GetRptHandler();
//            break;
            
        case SET_REPORT:
            HID_SetRptHandler();            
            break;
            
        case GET_IDLE:
            Transfer_Cnt = 1;                      /* Set data count*/
            pSrc = (byte*)&Current_Idle_Rate;      /* Set source*/
            Ctrl_Trf_Session_Owner = HID_CLASS_ID;
            break;
            
        case SET_IDLE:
            Current_Idle_Rate = LSB(Setup_Pkt.CtlPara.W_Value);
            Ctrl_Trf_Session_Owner = HID_CLASS_ID;
            break;
            
        case GET_PROTOCOL:
            Transfer_Cnt = 1;                       /* Set data count*/
            pSrc = (byte*)&Current_Active_Protocol; /* Set source */
            Ctrl_Trf_Session_Owner = HID_CLASS_ID;
            break;
            
        case SET_PROTOCOL:
            Current_Active_Protocol = MSB(Setup_Pkt.CtlPara.W_Value);
            Ctrl_Trf_Session_Owner = HID_CLASS_ID;
            break;
 
        default:
            break;
 
    }

}



/******************************************************************************
 * Function:        void HID_GetRptHandler(void)
 * Input:           None
 * Output:          None
 * Overview:      
 * Note:            None
 *****************************************************************************/

void HID_GetRptHandler(void)
{
//   byte result[2];    
   switch(Setup_Pkt.ReqWval.bDscIndex)                 /*report type*/
   {                                                   /*report ID is not used*/
    case 0x00:
//      result[0]=0xa5;
//      result[1]=0x00;
//      pSrc = (byte*)result;
//      Transfer_Cnt  = 2;    /*report length use the default value*/
//      Ctrl_Trf_Session_Owner = HID_CLASS_ID;
//    break;


    case 0x01:
      pObj = (byte*)Hid_Report_In;
      pSrc = (byte*)Rpt_Buf;
      Transfer_Cnt  = HID_INT_IN_EP_SIZE;    /*report length use the default value*/
      Ctrl_Trf_Session_Owner = HID_CLASS_ID;
    break;
     
    case 0x02:                                        /*This is optional*/
      pObj = (byte*)Hid_Report_In;
      pSrc = (byte*)Rec_Buf;
      Transfer_Cnt  = HID_INT_OUT_EP_SIZE;
      Ctrl_Trf_Session_Owner = HID_CLASS_ID;
    break;
    
    default:
    break;
   }
   
}


/******************************************************************************
 * Function:        void HID_SetRptHandler(void)
 * Input:           None
 * Output:          None
 * Overview:      
 * Note:            None
 *****************************************************************************/
void HID_SetRptHandler(void)
{
  switch(Setup_Pkt.ReqWval.bDscType)                 /*report type*/
   {                                                   /*report ID is not used*/
    case 0x01:
      pObj = (byte*)Rpt_Buf;
      pSrc = (byte*)Hid_Report_Out;
      Transfer_Cnt  = HID_INT_IN_EP_SIZE;    /*report length use the default value*/
      Ctrl_Trf_Session_Owner = HID_CLASS_ID;
    break;
     
    case 0x02:                                        /*This is optional*/
      pObj = (byte*)Rec_Buf;
      pSrc = (byte*)Hid_Report_Out;
      Transfer_Cnt  = HID_INT_OUT_EP_SIZE;
      Ctrl_Trf_Session_Owner = HID_CLASS_ID;
    break;

    case 0x03:                                        /*This is optional*/
      pObj = (byte*)Rec_Buf;
      pSrc = (byte*)Hid_Report_Out;
      Transfer_Cnt  = HID_INT_OUT_EP_SIZE;
      Ctrl_Trf_Session_Owner = HID_CLASS_ID;
    break;

    
    default:
    break;
   }
     
  return;
}



/******************************************************************************
 * Function:        void HID_Transfer_Rpt(char *buffer, byte len)
 * Input:           buffer  : Pointer to the starting location of data bytes
 *                  len     : Number of bytes to be transferred
 * Output:          None
 *
 * Overview:      
 *
 * Note:            None
 *****************************************************************************/
void HID_Transfer_Rpt(char *buffer, byte len)
{
	byte i;

	if(len > HID_INT_IN_EP_SIZE)   /* the data length should be equal to or smaller than HID_INT_IN_EP_SIZE.*/
	    len = HID_INT_IN_EP_SIZE;
	
   /* Copy data from user's buffer to dual-ram buffer*/
   for (i = 0; i < len; i++)
   	Hid_Report_In[i] = buffer[i];

   HID_BD_IN.Cnt = len;
   USB_Buf_Rdy(&HID_BD_IN);

}

/******************************************************************************
 * Function:        byte HID_Receive_Rpt(char *buffer, byte len)
 *
 * Input:           buffer  : Pointer to where received bytes are to be stored
 *                  len     : The number of bytes expected.
 * Output:          The number of bytes copied to buffer.

 * Overview:        HID_Receive_Rpt copies a string of bytes received through
 *                  USB HID OUT endpoint to a user's specified location. 
 *                  It is a non-blocking function. It does not wait
 *                  for data if there is no data available. Instead it returns
 *                  '0' to notify the caller that there is no data available.
 *
 *****************************************************************************/
byte HID_Receive_Rpt(char *buffer, byte len)
{
    byte Rx_Len = len;
    byte i;
    
    if(!HID_BD_OUT.Stat.McuCtlBit.OWN)
    {
        if(Rx_Len > HID_BD_OUT.Cnt)
            Rx_Len = HID_BD_OUT.Cnt;
        
        for(i = 0; i < len; i++)
            buffer[i] = Hid_Report_Out[i];

        HID_BD_OUT.Cnt = sizeof(Hid_Report_Out);
        USB_Buf_Rdy(&HID_BD_OUT);
    }
    
    return Rx_Len;
    
}

