void Endpoint_Streaming(uint8_t corenum, uint8_t *buffer, uint16_t packetsize,
						uint16_t totalpackets, uint16_t dummypackets)
{
	uint8_t PhyEP = endpointhandle(corenum)[endpointselected[corenum]];
	uint16_t i;

	if (PhyEP & 1) {
		for (i = 0; i < totalpackets; i++) {
			while (!Endpoint_IsReadWriteAllowed(corenum)) ;
			Endpoint_Write_Stream_LE(corenum,(void *) (buffer + i * packetsize), packetsize, NULL);
			Endpoint_ClearIN(corenum);
		}
		for (i = 0; i < dummypackets; i++) {
			while (!Endpoint_IsReadWriteAllowed(corenum)) ;
			Endpoint_Write_Stream_LE(corenum,(void *) buffer, packetsize, NULL);
			Endpoint_ClearIN(corenum);
		}
	}
	else {
		stream_total_packets = totalpackets + dummypackets;
		for (i = 0; i < totalpackets; i++) {
			DcdDataTransfer(PhyEP, (uint8_t *) (buffer + i * packetsize), packetsize);
			Endpoint_ClearOUT(corenum);
			while (!Endpoint_IsReadWriteAllowed(corenum)) ;
		}
		for (i = 0; i < dummypackets; i++) {
			DcdDataTransfer(PhyEP, buffer, packetsize);
			Endpoint_ClearOUT(corenum);
			while (!Endpoint_IsReadWriteAllowed(corenum)) ;
		}
		stream_total_packets = 0;
	}
}
void DMAEndTransferISR()
{
	uint32_t PhyEP;
	uint32_t EoTIntSt = USB_REG(0)->EoTIntSt;

	for (PhyEP = 2; PhyEP < USED_PHYSICAL_ENDPOINTS; PhyEP++)			   /* Check All Endpoints */
		if ( EoTIntSt & _BIT(PhyEP) ) {
			if ( IsOutEndpoint(PhyEP) ) {				/* OUT Endpoint */
                                uint32_t tem = usb_data_buffer_OUT_index[0];    //just to clear warning
				if (dmaDescriptor[PhyEP].Isochronous == 1) {// iso endpoint
					SizeAudioTransfer = (BufferAddressIso[0]) & 0xFFFF;
					ISO_Address = (uint8_t *) CALLBACK_HAL_GetISOBufferAddress(PhyEP / 2, &SizeAudioTransfer);
					DcdDataTransfer(PhyEP, ISO_Address, 512);
				}
				usb_data_buffer_OUT_size[0] += dmaDescriptor[PhyEP].PresentCount;
				if ((usb_data_buffer_OUT_size[0] + tem + dmaDescriptor[PhyEP].MaxPacketSize) > 512) {
					USB_REG(0)->DMAIntEn &= ~(1 << 1);
				}
			}
			else {								/* IN Endpoint */
				/* Should be left blank */
			}
		}
	USB_REG(0)->EoTIntClr = EoTIntSt;
}
void DMAEndTransferISR() 
{
	uint32_t PhyEP;
	uint32_t EoTIntSt = LPC_USB->USBEoTIntSt;

	for (PhyEP = 2; PhyEP < USED_PHYSICAL_ENDPOINTS; PhyEP++)              /* Check All Endpoints */
	{
		if ( EoTIntSt & _BIT(PhyEP) )
		{
			if ( IsOutEndpoint(PhyEP) )                 /* OUT Endpoint */
			{
				if(dmaDescriptor[PhyEP].Isochronous == 1) // iso endpoint
				{
					SizeAudioTransfer = (BufferAddressIso[0])& 0xFFFF;
					ISO_Address = (uint8_t*)CALLBACK_HAL_GetISOBufferAddress(PhyEP/2,&SizeAudioTransfer);
					DcdDataTransfer(PhyEP, ISO_Address,512);
				}
				usb_data_buffer_OUT_size += dmaDescriptor[PhyEP].PresentCount;
				if((usb_data_buffer_OUT_size + usb_data_buffer_OUT_index +
								dmaDescriptor[PhyEP].MaxPacketSize) > 512)
							LPC_USB->USBDMAIntEn &= ~(1<<1);
			}
			else			                    /* IN Endpoint */
			{
				/* Should be left blank */
			}
		}
	}
	LPC_USB->USBEoTIntClr = EoTIntSt;
}
void Endpoint_Streaming(uint8_t * buffer,uint16_t packetsize,
						uint16_t totalpackets,uint16_t dummypackets)
{
	uint8_t PhyEP = endpointhandle[endpointselected];
	uint16_t i;

	dummypackets = dummypackets;
	if(PhyEP&1)
	{
		for(i=0;i<totalpackets;i++){
			while(!Endpoint_IsReadWriteAllowed());
			Endpoint_Write_Stream_LE((void*)(buffer + i*packetsize), packetsize,NULL);
			Endpoint_ClearIN();
		}
	}
	else
	{
		for(i=0;i<totalpackets;i++){
			DcdDataTransfer(PhyEP, usb_data_buffer_OUT, packetsize);
			Endpoint_ClearOUT();
			while(!Endpoint_IsReadWriteAllowed());
			Endpoint_Read_Stream_LE((void*)(buffer + i*packetsize),packetsize,NULL);
		}
	}
}
void DMANewTransferRequestISR() 
{
	uint32_t PhyEP;
	uint32_t NDDRIntSt = LPC_USB->NDDRIntSt;

	for (PhyEP = 2; PhyEP < USED_PHYSICAL_ENDPOINTS; PhyEP++)              /* Check All Endpoints */
	{
		if ( NDDRIntSt & _BIT(PhyEP) )
		{
			if ( IsOutEndpoint(PhyEP) )                     /* OUT Endpoint */
			{
				if(dmaDescriptor[PhyEP].Isochronous == 1) // iso endpoint
				{
					DcdDataTransfer(PhyEP, ISO_Address,512);
				}
				else
				{
					uint16_t MaxPS = dmaDescriptor[PhyEP].MaxPacketSize;
					if(usb_data_buffer_OUT_size==0){
						usb_data_buffer_OUT_index = 0;
						DcdDataTransfer(PhyEP, usb_data_buffer_OUT, MaxPS);
						
					}else{
                                          uint32_t index = usb_data_buffer_OUT_index;
					  DcdDataTransfer(PhyEP, 
							&usb_data_buffer_OUT[usb_data_buffer_OUT_size + index], 
							MaxPS);
					}
				}
			}
			else			                    /* IN Endpoint */
			{
				if(dmaDescriptor[PhyEP].Isochronous == 1)
				{
					ISO_Address = (uint8_t*)CALLBACK_HAL_GetISOBufferAddress(PhyEP/2,&SizeAudioTransfer);
					if(SizeAudioTransfer > 0)
						DcdDataTransfer(PhyEP, ISO_Address,SizeAudioTransfer);
					else
						DcdDataTransfer(PhyEP, ISO_Address,512);
				}
			}
		}
	}
	LPC_USB->NDDRIntClr = NDDRIntSt;
}
/********************************************************************//**
 * @brief
 * @param
 * @return
 *********************************************************************/
bool Endpoint_ConfigureEndpoint(const uint8_t Number, const uint8_t Type,
							   const uint8_t Direction, const uint16_t Size, const uint8_t Banks)
{
	uint8_t* ISO_Address;
	uint32_t PhyEP = 2*Number + (Direction == ENDPOINT_DIR_OUT ? 0 : 1);
	uint32_t EndPtCtrl = ENDPTCTRL_REG(Number);

	memset(&dQueueHead[PhyEP], 0, sizeof(DeviceQueueHead) );
	
	dQueueHead[PhyEP].MaxPacketSize = Size & 0x3ff;
	dQueueHead[PhyEP].IntOnSetup = 1;
	dQueueHead[PhyEP].ZeroLengthTermination = 1;
	dQueueHead[PhyEP].overlay.NextTD = LINK_TERMINATE;
		
	if (Direction == ENDPOINT_DIR_OUT)
	{
		EndPtCtrl &= ~0x0000FFFF;
		EndPtCtrl |= ((Type << 2) & ENDPTCTRL_RxType) | ENDPTCTRL_RxEnable | ENDPTCTRL_RxToggleReset;
		if(Type == EP_TYPE_ISOCHRONOUS)
		{
			uint32_t size = 0;
			ENDPTCTRL_REG(Number) = (Type << 2);					// TODO dummy to let DcdDataTransfer() knows iso transfer
			ISO_Address = (uint8_t*)CALLBACK_HAL_GetISOBufferAddress(Number, &size);
			DcdDataTransfer(PhyEP, ISO_Address,USB_DATA_BUFFER_TEM_LENGTH);
		}
		else
			USB_REG(USBPortNum)->ENDPTNAKEN |=  (1 << EP_Physical2BitPosition(PhyEP));
	}else /* ENDPOINT_DIR_IN */
	{
		EndPtCtrl &= ~0xFFFF0000;
		EndPtCtrl |= ((Type << 18) & ENDPTCTRL_TxType)| ENDPTCTRL_TxEnable| ENDPTCTRL_TxToggleReset;
		if(Type == EP_TYPE_ISOCHRONOUS)
		{
			uint32_t size = 0;
			ENDPTCTRL_REG(Number) = (Type << 18);					// TODO dummy to let DcdDataTransfer() knows iso transfer
			ISO_Address = (uint8_t*)CALLBACK_HAL_GetISOBufferAddress(Number, &size);
			DcdDataTransfer(PhyEP, ISO_Address, size);
		}
	}
	ENDPTCTRL_REG(Number) = EndPtCtrl;

	endpointhandle[Number] = (Number==ENDPOINT_CONTROLEP) ? ENDPOINT_CONTROLEP : PhyEP;
	return true;
}
void DMANewTransferRequestISR()
{
	uint32_t PhyEP;
	uint32_t NDDRIntSt = USB_REG(0)->NDDRIntSt;

	for (PhyEP = 2; PhyEP < USED_PHYSICAL_ENDPOINTS; PhyEP++)			   /* Check All Endpoints */
		if ( NDDRIntSt & _BIT(PhyEP) ) {
			if ( IsOutEndpoint(PhyEP) ) {					/* OUT Endpoint */
				if (dmaDescriptor[PhyEP].Isochronous == 1) {// iso endpoint
					DcdDataTransfer(PhyEP, ISO_Address, 512);
				}
				else {
					uint16_t MaxPS = dmaDescriptor[PhyEP].MaxPacketSize;
					if (usb_data_buffer_OUT_size[0] == 0) {
						usb_data_buffer_OUT_index[0] = 0;
						DcdDataTransfer(PhyEP, usb_data_buffer_OUT[0], MaxPS);

					}
					else {
							uint32_t tem = usb_data_buffer_OUT_index[0];      //just to clear warning
							DcdDataTransfer(PhyEP, &usb_data_buffer_OUT[0][usb_data_buffer_OUT_size[0] + tem], MaxPS);
					}
				}
			}
			else {								/* IN Endpoint */
				if (dmaDescriptor[PhyEP].Isochronous == 1) {
					ISO_Address = (uint8_t *) CALLBACK_HAL_GetISOBufferAddress(PhyEP / 2, &SizeAudioTransfer);
					if (SizeAudioTransfer > 0) {
						DcdDataTransfer(PhyEP, ISO_Address, SizeAudioTransfer);
					}
					else {
						DcdDataTransfer(PhyEP, ISO_Address, 512);
					}
				}
			}
		}
	USB_REG(0)->NDDRIntClr = NDDRIntSt;
}
void USB_IRQHandler(void)
{
	
#if defined(USB_DEVICE_ROM_DRIVER)
	UsbdRom_IrqHandler();
#else	
	uint32_t IntStat = LPC_USB->INTSTAT;			
        uint32_t IntEn = LPC_USB->INTEN;
        
        IntStat &= IntEn;                                                       /* Get Interrupt Status and clear immediately. */
        
	if (IntStat == 0) {
		return;
	}

	LPC_USB->INTSTAT = IntStat;

	/* SOF Interrupt */
	if (IntStat & FRAME_INT) {}

	/* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */
	if (IntStat & DEV_STAT_INT) {
		uint32_t DevCmdStat = LPC_USB->DEVCMDSTAT;				/* Device Status */

		if (DevCmdStat & USB_DRESET_C) {				/* Reset */
			LPC_USB->DEVCMDSTAT |= USB_DRESET_C;
			HAL_Reset();
			USB_DeviceState[0] = DEVICE_STATE_Default;
			Endpoint_ConfigureEndpointControl(USB_Device_ControlEndpointSize);
		}

		if (DevCmdStat & USB_DCON_C) {					/* Connect change */
			LPC_USB->DEVCMDSTAT |= USB_DCON_C;
		}

		if (DevCmdStat & USB_DSUS_C) {					/* Suspend/Resume */
			LPC_USB->DEVCMDSTAT |= USB_DSUS_C;
			if (DevCmdStat & USB_DSUS) {				/* Suspend */
			}
			else {								/* Resume */
			}
		}
	}

	/* Endpoint's Interrupt */
	if (IntStat & 0x3FF) {	/* if any of the EP0 through EP9 is set, or bit 0 through 9 on disr */
		uint32_t PhyEP;
		for (PhyEP = 0; PhyEP < USED_PHYSICAL_ENDPOINTS; PhyEP++) /* Check All Endpoints */
			if ( IntStat & (1 << PhyEP) ) {
				if ( IsOutEndpoint(PhyEP) ) {	/* OUT Endpoint */
					if ( !Endpoint_IsSETUPReceived(0) ) {
						if (EndPointCmdStsList[PhyEP][0].NBytes == 0x200) {
							if (PhyEP == 0) {
								DcdDataTransfer(PhyEP, usb_data_buffer[0], 512);
							}
							else if (stream_total_packets == 0)   {
								DcdDataTransfer(PhyEP, usb_data_buffer_OUT[0], 512);
							}
							if ((PhyEP == 0) || (stream_total_packets == 0)) {
								epout_primed = true;
							}
						}
						else {
							if (epout_primed) {
								epout_primed = false;
								if (PhyEP == 0) {
									usb_data_buffer_size[0] = (512 - EndPointCmdStsList[PhyEP][0].NBytes);
								}
								else {
									usb_data_buffer_OUT_size[0] = (512 - EndPointCmdStsList[PhyEP][0].NBytes);
								}
							}
						}
					}
				}
				else {								/* IN Endpoint */
					if (Remain_length[PhyEP / 2] > 0) {
						uint32_t i;
						if (PhyEP == 1) {	/* Control IN */
							for (i = 0; i < Remain_length[PhyEP / 2]; i++)
								usb_data_buffer[0][i] = usb_data_buffer[0][i + EndpointMaxPacketSize[PhyEP]];
							DcdDataTransfer(PhyEP, usb_data_buffer[0], Remain_length[PhyEP / 2]);
						}
						else {
							for (i = 0; i < Remain_length[PhyEP / 2]; i++)
								usb_data_buffer_IN[0][i] = usb_data_buffer_IN[0][i + EndpointMaxPacketSize[PhyEP]];
							DcdDataTransfer(PhyEP, usb_data_buffer_IN[0], Remain_length[PhyEP / 2]);
						}
					}
					else {
						if (PhyEP == 1) {	/* Control IN */
							if (shortpacket) {
								shortpacket = false;
								DcdDataTransfer(PhyEP, usb_data_buffer[0], 0);
							}
						}
					}
				}
			}
	}
#endif
}