#include "OB90A64U1.h"
#include "Timer32.h"
#include "usb.h"
#include "usbdef.h"
#include "usbcom.h"


uint8_t  g_USBSuspendFlag  = 0;
uint8_t  g_USBHandShakeFlag = 0;
uint32_t g_usb_interrupt0 = 0;
uint32_t g_usb_interrupt1 = 0;

void USB_Open(void)
{
	USB_SetClockSource();	 
  USB_AutoTrim48M();
  NVIC_EnableIRQ(USB_IRQn);
	NVIC_EnableIRQ(USBRSM_IRQn);
  OB_USB->UCTRL1 = USB_CONTROL1_IP_EN | USB_CONTROL1_UDC_EN;  
	OB_USB->UCTRL2 = USB_CONTROL2_R1_CLOSE | USB_CONTROL2_R2_CLOSE;
  OB_USB->UIERS0  = USB_INTERTUPT_EN_USB | USB_INTERTUPT_EN_RESET;; 
  OB_USB->UIERS1  = 0xFFFFFFFF;
	USB_SetFifoSize();
	USB_SetCon(USB_CONTROL_POINT,        USB_TRANSFER_SETUP);
	USB_SetCon(USB_INTERRUPT_IN_POINT,  USB_TRANSFER_INTERRUPT_IN);
	USB_SetCon(USB_INTERRUPT_OUT_POINT, USB_TRANSFER_INTERRUPT_OUT);
	USB_SetCon(USB_BULK_IN_POINT,       USB_TRANSFER_BULK_IN);
	USB_SetCon(USB_BULK_OUT_POINT,      USB_TRANSFER_BULK_OUT);
	USB_SetCon(USB_ISO_IN_POINT,        USB_TRANSFER_ISO_IN);
	USB_SetCon(USB_ISO_OUT_POINT,       USB_TRANSFER_ISO_OUT);	
  TIMER32_UsbDelay(OB_CT32B0 ,10);	
}

uint32_t USB_ControlIn(uint8_t* pBuff, uint32_t DataLen)
{
  uint32_t EndPointLength;
  uint32_t UsbStatus ,TimerOut;

	TimerOut = USB_GetInterruptTimerOut(USB_CONTROL_POINT); 
  UsbStatus = USB_Transfer_In(pBuff,USB_CONTROL_POINT, DataLen, DataLen);	
  if(UsbStatus != USB_STATUS_OK)
  {  
	 	  USBSetReady(USB_CONTROL_POINT);	
			return UsbStatus;
		}
    //-----------------------------------------------------------------------------------
		USBSetReady(USB_CONTROL_POINT);	  
		UsbStatus = USB_WaitInterrupt(USB_CONTROL_POINT,USB_DIR_OUT,  TimerOut, &EndPointLength);
		USBSetReady(USB_CONTROL_POINT);	 

	return UsbStatus;
}

uint32_t USBCommControlOut(uint8_t* pBuff, uint32_t* pDataLen)
{
  uint32_t  Length;
  USBGetFiFo(pBuff, USB_CONTROL_POINT, &Length);
	return USB_STATUS_OK;
}


uint32_t USB_Transfer_In(uint8_t* pBuff, uint32_t EndPonit, uint32_t McuLength, uint32_t PcLength)
{
  uint32_t TransferLength, Offset ;
  uint32_t UsbStatus;
	uint32_t FifoLength, TimerOut, Null;
	
	TimerOut = USB_GetInterruptTimerOut(EndPonit);    
	FifoLength = USB_GetFifoSize(EndPonit);
	 Offset = 0;
	 Null = 0;
	 if(McuLength >= PcLength)	   
			McuLength = PcLength;
	 else
			Null = 1;

    while ( McuLength != 0 )
    {
				
			if( McuLength >= FifoLength )
        {
					TransferLength = FifoLength;
					McuLength = McuLength - FifoLength;
				}
				else
				{					
					TransferLength = McuLength;
					McuLength = 0x00;
				}

				USB_WriteFifo((pBuff + Offset), EndPonit, TransferLength);
        Offset = Offset + TransferLength;
	      USBSetReady(EndPonit);		        // Wait Host Ack
    
				UsbStatus = USB_WaitInterrupt(EndPonit ,USB_DIR_IN,  TimerOut, &TransferLength); 
				if (  UsbStatus != USB_STATUS_OK )
    			  break;
				
    }
    
    if ( ( Null == 1 ) && (UsbStatus == USB_STATUS_OK ))
    {
				USBSetReady(EndPonit);
        // Wait Host Ack
			  UsbStatus =USB_WaitInterrupt(EndPonit, USB_DIR_IN,  TimerOut, &TransferLength);
     }

	return UsbStatus;
}

uint32_t USB_Transfer_Out(uint8_t* pBuff, uint32_t EndPonit, uint32_t PcLength)
{

    uint32_t  UsbStatus ; 
		uint32_t  TimerOut, TransferLength;
		TimerOut = USB_GetInterruptTimerOut(EndPonit); 
	  
		while (1)
    {

		  USBGetFiFo(pBuff, USB_BULK_OUT_POINT, &TransferLength);
      pBuff = (pBuff + TransferLength);
			
		   if(PcLength > TransferLength)	        
					PcLength = PcLength - TransferLength;
       else 
					PcLength = 0x00;
			
			 USBSetReady(EndPonit);
			 if ( PcLength == 0 )
			 {
					UsbStatus = USB_STATUS_OK;		
					break;			 
			 }       
			 else				 
			 {
          UsbStatus =  USB_WaitInterrupt(EndPonit,USB_DIR_OUT,  TimerOut, &TransferLength) ;
					if ( UsbStatus != USB_STATUS_OK )
              break;
        }

      }
	
	return UsbStatus;
}



void USB_StallEp(uint32_t EndPoint)
{
 	uint32_t Loop; 
	OB_USB->DSTALL = EndPoint;    
	Loop = 100000;
	if(EndPoint == USB_CONTROL_POINT)
	  USBSetReady(EndPoint);
  else
	{
	   while(Loop--)
		 {
		   if(OB_USB->DSTALL == 0x00)
		     break;
		 }
	
	}		
}  



uint32_t USB_WaitInterrupt(uint32_t EndPoint, uint32_t IN_OUT, uint32_t Timeout, uint32_t *Length)
{
   uint32_t Shift;
	 uint32_t Buff ;
  uint32_t UsbStatus;

	TIMER32_Enable(OB_CT32B0);
	
	UsbStatus = USB_STATUS_TIMER_OUT;
	switch (EndPoint)
	 {
		 case USB_END_POINT_0:
			Shift = 0x00; 
		 *Length = OB_USB->EPCNT0;
		 break;
		 case USB_END_POINT_1:
			Shift = 0x04; 
			*Length = OB_USB->EPCNT1;
		 break;
		 case USB_END_POINT_2:
			Shift = 0x08; 
			*Length = OB_USB->EPCNT2;		 
		 break;
		 case USB_END_POINT_3:
			Shift = 0x0C; 
			*Length = OB_USB->EPCNT3;		 
		 break;
		 case USB_END_POINT_4:
			Shift = 0x10; 
			*Length = OB_USB->EPCNT4;		 
		 break;
		 case USB_END_POINT_5:
			Shift = 0x14; 
			*Length = OB_USB->EPCNT5;		 
		 break;
		 case USB_END_POINT_6:
			Shift = 0x18; 
			*Length = OB_USB->EPCNT6;		 
		 break;
		 case USB_END_POINT_7:
			Shift = 0x1C; 
			*Length = OB_USB->EPCNT7;		 
		 break;	 
		 default:
			Shift = 0x00; 
		 break;
	 }
	if(EndPoint == USB_CONTROL_POINT)
	{	
   	Buff = 0x01 << Shift;
	} 
		else
	{
	  if(IN_OUT == USB_DIR_IN)
	    Buff = (0x02  ) << Shift;
	  else
	   Buff = (0x04  ) << Shift;
	}	

  	while (1)
    {
   		//---------------------------------------------------------------------------------  
			if((g_usb_interrupt0 & USB_INTERTUPT_EN_RESET) == USB_INTERTUPT_EN_RESET)
			 {
			   g_usb_interrupt0 = g_usb_interrupt0 & ( ~USB_INTERTUPT_EN_RESET);
				 UsbStatus = USB_STATUS_RESET;
				 break;
			 }		 
   		//---------------------------------------------------------------------------------  
			 if(g_usb_interrupt1 != 0x00)
			 {
									  
				 if( (g_usb_interrupt1 & Buff ) == Buff)	
					{						
           	if( (EndPoint == USB_CONTROL_POINT) && (IN_OUT == USB_DIR_IN))
						{	
								if( (OB_USB->UEPSTAT & 0x02) != 0x02)		
								{
									UsbStatus = USB_STATUS_OTHER_POINT;	
                  break;									
								}
						}
						g_usb_interrupt1 = g_usb_interrupt1& (~Buff);				  
						UsbStatus = USB_STATUS_OK;
					}	
					else 				 
						UsbStatus = USB_STATUS_OTHER_POINT;					
					
				break;	
			 }  
 				//----------------------------------------------------------------------
				if( (OB_CT32B0->TMR32IR & 0x01) == 1)
				{		 					
					OB_CT32B0->TMR32IR =1;
					Timeout--;		
          if(Timeout == 0x00)		
           break;						
			  }
					  	
    }
   TIMER32_Close(OB_CT32B0);
		
    return UsbStatus;
}

void USB_IRQHandler(void) //interrupt
{


	  g_usb_interrupt0    = g_usb_interrupt0 | OB_USB->UIFR0;
    g_usb_interrupt1    = g_usb_interrupt1 | OB_USB->UIFR1;

 	  // EndPoint
   	OB_USB->UIFRC1    = OB_USB->UIFR1;
    
    // Suspend
    if ((OB_USB->UIFR0 & (USB_INTERTUPT_EN_SUSPEND)) != 0x00)
			OB_USB->UIFRC0 = USB_INTERTUPT_EN_SUSPEND;
    
    // Reset
    if ((OB_USB->UIFR0 & (USB_INTERTUPT_EN_RESET)) != 0x00)
			OB_USB->UIFRC0 = USB_INTERTUPT_EN_RESET;
			
}

void USBRSM_IRQHandler(void) // interrupt 
{    
    OB_USB->UIFRC0 = (1<< 13); //RSUMIE
}



void USBSetReady(uint32_t EndPoint)
{
	OB_USB->EPRDY = (~EndPoint) & 0x000000FF;
}	

void USBGetFiFo(uint8_t* pBuff, uint32_t EndPoint, uint32_t *Length)
{
	uint32_t Loop, Buff;
	if(EndPoint == USB_END_POINT_0)
  {  
		Buff		 = OB_USB->EPCNT0;
		*Length = Buff;
		for(Loop = 0x00; Loop<Buff; Loop++)
		{
		   *pBuff = (uint8_t) OB_USB->EPDATA0;
		  	pBuff++;
		}
	}
	else if(EndPoint == USB_END_POINT_1)
  {  
		Buff		 = OB_USB->EPCNT1;
		*Length = Buff;
		for(Loop = 0x00; Loop<Buff; Loop++)
		{
		   *pBuff = (uint8_t) OB_USB->EPDATA1;
		  	pBuff++;
		}
	}
	else 	if(EndPoint == USB_END_POINT_2)
  {  
		Buff		 = OB_USB->EPCNT2;
		*Length = Buff;
		for(Loop = 0x00; Loop<Buff; Loop++)
		{
		   *pBuff = (uint8_t) OB_USB->EPDATA2;
		  	pBuff++;
		}
	}
	else 	if(EndPoint == USB_END_POINT_3)
  {  
		Buff		 = OB_USB->EPCNT3;
		*Length = Buff;
		for(Loop = 0x00; Loop<Buff; Loop++)
		{
		   *pBuff = (uint8_t) OB_USB->EPDATA3;
		  	pBuff++;
		}	
	}
	else 	if(EndPoint == USB_END_POINT_4)
  {  
		Buff		 = OB_USB->EPCNT4;
		*Length = Buff;
		for(Loop = 0x00; Loop<Buff; Loop++)
		{
		   *pBuff = (uint8_t) OB_USB->EPDATA4;
		  	pBuff++;
		}	
	}
	else 	if(EndPoint == USB_END_POINT_5)
  {  
		Buff		 = OB_USB->EPCNT5;
		*Length = Buff;
		for(Loop = 0x00; Loop<Buff; Loop++)
		{
		   *pBuff = (uint8_t) OB_USB->EPDATA5;
		  	pBuff++;
		}
	}
	else 	if(EndPoint == USB_END_POINT_6)
  {  
		Buff		 = OB_USB->EPCNT6;
		*Length = Buff;
		for(Loop = 0x00; Loop<Buff; Loop++)
		{
		   *pBuff = (uint8_t) OB_USB->EPDATA6;
		  	pBuff++;
		}	
	}
	else
	{
		Buff		 = OB_USB->EPCNT7;
		*Length = Buff;
		for(Loop = 0x00; Loop<Buff; Loop++)
		{
		   *pBuff = (uint8_t) OB_USB->EPDATA7;
		  	pBuff++;
		}	
	}

}

void USB_WriteFifo(uint8_t* pBuff, uint32_t EndPoint, uint32_t Length)
{

	uint32_t Loop ;
	if(EndPoint == USB_END_POINT_0)
  {  
		for(Loop = 0x00; Loop<Length; Loop++)
		{
		    OB_USB->EPDATA0 =(uint32_t)(*pBuff);
		  	pBuff++;
		}
	}
	else if(EndPoint == USB_END_POINT_1)
  {  
		for(Loop = 0x00; Loop<Length; Loop++)
		{
		    OB_USB->EPDATA1 =(uint32_t)(*pBuff);
		  	pBuff++;
		}
	}
	else 	if(EndPoint == USB_END_POINT_2)
  {  
		for(Loop = 0x00; Loop<Length; Loop++)
		{
		    OB_USB->EPDATA2 =(uint32_t)(*pBuff);
		  	pBuff++;
		}
	}
	else 	if(EndPoint == USB_END_POINT_3)
  {  
		for(Loop = 0x00; Loop<Length; Loop++)
		{
		    OB_USB->EPDATA3 =(uint32_t)(*pBuff);
		  	pBuff++;
		}
	}
	else 	if(EndPoint == USB_END_POINT_4)
  {  
		for(Loop = 0x00; Loop<Length; Loop++)
		{
		    OB_USB->EPDATA4 =(uint32_t)(*pBuff);
		  	pBuff++;
		}	
	}
	else 	if(EndPoint == USB_END_POINT_5)
  {  
		for(Loop = 0x00; Loop<Length; Loop++)
		{
		    OB_USB->EPDATA5 =(uint32_t)(*pBuff);
		  	pBuff++;
		}
	}
	else 	if(EndPoint == USB_END_POINT_6)
  {  
		for(Loop = 0x00; Loop<Length; Loop++)
		{
		    OB_USB->EPDATA6 =(uint32_t)(*pBuff);
		  	pBuff++;
		}	
	}
	else
	{
		for(Loop = 0x00; Loop<Length; Loop++)
		{
		    OB_USB->EPDATA7 =(uint32_t)(*pBuff);
		  	pBuff++;
		}
	}

}

void USB_ProcCtrlPkg(void)
{
  USB_SETUP_PACKET  setup_pkg;
  uint32_t            nDataLen;
    if ( USBCommControlOut((uint8_t*)&setup_pkg, &nDataLen) == USB_STATUS_OK )
       COM_DecodeSetupCommands(&setup_pkg);
    else
        USB_StallEp(USB_CONTROL_POINT);

}


void USB_SetCon(uint32_t EndPoint, uint32_t Type)
{

  if(EndPoint == USB_END_POINT_0)	
		OB_USB->EP0CON = (OB_USB->EP0CON & 0X0f ) | Type;
  if(EndPoint == USB_END_POINT_1)	
		OB_USB->EP1CON = (OB_USB->EP1CON & 0X0f ) | Type;
  if(EndPoint == USB_END_POINT_2)	
		OB_USB->EP2CON = (OB_USB->EP2CON & 0X0f ) | Type;
  if(EndPoint == USB_END_POINT_3)	
		OB_USB->EP3CON = (OB_USB->EP3CON & 0X0f ) | Type;
  if(EndPoint == USB_END_POINT_4)	
		OB_USB->EP4CON = (OB_USB->EP4CON & 0X0f ) | Type;
  if(EndPoint == USB_END_POINT_5)	
		OB_USB->EP5CON = (OB_USB->EP5CON & 0X0f ) | Type;
  if(EndPoint == USB_END_POINT_6)	
		OB_USB->EP6CON = (OB_USB->EP6CON & 0X0f ) | Type;
  if(EndPoint == USB_END_POINT_7)	
		OB_USB->EP7CON = (OB_USB->EP7CON & 0X0f ) | Type;

	
}

void USB_SetFifoSize(void)
{
  OB_USB->EP0FIFOADD = 0x00;	
	OB_USB->EP1FIFOADD = OB_USB->EP0FIFOADD + USB_FIFO_SIZE_EP0;
	OB_USB->EP2FIFOADD = OB_USB->EP1FIFOADD + USB_FIFO_SIZE_EP1;
	OB_USB->EP3FIFOADD = OB_USB->EP2FIFOADD + USB_FIFO_SIZE_EP2;
	OB_USB->EP4FIFOADD = OB_USB->EP3FIFOADD + USB_FIFO_SIZE_EP3;
	OB_USB->EP5FIFOADD = OB_USB->EP4FIFOADD + USB_FIFO_SIZE_EP4;
	OB_USB->EP6FIFOADD = OB_USB->EP5FIFOADD + USB_FIFO_SIZE_EP5;
	OB_USB->EP7FIFOADD = OB_USB->EP6FIFOADD + USB_FIFO_SIZE_EP6;
}	


uint32_t USB_GetFifoSize(uint32_t EndPoint)
{
  if(EndPoint == USB_END_POINT_0)
		return USB_FIFO_SIZE_EP0;

  else if(EndPoint == USB_END_POINT_1)
		return USB_FIFO_SIZE_EP1;

  else if(EndPoint == USB_END_POINT_2)
		return USB_FIFO_SIZE_EP2;

  else if(EndPoint == USB_END_POINT_3)
		return USB_FIFO_SIZE_EP3;

  else if(EndPoint == USB_END_POINT_4)
		return USB_FIFO_SIZE_EP4;

  else if(EndPoint == USB_END_POINT_5)
		return USB_FIFO_SIZE_EP5;

  else if(EndPoint == USB_END_POINT_6)
		return USB_FIFO_SIZE_EP6;
 
	else
		return USB_FIFO_SIZE_EP7;
		 
}


uint32_t USB_GetInterruptTimerOut(uint32_t EndPoint)
{

 if(EndPoint == USB_CONTROL_POINT)
	return USB_TIMER_OUT_SETUP ;
 
 else if( (EndPoint == USB_BULK_IN_POINT) || (EndPoint == USB_BULK_OUT_POINT))
	return USB_TIMER_OUT_BULK ;

 else if( (EndPoint == USB_INTERRUPT_IN_POINT) || (EndPoint == USB_INTERRUPT_OUT_POINT))
		return USB_TIMER_OUT_INTERRUPT;  

 else if( (EndPoint == USB_ISO_IN_POINT) || (EndPoint == USB_ISO_OUT_POINT)) 
		return USB_TIMER_OUT_ISO;      

 else 
	 return 0;		

}

void USB_AutoTrim48M(void)	  
{
  uint32_t  CMP, K_sel, Step_sel;
	CMP = 48;
	K_sel = 0x01;
	Step_sel =0;
	OB_AUTOK->CON = OB_AUTOK->CON | 0x80000000 | (CMP << 8) | (K_sel << 4) | (Step_sel << 28); 

}

void USB_SetClockSource(void)	  
{
  OB_SYSCON->DPLLUSB_b.DPLL_USB_DIV = 3;
	OB_SYSCON->DPLLUSB_b.USB_SOURCE = 0;
}
