diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d02acbe15a96c012cc2b63daf3b44245f5a96d3b..2c2e2559398adb1688340a63e5ce5dcef9193c52 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -23,7 +23,7 @@ jobs:
     steps:
     - uses: actions/checkout@v3
     - name: Install Dependencies
-      run: sudo apt-get update && sudo apt-get install -y build-essential make libnewlib-dev gcc-riscv64-unknown-elf libusb-1.0-0-dev
+      run: sudo apt-get update && sudo apt-get install -y build-essential make libnewlib-dev gcc-riscv64-unknown-elf libusb-1.0-0-dev libudev-dev
     - name: Build ${{ matrix.example }}
       run: cd ${{ matrix.example }} && make V=1 -j3 $(basename ${{ matrix.example }}.elf) && riscv64-unknown-elf-size $(basename ${{ matrix.example }}.elf)
   # Build using PlatformIO
diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c
index d7d8f9798e899b909afefbbcb11e6231aa20cce0..0eb088650c75182f6323bc48190317cbd16e5f73 100644
--- a/ch32v003fun/ch32v003fun.c
+++ b/ch32v003fun/ch32v003fun.c
@@ -717,7 +717,7 @@ void NMI_Handler( void ) 				 __attribute__((section(".text.vector_handler"))) _
 void NMI_Handler( void )                 __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 #endif
 void HardFault_Handler( void )           __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
-#if defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x)
 void Ecall_M_Mode_Handler( void ) 		 __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void Ecall_U_Mode_Handler( void ) 		 __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void Break_Point_Handler( void ) 		 __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
@@ -732,7 +732,7 @@ void RTC_IRQHandler( void )				 __attribute__((section(".text.vector_handler")))
 #endif // defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 void FLASH_IRQHandler( void )            __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void RCC_IRQHandler( void )              __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
-#ifdef CH32V003
+#if defined(CH32V003) || defined(CH32X03x)
 void EXTI7_0_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void AWU_IRQHandler( void )              __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 #elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
@@ -749,7 +749,7 @@ void DMA1_Channel4_IRQHandler( void )    __attribute__((section(".text.vector_ha
 void DMA1_Channel5_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void DMA1_Channel6_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void DMA1_Channel7_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
-#ifdef CH32V003
+#if defined( CH32V003 ) || defined(CH32X03x)
 void ADC1_IRQHandler( void )             __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 #elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 void ADC1_2_IRQHandler( void ) 			 __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
@@ -774,7 +774,7 @@ void TIM4_IRQHandler( void ) 			 __attribute__((section(".text.vector_handler"))
 #endif // defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 void I2C1_EV_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void I2C1_ER_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
-#ifdef CH32V003
+#if defined( CH32V003 ) || defined( CH32X03x )
 void USART1_IRQHandler( void )           __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void SPI1_IRQHandler( void )             __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 #elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
@@ -840,7 +840,26 @@ void DMA2_Channel10_IRQHandler( void ) 	__attribute__((section(".text.vector_han
 void DMA2_Channel11_IRQHandler( void ) 	__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 #endif
 
-#ifdef CH32V003
+#if defined( CH32X03x)
+void USART2_IRQHandler( void )        __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void EXTI15_8_IRQHandler( void )      __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void EXTI25_16_IRQHandler( void )     __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void USART3_IRQHandler( void ) 		  __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void USART4_IRQHandler( void ) 		  __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void DMA1_Channel8_IRQHandler( void ) __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void USBFS_IRQHandler( void )         __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void USBFS_WakeUp_IRQHandler( void )  __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void PIOC_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void OPA_IRQHandler( void )           __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void USBPD_IRQHandler( void )         __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void USBPD_WKUP_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TIM2_CC_IRQHandler( void )       __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TIM2_TRG_IRQHandler( void )      __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TIM2_BRK_IRQHandler( void )      __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TIM3_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+#endif
+
+#if defined( CH32V003 ) || defined( CH32X03x )
 
 void InterruptVector()         __attribute__((naked)) __attribute((section(".init"))) __attribute((weak,alias("InterruptVectorDefault")));
 void InterruptVectorDefault()  __attribute__((naked)) __attribute((section(".init")));
@@ -852,18 +871,46 @@ void InterruptVectorDefault()
 	.option   push;\n\
 	.option   norvc;\n\
 	j handle_reset\n" );
+#if 0 // What is this for?  I don't see any reason to have it.
+#ifdef CH32X03x
+	asm volatile( "\n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00000013 \n\
+	.word 0x00100073" );
+#endif
+#endif
+
 #if !defined(FUNCONF_TINYVECTOR) || !FUNCONF_TINYVECTOR
 	asm volatile( "\n\
 	.word   0\n\
 	.word   NMI_Handler               /* NMI Handler */                    \n\
 	.word   HardFault_Handler         /* Hard Fault Handler */             \n\
+	.word   0\n"
+#if defined(CH32X03x)
+"	.word   Ecall_M_Mode_Handler       /* Ecall M Mode */ \n\
+	.word   0 \n\
+	.word   0 \n\
+	.word   Ecall_U_Mode_Handler       /* Ecall U Mode */ \n\
+	.word   Break_Point_Handler        /* Break Point */ \n\
+"
+#else
+"	.word   0\n\
 	.word   0\n\
 	.word   0\n\
 	.word   0\n\
-	.word   0\n\
-	.word   0\n\
-	.word   0\n\
-	.word   0\n\
+	.word   0\n"
+#endif
+"	.word   0\n\
 	.word   0\n\
 	.word   SysTick_Handler           /* SysTick Handler */                \n\
 	.word   0\n\
@@ -892,8 +939,26 @@ void InterruptVectorDefault()
 	.word   TIM1_UP_IRQHandler        /* TIM1 Update */                    \n\
 	.word   TIM1_TRG_COM_IRQHandler   /* TIM1 Trigger and Commutation */   \n\
 	.word   TIM1_CC_IRQHandler        /* TIM1 Capture Compare */           \n\
-	.word   TIM2_IRQHandler           /* TIM2 */                           \n\
-");
+	.word   TIM2_IRQHandler           /* TIM2 */                           \n"
+#if defined( CH32X03x )
+"	.word	USART2_IRQHandler         /* UART2 Interrupt                          */ \n\
+	.word	EXTI15_8_IRQHandler       /* External Line[8:15] Interrupt            */ \n\
+	.word	EXTI25_16_IRQHandler      /* External Line[25:16] Interrupt           */ \n\
+	.word	USART3_IRQHandler         /* UART2 Interrupt                          */ \n\
+	.word	USART4_IRQHandler         /* UART2 Interrupt                          */ \n\
+	.word	DMA1_Channel8_IRQHandler  /* DMA1 Channel 8 global Interrupt          */ \n\
+	.word	USBFS_IRQHandler          /* USB Full-Speed Interrupt                 */ \n\
+	.word	USBFS_WakeUp_IRQHandler   /* USB Full-Speed Wake-Up Interrupt         */ \n\
+	.word	PIOC_IRQHandler           /* Programmable IO Controller Interrupt     */ \n\
+	.word	OPA_IRQHandler            /* Op Amp Interrupt                         */ \n\
+	.word	USBPD_IRQHandler          /* USB Power Delivery Interrupt             */ \n\
+	.word	USBPD_WKUP_IRQHandler     /* USB Power Delivery Wake-Up Interrupt     */ \n\
+	.word	TIM2_CC_IRQHandler        /* Timer 2 Compare Global Interrupt         */ \n\
+	.word	TIM2_TRG_IRQHandler       /* Timer 2 Trigger Global Interrupt         */ \n\
+	.word	TIM2_BRK_IRQHandler       /* Timer 2 Brk Global Interrupt             */ \n\
+	.word	TIM3_IRQHandler           /* Timer 3 Global Interrupt                 */"
+#endif
+	);
 #endif
 	asm volatile( ".option   pop;\n");
 }
@@ -910,9 +975,17 @@ void handle_reset()
 ".option arch, +zicsr\n"
 #endif
 	// Setup the interrupt vector, processor status and INTSYSCR.
+
+#if FUNCONF_ENABLE_HPE	// Enabled nested and hardware (HPE) stack, since it's really good on the x035.
+"	li t0, 0x88\n\
+	csrs mstatus, t0\n"
+"	li t0, 0x0b\n\
+	csrw 0x804, t0\n"
+#else
 "	li a0, 0x80\n\
-	csrw mstatus, a0\n\
-	li a3, 0x3\n\
+	csrw mstatus, a0\n"
+#endif
+"	li a3, 0x3\n\
 	la a0, InterruptVector\n\
 	or a0, a0, a3\n\
 	csrw mtvec, a0\n" 
@@ -950,7 +1023,6 @@ asm volatile(
 #endif
 );
 
-
 #if defined( FUNCONF_SYSTICK_USE_HCLK ) && FUNCONF_SYSTICK_USE_HCLK
 	SysTick->CTLR = 5;
 #else
@@ -1137,7 +1209,8 @@ void InterruptVectorDefault()
     .word   DMA2_Channel10_IRQHandler  /* DMA2 Channel 10 */ \n\
     .word   DMA2_Channel11_IRQHandler  /* DMA2 Channel 11 */ \n"
 #endif
-#endif
+
+#endif // !defined(FUNCONF_TINYVECTOR) || !FUNCONF_TINYVECTOR
 "	.option rvc; \n");
 
 }
@@ -1190,14 +1263,19 @@ void handle_reset( void )
 	asm volatile(
 "	li t0, 0x1f\n\
 	csrw 0xbc0, t0\n"
-#if defined(CH32V20x)
-	// Enabled nested and hardware stack
+
+//XXX TODO: CHECKME - TEST ON 203!!!
+#if FUNCONF_ENABLE_HPE	// Enabled nested and hardware (HPE) stack, since it's really good on the x035.
 "	li t0, 0x88\n\
 	csrs mstatus, t0\n"
-#elif defined(CH32V30x)
-	// Enable nested and hardware stack
 "	li t0, 0x0b\n\
 	csrw 0x804, t0\n"
+#else
+"	li a0, 0x80\n\
+	csrw mstatus, a0\n"
+#endif
+
+#if defined(CH32V30x)
 	// Enable floating point and interrupt
 "	li t0, 0x688\n\
 	csrs mstatus, t0\n"
@@ -1232,6 +1310,12 @@ void SetupUART( int uartBRR )
 	// Push-Pull, 10MHz Output, GPIO D5, with AutoFunction
 	GPIOD->CFGLR &= ~(0xf<<(4*5));
 	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
+#elif defined(CH32X03x)
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1;
+
+	// Push-Pull, 10MHz Output, GPIO A9, with AutoFunction
+	GPIOB->CFGHR &= ~(0xf<<(4*2));
+	GPIOB->CFGHR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*2);
 #else
 	RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1;
 
@@ -1403,9 +1487,11 @@ void DelaySysTick( uint32_t n )
 #elif defined(CH32V20x) || defined(CH32V30x)
 	uint64_t targend = SysTick->CNT + n;
 	while( ((int64_t)( SysTick->CNT - targend )) < 0 );
-#elif defined(CH32V10x)
+#elif defined(CH32V10x) || defined(CH32X03x)
 	uint32_t targend = SysTick->CNTL + n;
 	while( ((int32_t)( SysTick->CNTL - targend )) < 0 );
+#else
+	#error DelaySysTick not defined.
 #endif
 }
 
@@ -1430,7 +1516,7 @@ void SystemInit()
 		#define BASE_CFGR0 RCC_HPRE_DIV1 | RCC_PPRE2_DIV1 | RCC_PPRE1_DIV2 | PLL_MULTIPLICATION
 	#endif
 #else
-	#if defined(CH32V003)
+	#if defined(CH32V003) || defined(CH32X03x)
 		#define BASE_CFGR0 RCC_HPRE_DIV1     					  // HCLK = SYSCLK = APB1 And, no pll.
 	#else
 		#define BASE_CFGR0 RCC_HPRE_DIV1 | RCC_PPRE2_DIV1 | RCC_PPRE1_DIV1
@@ -1441,6 +1527,17 @@ void SystemInit()
 #define BASE_CTLR	(((FUNCONF_HSITRIM) << 3) | RCC_HSION | HSEBYP | RCC_CSS)
 //#define BASE_CTLR	(((FUNCONF_HSITRIM) << 3) | HSEBYP | RCC_CSS)	// disable HSI in HSE modes
 
+	// CH32V003 flash latency
+#if defined(CH32X03x)
+	FLASH->ACTLR = FLASH_ACTLR_LATENCY_2;                   // +2 Cycle Latency (Recommended per TRM)
+#elif defined(CH32V003)
+	#if FUNCONF_SYSTEM_CORE_CLOCK > 25000000
+		FLASH->ACTLR = FLASH_ACTLR_LATENCY_1;               // +1 Cycle Latency
+	#else
+		FLASH->ACTLR = FLASH_ACTLR_LATENCY_0;               // +0 Cycle Latency
+	#endif
+#endif
+
 #if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
 	#if defined(CH32V30x) || defined(CH32V20x) || defined(CH32V10x)
 		EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
@@ -1483,15 +1580,6 @@ void SystemInit()
 	FLASH->ACTLR |= FLASH_ACTLR_PRFTBE;
 #endif
 
-	// CH32V003 flash latency
-#if defined(CH32V003)
-	#if FUNCONF_SYSTEM_CORE_CLOCK > 25000000
-		FLASH->ACTLR = FLASH_ACTLR_LATENCY_1;               // +1 Cycle Latency
-	#else
-		FLASH->ACTLR = FLASH_ACTLR_LATENCY_0;               // +0 Cycle Latency
-	#endif
-#endif
-
 	// CH32V10x flash latency
 #if defined(CH32V10x)
 	#if defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h
index 861fc5ffc74f322ab56721479ef71a1ac5ea9189..7fceaa415337dc0ca4a6e8a2cee6297b2f9257d7 100644
--- a/ch32v003fun/ch32v003fun.h
+++ b/ch32v003fun/ch32v003fun.h
@@ -55,10 +55,12 @@
 #define FUNCONF_TINYVECTOR 0            // If enabled, Does not allow normal interrupts.
 #define FUNCONF_UART_PRINTF_BAUD 115200 // Only used if FUNCONF_USE_UARTPRINTF is set.
 #define FUNCONF_DEBUGPRINTF_TIMEOUT 160000 // Arbitrary time units
+#define FUNCONF_ENABLE_HPE 1            // Enable hardware interrupt stack.  Very good on QingKeV4, i.e. x035, v10x, v20x, v30x, but questionable on 003.
+#define FUNCONF_USE_5V_VDD 0            // Enable this if you plan to use your part at 5V - affects USB and PD configration on the x035.
 */
 
 // Sanity check for when porting old code.
-#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x)
 	#if defined(CH32V003)
 		#error Cannot define CH32V003 and another arch.
 	#endif
@@ -85,10 +87,31 @@
 	#define FUNCONF_USE_HSE 0
 #endif
 
+#if defined( CH32X03x ) && FUNCONF_USE_HSE
+	#error No HSE in CH32X03x
+#endif
+
 #if !defined( FUNCONF_USE_PLL )
-	#define FUNCONF_USE_PLL 1 // Default to use PLL
+	#if defined( CH32X03x )
+		#define FUNCONF_USE_PLL 0 // No PLL on X03x
+	#else
+		#define FUNCONF_USE_PLL 1 // Default to use PLL
+	#endif
 #endif
 
+#if defined( CH32X03x ) && FUNCONF_USE_PLL
+	#error No PLL on the X03x
+#endif
+
+#ifndef FUNCONF_ENABLE_HPE
+	#if defined( CH32V003 )
+		#define FUNCONF_ENABLE_HPE 0
+	#else
+		#define FUNCONF_ENABLE_HPE 1
+	#endif
+#endif
+
+
 #if !defined( FUNCONF_USE_CLK_SEC )
 	#define FUNCONF_USE_CLK_SEC  1// use clock security system by default
 #endif
@@ -112,6 +135,8 @@
 #ifndef HSI_VALUE
 	#if defined(CH32V003)
 		#define HSI_VALUE                 (24000000) // Value of the Internal oscillator in Hz, default.
+	#elif defined(CH32X03x)
+		#define HSI_VALUE				  (48000000)
 	#elif defined(CH32V10x)
 		#define HSI_VALUE				  (8000000)
 	#elif defined(CH32V20x)
@@ -155,6 +180,10 @@
 	#endif
 #endif
 
+#ifndef FUNCONF_USE_5V_VDD
+	#define FUNCONF_USE_5V_VDD 0
+#endif
+
 // Default package for CH32V20x
 #if defined(CH32V20x)
 #if !defined(CH32V20x_D8W) && !defined(CH32V20x_D8) && !defined(CH32V20x_D6)
@@ -208,7 +237,7 @@ typedef enum IRQn
     SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
     Software_IRQn = 14,      /* 14 software Interrupt                                */
 
-#ifdef CH32V003
+#if defined( CH32V003 ) || defined(CH32X03x)
     /******  RISC-V specific Interrupt Numbers *********************************************************/
     WWDG_IRQn = 16,          /* Window WatchDog Interrupt                            */
     PVD_IRQn = 17,           /* PVD through EXTI Line detection Interrupt            */
@@ -233,6 +262,24 @@ typedef enum IRQn
     TIM1_TRG_COM_IRQn = 36,  /* TIM1 Trigger and Commutation Interrupt               */
     TIM1_CC_IRQn = 37,       /* TIM1 Capture Compare Interrupt                       */
     TIM2_IRQn = 38,          /* TIM2 global Interrupt                                */
+#if defined(CH32X03x)
+	USART2_IRQn = 39,          /* UART2 Interrupt                          */
+	EXTI15_8_IRQn = 40,        /* External Line[8:15] Interrupt            */
+	EXTI25_16_IRQn = 41,       /* External Line[25:16] Interrupt           */
+	USART3_IRQn = 42,          /* UART2 Interrupt                          */
+	USART4_IRQn = 43,          /* UART2 Interrupt                          */
+	DMA1_Channel8_IRQn = 44,   /* DMA1 Channel 8 global Interrupt          */
+	USBFS_IRQn = 45,           /* USB Full-Speed Interrupt                 */
+	USBFS_WakeUp_IRQn = 46,    /* USB Full-Speed Wake-Up Interrupt         */
+	PIOC_IRQn = 47,            /* Programmable IO Controller Interrupt     */
+	OPA_IRQn = 48,             /* Op Amp Interrupt                         */
+	USBPD_IRQn = 49,           /* USB Power Delivery Interrupt             */
+	USBPD_WKUP_IRQn = 50,      /* USB Power Delivery Wake-Up Interrupt     */
+	TIM2_CC_IRQn = 51,         /* Timer 2 Compare Global Interrupt         */
+	TIM2_TRG_IRQn = 52,        /* Timer 2 Trigger Global Interrupt         */
+	TIM2_BRK_IRQn = 53,        /* Timer 2 Brk Global Interrupt             */
+	TIM3_IRQn = 54,            /* Timer 3 Global Interrupt                 */
+#endif
 #elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 	/******  RISC-V specific Interrupt Numbers *********************************************************/
 	WWDG_IRQn = 16,            /* Window WatchDog Interrupt                            */
@@ -411,7 +458,7 @@ typedef enum IRQn
 
 #define HardFault_IRQn    EXC_IRQn
 
-#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x)
 	#define ADC1_2_IRQn       ADC_IRQn
 #endif
 
@@ -446,6 +493,11 @@ typedef struct
     __IO uint32_t RDATAR;
 #if defined(CH32V20x)
     __IO uint32_t DLYR;
+#elif defined(CH32X03x)
+    __IO uint32_t CTLR3;
+    __IO uint32_t WDTR1;
+    __IO uint32_t WDTR2;
+    __IO uint32_t WDTR3;
 #endif
 } ADC_TypeDef;
 
@@ -855,6 +907,10 @@ typedef struct
 	__IO uint32_t BSHR;
 	__IO uint32_t BCR;
 	__IO uint32_t LCKR;
+#ifdef CH32X03x
+	__IO uint32_t CFGXR;
+	__IO uint32_t BSXR;
+#endif
 } GPIO_TypeDef;
 
 #define DYN_GPIO_READ(gpio, field) ((GPIO_##field##_t) { .__FULL = gpio->field })
@@ -868,6 +924,14 @@ typedef struct
     uint32_t RESERVED0;
     __IO uint32_t PCFR1;
     __IO uint32_t EXTICR;
+#elif defined(CH32X03x)
+    uint32_t RESERVED0;
+    __IO uint32_t PCFR1;
+    __IO uint32_t EXTICR1;
+    __IO uint32_t EXTICR2;
+    uint32_t RESERVED1;
+    uint32_t RESERVED2;
+    __IO uint32_t CTLR;
 #elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 	__IO uint32_t ECR;
 	__IO uint32_t PCFR1;
@@ -1073,6 +1137,19 @@ typedef struct
     uint16_t      RESERVED14;
     __IO uint16_t DMAADR;
     uint16_t      RESERVED15;
+#elif defined( CH32X03x )
+    __IO uint32_t CH1CVR;
+    __IO uint32_t CH2CVR;
+    __IO uint32_t CH3CVR;
+    __IO uint32_t CH4CVR;
+    __IO uint16_t BDTR;
+    uint16_t      RESERVED13;
+    __IO uint16_t DMACFGR;
+    uint16_t      RESERVED14;
+    __IO uint16_t DMAADR;
+    uint16_t      RESERVED15;
+    __IO uint16_t SPEC;
+    uint16_t      RESERVED16;
 #elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 	__IO uint16_t CH1CVR;
 	uint16_t      RESERVED13;
@@ -1372,6 +1449,7 @@ typedef struct  __attribute__((packed))
     __IO uint8_t  RESERVED52;
     __IO uint16_t HOST_SPLIT_DATA;
 } USBHSH_TypeDef;
+
 #endif	// #if defined(CH32V30x)
 
 /* USBFS Registers */
@@ -1608,6 +1686,309 @@ typedef struct
 
 #endif // #if defined(CH32V20x) || defined(CH32V30x)
 
+
+#if defined(CH32X03x)
+/* Touch Sensor, Mirrors Analog to Digital Converter */
+typedef struct
+{
+	__IO uint32_t RESERVED0[3];
+	__IO uint32_t CHARGE1;
+	__IO uint32_t CHARGE2;
+	__IO uint32_t RESERVED1[10];
+	__IO uint32_t CHGOFFSET;
+	__IO uint32_t RESERVED2[3];
+	__IO uint32_t DR_ACT_DCG;
+} TKEY_TypeDef;
+
+/* Op amp / comparator */
+typedef struct
+{
+	__IO uint16_t CFGR1;
+	__IO uint16_t CFGR2;
+	__IO uint32_t CTLR1;
+	__IO uint32_t CTLR2;
+	__IO uint32_t OPA_KEY;
+	__IO uint32_t CMP_KEY;
+	__IO uint32_t POLL_KEY;
+} OPACMP_TypeDef;
+
+/* USB Full Speed Device Mode */
+typedef struct
+{
+	__IO uint8_t BASE_CTRL; //XXX (spelling)
+	__IO uint8_t UDEV_CTRL; // or host ctlr
+	__IO uint8_t INT_EN;
+	__IO uint8_t DEV_ADDR;
+	__IO uint8_t RESERVED0;
+	__IO uint8_t MIS_ST;
+	__IO uint8_t INT_FG;
+	__IO uint8_t INT_ST;
+	__IO uint16_t RX_LEN;
+	__IO uint16_t RESERVED1;
+	__IO uint8_t UEP4_1_MOD;
+	__IO uint8_t UEP2_3_MOD; // Also HOST_EP_MOD
+	__IO uint8_t UEP567_MOD;
+	__IO uint8_t RESERVED2;
+
+	__IO uint32_t UEP0_DMA;
+	__IO uint32_t UEP1_DMA;
+	__IO uint32_t UEP2_DMA; // Also HOST_RX_DMA
+	__IO uint32_t UEP3_DMA; // Also HOST_TX_DMA
+
+	//__IO uint32_t UEP0_CTRL;
+	__IO uint16_t UEP0_TX_LEN;
+	__IO uint16_t UEP0_CTRL_H;
+
+	//__IO uint32_t UEP1_CTRL;
+	__IO uint16_t UEP1_TX_LEN;
+	__IO uint16_t UEP1_CTRL_H; // Also HOST_SETUP
+
+	//__IO uint32_t UEP2_CTRL;
+	__IO uint16_t UEP2_TX_LEN; // Also HOST_PID
+	__IO uint16_t UEP2_CTRL_H; // Also HOST_RX_CTL
+
+	//__IO uint32_t UEP3_CTRL;
+	__IO uint16_t UEP3_TX_LEN; // Also HOST_TX_LEN
+	__IO uint16_t UEP3_CTRL_H; // Also HOST_TX_CTL
+
+	//__IO uint32_t UEP4_CTRL;
+	__IO uint16_t UEP4_TX_LEN;
+	__IO uint16_t UEP4_CTRL_H;
+
+	__IO uint32_t RESERVED3[8];
+
+	__IO uint32_t UEP5_DMA;
+	__IO uint32_t UEP6_DMA;
+	__IO uint32_t UEP7_DMA;
+
+	__IO uint32_t RESERVED4;
+
+	//__IO uint32_t UEP5_CTRL;
+	__IO uint16_t UEP5_TX_LEN;
+	__IO uint16_t UEP5_CTRL_H;
+
+	//__IO uint32_t UEP6_CTRL;
+	__IO uint16_t UEP6_TX_LEN;
+	__IO uint16_t UEP6_CTRL_H;
+
+	//__IO uint32_t UEP7_CTRL;
+	__IO uint16_t UEP7_TX_LEN;
+	__IO uint16_t UEP7_CTRL_H;
+
+	__IO uint32_t UEPX_MOD;
+} USBFS_TypeDef;
+
+
+
+#define USB_PHY_V33 (1<<6)
+#define USB_IOEN (1<<7)
+
+
+#define USBFSD_UEP_MOD_BASE         0x4002340C
+#define USBFSD_UEP_DMA_BASE         0x40023410
+#define USBFSD_UEP_LEN_BASE         0x40023420
+#define USBFSD_UEP_CTL_BASE         0x40023422
+#define USBFSD_UEP_RX_EN            0x08
+#define USBFSD_UEP_TX_EN            0x04
+#define USBFSD_UEP_BUF_MOD          0x01
+#define USBFSD_UEP_MOD( N )         (*((volatile uint8_t *)( USBFSD_UEP_MOD_BASE + N )))
+#define USBFSD_UEP_TX_CTRL( N )     (*((volatile uint8_t *)( USBFSD_UEP_CTL_BASE + N * 0x04 )))
+#define USBFSD_UEP_RX_CTRL( N )     (*((volatile uint8_t *)( USBFSD_UEP_CTL_BASE + N * 0x04 )))
+#define USBFSD_UEP_DMA( N )         (*((volatile uint32_t *)( USBFSD_UEP_DMA_BASE + N * 0x04 )))
+#define USBFSD_UEP_BUF( N )         ((uint8_t *)(*((volatile uint32_t *)( USBFSD_UEP_DMA_BASE + N * 0x04 ))) + 0x20000000)
+#define USBFSD_UEP_TLEN( N )        (*((volatile uint16_t *)( USBFSD_UEP_LEN_BASE + N * 0x04 )))
+
+/* R8_UEPn_TX_CTRL */
+#define USBFS_UEP_T_AUTO_TOG        (1<<4)      // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle
+#define USBFS_UEP_T_TOG             (1<<6)      // prepared data toggle flag of USB endpoint X transmittal (IN): 0=DATA0, 1=DATA1
+#define USBFS_UEP_T_RES_MASK        (3<<0)      // bit mask of handshake response type for USB endpoint X transmittal (IN)
+#define USBFS_UEP_T_RES_ACK         (0<<1)
+#define USBFS_UEP_T_RES_NONE        (1<<0)
+#define USBFS_UEP_T_RES_NAK         (1<<1)
+#define USBFS_UEP_T_RES_STALL       (3<<0)
+// bUEP_T_RES1 & bUEP_T_RES0: handshake response type for USB endpoint X transmittal (IN)
+//   00: DATA0 or DATA1 then expecting ACK (ready)
+//   01: DATA0 or DATA1 then expecting no response, time out from host, for non-zero endpoint isochronous transactions
+//   10: NAK (busy)
+//   11: STALL (error)
+// host aux setup
+
+/* R8_UEPn_RX_CTRL, n=0-7 */
+#define USBFS_UEP_R_AUTO_TOG        (1<<4)      // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle
+#define USBFS_UEP_R_TOG             (1<<7)      // expected data toggle flag of USB endpoint X receiving (OUT): 0=DATA0, 1=DATA1
+#define USBFS_UEP_R_RES_MASK        (3<<2)      // bit mask of handshake response type for USB endpoint X receiving (OUT)
+#define USBFS_UEP_R_RES_ACK         (0<<3)
+#define USBFS_UEP_R_RES_NONE        (1<<2)
+#define USBFS_UEP_R_RES_NAK         (1<<3)
+#define USBFS_UEP_R_RES_STALL       (3<<2)
+
+
+#define EP1_T_EN					(1<<6)
+#define EP2_T_EN					(1<<2)
+#define EP3_T_EN					(1<<6)
+#define EP4_T_EN					(1<<2)
+#define EP1_R_EN					(1<<7)
+#define EP2_R_EN					(1<<3)
+#define EP3_R_EN					(1<<7)
+#define EP4_R_EN					(1<<3)
+
+
+/* R8_USB_CTRL */
+#define USBFS_UC_HOST_MODE          0x80
+#define USBFS_UC_LOW_SPEED          0x40
+#define USBFS_UC_DEV_PU_EN          0x20
+#define USBFS_UC_SYS_CTRL_MASK      0x30
+#define USBFS_UC_SYS_CTRL0          0x00
+#define USBFS_UC_SYS_CTRL1          0x10
+#define USBFS_UC_SYS_CTRL2          0x20
+#define USBFS_UC_SYS_CTRL3          0x30
+#define USBFS_UC_INT_BUSY           0x08
+#define USBFS_UC_RESET_SIE          0x04
+#define USBFS_UC_CLR_ALL            0x02
+#define USBFS_UC_DMA_EN             0x01
+
+/* R8_USB_INT_EN */
+#define USBFS_UIE_DEV_SOF           0x80
+#define USBFS_UIE_DEV_NAK           0x40
+#define USBFS_UIE_FIFO_OV           0x10
+#define USBFS_UIE_HST_SOF           0x08
+#define USBFS_UIE_SUSPEND           0x04
+#define USBFS_UIE_TRANSFER          0x02
+#define USBFS_UIE_DETECT            0x01
+#define USBFS_UIE_BUS_RST           0x01
+
+/* R8_USB_DEV_AD */
+#define USBFS_UDA_GP_BIT            0x80
+#define USBFS_USB_ADDR_MASK         0x7F
+
+/* R8_USB_MIS_ST */
+#define USBFS_UMS_SOF_PRES          0x80
+#define USBFS_UMS_SOF_ACT           0x40
+#define USBFS_UMS_SIE_FREE          0x20
+#define USBFS_UMS_R_FIFO_RDY        0x10
+#define USBFS_UMS_BUS_RESET         0x08
+#define USBFS_UMS_SUSPEND           0x04
+#define USBFS_UMS_DM_LEVEL          0x02
+#define USBFS_UMS_DEV_ATTACH        0x01
+
+
+
+
+#define USBFS_UDA_GP_BIT            0x80
+#define USBFS_USB_ADDR_MASK         0x7F
+
+#define DEF_USBD_UEP0_SIZE		   64	 /* usb hs/fs device end-point 0 size */
+#define UEP_SIZE 64
+
+#define DEF_UEP_IN                  0x80
+#define DEF_UEP_OUT                 0x00
+#define DEF_UEP_BUSY                0x01
+#define DEF_UEP_FREE                0x00
+
+#define DEF_UEP0 0
+#define DEF_UEP1 1
+#define DEF_UEP2 2
+#define DEF_UEP3 3
+#define DEF_UEP4 4
+#define DEF_UEP5 5
+#define DEF_UEP6 6
+#define DEF_UEP7 7
+#define UNUM_EP 8
+
+
+
+/* USB Host Mode */
+
+typedef struct
+{
+	__IO uint8_t RESERVED0;
+	__IO uint8_t HOST_CTRL;
+	__IO uint8_t RESERVED1;
+	__IO uint8_t RESERVED2;
+	__IO uint8_t RESERVED3;
+	__IO uint8_t RESERVED4;
+	__IO uint8_t RESERVED5;
+	__IO uint8_t RESERVED6;
+	__IO uint16_t RESERVED7;
+	__IO uint16_t RESERVED8;
+	__IO uint8_t RESERVED9;
+	__IO uint8_t HOST_EP_MOD;
+	__IO uint8_t RESERVED10;
+	__IO uint8_t RESERVED11;
+
+	__IO uint32_t RESERVED12;
+	__IO uint32_t RESERVED13;
+	__IO uint32_t HOST_RX_DMA;
+	__IO uint32_t HOST_TX_DMA;
+
+	__IO uint16_t RESERVED14;
+	__IO uint16_t RESERVED15;
+	__IO uint16_t RESERVED16;
+
+	__IO uint16_t HOST_SETUP;
+	__IO uint16_t HOST_EP_PID;
+	__IO uint16_t HOST_RX_CTL;
+	__IO uint16_t HOST_TX_LEN;
+	__IO uint16_t HOST_TX_CTL;
+
+	__IO uint16_t RESERVED20;
+	__IO uint16_t RESERVED21;
+
+	__IO uint32_t RESERVED22[8];
+
+	__IO uint32_t RESERVED23;
+	__IO uint32_t RESERVED24;
+	__IO uint32_t RESERVED25;
+
+	__IO uint32_t RESERVED26;
+
+	__IO uint16_t RESERVED27;
+	__IO uint16_t RESERVED28;
+
+	__IO uint16_t RESERVED29;
+	__IO uint16_t RESERVED30;
+
+	__IO uint16_t RESERVED31;
+	__IO uint16_t RESERVED32;
+
+	__IO uint32_t RESERVED33;
+} USBDH_TypeDef;
+
+
+/* USB Power Delivery */
+typedef struct
+{
+	__IO uint32_t CONFIG;
+	__IO uint32_t CONTROL;
+	__IO uint32_t STATUS;
+	__IO uint32_t PORT;
+	__IO uint32_t DMA;
+} USBPD_TypeDef;
+
+
+/* USB Power Delivery */
+typedef struct
+{
+	__IO uint16_t CONFIG;
+	__IO uint16_t BCM_CLK_CNT;
+
+	__IO uint8_t CONTROL;
+	__IO uint8_t TX_SEL;
+	__IO uint16_t BMC_TX_SZ;
+
+	__IO uint8_t DATA_BUF;
+	__IO uint8_t STATUS;
+	__IO uint16_t BMC_BYTE_CNT;
+
+	__IO uint16_t PORT_CC1;
+	__IO uint16_t PORT_CC2;
+
+	__IO uint32_t USBPD_DMA;
+} USBPD_DETAILED_TypeDef;
+
+#endif // #if defined(CH32X03x)
+
+
 #endif
 
 /* Peripheral memory map */
@@ -1636,10 +2017,12 @@ typedef struct
 #define AHBPERIPH_BASE                          (PERIPH_BASE + 0x20000)
 
 #define TIM2_BASE                               (APB1PERIPH_BASE + 0x0000)
-#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x)
 #define TIM3_BASE                               (APB1PERIPH_BASE + 0x0400)
+#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 #define TIM4_BASE                               (APB1PERIPH_BASE + 0x0800)
 #define TIM5_BASE                               (APB1PERIPH_BASE + 0x0C00)
+#endif // CH32V10x, CH32V20x, CH32V30x
 #if defined(CH32V30x)	// CH32V30x
 #define TIM6_BASE             					(APB1PERIPH_BASE + 0x1000)
 #define TIM7_BASE             					(APB1PERIPH_BASE + 0x1400)
@@ -1654,8 +2037,10 @@ typedef struct
 #define TIM13_BASE                              (APB1PERIPH_BASE + 0x1C00)
 #define TIM14_BASE                              (APB1PERIPH_BASE + 0x2000)
 #endif					// CH32V10x
+#if defined(CH32V003) || defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 #define RTC_BASE                                (APB1PERIPH_BASE + 0x2800)
 #endif
+#endif
 #define WWDG_BASE                               (APB1PERIPH_BASE + 0x2C00)
 #define IWDG_BASE                               (APB1PERIPH_BASE + 0x3000)
 #if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
@@ -1663,6 +2048,8 @@ typedef struct
 #if defined(CH32V10x) || defined(CH32V30x)
 #define SPI3_BASE             					(APB1PERIPH_BASE + 0x3C00)
 #endif // defined(CH32V30x) || defined(CH32V10x)
+#endif
+#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x)
 #define USART2_BASE                             (APB1PERIPH_BASE + 0x4400)
 #define USART3_BASE                             (APB1PERIPH_BASE + 0x4800)
 #define UART4_BASE                              (APB1PERIPH_BASE + 0x4C00)
@@ -1691,7 +2078,7 @@ typedef struct
 #define AFIO_BASE                               (APB2PERIPH_BASE + 0x0000)
 #define EXTI_BASE                               (APB2PERIPH_BASE + 0x0400)
 #define GPIOA_BASE                              (APB2PERIPH_BASE + 0x0800)
-#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x)
 #define GPIOB_BASE                              (APB2PERIPH_BASE + 0x0C00)
 #endif
 #define GPIOC_BASE                              (APB2PERIPH_BASE + 0x1000)
@@ -1755,12 +2142,19 @@ typedef struct
 #define RCC_BASE                                (AHBPERIPH_BASE + 0x1000)
 
 #define FLASH_R_BASE                            (AHBPERIPH_BASE + 0x2000) /* Flash registers base address */
+
 #if defined(CH32V20x)
 #define CRC_BASE                                (AHBPERIPH_BASE + 0x3000)
 #define OPA_BASE                                (AHBPERIPH_BASE + 0x3804)
 #define ETH10M_BASE                             (AHBPERIPH_BASE + 0x8000)
 
 #define USBFS_BASE                              ((uint32_t)0x50000000)
+#elif defined(CH32X03x)
+
+#define OPA_BASE                                (AHBPERIPH_BASE + 0x6000)
+#define USBFS_BASE                              (AHBPERIPH_BASE + 0x3400)
+#define USBPD_BASE                              (AHBPERIPH_BASE + 0x7000)
+
 #elif defined(CH32V30x)
 #define CRC_BASE              					(AHBPERIPH_BASE + 0x3000)
 #define USBHS_BASE            					(AHBPERIPH_BASE + 0x3400)
@@ -1802,6 +2196,123 @@ typedef struct
 #endif
 #endif
 
+
+
+// AFIO CTLR Bits
+#define PB6_FILT_EN    (1<<27)
+#define PB5_FILT_EN    (1<<26)
+#define PA4_FILT_EN    (1<<25)
+#define PA3_FILT_EN    (1<<24)
+#define UDM_BC_CMPO	   (1<<19)
+#define UDP_BC_CMPO    (1<<17)
+#define UDM_BC_VSRC    (1<<17)
+#define UDP_BC_VSRC    (1<<16)
+#define USBPD_IN_HVT   (1<<9)
+#define USBPD_PHY_V33  (1<<8)
+#define USB_IOEN       (1<<7)
+#define USB_PHY_V33    (1<<6)
+#define UDP_PUE_00     (0b00<<2)
+#define UDP_PUE_01     (0b01<<2)
+#define UDP_PUE_10     (0b10<<2)
+#define UDP_PUE_11     (0b11<<2)
+#define UDM_PUE_00     (0b00<<0)
+#define UDM_PUE_01     (0b01<<0)
+#define UDM_PUE_10     (0b10<<0)
+#define UDM_PUE_11     (0b11<<0)
+#define UDP_PUE_MASK                0x0000000C
+#define UDP_PUE_DISABLE             0x00000000
+#define UDP_PUE_35UA                0x00000004
+#define UDP_PUE_10K                 0x00000008
+#define UDP_PUE_1K5                 0x0000000C
+#define UDM_PUE_MASK                0x00000003
+#define UDM_PUE_DISABLE             0x00000000
+#define UDM_PUE_35UA                0x00000001
+#define UDM_PUE_10K                 0x00000002
+#define UDM_PUE_1K5                 0x00000003
+
+
+// USB PD Bits
+#define IE_TX_END      (1<<15)
+#define IE_RX_RESET    (1<<14)
+#define IE_RX_ACT      (1<<13)
+#define IE_RX_BYTE     (1<<12)
+#define IE_RX_BIT      (1<<11)
+#define IE_PD_IO       (1<<10)
+#define WAKE_POLAR     (1<<5)
+#define PD_RST_EN      (1<<4)
+#define PD_DMA_EN      (1<<3)
+#define CC_SEL         (1<<2)
+#define PD_ALL_CLR     (1<<1)
+#define PD_FILT_EN     (1<<0)
+#define BMC_CLK_CNT_MASK  (0xff)
+
+//R8_CONTROL
+#define BMC_BYTE_HI    (1<<7)
+#define TX_BIT_BACK    (1<<6)
+#define DATA_FLAG      (1<<5)
+#define RX_STATE_MASK  (0x7<<2)
+#define RX_STATE_0     (1<<2)
+#define RX_STATE_1     (1<<3)
+#define RX_STATE_2     (1<<4)
+#define BMC_START      (1<<1)
+#define PD_TX_EN       (1<<0)
+
+#define TX_SEL4_MASK   (3<<6)
+#define TX_SEL4_0      (1<<6)
+#define TX_SEL4_1      (1<<7)
+
+#define TX_SEL3_MASK   (3<<4)
+#define TX_SEL3_0      (1<<4)
+#define TX_SEL3_1      (1<<5)
+
+#define TX_SEL2_MASK   (3<<2)
+#define TX_SEL2_0      (1<<2)
+#define TX_SEL2_1      (1<<3)
+
+#define TX_SEL1        (1<<0)
+
+#define BMC_TX_SZ_MASK (0x1ff)
+
+//R8_STATUS
+#define IF_TX_END      (1<<7)
+#define IF_RX_RESET    (1<<6)
+#define IF_RX_ACT      (1<<5)
+#define IF_RX_BYTE     (1<<4)
+#define IF_RX_BIT      (1<<3)
+#define IFBUF_ERR      (1<<2)
+#define BMC_AUX_MASK   (3<<0)
+#define BMC_AUX_1      (1<<1)
+#define BMC_AUX_0      (1<<0)
+
+// PORT CC1
+#define CC1_CE_MASK    (7<<5)
+#define CC1_CE_0       (1<<5)
+#define CC1_CE_1       (2<<5)
+#define CC1_CE_2       (4<<5)
+
+#define CC1_LVE        (1<<4)
+#define CC1_PU_MASK    (3<<2)
+#define CC1_PU_DISABLE (0<<2)
+#define CC1_PU_330uA   (1<<2)
+#define CC1_PU_180uA   (2<<2)
+#define CC1_PU_80uA    (3<<2)
+#define PA_CC1_AI      (1<<0)
+
+#define CC2_CE_MASK    (7<<5)
+#define CC2_CE_0       (1<<5)
+#define CC2_CE_1       (2<<5)
+#define CC2_CE_2       (4<<5)
+
+#define CC2_LVE        (1<<4)
+#define CC2_PU_MASK    (3<<2)
+#define CC2_PU_DISABLE (0<<2)
+#define CC2_PU_330uA   (1<<2)
+#define CC2_PU_180uA   (2<<2)
+#define CC2_PU_80uA    (3<<2)
+#define PA_CC2_AI      (1<<0)
+
+
+
 /* Peripheral declaration */
 #define TIM2                                    ((TIM_TypeDef *)TIM2_BASE)
 #if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
@@ -1859,7 +2370,7 @@ typedef struct
 #define AFIO                                    ((AFIO_TypeDef *)AFIO_BASE)
 #define EXTI                                    ((EXTI_TypeDef *)EXTI_BASE)
 #define GPIOA                                   ((GPIO_TypeDef *)GPIOA_BASE)
-#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x)
 #define GPIOB                                   ((GPIO_TypeDef *)GPIOB_BASE)
 #endif
 #define GPIOC                                   ((GPIO_TypeDef *)GPIOC_BASE)
@@ -1872,6 +2383,15 @@ typedef struct
 #define ADC1                                    ((ADC_TypeDef *)ADC1_BASE)
 #if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 #define ADC2                                    ((ADC_TypeDef *)ADC2_BASE)
+#endif
+#ifdef CH32X03x
+#define TKey                                    ((TKEY_TypeDef *)ADC1_BASE)
+#define OPA										((OPACMP_TypeDef *)OPA_BASE)
+#define USBFS									((USBFS_TypeDef *)USBFS_BASE)
+#define USBPDWORD								((USBPD_TypeDef *)USBPD_BASE)
+#define USBPD									((USBPD_DETAILED_TypeDef *)USBPD_BASE)
+#define USBDH									((USBDH_TypeDef *)USBFS_BASE)
+
 #endif
 #if defined(CH32V20x) || defined(CH32V30x)
 #define TKey1                                   ((ADC_TypeDef *)ADC1_BASE)
@@ -1904,7 +2424,7 @@ typedef struct
 #define DMA1_Channel5                           ((DMA_Channel_TypeDef *)DMA1_Channel5_BASE)
 #define DMA1_Channel6                           ((DMA_Channel_TypeDef *)DMA1_Channel6_BASE)
 #define DMA1_Channel7                           ((DMA_Channel_TypeDef *)DMA1_Channel7_BASE)
-#if defined(CH32V20x)
+#if defined(CH32V20x) || defined(CH32X03x)
 #define DMA1_Channel8                           ((DMA_Channel_TypeDef *)DMA1_Channel8_BASE)
 #endif
 #if defined(CH32V10x) || defined(CH32V30x)
@@ -4277,7 +4797,7 @@ typedef struct
 /*                      FLASH and Option Bytes Registers                      */
 /******************************************************************************/
 
-#if defined(CH32V003) || defined(CH32V10x)
+#if defined(CH32V003) || defined(CH32V10x) || defined(CH32X03x)
 /*******************  Bit definition for FLASH_ACTLR register  ******************/
 #define FLASH_ACTLR_LATENCY                     ((uint8_t)0x03) /* LATENCY[2:0] bits (Latency) */
 #define FLASH_ACTLR_LATENCY_0                   ((uint8_t)0x00) /* Bit 0 */
@@ -5080,7 +5600,7 @@ typedef struct
 #define RCC_HPRE_2                              ((uint32_t)0x00000040) /* Bit 2 */
 #define RCC_HPRE_3                              ((uint32_t)0x00000080) /* Bit 3 */
 
-#if defined(CH32V003)
+#if defined(CH32V003) || defined(CH32X03x)
 #define RCC_HPRE_DIV1                           ((uint32_t)0x00000000) /* SYSCLK not divided */
 #define RCC_HPRE_DIV2                           ((uint32_t)0x00000010) /* SYSCLK divided by 2 */
 #define RCC_HPRE_DIV3                           ((uint32_t)0x00000020) /* SYSCLK divided by 3 */
@@ -5270,6 +5790,8 @@ typedef struct
 #define RCC_FLITFEN                             ((uint16_t)0x0010) /* FLITF clock enable */
 #define RCC_CRCEN                               ((uint16_t)0x0040) /* CRC clock enable */
 #define RCC_USBHD                               ((uint16_t)0x1000)
+#define RCC_USBFS                               ((uint16_t)0x1000)
+#define RCC_USBPD                               ((uint16_t)0x20000)
 
 /******************  Bit definition for RCC_APB2PCENR register  *****************/
 #define RCC_AFIOEN                              ((uint32_t)0x00000001) /* Alternate Function I/O clock enable */
@@ -9131,7 +9653,9 @@ typedef enum
 #define GPIO_PortSourceGPIOA           ((uint8_t)0x00)
 #define GPIO_PortSourceGPIOC           ((uint8_t)0x02)
 #define GPIO_PortSourceGPIOD           ((uint8_t)0x03)
-#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32X03x)
+#define GPIO_PortSourceGPIOB            ((uint8_t)0x01)
+#elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 #define GPIO_PortSourceGPIOB            ((uint8_t)0x01)
 #define GPIO_PortSourceGPIOD            ((uint8_t)0x03)
 #define GPIO_PortSourceGPIOE            ((uint8_t)0x04)
@@ -9148,7 +9672,7 @@ typedef enum
 #define GPIO_PinSource5                ((uint8_t)0x05)
 #define GPIO_PinSource6                ((uint8_t)0x06)
 #define GPIO_PinSource7                ((uint8_t)0x07)
-#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x)
 #define GPIO_PinSource8                 ((uint8_t)0x08)
 #define GPIO_PinSource9                 ((uint8_t)0x09)
 #define GPIO_PinSource10                ((uint8_t)0x0A)
@@ -9883,7 +10407,7 @@ typedef struct
 
 #endif
 
-#ifdef CH32V003
+#if defined(CH32V003) || defined(CH32X03x)
 
 /* AHB_peripheral */
 #define RCC_AHBPeriph_DMA1               ((uint32_t)0x00000001)
@@ -9892,6 +10416,9 @@ typedef struct
 /* APB2_peripheral */
 #define RCC_APB2Periph_AFIO              ((uint32_t)0x00000001)
 #define RCC_APB2Periph_GPIOA             ((uint32_t)0x00000004)
+#ifdef CH32X03x
+#define RCC_APB2Periph_GPIOB             ((uint32_t)0x00000008)
+#endif
 #define RCC_APB2Periph_GPIOC             ((uint32_t)0x00000010)
 #define RCC_APB2Periph_GPIOD             ((uint32_t)0x00000020)
 #define RCC_APB2Periph_ADC1              ((uint32_t)0x00000200)
@@ -9905,6 +10432,17 @@ typedef struct
 #define RCC_APB1Periph_I2C1              ((uint32_t)0x00200000)
 #define RCC_APB1Periph_PWR               ((uint32_t)0x10000000)
 
+#if defined(CH32X03x)
+
+/* APB2_peripheral */
+#define RCC_APB2Periph_GPIOB             ((uint32_t)0x00000008)
+
+#define RCC_APB1Periph_USART2            ((uint32_t)0x00020000)
+#define RCC_APB1Periph_USART3            ((uint32_t)0x00040000)
+#define RCC_APB1Periph_UART4             ((uint32_t)0x00080000)
+
+#endif
+
 #elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 
 /* AHB_peripheral */
@@ -10814,7 +11352,8 @@ typedef struct
 #define USART_FLAG_FE                        ((uint16_t)0x0002)
 #define USART_FLAG_PE                        ((uint16_t)0x0001)
 
-#if defined(CH32V10x)
+// While not truly CH32X035, we can re-use some of the USB register defs.
+#if defined(CH32V10x) | defined(CH32X03x)
 /* ch32v10x_usb.h ------------------------------------------------------------*/
 
 #ifndef NULL
@@ -11144,190 +11683,6 @@ typedef volatile unsigned long *PUINT32V;
 #define R16_UEP7_T_LEN       (*((PUINT16V)(0x4002344c))) // endpoint 7 transmittal length(16-bits for ch32v10x)
 #define R8_UEP7_CTRL         (*((PUINT8V)(0x4002344e)))  // endpoint 7 control
 
-/* USB constant and structure define */
-
-/* USB PID */
-#ifndef USB_PID_SETUP
-  #define USB_PID_NULL     0x00  /* reserved PID */
-  #define USB_PID_SOF      0x05
-  #define USB_PID_SETUP    0x0D
-  #define USB_PID_IN       0x09
-  #define USB_PID_OUT      0x01
-  #define USB_PID_ACK      0x02
-  #define USB_PID_NAK      0x0A
-  #define USB_PID_STALL    0x0E
-  #define USB_PID_DATA0    0x03
-  #define USB_PID_DATA1    0x0B
-  #define USB_PID_PRE      0x0C
-#endif
-
-/* USB standard device request code */
-#ifndef USB_GET_DESCRIPTOR
-  #define USB_GET_STATUS           0x00
-  #define USB_CLEAR_FEATURE        0x01
-  #define USB_SET_FEATURE          0x03
-  #define USB_SET_ADDRESS          0x05
-  #define USB_GET_DESCRIPTOR       0x06
-  #define USB_SET_DESCRIPTOR       0x07
-  #define USB_GET_CONFIGURATION    0x08
-  #define USB_SET_CONFIGURATION    0x09
-  #define USB_GET_INTERFACE        0x0A
-  #define USB_SET_INTERFACE        0x0B
-  #define USB_SYNCH_FRAME          0x0C
-#endif
-
-/* USB hub class request code */
-#ifndef HUB_GET_DESCRIPTOR
-  #define HUB_GET_STATUS        0x00
-  #define HUB_CLEAR_FEATURE     0x01
-  #define HUB_GET_STATE         0x02
-  #define HUB_SET_FEATURE       0x03
-  #define HUB_GET_DESCRIPTOR    0x06
-  #define HUB_SET_DESCRIPTOR    0x07
-#endif
-
-/* USB HID class request code */
-#ifndef HID_GET_REPORT
-  #define HID_GET_REPORT      0x01
-  #define HID_GET_IDLE        0x02
-  #define HID_GET_PROTOCOL    0x03
-  #define HID_SET_REPORT      0x09
-  #define HID_SET_IDLE        0x0A
-  #define HID_SET_PROTOCOL    0x0B
-#endif
-
-/* USB CDC Class request code */
-#ifndef CDC_GET_LINE_CODING
-#define CDC_GET_LINE_CODING   0X21      /* This request allows the host to find out the currently configured line coding */
-#define CDC_SET_LINE_CODING   0x20      /* Configures DTE rate, stop-bits, parity, and number-of-character */
-#define CDC_SET_LINE_CTLSTE   0X22      /* This request generates RS-232/V.24 style control signals */
-#define CDC_SEND_BREAK        0X23      /* Sends special carrier modulation used to specify RS-232 style break */
-#endif
-
-/* Bit define for USB request type */
-#ifndef USB_REQ_TYP_MASK
-  #define USB_REQ_TYP_IN          0x80  /* control IN, device to host */
-  #define USB_REQ_TYP_OUT         0x00  /* control OUT, host to device */
-  #define USB_REQ_TYP_READ        0x80  /* control read, device to host */
-  #define USB_REQ_TYP_WRITE       0x00  /* control write, host to device */
-  #define USB_REQ_TYP_MASK        0x60  /* bit mask of request type */
-  #define USB_REQ_TYP_STANDARD    0x00
-  #define USB_REQ_TYP_CLASS       0x20
-  #define USB_REQ_TYP_VENDOR      0x40
-  #define USB_REQ_TYP_RESERVED    0x60
-  #define USB_REQ_RECIP_MASK      0x1F  /* bit mask of request recipient */
-  #define USB_REQ_RECIP_DEVICE    0x00
-  #define USB_REQ_RECIP_INTERF    0x01
-  #define USB_REQ_RECIP_ENDP      0x02
-  #define USB_REQ_RECIP_OTHER     0x03
-  #define USB_REQ_FEAT_REMOTE_WAKEUP  0x01
-  #define USB_REQ_FEAT_ENDP_HALT      0x00
-#endif
-
-/* USB request type for hub class request */
-#ifndef HUB_GET_HUB_DESCRIPTOR
-  #define HUB_CLEAR_HUB_FEATURE     0x20
-  #define HUB_CLEAR_PORT_FEATURE    0x23
-  #define HUB_GET_BUS_STATE         0xA3
-  #define HUB_GET_HUB_DESCRIPTOR    0xA0
-  #define HUB_GET_HUB_STATUS        0xA0
-  #define HUB_GET_PORT_STATUS       0xA3
-  #define HUB_SET_HUB_DESCRIPTOR    0x20
-  #define HUB_SET_HUB_FEATURE       0x20
-  #define HUB_SET_PORT_FEATURE      0x23
-#endif
-
-/* Hub class feature selectors */
-#ifndef HUB_PORT_RESET
-  #define HUB_C_HUB_LOCAL_POWER      0
-  #define HUB_C_HUB_OVER_CURRENT     1
-  #define HUB_PORT_CONNECTION        0
-  #define HUB_PORT_ENABLE            1
-  #define HUB_PORT_SUSPEND           2
-  #define HUB_PORT_OVER_CURRENT      3
-  #define HUB_PORT_RESET             4
-  #define HUB_PORT_POWER             8
-  #define HUB_PORT_LOW_SPEED         9
-  #define HUB_C_PORT_CONNECTION      16
-  #define HUB_C_PORT_ENABLE          17
-  #define HUB_C_PORT_SUSPEND         18
-  #define HUB_C_PORT_OVER_CURRENT    19
-  #define HUB_C_PORT_RESET           20
-#endif
-
-/* USB descriptor type */
-#ifndef USB_DESCR_TYP_DEVICE
-  #define USB_DESCR_TYP_DEVICE     0x01
-  #define USB_DESCR_TYP_CONFIG     0x02
-  #define USB_DESCR_TYP_STRING     0x03
-  #define USB_DESCR_TYP_INTERF     0x04
-  #define USB_DESCR_TYP_ENDP       0x05
-  #define USB_DESCR_TYP_QUALIF     0x06
-  #define USB_DESCR_TYP_SPEED      0x07
-  #define USB_DESCR_TYP_OTG        0x09
-  #define USB_DESCR_TYP_HID        0x21
-  #define USB_DESCR_TYP_REPORT     0x22
-  #define USB_DESCR_TYP_PHYSIC     0x23
-  #define USB_DESCR_TYP_CS_INTF    0x24
-  #define USB_DESCR_TYP_CS_ENDP    0x25
-  #define USB_DESCR_TYP_HUB        0x29
-#endif
-
-/* USB device class */
-#ifndef USB_DEV_CLASS_HUB
-  #define USB_DEV_CLASS_RESERVED     0x00
-  #define USB_DEV_CLASS_AUDIO        0x01
-  #define USB_DEV_CLASS_COMMUNIC     0x02
-  #define USB_DEV_CLASS_HID          0x03
-  #define USB_DEV_CLASS_MONITOR      0x04
-  #define USB_DEV_CLASS_PHYSIC_IF    0x05
-  #define USB_DEV_CLASS_IMAGE        0x06
-  #define USB_DEV_CLASS_PRINTER      0x07
-  #define USB_DEV_CLASS_STORAGE      0x08
-  #define USB_DEV_CLASS_HUB          0x09
-  #define USB_DEV_CLASS_VEN_SPEC     0xFF
-#endif
-
-/* USB endpoint type and attributes */
-#ifndef USB_ENDP_TYPE_MASK
-  #define USB_ENDP_DIR_MASK      0x80
-  #define USB_ENDP_ADDR_MASK     0x0F
-  #define USB_ENDP_TYPE_MASK     0x03
-  #define USB_ENDP_TYPE_CTRL     0x00
-  #define USB_ENDP_TYPE_ISOCH    0x01
-  #define USB_ENDP_TYPE_BULK     0x02
-  #define USB_ENDP_TYPE_INTER    0x03
-#endif
-
-#ifndef USB_DEVICE_ADDR
-  #define USB_DEVICE_ADDR    0x02
-#endif
-#ifndef DEFAULT_ENDP0_SIZE
-  #define DEFAULT_ENDP0_SIZE 8  /* default maximum packet size for endpoint 0 */
-#endif
-#ifndef MAX_PACKET_SIZE
-  #define MAX_PACKET_SIZE    64  /* maximum packet size */
-#endif
-#ifndef USB_BO_CBW_SIZE
-  #define USB_BO_CBW_SIZE    0x1F
-  #define USB_BO_CSW_SIZE    0x0D
-#endif
-#ifndef USB_BO_CBW_SIG0
-  #define USB_BO_CBW_SIG0    0x55
-  #define USB_BO_CBW_SIG1    0x53
-  #define USB_BO_CBW_SIG2    0x42
-  #define USB_BO_CBW_SIG3    0x43
-  #define USB_BO_CSW_SIG0    0x55
-  #define USB_BO_CSW_SIG1    0x53
-  #define USB_BO_CSW_SIG2    0x42
-  #define USB_BO_CSW_SIG3    0x53
-#endif
-
-#define DEF_STRING_DESC_LANG 0x00
-#define DEF_STRING_DESC_MANU 0x01
-#define DEF_STRING_DESC_PROD 0x02
-#define DEF_STRING_DESC_SERN 0x03
-
 /* ch32v10x_usb_host.h -----------------------------------------------------------*/
 
 #define ERR_SUCCESS            0x00
@@ -11481,7 +11836,7 @@ typedef struct{
     __IO uint32_t SCTLR;
 }PFIC_Type;
 
-#ifdef CH32V003
+#if defined (CH32V003) 
 
 /* memory mapped structure for SysTick */
 typedef struct
@@ -11505,6 +11860,19 @@ typedef struct
 	__IO uint64_t CMP;
 } SysTick_Type;
 
+#elif defined(CH32X03x)
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+  __IO uint32_t CTLR;
+  __IO uint32_t SR;
+  __IO uint32_t CNTL;
+  __IO uint32_t CNTH;
+  __IO uint32_t CMPL;
+  __IO uint32_t CMPH;
+} SysTick_Type;
+
 #elif defined(CH32V10x)
 
 /* memory mapped structure for SysTick */
@@ -12310,8 +12678,7 @@ extern "C" {
 #define PD6 54
 #define PD7 55
 
-
-#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined( CH32X03x )
 #define PA0 0
 #define PA3 3
 #define PA4 4
@@ -12342,6 +12709,14 @@ extern "C" {
 #define PB13 29
 #define PB14 30
 #define PB15 31
+#define PC8 40
+#define PC9 41
+#define PC10 42
+#define PC11 43
+#define PC12 44
+#define PC13 45
+#define PC14 46
+#define PC15 47
 #endif
 
 
@@ -12350,7 +12725,10 @@ extern "C" {
 
 #define funDigitalWrite( pin, value ) { GpioOf( pin )->BSHR = 1<<((!(value))*16 + ((pin) & 0xf)); }
 
-#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#if defined(CH32X03x)
+#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC ); }
+#define funPinMode( pin, mode ) { *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); }
+#elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
 #define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD ); }
 #define funPinMode( pin, mode ) { *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); }
 #define funGpioInitB() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB ); }
diff --git a/ch32v003fun/ch32v003fun.ld b/ch32v003fun/ch32v003fun.ld
index 4ad76b48f49b06639c546fd7f8a262f18691f88e..10096e476c78dd20d4506cef1d492e630374b20a 100644
--- a/ch32v003fun/ch32v003fun.ld
+++ b/ch32v003fun/ch32v003fun.ld
@@ -38,6 +38,13 @@ MEMORY
 	#else
 		#error "Unknown MCU package"
 	#endif
+#elif TARGET_MCU_LD == 4
+	#if MCU_PACKAGE == 1
+		FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 62K
+		RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
+	#else
+		#error "Unknown MCU package"
+	#endif
 #else
 	#error "Unknown MCU target"
 #endif
diff --git a/ch32v003fun/ch32v003fun.mk b/ch32v003fun/ch32v003fun.mk
index 664a861b6898157d381a8e6e8f251f307e23a1c6..ee6519e8733ae54364f4a781b3d5fbc03b8d637c 100644
--- a/ch32v003fun/ch32v003fun.mk
+++ b/ch32v003fun/ch32v003fun.mk
@@ -56,6 +56,30 @@ else
 		endif
 
 		TARGET_MCU_LD:=1
+	else ifeq ($(findstring CH32X03,$(TARGET_MCU)),CH32X03) # CH32X033, X035
+		TARGET_MCU_PACKAGE?=CH32X035F8U6
+		CFLAGS_ARCH+=-march=rv32imac \
+			-mabi=ilp32 \
+			-DCH32X03x=1
+
+		# MCU Flash/RAM split
+		ifeq ($(findstring F8, $(TARGET_MCU_PACKAGE)), F8)
+			MCU_PACKAGE:=1
+		else ifeq ($(findstring R8, $(TARGET_MCU_PACKAGE)), R8)
+			MCU_PACKAGE:=1
+		else ifeq ($(findstring K8, $(TARGET_MCU_PACKAGE)), K8)
+			MCU_PACKAGE:=1
+		else ifeq ($(findstring C8, $(TARGET_MCU_PACKAGE)), C8)
+			MCU_PACKAGE:=1
+		else ifeq ($(findstring G8, $(TARGET_MCU_PACKAGE)), G8)
+			MCU_PACKAGE:=1
+		else ifeq ($(findstring G6, $(TARGET_MCU_PACKAGE)), G6)
+			MCU_PACKAGE:=1
+		else ifeq ($(findstring F7, $(TARGET_MCU_PACKAGE)), F7)
+			MCU_PACKAGE:=1
+		endif
+
+		TARGET_MCU_LD:=4		
 	else ifeq ($(findstring CH32V20,$(TARGET_MCU)),CH32V20) # CH32V203
 		TARGET_MCU_PACKAGE?=CH32V203F8P6
 		CFLAGS_ARCH+=	-march=rv32imac \
@@ -63,7 +87,14 @@ else
 			-DCH32V20x=1
 
 		# MCU Flash/RAM split
-		ifeq ($(findstring F8, $(TARGET_MCU_PACKAGE)), F8)
+
+
+		# Package
+		ifeq ($(findstring 203RB, $(TARGET_MCU_PACKAGE)), 203RB)
+			CFLAGS+=-DCH32V20x_D8
+		else ifeq ($(findstring 208, $(TARGET_MCU_PACKAGE)), 208)
+			CFLAGS+=-DCH32V20x_D8W
+		else ifeq ($(findstring F8, $(TARGET_MCU_PACKAGE)), F8)
 			MCU_PACKAGE:=1
 		else ifeq ($(findstring G8, $(TARGET_MCU_PACKAGE)), G8)
 			MCU_PACKAGE:=1
@@ -87,13 +118,6 @@ else
 			MCU_PACKAGE:=3
 		else ifeq ($(findstring WB, $(TARGET_MCU_PACKAGE)), WB)
 			MCU_PACKAGE:=3
-		endif
-
-		# Package
-		ifeq ($(findstring 203RB, $(TARGET_MCU_PACKAGE)), 203RB)
-			CFLAGS+=-DCH32V20x_D8
-		else ifeq ($(findstring 208, $(TARGET_MCU_PACKAGE)), 208)
-			CFLAGS+=-DCH32V20x_D8W
 		else
 			CFLAGS+=-DCH32V20x_D6
 		endif
@@ -200,6 +224,6 @@ cv_flash : $(TARGET).bin
 	$(FLASH_COMMAND)
 
 cv_clean :
-	rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).lst $(TARGET).map $(TARGET).hex || true
+	rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).lst $(TARGET).map $(TARGET).hex $(GENERATED_LD_FILE) || true
 
 build : $(TARGET).bin
diff --git a/examples/blink/blink.bin b/examples/blink/blink.bin
index c4ae5e0476d01db8c9adede2e3af224eff6ec4c4..23614187313a10492587efeb0091524a302f18e1 100755
Binary files a/examples/blink/blink.bin and b/examples/blink/blink.bin differ
diff --git a/examples_v20x/blink/Makefile b/examples_v20x/blink/Makefile
index 90acba47f71e2bdda4ccbfb405b65054e889173e..80ca9c6a6e6726c66894c02992483aefdfb01964 100644
--- a/examples_v20x/blink/Makefile
+++ b/examples_v20x/blink/Makefile
@@ -1,7 +1,8 @@
 all : flash
 
 TARGET:=blink
-TARGET_MCU:=CH32V203
+TARGET_MCU:=CH32V203G6U6
+TARGET_MCU_PACKAGE:=CH32V203G6U6
 
 include ../../ch32v003fun/ch32v003fun.mk
 
diff --git a/examples_x035/blink/Makefile b/examples_x035/blink/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..0290b25c0a7904729536fe40556e02c2e308844f
--- /dev/null
+++ b/examples_x035/blink/Makefile
@@ -0,0 +1,11 @@
+all : flash
+
+TARGET:=blink
+TARGET_MCU:=CH32X035
+
+include ../../ch32v003fun/ch32v003fun.mk
+
+flash : cv_flash
+clean : cv_clean
+
+
diff --git a/examples_x035/blink/blink.c b/examples_x035/blink/blink.c
new file mode 100644
index 0000000000000000000000000000000000000000..0a57d204f214c309a70d747b2fc02c612e4f5198
--- /dev/null
+++ b/examples_x035/blink/blink.c
@@ -0,0 +1,22 @@
+#include "ch32v003fun.h"
+#include <stdio.h>
+
+int main()
+{
+	SystemInit();
+
+	funGpioInitAll();
+
+	funPinMode( PA0, GPIO_CFGLR_OUT_10Mhz_PP );
+
+	while(1)
+	{
+		funDigitalWrite( PA0, FUN_HIGH );	 // Turn on GPIO
+		//Delay_Ms( 1000 );
+		funDigitalWrite( PA0, FUN_LOW );	 // Turn off GPIO
+		//Delay_Ms( 1000 );
+		funDigitalWrite( PA0, FUN_HIGH );	 // Turn on GPIO
+		asm volatile( "c.nop" );
+		funDigitalWrite( PA0, FUN_LOW );	 // Turn off GPIO
+	}
+}
diff --git a/examples_x035/blink/funconfig.h b/examples_x035/blink/funconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9342aedd278550d482a89f1d3c98c16d6ef85d6
--- /dev/null
+++ b/examples_x035/blink/funconfig.h
@@ -0,0 +1,5 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#endif
+
diff --git a/examples_x035/debugprintfdemo/Makefile b/examples_x035/debugprintfdemo/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8a29f56f4147e896e3985725b6516dce189c31f9
--- /dev/null
+++ b/examples_x035/debugprintfdemo/Makefile
@@ -0,0 +1,10 @@
+all : flash
+
+TARGET:=debugprintfdemo
+TARGET_MCU:=CH32X035
+
+include ../../ch32v003fun/ch32v003fun.mk
+
+flash : cv_flash
+clean : cv_clean
+
diff --git a/examples_x035/debugprintfdemo/debugprintfdemo.c b/examples_x035/debugprintfdemo/debugprintfdemo.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c65c329c14c6a325949c4b1a539ad9d94e782ad
--- /dev/null
+++ b/examples_x035/debugprintfdemo/debugprintfdemo.c
@@ -0,0 +1,37 @@
+/* Small example showing how to use the SWIO programming pin to 
+   do printf through the debug interface */
+
+#include "ch32v003fun.h"
+#include <stdio.h>
+
+uint32_t count;
+
+int last = 0;
+void handle_debug_input( int numbytes, uint8_t * data )
+{
+	last = data[0];
+	count += numbytes;
+}
+
+int main()
+{
+	SystemInit();
+
+	funGpioInitAll();
+
+	funPinMode( PA0, GPIO_CFGLR_OUT_10Mhz_PP );
+
+	while(1)
+	{
+		GPIOA->BSHR = 1;	 // Turn on GPIOs
+		printf( "+%lu %lu\n", count++ );
+		Delay_Ms(100);
+		int i;
+		for( i = 0; i < 10000; i++ )
+			poll_input();
+		GPIOA->BSHR = (1<<16); // Turn off GPIODs
+		printf( "-%lu[%c]\n", count++, last );
+		Delay_Ms(100);
+	}
+}
+
diff --git a/examples_x035/debugprintfdemo/funconfig.h b/examples_x035/debugprintfdemo/funconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8a70b30cc8ba3115935c2140704b1a6ab83ebd2
--- /dev/null
+++ b/examples_x035/debugprintfdemo/funconfig.h
@@ -0,0 +1,9 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+// Though this should be on by default we can extra force it on.
+#define FUNCONF_USE_DEBUGPRINTF 1
+#define FUNCONF_DEBUGPRINTF_TIMEOUT (1<<31) // Wait for a very very long time.
+
+#endif
+
diff --git a/examples_x035/sandbox/Makefile b/examples_x035/sandbox/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..2b907ec5bb86b131e57602b733e1c8770413705d
--- /dev/null
+++ b/examples_x035/sandbox/Makefile
@@ -0,0 +1,10 @@
+all : flash
+
+TARGET:=sandbox
+TARGET_MCU:=CH32X035
+
+include ../../ch32v003fun/ch32v003fun.mk
+
+flash : cv_flash
+clean : cv_clean
+
diff --git a/examples_x035/sandbox/funconfig.h b/examples_x035/sandbox/funconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8a70b30cc8ba3115935c2140704b1a6ab83ebd2
--- /dev/null
+++ b/examples_x035/sandbox/funconfig.h
@@ -0,0 +1,9 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+// Though this should be on by default we can extra force it on.
+#define FUNCONF_USE_DEBUGPRINTF 1
+#define FUNCONF_DEBUGPRINTF_TIMEOUT (1<<31) // Wait for a very very long time.
+
+#endif
+
diff --git a/examples_x035/sandbox/sandbox.c b/examples_x035/sandbox/sandbox.c
new file mode 100644
index 0000000000000000000000000000000000000000..a83ff5fe7cc08d6a1607b7099df7d88f6bbb90db
--- /dev/null
+++ b/examples_x035/sandbox/sandbox.c
@@ -0,0 +1,29 @@
+/* Small example showing how to use the SWIO programming pin to 
+   do printf through the debug interface */
+
+#include "ch32v003fun.h"
+#include <stdio.h>
+
+uint32_t count;
+
+int last = 0;
+
+void handle_debug_input( int numbytes, uint8_t * data )
+{
+	last = data[0];
+	count += numbytes;
+}
+
+int main()
+{
+	SystemInit();
+
+	funGpioInitAll();
+
+	funPinMode( PA0, GPIO_CFGLR_OUT_10Mhz_PP );
+
+	printf( "Hello\n" );
+
+	while(1);
+}
+
diff --git a/examples_x035/usbdevice/99-x035demo.rules b/examples_x035/usbdevice/99-x035demo.rules
new file mode 100644
index 0000000000000000000000000000000000000000..39e7ce9169f0bb75f04d6cb1663e1c7cd0eab47d
--- /dev/null
+++ b/examples_x035/usbdevice/99-x035demo.rules
@@ -0,0 +1,12 @@
+KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="d035"
+KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="d035", GROUP="plugdev", MODE="0660"
+#KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0660", GROUP="plugdev"
+
+
+#, TAG+="uaccess", TAG+="udev-acl"
+# KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="d035", GROUP="plugdev", MODE="0664"
+#KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="d035", MODE="0666"
+#KERNEL=="hiddev*", SUBSYSTEM=="usbmisc", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="d035", GROUP="plugdev", MODE="0660", TAG+="uaccess", TAG+="udev-acl"
+#SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="d035", MODE="0660", GROUP="plugdev", TAG+="uaccess", TAG+="udev-acl"
+#KERNEL=="hidraw*", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="d035", MODE="0660", GROUP="plugdev", TAG+="uaccess", TAG+="udev-acl"
+
diff --git a/examples_x035/usbdevice/Makefile b/examples_x035/usbdevice/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..7ef3dfcee2d95df4d0143f3817f0124d1cc5691f
--- /dev/null
+++ b/examples_x035/usbdevice/Makefile
@@ -0,0 +1,16 @@
+all : flash
+
+TARGET:=usbdevice
+TARGET_MCU:=CH32X035
+ADDITIONAL_C_FILES:=
+include ../../ch32v003fun/ch32v003fun.mk
+
+install_udev_rules : 
+	sudo cp 99-x035demo.rules /etc/udev/rules.d/
+	sudo udevadm control --reload
+	sudo udevadm trigger
+
+
+flash : cv_flash
+clean : cv_clean
+
diff --git a/examples_x035/usbdevice/fsusb.c b/examples_x035/usbdevice/fsusb.c
new file mode 100644
index 0000000000000000000000000000000000000000..c67dfb4a745f0384557f45e670c9be18692f1a1b
--- /dev/null
+++ b/examples_x035/usbdevice/fsusb.c
@@ -0,0 +1,671 @@
+#include "fsusb.h"
+#include "ch32v003fun.h"
+#include <string.h>
+
+uint32_t USBDEBUG0, USBDEBUG1, USBDEBUG2;
+
+
+#define UEP_CTRL_H(n) (((uint16_t*)&USBFS->UEP0_CTRL_H)[n*2])
+
+struct _USBState FSUSBCTX;
+
+// based on https://github.com/openwch/ch32x035/tree/main/EVT/EXAM/USB/USBFS/DEVICE/CompositeKM/User
+
+// Mask for the combined USBFSD->INT_FG + USBFSD->INT_ST
+#define CRB_U_IS_NAK     (1<<7)
+#define CTOG_MATCH_SYNC  (1<<6)
+#define CRB_U_SIE_FREE   (1<<5)
+#define CRB_UIF_FIFO_OV  (1<<4)
+#define CRB_UIF_HST_SOF  (1<<3)
+#define CRB_UIF_SUSPEND  (1<<2)
+#define CRB_UIF_TRANSFER (1<<1)
+#define CRB_UIF_BUS_RST  (1<<0)
+#define CSETUP_ACT	     (1<<15)
+#define CRB_UIS_TOG_OK   (1<<14)
+#define CMASK_UIS_TOKEN  (3<<12)
+#define CMASK_UIS_ENDP   (0xf<<8)
+
+#define CUIS_TOKEN_OUT	 0x0
+#define CUIS_TOKEN_SOF   0x1
+#define CUIS_TOKEN_IN    0x2
+#define CUIS_TOKEN_SETUP 0x3
+
+static inline void DMA7FastCopy( uint8_t * dest, const uint8_t * src, int len )
+{
+	while( DMA1_Channel7->CNTR );
+	DMA1_Channel7->CFGR = 0;
+	DMA1_Channel7->MADDR = (uintptr_t)src;
+	DMA1_Channel7->PADDR = (uintptr_t)dest;
+	DMA1_Channel7->CNTR  = (len+3)/4;
+	DMA1_Channel7->CFGR  =
+		DMA_M2M_Enable | 
+		DMA_DIR_PeripheralDST |
+		DMA_Priority_Low |
+		DMA_MemoryDataSize_Word |
+		DMA_PeripheralDataSize_Word |
+		DMA_MemoryInc_Enable |
+		DMA_PeripheralInc_Enable |
+		DMA_Mode_Normal | DMA_CFGR1_EN;
+#if !( FUSB_CURSED_TURBO_DMA == 1 )
+	// Somehow, it seems to work (unsafely) without this.
+	// Really, though, it's probably fine.
+	while( DMA1_Channel7->CNTR );
+#endif
+}
+
+static inline void DMA7FastCopyComplete() { while( DMA1_Channel7->CNTR ); }
+
+#if FUSB_USE_HPE
+void USBFS_IRQHandler() __attribute__((section(".text.vector_handler")))  __attribute((naked));
+#else
+void USBFS_IRQHandler() __attribute__((section(".text.vector_handler")))  __attribute((interrupt));
+#endif
+
+void USBFS_InternalFinishSetup();
+
+void USBFS_IRQHandler()
+{
+#if FUSB_IO_PROFILE
+	GPIOA->BSHR = 1;
+#endif
+
+	// Based on https://github.com/openwch/ch32x035/blob/main/EVT/EXAM/USB/USBFS/DEVICE/CompositeKM/User/ch32x035_usbfs_device.c
+	// Combined FG + ST flag.
+	uint16_t intfgst = *(uint16_t*)(&USBFS->INT_FG);
+	int len = 0;
+	struct _USBState * ctx = &FSUSBCTX;
+	uint8_t * ctrl0buff = CTRL0BUFF;
+
+	// TODO: Check if needs to be do-while to re-check.
+	if( intfgst & CRB_UIF_TRANSFER )
+	{
+		int token = ( intfgst & CMASK_UIS_TOKEN) >> 12;
+		int ep = ( intfgst & CMASK_UIS_ENDP ) >> 8;
+
+		switch ( token )
+		{
+		case CUIS_TOKEN_IN:
+			if( ep )
+			{
+				if( ep < FUSB_CONFIG_EPS )
+				{
+					UEP_CTRL_H(ep) = ( UEP_CTRL_H(ep) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_NAK;
+					UEP_CTRL_H(ep) ^= USBFS_UEP_T_TOG;
+					ctx->USBFS_Endp_Busy[ ep ] = 0;
+				}
+			}
+			else
+			{
+				/* end-point 0 data in interrupt */
+				if( ctx->USBFS_SetupReqLen == 0 )
+				{
+					USBFS->UEP0_CTRL_H = USBFS_UEP_R_TOG | USBFS_UEP_R_RES_ACK;
+				}
+
+				if( ctx->pCtrlPayloadPtr )
+				{
+					// Shortcut mechanism, for descriptors or if the user wants it.
+					len = ctx->USBFS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBFS_SetupReqLen;
+					DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); // FYI -> Would need to do this if using DMA
+					ctx->USBFS_SetupReqLen -= len;
+					if( ctx->USBFS_SetupReqLen > 0 )
+						ctx->pCtrlPayloadPtr += len;
+					else
+						ctx->pCtrlPayloadPtr = 0;
+
+					USBFS->UEP0_TX_LEN = len;
+					USBFS->UEP0_CTRL_H ^= USBFS_UEP_T_TOG;
+				}
+				else if ( ( ctx->USBFS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
+				{
+
+#if FUSB_HID_USER_REPORTS
+					len = ctx->USBFS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBFS_SetupReqLen;
+					if( len && FSUSBCTX.USBFS_SetupReqCode == HID_GET_REPORT )
+					{
+						len = HandleHidUserReportDataIn( ctx, ctrl0buff, len );
+						USBFS->UEP0_TX_LEN = len;
+						USBFS->UEP0_CTRL_H ^= USBFS_UEP_T_TOG;
+						ctx->USBFS_SetupReqLen -= len;
+						ctx->pCtrlPayloadPtr += len;
+					}	
+#endif
+				}
+				else
+				{
+					switch( FSUSBCTX.USBFS_SetupReqCode )
+					{
+						case USB_GET_DESCRIPTOR:
+							break;
+
+						case USB_SET_ADDRESS:
+							USBFS->DEV_ADDR = ( USBFS->DEV_ADDR & USBFS_UDA_GP_BIT ) | ctx->USBFS_DevAddr;
+							break;
+
+						default:
+							break;
+					}
+				}
+			}
+			break;
+
+		/* data-out stage processing */
+		case CUIS_TOKEN_OUT:
+			switch( ep )
+			{
+				/* end-point 0 data out interrupt */
+				case DEF_UEP0:
+					if( intfgst & CRB_UIS_TOG_OK )
+					{
+#if FUSB_HID_USER_REPORTS
+						int len = USBFS->RX_LEN;
+						uint8_t * cptr = ctx->pCtrlPayloadPtr;
+						if( !cptr )
+						{
+							HandleHidUserReportDataOut( ctx, ctrl0buff, len );
+						}
+						else
+						{
+							int remain = ctx->USBFS_SetupReqLen - len;
+							if( remain < 0 )
+							{
+								len += remain;
+								remain = 0;
+							}
+							DMA7FastCopy( cptr, ctrl0buff, len );
+							ctx->USBFS_SetupReqLen = remain;
+							if( remain > 0 )
+								ctx->pCtrlPayloadPtr = cptr + len;
+							else
+								ctx->pCtrlPayloadPtr = 0;
+						}
+#endif
+
+						if( ctx->USBFS_SetupReqLen == 0 )
+						{
+							USBFS->UEP0_TX_LEN = 0;
+							USBFS->UEP0_CTRL_H = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_ACK;
+#if FUSB_HID_USER_REPORTS
+							DMA7FastCopyComplete();
+							HandleHidUserReportOutComplete( ctx );
+#endif
+						}
+						else
+						{
+							USBFS->UEP0_CTRL_H ^= USBFS_UEP_R_TOG;
+						}
+					}
+					break;
+
+				default:
+					break;
+			}
+			break;
+
+		/* Setup stage processing */
+		case CUIS_TOKEN_SETUP:
+
+			USBFS->UEP0_CTRL_H = USBFS_UEP_T_TOG|USBFS_UEP_T_RES_NAK|USBFS_UEP_R_TOG|USBFS_UEP_R_RES_NAK;
+
+			/* Store All Setup Values */
+			int USBFS_SetupReqType = FSUSBCTX.USBFS_SetupReqType  = pUSBFS_SetupReqPak->bmRequestType;
+			int USBFS_SetupReqCode = FSUSBCTX.USBFS_SetupReqCode  = pUSBFS_SetupReqPak->bRequest;
+			int USBFS_SetupReqLen = FSUSBCTX.USBFS_SetupReqLen    = pUSBFS_SetupReqPak->wLength;
+			int USBFS_SetupReqIndex = pUSBFS_SetupReqPak->wIndex;
+			int USBFS_IndexValue = FSUSBCTX.USBFS_IndexValue = ( pUSBFS_SetupReqPak->wIndex << 16 ) | pUSBFS_SetupReqPak->wValue;
+			len = 0;
+
+			if( ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
+			{
+#if FUSB_HID_INTERFACES > 0 
+				if( ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_CLASS )
+				{
+					/* Class Request */
+					switch( USBFS_SetupReqCode )
+					{
+						case HID_SET_REPORT:
+#if FUSB_HID_USER_REPORTS
+							len = HandleHidUserSetReportSetup( ctx, pUSBFS_SetupReqPak );
+							if( len < 0 ) goto sendstall;
+							ctx->USBFS_SetupReqLen = len;
+							USBFS->UEP0_TX_LEN = 0;
+							USBFS->UEP0_CTRL_H = USBFS_UEP_R_TOG | USBFS_UEP_R_RES_ACK | USBFS_UEP_T_TOG;
+							goto replycomplete;
+						case HID_GET_REPORT:
+							len = HandleHidUserGetReportSetup( ctx, pUSBFS_SetupReqPak );
+							len = 255;
+							if( len < 0 ) goto sendstall;
+							ctx->USBFS_SetupReqLen = len;
+							len = len >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : len;
+							if( !ctx->pCtrlPayloadPtr )
+							{
+								len = HandleHidUserReportDataIn( ctx, ctrl0buff, len );
+							}
+							else
+							{
+								DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len );
+								ctx->pCtrlPayloadPtr += len;
+							}
+							USBFS->UEP0_TX_LEN = len;
+							USBFS->UEP0_CTRL_H = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_ACK;
+							ctx->USBFS_SetupReqLen -= len;
+							goto replycomplete;
+#endif
+							break;
+
+
+						case HID_SET_IDLE:
+							if( USBFS_SetupReqIndex < FUSB_HID_INTERFACES )
+								FSUSBCTX.USBFS_HidIdle[ USBFS_SetupReqIndex ] = (uint8_t)( USBFS_IndexValue >> 8 );
+							break;
+						case HID_SET_PROTOCOL:
+							if ( USBFS_SetupReqIndex < FUSB_HID_INTERFACES )
+								FSUSBCTX.USBFS_HidProtocol[USBFS_SetupReqIndex] = (uint8_t)USBFS_IndexValue;
+							break;
+
+						case HID_GET_IDLE:
+							if( USBFS_SetupReqIndex < FUSB_HID_INTERFACES )
+							{
+								ctrl0buff[0] = FSUSBCTX.USBFS_HidIdle[ USBFS_SetupReqIndex ];
+								len = 1;
+							}
+							break;
+
+						case HID_GET_PROTOCOL:
+							if( USBFS_SetupReqIndex < FUSB_HID_INTERFACES )
+							{
+								ctrl0buff[0] = FSUSBCTX.USBFS_HidProtocol[ USBFS_SetupReqIndex ];
+								len = 1;
+							}
+							break;
+
+						default:
+							goto sendstall;
+							break;
+					}
+				}
+#else
+				;
+#endif
+			}
+			else
+			{
+				/* usb standard request processing */
+				switch( USBFS_SetupReqCode )
+				{
+					/* get device/configuration/string/report/... descriptors */
+					case USB_GET_DESCRIPTOR:
+					{
+						const struct descriptor_list_struct * e = descriptor_list;
+						const struct descriptor_list_struct * e_end = e + DESCRIPTOR_LIST_ENTRIES;
+						for( ; e != e_end; e++ )
+						{
+							if( e->lIndexValue == USBFS_IndexValue )
+							{
+								ctx->pCtrlPayloadPtr = (uint8_t*)e->addr;
+								len = e->length;
+								break;
+							}
+						}
+						if( e == e_end )
+						{
+							goto sendstall;
+						}
+
+
+						/* Copy Descriptors to Endp0 DMA buffer */
+						int totalLen = USBFS_SetupReqLen;
+						if( totalLen > len )
+						{
+							totalLen = len;
+						}
+						len = ( totalLen >= DEF_USBD_UEP0_SIZE ) ? DEF_USBD_UEP0_SIZE : totalLen;
+						DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); //memcpy( CTRL0BUFF, ctx->pCtrlPayloadPtr, len );
+						ctx->USBFS_SetupReqLen = totalLen - len;
+						ctx->pCtrlPayloadPtr += len;
+						USBFS->UEP0_TX_LEN = len;
+						USBFS->UEP0_CTRL_H = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_ACK;
+						goto replycomplete;
+					}
+
+					/* Set usb address */
+					case USB_SET_ADDRESS:
+						ctx->USBFS_DevAddr = (uint8_t)( ctx->USBFS_IndexValue & 0xFF );
+						break;
+
+					/* Get usb configuration now set */
+					case USB_GET_CONFIGURATION:
+						ctrl0buff[0] = ctx->USBFS_DevConfig;
+						if( ctx->USBFS_SetupReqLen > 1 )
+							ctx->USBFS_SetupReqLen = 1;
+						break;
+
+					/* Set usb configuration to use */
+					case USB_SET_CONFIGURATION:
+						ctx->USBFS_DevConfig = (uint8_t)( ctx->USBFS_IndexValue & 0xFF );
+						ctx->USBFS_DevEnumStatus = 0x01;
+						break;
+
+					/* Clear or disable one usb feature */
+					case USB_CLEAR_FEATURE:
+#if FUSB_SUPPORTS_SLEEP
+						if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
+						{
+							/* clear one device feature */
+							if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP )
+							{
+								/* clear usb sleep status, device not prepare to sleep */
+								ctx->USBFS_DevSleepStatus &= ~0x01;
+							}
+							else
+							{
+								goto sendstall;
+							}
+						}
+						else
+#endif
+						if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
+						{
+							if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
+							{
+								/* Clear End-point Feature */
+								if( ( USBFS_SetupReqIndex & DEF_UEP_IN ) && ep < FUSB_CONFIG_EPS ) 
+								{
+									UEP_CTRL_H(ep) = USBFS_UEP_T_RES_NAK;
+								}
+								else
+								{
+									goto sendstall;
+								}
+							}
+							else
+							{
+								goto sendstall;
+							}
+						}
+						else
+						{
+							goto sendstall;
+						}
+						break;
+
+					/* set or enable one usb feature */
+					case USB_SET_FEATURE:
+						if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
+						{
+#if FUSB_SUPPORTS_SLEEP
+							/* Set Device Feature */
+							if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP )
+							{
+								/* Set Wake-up flag, device prepare to sleep */
+								USBFS_DevSleepStatus |= 0x01;
+							}
+							else
+#endif
+							{
+								goto sendstall;
+							}
+						}
+						else if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
+						{
+							/* Set Endpoint Feature */
+							if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
+							{
+								if( ( USBFS_SetupReqIndex & DEF_UEP_IN ) && ep < FUSB_CONFIG_EPS )
+									UEP_CTRL_H(ep) = ( UEP_CTRL_H(ep) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_STALL;
+							}
+							else
+								goto sendstall;
+						}
+						else
+							goto sendstall;
+						break;
+
+					/* This request allows the host to select another setting for the specified interface  */
+					case USB_GET_INTERFACE:
+						ctrl0buff[0] = 0x00;
+						if( USBFS_SetupReqLen > 1 ) USBFS_SetupReqLen = 1;
+						break;
+
+					case USB_SET_INTERFACE:
+						break;
+
+					/* host get status of specified device/interface/end-points */
+					case USB_GET_STATUS:
+						ctrl0buff[0] = 0x00;
+						ctrl0buff[1] = 0x00;
+						if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
+						{
+#if FUSB_SUPPORTS_SLEEP
+							ctrl0buff[0] = (ctx->USBFS_DevSleepStatus & 0x01)<<1;
+#else
+							ctrl0buff[0] = 0x00;
+#endif
+						}
+						else if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
+						{
+							if( ( USBFS_SetupReqIndex & DEF_UEP_IN ) && ep < FUSB_CONFIG_EPS )
+								ctrl0buff[0] = ( UEP_CTRL_H(ep) & USBFS_UEP_T_RES_MASK ) == USBFS_UEP_T_RES_STALL;
+							else
+								goto sendstall;
+						}
+						else
+							goto sendstall;
+						if( USBFS_SetupReqLen > 2 )
+							USBFS_SetupReqLen = 2;
+						break;
+
+					default:
+						goto sendstall;
+						break;
+				}
+			}
+
+
+			{
+				/* end-point 0 data Tx/Rx */
+				if( USBFS_SetupReqType & DEF_UEP_IN )
+				{
+					len = ( USBFS_SetupReqLen > DEF_USBD_UEP0_SIZE )? DEF_USBD_UEP0_SIZE : USBFS_SetupReqLen;
+					USBFS_SetupReqLen -= len;
+					USBFS->UEP0_TX_LEN = len;
+					USBFS->UEP0_CTRL_H = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_ACK;
+				}
+				else
+				{
+					if( USBFS_SetupReqLen == 0 )
+					{
+						USBFS->UEP0_TX_LEN = 0;
+						USBFS->UEP0_CTRL_H = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_ACK;
+					}
+					else
+					{
+						USBFS->UEP0_CTRL_H = USBFS_UEP_R_TOG | USBFS_UEP_R_RES_ACK;
+					}
+				}
+			}
+			break;
+
+			// This might look a little weird, for error handling but it saves a nontrivial amount of storage, and simplifies
+			// control flow to hard-abort here.
+		sendstall:
+			// if one request not support, return stall.  Stall means permanent error.
+			USBFS->UEP0_CTRL_H = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL|USBFS_UEP_R_TOG | USBFS_UEP_R_RES_STALL;
+		replycomplete:
+			break;
+
+		/* Sof pack processing */
+		case CUIS_TOKEN_SOF:
+			break;
+
+		default :
+			break;
+		}
+
+
+	}
+	else if( intfgst & CRB_UIF_BUS_RST )
+	{
+		/* usb reset interrupt processing */
+		ctx->USBFS_DevConfig = 0;
+		ctx->USBFS_DevAddr = 0;
+		ctx->USBFS_DevSleepStatus = 0;
+		ctx->USBFS_DevEnumStatus = 0;
+
+		USBFS->DEV_ADDR = 0;
+		USBFS_InternalFinishSetup( );
+	}
+	else if( intfgst & CRB_UIF_SUSPEND )
+	{
+		/* usb suspend interrupt processing */
+		if( USBFS->MIS_ST & USBFS_UMS_SUSPEND )
+		{
+			ctx->USBFS_DevSleepStatus |= 0x02;
+			if( ctx->USBFS_DevSleepStatus == 0x03 )
+			{
+				/* Handling usb sleep here */
+				//TODO: MCU_Sleep_Wakeup_Operate( );
+			}
+		}
+		else
+		{
+			ctx->USBFS_DevSleepStatus &= ~0x02;
+		}
+	}
+
+	// Handle any other interrupts and just clear them out.
+	*(uint16_t*)(&USBFS->INT_FG) = intfgst;
+
+#if FUSB_IO_PROFILE
+	GPIOA->BSHR = 1<<16;
+#endif
+
+#if FUSB_USE_HPE
+	asm volatile( "mret" );
+#endif
+}
+
+void USBFS_InternalFinishSetup()
+{
+#if FUSB_CONFIG_EPS > 4
+    USBFS->UEP4_1_MOD = RB_UEP1_TX_EN | RB_UEP4_TX_EN;
+#elif FUSB_CONFIG_EPS > 1
+    USBFS->UEP4_1_MOD = RB_UEP1_TX_EN | RB_UEP4_TX_EN;
+#endif
+
+#if FUSB_CONFIG_EPS > 3
+    USBFS->UEP2_3_MOD = RB_UEP2_TX_EN | RB_UEP3_TX_EN;
+#elif FUSB_CONFIG_EPS > 2
+    USBFS->UEP2_3_MOD = RB_UEP2_TX_EN;
+#endif
+
+	USBFS->UEP567_MOD = 0;
+
+	// This is really cursed.  Somehow it doesn't explode.
+	// But, normally the USB wants a separate buffer here.
+
+#if FUSB_CONFIG_EPS > 4
+	USBFS->UEP4_DMA = (uintptr_t)FSUSBCTX.ENDPOINTS[4];
+#endif
+#if FUSB_CONFIG_EPS > 3
+	USBFS->UEP3_DMA = (uintptr_t)FSUSBCTX.ENDPOINTS[3];
+#endif
+#if FUSB_CONFIG_EPS > 2
+	USBFS->UEP2_DMA = (uintptr_t)FSUSBCTX.ENDPOINTS[2];
+#endif
+#if FUSB_CONFIG_EPS > 1
+	USBFS->UEP1_DMA = (uintptr_t)FSUSBCTX.ENDPOINTS[1];
+#endif
+#if FUSB_CONFIG_EPS > 0
+	USBFS->UEP0_DMA = (uintptr_t)FSUSBCTX.ENDPOINTS[0];
+#else
+#error You must have at least EP0!
+#endif
+
+	UEP_CTRL_H(0) = USBFS_UEP_R_RES_ACK | USBFS_UEP_T_RES_NAK;
+	int i;
+	for( i = 1; i < FUSB_CONFIG_EPS; i++ )
+		UEP_CTRL_H(i) = USBFS_UEP_T_RES_NAK;
+                                                                    
+    for(uint8_t i=0; i< sizeof(FSUSBCTX.USBFS_Endp_Busy)/sizeof(FSUSBCTX.USBFS_Endp_Busy[0]); i++ )
+    {
+        FSUSBCTX.USBFS_Endp_Busy[ i ] = 0;
+    }
+}
+
+int FSUSBSetup()
+{
+	RCC->APB2PCENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC;
+	RCC->AHBPCENR |= RCC_USBFS | RCC_AHBPeriph_DMA1;
+
+	NVIC_EnableIRQ( USBFS_IRQn );
+
+	AFIO->CTLR |= USB_PHY_V33;
+
+	USBFS->BASE_CTRL = RB_UC_RESET_SIE | RB_UC_CLR_ALL;
+	USBFS->BASE_CTRL = 0x00;
+
+	USBFS_InternalFinishSetup();
+
+	// Enter device mode.
+	USBFS->INT_EN = RB_UIE_SUSPEND | RB_UIE_TRANSFER | RB_UIE_BUS_RST;
+	USBFS->DEV_ADDR = 0x00;
+	USBFS->BASE_CTRL = RB_UC_DEV_PU_EN | RB_UC_INT_BUSY | RB_UC_DMA_EN;
+	USBFS->INT_FG = 0xff;
+	USBFS->UDEV_CTRL = RB_UD_PD_DIS | RB_UD_PORT_EN;
+
+	// Go on-bus.
+
+	// From the TRM:
+	//
+	//   USB multiplexing IO pins enable:
+	//
+	// Enabling USB requires, in addition to USB_IOEN set to
+	// 1, the setting of: MODE=0 in GPIO configuration register
+	// GPIOC_CFGXR corresponding to PC16 and PC17 to
+	// select the input mode.
+	//
+	// for USB device, CNF=10 corresponding to PC17 to select
+	// the input mode with up and down For USB devices, PC17
+	// corresponding to CNF=10 selects the input mode with up
+	// and down pull, PC17 corresponding to bit 1 in
+	// GPIOC_OUTDR selects the up pull, and PC16
+	// corresponding to CNF=01 selects the floating input.
+
+#if FUSB_5V_OPERATION
+	// XXX This is dubious, copied from x035 - checkme (UDP_PUE_10K)
+	AFIO->CTLR = (AFIO->CTLR & ~(UDP_PUE_MASK | UDM_PUE_MASK | USB_PHY_V33)) | UDP_PUE_10K | USB_IOEN;
+#else
+	AFIO->CTLR = (AFIO->CTLR & ~(UDP_PUE_MASK | UDM_PUE_MASK )) | USB_PHY_V33 | UDP_PUE_1K5 | USB_IOEN;
+#endif
+
+	AFIO->CTLR = (AFIO->CTLR & ~(UDP_PUE_11 | UDM_PUE_11 )) | USB_PHY_V33 | USB_IOEN | UDP_PUE_11; //1.5k pullup
+
+	// Enable PC16/17 Alternate Function (USB)
+	// According to EVT, GPIO16 = GPIO_Mode_IN_FLOATING, GPIO17 = GPIO_Mode_IPU
+	GPIOC->CFGXR = 	( GPIOC->CFGXR & ~( (0xf<<(4*0)) | (0xf<<(4*1)) ) )  |
+					(((GPIO_CFGLR_IN_FLOAT)<<(4*0)) | (((GPIO_CFGLR_IN_PUPD)<<(4*1)))); // MSBs are CNF, LSBs are MODE
+	GPIOC->BSXR = 1<<1; // PC17 on.
+
+	// Go on-bus.
+	return 0;
+}
+
+// To TX, you can use USBFS_GetEPBufferIfAvailable or USBFSD_UEP_DMA( endp )
+
+static inline uint8_t * USBFS_GetEPBufferIfAvailable( int endp )
+{
+	if( FSUSBCTX.USBFS_Endp_Busy[ endp ] ) return 0;
+	return USBFSD_UEP_BUF( endp );
+}
+
+static inline void USBFS_SendEndpoint( int endp, int len )
+{
+	USBFSD_UEP_TLEN( endp ) = len;
+	USBFSD_UEP_TX_CTRL( endp ) = ( USBFSD_UEP_TX_CTRL( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK;
+	FSUSBCTX.USBFS_Endp_Busy[ endp ] = 0x01;
+}
+
+
+
+
diff --git a/examples_x035/usbdevice/fsusb.h b/examples_x035/usbdevice/fsusb.h
new file mode 100644
index 0000000000000000000000000000000000000000..8533b83673bf9a26b38db3b6760f01f10eaeeac9
--- /dev/null
+++ b/examples_x035/usbdevice/fsusb.h
@@ -0,0 +1,90 @@
+#ifndef _FSUSB_H
+#define _FSUSB_H
+
+/*	Full speed USB infrastructure for CH32X035.
+	Based off of the official USB stack, but, with significant perf and space
+	reductions.
+
+	Limitations:
+	 * Limited to EPs 0..4.
+	 * By default, functions are using dedicated buffers, not DMA (but there is no reason DMA could not be used instead)
+	 * 
+
+
+	General Notes:
+	 * They seem to be using DMA->RX but TX via non-DMA (the opposite of what they should have done)
+
+	*/
+
+
+
+#include <stdint.h>
+#include "ch32v003fun.h"
+#include "usb_defines.h"
+#include "usb_config.h"
+
+extern uint32_t USBDEBUG0, USBDEBUG1, USBDEBUG2;
+
+struct _USBState;
+
+// Provided functions:
+int FSUSBSetup();
+uint8_t USBFS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
+static inline uint8_t * USBFS_GetEPBufferIfAvailable( int endp );
+static inline void USBFS_SendEndpoint( int endp, int len );
+static inline uint8_t * USBFS_GetEPBufferIfAvailable( int endp );
+static inline void USBFS_SendEndpoint( int endp, int len );
+
+static inline void DMA7FastCopy( uint8_t * dest, const uint8_t * src, int len );
+static inline void DMA7FastCopyComplete();
+
+
+
+
+// Implement the following:
+#if FUSB_HID_USER_REPORTS
+int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
+int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
+void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
+int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
+void HandleHidUserReportOutComplete( struct _USBState * ctx );
+#endif
+
+
+
+
+struct _USBState
+{
+	// Setup Request
+	uint8_t  USBFS_SetupReqCode;
+	uint8_t  USBFS_SetupReqType;
+	uint16_t USBFS_SetupReqLen;   // Used for tracking place along send.
+	uint32_t USBFS_IndexValue;
+
+	// USB Device Status
+	uint8_t  USBFS_DevConfig;
+	uint8_t  USBFS_DevAddr;
+	uint8_t  USBFS_DevSleepStatus;
+	uint8_t  USBFS_DevEnumStatus;
+
+	uint8_t  *  pCtrlPayloadPtr;
+
+	uint8_t ENDPOINTS[FUSB_CONFIG_EPS][64];
+
+	#define CTRL0BUFF					(FSUSBCTX.ENDPOINTS[0])
+	#define pUSBFS_SetupReqPak			((tusb_control_request_t*)CTRL0BUFF)
+
+#if FUSB_HID_INTERFACES > 0
+	uint8_t USBFS_HidIdle[FUSB_HID_INTERFACES];
+	uint8_t USBFS_HidProtocol[FUSB_HID_INTERFACES];
+#endif
+	volatile uint8_t  USBFS_Endp_Busy[FUSB_CONFIG_EPS];
+};
+
+extern struct _USBState FSUSBCTX;
+
+
+#include "fsusb.c"
+
+#endif
+
diff --git a/examples_x035/usbdevice/funconfig.h b/examples_x035/usbdevice/funconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4f64d23b521f3d8238b8f23ab9c6083d15073f3
--- /dev/null
+++ b/examples_x035/usbdevice/funconfig.h
@@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+// Though this should be on by default we can extra force it on.
+#define FUNCONF_USE_DEBUGPRINTF 1
+#define FUNCONF_DEBUGPRINTF_TIMEOUT (1<<31) // Wait for a very very long time.
+#define FUNCONF_5V_OPERATION 1
+
+#endif
+
diff --git a/examples_x035/usbdevice/testtop.hidapi/Makefile b/examples_x035/usbdevice/testtop.hidapi/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a59f3cf694dc6b766180c32569e5d05130edc0ce
--- /dev/null
+++ b/examples_x035/usbdevice/testtop.hidapi/Makefile
@@ -0,0 +1,12 @@
+all : testtop
+
+# to make CI happy.
+testtop.hidapi.elf : testtop.c
+	gcc -o $@ $^ -I../../../minichlink -ludev
+
+testtop : testtop.c
+	gcc -o $@ $^ -I../../../minichlink -ludev
+
+clean :
+	rm -rf *.o *~ testtop
+
diff --git a/examples_x035/usbdevice/testtop.hidapi/os_generic.h b/examples_x035/usbdevice/testtop.hidapi/os_generic.h
new file mode 100644
index 0000000000000000000000000000000000000000..6bd7c1e882073b7a4bf0ab8fa226fee452ef771a
--- /dev/null
+++ b/examples_x035/usbdevice/testtop.hidapi/os_generic.h
@@ -0,0 +1,521 @@
+#ifndef _OS_GENERIC_H
+#define _OS_GENERIC_H
+/*
+	"osgeneric" Generic, platform independent tool for threads and time.
+		Geared around Windows and Linux. Designed for operation on MSVC,
+		TCC, GCC and clang.  Others may work.
+
+    It offers the following operations:
+
+	Delay functions:
+		void OGSleep( int is );
+		void OGUSleep( int ius );
+
+	Getting current time (may be time from program start, boot, or epoc)
+		double OGGetAbsoluteTime();
+		double OGGetFileTime( const char * file );
+
+	Thread functions
+		og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter );
+		void * OGJoinThread( og_thread_t ot );
+		void OGCancelThread( og_thread_t ot );
+
+	Mutex functions, used for protecting data structures.
+		 (recursive on platforms where available.)
+		og_mutex_t OGCreateMutex();
+		void OGLockMutex( og_mutex_t om );
+		void OGUnlockMutex( og_mutex_t om );
+		void OGDeleteMutex( og_mutex_t om );
+
+	Always a semaphore (not recursive)
+		og_sema_t OGCreateSema(); //Create a semaphore, comes locked initially.
+          NOTE: For platform compatibility, max count is 32767
+		void OGLockSema( og_sema_t os );
+		int OGGetSema( og_sema_t os );  //if <0 there was a failure.
+		void OGUnlockSema( og_sema_t os );
+		void OGDeleteSema( og_sema_t os );
+
+	TLS (Thread-Local Storage)
+		og_tls_t OGCreateTLS();
+		void OGDeleteTLS( og_tls_t tls );
+		void OGSetTLS( og_tls_t tls, void * data );
+		void * OGGetTLS( og_tls_t tls );
+
+   You can permute the operations of this file by the following means:
+    OSG_NO_IMPLEMENTATION
+	OSG_PREFIX
+	OSG_NOSTATIC
+
+   The default behavior is to do static inline.
+
+   Copyright (c) 2011-2012,2013,2016,2018,2019,2020 <>< Charles Lohr
+
+   This file may be licensed under the MIT/x11 license, NewBSD or CC0 licenses
+
+   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 this file.
+
+   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.
+
+	Date Stamp: 2019-09-05 CNL: Allow for noninstantiation and added TLS.
+	Date Stamp: 2018-03-25 CNL: Switched to header-only format.
+*/
+
+
+#if defined( OSG_NOSTATIC ) && OSG_NOSTATIC != 0
+#ifndef OSG_PREFIX
+#define OSG_PREFIX
+#endif
+#ifndef OSG_NO_IMPLEMENTATION
+#define OSG_NO_IMPLEMENTATION
+#endif
+#endif
+
+#ifndef OSG_PREFIX
+#ifdef __wasm__
+#define OSG_PREFIX
+#else
+#define OSG_PREFIX static inline
+#endif
+#endif
+
+//In case you want to hook the closure of a thread, i.e. if your system has thread-local storage.
+#ifndef OSG_TERM_THREAD_CODE
+#define OSG_TERM_THREAD_CODE
+#endif
+
+typedef void* og_thread_t;
+typedef void* og_mutex_t;
+typedef void* og_sema_t;
+typedef void* og_tls_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+OSG_PREFIX void OGSleep( int is );
+OSG_PREFIX void OGUSleep( int ius );
+OSG_PREFIX double OGGetAbsoluteTime();
+OSG_PREFIX double OGGetFileTime( const char * file );
+OSG_PREFIX og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter );
+OSG_PREFIX void * OGJoinThread( og_thread_t ot );
+OSG_PREFIX void OGCancelThread( og_thread_t ot );
+OSG_PREFIX og_mutex_t OGCreateMutex();
+OSG_PREFIX void OGLockMutex( og_mutex_t om );
+OSG_PREFIX void OGUnlockMutex( og_mutex_t om );
+OSG_PREFIX void OGDeleteMutex( og_mutex_t om );
+OSG_PREFIX og_sema_t OGCreateSema();
+OSG_PREFIX int OGGetSema( og_sema_t os );
+OSG_PREFIX void OGLockSema( og_sema_t os );
+OSG_PREFIX void OGUnlockSema( og_sema_t os );
+OSG_PREFIX void OGDeleteSema( og_sema_t os );
+OSG_PREFIX og_tls_t OGCreateTLS();
+OSG_PREFIX void OGDeleteTLS( og_tls_t key );
+OSG_PREFIX void * OGGetTLS( og_tls_t key );
+OSG_PREFIX void OGSetTLS( og_tls_t key, void * data );
+
+#ifdef __cplusplus
+};
+#endif
+
+#ifndef OSG_NO_IMPLEMENTATION
+
+#if defined( WIN32 ) || defined (WINDOWS) || defined( _WIN32)
+#define USE_WINDOWS
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef USE_WINDOWS
+
+#include <windows.h>
+#include <stdint.h>
+
+OSG_PREFIX void OGSleep( int is )
+{
+	Sleep( is*1000 );
+}
+
+OSG_PREFIX void OGUSleep( int ius )
+{
+	Sleep( ius/1000 );
+}
+
+OSG_PREFIX double OGGetAbsoluteTime()
+{
+	static LARGE_INTEGER lpf;
+	LARGE_INTEGER li;
+
+	if( !lpf.QuadPart )
+	{
+		QueryPerformanceFrequency( &lpf );
+	}
+
+	QueryPerformanceCounter( &li );
+	return (double)li.QuadPart / (double)lpf.QuadPart;
+}
+
+
+OSG_PREFIX double OGGetFileTime( const char * file )
+{
+	FILETIME ft;
+
+	HANDLE h = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+
+	if( h==INVALID_HANDLE_VALUE )
+		return -1;
+
+	GetFileTime( h, 0, 0, &ft );
+
+	CloseHandle( h );
+
+	return ft.dwHighDateTime + ft.dwLowDateTime;
+}
+
+
+OSG_PREFIX og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter )
+{
+	return (og_thread_t)CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)routine, parameter, 0, 0 );
+}
+
+OSG_PREFIX void * OGJoinThread( og_thread_t ot )
+{
+	WaitForSingleObject( ot, INFINITE );
+	OSG_TERM_THREAD_CODE
+	CloseHandle( ot );
+	return 0;
+}
+
+OSG_PREFIX void OGCancelThread( og_thread_t ot )
+{
+	OSG_TERM_THREAD_CODE
+	TerminateThread( ot, 0);
+	CloseHandle( ot );	
+}
+
+OSG_PREFIX og_mutex_t OGCreateMutex()
+{
+	return CreateMutex( 0, 0, 0 );
+}
+
+OSG_PREFIX void OGLockMutex( og_mutex_t om )
+{
+	WaitForSingleObject(om, INFINITE);
+}
+
+OSG_PREFIX void OGUnlockMutex( og_mutex_t om )
+{
+	ReleaseMutex(om);
+}
+
+OSG_PREFIX void OGDeleteMutex( og_mutex_t om )
+{
+	CloseHandle( om );
+}
+
+
+
+OSG_PREFIX og_sema_t OGCreateSema()
+{
+	HANDLE sem = CreateSemaphore( 0, 0, 32767, 0 );
+	return (og_sema_t)sem;
+}
+
+OSG_PREFIX int OGGetSema( og_sema_t os )
+{
+	typedef LONG NTSTATUS;
+	HANDLE sem = (HANDLE)os;
+	typedef NTSTATUS (NTAPI *_NtQuerySemaphore)(
+		HANDLE SemaphoreHandle, 
+		DWORD SemaphoreInformationClass, /* Would be SEMAPHORE_INFORMATION_CLASS */
+		PVOID SemaphoreInformation,      /* but this is to much to dump here     */
+		ULONG SemaphoreInformationLength, 
+		PULONG ReturnLength OPTIONAL
+	);
+
+	typedef struct _SEMAPHORE_BASIC_INFORMATION {   
+		ULONG CurrentCount; 
+		ULONG MaximumCount;
+	} SEMAPHORE_BASIC_INFORMATION;
+
+
+	static _NtQuerySemaphore NtQuerySemaphore;
+	SEMAPHORE_BASIC_INFORMATION BasicInfo;
+	NTSTATUS Status;
+
+	if( !NtQuerySemaphore )
+	{	
+	    NtQuerySemaphore = (_NtQuerySemaphore)GetProcAddress (GetModuleHandle ("ntdll.dll"), "NtQuerySemaphore");
+		if( !NtQuerySemaphore )
+		{
+			return -1;
+		}
+	}
+
+	
+    Status = NtQuerySemaphore (sem, 0 /*SemaphoreBasicInformation*/, 
+        &BasicInfo, sizeof (SEMAPHORE_BASIC_INFORMATION), NULL);
+
+    if (Status == ERROR_SUCCESS)
+    {       
+        return BasicInfo.CurrentCount;
+    }
+
+	return -2;
+}
+
+OSG_PREFIX void OGLockSema( og_sema_t os )
+{
+	WaitForSingleObject( (HANDLE)os, INFINITE );
+}
+
+OSG_PREFIX void OGUnlockSema( og_sema_t os )
+{
+	ReleaseSemaphore( (HANDLE)os, 1, 0 );
+}
+
+OSG_PREFIX void OGDeleteSema( og_sema_t os )
+{
+	CloseHandle( os );
+}
+
+OSG_PREFIX og_tls_t OGCreateTLS()
+{
+	return (og_tls_t)(intptr_t)TlsAlloc();
+}
+
+OSG_PREFIX void OGDeleteTLS( og_tls_t key )
+{
+	TlsFree( (DWORD)(intptr_t)key );
+}
+
+OSG_PREFIX void * OGGetTLS( og_tls_t key )
+{
+	return TlsGetValue( (DWORD)(intptr_t)key );
+}
+
+OSG_PREFIX void OGSetTLS( og_tls_t key, void * data )
+{
+	TlsSetValue( (DWORD)(intptr_t)key, data );
+}
+
+#elif defined( __wasm__ )
+
+//We don't actually have any function defintions here.
+//The outside system will handle it.
+
+#else
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <semaphore.h>
+#include <unistd.h>
+
+OSG_PREFIX void OGSleep( int is )
+{
+	sleep( is );
+}
+
+OSG_PREFIX void OGUSleep( int ius )
+{
+	usleep( ius );
+}
+
+OSG_PREFIX double OGGetAbsoluteTime()
+{
+	struct timeval tv;
+	gettimeofday( &tv, 0 );
+	return ((double)tv.tv_usec)/1000000. + (tv.tv_sec);
+}
+
+OSG_PREFIX double OGGetFileTime( const char * file )
+{
+	struct stat buff; 
+
+	int r = stat( file, &buff );
+
+	if( r < 0 )
+	{
+		return -1;
+	}
+
+	return buff.st_mtime;
+}
+
+
+
+OSG_PREFIX og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter )
+{
+	pthread_t * ret = (pthread_t *)malloc( sizeof( pthread_t ) );
+	if( !ret ) return 0;
+	int r = pthread_create( ret, 0, routine, parameter );
+	if( r )
+	{
+		free( ret );
+		return 0;
+	}
+	return (og_thread_t)ret;
+}
+
+OSG_PREFIX void * OGJoinThread( og_thread_t ot )
+{
+	void * retval;
+	if( !ot )
+	{
+		return 0;
+	}
+	pthread_join( *(pthread_t*)ot, &retval );
+	OSG_TERM_THREAD_CODE
+	free( ot );
+	return retval;
+}
+
+OSG_PREFIX void OGCancelThread( og_thread_t ot )
+{
+	if( !ot )
+	{
+		return;
+	}
+#ifdef ANDROID
+	pthread_kill( *(pthread_t*)ot, SIGTERM );
+#else
+	pthread_cancel( *(pthread_t*)ot );
+#endif
+	OSG_TERM_THREAD_CODE
+	free( ot );
+}
+
+OSG_PREFIX og_mutex_t OGCreateMutex()
+{
+	pthread_mutexattr_t   mta;
+	og_mutex_t r = malloc( sizeof( pthread_mutex_t ) );
+	if( !r ) return 0;
+
+	pthread_mutexattr_init(&mta);
+	pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
+
+	pthread_mutex_init( (pthread_mutex_t *)r, &mta );
+
+	return r;
+}
+
+OSG_PREFIX void OGLockMutex( og_mutex_t om )
+{
+	if( !om )
+	{
+		return;
+	}
+	pthread_mutex_lock( (pthread_mutex_t*)om );
+}
+
+OSG_PREFIX void OGUnlockMutex( og_mutex_t om )
+{
+	if( !om )
+	{
+		return;
+	}
+	pthread_mutex_unlock( (pthread_mutex_t*)om );
+}
+
+OSG_PREFIX void OGDeleteMutex( og_mutex_t om )
+{
+	if( !om )
+	{
+		return;
+	}
+
+	pthread_mutex_destroy( (pthread_mutex_t*)om );
+	free( om );
+}
+
+
+
+
+OSG_PREFIX og_sema_t OGCreateSema()
+{
+	sem_t * sem = (sem_t *)malloc( sizeof( sem_t ) );
+	if( !sem ) return 0;
+	sem_init( sem, 0, 0 );
+	return (og_sema_t)sem;
+}
+
+OSG_PREFIX int OGGetSema( og_sema_t os )
+{
+	int valp;
+	sem_getvalue( (sem_t*)os, &valp );
+	return valp;
+}
+
+
+OSG_PREFIX void OGLockSema( og_sema_t os )
+{
+	sem_wait( (sem_t*)os );
+}
+
+OSG_PREFIX void OGUnlockSema( og_sema_t os )
+{
+	sem_post( (sem_t*)os );
+}
+
+OSG_PREFIX void OGDeleteSema( og_sema_t os )
+{
+	sem_destroy( (sem_t*)os );
+	free(os);
+}
+
+OSG_PREFIX og_tls_t OGCreateTLS()
+{
+	pthread_key_t ret = 0;
+	pthread_key_create(&ret, 0);
+	return (og_tls_t)(intptr_t)ret;
+}
+
+OSG_PREFIX void OGDeleteTLS( og_tls_t key )
+{
+	pthread_key_delete( (pthread_key_t)(intptr_t)key );
+}
+
+OSG_PREFIX void * OGGetTLS( og_tls_t key )
+{
+	return pthread_getspecific( (pthread_key_t)(intptr_t)key );
+}
+
+OSG_PREFIX void OGSetTLS( og_tls_t key, void * data )
+{
+	pthread_setspecific( (pthread_key_t)(intptr_t)key, data );
+}
+
+#endif
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif //OSG_NO_IMPLEMENTATION
+
+#endif //_OS_GENERIC_H
+
+
diff --git a/examples_x035/usbdevice/testtop.hidapi/testtop.c b/examples_x035/usbdevice/testtop.hidapi/testtop.c
new file mode 100644
index 0000000000000000000000000000000000000000..ea2a11cf0ddfd7969fd1dcb5bbcc99e4148f658e
--- /dev/null
+++ b/examples_x035/usbdevice/testtop.hidapi/testtop.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+// We borrow the combined hidapi.c from minichlink.
+//
+// This is for total perf testing.
+
+#include "hidapi.c"
+
+#include "os_generic.h"
+
+int main()
+{
+	hid_device * hd = hid_open( 0x1209, 0xd035, L"CUSTOMDEVICE000"); // third parameter is "serial"
+	if( !hd )
+	{
+		fprintf( stderr, "Error: Failed to open device.\n" );
+		return -4;
+	}
+
+	// Size of buffers must match the report descriptor size in the special_hid_desc
+	//  NOTE: You are permitted to have multiple entries.
+	uint8_t buffer0[255] = { 0 }; // NOTE: This must be ONE MORE THAN what is in the hid descriptor.
+	uint8_t buffer1[255] = { 0 };
+	int r;
+	int i;
+	int j;
+	int retries = 0;
+	double dStart = OGGetAbsoluteTime();
+	double dSecond = dStart;
+	double dStartSend = 0.0;
+	double dSendTotal = 0;
+	double dRecvTotal = 0;
+	for( j = 0; ; j++ )
+	{
+		buffer0[0] = 0xaa; // First byte must match the ID.
+
+		// But we can fill in random for the rest.
+		for( i = 1; i < sizeof( buffer0 ); i ++ )
+			buffer0[i] = i;//rand(); 
+
+		if( buffer0[1] == 0xa4 ) buffer0[1]++;
+
+		retrysend:
+		
+		dStartSend = OGGetAbsoluteTime();
+		r = hid_send_feature_report( hd, buffer0, sizeof(buffer0) );
+		dSendTotal += OGGetAbsoluteTime() - dStartSend;
+		if( r != sizeof(buffer0) )
+		{
+			fprintf( stderr, "Warning: HID Send fault (%d) Retrying\n", r );
+			retries++;
+			if( retries > 10 ) break;
+			goto retrysend;
+		}
+
+		retries = 0;
+		printf( "<" ); // Print this out meaning we sent the data.
+
+		memset( buffer1, 0xff, sizeof( buffer1 ) );
+		buffer1[0] = 0xaa; // First byte must be ID.
+
+		double dStartRecv = OGGetAbsoluteTime();
+		r = hid_get_feature_report( hd, buffer1, sizeof(buffer1) );
+		dRecvTotal += OGGetAbsoluteTime() - dStartRecv;
+
+		printf( ">" ); fflush( stdout);
+
+		if( r != sizeof( buffer1 ) && r != sizeof( buffer1 ) + 1) { printf( "Got %d\n", r ); break; }
+
+		// Validate the scratches matched.
+		if( memcmp( buffer0, buffer1, sizeof( buffer0 ) ) != 0 ) 
+		{
+			printf( "%d: ", r );
+			for( i = 0; i < r; i++ )
+				printf( "[%d] %02x>%02x %s", i, buffer0[i], buffer1[i], (buffer1[i] != buffer0[i])?"MISMATCH ":""  );
+			printf( "\n" );
+			break;
+		}
+		
+		if( dStartRecv - dSecond > 1.0 )
+		{
+			printf( "\n%2.3f KB/s PC->003 / %2.3f KB/s 003->PC\n", j * .249 / dSendTotal, j * .249 / dRecvTotal );
+			dSecond++;
+		}
+	}
+
+	hid_close( hd );
+}
+
diff --git a/examples_x035/usbdevice/testtop.hidapi/winbuild.bat b/examples_x035/usbdevice/testtop.hidapi/winbuild.bat
new file mode 100644
index 0000000000000000000000000000000000000000..250ad79e51cb84f2972d04f35eb399186b5852e1
--- /dev/null
+++ b/examples_x035/usbdevice/testtop.hidapi/winbuild.bat
@@ -0,0 +1 @@
+tcc testtop.c -I../../ch32v003fun/minichlink -lsetupapi
diff --git a/examples_x035/usbdevice/testtop.webusb/index.html b/examples_x035/usbdevice/testtop.webusb/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..c3ab96533f85cd5208d392a7b211df077808f2d0
--- /dev/null
+++ b/examples_x035/usbdevice/testtop.webusb/index.html
@@ -0,0 +1,244 @@
+<HTML>
+<HEAD>
+<STYLE>
+:root {
+  color-scheme: dark;
+}
+</STYLE>
+<LINK rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> 
+<META charset="UTF-8">
+<SCRIPT>
+
+const expectedProductName = "CNLohr ch32v003fun ch32x035 test";
+const filter = { vendorId : 0x1209, productId : 0xd035 };
+let dev = null;
+let loopAbort = false;
+
+function setStatus( msg )
+{
+	document.getElementById( "STATUS" ).innerHTML = msg;
+	console.log( msg );
+}
+
+function setStatusError( msg )
+{
+	setStatus( "<FONT COLOR=RED>" + msg + "</FONT>" );
+	console.log( msg );
+	console.trace();
+}
+
+function tryConnect()
+{
+	if( !navigator.hid )
+	{
+		return;
+	}
+	
+	if( !dev )
+	{
+		navigator.hid.getDevices().then( (devices) =>
+		{
+			if( devices.length == 0 )
+				setStatusError( "No devices found. Open a device." );
+			else
+				devices.forEach( tryOpen );
+		});
+	}
+}
+
+async function closeDeviceTool()
+{
+	loopAbort = false;
+	setStatusError( "Disconnected" );
+}
+
+function onLoad()
+{
+	setTimeout( sendLoop, 1 );
+
+	if( !navigator.hid )
+	{
+		setStatusError( "Browser does not support HID." );
+		document.getElementById( "connectButton" ).hidden = true;
+	}
+	else
+	{
+		navigator.hid.addEventListener("disconnect", (event) => { if( event.device.productName == expectedProductName ) closeDeviceTool(); } );
+	}
+
+    setTimeout( () => { elapsedOK = true; }, 3000 );
+
+}
+
+function reqConnect()
+{
+	loopAbort = true;
+	const initialization = navigator.hid.requestDevice( { filters: [ filter ] } );
+	initialization.then( gotUSBDevice );
+	initialization.catch( setStatusError );
+}
+
+function gotUSBDevice(result)
+{
+	if( result.length < 1 )
+	{
+		setStatusError( "Error: No devices found" );
+		return;
+	}
+
+	if( result[0].productName != expectedProductName )
+	{
+		setStatusError( "Error: Wrong device name.  Got " + result[0].productName + " Expected " + expectedProductName );
+		return;
+	}
+
+	const thisDev = result[0];
+	
+	tryOpen( thisDev );
+}
+
+function tryOpen( thisDev )
+{
+	thisDev.open().then( ( result ) => {
+		if( result === undefined )
+		{
+			if( dev ) dev.close();
+			loopAbort = false;
+			dev = thisDev;
+			setStatus( "Connected." );
+		}
+		else
+		{
+			setStatusError( "Error: Could not open; " + result );
+		}
+	} ).catch( (e) => setStatusError( "Error: Could not open; " + e ) );
+}
+
+let sendReport = null;
+let receiveReport = null;
+
+async function sendLoopError( e )
+{
+	sendReport = null;
+	receiveReport = null;
+	if( dev ) await dev.close();
+	dev = null;
+	setStatusError( e );
+}
+
+async function sendLoop()
+{
+	const sleep = ms => new Promise(r => setTimeout(r, ms));
+	var arraySend = new Uint8Array(255);
+	var frameNo = 0|0;
+	var lastTime = performance.now();
+	let goodCount = 0;
+	let badCount = 0;
+	let kBsecAvg = 0;
+	let xActionSecAvg = 0;
+	while( true )
+	{
+		if( dev && !loopAbort )
+		{
+			var i = 0|0;
+			for( var i = 0|0; i < 255|0; i++ )
+				arraySend[i] = (Math.random()*256)|0;
+
+			sendReport = dev.sendFeatureReport( 0xAA, arraySend ).catch( sendLoopError );
+			if( !sendReport ) sendLoopError( "error creating sendFeatureReport" );
+
+			receiveReport = dev.receiveFeatureReport( 0xAA ).catch( sendLoopError );
+			if( !receiveReport ) sendLoopError( "error creating receiveReport" );
+
+			frameNo++;
+
+			const updateStatsPerfPer = 4;
+			if( frameNo % updateStatsPerfPer == 0 )
+			{
+				let thisTime = performance.now();
+				let deltaTime = thisTime - lastTime;
+				let kBsec = (255*1000/1024*updateStatsPerfPer)/(deltaTime);
+				let xActionSec = (2*updateStatsPerfPer*1000)/(deltaTime);
+				kBsecAvg = kBsecAvg * 0.9 + kBsec * 0.1;
+				xActionSecAvg = xActionSecAvg * 0.9 + xActionSec * 0.1;
+
+				document.getElementById( "StatusPerf" ).innerHTML = 
+					(kBsecAvg).toFixed(2) + " kBytes/s (Split between send and receive)<br>" +
+					(xActionSecAvg).toFixed(2)  + "transactions/sec<br>" +
+					"Good Count: " + goodCount + "<BR>Bad Count: " + badCount;
+				lastTime = thisTime;
+			}
+
+			if( sendReport )
+			{
+				await sendReport;
+			}
+			if( receiveReport )
+			{
+				// Validate Data.
+				let receiveData = await receiveReport;
+				if( receiveData && receiveData.buffer )
+				{
+					let data = new Uint8Array( receiveData.buffer );
+
+					// Tricky: Data goes:
+					//  reportID -> Payload...
+					let failed = false;
+					for( var i = 0|0; i < 254|0; i++ )
+					{
+						if( data[i+1] != arraySend[i] )
+						{
+							console.log( "Disagreement at index " + i );
+							console.log( data );
+							console.log( arraySend );
+							badCount++;
+							failed = true;
+							break;
+						}
+					}
+					if( !failed ) goodCount++;
+				}
+				else
+				{
+					badCount++;
+				}
+			}
+		}
+		else if( loopAbort )
+		{
+			if( dev )
+			{
+				console.log( "Loop Aborting, Dev Closing" );
+				await dev.close();
+				console.log( "Loop Aborting, Dev Closed." );
+				dev = null;
+			}
+			await sleep(100);
+		}
+		else
+		{
+			// Try opening dev.
+			console.log( "Attempting reconnect." );
+			tryConnect();
+			goodCount = 0;
+			badCount = 0;
+			let i = 0|0;
+			for( i = 0; i < 10; i++ )
+			{
+				await sleep(100);
+				if( dev )
+				{
+					break;
+				}
+			}
+		}
+	}
+}
+
+</SCRIPT>
+<BODY onload="onLoad()">
+
+<TABLE><TR><TD><INPUT TYPE=SUBMIT onClick="reqConnect()" VALUE="Open Device" ID=connectButton></TD><TD><DIV ID=STATUS></DIV></TD></TR></TABLE>
+<DIV ID="StatusPerf"></DIV>
+</BODY>
+</HTML>
diff --git a/examples_x035/usbdevice/usb_config.h b/examples_x035/usbdevice/usb_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..093cd7a27d1750907a47588d8d0b88cedb065670
--- /dev/null
+++ b/examples_x035/usbdevice/usb_config.h
@@ -0,0 +1,279 @@
+#ifndef _USB_CONFIG_H
+#define _USB_CONFIG_H
+
+#include "funconfig.h"
+#include "ch32v003fun.h"
+
+#define FUSB_CONFIG_EPS       4 // Include EP0 in this count
+#define FUSB_SUPPORTS_SLEEP   0
+#define FUSB_HID_INTERFACES   2
+#define FUSB_CURSED_TURBO_DMA 0 // Hacky, but seems fine, shaves 2.5us off filling 64-byte buffers.
+#define FUSB_HID_USER_REPORTS 1
+#define FUSB_IO_PROFILE       1
+#define FUSB_USE_HPE          FUNCONF_ENABLE_HPE
+#define FUSB_5V_OPERATION     FUNCONF_5V_OPERATION
+
+#include "usb_defines.h"
+
+//Taken from http://www.usbmadesimple.co.uk/ums_ms_desc_dev.htm
+static const uint8_t device_descriptor[] = {
+	18, //Length
+	1,  //Type (Device)
+	0x00, 0x02, //Spec
+	0x0, //Device Class
+	0x0, //Device Subclass
+	0x0, //Device Protocol  (000 = use config descriptor)
+	64, //Max packet size for EP0 (This has to be 8 because of the USB Low-Speed Standard)
+	0x09, 0x12, //ID Vendor
+	0x35, 0xd0, //ID Product
+	0x03, 0x00, //ID Rev
+	1, //Manufacturer string
+	2, //Product string
+	3, //Serial string
+	1, //Max number of configurations
+};
+
+
+/* Keyboard Report Descriptor */
+static const uint8_t KeyRepDesc[ ] =
+{
+    0x05, 0x01,                                             // Usage Page (Generic Desktop)
+    0x09, 0x06,                                             // Usage (Keyboard)
+    0xA1, 0x01,                                             // Collection (Application)
+    0x05, 0x07,                                             // Usage Page (Key Codes)
+    0x19, 0xE0,                                             // Usage Minimum (224)
+    0x29, 0xE7,                                             // Usage Maximum (231)
+    0x15, 0x00,                                             // Logical Minimum (0)
+    0x25, 0x01,                                             // Logical Maximum (1)
+    0x75, 0x01,                                             // Report Size (1)
+    0x95, 0x08,                                             // Report Count (8)
+    0x81, 0x02,                                             // Input (Data,Variable,Absolute)
+    0x95, 0x01,                                             // Report Count (1)
+    0x75, 0x08,                                             // Report Size (8)
+    0x81, 0x01,                                             // Input (Constant)
+    0x95, 0x03,                                             // Report Count (3)
+    0x75, 0x01,                                             // Report Size (1)
+    0x05, 0x08,                                             // Usage Page (LEDs)
+    0x19, 0x01,                                             // Usage Minimum (1)
+    0x29, 0x03,                                             // Usage Maximum (3)
+    0x91, 0x02,                                             // Output (Data,Variable,Absolute)
+    0x95, 0x05,                                             // Report Count (5)
+    0x75, 0x01,                                             // Report Size (1)
+    0x91, 0x01,                                             // Output (Constant,Array,Absolute)
+    0x95, 0x06,                                             // Report Count (6)
+    0x75, 0x08,                                             // Report Size (8)
+    0x26, 0xFF, 0x00,                                       // Logical Maximum (255)
+    0x05, 0x07,                                             // Usage Page (Key Codes)
+    0x19, 0x00,                                             // Usage Minimum (0)
+    0x29, 0x91,                                             // Usage Maximum (145)
+    0x81, 0x00,                                             // Input(Data,Array,Absolute)
+    0xC0                                                    // End Collection
+};
+
+/* Mouse Report Descriptor */
+static const uint8_t MouseRepDesc[ ] =
+{
+
+    0x05, 0x01,                                             // Usage Page (Generic Desktop)
+    0x09, 0x02,                                             // Usage (Mouse)
+    0xA1, 0x01,                                             // Collection (Application)
+    0x09, 0x01,                                             // Usage (Pointer)
+    0xA1, 0x00,                                             // Collection (Physical)
+    0x05, 0x09,                                             // Usage Page (Button)
+    0x19, 0x01,                                             // Usage Minimum (Button 1)
+    0x29, 0x03,                                             // Usage Maximum (Button 3)
+    0x15, 0x00,                                             // Logical Minimum (0)
+    0x25, 0x01,                                             // Logical Maximum (1)
+    0x75, 0x01,                                             // Report Size (1)
+    0x95, 0x03,                                             // Report Count (3)
+    0x81, 0x02,                                             // Input (Data,Variable,Absolute)
+    0x75, 0x05,                                             // Report Size (5)
+    0x95, 0x01,                                             // Report Count (1)
+    0x81, 0x01,                                             // Input (Constant,Array,Absolute)
+    0x05, 0x01,                                             // Usage Page (Generic Desktop)
+    0x09, 0x30,                                             // Usage (X)
+    0x09, 0x31,                                             // Usage (Y)
+    0x09, 0x38,                                             // Usage (Wheel)
+    0x15, 0x81,                                             // Logical Minimum (-127)
+    0x25, 0x7F,                                             // Logical Maximum (127)
+    0x75, 0x08,                                             // Report Size (8)
+    0x95, 0x03,                                             // Report Count (3)
+    0x81, 0x06,                                             // Input (Data,Variable,Relative)
+    0xC0,                                                   // End Collection
+    0xC0                                                    // End Collection
+};
+
+static const uint8_t HIDAPIRepDesc[ ] =
+{
+	HID_USAGE_PAGE ( 0xff ), // Vendor-defined page.
+	HID_USAGE      ( 0x00 ),
+	HID_REPORT_SIZE ( 8 ),
+	HID_COLLECTION ( HID_COLLECTION_LOGICAL ),
+		HID_REPORT_COUNT   ( 254 ),
+		HID_REPORT_ID      ( 0xaa )
+		HID_USAGE          ( 0x01 ),
+		HID_FEATURE        ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,
+		HID_REPORT_COUNT   ( 63 ), // For use with `hidapitester --vidpid 1209/D003 --open --read-feature 171`
+		HID_REPORT_ID      ( 0xab )
+		HID_USAGE          ( 0x01 ),	
+		HID_FEATURE        ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,
+	HID_COLLECTION_END,
+};
+
+/* Configuration Descriptor Set */
+static const uint8_t config_descriptor[ ] =
+{
+    /* Configuration Descriptor */
+    0x09,                                                   // bLength
+    0x02,                                                   // bDescriptorType
+    0x54, 0x00,                                             // wTotalLength
+    0x03,                                                   // bNumInterfaces (3)
+    0x01,                                                   // bConfigurationValue
+    0x00,                                                   // iConfiguration
+    0xA0,                                                   // bmAttributes: Bus Powered; Remote Wakeup
+    0x32,                                                   // MaxPower: 100mA
+
+    /* Interface Descriptor (Keyboard) */
+    0x09,                                                   // bLength
+    0x04,                                                   // bDescriptorType
+    0x00,                                                   // bInterfaceNumber
+    0x00,                                                   // bAlternateSetting
+    0x01,                                                   // bNumEndpoints
+    0x03,                                                   // bInterfaceClass
+    0x01,                                                   // bInterfaceSubClass
+    0x01,                                                   // bInterfaceProtocol: Keyboard
+    0x00,                                                   // iInterface
+
+    /* HID Descriptor (Keyboard) */
+    0x09,                                                   // bLength
+    0x21,                                                   // bDescriptorType
+    0x11, 0x01,                                             // bcdHID
+    0x00,                                                   // bCountryCode
+    0x01,                                                   // bNumDescriptors
+    0x22,                                                   // bDescriptorType
+    sizeof(KeyRepDesc), 0x00,                               // wDescriptorLength
+
+    /* Endpoint Descriptor (Keyboard) */
+    0x07,                                                   // bLength
+    0x05,                                                   // bDescriptorType
+    0x81,                                                   // bEndpointAddress: IN Endpoint 1
+    0x03,                                                   // bmAttributes
+    0x08, 0x00,                                             // wMaxPacketSize
+    0x0A,                                                   // bInterval: 10mS
+
+    /* Interface Descriptor (Mouse) */
+    0x09,                                                   // bLength
+    0x04,                                                   // bDescriptorType
+    0x01,                                                   // bInterfaceNumber
+    0x00,                                                   // bAlternateSetting
+    0x01,                                                   // bNumEndpoints
+    0x03,                                                   // bInterfaceClass
+    0x01,                                                   // bInterfaceSubClass
+    0x02,                                                   // bInterfaceProtocol: Mouse
+    0x00,                                                   // iInterface
+
+    /* HID Descriptor (Mouse) */
+    0x09,                                                   // bLength
+    0x21,                                                   // bDescriptorType
+    0x10, 0x01,                                             // bcdHID
+    0x00,                                                   // bCountryCode
+    0x01,                                                   // bNumDescriptors
+    0x22,                                                   // bDescriptorType
+    sizeof(MouseRepDesc), 0x00,                             // wDescriptorLength
+
+    /* Endpoint Descriptor (Mouse) */
+    0x07,                                                   // bLength
+    0x05,                                                   // bDescriptorType
+    0x82,                                                   // bEndpointAddress: IN Endpoint 2
+    0x03,                                                   // bmAttributes
+    0x08, 0x00,                                             // wMaxPacketSize
+    0x01,                                                   // bInterval: 1mS
+
+
+    /* Interface Descriptor (Mouse) */
+    0x09,                                                   // bLength
+    0x04,                                                   // bDescriptorType
+    0x02,                                                   // bInterfaceNumber
+    0x00,                                                   // bAlternateSetting
+    0x01,                                                   // bNumEndpoints
+    0x03,                                                   // bInterfaceClass
+    0x00,                                                   // bInterfaceSubClass
+    0xff,                                                   // bInterfaceProtocol: OTher
+    0x00,                                                   // iInterface
+
+    /* HID Descriptor (Mouse) */
+    0x09,                                                   // bLength
+    0x21,                                                   // bDescriptorType
+    0x10, 0x01,                                             // bcdHID
+    0x00,                                                   // bCountryCode
+    0x01,                                                   // bNumDescriptors
+    0x22,                                                   // bDescriptorType
+    sizeof(HIDAPIRepDesc), 0x00,                             // wDescriptorLength
+
+    /* Endpoint Descriptor (Mouse) */
+    0x07,                                                   // bLength
+    0x05,                                                   // bDescriptorType
+    0x83,                                                   // bEndpointAddress: IN Endpoint 2
+    0x03,                                                   // bmAttributes
+    0x08, 0x00,                                             // wMaxPacketSize
+    0x0a,                                                   // bInterval: 10mS
+};
+
+
+
+#define STR_MANUFACTURER u"CNLohr"
+#define STR_PRODUCT      u"ch32v003fun ch32x035 test"
+#define STR_SERIAL       u"CUSTOMDEVICE000"
+
+struct usb_string_descriptor_struct {
+	uint8_t bLength;
+	uint8_t bDescriptorType;
+	uint16_t wString[];
+};
+const static struct usb_string_descriptor_struct string0 __attribute__((section(".rodata"))) = {
+	4,
+	3,
+	{0x0409}
+};
+const static struct usb_string_descriptor_struct string1 __attribute__((section(".rodata")))  = {
+	sizeof(STR_MANUFACTURER),
+	3,
+	STR_MANUFACTURER
+};
+const static struct usb_string_descriptor_struct string2 __attribute__((section(".rodata")))  = {
+	sizeof(STR_PRODUCT),
+	3,
+	STR_PRODUCT
+};
+const static struct usb_string_descriptor_struct string3 __attribute__((section(".rodata")))  = {
+	sizeof(STR_SERIAL),
+	3,
+	STR_SERIAL
+};
+
+// This table defines which descriptor data is sent for each specific
+// request from the host (in wValue and wIndex).
+const static struct descriptor_list_struct {
+	uint32_t	lIndexValue;
+	const uint8_t	*addr;
+	uint8_t		length;
+} descriptor_list[] = {
+	{0x00000100, device_descriptor, sizeof(device_descriptor)},
+	{0x00000200, config_descriptor, sizeof(config_descriptor)},
+	// interface number // 2200 for hid descriptors.
+	{0x00002200, KeyRepDesc, sizeof(KeyRepDesc)},
+	{0x00012200, MouseRepDesc, sizeof(MouseRepDesc)},
+	{0x00022200, HIDAPIRepDesc, sizeof(HIDAPIRepDesc)},
+
+	{0x00002100, config_descriptor + 18, 9 }, // Not sure why, this seems to be useful for Windows + Android.
+
+	{0x00000300, (const uint8_t *)&string0, 4},
+	{0x04090301, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
+	{0x04090302, (const uint8_t *)&string2, sizeof(STR_PRODUCT)},	
+	{0x04090303, (const uint8_t *)&string3, sizeof(STR_SERIAL)}
+};
+#define DESCRIPTOR_LIST_ENTRIES ((sizeof(descriptor_list))/(sizeof(struct descriptor_list_struct)) )
+
+
+#endif
+
diff --git a/examples_x035/usbdevice/usb_defines.h b/examples_x035/usbdevice/usb_defines.h
new file mode 100644
index 0000000000000000000000000000000000000000..02d8f45696d958c27278d83c732cdf9a0ec77003
--- /dev/null
+++ b/examples_x035/usbdevice/usb_defines.h
@@ -0,0 +1,1779 @@
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * 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.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/** \ingroup group_usb_definitions
+ *  \defgroup USBDef_Type USB Types
+ *  @{ */
+
+// Cribbed from the WCH x035 example code, but originally from USB IF.
+
+#ifndef _TUSB_TYPES_H_
+#define _TUSB_TYPES_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+
+/*------------------------------------------------------------------*/
+/* From Linux
+ *------------------------------------------------------------------*/
+
+
+#define USB_DIR_OUT			0		/* to device */
+#define USB_DIR_IN			0x80		/* to host */
+
+#define USB_TYPE_MASK			(0x03 << 5)
+#define USB_TYPE_STANDARD		(0x00 << 5)
+#define USB_TYPE_CLASS			(0x01 << 5)
+#define USB_TYPE_VENDOR			(0x02 << 5)
+#define USB_TYPE_RESERVED		(0x03 << 5)
+
+
+/*
+ * USB recipients, the third of three bRequestType fields
+ */
+#define USB_RECIP_MASK			0x1f
+#define USB_RECIP_DEVICE		0x00
+#define USB_RECIP_INTERFACE		0x01
+#define USB_RECIP_ENDPOINT		0x02
+#define USB_RECIP_OTHER			0x03
+/* From Wireless USB 1.0 */
+#define USB_RECIP_PORT			0x04
+#define USB_RECIP_RPIPE		0x05
+
+#define TU_ATTR_PACKED __attribute__((packed))
+#ifndef TU_BIT
+#define TU_BIT(n)             (1U << (n))
+#endif
+#define TU_STRCAT(a, b)   a##b            ///< concat without expand
+#define TU_XSTRCAT(a, b)  TU_STRCAT(a, b) ///< expand then concat
+// Compile-time Assert
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+  #define TU_VERIFY_STATIC   _Static_assert
+#elif defined (__cplusplus) && __cplusplus >= 201103L
+  #define TU_VERIFY_STATIC   static_assert
+#else
+  #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) }
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*------------------------------------------------------------------*/
+/* CONSTANTS
+ *------------------------------------------------------------------*/
+
+/// defined base on EHCI specs value for Endpoint Speed
+typedef enum
+{
+  TUSB_SPEED_FULL = 0,
+  TUSB_SPEED_LOW     ,
+  TUSB_SPEED_HIGH,
+  TUSB_SPEED_INVALID = 0xff,
+}tusb_speed_t;
+
+/// defined base on USB Specs Endpoint's bmAttributes
+typedef enum
+{
+  TUSB_XFER_CONTROL = 0 ,
+  TUSB_XFER_ISOCHRONOUS ,
+  TUSB_XFER_BULK        ,
+  TUSB_XFER_INTERRUPT
+}tusb_xfer_type_t;
+
+typedef enum
+{
+  TUSB_DIR_OUT = 0,
+  TUSB_DIR_IN  = 1,
+
+  TUSB_DIR_IN_MASK = 0x80
+}tusb_dir_t;
+
+/// USB Descriptor Types
+typedef enum
+{
+  TUSB_DESC_DEVICE                = 0x01,
+  TUSB_DESC_CONFIGURATION         = 0x02,
+  TUSB_DESC_STRING                = 0x03,
+  TUSB_DESC_INTERFACE             = 0x04,
+  TUSB_DESC_ENDPOINT              = 0x05,
+  TUSB_DESC_DEVICE_QUALIFIER      = 0x06,
+  TUSB_DESC_OTHER_SPEED_CONFIG    = 0x07,
+  TUSB_DESC_INTERFACE_POWER       = 0x08,
+  TUSB_DESC_OTG                   = 0x09,
+  TUSB_DESC_DEBUG                 = 0x0A,
+  TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B,
+
+  TUSB_DESC_BOS                   = 0x0F,
+  TUSB_DESC_DEVICE_CAPABILITY     = 0x10,
+
+  TUSB_DESC_FUNCTIONAL            = 0x21,
+
+  // Class Specific Descriptor
+  TUSB_DESC_CS_DEVICE             = 0x21,
+  TUSB_DESC_CS_CONFIGURATION      = 0x22,
+  TUSB_DESC_CS_STRING             = 0x23,
+  TUSB_DESC_CS_INTERFACE          = 0x24,
+  TUSB_DESC_CS_ENDPOINT           = 0x25,
+
+  TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION     = 0x30,
+  TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31
+}tusb_desc_type_t;
+
+typedef enum
+{
+  TUSB_REQ_GET_STATUS        = 0  ,
+  TUSB_REQ_CLEAR_FEATURE     = 1  ,
+  TUSB_REQ_RESERVED          = 2  ,
+  TUSB_REQ_SET_FEATURE       = 3  ,
+  TUSB_REQ_RESERVED2         = 4  ,
+  TUSB_REQ_SET_ADDRESS       = 5  ,
+  TUSB_REQ_GET_DESCRIPTOR    = 6  ,
+  TUSB_REQ_SET_DESCRIPTOR    = 7  ,
+  TUSB_REQ_GET_CONFIGURATION = 8  ,
+  TUSB_REQ_SET_CONFIGURATION = 9  ,
+  TUSB_REQ_GET_INTERFACE     = 10 ,
+  TUSB_REQ_SET_INTERFACE     = 11 ,
+  TUSB_REQ_SYNCH_FRAME       = 12
+}tusb_request_code_t;
+
+typedef enum
+{
+  TUSB_REQ_FEATURE_EDPT_HALT     = 0,
+  TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1,
+  TUSB_REQ_FEATURE_TEST_MODE     = 2
+}tusb_request_feature_selector_t;
+
+typedef enum
+{
+  TUSB_REQ_TYPE_STANDARD = 0,
+  TUSB_REQ_TYPE_CLASS,
+  TUSB_REQ_TYPE_VENDOR,
+  TUSB_REQ_TYPE_INVALID
+} tusb_request_type_t;
+
+typedef enum
+{
+  TUSB_REQ_RCPT_DEVICE =0,
+  TUSB_REQ_RCPT_INTERFACE,
+  TUSB_REQ_RCPT_ENDPOINT,
+  TUSB_REQ_RCPT_OTHER
+} tusb_request_recipient_t;
+
+// https://www.usb.org/defined-class-codes
+typedef enum
+{
+  TUSB_CLASS_UNSPECIFIED          = 0    ,
+  TUSB_CLASS_AUDIO                = 1    ,
+  TUSB_CLASS_CDC                  = 2    ,
+  TUSB_CLASS_HID                  = 3    ,
+  TUSB_CLASS_RESERVED_4           = 4    ,
+  TUSB_CLASS_PHYSICAL             = 5    ,
+  TUSB_CLASS_IMAGE                = 6    ,
+  TUSB_CLASS_PRINTER              = 7    ,
+  TUSB_CLASS_MSC                  = 8    ,
+  TUSB_CLASS_HUB                  = 9    ,
+  TUSB_CLASS_CDC_DATA             = 10   ,
+  TUSB_CLASS_SMART_CARD           = 11   ,
+  TUSB_CLASS_RESERVED_12          = 12   ,
+  TUSB_CLASS_CONTENT_SECURITY     = 13   ,
+  TUSB_CLASS_VIDEO                = 14   ,
+  TUSB_CLASS_PERSONAL_HEALTHCARE  = 15   ,
+  TUSB_CLASS_AUDIO_VIDEO          = 16   ,
+
+  TUSB_CLASS_DIAGNOSTIC           = 0xDC ,
+  TUSB_CLASS_WIRELESS_CONTROLLER  = 0xE0 ,
+  TUSB_CLASS_MISC                 = 0xEF ,
+  TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE ,
+  TUSB_CLASS_VENDOR_SPECIFIC      = 0xFF
+}tusb_class_code_t;
+
+typedef enum
+{
+  MISC_SUBCLASS_COMMON = 2
+}misc_subclass_type_t;
+
+typedef enum
+{
+  MISC_PROTOCOL_IAD = 1
+}misc_protocol_type_t;
+
+typedef enum
+{
+  APP_SUBCLASS_USBTMC = 0x03,
+  APP_SUBCLASS_DFU_RUNTIME = 0x01
+} app_subclass_type_t;
+
+typedef enum
+{
+  DEVICE_CAPABILITY_WIRELESS_USB               = 0x01,
+  DEVICE_CAPABILITY_USB20_EXTENSION            = 0x02,
+  DEVICE_CAPABILITY_SUPERSPEED_USB             = 0x03,
+  DEVICE_CAPABILITY_CONTAINER_id               = 0x04,
+  DEVICE_CAPABILITY_PLATFORM                   = 0x05,
+  DEVICE_CAPABILITY_POWER_DELIVERY             = 0x06,
+  DEVICE_CAPABILITY_BATTERY_INFO               = 0x07,
+  DEVICE_CAPABILITY_PD_CONSUMER_PORT           = 0x08,
+  DEVICE_CAPABILITY_PD_PROVIDER_PORT           = 0x09,
+  DEVICE_CAPABILITY_SUPERSPEED_PLUS            = 0x0A,
+  DEVICE_CAPABILITY_PRECESION_TIME_MEASUREMENT = 0x0B,
+  DEVICE_CAPABILITY_WIRELESS_USB_EXT           = 0x0C,
+  DEVICE_CAPABILITY_BILLBOARD                  = 0x0D,
+  DEVICE_CAPABILITY_AUTHENTICATION             = 0x0E,
+  DEVICE_CAPABILITY_BILLBOARD_EX               = 0x0F,
+  DEVICE_CAPABILITY_CONFIGURATION_SUMMARY      = 0x10
+}device_capability_type_t;
+
+enum {
+  TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5),
+  TUSB_DESC_CONFIG_ATT_SELF_POWERED  = TU_BIT(6),
+};
+
+#define TUSB_DESC_CONFIG_POWER_MA(x)  ((x)/2)
+
+/// Device State TODO remove
+typedef enum
+{
+  TUSB_DEVICE_STATE_UNPLUG = 0  ,
+  TUSB_DEVICE_STATE_CONFIGURED  ,
+  TUSB_DEVICE_STATE_SUSPENDED   ,
+}tusb_device_state_t;
+
+typedef enum
+{
+  XFER_RESULT_SUCCESS,
+  XFER_RESULT_FAILED,
+  XFER_RESULT_STALLED,
+}xfer_result_t;
+
+enum // TODO remove
+{
+  DESC_OFFSET_LEN  = 0,
+  DESC_OFFSET_TYPE = 1
+};
+
+enum
+{
+  INTERFACE_INVALID_NUMBER = 0xff
+};
+
+
+typedef enum
+{
+  MS_OS_20_SET_HEADER_DESCRIPTOR       = 0x00,
+  MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01,
+  MS_OS_20_SUBSET_HEADER_FUNCTION      = 0x02,
+  MS_OS_20_FEATURE_COMPATBLE_ID        = 0x03,
+  MS_OS_20_FEATURE_REG_PROPERTY        = 0x04,
+  MS_OS_20_FEATURE_MIN_RESUME_TIME     = 0x05,
+  MS_OS_20_FEATURE_MODEL_ID            = 0x06,
+  MS_OS_20_FEATURE_CCGP_DEVICE         = 0x07,
+  MS_OS_20_FEATURE_VENDOR_REVISION     = 0x08
+} microsoft_os_20_type_t;
+
+enum
+{
+  CONTROL_STAGE_SETUP,
+  CONTROL_STAGE_DATA,
+  CONTROL_STAGE_ACK
+};
+
+//--------------------------------------------------------------------+
+// USB Descriptors
+//--------------------------------------------------------------------+
+
+/// USB Device Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t  bDescriptorType    ; ///< DEVICE Descriptor Type.
+  uint16_t bcdUSB             ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant.
+
+  uint8_t  bDeviceClass       ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific.
+  uint8_t  bDeviceSubClass    ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
+  uint8_t  bDeviceProtocol    ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis.
+  uint8_t  bMaxPacketSize0    ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
+
+  uint16_t idVendor           ; ///< Vendor ID (assigned by the USB-IF).
+  uint16_t idProduct          ; ///< Product ID (assigned by the manufacturer).
+  uint16_t bcdDevice          ; ///< Device release number in binary-coded decimal.
+  uint8_t  iManufacturer      ; ///< Index of string descriptor describing manufacturer.
+  uint8_t  iProduct           ; ///< Index of string descriptor describing product.
+  uint8_t  iSerialNumber      ; ///< Index of string descriptor describing the device's serial number.
+
+  uint8_t  bNumConfigurations ; ///< Number of possible configurations.
+} tusb_desc_device_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct");
+
+// USB Binary Device Object Store (BOS) Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength         ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType ; ///< CONFIGURATION Descriptor Type
+  uint16_t wTotalLength    ; ///< Total length of data returned for this descriptor
+  uint8_t  bNumDeviceCaps  ; ///< Number of device capability descriptors in the BOS
+} tusb_desc_bos_t;
+
+/// USB Configuration Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength             ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType     ; ///< CONFIGURATION Descriptor Type
+  uint16_t wTotalLength        ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration.
+
+  uint8_t  bNumInterfaces      ; ///< Number of interfaces supported by this configuration
+  uint8_t  bConfigurationValue ; ///< Value to use as an argument to the SetConfiguration() request to select this configuration.
+  uint8_t  iConfiguration      ; ///< Index of string descriptor describing this configuration
+  uint8_t  bmAttributes        ; ///< Configuration characteristics \n D7: Reserved (set to one)\n D6: Self-powered \n D5: Remote Wakeup \n D4...0: Reserved (reset to zero) \n D7 is reserved and must be set to one for historical reasons. \n A device configuration that uses power from the bus and a local source reports a non-zero value in bMaxPower to indicate the amount of bus power required and sets D6. The actual power source at runtime may be determined using the GetStatus(DEVICE) request (see USB 2.0 spec Section 9.4.5). \n If a device configuration supports remote wakeup, D5 is set to one.
+  uint8_t  bMaxPower           ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA).
+} tusb_desc_configuration_t;
+
+/// USB Interface Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength            ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType    ; ///< INTERFACE Descriptor Type
+
+  uint8_t  bInterfaceNumber   ; ///< Number of this interface. Zero-based value identifying the index in the array of concurrent interfaces supported by this configuration.
+  uint8_t  bAlternateSetting  ; ///< Value used to select this alternate setting for the interface identified in the prior field
+  uint8_t  bNumEndpoints      ; ///< Number of endpoints used by this interface (excluding endpoint zero). If this value is zero, this interface only uses the Default Control Pipe.
+  uint8_t  bInterfaceClass    ; ///< Class code (assigned by the USB-IF). \li A value of zero is reserved for future standardization. \li If this field is set to FFH, the interface class is vendor-specific. \li All other values are reserved for assignment by the USB-IF.
+  uint8_t  bInterfaceSubClass ; ///< Subclass code (assigned by the USB-IF). \n These codes are qualified by the value of the bInterfaceClass field. \li If the bInterfaceClass field is reset to zero, this field must also be reset to zero. \li If the bInterfaceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
+  uint8_t  bInterfaceProtocol ; ///< Protocol code (assigned by the USB). \n These codes are qualified by the value of the bInterfaceClass and the bInterfaceSubClass fields. If an interface supports class-specific requests, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use a class-specific protocol on this interface. \li If this field is set to FFH, the device uses a vendor-specific protocol for this interface.
+  uint8_t  iInterface         ; ///< Index of string descriptor describing this interface
+} tusb_desc_interface_t;
+
+/// USB Endpoint Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength          ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType  ; ///< ENDPOINT Descriptor Type
+
+  uint8_t  bEndpointAddress ; ///< The address of the endpoint on the USB device described by this descriptor. The address is encoded as follows: \n Bit 3...0: The endpoint number \n Bit 6...4: Reserved, reset to zero \n Bit 7: Direction, ignored for control endpoints 0 = OUT endpoint 1 = IN endpoint.
+
+  struct TU_ATTR_PACKED {
+    uint8_t xfer  : 2;
+    uint8_t sync  : 2;
+    uint8_t usage : 2;
+    uint8_t       : 2;
+  } bmAttributes     ; ///< This field describes the endpoint's attributes when it is configured using the bConfigurationValue. \n Bits 1..0: Transfer Type \n- 00 = Control \n- 01 = Isochronous \n- 10 = Bulk \n- 11 = Interrupt \n If not an isochronous endpoint, bits 5..2 are reserved and must be set to zero. If isochronous, they are defined as follows: \n Bits 3..2: Synchronization Type \n- 00 = No Synchronization \n- 01 = Asynchronous \n- 10 = Adaptive \n- 11 = Synchronous \n Bits 5..4: Usage Type \n- 00 = Data endpoint \n- 01 = Feedback endpoint \n- 10 = Implicit feedback Data endpoint \n- 11 = Reserved \n Refer to Chapter 5 of USB 2.0 specification for more information. \n All other bits are reserved and must be reset to zero. Reserved bits must be ignored by the host.
+
+  struct TU_ATTR_PACKED {
+    uint16_t size           : 11; ///< Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. \n For isochronous endpoints, this value is used to reserve the bus time in the schedule, required for the per-(micro)frame data payloads. The pipe may, on an ongoing basis, actually use less bandwidth than that reserved. The device reports, if necessary, the actual bandwidth used via its normal, non-USB defined mechanisms. \n For all endpoints, bits 10..0 specify the maximum packet size (in bytes). \n For high-speed isochronous and interrupt endpoints: \n Bits 12..11 specify the number of additional transaction opportunities per microframe: \n- 00 = None (1 transaction per microframe) \n- 01 = 1 additional (2 per microframe) \n- 10 = 2 additional (3 per microframe) \n- 11 = Reserved \n Bits 15..13 are reserved and must be set to zero.
+    uint16_t hs_period_mult : 2;
+    uint16_t TU_RESERVED    : 3;
+  }wMaxPacketSize;
+
+  uint8_t  bInterval        ; ///< Interval for polling endpoint for data transfers. Expressed in frames or microframes depending on the device operating speed (i.e., either 1 millisecond or 125 us units). \n- For full-/high-speed isochronous endpoints, this value must be in the range from 1 to 16. The bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$). \n- For full-/low-speed interrupt endpoints, the value of this field may be from 1 to 255. \n- For high-speed interrupt endpoints, the bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$) . This value must be from 1 to 16. \n- For high-speed bulk/control OUT endpoints, the bInterval must specify the maximum NAK rate of the endpoint. A value of 0 indicates the endpoint never NAKs. Other values indicate at most 1 NAK each bInterval number of microframes. This value must be in the range from 0 to 255. \n Refer to Chapter 5 of USB 2.0 specification for more information.
+} tusb_desc_endpoint_t;
+
+/// USB Other Speed Configuration Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength             ; ///< Size of descriptor
+  uint8_t  bDescriptorType     ; ///< Other_speed_Configuration Type
+  uint16_t wTotalLength        ; ///< Total length of data returned
+
+  uint8_t  bNumInterfaces      ; ///< Number of interfaces supported by this speed configuration
+  uint8_t  bConfigurationValue ; ///< Value to use to select configuration
+  uint8_t  IConfiguration      ; ///< Index of string descriptor
+  uint8_t  bmAttributes        ; ///< Same as Configuration descriptor
+  uint8_t  bMaxPower           ; ///< Same as Configuration descriptor
+} tusb_desc_other_speed_t;
+
+/// USB Device Qualifier Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength            ; ///< Size of descriptor
+  uint8_t  bDescriptorType    ; ///< Device Qualifier Type
+  uint16_t bcdUSB             ; ///< USB specification version number (e.g., 0200H for V2.00)
+
+  uint8_t  bDeviceClass       ; ///< Class Code
+  uint8_t  bDeviceSubClass    ; ///< SubClass Code
+  uint8_t  bDeviceProtocol    ; ///< Protocol Code
+  uint8_t  bMaxPacketSize0    ; ///< Maximum packet size for other speed
+  uint8_t  bNumConfigurations ; ///< Number of Other-speed Configurations
+  uint8_t  bReserved          ; ///< Reserved for future use, must be zero
+} tusb_desc_device_qualifier_t;
+
+/// USB Interface Association Descriptor (IAD ECN)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength           ; ///< Size of descriptor
+  uint8_t bDescriptorType   ; ///< Other_speed_Configuration Type
+
+  uint8_t bFirstInterface   ; ///< Index of the first associated interface.
+  uint8_t bInterfaceCount   ; ///< Total number of associated interfaces.
+
+  uint8_t bFunctionClass    ; ///< Interface class ID.
+  uint8_t bFunctionSubClass ; ///< Interface subclass ID.
+  uint8_t bFunctionProtocol ; ///< Interface protocol ID.
+
+  uint8_t iFunction         ; ///< Index of the string descriptor describing the interface association.
+} tusb_desc_interface_assoc_t;
+
+// USB String Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength         ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType ; ///< Descriptor Type
+  uint16_t unicode_string[];
+} tusb_desc_string_t;
+
+// USB Binary Device Object Store (BOS)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength;
+  uint8_t bDescriptorType ;
+  uint8_t bDevCapabilityType;
+  uint8_t bReserved;
+  uint8_t PlatformCapabilityUUID[16];
+  uint8_t CapabilityData[];
+} tusb_desc_bos_platform_t;
+
+// USB WebuSB URL Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength;
+  uint8_t bDescriptorType;
+  uint8_t bScheme;
+  char    url[];
+} tusb_desc_webusb_url_t;
+
+/*------------------------------------------------------------------*/
+/* Types
+ *------------------------------------------------------------------*/
+typedef struct TU_ATTR_PACKED{
+  union {
+    struct TU_ATTR_PACKED {
+      uint8_t recipient :  5; ///< Recipient type tusb_request_recipient_t.
+      uint8_t type      :  2; ///< Request type tusb_request_type_t.
+      uint8_t direction :  1; ///< Direction type. tusb_dir_t
+    } bmRequestType_bit;
+
+    uint8_t bmRequestType;
+  };
+
+  uint8_t  bRequest;
+  uint16_t wValue;
+  uint16_t wIndex;
+  uint16_t wLength;
+} tusb_control_request_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct");
+
+// TODO move to somewhere suitable
+static inline uint8_t bm_request_type(uint8_t direction, uint8_t type, uint8_t recipient)
+{
+  return ((uint8_t) (direction << 7)) | ((uint8_t) (type << 5)) | (recipient);
+}
+
+//--------------------------------------------------------------------+
+// Endpoint helper
+//--------------------------------------------------------------------+
+
+// Get direction from Endpoint address
+static inline tusb_dir_t tu_edpt_dir(uint8_t addr)
+{
+  return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+}
+
+// Get Endpoint number from address
+static inline uint8_t tu_edpt_number(uint8_t addr)
+{
+  return (uint8_t)(addr & (~TUSB_DIR_IN_MASK));
+}
+
+static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
+{
+  return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0));
+}
+
+//--------------------------------------------------------------------+
+// Descriptor helper
+//--------------------------------------------------------------------+
+static inline uint8_t const * tu_desc_next(void const* desc)
+{
+  uint8_t const* desc8 = (uint8_t const*) desc;
+  return desc8 + desc8[DESC_OFFSET_LEN];
+}
+
+static inline uint8_t tu_desc_type(void const* desc)
+{
+  return ((uint8_t const*) desc)[DESC_OFFSET_TYPE];
+}
+
+static inline uint8_t tu_desc_len(void const* desc)
+{
+  return ((uint8_t const*) desc)[DESC_OFFSET_LEN];
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+// from tinyusb_hid.h
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define TU_U16_HIGH(u16)      ((uint8_t) (((u16) >> 8) & 0x00ff))
+#define TU_U16_LOW(u16)       ((uint8_t) ((u16)       & 0x00ff))
+#define U16_TO_U8S_BE(u16)    TU_U16_HIGH(u16), TU_U16_LOW(u16)
+#define U16_TO_U8S_LE(u16)    TU_U16_LOW(u16), TU_U16_HIGH(u16)
+
+#ifndef TU_ATTR_PACKED
+#define TU_ATTR_PACKED __attribute__((packed))
+#endif
+#ifndef TU_BIT
+#define TU_BIT( x ) (1<<(x))
+#endif
+
+/* USB constant and structure define */
+
+/* USB PID */
+#ifndef USB_PID_SETUP
+  #define USB_PID_NULL     0x00  /* reserved PID */
+  #define USB_PID_SOF      0x05
+  #define USB_PID_SETUP    0x0D
+  #define USB_PID_IN       0x09
+  #define USB_PID_OUT      0x01
+  #define USB_PID_ACK      0x02
+  #define USB_PID_NAK      0x0A
+  #define USB_PID_STALL    0x0E
+  #define USB_PID_DATA0    0x03
+  #define USB_PID_DATA1    0x0B
+  #define USB_PID_PRE      0x0C
+#endif
+
+/* USB standard device request code */
+#ifndef USB_GET_DESCRIPTOR
+  #define USB_GET_STATUS           0x00
+  #define USB_CLEAR_FEATURE        0x01
+  #define USB_SET_FEATURE          0x03
+  #define USB_SET_ADDRESS          0x05
+  #define USB_GET_DESCRIPTOR       0x06
+  #define USB_SET_DESCRIPTOR       0x07
+  #define USB_GET_CONFIGURATION    0x08
+  #define USB_SET_CONFIGURATION    0x09
+  #define USB_GET_INTERFACE        0x0A
+  #define USB_SET_INTERFACE        0x0B
+  #define USB_SYNCH_FRAME          0x0C
+#endif
+
+/* USB hub class request code */
+#ifndef HUB_GET_DESCRIPTOR
+  #define HUB_GET_STATUS        0x00
+  #define HUB_CLEAR_FEATURE     0x01
+  #define HUB_GET_STATE         0x02
+  #define HUB_SET_FEATURE       0x03
+  #define HUB_GET_DESCRIPTOR    0x06
+  #define HUB_SET_DESCRIPTOR    0x07
+#endif
+
+/* USB HID class request code */
+#ifndef HID_GET_REPORT
+  #define HID_GET_REPORT      0x01
+  #define HID_GET_IDLE        0x02
+  #define HID_GET_PROTOCOL    0x03
+  #define HID_SET_REPORT      0x09
+  #define HID_SET_IDLE        0x0A
+  #define HID_SET_PROTOCOL    0x0B
+#endif
+
+/* USB CDC Class request code */
+#ifndef CDC_GET_LINE_CODING
+#define CDC_GET_LINE_CODING   0X21      /* This request allows the host to find out the currently configured line coding */
+#define CDC_SET_LINE_CODING   0x20      /* Configures DTE rate, stop-bits, parity, and number-of-character */
+#define CDC_SET_LINE_CTLSTE   0X22      /* This request generates RS-232/V.24 style control signals */
+#define CDC_SEND_BREAK        0X23      /* Sends special carrier modulation used to specify RS-232 style break */
+#endif
+
+/* Bit define for USB request type */
+#ifndef USB_REQ_TYP_MASK
+  #define USB_REQ_TYP_IN          0x80  /* control IN, device to host */
+  #define USB_REQ_TYP_OUT         0x00  /* control OUT, host to device */
+  #define USB_REQ_TYP_READ        0x80  /* control read, device to host */
+  #define USB_REQ_TYP_WRITE       0x00  /* control write, host to device */
+  #define USB_REQ_TYP_MASK        0x60  /* bit mask of request type */
+  #define USB_REQ_TYP_STANDARD    0x00
+  #define USB_REQ_TYP_CLASS       0x20
+  #define USB_REQ_TYP_VENDOR      0x40
+  #define USB_REQ_TYP_RESERVED    0x60
+  #define USB_REQ_RECIP_MASK      0x1F  /* bit mask of request recipient */
+  #define USB_REQ_RECIP_DEVICE    0x00
+  #define USB_REQ_RECIP_INTERF    0x01
+  #define USB_REQ_RECIP_ENDP      0x02
+  #define USB_REQ_RECIP_OTHER     0x03
+  #define USB_REQ_FEAT_REMOTE_WAKEUP  0x01
+  #define USB_REQ_FEAT_ENDP_HALT      0x00
+#endif
+
+/* USB request type for hub class request */
+#ifndef HUB_GET_HUB_DESCRIPTOR
+  #define HUB_CLEAR_HUB_FEATURE     0x20
+  #define HUB_CLEAR_PORT_FEATURE    0x23
+  #define HUB_GET_BUS_STATE         0xA3
+  #define HUB_GET_HUB_DESCRIPTOR    0xA0
+  #define HUB_GET_HUB_STATUS        0xA0
+  #define HUB_GET_PORT_STATUS       0xA3
+  #define HUB_SET_HUB_DESCRIPTOR    0x20
+  #define HUB_SET_HUB_FEATURE       0x20
+  #define HUB_SET_PORT_FEATURE      0x23
+#endif
+
+/* Hub class feature selectors */
+#ifndef HUB_PORT_RESET
+  #define HUB_C_HUB_LOCAL_POWER      0
+  #define HUB_C_HUB_OVER_CURRENT     1
+  #define HUB_PORT_CONNECTION        0
+  #define HUB_PORT_ENABLE            1
+  #define HUB_PORT_SUSPEND           2
+  #define HUB_PORT_OVER_CURRENT      3
+  #define HUB_PORT_RESET             4
+  #define HUB_PORT_POWER             8
+  #define HUB_PORT_LOW_SPEED         9
+  #define HUB_C_PORT_CONNECTION      16
+  #define HUB_C_PORT_ENABLE          17
+  #define HUB_C_PORT_SUSPEND         18
+  #define HUB_C_PORT_OVER_CURRENT    19
+  #define HUB_C_PORT_RESET           20
+#endif
+
+/* USB descriptor type */
+#ifndef USB_DESCR_TYP_DEVICE
+  #define USB_DESCR_TYP_DEVICE     0x01
+  #define USB_DESCR_TYP_CONFIG     0x02
+  #define USB_DESCR_TYP_STRING     0x03
+  #define USB_DESCR_TYP_INTERF     0x04
+  #define USB_DESCR_TYP_ENDP       0x05
+  #define USB_DESCR_TYP_QUALIF     0x06
+  #define USB_DESCR_TYP_SPEED      0x07
+  #define USB_DESCR_TYP_OTG        0x09
+  #define USB_DESCR_TYP_HID        0x21
+  #define USB_DESCR_TYP_REPORT     0x22
+  #define USB_DESCR_TYP_PHYSIC     0x23
+  #define USB_DESCR_TYP_CS_INTF    0x24
+  #define USB_DESCR_TYP_CS_ENDP    0x25
+  #define USB_DESCR_TYP_HUB        0x29
+#endif
+
+/* USB device class */
+#ifndef USB_DEV_CLASS_HUB
+  #define USB_DEV_CLASS_RESERVED     0x00
+  #define USB_DEV_CLASS_AUDIO        0x01
+  #define USB_DEV_CLASS_COMMUNIC     0x02
+  #define USB_DEV_CLASS_HID          0x03
+  #define USB_DEV_CLASS_MONITOR      0x04
+  #define USB_DEV_CLASS_PHYSIC_IF    0x05
+  #define USB_DEV_CLASS_IMAGE        0x06
+  #define USB_DEV_CLASS_PRINTER      0x07
+  #define USB_DEV_CLASS_STORAGE      0x08
+  #define USB_DEV_CLASS_HUB          0x09
+  #define USB_DEV_CLASS_VEN_SPEC     0xFF
+#endif
+
+/* USB endpoint type and attributes */
+#ifndef USB_ENDP_TYPE_MASK
+  #define USB_ENDP_DIR_MASK      0x80
+  #define USB_ENDP_ADDR_MASK     0x0F
+  #define USB_ENDP_TYPE_MASK     0x03
+  #define USB_ENDP_TYPE_CTRL     0x00
+  #define USB_ENDP_TYPE_ISOCH    0x01
+  #define USB_ENDP_TYPE_BULK     0x02
+  #define USB_ENDP_TYPE_INTER    0x03
+#endif
+
+#ifndef USB_DEVICE_ADDR
+  #define USB_DEVICE_ADDR    0x02
+#endif
+#ifndef DEFAULT_ENDP0_SIZE
+  #define DEFAULT_ENDP0_SIZE 8  /* default maximum packet size for endpoint 0 */
+#endif
+#ifndef MAX_PACKET_SIZE
+  #define MAX_PACKET_SIZE    64  /* maximum packet size */
+#endif
+#ifndef USB_BO_CBW_SIZE
+  #define USB_BO_CBW_SIZE    0x1F
+  #define USB_BO_CSW_SIZE    0x0D
+#endif
+#ifndef USB_BO_CBW_SIG0
+  #define USB_BO_CBW_SIG0    0x55
+  #define USB_BO_CBW_SIG1    0x53
+  #define USB_BO_CBW_SIG2    0x42
+  #define USB_BO_CBW_SIG3    0x43
+  #define USB_BO_CSW_SIG0    0x55
+  #define USB_BO_CSW_SIG1    0x53
+  #define USB_BO_CSW_SIG2    0x42
+  #define USB_BO_CSW_SIG3    0x53
+#endif
+
+#define DEF_STRING_DESC_LANG 0x00
+#define DEF_STRING_DESC_MANU 0x01
+#define DEF_STRING_DESC_PROD 0x02
+#define DEF_STRING_DESC_SERN 0x03
+
+
+//--------------------------------------------------------------------+
+// Common Definitions
+//--------------------------------------------------------------------+
+/** \defgroup ClassDriver_HID_Common Common Definitions
+ *  @{ */
+
+ /// USB HID Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength;         /**< Numeric expression that is the total size of the HID descriptor */
+  uint8_t  bDescriptorType; /**< Constant name specifying type of HID descriptor. */
+
+  uint16_t bcdHID;          /**< Numeric expression identifying the HID Class Specification release */
+  uint8_t  bCountryCode;    /**< Numeric expression identifying country code of the localized hardware.  */
+  uint8_t  bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */
+
+  uint8_t  bReportType;     /**< Type of HID class report. */
+  uint16_t wReportLength;   /**< the total size of the Report descriptor. */
+} tusb_hid_descriptor_hid_t;
+
+/// HID Subclass
+typedef enum
+{
+  HID_SUBCLASS_NONE = 0, ///< No Subclass
+  HID_SUBCLASS_BOOT = 1  ///< Boot Interface Subclass
+}hid_subclass_type_t;
+
+/// HID Protocol
+typedef enum
+{
+  HID_PROTOCOL_NONE     = 0, ///< None
+  HID_PROTOCOL_KEYBOARD = 1, ///< Keyboard
+  HID_PROTOCOL_MOUSE    = 2  ///< Mouse
+}hid_protocol_type_t;
+
+/// HID Descriptor Type
+typedef enum
+{
+  HID_DESC_TYPE_HID      = 0x21, ///< HID Descriptor
+  HID_DESC_TYPE_REPORT   = 0x22, ///< Report Descriptor
+  HID_DESC_TYPE_PHYSICAL = 0x23  ///< Physical Descriptor
+}hid_descriptor_type_t;
+
+/// HID Request Report Type
+typedef enum
+{
+  HID_REPORT_TYPE_INVALID = 0,
+  HID_REPORT_TYPE_INPUT,      ///< Input
+  HID_REPORT_TYPE_OUTPUT,     ///< Output
+  HID_REPORT_TYPE_FEATURE     ///< Feature
+}hid_report_type_t;
+
+/// HID Class Specific Control Request
+typedef enum
+{
+  HID_REQ_CONTROL_GET_REPORT   = 0x01, ///< Get Report
+  HID_REQ_CONTROL_GET_IDLE     = 0x02, ///< Get Idle
+  HID_REQ_CONTROL_GET_PROTOCOL = 0x03, ///< Get Protocol
+  HID_REQ_CONTROL_SET_REPORT   = 0x09, ///< Set Report
+  HID_REQ_CONTROL_SET_IDLE     = 0x0a, ///< Set Idle
+  HID_REQ_CONTROL_SET_PROTOCOL = 0x0b  ///< Set Protocol
+}hid_request_type_t;
+
+/// HID Country Code
+typedef enum
+{
+  HID_LOCAL_NotSupported = 0   , ///< NotSupported
+  HID_LOCAL_Arabic             , ///< Arabic
+  HID_LOCAL_Belgian            , ///< Belgian
+  HID_LOCAL_Canadian_Bilingual , ///< Canadian_Bilingual
+  HID_LOCAL_Canadian_French    , ///< Canadian_French
+  HID_LOCAL_Czech_Republic     , ///< Czech_Republic
+  HID_LOCAL_Danish             , ///< Danish
+  HID_LOCAL_Finnish            , ///< Finnish
+  HID_LOCAL_French             , ///< French
+  HID_LOCAL_German             , ///< German
+  HID_LOCAL_Greek              , ///< Greek
+  HID_LOCAL_Hebrew             , ///< Hebrew
+  HID_LOCAL_Hungary            , ///< Hungary
+  HID_LOCAL_International      , ///< International
+  HID_LOCAL_Italian            , ///< Italian
+  HID_LOCAL_Japan_Katakana     , ///< Japan_Katakana
+  HID_LOCAL_Korean             , ///< Korean
+  HID_LOCAL_Latin_American     , ///< Latin_American
+  HID_LOCAL_Netherlands_Dutch  , ///< Netherlands/Dutch
+  HID_LOCAL_Norwegian          , ///< Norwegian
+  HID_LOCAL_Persian_Farsi      , ///< Persian (Farsi)
+  HID_LOCAL_Poland             , ///< Poland
+  HID_LOCAL_Portuguese         , ///< Portuguese
+  HID_LOCAL_Russia             , ///< Russia
+  HID_LOCAL_Slovakia           , ///< Slovakia
+  HID_LOCAL_Spanish            , ///< Spanish
+  HID_LOCAL_Swedish            , ///< Swedish
+  HID_LOCAL_Swiss_French       , ///< Swiss/French
+  HID_LOCAL_Swiss_German       , ///< Swiss/German
+  HID_LOCAL_Switzerland        , ///< Switzerland
+  HID_LOCAL_Taiwan             , ///< Taiwan
+  HID_LOCAL_Turkish_Q          , ///< Turkish-Q
+  HID_LOCAL_UK                 , ///< UK
+  HID_LOCAL_US                 , ///< US
+  HID_LOCAL_Yugoslavia         , ///< Yugoslavia
+  HID_LOCAL_Turkish_F            ///< Turkish-F
+} hid_country_code_t;
+
+/** @} */
+
+//--------------------------------------------------------------------+
+// GAMEPAD
+//--------------------------------------------------------------------+
+/** \addtogroup ClassDriver_HID_Gamepad Gamepad
+ *  @{ */
+
+/* From https://www.kernel.org/doc/html/latest/input/gamepad.html
+          ____________________________              __
+         / [__ZL__]          [__ZR__] \               |
+        / [__ TL __]        [__ TR __] \              | Front Triggers
+     __/________________________________\__         __|
+    /                                  _   \          |
+   /      /\           __             (N)   \         |
+  /       ||      __  |MO|  __     _       _ \        | Main Pad
+ |    <===DP===> |SE|      |ST|   (W) -|- (E) |       |
+  \       ||    ___          ___       _     /        |
+  /\      \/   /   \        /   \     (S)   /\      __|
+ /  \________ | LS  | ____ |  RS | ________/  \       |
+|         /  \ \___/ /    \ \___/ /  \         |      | Control Sticks
+|        /    \_____/      \_____/    \        |    __|
+|       /                              \       |
+ \_____/                                \_____/
+
+     |________|______|    |______|___________|
+       D-Pad    Left       Right   Action Pad
+               Stick       Stick
+
+                 |_____________|
+                    Menu Pad
+
+  Most gamepads have the following features:
+  - Action-Pad 4 buttons in diamonds-shape (on the right side) NORTH, SOUTH, WEST and EAST.
+  - D-Pad (Direction-pad) 4 buttons (on the left side) that point up, down, left and right.
+  - Menu-Pad Different constellations, but most-times 2 buttons: SELECT - START.
+  - Analog-Sticks provide freely moveable sticks to control directions, Analog-sticks may also
+  provide a digital button if you press them.
+  - Triggers are located on the upper-side of the pad in vertical direction. The upper buttons
+  are normally named Left- and Right-Triggers, the lower buttons Z-Left and Z-Right.
+  - Rumble Many devices provide force-feedback features. But are mostly just simple rumble motors.
+ */
+
+/// HID Gamepad Protocol Report.
+typedef struct TU_ATTR_PACKED
+{
+  int8_t  x;         ///< Delta x  movement of left analog-stick
+  int8_t  y;         ///< Delta y  movement of left analog-stick
+  int8_t  z;         ///< Delta z  movement of right analog-joystick
+  int8_t  rz;        ///< Delta Rz movement of right analog-joystick
+  int8_t  rx;        ///< Delta Rx movement of analog left trigger
+  int8_t  ry;        ///< Delta Ry movement of analog right trigger
+  uint8_t hat;       ///< Buttons mask for currently pressed buttons in the DPad/hat
+  uint16_t buttons;  ///< Buttons mask for currently pressed buttons
+}hid_gamepad_report_t;
+
+/// HID Switch Gamepad Protocol Report.
+typedef struct TU_ATTR_PACKED
+{
+  uint16_t buttons;  ///< Buttons mask for currently pressed buttons
+  uint8_t hat;       ///< Buttons mask for currently pressed buttons in the DPad/hat
+  int8_t  x;         ///< Delta x  movement of left analog-stick
+  int8_t  y;         ///< Delta y  movement of left analog-stick
+  int8_t  rx;        ///< Delta Rx movement of analog left trigger
+  int8_t  ry;        ///< Delta Ry movement of analog right trigger
+  int8_t  z;         ///< Delta z  movement of right analog-joystick
+  int8_t  rz;        ///< Delta Rz movement of right analog-joystick
+}hid_gamepad_ns_report_t;
+
+/// Standard Gamepad Buttons Bitmap (from Linux input event codes)
+typedef enum
+{
+  GAMEPAD_BUTTON_A      = TU_BIT(0),  ///< A/South button
+  GAMEPAD_BUTTON_B      = TU_BIT(1),  ///< B/East button
+  GAMEPAD_BUTTON_C      = TU_BIT(2),  ///< C button
+  GAMEPAD_BUTTON_X      = TU_BIT(3),  ///< X/North button
+  GAMEPAD_BUTTON_Y      = TU_BIT(4),  ///< Y/West button
+  GAMEPAD_BUTTON_Z      = TU_BIT(5),  ///< Z button
+  GAMEPAD_BUTTON_TL     = TU_BIT(6),  ///< L1 button
+  GAMEPAD_BUTTON_TR     = TU_BIT(7),  ///< R1 button
+  GAMEPAD_BUTTON_TL2    = TU_BIT(8),  ///< L2 button
+  GAMEPAD_BUTTON_TR2    = TU_BIT(9),  ///< R2 button
+  GAMEPAD_BUTTON_SELECT = TU_BIT(10), ///< Select button
+  GAMEPAD_BUTTON_START  = TU_BIT(11), ///< Start button
+  GAMEPAD_BUTTON_MODE   = TU_BIT(12), ///< Mode button
+  GAMEPAD_BUTTON_THUMBL = TU_BIT(13), ///< L3 button
+  GAMEPAD_BUTTON_THUMBR = TU_BIT(14), ///< R3 button
+//GAMEPAD_BUTTON_       = TU_BIT(15), ///< Undefined button
+}hid_gamepad_button_bm_t;
+
+/// Switch Gamepad Buttons Bitmap
+typedef enum
+{
+  GAMEPAD_NS_BUTTON_Y       = 0x01,
+  GAMEPAD_NS_BUTTON_B       = 0x02,
+  GAMEPAD_NS_BUTTON_A       = 0x04,
+  GAMEPAD_NS_BUTTON_X       = 0x08,
+  GAMEPAD_NS_BUTTON_TL      = 0x10,
+  GAMEPAD_NS_BUTTON_TR      = 0x20,
+  GAMEPAD_NS_BUTTON_TL2     = 0x40,
+  GAMEPAD_NS_BUTTON_TR2     = 0x80,
+  GAMEPAD_NS_BUTTON_MINUS   = 0x100,
+  GAMEPAD_NS_BUTTON_PLUS    = 0x200,
+  GAMEPAD_NS_BUTTON_THUMBL  = 0x400,
+  GAMEPAD_NS_BUTTON_THUMBR  = 0x800,
+  GAMEPAD_NS_BUTTON_HOME    = 0x1000,
+  GAMEPAD_NS_BUTTON_CAPTURE = 0x2000,
+  GAMEPAD_NS_BUTTON_Z       = 0x4000, ///UNUSED?
+}hid_gamepad_ns_button_bm_t;
+
+/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes)
+typedef enum
+{
+  GAMEPAD_HAT_CENTERED   = 0,  ///< DPAD_CENTERED
+  GAMEPAD_HAT_UP         = 1,  ///< DPAD_UP
+  GAMEPAD_HAT_UP_RIGHT   = 2,  ///< DPAD_UP_RIGHT
+  GAMEPAD_HAT_RIGHT      = 3,  ///< DPAD_RIGHT
+  GAMEPAD_HAT_DOWN_RIGHT = 4,  ///< DPAD_DOWN_RIGHT
+  GAMEPAD_HAT_DOWN       = 5,  ///< DPAD_DOWN
+  GAMEPAD_HAT_DOWN_LEFT  = 6,  ///< DPAD_DOWN_LEFT
+  GAMEPAD_HAT_LEFT       = 7,  ///< DPAD_LEFT
+  GAMEPAD_HAT_UP_LEFT    = 8,  ///< DPAD_UP_LEFT
+}hid_gamepad_hat_t;
+
+/// Switch Gamepad HAT/DPAD Buttons (from Linux input event codes)
+typedef enum
+{
+  GAMEPAD_NS_HAT_CENTERED   = 8,  ///< DPAD_CENTERED
+  GAMEPAD_NS_HAT_UP         = 0,  ///< DPAD_UP
+  GAMEPAD_NS_HAT_UP_RIGHT   = 1,  ///< DPAD_UP_RIGHT
+  GAMEPAD_NS_HAT_RIGHT      = 2,  ///< DPAD_RIGHT
+  GAMEPAD_NS_HAT_DOWN_RIGHT = 3,  ///< DPAD_DOWN_RIGHT
+  GAMEPAD_NS_HAT_DOWN       = 4,  ///< DPAD_DOWN
+  GAMEPAD_NS_HAT_DOWN_LEFT  = 5,  ///< DPAD_DOWN_LEFT
+  GAMEPAD_NS_HAT_LEFT       = 6,  ///< DPAD_LEFT
+  GAMEPAD_NS_HAT_UP_LEFT    = 7,  ///< DPAD_UP_LEFT
+}hid_gamepad_ns_hat_t;
+
+/// @}
+
+//--------------------------------------------------------------------+
+// MOUSE
+//--------------------------------------------------------------------+
+/** \addtogroup ClassDriver_HID_Mouse Mouse
+ *  @{ */
+
+/// Standard HID Boot Protocol Mouse Report.
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */
+  int8_t  x;       /**< Current delta x movement of the mouse. */
+  int8_t  y;       /**< Current delta y movement on the mouse. */
+  int8_t  wheel;   /**< Current delta wheel movement on the mouse. */
+  int8_t  pan;     // using AC Pan
+} hid_mouse_report_t;
+
+/// Standard Mouse Buttons Bitmap
+typedef enum
+{
+  MOUSE_BUTTON_LEFT     = TU_BIT(0), ///< Left button
+  MOUSE_BUTTON_RIGHT    = TU_BIT(1), ///< Right button
+  MOUSE_BUTTON_MIDDLE   = TU_BIT(2), ///< Middle button
+  MOUSE_BUTTON_BACKWARD = TU_BIT(3), ///< Backward button,
+  MOUSE_BUTTON_FORWARD  = TU_BIT(4), ///< Forward button,
+}hid_mouse_button_bm_t;
+
+/// @}
+
+//--------------------------------------------------------------------+
+// Keyboard
+//--------------------------------------------------------------------+
+/** \addtogroup ClassDriver_HID_Keyboard Keyboard
+ *  @{ */
+
+/// Standard HID Boot Protocol Keyboard Report.
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t modifier;   /**< Keyboard modifier (KEYBOARD_MODIFIER_* masks). */
+  uint8_t reserved;   /**< Reserved for OEM use, always set to 0. */
+  uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */
+} hid_keyboard_report_t;
+
+/// Keyboard modifier codes bitmap
+typedef enum
+{
+  KEYBOARD_MODIFIER_LEFTCTRL   = TU_BIT(0), ///< Left Control
+  KEYBOARD_MODIFIER_LEFTSHIFT  = TU_BIT(1), ///< Left Shift
+  KEYBOARD_MODIFIER_LEFTALT    = TU_BIT(2), ///< Left Alt
+  KEYBOARD_MODIFIER_LEFTGUI    = TU_BIT(3), ///< Left Window
+  KEYBOARD_MODIFIER_RIGHTCTRL  = TU_BIT(4), ///< Right Control
+  KEYBOARD_MODIFIER_RIGHTSHIFT = TU_BIT(5), ///< Right Shift
+  KEYBOARD_MODIFIER_RIGHTALT   = TU_BIT(6), ///< Right Alt
+  KEYBOARD_MODIFIER_RIGHTGUI   = TU_BIT(7)  ///< Right Window
+}hid_keyboard_modifier_bm_t;
+
+typedef enum
+{
+  KEYBOARD_LED_NUMLOCK    = TU_BIT(0), ///< Num Lock LED
+  KEYBOARD_LED_CAPSLOCK   = TU_BIT(1), ///< Caps Lock LED
+  KEYBOARD_LED_SCROLLLOCK = TU_BIT(2), ///< Scroll Lock LED
+  KEYBOARD_LED_COMPOSE    = TU_BIT(3), ///< Composition Mode
+  KEYBOARD_LED_KANA       = TU_BIT(4) ///< Kana mode
+}hid_keyboard_led_bm_t;
+
+/// @}
+
+//--------------------------------------------------------------------+
+// HID KEYCODE
+//--------------------------------------------------------------------+
+#define HID_KEY_NONE                      0x00
+#define HID_KEY_A                         0x04
+#define HID_KEY_B                         0x05
+#define HID_KEY_C                         0x06
+#define HID_KEY_D                         0x07
+#define HID_KEY_E                         0x08
+#define HID_KEY_F                         0x09
+#define HID_KEY_G                         0x0A
+#define HID_KEY_H                         0x0B
+#define HID_KEY_I                         0x0C
+#define HID_KEY_J                         0x0D
+#define HID_KEY_K                         0x0E
+#define HID_KEY_L                         0x0F
+#define HID_KEY_M                         0x10
+#define HID_KEY_N                         0x11
+#define HID_KEY_O                         0x12
+#define HID_KEY_P                         0x13
+#define HID_KEY_Q                         0x14
+#define HID_KEY_R                         0x15
+#define HID_KEY_S                         0x16
+#define HID_KEY_T                         0x17
+#define HID_KEY_U                         0x18
+#define HID_KEY_V                         0x19
+#define HID_KEY_W                         0x1A
+#define HID_KEY_X                         0x1B
+#define HID_KEY_Y                         0x1C
+#define HID_KEY_Z                         0x1D
+#define HID_KEY_1                         0x1E
+#define HID_KEY_2                         0x1F
+#define HID_KEY_3                         0x20
+#define HID_KEY_4                         0x21
+#define HID_KEY_5                         0x22
+#define HID_KEY_6                         0x23
+#define HID_KEY_7                         0x24
+#define HID_KEY_8                         0x25
+#define HID_KEY_9                         0x26
+#define HID_KEY_0                         0x27
+#define HID_KEY_ENTER                     0x28
+#define HID_KEY_ESCAPE                    0x29
+#define HID_KEY_BACKSPACE                 0x2A
+#define HID_KEY_TAB                       0x2B
+#define HID_KEY_SPACE                     0x2C
+#define HID_KEY_MINUS                     0x2D
+#define HID_KEY_EQUAL                     0x2E
+#define HID_KEY_BRACKET_LEFT              0x2F
+#define HID_KEY_BRACKET_RIGHT             0x30
+#define HID_KEY_BACKSLASH                 0x31
+#define HID_KEY_EUROPE_1                  0x32
+#define HID_KEY_SEMICOLON                 0x33
+#define HID_KEY_APOSTROPHE                0x34
+#define HID_KEY_GRAVE                     0x35
+#define HID_KEY_COMMA                     0x36
+#define HID_KEY_PERIOD                    0x37
+#define HID_KEY_SLASH                     0x38
+#define HID_KEY_CAPS_LOCK                 0x39
+#define HID_KEY_F1                        0x3A
+#define HID_KEY_F2                        0x3B
+#define HID_KEY_F3                        0x3C
+#define HID_KEY_F4                        0x3D
+#define HID_KEY_F5                        0x3E
+#define HID_KEY_F6                        0x3F
+#define HID_KEY_F7                        0x40
+#define HID_KEY_F8                        0x41
+#define HID_KEY_F9                        0x42
+#define HID_KEY_F10                       0x43
+#define HID_KEY_F11                       0x44
+#define HID_KEY_F12                       0x45
+#define HID_KEY_PRINT_SCREEN              0x46
+#define HID_KEY_SCROLL_LOCK               0x47
+#define HID_KEY_PAUSE                     0x48
+#define HID_KEY_INSERT                    0x49
+#define HID_KEY_HOME                      0x4A
+#define HID_KEY_PAGE_UP                   0x4B
+#define HID_KEY_DELETE                    0x4C
+#define HID_KEY_END                       0x4D
+#define HID_KEY_PAGE_DOWN                 0x4E
+#define HID_KEY_ARROW_RIGHT               0x4F
+#define HID_KEY_ARROW_LEFT                0x50
+#define HID_KEY_ARROW_DOWN                0x51
+#define HID_KEY_ARROW_UP                  0x52
+#define HID_KEY_NUM_LOCK                  0x53
+#define HID_KEY_KEYPAD_DIVIDE             0x54
+#define HID_KEY_KEYPAD_MULTIPLY           0x55
+#define HID_KEY_KEYPAD_SUBTRACT           0x56
+#define HID_KEY_KEYPAD_ADD                0x57
+#define HID_KEY_KEYPAD_ENTER              0x58
+#define HID_KEY_KEYPAD_1                  0x59
+#define HID_KEY_KEYPAD_2                  0x5A
+#define HID_KEY_KEYPAD_3                  0x5B
+#define HID_KEY_KEYPAD_4                  0x5C
+#define HID_KEY_KEYPAD_5                  0x5D
+#define HID_KEY_KEYPAD_6                  0x5E
+#define HID_KEY_KEYPAD_7                  0x5F
+#define HID_KEY_KEYPAD_8                  0x60
+#define HID_KEY_KEYPAD_9                  0x61
+#define HID_KEY_KEYPAD_0                  0x62
+#define HID_KEY_KEYPAD_DECIMAL            0x63
+#define HID_KEY_EUROPE_2                  0x64
+#define HID_KEY_APPLICATION               0x65
+#define HID_KEY_POWER                     0x66
+#define HID_KEY_KEYPAD_EQUAL              0x67
+#define HID_KEY_F13                       0x68
+#define HID_KEY_F14                       0x69
+#define HID_KEY_F15                       0x6A
+#define HID_KEY_F16                       0x6B
+#define HID_KEY_F17                       0x6C
+#define HID_KEY_F18                       0x6D
+#define HID_KEY_F19                       0x6E
+#define HID_KEY_F20                       0x6F
+#define HID_KEY_F21                       0x70
+#define HID_KEY_F22                       0x71
+#define HID_KEY_F23                       0x72
+#define HID_KEY_F24                       0x73
+#define HID_KEY_EXECUTE                   0x74
+#define HID_KEY_HELP                      0x75
+#define HID_KEY_MENU                      0x76
+#define HID_KEY_SELECT                    0x77
+#define HID_KEY_STOP                      0x78
+#define HID_KEY_AGAIN                     0x79
+#define HID_KEY_UNDO                      0x7A
+#define HID_KEY_CUT                       0x7B
+#define HID_KEY_COPY                      0x7C
+#define HID_KEY_PASTE                     0x7D
+#define HID_KEY_FIND                      0x7E
+#define HID_KEY_MUTE                      0x7F
+#define HID_KEY_VOLUME_UP                 0x80
+#define HID_KEY_VOLUME_DOWN               0x81
+#define HID_KEY_LOCKING_CAPS_LOCK         0x82
+#define HID_KEY_LOCKING_NUM_LOCK          0x83
+#define HID_KEY_LOCKING_SCROLL_LOCK       0x84
+#define HID_KEY_KEYPAD_COMMA              0x85
+#define HID_KEY_KEYPAD_EQUAL_SIGN         0x86
+#define HID_KEY_KANJI1                    0x87
+#define HID_KEY_KANJI2                    0x88
+#define HID_KEY_KANJI3                    0x89
+#define HID_KEY_KANJI4                    0x8A
+#define HID_KEY_KANJI5                    0x8B
+#define HID_KEY_KANJI6                    0x8C
+#define HID_KEY_KANJI7                    0x8D
+#define HID_KEY_KANJI8                    0x8E
+#define HID_KEY_KANJI9                    0x8F
+#define HID_KEY_LANG1                     0x90
+#define HID_KEY_LANG2                     0x91
+#define HID_KEY_LANG3                     0x92
+#define HID_KEY_LANG4                     0x93
+#define HID_KEY_LANG5                     0x94
+#define HID_KEY_LANG6                     0x95
+#define HID_KEY_LANG7                     0x96
+#define HID_KEY_LANG8                     0x97
+#define HID_KEY_LANG9                     0x98
+#define HID_KEY_ALTERNATE_ERASE           0x99
+#define HID_KEY_SYSREQ_ATTENTION          0x9A
+#define HID_KEY_CANCEL                    0x9B
+#define HID_KEY_CLEAR                     0x9C
+#define HID_KEY_PRIOR                     0x9D
+#define HID_KEY_RETURN                    0x9E
+#define HID_KEY_SEPARATOR                 0x9F
+#define HID_KEY_OUT                       0xA0
+#define HID_KEY_OPER                      0xA1
+#define HID_KEY_CLEAR_AGAIN               0xA2
+#define HID_KEY_CRSEL_PROPS               0xA3
+#define HID_KEY_EXSEL                     0xA4
+// RESERVED					                      0xA5-DF
+#define HID_KEY_CONTROL_LEFT              0xE0
+#define HID_KEY_SHIFT_LEFT                0xE1
+#define HID_KEY_ALT_LEFT                  0xE2
+#define HID_KEY_GUI_LEFT                  0xE3
+#define HID_KEY_CONTROL_RIGHT             0xE4
+#define HID_KEY_SHIFT_RIGHT               0xE5
+#define HID_KEY_ALT_RIGHT                 0xE6
+#define HID_KEY_GUI_RIGHT                 0xE7
+
+
+//--------------------------------------------------------------------+
+// REPORT DESCRIPTOR
+//--------------------------------------------------------------------+
+//------------- ITEM & TAG -------------//
+#define HID_REPORT_DATA_0(data)
+#define HID_REPORT_DATA_1(data) , data
+#define HID_REPORT_DATA_2(data) , U16_TO_U8S_LE(data)
+#define HID_REPORT_DATA_3(data) , U32_TO_U8S_LE(data)
+
+#define HID_REPORT_ITEM(data, tag, type, size) \
+  (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data)
+
+#define RI_TYPE_MAIN   0
+#define RI_TYPE_GLOBAL 1
+#define RI_TYPE_LOCAL  2
+
+//------------- MAIN ITEMS 6.2.2.4 -------------//
+#define HID_INPUT(x)           HID_REPORT_ITEM(x,  8, RI_TYPE_MAIN, 1)
+#define HID_OUTPUT(x)          HID_REPORT_ITEM(x,  9, RI_TYPE_MAIN, 1)
+#define HID_COLLECTION(x)      HID_REPORT_ITEM(x, 10, RI_TYPE_MAIN, 1)
+#define HID_FEATURE(x)         HID_REPORT_ITEM(x, 11, RI_TYPE_MAIN, 1)
+#define HID_COLLECTION_END     HID_REPORT_ITEM(x, 12, RI_TYPE_MAIN, 0)
+
+//------------- INPUT, OUTPUT, FEATURE 6.2.2.5 -------------//
+#define HID_DATA             (0<<0)
+#define HID_CONSTANT         (1<<0)
+
+#define HID_ARRAY            (0<<1)
+#define HID_VARIABLE         (1<<1)
+
+#define HID_ABSOLUTE         (0<<2)
+#define HID_RELATIVE         (1<<2)
+
+#define HID_WRAP_NO          (0<<3)
+#define HID_WRAP             (1<<3)
+
+#define HID_LINEAR           (0<<4)
+#define HID_NONLINEAR        (1<<4)
+
+#define HID_PREFERRED_STATE  (0<<5)
+#define HID_PREFERRED_NO     (1<<5)
+
+#define HID_NO_NULL_POSITION (0<<6)
+#define HID_NULL_STATE       (1<<6)
+
+#define HID_NON_VOLATILE     (0<<7)
+#define HID_VOLATILE         (1<<7)
+
+#define HID_BITFIELD         (0<<8)
+#define HID_BUFFERED_BYTES   (1<<8)
+
+//------------- COLLECTION ITEM 6.2.2.6 -------------//
+enum {
+  HID_COLLECTION_PHYSICAL = 0,
+  HID_COLLECTION_APPLICATION,
+  HID_COLLECTION_LOGICAL,
+  HID_COLLECTION_REPORT,
+  HID_COLLECTION_NAMED_ARRAY,
+  HID_COLLECTION_USAGE_SWITCH,
+  HID_COLLECTION_USAGE_MODIFIER
+};
+
+//------------- GLOBAL ITEMS 6.2.2.7 -------------//
+#define HID_USAGE_PAGE(x)         HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, 1)
+#define HID_USAGE_PAGE_N(x, n)    HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, n)
+
+#define HID_LOGICAL_MIN(x)        HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, 1)
+#define HID_LOGICAL_MIN_N(x, n)   HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, n)
+
+#define HID_LOGICAL_MAX(x)        HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, 1)
+#define HID_LOGICAL_MAX_N(x, n)   HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, n)
+
+#define HID_PHYSICAL_MIN(x)       HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, 1)
+#define HID_PHYSICAL_MIN_N(x, n)  HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, n)
+
+#define HID_PHYSICAL_MAX(x)       HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, 1)
+#define HID_PHYSICAL_MAX_N(x, n)  HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, n)
+
+#define HID_UNIT_EXPONENT(x)      HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, 1)
+#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, n)
+
+#define HID_UNIT(x)               HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, 1)
+#define HID_UNIT_N(x, n)          HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, n)
+
+#define HID_REPORT_SIZE(x)        HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, 1)
+#define HID_REPORT_SIZE_N(x, n)   HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, n)
+
+#define HID_REPORT_ID(x)          HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, 1),
+#define HID_REPORT_ID_N(x)        HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, n),
+
+#define HID_REPORT_COUNT(x)       HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, 1)
+#define HID_REPORT_COUNT_N(x, n)  HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, n)
+
+#define HID_PUSH                  HID_REPORT_ITEM(x, 10, RI_TYPE_GLOBAL, 0)
+#define HID_POP                   HID_REPORT_ITEM(x, 11, RI_TYPE_GLOBAL, 0)
+
+//------------- LOCAL ITEMS 6.2.2.8 -------------//
+#define HID_USAGE(x)              HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, 1)
+#define HID_USAGE_N(x, n)         HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, n)
+
+#define HID_USAGE_MIN(x)          HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, 1)
+#define HID_USAGE_MIN_N(x, n)     HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, n)
+
+#define HID_USAGE_MAX(x)          HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, 1)
+#define HID_USAGE_MAX_N(x, n)     HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, n)
+
+//--------------------------------------------------------------------+
+// Usage Table
+//--------------------------------------------------------------------+
+
+/// HID Usage Table - Table 1: Usage Page Summary
+enum {
+  HID_USAGE_PAGE_DESKTOP         = 0x01,
+  HID_USAGE_PAGE_SIMULATE        = 0x02,
+  HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03,
+  HID_USAGE_PAGE_SPORT           = 0x04,
+  HID_USAGE_PAGE_GAME            = 0x05,
+  HID_USAGE_PAGE_GENERIC_DEVICE  = 0x06,
+  HID_USAGE_PAGE_KEYBOARD        = 0x07,
+  HID_USAGE_PAGE_LED             = 0x08,
+  HID_USAGE_PAGE_BUTTON          = 0x09,
+  HID_USAGE_PAGE_ORDINAL         = 0x0a,
+  HID_USAGE_PAGE_TELEPHONY       = 0x0b,
+  HID_USAGE_PAGE_CONSUMER        = 0x0c,
+  HID_USAGE_PAGE_DIGITIZER       = 0x0d,
+  HID_USAGE_PAGE_PID             = 0x0f,
+  HID_USAGE_PAGE_UNICODE         = 0x10,
+  HID_USAGE_PAGE_ALPHA_DISPLAY   = 0x14,
+  HID_USAGE_PAGE_MEDICAL         = 0x40,
+  HID_USAGE_PAGE_MONITOR         = 0x80, //0x80 - 0x83
+  HID_USAGE_PAGE_POWER           = 0x84, // 0x084 - 0x87
+  HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c,
+  HID_USAGE_PAGE_SCALE           = 0x8d,
+  HID_USAGE_PAGE_MSR             = 0x8e,
+  HID_USAGE_PAGE_CAMERA          = 0x90,
+  HID_USAGE_PAGE_ARCADE          = 0x91,
+  HID_USAGE_PAGE_VENDOR          = 0xFF00 // 0xFF00 - 0xFFFF
+};
+
+/// HID Usage Table - Table 6: Generic Desktop Page
+enum {
+  HID_USAGE_DESKTOP_POINTER                               = 0x01,
+  HID_USAGE_DESKTOP_MOUSE                                 = 0x02,
+  HID_USAGE_DESKTOP_JOYSTICK                              = 0x04,
+  HID_USAGE_DESKTOP_GAMEPAD                               = 0x05,
+  HID_USAGE_DESKTOP_KEYBOARD                              = 0x06,
+  HID_USAGE_DESKTOP_KEYPAD                                = 0x07,
+  HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER                 = 0x08,
+  HID_USAGE_DESKTOP_TABLET_PC_SYSTEM                      = 0x09,
+  HID_USAGE_DESKTOP_X                                     = 0x30,
+  HID_USAGE_DESKTOP_Y                                     = 0x31,
+  HID_USAGE_DESKTOP_Z                                     = 0x32,
+  HID_USAGE_DESKTOP_RX                                    = 0x33,
+  HID_USAGE_DESKTOP_RY                                    = 0x34,
+  HID_USAGE_DESKTOP_RZ                                    = 0x35,
+  HID_USAGE_DESKTOP_SLIDER                                = 0x36,
+  HID_USAGE_DESKTOP_DIAL                                  = 0x37,
+  HID_USAGE_DESKTOP_WHEEL                                 = 0x38,
+  HID_USAGE_DESKTOP_HAT_SWITCH                            = 0x39,
+  HID_USAGE_DESKTOP_COUNTED_BUFFER                        = 0x3a,
+  HID_USAGE_DESKTOP_BYTE_COUNT                            = 0x3b,
+  HID_USAGE_DESKTOP_MOTION_WAKEUP                         = 0x3c,
+  HID_USAGE_DESKTOP_START                                 = 0x3d,
+  HID_USAGE_DESKTOP_SELECT                                = 0x3e,
+  HID_USAGE_DESKTOP_VX                                    = 0x40,
+  HID_USAGE_DESKTOP_VY                                    = 0x41,
+  HID_USAGE_DESKTOP_VZ                                    = 0x42,
+  HID_USAGE_DESKTOP_VBRX                                  = 0x43,
+  HID_USAGE_DESKTOP_VBRY                                  = 0x44,
+  HID_USAGE_DESKTOP_VBRZ                                  = 0x45,
+  HID_USAGE_DESKTOP_VNO                                   = 0x46,
+  HID_USAGE_DESKTOP_FEATURE_NOTIFICATION                  = 0x47,
+  HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER                 = 0x48,
+  HID_USAGE_DESKTOP_SYSTEM_CONTROL                        = 0x80,
+  HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN                     = 0x81,
+  HID_USAGE_DESKTOP_SYSTEM_SLEEP                          = 0x82,
+  HID_USAGE_DESKTOP_SYSTEM_WAKE_UP                        = 0x83,
+  HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU                   = 0x84,
+  HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU                      = 0x85,
+  HID_USAGE_DESKTOP_SYSTEM_APP_MENU                       = 0x86,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_HELP                      = 0x87,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT                      = 0x88,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT                    = 0x89,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT                     = 0x8A,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT                      = 0x8B,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_UP                        = 0x8C,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN                      = 0x8D,
+  HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART                   = 0x8E,
+  HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART                   = 0x8F,
+  HID_USAGE_DESKTOP_DPAD_UP                               = 0x90,
+  HID_USAGE_DESKTOP_DPAD_DOWN                             = 0x91,
+  HID_USAGE_DESKTOP_DPAD_RIGHT                            = 0x92,
+  HID_USAGE_DESKTOP_DPAD_LEFT                             = 0x93,
+  HID_USAGE_DESKTOP_SYSTEM_DOCK                           = 0xA0,
+  HID_USAGE_DESKTOP_SYSTEM_UNDOCK                         = 0xA1,
+  HID_USAGE_DESKTOP_SYSTEM_SETUP                          = 0xA2,
+  HID_USAGE_DESKTOP_SYSTEM_BREAK                          = 0xA3,
+  HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK                 = 0xA4,
+  HID_USAGE_DESKTOP_APPLICATION_BREAK                     = 0xA5,
+  HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK            = 0xA6,
+  HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE                   = 0xA7,
+  HID_USAGE_DESKTOP_SYSTEM_HIBERNATE                      = 0xA8,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT                 = 0xB0,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL               = 0xB1,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL               = 0xB2,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH                   = 0xB3,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL                   = 0xB4,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT         = 0xB5,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE          = 0xB7
+};
+
+
+/// HID Usage Table: Consumer Page (0x0C)
+/// Only contains controls that supported by Windows (whole list is too long)
+enum
+{
+  // Generic Control
+  HID_USAGE_CONSUMER_CONTROL                           = 0x0001,
+
+  // Power Control
+  HID_USAGE_CONSUMER_POWER                             = 0x0030,
+  HID_USAGE_CONSUMER_RESET                             = 0x0031,
+  HID_USAGE_CONSUMER_SLEEP                             = 0x0032,
+
+  // Screen Brightness
+  HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT              = 0x006F,
+  HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT              = 0x0070,
+
+  // These HID usages operate only on mobile systems (battery powered) and
+  // require Windows 8 (build 8302 or greater).
+  HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS           = 0x000C,
+  HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS            = 0x00C6,
+  HID_USAGE_CONSUMER_WIRELESS_RADIO_LED                = 0x00C7,
+  HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH      = 0x00C8,
+
+  // Media Control
+  HID_USAGE_CONSUMER_PLAY_PAUSE                        = 0x00CD,
+  HID_USAGE_CONSUMER_SCAN_NEXT                         = 0x00B5,
+  HID_USAGE_CONSUMER_SCAN_PREVIOUS                     = 0x00B6,
+  HID_USAGE_CONSUMER_STOP                              = 0x00B7,
+  HID_USAGE_CONSUMER_VOLUME                            = 0x00E0,
+  HID_USAGE_CONSUMER_MUTE                              = 0x00E2,
+  HID_USAGE_CONSUMER_BASS                              = 0x00E3,
+  HID_USAGE_CONSUMER_TREBLE                            = 0x00E4,
+  HID_USAGE_CONSUMER_BASS_BOOST                        = 0x00E5,
+  HID_USAGE_CONSUMER_VOLUME_INCREMENT                  = 0x00E9,
+  HID_USAGE_CONSUMER_VOLUME_DECREMENT                  = 0x00EA,
+  HID_USAGE_CONSUMER_BASS_INCREMENT                    = 0x0152,
+  HID_USAGE_CONSUMER_BASS_DECREMENT                    = 0x0153,
+  HID_USAGE_CONSUMER_TREBLE_INCREMENT                  = 0x0154,
+  HID_USAGE_CONSUMER_TREBLE_DECREMENT                  = 0x0155,
+
+  // Application Launcher
+  HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183,
+  HID_USAGE_CONSUMER_AL_EMAIL_READER                   = 0x018A,
+  HID_USAGE_CONSUMER_AL_CALCULATOR                     = 0x0192,
+  HID_USAGE_CONSUMER_AL_LOCAL_BROWSER                  = 0x0194,
+
+  // Browser/Explorer Specific
+  HID_USAGE_CONSUMER_AC_SEARCH                         = 0x0221,
+  HID_USAGE_CONSUMER_AC_HOME                           = 0x0223,
+  HID_USAGE_CONSUMER_AC_BACK                           = 0x0224,
+  HID_USAGE_CONSUMER_AC_FORWARD                        = 0x0225,
+  HID_USAGE_CONSUMER_AC_STOP                           = 0x0226,
+  HID_USAGE_CONSUMER_AC_REFRESH                        = 0x0227,
+  HID_USAGE_CONSUMER_AC_BOOKMARKS                      = 0x022A,
+
+  // Mouse Horizontal scroll
+  HID_USAGE_CONSUMER_AC_PAN                            = 0x0238,
+};
+
+/*--------------------------------------------------------------------
+ * ASCII to KEYCODE Conversion
+ *  Expand to array of [128][2] (shift, keycode)
+ *
+ * Usage: example to convert input chr into keyboard report (modifier + keycode)
+ *
+ *  uint8_t const conv_table[128][2] =  { HID_ASCII_TO_KEYCODE };
+ *
+ *  uint8_t keycode[6] = { 0 };
+ *  uint8_t modifier   = 0;
+ *
+ *  if ( conv_table[chr][0] ) modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
+ *  keycode[0] = conv_table[chr][1];
+ *  tud_hid_keyboard_report(report_id, modifier, keycode);
+ *
+ *--------------------------------------------------------------------*/
+#define HID_ASCII_TO_KEYCODE \
+    {0, 0                     }, /* 0x00 Null      */ \
+    {0, 0                     }, /* 0x01           */ \
+    {0, 0                     }, /* 0x02           */ \
+    {0, 0                     }, /* 0x03           */ \
+    {0, 0                     }, /* 0x04           */ \
+    {0, 0                     }, /* 0x05           */ \
+    {0, 0                     }, /* 0x06           */ \
+    {0, 0                     }, /* 0x07           */ \
+    {0, HID_KEY_BACKSPACE     }, /* 0x08 Backspace */ \
+    {0, HID_KEY_TAB           }, /* 0x09 Tab       */ \
+    {0, HID_KEY_RETURN        }, /* 0x0A Line Feed */ \
+    {0, 0                     }, /* 0x0B           */ \
+    {0, 0                     }, /* 0x0C           */ \
+    {0, HID_KEY_RETURN        }, /* 0x0D CR        */ \
+    {0, 0                     }, /* 0x0E           */ \
+    {0, 0                     }, /* 0x0F           */ \
+    {0, 0                     }, /* 0x10           */ \
+    {0, 0                     }, /* 0x11           */ \
+    {0, 0                     }, /* 0x12           */ \
+    {0, 0                     }, /* 0x13           */ \
+    {0, 0                     }, /* 0x14           */ \
+    {0, 0                     }, /* 0x15           */ \
+    {0, 0                     }, /* 0x16           */ \
+    {0, 0                     }, /* 0x17           */ \
+    {0, 0                     }, /* 0x18           */ \
+    {0, 0                     }, /* 0x19           */ \
+    {0, 0                     }, /* 0x1A           */ \
+    {0, HID_KEY_ESCAPE        }, /* 0x1B Escape    */ \
+    {0, 0                     }, /* 0x1C           */ \
+    {0, 0                     }, /* 0x1D           */ \
+    {0, 0                     }, /* 0x1E           */ \
+    {0, 0                     }, /* 0x1F           */ \
+                                                      \
+    {0, HID_KEY_SPACE         }, /* 0x20           */ \
+    {1, HID_KEY_1             }, /* 0x21 !         */ \
+    {1, HID_KEY_APOSTROPHE    }, /* 0x22 "         */ \
+    {1, HID_KEY_3             }, /* 0x23 #         */ \
+    {1, HID_KEY_4             }, /* 0x24 $         */ \
+    {1, HID_KEY_5             }, /* 0x25 %         */ \
+    {1, HID_KEY_7             }, /* 0x26 &         */ \
+    {0, HID_KEY_APOSTROPHE    }, /* 0x27 '         */ \
+    {1, HID_KEY_9             }, /* 0x28 (         */ \
+    {1, HID_KEY_0             }, /* 0x29 )         */ \
+    {1, HID_KEY_8             }, /* 0x2A *         */ \
+    {1, HID_KEY_EQUAL         }, /* 0x2B +         */ \
+    {0, HID_KEY_COMMA         }, /* 0x2C ,         */ \
+    {0, HID_KEY_MINUS         }, /* 0x2D -         */ \
+    {0, HID_KEY_PERIOD        }, /* 0x2E .         */ \
+    {0, HID_KEY_SLASH         }, /* 0x2F /         */ \
+    {0, HID_KEY_0             }, /* 0x30 0         */ \
+    {0, HID_KEY_1             }, /* 0x31 1         */ \
+    {0, HID_KEY_2             }, /* 0x32 2         */ \
+    {0, HID_KEY_3             }, /* 0x33 3         */ \
+    {0, HID_KEY_4             }, /* 0x34 4         */ \
+    {0, HID_KEY_5             }, /* 0x35 5         */ \
+    {0, HID_KEY_6             }, /* 0x36 6         */ \
+    {0, HID_KEY_7             }, /* 0x37 7         */ \
+    {0, HID_KEY_8             }, /* 0x38 8         */ \
+    {0, HID_KEY_9             }, /* 0x39 9         */ \
+    {1, HID_KEY_SEMICOLON     }, /* 0x3A :         */ \
+    {0, HID_KEY_SEMICOLON     }, /* 0x3B ;         */ \
+    {1, HID_KEY_COMMA         }, /* 0x3C <         */ \
+    {0, HID_KEY_EQUAL         }, /* 0x3D =         */ \
+    {1, HID_KEY_PERIOD        }, /* 0x3E >         */ \
+    {1, HID_KEY_SLASH         }, /* 0x3F ?         */ \
+                                                      \
+    {1, HID_KEY_2             }, /* 0x40 @         */ \
+    {1, HID_KEY_A             }, /* 0x41 A         */ \
+    {1, HID_KEY_B             }, /* 0x42 B         */ \
+    {1, HID_KEY_C             }, /* 0x43 C         */ \
+    {1, HID_KEY_D             }, /* 0x44 D         */ \
+    {1, HID_KEY_E             }, /* 0x45 E         */ \
+    {1, HID_KEY_F             }, /* 0x46 F         */ \
+    {1, HID_KEY_G             }, /* 0x47 G         */ \
+    {1, HID_KEY_H             }, /* 0x48 H         */ \
+    {1, HID_KEY_I             }, /* 0x49 I         */ \
+    {1, HID_KEY_J             }, /* 0x4A J         */ \
+    {1, HID_KEY_K             }, /* 0x4B K         */ \
+    {1, HID_KEY_L             }, /* 0x4C L         */ \
+    {1, HID_KEY_M             }, /* 0x4D M         */ \
+    {1, HID_KEY_N             }, /* 0x4E N         */ \
+    {1, HID_KEY_O             }, /* 0x4F O         */ \
+    {1, HID_KEY_P             }, /* 0x50 P         */ \
+    {1, HID_KEY_Q             }, /* 0x51 Q         */ \
+    {1, HID_KEY_R             }, /* 0x52 R         */ \
+    {1, HID_KEY_S             }, /* 0x53 S         */ \
+    {1, HID_KEY_T             }, /* 0x55 T         */ \
+    {1, HID_KEY_U             }, /* 0x55 U         */ \
+    {1, HID_KEY_V             }, /* 0x56 V         */ \
+    {1, HID_KEY_W             }, /* 0x57 W         */ \
+    {1, HID_KEY_X             }, /* 0x58 X         */ \
+    {1, HID_KEY_Y             }, /* 0x59 Y         */ \
+    {1, HID_KEY_Z             }, /* 0x5A Z         */ \
+    {0, HID_KEY_BRACKET_LEFT  }, /* 0x5B [         */ \
+    {0, HID_KEY_BACKSLASH     }, /* 0x5C '\'       */ \
+    {0, HID_KEY_BRACKET_RIGHT }, /* 0x5D ]         */ \
+    {1, HID_KEY_6             }, /* 0x5E ^         */ \
+    {1, HID_KEY_MINUS         }, /* 0x5F _         */ \
+                                                      \
+    {0, HID_KEY_GRAVE         }, /* 0x60 `         */ \
+    {0, HID_KEY_A             }, /* 0x61 a         */ \
+    {0, HID_KEY_B             }, /* 0x62 b         */ \
+    {0, HID_KEY_C             }, /* 0x63 c         */ \
+    {0, HID_KEY_D             }, /* 0x66 d         */ \
+    {0, HID_KEY_E             }, /* 0x65 e         */ \
+    {0, HID_KEY_F             }, /* 0x66 f         */ \
+    {0, HID_KEY_G             }, /* 0x67 g         */ \
+    {0, HID_KEY_H             }, /* 0x68 h         */ \
+    {0, HID_KEY_I             }, /* 0x69 i         */ \
+    {0, HID_KEY_J             }, /* 0x6A j         */ \
+    {0, HID_KEY_K             }, /* 0x6B k         */ \
+    {0, HID_KEY_L             }, /* 0x6C l         */ \
+    {0, HID_KEY_M             }, /* 0x6D m         */ \
+    {0, HID_KEY_N             }, /* 0x6E n         */ \
+    {0, HID_KEY_O             }, /* 0x6F o         */ \
+    {0, HID_KEY_P             }, /* 0x70 p         */ \
+    {0, HID_KEY_Q             }, /* 0x71 q         */ \
+    {0, HID_KEY_R             }, /* 0x72 r         */ \
+    {0, HID_KEY_S             }, /* 0x73 s         */ \
+    {0, HID_KEY_T             }, /* 0x75 t         */ \
+    {0, HID_KEY_U             }, /* 0x75 u         */ \
+    {0, HID_KEY_V             }, /* 0x76 v         */ \
+    {0, HID_KEY_W             }, /* 0x77 w         */ \
+    {0, HID_KEY_X             }, /* 0x78 x         */ \
+    {0, HID_KEY_Y             }, /* 0x79 y         */ \
+    {0, HID_KEY_Z             }, /* 0x7A z         */ \
+    {1, HID_KEY_BRACKET_LEFT  }, /* 0x7B {         */ \
+    {1, HID_KEY_BACKSLASH     }, /* 0x7C |         */ \
+    {1, HID_KEY_BRACKET_RIGHT }, /* 0x7D }         */ \
+    {1, HID_KEY_GRAVE         }, /* 0x7E ~         */ \
+    {0, HID_KEY_DELETE        }  /* 0x7F Delete    */ \
+
+/*--------------------------------------------------------------------
+ * KEYCODE to Ascii Conversion
+ *  Expand to array of [128][2] (ascii without shift, ascii with shift)
+ *
+ * Usage: example to convert ascii from keycode (key) and shift modifier (shift).
+ * Here we assume key < 128 ( printable )
+ *
+ *  uint8_t const conv_table[128][2] =  { HID_KEYCODE_TO_ASCII };
+ *  char ch = shift ? conv_table[chr][1] : conv_table[chr][0];
+ *
+ *--------------------------------------------------------------------*/
+#define HID_KEYCODE_TO_ASCII    \
+    {0     , 0      }, /* 0x00 */ \
+    {0     , 0      }, /* 0x01 */ \
+    {0     , 0      }, /* 0x02 */ \
+    {0     , 0      }, /* 0x03 */ \
+    {'a'   , 'A'    }, /* 0x04 */ \
+    {'b'   , 'B'    }, /* 0x05 */ \
+    {'c'   , 'C'    }, /* 0x06 */ \
+    {'d'   , 'D'    }, /* 0x07 */ \
+    {'e'   , 'E'    }, /* 0x08 */ \
+    {'f'   , 'F'    }, /* 0x09 */ \
+    {'g'   , 'G'    }, /* 0x0a */ \
+    {'h'   , 'H'    }, /* 0x0b */ \
+    {'i'   , 'I'    }, /* 0x0c */ \
+    {'j'   , 'J'    }, /* 0x0d */ \
+    {'k'   , 'K'    }, /* 0x0e */ \
+    {'l'   , 'L'    }, /* 0x0f */ \
+    {'m'   , 'M'    }, /* 0x10 */ \
+    {'n'   , 'N'    }, /* 0x11 */ \
+    {'o'   , 'O'    }, /* 0x12 */ \
+    {'p'   , 'P'    }, /* 0x13 */ \
+    {'q'   , 'Q'    }, /* 0x14 */ \
+    {'r'   , 'R'    }, /* 0x15 */ \
+    {'s'   , 'S'    }, /* 0x16 */ \
+    {'t'   , 'T'    }, /* 0x17 */ \
+    {'u'   , 'U'    }, /* 0x18 */ \
+    {'v'   , 'V'    }, /* 0x19 */ \
+    {'w'   , 'W'    }, /* 0x1a */ \
+    {'x'   , 'X'    }, /* 0x1b */ \
+    {'y'   , 'Y'    }, /* 0x1c */ \
+    {'z'   , 'Z'    }, /* 0x1d */ \
+    {'1'   , '!'    }, /* 0x1e */ \
+    {'2'   , '@'    }, /* 0x1f */ \
+    {'3'   , '#'    }, /* 0x20 */ \
+    {'4'   , '$'    }, /* 0x21 */ \
+    {'5'   , '%'    }, /* 0x22 */ \
+    {'6'   , '^'    }, /* 0x23 */ \
+    {'7'   , '&'    }, /* 0x24 */ \
+    {'8'   , '*'    }, /* 0x25 */ \
+    {'9'   , '('    }, /* 0x26 */ \
+    {'0'   , ')'    }, /* 0x27 */ \
+    {'\r'  , '\r'   }, /* 0x28 */ \
+    {'\x1b', '\x1b' }, /* 0x29 */ \
+    {'\b'  , '\b'   }, /* 0x2a */ \
+    {'\t'  , '\t'   }, /* 0x2b */ \
+    {' '   , ' '    }, /* 0x2c */ \
+    {'-'   , '_'    }, /* 0x2d */ \
+    {'='   , '+'    }, /* 0x2e */ \
+    {'['   , '{'    }, /* 0x2f */ \
+    {']'   , '}'    }, /* 0x30 */ \
+    {'\\'  , '|'    }, /* 0x31 */ \
+    {'#'   , '~'    }, /* 0x32 */ \
+    {';'   , ':'    }, /* 0x33 */ \
+    {'\''  , '\"'   }, /* 0x34 */ \
+    {'`'   , '~'    }, /* 0x35 */ \
+    {','   , '<'    }, /* 0x36 */ \
+    {'.'   , '>'    }, /* 0x37 */ \
+    {'/'   , '?'    }, /* 0x38 */ \
+                                  \
+    {0     , 0      }, /* 0x39 */ \
+    {0     , 0      }, /* 0x3a */ \
+    {0     , 0      }, /* 0x3b */ \
+    {0     , 0      }, /* 0x3c */ \
+    {0     , 0      }, /* 0x3d */ \
+    {0     , 0      }, /* 0x3e */ \
+    {0     , 0      }, /* 0x3f */ \
+    {0     , 0      }, /* 0x40 */ \
+    {0     , 0      }, /* 0x41 */ \
+    {0     , 0      }, /* 0x42 */ \
+    {0     , 0      }, /* 0x43 */ \
+    {0     , 0      }, /* 0x44 */ \
+    {0     , 0      }, /* 0x45 */ \
+    {0     , 0      }, /* 0x46 */ \
+    {0     , 0      }, /* 0x47 */ \
+    {0     , 0      }, /* 0x48 */ \
+    {0     , 0      }, /* 0x49 */ \
+    {0     , 0      }, /* 0x4a */ \
+    {0     , 0      }, /* 0x4b */ \
+    {0     , 0      }, /* 0x4c */ \
+    {0     , 0      }, /* 0x4d */ \
+    {0     , 0      }, /* 0x4e */ \
+    {0     , 0      }, /* 0x4f */ \
+    {0     , 0      }, /* 0x50 */ \
+    {0     , 0      }, /* 0x51 */ \
+    {0     , 0      }, /* 0x52 */ \
+    {0     , 0      }, /* 0x53 */ \
+                                  \
+    {'/'   , '/'    }, /* 0x54 */ \
+    {'*'   , '*'    }, /* 0x55 */ \
+    {'-'   , '-'    }, /* 0x56 */ \
+    {'+'   , '+'    }, /* 0x57 */ \
+    {'\r'  , '\r'   }, /* 0x58 */ \
+    {'1'   , 0      }, /* 0x59 */ \
+    {'2'   , 0      }, /* 0x5a */ \
+    {'3'   , 0      }, /* 0x5b */ \
+    {'4'   , 0      }, /* 0x5c */ \
+    {'5'   , '5'    }, /* 0x5d */ \
+    {'6'   , 0      }, /* 0x5e */ \
+    {'7'   , 0      }, /* 0x5f */ \
+    {'8'   , 0      }, /* 0x60 */ \
+    {'9'   , 0      }, /* 0x61 */ \
+    {'0'   , 0      }, /* 0x62 */ \
+    {'0'   , 0      }, /* 0x63 */ \
+    {'='   , '='    }, /* 0x67 */ \
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+
+
+
+#endif /* _TUSB_TYPES_H_ */
+
+
diff --git a/examples_x035/usbdevice/usbdevice.c b/examples_x035/usbdevice/usbdevice.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3280a385f8ac83450e8991c2aa64dac81c58535
--- /dev/null
+++ b/examples_x035/usbdevice/usbdevice.c
@@ -0,0 +1,87 @@
+/* Small example showing how to use the SWIO programming pin to 
+   do printf through the debug interface */
+
+#include "ch32v003fun.h"
+#include <stdio.h>
+#include <string.h>
+#include "fsusb.h"
+
+uint32_t count;
+
+int last = 0;
+void handle_debug_input( int numbytes, uint8_t * data )
+{
+	last = data[0];
+	count += numbytes;
+}
+
+uint8_t scratchpad[256];
+
+int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req )
+{
+	int id = req->wValue & 0xff;
+	if( id == 0xaa )
+	{
+	//	memset( scratchpad, 0x55, sizeof(scratchpad) );
+	//	printf( "SET REPORT! %d [%02x]\n", req->wLength, scratchpad[200] );
+		ctx->pCtrlPayloadPtr = scratchpad;
+		return req->wLength;
+	}
+	return 0;
+}
+
+int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req )
+{
+	int id = req->wValue & 0xff;
+	if( id == 0xaa )
+	{
+		//printf( "GET REPORT! %d\n", req->wLength );
+		ctx->pCtrlPayloadPtr = scratchpad;
+		return 255;
+	}
+	return 0;
+}
+
+void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len )
+{
+}
+
+int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len )
+{
+//	printf( "IN %d %d %08x %08x\n", len, ctx->USBFS_SetupReqLen, data, FSUSBCTX.ENDPOINTS[0] );
+//	memset( data, 0xcc, len );
+	return len;
+}
+
+void HandleHidUserReportOutComplete( struct _USBState * ctx )
+{
+	return;
+}
+
+int main()
+{
+	SystemInit();
+
+	funGpioInitAll();
+
+	funPinMode( PA0, GPIO_CFGLR_OUT_10Mhz_PP );
+
+	FSUSBSetup();
+
+	while(1)
+	{
+		//printf( "%lu %08lx %lu %d %d\n", USBDEBUG0, USBDEBUG1, USBDEBUG2, 0, 0 );
+		int i;
+		for( i = 1; i < 3; i++ )
+		{
+
+			uint32_t * buffer = (uint32_t*)USBFS_GetEPBufferIfAvailable( i );
+			if( buffer )
+			{
+				buffer[0] = 0x000000aa;
+				USBFS_SendEndpoint( i, (i==1)?8:4 );
+			}
+		}
+	}
+}
+
diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h
index 170667f9abe4ce1d78001bda1d9316d5a4f839e5..6266cbb910a32700d4554e7cf22d1d46539ef32d 100644
--- a/minichlink/minichlink.h
+++ b/minichlink/minichlink.h
@@ -111,7 +111,8 @@ enum RiscVChip {
 	CHIP_CH32V20x = 0x05,
 	CHIP_CH32V30x = 0x06,
 	CHIP_CH58x = 0x07,
-	CHIP_CH32V003 = 0x09
+	CHIP_CH32V003 = 0x09,
+	CHIP_CH32X03x = 0x1000, // TODO: Figure out how to get the programmer to really tell us what this is.
 };
 
 struct InternalState
diff --git a/minichlink/pgm-wch-linke.c b/minichlink/pgm-wch-linke.c
index b37ae8245b5bbca3fd4a9447cf65610249624c13..b322a9c0e5d4decae559a2a39c14bf70617c3f03 100644
--- a/minichlink/pgm-wch-linke.c
+++ b/minichlink/pgm-wch-linke.c
@@ -37,6 +37,9 @@ static void printChipInfo(enum RiscVChip chip) {
 		case CHIP_CH58x:
 			fprintf(stderr, "Detected: CH58x\n");
 			break;
+		case CHIP_CH32X03x:
+			fprintf(stderr, "Detected: CH32X03x\n");
+			break;
 		case CHIP_CH32V003:
 			fprintf(stderr, "Detected: CH32V003\n");
 			break;
@@ -46,6 +49,7 @@ static void printChipInfo(enum RiscVChip chip) {
 static int checkChip(enum RiscVChip chip) {
 	switch(chip) {
 		case CHIP_CH32V003:
+		case CHIP_CH32X03x:
 			return 0; // Use direct mode
 		case CHIP_CH32V10x:
 		case CHIP_CH32V20x:
@@ -322,15 +326,31 @@ static int LESetupInterface( void * d )
 
 	// This puts the processor on hold to allow the debugger to run.
 	int already_tried_reset = 0;
+	int is_already_connected = 0;
 	do
 	{
+		// Read DMSTATUS - in case we are a ch32x035, or other chip that does not respond to \x81\x0d\x01\x02.
+		wch_link_command( dev, "\x81\x08\x06\x05\x11\x00\x00\x00\x00\x01", 11, (int*)&transferred, rbuff, 1024 ); // Reply: Ignored, 820d050900300500
+		if( transferred == 9 && rbuff[8] != 0x02 && rbuff[8] != 0x03 )
+		{
+			// Already connected.
+			if( is_already_connected )
+			{
+				printf( "Already Connected\n" );
+				// Still need to read in the data so we can select the correct chip.
+				wch_link_command( dev, "\x81\x0d\x01\x02", 4, (int*)&transferred, rbuff, 1024 ); // ?? this seems to work?
+				break;
+			}
+			is_already_connected = 1;
+		}
+
 		wch_link_command( dev, "\x81\x0d\x01\x02", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Ignored, 820d050900300500
 		if (rbuff[0] == 0x81 && rbuff[1] == 0x55 && rbuff[2] == 0x01 ) // && rbuff[3] == 0x01 )
 		{
 			// The following code may try to execute a few times to get the processor to actually reset.
 			// This code could likely be much better.
-
-			fprintf(stderr, "link error, nothing connected to linker (%d = [%02x %02x %02x %02x]).  Trying to put processor in hold and retrying.\n", transferred, rbuff[0], rbuff[1], rbuff[2], rbuff[3]);
+			if( already_tried_reset > 1)
+				fprintf(stderr, "link error, nothing connected to linker (%d = [%02x %02x %02x %02x]).  Trying to put processor in hold and retrying.\n", transferred, rbuff[0], rbuff[1], rbuff[2], rbuff[3]);
 
 			// Give up if too long
 			if( already_tried_reset > 10 )
@@ -360,43 +380,36 @@ static int LESetupInterface( void * d )
 	} while( 1 );
 
 	if(rbuff[3] == 0x08 || rbuff[3] > 0x09) {
-		fprintf( stderr, "Chip Type unknown. Aborting...\n" );
+		fprintf( stderr, "Chip Type unknown [%02x]. Aborting...\n", rbuff[3] );
 		return -1;
 	}
 
 	enum RiscVChip chip = (enum RiscVChip)rbuff[3];
 	printChipInfo(chip);
 
-	int result = checkChip(chip);
-	if( result == 1 ) // Using blob write
-	{
-		fprintf( stderr, "Using binary blob write for operation.\n" );
-		MCF.WriteBinaryBlob = LEWriteBinaryBlob;
-
-		iss->sector_size = 256;
-
-		wch_link_command( dev, "\x81\x0d\x01\x03", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Ignored, 820d050900300500
-	} else if( result < 0 ) {
-		fprintf( stderr, "Chip type not supported. Aborting...\n" );
-		return -1;
-	}
-
 	iss->target_chip_type = chip;
 
 	// For some reason, if we don't do this sometimes the programmer starts in a hosey mode.
 	MCF.WriteReg32( d, DMCONTROL, 0x80000001 ); // Make the debug module work properly.
 	MCF.WriteReg32( d, DMCONTROL, 0x80000001 ); // Initiate a halt request.
-	MCF.WriteReg32( d, DMCONTROL, 0x80000001 ); // No, really make sure.
-	MCF.WriteReg32( d, DMABSTRACTCS, 0x00000700 ); // Ignore any pending errors.
-	MCF.WriteReg32( d, DMABSTRACTAUTO, 0 );
-	MCF.WriteReg32( d, DMCOMMAND, 0x00221000 ); // Read x0 (Null command) with nopostexec (to fix v307 read issues)
+	MCF.WriteReg32( d, DMCONTROL, 0x80000003 ); // No, really make sure, and also super halt processor.
+	MCF.WriteReg32( d, DMCONTROL, 0x80000001 ); // Un-super-halt processor.
 
 	int r = 0;
 
-	r |= MCF.WaitForDoneOp( d, 0 );
+
+	int timeout = 0;
+retry_DoneOp:
+	MCF.WriteReg32( d, DMABSTRACTCS, 0x00000700 ); // Ignore any pending errors.
+	MCF.WriteReg32( d, DMABSTRACTAUTO, 0 );
+	MCF.WriteReg32( d, DMCOMMAND, 0x00221000 ); // Read x0 (Null command) with nopostexec (to fix v307 read issues)
+	r = MCF.WaitForDoneOp( d, 0 );
 	if( r )
 	{
-		fprintf( stderr, "Fault on setup\n" );
+		fprintf( stderr, "Retrying\n" );
+		if( timeout++ < 10 ) goto retry_DoneOp;
+		fprintf( stderr, "Fault on setup %d\n", r );
+		return -4;
 	}
 	else
 	{
@@ -406,18 +419,49 @@ static int LESetupInterface( void * d )
 	// This puts the processor on hold to allow the debugger to run.
 	// Recommended to switch to 05 from 09 by Alexander M
 	//	wch_link_command( dev, "\x81\x11\x01\x09", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below)
+retry_ID:
 	wch_link_command( dev, "\x81\x11\x01\x05", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below)
 
+	if( rbuff[0] == 0x00 )
+	{
+		if( timeout++ < 10 ) goto retry_ID;
+		fprintf( stderr, "Failed to get chip ID\n" );
+		return -4;
+	}
+
 	if( transferred != 20 )
 	{
 		fprintf( stderr, "Error: could not get part status\n" );
 		return -1;
 	}
-	fprintf( stderr, "Flash Storage: %d kB\n", (rbuff[2]<<8) | rbuff[3] );  // Is this Flash size?
+	int flash_size = (rbuff[2]<<8) | rbuff[3];
+	fprintf( stderr, "Flash Storage: %d kB\n", flash_size );
 	fprintf( stderr, "Part UUID    : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", rbuff[4], rbuff[5], rbuff[6], rbuff[7], rbuff[8], rbuff[9], rbuff[10], rbuff[11] );
 	fprintf( stderr, "PFlags       : %02x-%02x-%02x-%02x\n", rbuff[12], rbuff[13], rbuff[14], rbuff[15] );
 	fprintf( stderr, "Part Type (B): %02x-%02x-%02x-%02x\n", rbuff[16], rbuff[17], rbuff[18], rbuff[19] );
 
+	if( iss->target_chip_type == CHIP_CH32V10x && flash_size == 62 )
+	{
+		fprintf( stderr, "While the debugger reports this as a CH32V10x, it's probably a CH32X03x\n" );
+		chip = iss->target_chip_type = CHIP_CH32X03x;
+		iss->sector_size = 256;
+	}
+
+	int result = checkChip(chip);
+	if( result == 1 ) // Using blob write
+	{
+		fprintf( stderr, "Using binary blob write for operation.\n" );
+		MCF.WriteBinaryBlob = LEWriteBinaryBlob;
+
+		iss->sector_size = 256;
+
+		wch_link_command( dev, "\x81\x0d\x01\x03", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Ignored, 820d050900300500
+	} else if( result < 0 ) {
+		fprintf( stderr, "Chip type not supported. Aborting...\n" );
+		return -1;
+	}
+
+
 	// Check for read protection
 	wch_link_command( dev, "\x81\x06\x01\x01", 4, (int*)&transferred, rbuff, 1024 );
 	if(transferred != 4) {
@@ -775,6 +819,7 @@ static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len,
 			WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, blob+pplace, iss->sector_size, &transferred, WCHTIMEOUT ) );
 		}
 	}
+
 	return 0;
 }