/*************************************************************************
 * 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   : mouse.c
 *
 * Description : This file processes the mouse report 
 *               
 *
 * History     :
 * 04/01/2007  : Initial Development
 * 
 *************************************************************************************************/

#include <MC9S08JM60.h>
#include "typedef.h"
#include "mouse.h"
#include "Usb_drv.h"
#include "adc.h"
#include "kbi.h"
#include "rtc.h"
#include "starlight.h"
#include <hidef.h> 



/*Local variable definition*/
static byte Emulate_Mode;
static signed char Dir_Table[]= {-10,0,1, -3, 0, -15, 0, -2};
static byte Move_Len = 0;
static signed char  Shift_Val = 0; 
static unsigned char Adc_Ch = 0x00;
static word Adc_Result;

/*Global variable definition*/
//star char Rec_Buf[4];
char Rec_Buf[64];       //star
//char Rpt_Buf[4];
char Rpt_Buf[64];      //star

byte PC_Rx_DataBuffer[CMD_DATA_BUFFER_SIZE];
byte PC_Tx_DataBuffer[64];


byte SPI_Tx_length;
byte newdatafromPC;
byte PCCommandPacketCompleted=TRUE;
byte PCSub_Packet_Count;
byte sendout_IN_data=FALSE;

byte SPI_TimeOutCounter;
byte FPGARST_TimeOutCounter;

byte FPGAstate=FPGA_NORMAL;

byte RxPacketCount=0;

byte FPGA_RxBuffer[FPGA_RX_SIZE];

byte FPGA_GetRegisterNow=FALSE;

byte SPIsendcompleted=TRUE;

byte PFGA_SPI_data_being_sent=FALSE;

byte New_OUT_Token_During_SPI_Tx=FALSE;

byte CMD_Size_Change_from_164=FALSE;
byte Existing_CMD_164byte=FALSE; 

/*Local Function definition*/
void USB_Status_Indictor(void);
void Get_Offset(void);
void Emulate_Mouse_WithButton(void);


#ifdef USE_ACCELEROMETER    /*Use the 3 axis accelerator on demo board as the mouse input*/
void Set_Sentivity(char Sen);
void Emulate_Mouse_WithAccel(void);
#endif

/*Global Function definition*/
void Sw_Init(void);                                       
void Usr_Task(void);
void HID_Rec_Data(void);
void HID_Rec_Data(void);

extern void send_SPI_data(byte Tx_size);
extern void init_testbuffer(void);  
extern void task_SPI(void);

/******************************************************************************
 * Function:        void Sw_Init(void)
 * Input:           None
 * Output:          None
 * Overview:        This function initializes the mouse report structure
 *                
 *****************************************************************************/
void Sw_Init(void)
{
    Rpt_Buf[0]=0;
    Rpt_Buf[1]=0;
    Rpt_Buf[2]=0;
    Rpt_Buf[3]=0;
    Emulate_Mode = 0;
}



/******************************************************************************
 * Function:        void ProcessIO(void)
 * Input:           None
 * Output:          None
 * Overview:        This function is the entry for mouse (or other usuage)
 *                
 *****************************************************************************/
void Usr_Task(void)
{   
    byte i;

    if (Kbi_Stat>0){
 //       newdatafromPC=1;
        Kbi_Stat = 0;
    }
    
    task_SPI();
 
          
   if (sendout_IN_data){
   
      Rpt_Buf[0]=0;
      
      for (i=1;i<5;i++){
          Rpt_Buf[i]= FPGA_RxBuffer[i+6];
      }
    HID_Transfer_Rpt(Rpt_Buf,64);

     sendout_IN_data=FALSE;
     FPGA_GetRegisterNow=FALSE;
     
           for (i=1;i<5;i++){
         FPGA_RxBuffer[i]=0;
      }

   }
 

//starlight
//starlight    USB_Status_Indictor();

    if((Usb_Device_State < CONFIGURED_STATE)||(USBCTL0_USBRESMEN == 1) || (INTENB_RESUME ==1))
  		return;
   

    
   #ifdef USE_ACCELEROMETER
      Emulate_Mouse_WithAccel();
   #else
//star      Get_Offset();
//star      Emulate_Mouse_WithButton();
   #endif


}

/******************************************************************************
 * Function:        (void)
 * Input:           None
 * Output:          None
 * Overview:        This function gets the input from mouse movement
 *                  
 *****************************************************************************/
void Check_PC_command(void){
  

}



/******************************************************************************
 * Function:        void Get_Offset(void)
 * Input:           None
 * Output:          None
 * Overview:        This function gets the offset value for pushing the button 
 *                  each time 
 *                  
 *****************************************************************************/
 void Get_Offset(void)
 {
    static Cnt = 0;
    word Comp_Val;

    Cnt++;
    if(Cnt > 100)
    {
      Cnt = 0;
       
      Adc_Result = ((HiAdcResult<<8) | (LowAdcResult));

      Adc_Ch = 0x02;
      if(! ADCSC2_ADACT)
        {
          Adc_Result = ((HiAdcResult<<8) | (LowAdcResult));
              
          Comp_Val = 0x0FF;
          Shift_Val = -8;
              
          while(Comp_Val < 0xFFF)
            {
              if(Adc_Result > Comp_Val)
               {
                  Shift_Val ++;
                  Comp_Val += 0x100;
                  if(Shift_Val == 0)
                    Shift_Val ++;
               }
              else 
                break;
            }
    
          ADC_Cvt(Adc_Ch);
        }
    }
    return;
 }

/******************************************************************************
 * Function:        void Emulate_Mouse(void)
 * Input:           None
 * Output:          None
 * Overview:        This function gets the input from mouse movement, the mouse
 *                  will move if the any button are pushed,otherwise USB gets NAK
 *                  
 *****************************************************************************/
void Emulate_Mouse_WithButton(void)
{
     byte i;
     static byte Button_Is_Pressed = 0;

     if(HID_BD_IN.Stat.McuCtlBit.OWN)
        return;
     
     if(Emulate_Mode == 1)
      {
       if(!Mouse_En)
        return;
       else
        Mouse_En = 0;
       
       if(Move_Len > 1)
         {
           Rpt_Buf[0] = 0;
           Rpt_Buf[1] = Dir_Table[Move_Len & 0x07];           
           Rpt_Buf[2] = Dir_Table[(Move_Len+1) & 0x07];      
           Rpt_Buf[3] = 0x00;
           if(Move_Len > 14)
             Move_Len = 0;
         }
            
       if(Move_Len == 0 )
         {
           Rpt_Buf[1] = -127;
           Rpt_Buf[2] = 127;
         }
            
       if(Move_Len == 1 )
         {
           Rpt_Buf[1] = 27;
           Rpt_Buf[2] = 127;
         }
         
        Move_Len++;
        HID_Transfer_Rpt(Rpt_Buf,4);
       }
      else
       {
         if(Kbi_Stat > 0)
            {
              for(i=0; i<4; i++)
                Rpt_Buf[i] = 0;

              if(Kbi_Stat & 0x01)
                 Rpt_Buf[0] |= 0x01;
                   
              if(Kbi_Stat & 0x02)
                 Rpt_Buf[0] |= 0x02;
                  
              if(Kbi_Stat & 0x04)
                 Rpt_Buf[1] = Shift_Val;
                 
              if(Kbi_Stat & 0x08)
                 Rpt_Buf[2] = Shift_Val;
             
              Button_Is_Pressed =  1;
              Kbi_Stat = 0x00; 
                    
              HID_Transfer_Rpt(Rpt_Buf,4);
             
              return;
            }
            
        if(Button_Is_Pressed)
        {   
          for(i=0; i<4; i++)
             Rpt_Buf[i] = 0;
          
          Button_Is_Pressed = 0x00; 
          HID_Transfer_Rpt(Rpt_Buf,4);
        }
        
     }
    return;
}
   
/******************************************************************************
 * Function:        void EmulateMouseWithAcce(void)
 * Input:           None
 * Output:          None
 * Overview:        This function gets the input from mouse movement
 *                  
 *****************************************************************************/
#ifdef USE_ACCELEROMETER
void Emulate_Mouse_WithAccel(void)
{
     word Comp_Val;
     byte i;
     
     if(Emulate_Mode == 1)
      {
       if(Move_Len > 1)
         {
           Rpt_Buf[0] = 0;
           Rpt_Buf[1] = Dir_Table[Move_Len & 0x07];           
           Rpt_Buf[2] = Dir_Table[(Move_Len+1) & 0x07];      
           Rpt_Buf[3] = 0x00;//Dir_Table[(Move_Len+4) & 0x07];
           if(Move_Len > 14)
             Move_Len = 0;
         }
            
       if(Move_Len == 0 )
         {
           Rpt_Buf[1] = -127;
           Rpt_Buf[2] = 127;
         }
            
       if(Move_Len == 1 )
         {
           Rpt_Buf[1] = 27;
           Rpt_Buf[2] = 127;
         }
       }
      else
       {
        if(Mouse_En)
        {
         //Mouse_En = 0;
         RTC_DISBALE();
        }
        else
          return;
        
         // with 3-axis accelerometer
         if(! ADCSC2_ADACT)
           {
             Adc_Result = ((HiAdcResult<<8) | (LowAdcResult));
                   
             Comp_Val = 0x0FF;
             Shift_Val = -8;
                    
             while(Comp_Val < 0xFFF)
              {
               if(Adc_Result > Comp_Val)
                 {
                   Shift_Val ++;
                   Comp_Val += 0x100;
                 }
               else 
                  break;
               }
            }
         else
            return;
               
         switch (Adc_Ch)
           {
            case 0:
              {
                Rpt_Buf[2] =  Shift_Val;
                    
                Adc_Ch = 0x01;
                ADC_Cvt(Adc_Ch);
              }  
            break;
                
            case 1:  
               {
                 Rpt_Buf[3] =  Shift_Val;
                 Adc_Ch = 0x03;
                 ADC_Cvt(Adc_Ch);
               } 
                  
             break;
                
            case 2:  
                if(! ADCSC2_ADACT)
                  {
                    if(Adc_Result < 0x4FF)
                       Set_Sentivity(0);
                    else
                      {
                       if(Adc_Result < 0x8FF)
                          Set_Sentivity(0x01);
                       else
                         {
                          if(Adc_Result < 0xCFF)
                             Set_Sentivity(0x02);
                          else
                             Set_Sentivity(0x03);
                         }
                      }
                    Adc_Ch = 0x00;
                    ADC_Cvt(Adc_Ch);
                  }
                 
           break;
                
           case 3:  
             if(! ADCSC2_ADACT)
               {
                Rpt_Buf[1] =  Shift_Val;
                   
                Adc_Ch = 0x02;
                ADC_Cvt(Adc_Ch);
               } 
                  
            break; 
                
            default:
              Adc_Ch = 0x00;
              if(! ADCSC2_ADACT)
               ADC_Cvt(Adc_Ch);
              break; 
         }
     }
  
    if(! HID_BD_IN.Stat.McuCtlBit.UOWN)
    {
      HID_Transfer_Rpt(Rpt_Buf,HID_INT_IN_EP_SIZE);
      Move_Len++;
    }
    else
      return;
    
    for(i = 0; i< HID_INT_IN_EP_SIZE; i++)
      Rpt_Buf[i] = 0x00;
}
#endif

/******************************************************************************
 * Function:        void HID_Rec_Data(void)
 * Input:           None
 * Output:          None
 * Overview:        Per HID class std. 1.1, it supports bidirectional communication
 *                  this function is used to receive the data transferred by host
 *****************************************************************************/
void HID_Rec_Data(void)
{
  byte i,RxDataSize, Rx_offset=0;
  

//  byte len_low, len_high;
//  word packetlen;

  RxPacketCount++;
  
  RxDataSize = HID_Receive_Rpt(Rec_Buf,HID_INT_OUT_EP_SIZE);
  
//  if(RxDataSize > 0)     /*Add other processing code*/
  
      for (i=0;i<RxDataSize;i++){                // put all or first portion data into rx buffer
       PC_Rx_DataBuffer[i]=Rec_Buf[i];
     };

     newdatafromPC=TRUE;
     
     
  if (PCCommandPacketCompleted){                   //loop _100

 
    if   (PCSub_Packet_Count==0)  {
      
 
          if ((Rec_Buf[3]==CMD_OUT_PWM_A)||(Rec_Buf[3]==CMD_OUT_PWM_B)||(Rec_Buf[3]==CMD_OUT_PWM_STEP)){     // 1st packet of 3-packet-command received
             PCCommandPacketCompleted=FALSE;
             FPGA_GetRegisterNow=FALSE;

            } 
           else {                                                          // normal 1 packet command received 
               if (Rec_Buf[3]==CMD_GET_REGISTER){
                      FPGA_GetRegisterNow=TRUE;
                  } else{
                      FPGA_GetRegisterNow=FALSE;
                  }
      
           }
    }
 
 
  }else {
           PCSub_Packet_Count++;
 
           if (PCSub_Packet_Count==2){
              PCSub_Packet_Count=0;
              PCCommandPacketCompleted=TRUE;
           }

  }
  

  
    asm nop ; //debug
  
    return;
}

/******************************************************************************
 * Function:        void USB_Status_Indictor(void)
 * Input:           None
 * Output:          None
 * Overview:        USB_Status_Indictor turns on and off LEDs corresponding to
 *                  the USB device state.
 *****************************************************************************/
void USB_Status_Indictor(void)
{
    static word led_count=0;
    
    if(led_count == 0)
	    led_count = 20000;
    led_count--;

    
    if(Usb_Device_State == USB_SUSPEND)
    {
        if(led_count==0)
          LED_Both_Off();
        LED_3_On();
    }                                                                
    else
    {
        LED_3_Off();
        if(Usb_Device_State == POWERED_STATE)
        {
            LED_Only_1_On();
            
        }
        else if(Usb_Device_State == ATTACHED_STATE)
        {
            LED_Only_2_On();
            LED_1_Off();
        }
        else if(Usb_Device_State == DEFAULT_STATE)
        {
             LED_Both_On();
        }
        else if(Usb_Device_State == ADDRESS_STATE)
        {
            if(led_count == 0)
            {
                LED_1_Toggle();
                LED_2_Off();
            }
        }
        else if(Usb_Device_State == CONFIGURED_STATE)
        {
            if(led_count==0)
            {
                LED_1_Toggle();
                LED_2_Toggle();         
            }
        }
    }

}


/******************************************************************************
 * Function:        void Set_Sentivity(char Sen)
 * Input:           Sen is used to set the sentivity of accelerator
 *                  refer to the data sheet of accelerator for more inf. 
 * Output:          None
 * Overview:        Set the senstivity of accelerator
 *****************************************************************************/

#ifdef USE_ACCELEROMETER
void Set_Sentivity(char Sen)
{
  switch(Sen)
  {
    case 0:
      PTAD_PTAD5 = 1;
      PTDD_PTDD7 = 1;
    break;
    case 1:
      PTAD_PTAD5 = 0;
      PTDD_PTDD7 = 1;
    break;

    case 2:
      PTAD_PTAD5 = 1;
      PTDD_PTDD7 = 0;
    break;

    case 3:
      PTAD_PTAD5 = 0;
      PTDD_PTDD7 = 0;
    break;

    default:
    break;
  }
}
#endif