Sfoglia il codice sorgente

update:少传了文件

alienwalker 4 anni fa
parent
commit
754d45c335
1 ha cambiato i file con 1089 aggiunte e 0 eliminazioni
  1. 1089 0
      bsp/common/src/core_usb_app.c

+ 1089 - 0
bsp/common/src/core_usb_app.c

@@ -0,0 +1,1089 @@
+/*
+ * Copyright (c) 2022 OpenLuat & AirM2M
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "user.h"
+
+enum
+{
+	DEVICE_INTERFACE_HID_SN,
+	DEVICE_INTERFACE_MSC_SN,
+	DEVICE_INTERFACE_SERIAL_SN,
+	DEVICE_INTERFACE_MAX,
+};
+#define DEVICE_HID_KEYBOARD_EP_IN		(0x01)
+#define DEVICE_HID_KEYBOARD_EP_OUT		(0x01)
+#define DEVICE_MASS_STORAGE_EP_IN		(0x02)
+#define DEVICE_MASS_STORAGE_EP_OUT		(0x02)
+#define DEVICE_GENERIC_SERIAL_EP_IN		(0x03)
+#define DEVICE_GENERIC_SERIAL_EP_OUT	(0x03)
+#define VIRTUAL_SERIAL_BUFFER_LEN		(8192)
+#define VIRTUAL_VHID_BUFFER_LEN			(2048)
+#define VIRTUAL_UDISK_BLOCKS_LEN			(512)
+#define VIRTUAL_UDISK_BLOCKS_NUMS			(32)
+#define VIRTUAL_UDISK_LEN				(VIRTUAL_UDISK_BLOCKS_NUMS * VIRTUAL_UDISK_BLOCKS_LEN)
+//#define TEST_SPEED
+
+typedef struct
+{
+	uint32_t CurAddress;
+	uint32_t BlockNums;
+	uint32_t BlockSize;
+	uint32_t BlockTotalNums;
+	uint8_t *VirtualData;
+}Virtual_UDiskCtrlStruct;
+
+typedef struct
+{
+	Buffer_Struct TxBuf;
+	Buffer_Struct TxCacheBuf;	// 缓存下次发送的数据
+	CBFuncEx_t CB;
+	uint8_t USB_ID;
+	uint8_t IsReady;
+	uint8_t ToHostEpIndex;
+}Virtual_HIDCtrlStruct;
+
+
+typedef struct
+{
+	Buffer_Struct TxBuf;
+	Buffer_Struct TxCacheBuf;	// 缓存下次发送的数据
+	Buffer_Struct RxBuf;
+	CBFuncEx_t CB;
+	Timer_t *RxTimer;
+	uint32_t RxTimeoutUS;
+	uint8_t *TxData;
+	uint8_t USBOnOff;
+	uint8_t UartOnOff;
+	uint8_t USB_ID;
+	uint8_t ToHostEpIndex;
+	uint8_t ToDeviceEpIndex;
+}Virtual_UartCtrlStruct;
+
+static MSC_SCSICtrlStruct prvLuatOS_SCSI;
+static Virtual_HIDCtrlStruct prvLuatOS_VirtualHID;
+static Virtual_UDiskCtrlStruct prvLuatOS_VirtualUDisk;
+static Virtual_UartCtrlStruct prvLuatOS_VirtualUart[VIRTUAL_UART_MAX];
+
+/* LangID = 0x0409: U.S. English */
+static const char prvCore_StringManufacturer[] = "airm2m";
+static const char prvCore_StringProduct[] = "air105 usb device";
+static const char prvCore_StringSerial[] = "00001";
+static const char prvCore_StringConfig[] = "luatos";
+static const char *prvCore_StringInterface[3] = {
+		"virtual Mass Storage Device",
+		"virtual HID Keyboard",
+		"virtual Serial"
+};
+
+
+
+static const usb_device_descriptor_t prvCore_DeviceDesc =
+{
+		.bLength = USB_LEN_DEV_DESC,
+		.bDescriptorType = UDESC_DEVICE,
+		.bcdUSB = {0x00, 0x02},
+		.bDeviceClass = UDCLASS_IN_INTERFACE,
+		.bDeviceSubClass = 0,
+		.bDeviceProtocol = 0,
+		.bMaxPacketSize = 0x40,
+		.idVendor = {0x82, 0x17},
+		.idProduct = {0x00, 0x4e},
+//		.idVendor = {0x83, 0x04},
+//		.idProduct = {0x20, 0x57},
+		.bcdDevice = {0x00, 0x02},
+		.iManufacturer = USBD_IDX_MANUFACTURER_STR,
+		.iProduct = USBD_IDX_PRODUCT_STR,
+		.iSerialNumber = 0,
+		.bNumConfigurations = 1,
+};
+
+static const usb_device_qualifier_t prvCore_QualifierDesc =
+{
+	.bLength = USB_LEN_DEV_QUALIFIER_DESC,   /* bLength  */
+	.bDescriptorType = UDESC_DEVICE_QUALIFIER,   /* bDescriptorType */
+	.bcdUSB = {0x00, 0x02},
+	.bDeviceClass = UDCLASS_IN_INTERFACE,
+	.bDeviceSubClass = 0,
+	.bDeviceProtocol = 0,
+	.bMaxPacketSize0 = 0x40,
+	.bNumConfigurations = 1,
+	.bReserved = 0
+};
+
+static const usb_config_descriptor_t prvCore_ConfigDesc =
+{
+		.bLength = USB_LEN_CFG_DESC,
+		.bDescriptorType = UDESC_CONFIG,
+		.wTotalLength = {0x00, 0x00},
+		.bNumInterface = DEVICE_INTERFACE_MAX,
+		.bConfigurationValue = 1,
+		.iConfiguration = USBD_IDX_CONFIG_STR,
+		.bmAttributes = UC_SELF_POWERED|UC_BUS_POWERED,
+		.bMaxPower = (USB_MIN_POWER >> 1),
+};
+
+static const usb_interface_assoc_descriptor_t prvCore_AssocInterfaceDesc =
+{
+		.bLength = USB_LEN_ASSOC_IF_DESC,
+		.bDescriptorType = UDESC_IFACE_ASSOC,
+		.bFirstInterface = 0,
+		.bInterfaceCount = 1,
+//		.bFunctionClass = UICLASS_MASS,
+//		.bFunctionSubClass = UISUBCLASS_SCSI,
+//		.bFunctionProtocol = UIPROTO_MASS_BBB,
+//		.bFunctionClass = 0,
+//		.bFunctionSubClass = 0,
+//		.bFunctionProtocol = 0,
+		.bFunctionClass = UICLASS_HID,
+		.bFunctionSubClass = 0,
+		.bFunctionProtocol = UIPROTO_BOOT_KEYBOARD,
+		.iFunction = USBD_IDX_INTERFACE0_STR,
+};
+
+static const usb_interface_descriptor_t prvCore_MassStorgeInterfaceDesc =
+{
+		.bLength = USB_LEN_IF_DESC,
+		.bDescriptorType = UDESC_INTERFACE,
+		.bInterfaceNumber = DEVICE_INTERFACE_MSC_SN,
+		.bAlternateSetting = 0,
+		.bNumEndpoints = 2,
+		.bInterfaceClass = UICLASS_MASS,
+		.bInterfaceSubClass = UISUBCLASS_SCSI,
+		.bInterfaceProtocol = UIPROTO_MASS_BBB,
+		.iInterface = USBD_IDX_INTERFACE0_STR,
+};
+
+static const usb_endpoint_descriptor_t prvCore_MassStorgeEndpointDesc[2] =
+{
+		{
+				.bLength = USB_LEN_EP_DESC,
+				.bDescriptorType = UDESC_ENDPOINT,
+				.bEndpointAddress = UE_DIR_IN|DEVICE_MASS_STORAGE_EP_IN,
+				.bmAttributes = UE_BULK,
+				.wMaxPacketSize = {0x40,0x00},
+				.bInterval = 10,
+		},
+		{
+				.bLength = USB_LEN_EP_DESC,
+				.bDescriptorType = UDESC_ENDPOINT,
+				.bEndpointAddress = UE_DIR_OUT|DEVICE_MASS_STORAGE_EP_OUT,
+				.bmAttributes = UE_BULK,
+				.wMaxPacketSize = {0x40,0x00},
+				.bInterval = 10,
+		}
+};
+
+static const usb_interface_descriptor_t prvCore_HIDInterfaceDesc =
+{
+		.bLength = USB_LEN_IF_DESC,
+		.bDescriptorType = UDESC_INTERFACE,
+		.bInterfaceNumber = DEVICE_INTERFACE_HID_SN,
+		.bAlternateSetting = 0,
+		.bNumEndpoints = 2,
+		.bInterfaceClass = UICLASS_HID,
+		.bInterfaceSubClass = 0,
+		.bInterfaceProtocol = UIPROTO_BOOT_KEYBOARD,
+		.iInterface = USBD_IDX_INTERFACE0_STR + 1,
+};
+
+static const usb_endpoint_descriptor_t prvCore_HIDEndpointDesc[2] =
+{
+		{
+				.bLength = USB_LEN_EP_DESC,
+				.bDescriptorType = UDESC_ENDPOINT,
+				.bEndpointAddress = UE_DIR_IN|DEVICE_HID_KEYBOARD_EP_IN,
+				.bmAttributes = UE_INTERRUPT,
+				.wMaxPacketSize = {0x08,0x00},
+				.bInterval = 10,
+		},
+		{
+				.bLength = USB_LEN_EP_DESC,
+				.bDescriptorType = UDESC_ENDPOINT,
+				.bEndpointAddress = UE_DIR_OUT|DEVICE_HID_KEYBOARD_EP_OUT,
+				.bmAttributes = UE_INTERRUPT,
+				.wMaxPacketSize = {0x08,0x00},
+				.bInterval = 10,
+		},
+};
+
+static const usb_interface_descriptor_t prvCore_SerialInterfaceDesc =
+{
+		.bLength = USB_LEN_IF_DESC,
+		.bDescriptorType = UDESC_INTERFACE,
+		.bInterfaceNumber = DEVICE_INTERFACE_SERIAL_SN,
+		.bAlternateSetting = 0,
+		.bNumEndpoints = 2,
+		.bInterfaceClass = UICLASS_VENDOR,
+		.bInterfaceSubClass = 0,
+		.bInterfaceProtocol = 0,
+		.iInterface = USBD_IDX_INTERFACE0_STR + 2,
+};
+
+static const usb_endpoint_descriptor_t prvCore_SerialEndpointDesc[2] =
+{
+		{
+				.bLength = USB_LEN_EP_DESC,
+				.bDescriptorType = UDESC_ENDPOINT,
+				.bEndpointAddress = UE_DIR_IN|DEVICE_GENERIC_SERIAL_EP_IN,
+				.bmAttributes = UE_BULK,
+				.wMaxPacketSize = {0x40,0x00},
+				.bInterval = 10,
+		},
+		{
+				.bLength = USB_LEN_EP_DESC,
+				.bDescriptorType = UDESC_ENDPOINT,
+				.bEndpointAddress = UE_DIR_OUT|DEVICE_GENERIC_SERIAL_EP_OUT,
+				.bmAttributes = UE_BULK,
+				.wMaxPacketSize = {0x40,0x00},
+				.bInterval = 10,
+		}
+};
+
+static const usb_hid_descriptor_t  prvCore_HIDDesc =
+{
+		.bLength = 9,
+		.bDescriptorType = USB_HID_DESCRIPTOR_TYPE,
+		.bcdHID = {0x11, 0x01},
+		.bCountryCode = 0x21,
+		.bNumDescriptors = 1,
+		.bReportDescriptorType = USB_HID_REPORT_DESC,
+		.wDescriptorLength = {63,0},
+};
+
+static const char prvCore_HIDReportDesc[63] = {
+	    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
+	    0x09, 0x06,                    // USAGE (Keyboard)
+	    0xa1, 0x01,                    // COLLECTION (Application)
+	    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
+	    0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
+	    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
+	    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
+	    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
+	    0x75, 0x01,                    //   REPORT_SIZE (1)
+	    0x95, 0x08,                    //   REPORT_COUNT (8)
+	    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
+	    0x95, 0x01,                    //   REPORT_COUNT (1)
+	    0x75, 0x08,                    //   REPORT_SIZE (8)
+	    0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
+	    0x95, 0x05,                    //   REPORT_COUNT (5)
+	    0x75, 0x01,                    //   REPORT_SIZE (1)
+	    0x05, 0x08,                    //   USAGE_PAGE (LEDs)
+	    0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
+	    0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
+	    0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
+	    0x95, 0x01,                    //   REPORT_COUNT (1)
+	    0x75, 0x03,                    //   REPORT_SIZE (3)
+	    0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
+	    0x95, 0x06,                    //   REPORT_COUNT (6)
+	    0x75, 0x08,                    //   REPORT_SIZE (8)
+	    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
+	    0x25, 0xff,                    //   LOGICAL_MAXIMUM (255)
+	    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
+	    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
+	    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
+	    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
+	    0xc0                           // END_COLLECTION
+};
+
+static int32_t prvCore_GetHIDDesc(void *pData, void *pParam)
+{
+	if (pData)
+	{
+		memcpy(pData, &prvCore_HIDDesc, sizeof(usb_hid_descriptor_t));
+	}
+	return sizeof(usb_hid_descriptor_t);
+}
+
+static usb_full_interface_t prvCore_InterfaceList[3] =
+{
+		{
+				&prvCore_HIDInterfaceDesc,
+				prvCore_HIDEndpointDesc,
+				NULL,
+				prvCore_GetHIDDesc,
+				2,
+		},
+		{
+				&prvCore_MassStorgeInterfaceDesc,
+				prvCore_MassStorgeEndpointDesc,
+				NULL,
+				NULL,
+				2,
+		},
+		{
+				&prvCore_SerialInterfaceDesc,
+				prvCore_SerialEndpointDesc,
+				NULL,
+				NULL,
+				2,
+		},
+};
+static const usb_full_config_t prvCore_Config =
+{
+		.pConfigDesc = &prvCore_ConfigDesc,
+		.pInterfaceAssocDesc = &prvCore_AssocInterfaceDesc,
+		.pInterfaceFullDesc = prvCore_InterfaceList,
+		.InterfaceNum = 3,
+};
+static const USB_FullConfigStruct prvCore_FullConfig =
+{
+		.pQualifierDesc = NULL,
+		.pFullConfig = {&prvCore_Config, NULL, NULL},
+};
+
+static const uint8_t prvCore_StandardInquiryData[STANDARD_INQUIRY_DATA_LEN] =
+{
+		0x00, //磁盘设备
+		0x00, //其中最高位D7为RMB。RMB=0,表示不可移除设备。如果RMB=1,则为可移除设备。
+		0x02, //各种版本号
+		0x02, //数据响应格式 0x02
+		0x1F, //附加数据长度,为31字节
+		0x00, //保留
+		0x00, //保留
+		0x00, //保留
+		'A','I','R','M','2','M',' ',' ',
+		'L','U','A','T','O','S','-','S','O','C',' ','U','S','B',' ',' ',
+		'1','.','0','0'
+};
+
+static const uint8_t prvCore_MSCPage00InquiryData[LENGTH_INQUIRY_PAGE00] =
+{
+	0x00,
+	0x00,
+	0x00,
+	(LENGTH_INQUIRY_PAGE00 - 4U),
+	0x00,
+	0x80
+};
+
+/* USB Mass storage VPD Page 0x80 Inquiry Data for Unit Serial Number */
+static const uint8_t prvCore_MSCPage80InquiryData[LENGTH_INQUIRY_PAGE80] =
+{
+	0x00,
+	0x80,
+	0x00,
+	LENGTH_INQUIRY_PAGE80,
+	0x20,     /* Put Product Serial number */
+	0x20,
+	0x20,
+	0x20
+};
+
+/* USB Mass storage sense 6 Data */
+static const uint8_t prvCore_MSCModeSense6data[MODE_SENSE6_LEN] =
+{
+	0x22,
+	0x00,
+	0x00,
+	0x00,
+	0x08,
+	0x12,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00
+};
+
+
+/* USB Mass storage sense 10  Data */
+static const uint8_t prvCore_MSCModeSense10data[MODE_SENSE10_LEN] =
+{
+	0x00,
+	0x26,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x08,
+	0x12,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00
+};
+
+static int32_t prvCore_SCSIInit(uint8_t LUN, void *pUserData)
+{
+	return 0;
+}
+
+static int32_t prvCore_SCSIGetCapacity(uint8_t LUN, uint32_t *BlockNum, uint32_t *BlockSize, void *pUserData)
+{
+	*BlockNum = prvLuatOS_VirtualUDisk.BlockTotalNums;
+	*BlockSize = prvLuatOS_VirtualUDisk.BlockSize;
+	return 0;
+}
+
+static int32_t prvCore_SCSIIsReady(uint8_t LUN, void *pUserData)
+{
+	return 0;
+}
+
+static int32_t prvCore_SCSIIsWriteProtected(uint8_t LUN, void *pUserData)
+{
+	return 0;
+}
+
+static int32_t prvCore_SCSIPreRead(uint8_t LUN, uint32_t BlockAddress, uint32_t BlockNums, void *pUserData)
+{
+	if ((BlockAddress + BlockNums) * prvLuatOS_VirtualUDisk.BlockSize > VIRTUAL_UDISK_LEN)
+	{
+		return -1;
+	}
+	prvLuatOS_VirtualUDisk.CurAddress = BlockAddress * prvLuatOS_VirtualUDisk.BlockSize;
+	return 0;
+}
+
+static int32_t prvCore_SCSIRead(uint8_t LUN, uint32_t Len, uint8_t **pOutData, uint32_t *OutLen, void *pUserData)
+{
+	if (Len + prvLuatOS_VirtualUDisk.CurAddress > VIRTUAL_UDISK_LEN)
+	{
+		return -1;
+	}
+	*pOutData = &prvLuatOS_VirtualUDisk.VirtualData[prvLuatOS_VirtualUDisk.CurAddress];
+	*OutLen = Len;
+	prvLuatOS_VirtualUDisk.CurAddress += Len;
+	return 0;
+}
+
+static int32_t prvCore_SCSIPreWrite(uint8_t LUN, uint32_t BlockAddress, uint32_t BlockNums, void *pUserData)
+{
+	if ((BlockAddress + BlockNums) * prvLuatOS_VirtualUDisk.BlockSize > VIRTUAL_UDISK_LEN)
+	{
+		return -1;
+	}
+	prvLuatOS_VirtualUDisk.CurAddress = BlockAddress * prvLuatOS_VirtualUDisk.BlockSize;
+	return 0;
+}
+
+static int32_t prvCore_SCSIWrite(uint8_t LUN, uint8_t *Data, uint32_t Len, void *pUserData)
+{
+	if (Len + prvLuatOS_VirtualUDisk.CurAddress > VIRTUAL_UDISK_LEN)
+	{
+		return -1;
+	}
+	memcpy(&prvLuatOS_VirtualUDisk.VirtualData[prvLuatOS_VirtualUDisk.CurAddress], Data, Len);
+	prvLuatOS_VirtualUDisk.CurAddress += Len;
+	return 0;
+}
+static int32_t prvCore_SCSIUserCmd(USB_EndpointDataStruct *pEpData, MSC_SCSICtrlStruct *pMSC)
+{
+	return -1;
+}
+
+static int32_t prvCore_SCSIGetMaxLUN(uint8_t *LUN, void *pUserData)
+{
+	*LUN = 0;
+}
+static const USB_StorageSCSITypeDef prvCore_SCSIFun =
+{
+		prvCore_SCSIGetMaxLUN,
+		prvCore_SCSIInit,
+		prvCore_SCSIGetCapacity,
+		prvCore_SCSIIsReady,
+		prvCore_SCSIIsWriteProtected,
+		prvCore_SCSIPreRead,
+		prvCore_SCSIRead,
+		prvCore_SCSIPreWrite,
+		prvCore_SCSIWrite,
+		prvCore_SCSIUserCmd,
+		&prvCore_StandardInquiryData,
+		&prvCore_MSCPage00InquiryData,
+		&prvCore_MSCPage80InquiryData,
+		&prvCore_MSCModeSense6data,
+		&prvCore_MSCModeSense10data,
+};
+
+static void prvCore_VUartOpen(Virtual_UartCtrlStruct *pVUart, uint8_t UartID)
+{
+	pVUart->USBOnOff = 1;
+	if (pVUart->TxBuf.Data)
+	{
+		DBG("send last data %ubyte", pVUart->TxBuf.MaxLen);
+		USB_StackTxEpData(pVUart->USB_ID, pVUart->ToHostEpIndex, pVUart->TxBuf.Data, pVUart->TxBuf.MaxLen, pVUart->TxBuf.MaxLen, 0);
+	}
+	else if (pVUart->TxCacheBuf.Pos)
+	{
+		DBG("send cache data %ubyte", pVUart->TxCacheBuf.Pos);
+		Buffer_StaticInit(&pVUart->TxBuf, pVUart->TxCacheBuf.Data, pVUart->TxCacheBuf.Pos);
+		OS_InitBuffer(&pVUart->TxCacheBuf, VIRTUAL_SERIAL_BUFFER_LEN);
+		USB_StackTxEpData(pVUart->USB_ID, pVUart->ToHostEpIndex, pVUart->TxBuf.Data, pVUart->TxBuf.MaxLen, pVUart->TxBuf.MaxLen, 0);
+	}
+	pVUart->CB(UartID, UART_CB_CONNECTED);
+}
+
+static int32_t prvCore_VUartRxTimeoutCB(void *pData, void *pParam)
+{
+	uint32_t UartID = (uint32_t)pParam;
+	prvLuatOS_VirtualUart[UartID].CB(UartID, UART_CB_RX_TIMEOUT);
+}
+
+static int32_t prvCore_VHIDDummyCB(void *pData, void *pParam)
+{
+	return 0;
+}
+
+static int32_t prvCore_VUartDummyCB(void *pData, void *pParam)
+{
+	return 0;
+}
+
+static int32_t prvCore_VMSCDummyCB(void *pData, void *pParam)
+{
+	return 0;
+}
+
+static void prvCore_VHIDSetReady(uint8_t OnOff)
+{
+	if (prvLuatOS_VirtualHID.IsReady != OnOff)
+	{
+		prvLuatOS_VirtualHID.IsReady = OnOff;
+		prvLuatOS_VirtualHID.CB(prvLuatOS_VirtualHID.USB_ID, prvLuatOS_VirtualHID.IsReady);
+	}
+}
+
+static int32_t prvCore_USBEp0CB(void *pData, void *pParam)
+{
+	int32_t Result = -ERROR_CMD_NOT_SUPPORT;
+	USB_EndpointDataStruct *pEpData = (USB_EndpointDataStruct *)pData;
+	USB_StorageSCSITypeDef *pUserFun = (USB_StorageSCSITypeDef *)prvLuatOS_SCSI.pSCSIUserFunList;
+	uint16_t wLength, wValue;
+	Virtual_UartCtrlStruct *pVUart;
+//	DBG("%d,%d,%d,%d", pEpData->USB_ID, pEpData->EpIndex, pEpData->IsToDevice, pEpData->Len);
+	if (!pEpData->IsDataStage)
+	{
+		wLength = BytesGetLe16(pEpData->pLastRequest->wLength);
+		if (pEpData->IsToDevice)
+		{
+			switch (pEpData->pLastRequest->bRequest)
+			{
+			case UCDC_SET_CONTROL_LINE_STATE:
+				pVUart = &prvLuatOS_VirtualUart[pEpData->pLastRequest->wIndex[0] - DEVICE_INTERFACE_SERIAL_SN];
+				switch (pEpData->pLastRequest->wValue[0])
+				{
+				case 0:
+					//close serial
+					pVUart->USBOnOff = 0;
+					pVUart->CB(pEpData->pLastRequest->wIndex[0] - DEVICE_INTERFACE_SERIAL_SN, UART_CB_ERROR);
+					break;
+				case 1:
+				case 3:
+					//open serial
+					prvCore_VUartOpen(pVUart, pEpData->pLastRequest->wIndex[0] - DEVICE_INTERFACE_SERIAL_SN);
+					prvLuatOS_VirtualUart[pEpData->pLastRequest->wIndex[0] - DEVICE_INTERFACE_SERIAL_SN].USBOnOff = 1;
+					break;
+				}
+				Result = ERROR_NONE;
+				break;
+			case USB_HID_REQ_SET_IDLE:
+				prvCore_VHIDSetReady(1);
+				Result = ERROR_NONE;
+				break;
+			case UR_GET_DESCRIPTOR:
+				switch(pEpData->pLastRequest->wValue[1])
+				{
+				case USB_HID_REPORT_DESC:
+					USB_StackTxEpData(pEpData->USB_ID, pEpData->EpIndex, prvCore_HIDReportDesc, sizeof(prvCore_HIDReportDesc), wLength, 1);
+					Result = ERROR_NONE;
+					break;
+				}
+				break;
+			case MSC_GET_MAX_LUN:
+				pUserFun->GetMaxLUN(&prvLuatOS_SCSI.LogicalUnitNum, prvLuatOS_SCSI.pUserData);
+				USB_StackTxEpData(pEpData->USB_ID, pEpData->EpIndex, &prvLuatOS_SCSI.LogicalUnitNum, 1, wLength, 1);
+
+				Result = ERROR_NONE;
+				break;
+			case MSC_RESET:
+				Result = ERROR_NONE;
+				break;
+			}
+		}
+	}
+	return Result;
+}
+
+static int32_t prvCore_MSCCB(void *pData, void *pParam)
+{
+	USB_EndpointDataStruct *pEpData = (USB_EndpointDataStruct *)pData;
+	USB_MSCHandle(pEpData, &prvLuatOS_SCSI);
+	return ERROR_NONE;
+}
+
+static int32_t prvCore_HIDCB(void *pData, void *pParam)
+{
+	USB_EndpointDataStruct *pEpData = (USB_EndpointDataStruct *)pData;
+	uint32_t USB_ID = (uint32_t)pParam;
+	Virtual_HIDCtrlStruct *pVHID = &prvLuatOS_VirtualHID;
+	if (pEpData->IsToDevice)
+	{
+		prvCore_VHIDSetReady(1);
+	}
+	else
+	{
+		OS_DeInitBuffer(&pVHID->TxBuf);
+		if (pVHID->TxCacheBuf.Pos)
+		{
+			Buffer_StaticInit(&pVHID->TxBuf, pVHID->TxCacheBuf.Data, pVHID->TxCacheBuf.Pos);
+			OS_InitBuffer(&pVHID->TxCacheBuf, VIRTUAL_VHID_BUFFER_LEN);
+			USB_StackTxEpData(pVHID->USB_ID, pVHID->ToHostEpIndex, pVHID->TxBuf.Data, pVHID->TxBuf.MaxLen, pVHID->TxBuf.MaxLen, 1);
+		}
+		else
+		{
+			pVHID->CB(USB_ID, USB_HID_SEND_DONE);
+		}
+	}
+	return ERROR_NONE;
+}
+
+static int32_t prvCore_SerialCB(void *pData, void *pParam)
+{
+	USB_EndpointDataStruct *pEpData = (USB_EndpointDataStruct *)pData;
+	uint32_t UartID = (uint32_t)pParam;
+	Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID];
+	if (pEpData->IsToDevice)
+	{
+		//open serial
+		if (!pVUart->USBOnOff)
+		{
+			prvCore_VUartOpen(pVUart, UartID);
+		}
+		if (pEpData->Data && pEpData->Len)
+		{
+			if ((pVUart->RxBuf.Pos + pEpData->Len) >= pVUart->RxBuf.MaxLen)
+			{
+				OS_ReSizeBuffer(&pVUart->RxBuf, pVUart->RxBuf.MaxLen * 2);
+			}
+			OS_BufferWrite(&pVUart->RxBuf, pEpData->Data, pEpData->Len);
+			if (pEpData->IsDataStage && pVUart->RxTimeoutUS)
+			{
+				Timer_StartUS(pVUart->RxTimer, pVUart->RxTimeoutUS, 0);
+			}
+			else
+			{
+				Timer_Stop(pVUart->RxTimer);
+				pVUart->CB(UartID, UART_CB_RX_NEW);
+			}
+		}
+	}
+	else
+	{
+		OS_DeInitBuffer(&pVUart->TxBuf);
+		if (pVUart->TxCacheBuf.Pos)
+		{
+			Buffer_StaticInit(&pVUart->TxBuf, pVUart->TxCacheBuf.Data, pVUart->TxCacheBuf.Pos);
+			OS_InitBuffer(&pVUart->TxCacheBuf, VIRTUAL_SERIAL_BUFFER_LEN);
+			USB_StackTxEpData(pVUart->USB_ID, pVUart->ToHostEpIndex, pVUart->TxBuf.Data, pVUart->TxBuf.MaxLen, pVUart->TxBuf.MaxLen, 0);
+		}
+		else
+		{
+			pVUart->CB(UartID, UART_CB_TX_ALL_DONE);
+		}
+	}
+	return ERROR_NONE;
+}
+
+static int32_t prvCore_USBStateCB(void *pData, void *pParam)
+{
+	PV_Union uPV;
+	uint8_t i;
+	uPV.p = pData;
+	switch(uPV.u8[1])
+	{
+	case USBD_BUS_TYPE_DISCONNECT:
+		prvCore_VHIDSetReady(0);
+		USB_MSCReset(&prvLuatOS_SCSI);
+		for(i = 0; i < VIRTUAL_UART_MAX; i++)
+		{
+			prvLuatOS_VirtualUart[i].USBOnOff = 0;
+			prvLuatOS_VirtualUart[i].CB(i, UART_CB_ERROR);
+		}
+		break;
+	case USBD_BUS_TYPE_ENABLE_CONNECT:
+		USB_StackStartDevice(uPV.u8[0]);
+		break;
+	}
+}
+
+void Core_USBDefaultDeviceStart(uint8_t USB_ID)
+{
+	uint8_t langid[2] = {0x09, 0x04};
+	int i;
+	prvLuatOS_VirtualHID.USB_ID = USB_ID;
+	prvLuatOS_VirtualHID.IsReady = 0;
+	prvLuatOS_VirtualHID.ToHostEpIndex = DEVICE_HID_KEYBOARD_EP_IN;
+	prvLuatOS_VirtualUDisk.BlockTotalNums = VIRTUAL_UDISK_BLOCKS_NUMS;
+	prvLuatOS_VirtualUDisk.BlockSize = VIRTUAL_UDISK_BLOCKS_LEN;
+	prvLuatOS_SCSI.LogicalUnitNum = 0;
+	prvLuatOS_SCSI.ToHostEpIndex = DEVICE_MASS_STORAGE_EP_IN;
+	prvLuatOS_SCSI.ToDeviceEpIndex = DEVICE_MASS_STORAGE_EP_OUT;
+	prvLuatOS_SCSI.pSCSIUserFunList = &prvCore_SCSIFun;
+	if (!prvLuatOS_VirtualHID.CB)
+	{
+		prvLuatOS_VirtualHID.CB = prvCore_VHIDDummyCB;
+	}
+	OS_ReInitBuffer(&prvLuatOS_VirtualHID.TxCacheBuf, VIRTUAL_VHID_BUFFER_LEN);
+	USB_StackPowerOnOff(USB_ID, 1);
+	USB_StackStop(USB_ID);
+	USB_StackClearSetup(USB_ID);
+	USB_StackSetDeviceBusPower(USB_ID, 1);
+	USB_StackSetEpCB(USB_ID, 0, prvCore_USBEp0CB, NULL);
+	USB_StackSetEpCB(USB_ID, DEVICE_HID_KEYBOARD_EP_IN, prvCore_HIDCB, USB_ID);
+	USB_StackSetEpCB(USB_ID, DEVICE_HID_KEYBOARD_EP_OUT, prvCore_HIDCB, USB_ID);
+	USB_StackSetEpCB(USB_ID, DEVICE_MASS_STORAGE_EP_IN, prvCore_MSCCB, USB_ID);
+	USB_StackSetEpCB(USB_ID, DEVICE_MASS_STORAGE_EP_OUT, prvCore_MSCCB, USB_ID);
+	USB_StackSetEpCB(USB_ID, DEVICE_GENERIC_SERIAL_EP_IN, prvCore_SerialCB, VIRTUAL_UART0);
+	USB_StackSetEpCB(USB_ID, DEVICE_GENERIC_SERIAL_EP_OUT, prvCore_SerialCB, VIRTUAL_UART0);
+	USB_StackSetDeviceConfig(USB_ID, &prvCore_DeviceDesc, &prvCore_FullConfig, 1, USBD_IDX_INTERFACE0_STR + 3, prvCore_USBStateCB, NULL);
+	USB_StackSetCharString(USB_ID, USBD_IDX_LANGID_STR, langid, 2);
+	USB_StackSetCharString(USB_ID, USBD_IDX_MANUFACTURER_STR, prvCore_StringManufacturer, sizeof(prvCore_StringManufacturer));
+	USB_StackSetCharString(USB_ID, USBD_IDX_PRODUCT_STR, prvCore_StringProduct, sizeof(prvCore_StringProduct));
+	USB_StackSetCharString(USB_ID, USBD_IDX_SERIAL_STR, prvCore_StringSerial, sizeof(prvCore_StringSerial));
+	USB_StackSetCharString(USB_ID, USBD_IDX_CONFIG_STR, prvCore_StringConfig, sizeof(prvCore_StringConfig));
+	for(i = 0; i < 3; i++)
+	{
+		USB_StackSetCharString(USB_ID, USBD_IDX_INTERFACE0_STR + i, prvCore_StringInterface[i], strlen(prvCore_StringInterface[i]));
+	}
+	for(i = 0; i < VIRTUAL_UART_MAX; i++)
+	{
+		prvLuatOS_VirtualUart[i].USBOnOff = 0;
+		prvLuatOS_VirtualUart[i].USB_ID = USB_ID;
+		if (!prvLuatOS_VirtualUart[i].RxTimer)
+		{
+			prvLuatOS_VirtualUart[i].RxTimer = Timer_Create(prvCore_VUartRxTimeoutCB, i, NULL);
+		}
+		if (!prvLuatOS_VirtualUart[i].CB)
+		{
+			prvLuatOS_VirtualUart[i].CB = prvCore_VUartDummyCB;
+		}
+		prvLuatOS_VirtualUart[i].RxTimeoutUS = 150;
+		OS_ReInitBuffer(&prvLuatOS_VirtualUart[i].TxCacheBuf, VIRTUAL_SERIAL_BUFFER_LEN);
+		OS_ReInitBuffer(&prvLuatOS_VirtualUart[i].RxBuf, VIRTUAL_SERIAL_BUFFER_LEN);
+	}
+	prvLuatOS_VirtualUart[VIRTUAL_UART0].ToDeviceEpIndex = DEVICE_GENERIC_SERIAL_EP_IN;
+	prvLuatOS_VirtualUart[VIRTUAL_UART0].ToHostEpIndex = DEVICE_GENERIC_SERIAL_EP_OUT;
+	prvLuatOS_VirtualUDisk.VirtualData = prvLuatOS_VirtualUart[VIRTUAL_UART0].TxCacheBuf.Data;
+	USB_MSCReset(&prvLuatOS_SCSI);
+
+	USB_StackStartDevice(USB_ID);
+}
+
+
+void Core_VHIDInit(uint8_t USB_ID, CBFuncEx_t CB)
+{
+	if (CB)
+	{
+		prvLuatOS_VirtualHID.CB = CB;
+	}
+	else
+	{
+		prvLuatOS_VirtualHID.CB = prvCore_VHIDDummyCB;
+	}
+
+}
+
+void Core_VUartInit(uint8_t UartID, uint32_t BaudRate, uint8_t IsRxCacheEnable, uint8_t DataBits, uint8_t Parity, uint8_t StopBits, CBFuncEx_t CB)
+{
+	Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID];
+//	switch(UartID)
+//	{
+//	case VIRTUAL_UART0:
+//		if (!prvService.IsUSBOpen)
+//		{
+//			Core_USBDefaultDeviceStart(USB_ID0);
+//			prvService.IsUSBOpen = 1;
+//		}
+//		break;
+//	}
+	if (CB)
+	{
+		pVUart->CB = CB;
+	}
+	else
+	{
+		pVUart->CB = prvCore_VUartDummyCB;
+	}
+	pVUart->UartOnOff = 1;
+}
+
+void Core_VUartDeInit(uint8_t UartID)
+{
+	Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID];
+	pVUart->UartOnOff = 0;
+}
+
+void Core_VUartSetRxTimeout(uint8_t UartID, uint32_t TimeoutUS)
+{
+	Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID];
+	pVUart->RxTimeoutUS = TimeoutUS;
+}
+
+void Core_VUartSetCb(uint8_t UartID, CBFuncEx_t CB)
+{
+	Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID];
+	if (CB)
+	{
+		pVUart->CB = CB;
+	}
+	else
+	{
+		pVUart->CB = prvCore_VUartDummyCB;
+	}
+}
+
+uint32_t Core_VUartRxBufferRead(uint8_t UartID, uint8_t *Data, uint32_t Len)
+{
+	uint32_t ReadLen;
+	Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID];
+	switch(UartID)
+	{
+	case VIRTUAL_UART0:
+		USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToDeviceEpIndex, 1, 0);
+		break;
+	}
+	if (!Len)
+	{
+		ReadLen = pVUart->RxBuf.Pos;
+		goto READ_END;
+
+	}
+	ReadLen = (pVUart->RxBuf.Pos < Len)?pVUart->RxBuf.Pos:Len;
+	memcpy(Data, pVUart->RxBuf.Data, ReadLen);
+	OS_BufferRemove(&pVUart->RxBuf, ReadLen);
+	if (!pVUart->RxBuf.Pos && pVUart->RxBuf.MaxLen > VIRTUAL_SERIAL_BUFFER_LEN)
+	{
+		OS_ReInitBuffer(&pVUart->RxBuf, VIRTUAL_SERIAL_BUFFER_LEN);
+	}
+READ_END:
+	switch(UartID)
+	{
+	case VIRTUAL_UART0:
+		USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToDeviceEpIndex, 1, 1);
+		break;
+	}
+	return ReadLen;
+}
+
+int32_t Core_VUartBufferTx(uint8_t UartID, const uint8_t *Data, uint32_t Len)
+{
+	Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID];
+
+	switch(UartID)
+	{
+	case VIRTUAL_UART0:
+		if (!pVUart->USBOnOff)
+		{
+			return -1;
+		}
+		USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToHostEpIndex, 0, 0);
+		break;
+	}
+
+	if (Data && Len)
+	{
+		OS_BufferWrite(&pVUart->TxCacheBuf, Data, Len);
+	}
+
+	if (pVUart->TxBuf.Data || pVUart->TxBuf.MaxLen)
+	{
+		goto TX_END;
+	}
+
+	// 把缓存的Tx指针交给发送的Tx指针,缓存的Tx指针重新建立一个
+	Buffer_StaticInit(&pVUart->TxBuf, pVUart->TxCacheBuf.Data, pVUart->TxCacheBuf.Pos);
+	OS_InitBuffer(&pVUart->TxCacheBuf, VIRTUAL_SERIAL_BUFFER_LEN);
+	USB_StackTxEpData(pVUart->USB_ID, pVUart->ToHostEpIndex, pVUart->TxBuf.Data, pVUart->TxBuf.MaxLen, pVUart->TxBuf.MaxLen, 0);
+TX_END:
+	switch(UartID)
+	{
+	case VIRTUAL_UART0:
+		USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToHostEpIndex, 0, 1);
+		break;
+	}
+	return 0;
+
+}
+void Core_VUartBufferTxStop(uint8_t UartID)
+{
+	Virtual_UartCtrlStruct *pVUart = &prvLuatOS_VirtualUart[UartID];
+	switch(UartID)
+	{
+	case VIRTUAL_UART0:
+		USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToHostEpIndex, 0, 0);
+		break;
+	}
+	OS_DeInitBuffer(&pVUart->TxBuf);
+	pVUart->TxCacheBuf.Pos = 0;
+	USB_StackStopDeviceTx(pVUart->USB_ID, pVUart->ToHostEpIndex, 0);
+	switch(UartID)
+	{
+	case VIRTUAL_UART0:
+		USB_StackEpIntOnOff(pVUart->USB_ID, pVUart->ToHostEpIndex, 0, 1);
+		break;
+	}
+}
+
+void Core_VHIDUploadData(uint8_t USB_ID, uint8_t *Data, uint16_t Len)
+{
+	if (!prvLuatOS_VirtualHID.IsReady) return;
+	USB_HIDKeyValue HIDKey;
+	USB_HIDKeyBoradKeyStruct HIDKeyBoard;
+	uint16_t Pos;
+	volatile uint8_t IsShift, i, LastValue;
+	Virtual_HIDCtrlStruct *pVHID = &prvLuatOS_VirtualHID;
+	USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 0);
+
+	if (Data && Len)
+	{
+		if ((Len*16 + pVHID->TxCacheBuf.Pos) > pVHID->TxCacheBuf.MaxLen)
+		{
+			OS_ReSizeBuffer(&pVHID->TxCacheBuf, Len*16 + pVHID->TxCacheBuf.Pos);
+		}
+		Pos = 0;
+		while(Pos < Len)
+		{
+			memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct));
+			HIDKey = USB_HIDGetValueFromAscii(Data[Pos]);
+			Pos++;
+			IsShift = HIDKey.Shift;
+			LastValue = HIDKey.Value;
+			HIDKeyBoard.SPECIALHID_KEY_b.RightShift = IsShift;
+			HIDKeyBoard.PressKey[0] = HIDKey.Value;
+//			DBG("%u,%c,%d,%x,%d", Pos - 1, Data[Pos - 1], 0, HIDKey.Value, HIDKey.Shift);
+ADD_REST:
+			for(i = 1; i < 4; i++)
+			{
+				HIDKey = USB_HIDGetValueFromAscii(Data[Pos]);
+				Pos++;
+				if ((IsShift != HIDKey.Shift))
+				{
+					//shift发生切换,必须换新的data
+					OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard));
+					memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct));
+					//加入一个抬起的data
+					OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard));
+					IsShift = HIDKey.Shift;
+					LastValue = HIDKey.Value;
+					HIDKeyBoard.SPECIALHID_KEY_b.RightShift = IsShift;
+					HIDKeyBoard.PressKey[0] = HIDKey.Value;
+//					DBG("%u,%c,%d,%x,%d", Pos - 1, Data[Pos - 1], 0, HIDKey.Value, HIDKey.Shift);
+					if (Pos < Len)
+					{
+						goto ADD_REST;
+					}
+					else
+					{
+						break;
+					}
+
+				}
+				else if (LastValue == HIDKey.Value)
+				{
+					OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard));
+					memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct));
+					//加入一个抬起的data
+					OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard));
+					IsShift = HIDKey.Shift;
+					LastValue = HIDKey.Value;
+					HIDKeyBoard.SPECIALHID_KEY_b.RightShift = IsShift;
+					HIDKeyBoard.PressKey[0] = HIDKey.Value;
+//					DBG("%u,%c,%d,%x,%d", Pos - 1, Data[Pos - 1], 0, HIDKey.Value, HIDKey.Shift);
+					if (Pos < Len)
+					{
+						goto ADD_REST;
+					}
+					else
+					{
+						break;
+					}
+				}
+				else
+				{
+					LastValue = HIDKey.Value;
+					HIDKeyBoard.PressKey[i] = HIDKey.Value;
+//					DBG("%u,%c,%d,%x,%d", Pos - 1, Data[Pos - 1], i, HIDKey.Value, HIDKey.Shift);
+					if (Pos >= Len)
+					{
+						break;
+					}
+				}
+			}
+			OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard));
+			//加入一个抬起的data
+			memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct));
+			OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard));
+		}
+		//加入一个抬起的data
+		memset(&HIDKeyBoard, 0, sizeof(USB_HIDKeyBoradKeyStruct));
+		OS_BufferWrite(&pVHID->TxCacheBuf, &HIDKeyBoard, sizeof(HIDKeyBoard));
+	}
+//	pVHID->TxCacheBuf.Pos = 0;
+//	return;
+	if (pVHID->TxBuf.Data || pVHID->TxBuf.MaxLen)
+	{
+		goto UPLOAD_END;
+	}
+
+	// 把缓存的Tx指针交给发送的Tx指针,缓存的Tx指针重新建立一个
+	Buffer_StaticInit(&pVHID->TxBuf, pVHID->TxCacheBuf.Data, pVHID->TxCacheBuf.Pos);
+	OS_InitBuffer(&pVHID->TxCacheBuf, VIRTUAL_VHID_BUFFER_LEN);
+	USB_StackTxEpData(pVHID->USB_ID, pVHID->ToHostEpIndex, pVHID->TxBuf.Data, pVHID->TxBuf.MaxLen, pVHID->TxBuf.MaxLen, 1);
+UPLOAD_END:
+	USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 1);
+}
+
+void Core_VHIDUploadStop(uint8_t USB_ID)
+{
+	Virtual_HIDCtrlStruct *pVHID = &prvLuatOS_VirtualHID;
+	USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 0);
+	OS_DeInitBuffer(&pVHID->TxBuf);
+	pVHID->TxCacheBuf.Pos = 0;
+	USB_StackStopDeviceTx(pVHID->USB_ID, pVHID->ToHostEpIndex, 0);
+	USB_StackEpIntOnOff(pVHID->USB_ID, pVHID->ToHostEpIndex, 0, 1);
+}