Esempio n. 1
0
/*******************************************************************************
* Function Name  : Mass_Storage_Out
* Description    : Mass Storage OUT transfer.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void Mass_Storage_Out (void)
{
  u8 CMD;
  CMD = CBW.CB[0];
  Data_Len = GetEPRxCount(ENDP2);

  PMAToUserBufferCopy(Bulk_Data_Buff, ENDP2_RXADDR, Data_Len);

  switch (Bot_State)
  {
    case BOT_IDLE:
      CBW_Decode();
      break;
    case BOT_DATA_OUT:
      if (CMD == SCSI_WRITE10)
      {
        SCSI_Write10_Cmd(SCSI_LBA , SCSI_BlkLen);
        break;
      }
      Bot_Abort(DIR_OUT);
      Set_Scsi_Sense_Data(ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
      Set_CSW (CSW_PHASE_ERROR, SEND_CSW_DISABLE);
      break;
    default:
      Bot_Abort(BOTH_DIR);
      Set_Scsi_Sense_Data(ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
      Set_CSW (CSW_PHASE_ERROR, SEND_CSW_DISABLE);
      break;
  }
}
Esempio n. 2
0
/*******************************************************************************
* Function Name  : EP1_OUT_Callback.
* Description    : EP1 OUT Callback Routine.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void EP1_OUT_Callback(void)
{
u8 DataLen; //保存接收数据的长度
u8 DataBuffer[64]; //保存接收数据的缓冲区

DataLen = GetEPRxCount(ENDP1); //获取收到的长度
PMAToUserBufferCopy(DataBuffer, ENDP1_RXADDR, DataLen); //复制数据
SetEPRxValid(ENDP1); //设置端点有效,以接收下一次数据

if(DataLen==1) //收到一字节的输出报告
{
  //D0位表示数字键盘灯,D1位表示大写字母锁定灯
//  if(DataBuffer[0]&0x01)  //数字键盘灯亮
//  {
//   GPIOC->BSRR=(1<<6); //亮LED3
//  }
//  else
//  {
//   GPIOC->BRR=(1<<6); //灭LED3
//  }
//  if(DataBuffer[0]&0x02) //大写字母锁定键
//  {
//   GPIOC->BSRR=(1<<7); //亮LED2
//  }
//  else
//  {
//   GPIOC->BRR=(1<<7); //灭LED2
//  }
}

}
Esempio n. 3
0
uint16_t stm32_usbd_ep_get_OUT_count(uint8_t idx)
{
	int8_t index;
	
	index = stm32_usbd_ep(idx);
	if (index < 0)
	{
		return 0;
	}
	idx = (uint8_t)index;
	
	if (stm32_usbd_OUT_dbuffer[idx])
	{
		if(GetENDPOINT(idx) & EP_DTOG_TX)
		{
			return GetEPDblBuf1Count(idx);
		}
		else
		{
			return GetEPDblBuf0Count(idx);
		}
	}
	else
	{
		return GetEPRxCount(idx);
	}
}
/*******************************************************************************
* Function Name  : USB_SIL_Read
* Description    : Write a buffer of data to a selected endpoint.
* Input          : - bEpAddr: The address of the non control endpoint.
*                  - pBufferPointer: The pointer to which will be saved the 
*                     received data buffer.
* Output         : None.
* Return         : Number of received data (in Bytes).
*******************************************************************************/
uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer)
{
  uint32_t DataLength = 0;

#ifndef STM32F10X_CL

  /* Get the number of received data on the selected Endpoint */
  DataLength = GetEPRxCount(bEpAddr & 0x7F);
  
  /* Use the memory interface function to write to the selected endpoint */
  PMAToUserBufferCopy(pBufferPointer, GetEPRxAddr(bEpAddr & 0x7F), DataLength);

#else
  
  USB_OTG_EP *ep;

  /* Get the structure pointer of the selected Endpoint */
  ep = PCD_GetOutEP(bEpAddr);
  
  /* Get the number of received data */
  DataLength = ep->xfer_len;
  
  /* Use the PCD interface layer function to read the selected endpoint */
  PCD_EP_Read (bEpAddr, pBufferPointer, DataLength);
  
#endif /* STM32F10X_CL */

  /* Return the number of received data */
  return DataLength;
}
Esempio n. 5
0
/////////////////////////////////////////////////////////////////////////////
//! Gets a byte from the receive buffer
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \return -1 if USB_COM not available
//! \return -2 if no new byte available
//! \return >= 0: received byte
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_USB_COM_RxBufferGet(u8 usb_com)
{
#if MIOS32_USB_COM_NUM == 0
  return -1; // no USB_COM available
#else
  if( usb_com >= MIOS32_USB_COM_NUM )
    return -1; // USB_COM not available

  if( !rx_buffer_new_data_ctr )
    return -2; // nothing new in buffer

  // get byte - this operation should be atomic!
  // MIOS32_IRQ_Disable();

  // TODO: access buffer directly, so that we don't need to copy into temporary buffer
  u8 buffer_out[MIOS32_USB_COM_DATA_OUT_SIZE];
  PMAToUserBufferCopy(buffer_out, MIOS32_USB_ENDP3_RXADDR, GetEPRxCount(ENDP3));
  u8 b = buffer_out[rx_buffer_ix++];
  if( !--rx_buffer_new_data_ctr )
    SetEPRxValid(ENDP3);
  // MIOS32_IRQ_Enable();

  return b; // return received byte
#endif
}
Esempio n. 6
0
/*******************************************************************************
* Function Name  : Mass_Storage_Out
* Description    : Mass Storage OUT transfer.
* Input          : None.
* Output         : None.
* Return         : None.
//USB->设备
*******************************************************************************/
void Mass_Storage_Out (void)
{
	u8 CMD;
	USB_STATUS_REG|=0X10;//标记轮询
	
	CMD = CBW.CB[0];
	Data_Len = GetEPRxCount(ENDP4);
	PMAToUserBufferCopy(Bulk_Data_Buff, ENDP4_RXADDR, Data_Len);
//printf("Bot_State_out:%d;Data_Len=%d",Bot_State,Data_Len);
	switch (Bot_State)
	{
		case BOT_IDLE:
			CBW_Decode();
			break;
		case BOT_DATA_OUT://USB发送数据到设备
			if (CMD == SCSI_WRITE10)
			{
				USB_STATUS_REG|=0X01;//标记正在写数据
				SCSI_Write10_Cmd(CBW.bLUN , SCSI_LBA , SCSI_BlkLen);
				break;
			}
			Bot_Abort(DIR_OUT);
			Set_Scsi_Sense_Data(CBW.bLUN, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
			Set_CSW (CSW_PHASE_ERROR, SEND_CSW_DISABLE);
			break;
		default:
			Bot_Abort(BOTH_DIR);
			Set_Scsi_Sense_Data(CBW.bLUN, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
			Set_CSW (CSW_PHASE_ERROR, SEND_CSW_DISABLE);
			break;
	}
}
Esempio n. 7
0
/*******************************************************************************
* Function Name  : EP2_OUT_Callback.
* Description    : EP2 OUT Callback Routine.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void EP2_OUT_Callback(void)
{
  USB_R_Size = GetEPRxCount(ENDP2);
  PMAToUserBufferCopy((u8 *)USB_R_Buffer, ENDP2_RXADDR, USB_R_Size);
  SetEPRxStatus(ENDP2, EP_RX_VALID); /* enable the next transaction*/
  USB_Receive_Flag = 0xff;
  //Mass_Storage_Out();
}
/*******************************************************************************
* Function Name  : EP3_OUT_Callback
* Description    :
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void EP3_OUT_Callback(void)
{
  Receive_length = GetEPRxCount(ENDP3); // Len data buffers USB.
  PMAToUserBufferCopy((unsigned char*)Receive_Buffer, ENDP3_RXADDR, Receive_length);
  //memcpy(&Command_Buffer[len_command], (unsigned char*)Receive_Buffer, Receive_length);       //Copy buffers USB -> TEMP.
  memset((unsigned char*)Receive_Buffer, 0, Receive_length);                                    //Clear buffer USB.
  SetEPRxValid(ENDP3);
}
Esempio n. 9
0
static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void)
{
	struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;

	bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
	PIOS_Assert(valid);

	uint32_t DataLength;

	/* Get the number of received data on the selected Endpoint */
	DataLength = GetEPRxCount(usb_cdc_dev->cfg->data_rx_ep);
	if (DataLength > sizeof(usb_cdc_dev->rx_packet_buffer)) {
		usb_cdc_dev->rx_oversize++;
		DataLength = sizeof(usb_cdc_dev->rx_packet_buffer);
	}

	/* Use the memory interface function to read from the selected endpoint */
	PMAToUserBufferCopy((uint8_t *) usb_cdc_dev->rx_packet_buffer,
			GetEPRxAddr(usb_cdc_dev->cfg->data_rx_ep),
			DataLength);

	if (!usb_cdc_dev->rx_in_cb) {
		/* No Rx call back registered, disable the receiver */
		SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_NAK);
		return;
	}

	uint16_t headroom;
	bool need_yield = false;
	uint16_t rc;
	rc = (usb_cdc_dev->rx_in_cb)(usb_cdc_dev->rx_in_context,
				usb_cdc_dev->rx_packet_buffer,
				DataLength,
				&headroom,
				&need_yield);

	if (rc < DataLength) {
		/* Lost bytes on rx */
		usb_cdc_dev->rx_dropped += (DataLength - rc);
	}

	if (headroom >= sizeof(usb_cdc_dev->rx_packet_buffer)) {
		/* We have room for a maximum length message */
		SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_VALID);
	} else {
		/* Not enough room left for a message, apply backpressure */
		SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_NAK);
	}

#if defined(PIOS_INCLUDE_FREERTOS)
	if (need_yield) {
		vPortYieldFromISR();
	}
#endif	/* PIOS_INCLUDE_FREERTOS */
}
Esempio n. 10
0
/*******************************************************************************
* Function Name  : USB_SIL_Read
* Description    : Write a buffer of data to a selected endpoint.
* Input          : - bEpAddr: The address of the non control endpoint.
*                  - pBufferPointer: The pointer to which will be saved the
*                     received data buffer.
* Output         : None.
* Return         : Number of received data (in Bytes).
*******************************************************************************/
uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer) {
    uint32_t DataLength = 0;

    /* Get the number of received data on the selected Endpoint */
    DataLength = GetEPRxCount(bEpAddr & 0x7F);

    /* Use the memory interface function to write to the selected endpoint */
    PMAToUserBufferCopy(pBufferPointer, GetEPRxAddr(bEpAddr & 0x7F), DataLength);

    /* Return the number of received data */
    return DataLength;
}
/*******************************************************************************
* Function Name  : EP3_OUT_Callback
* Description    : EP3 OUT Callback Routine.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void EP3_OUT_Callback(void)
{
  /* Get the number of received data on the selected Endpoint */
  USB_Rx_length = GetEPRxCount(ENDP3);

  /* Use the memory interface function to write to the selected endpoint */
  PMAToUserBufferCopy(USB_Rx_Buffer, ENDP3_RXADDR, USB_Rx_length);

  /* USB data should be immediately processed, this allow next USB traffic being
  NAKed till the end of the processing */
  USB_Rx_State = 1;

  USB_Rx_ptr = 0;


}
Esempio n. 12
0
PUBLIC uint32 HW_USB_Read(uint8 bEpAddr, uint8* pBufferPointer, bool SetValid)
{
    uint32 DataLength = 0;


    /* Get the number of received data on the selected Endpoint */
    DataLength = GetEPRxCount(bEpAddr & 0x7F);

    /* Use the memory interface function to write to the selected endpoint */
    HwUsbPMAToUserBufferCopy(pBufferPointer, GetEPRxAddr(bEpAddr & 0x7F), DataLength);

    if(SetValid)
    SetEPRxValid(bEpAddr & 0x0F);


    return DataLength;
}
void EP3_OUT_Callback(void)
{
    uint8_t i;
    
    UsbRxLength = GetEPRxCount( ENDP3 );
    PMAToUserBufferCopy( ( unsigned char* )UsbRxBuffer, ENDP3_RXADDR, UsbRxLength );
    
    for( i = 0; i < UsbRxLength; i++ )
    {
        if( IsFifoFull( &UartUsb.FifoRx ) == false )
        {
            // Read one byte from the receive data register
            FifoPush( &UartUsb.FifoRx, UsbRxBuffer[i] );
        }
    }

    if( UartUsb.IrqNotify != NULL )
    {
        UartUsb.IrqNotify( UART_NOTIFY_RX );
    }
}
Esempio n. 14
0
/**
 * EP1 OUT Callback Routine
 */
static void PIOS_USB_HID_EP_OUT_Callback(void)
{
	struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)pios_usb_hid_id;

	bool valid = PIOS_USB_HID_validate(usb_hid_dev);
	PIOS_Assert(valid);

	uint32_t DataLength;

	/* Read received data (63 bytes) */
	/* Get the number of received data on the selected Endpoint */
	DataLength = GetEPRxCount(usb_hid_dev->cfg->data_rx_ep);
	if (DataLength > sizeof(usb_hid_dev->rx_packet_buffer)) {
		DataLength = sizeof(usb_hid_dev->rx_packet_buffer);
	}

	/* Use the memory interface function to read from the selected endpoint */
	PMAToUserBufferCopy((uint8_t *) usb_hid_dev->rx_packet_buffer,
			GetEPRxAddr(usb_hid_dev->cfg->data_rx_ep),
			DataLength);

	if (!usb_hid_dev->rx_in_cb) {
		/* No Rx call back registered, disable the receiver */
		SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_NAK);
		return;
	}

	/* The first byte is report ID (not checked), the second byte is the valid data length */
	uint16_t headroom;
	bool need_yield = false;
#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE
	(usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context,
				&usb_hid_dev->rx_packet_buffer[1],
				sizeof(usb_hid_dev->rx_packet_buffer)-1,
				&headroom,
				&need_yield);
#else
	(usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context,
				&usb_hid_dev->rx_packet_buffer[2],
				usb_hid_dev->rx_packet_buffer[1],
				&headroom,
				&need_yield);
#endif

#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE
	uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 1;
#else
	uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 2;
#endif

	if (headroom >= max_payload_length) {

		/* We have room for a maximum length message */
		SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_VALID);
	} else {
		/* Not enough room left for a message, apply backpressure */
		SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_NAK);
	}

#if defined(PIOS_INCLUDE_FREERTOS)
	if (need_yield) {
		vPortYieldFromISR();
	}
#endif	/* PIOS_INCLUDE_FREERTOS */
}
Esempio n. 15
0
/*******************************************************************************
* Function Name  : EP3_OUT_Callback
* Description    :
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void EP3_OUT_Callback(void)
{
  packet_receive = 1;
  Receive_length = GetEPRxCount(ENDP3);
  PMAToUserBufferCopy((unsigned char*)Receive_Buffer, ENDP3_RXADDR, Receive_length);
}
Esempio n. 16
0
/**
  * @brief  Correct Transfer interrupt's service
  * @param  None
  * @retval None
  */
void CTR(void)
{
  USB_EP *ep;
  uint16_t count=0;
  uint8_t EPindex;
  __IO uint16_t wIstr;  
  __IO uint16_t wEPVal = 0;
  /* stay in loop while pending interrupts */
  while (((wIstr = _GetISTR()) & ISTR_CTR) != 0)
  {
    /* extract highest priority endpoint number */
    EPindex = (uint8_t)(wIstr & ISTR_EP_ID);
    
    if (EPindex == 0)
    {
      /* Decode and service control endpoint interrupt */
      
      /* DIR bit = origin of the interrupt */   
      if ((wIstr & ISTR_DIR) == 0)
      {
        /* DIR = 0 */
        
        /* DIR = 0      => IN  int */
        /* DIR = 0 implies that (EP_CTR_TX = 1) always  */
        _ClearEP_CTR_TX(ENDP0);
        ep = &((&USB_Device_dev)->dev.in_ep[0]);
        
        ep->xfer_count = GetEPTxCount(ep->num);
        ep->xfer_buff += ep->xfer_count;
 
        /* TX COMPLETE */
        USBD_DCD_INT_fops->DataInStage(&USB_Device_dev, 0x00);
      }
      else
      {
        /* DIR = 1 */
        
        /* DIR = 1 & CTR_RX       => SETUP or OUT int */
        /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */
        ep = &((&USB_Device_dev)->dev.out_ep[0]);
        wEPVal = _GetENDPOINT(ENDP0);
        
        if ((wEPVal &EP_SETUP) != 0)
        {
          /* Get SETUP Packet*/
          ep->xfer_count = GetEPRxCount(ep->num);
          PMAToUserBufferCopy(&((&USB_Device_dev)->dev.setup_packet[0]),ep->pmaadress , ep->xfer_count);       
          /* SETUP bit kept frozen while CTR_RX = 1*/ 
          _ClearEP_CTR_RX(ENDP0); 
          
          /* Process SETUP Packet*/
          USBD_DCD_INT_fops->SetupStage(&USB_Device_dev);
        }
        
        else if ((wEPVal & EP_CTR_RX) != 0)
        {
          _ClearEP_CTR_RX(ENDP0);
          /* Get Control Data OUT Packet*/
          ep->xfer_count = GetEPRxCount(ep->num);
          
          if (ep->xfer_count != 0)
          {
            PMAToUserBufferCopy(ep->xfer_buff, ep->pmaadress, ep->xfer_count);
            ep->xfer_buff+=ep->xfer_count;
          }
          
          /* Process Control Data OUT Packet*/
          USBD_DCD_INT_fops->DataOutStage(&USB_Device_dev, 0x00);
          
          _SetEPRxCount(ENDP0, ep->maxpacket);
          _SetEPRxStatus(ENDP0,EP_RX_VALID);
        }
      }
    }/* if(EPindex == 0) */
    else
    {
      
      /* Decode and service non control endpoints interrupt  */
      
      /* process related endpoint register */
      wEPVal = _GetENDPOINT(EPindex);
      if ((wEPVal & EP_CTR_RX) != 0)
      {  
        /* clear int flag */
        _ClearEP_CTR_RX(EPindex);
        ep = &((&USB_Device_dev)->dev.out_ep[EPindex]);
        
        /* OUT double Buffering*/
        if (ep->doublebuffer == 0)
        {
          count = GetEPRxCount(ep->num);
          if (count != 0)
          {
            PMAToUserBufferCopy(ep->xfer_buff, ep->pmaadress, count);
          }
        }
        else
        {
          if (GetENDPOINT(ep->num) & EP_DTOG_RX)
          {
            /*read from endpoint BUF0Addr buffer*/
            count = GetEPDblBuf0Count(ep->num);
            if (count != 0)
            {
              PMAToUserBufferCopy(ep->xfer_buff, ep->pmaaddr0, count);
            }
          }
          else
          {
            /*read from endpoint BUF1Addr buffer*/
            count = GetEPDblBuf1Count(ep->num);
            if (count != 0)
            {
              PMAToUserBufferCopy(ep->xfer_buff, ep->pmaaddr1, count);
            }
          }
          FreeUserBuffer(ep->num, EP_DBUF_OUT);  
        }
        /*multi-packet on the NON control OUT endpoint*/
        ep->xfer_count+=count;
        ep->xfer_buff+=count;
       
        if ((ep->xfer_len == 0) || (count < ep->maxpacket))
        {
          /* RX COMPLETE */
          USBD_DCD_INT_fops->DataOutStage(&USB_Device_dev, ep->num);
        }
        else
        {
          DCD_EP_PrepareRx (&USB_Device_dev,ep->num, ep->xfer_buff, ep->xfer_len);
        }
        
      } /* if((wEPVal & EP_CTR_RX) */
      
      if ((wEPVal & EP_CTR_TX) != 0)
      {
        ep = &((&USB_Device_dev)->dev.in_ep[EPindex]);
        
        /* clear int flag */
        _ClearEP_CTR_TX(EPindex);
        
        /* IN double Buffering*/
        if (ep->doublebuffer == 0)
        {
          ep->xfer_count = GetEPTxCount(ep->num);
          if (ep->xfer_count != 0)
          {
            UserToPMABufferCopy(ep->xfer_buff, ep->pmaadress, ep->xfer_count);
          }
        }
        else
        {
          if (GetENDPOINT(ep->num) & EP_DTOG_TX)
          {
            /*read from endpoint BUF0Addr buffer*/
            ep->xfer_count = GetEPDblBuf0Count(ep->num);
            if (ep->xfer_count != 0)
            {
              UserToPMABufferCopy(ep->xfer_buff, ep->pmaaddr0, ep->xfer_count);
            }
          }
          else
          {
            /*read from endpoint BUF1Addr buffer*/
            ep->xfer_count = GetEPDblBuf1Count(ep->num);
            if (ep->xfer_count != 0)
            {
              UserToPMABufferCopy(ep->xfer_buff, ep->pmaaddr1, ep->xfer_count);
            }
          }
          FreeUserBuffer(ep->num, EP_DBUF_IN);  
        }
        /*multi-packet on the NON control IN endpoint*/
        ep->xfer_count =GetEPTxCount(ep->num);
        ep->xfer_buff+=ep->xfer_count;
       
        /* Zero Length Packet? */
        if (ep->xfer_len == 0)
        {
          /* TX COMPLETE */
          USBD_DCD_INT_fops->DataInStage(&USB_Device_dev, ep->num);
        }
        else
        {
          DCD_EP_Tx  (&USB_Device_dev,ep->num, ep->xfer_buff, ep->xfer_len);
        }
        
      } /* if((wEPVal & EP_CTR_TX) != 0) */
      
    }/* if(EPindex == 0) else */
    
  }/* while(...) */
}
Esempio n. 17
0
/////////////////////////////////////////////////////////////////////////////
//! Called by STM32 USB driver to check for OUT streams
//! \note Applications shouldn't call this function directly, instead please use \ref MIOS32_COM layer functions
/////////////////////////////////////////////////////////////////////////////
void MIOS32_USB_COM_EP3_OUT_Callback(void)
{
  // new data has been received - notify this
  rx_buffer_new_data_ctr = GetEPRxCount(ENDP3);
  rx_buffer_ix = 0;
}
Esempio n. 18
0
/*******************************************************************************
 * Function Name  : EP3_OUT_Callback
 * Description    :
 * Input          : None.
 * Output         : None.
 * Return         : None.
 *******************************************************************************/
void EP3_OUT_Callback(void)
{
    receiveLength = GetEPRxCount(ENDP3);                                              // HJI
    PMAToUserBufferCopy((unsigned char*)receiveBuffer, ENDP3_RXADDR, receiveLength);  // HJI
}