Initial Refleks Lite hardware and firmware release

This commit is contained in:
2026-09-03 16:38:04 +03:00
commit 6e552c2ef1
146 changed files with 92135 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : usb_device.c
* @version : v2.0_Cube
* @brief : This file implements the USB Device
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usb_device.h"
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_hid.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USB Device Core handle declaration. */
USBD_HandleTypeDef hUsbDeviceFS;
/*
* -- Insert your variables declaration here --
*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/*
* -- Insert your external function declaration here --
*/
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/**
* Init USB device Library, add supported class and start the library
* @retval None
*/
void MX_USB_DEVICE_Init(void)
{
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
/* USER CODE END USB_DEVICE_Init_PreTreatment */
/* Init Device Library, add supported class and start the library. */
if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
{
Error_Handler();
}
if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_HID) != USBD_OK)
{
Error_Handler();
}
if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */
/* USER CODE END USB_DEVICE_Init_PostTreatment */
}
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,102 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : usb_device.h
* @version : v2.0_Cube
* @brief : Header for usb_device.c file.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USB_DEVICE__H__
#define __USB_DEVICE__H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx.h"
#include "stm32f1xx_hal.h"
#include "usbd_def.h"
/* USER CODE BEGIN INCLUDE */
/* USER CODE END INCLUDE */
/** @addtogroup USBD_OTG_DRIVER
* @{
*/
/** @defgroup USBD_DEVICE USBD_DEVICE
* @brief Device file for Usb otg low level driver.
* @{
*/
/** @defgroup USBD_DEVICE_Exported_Variables USBD_DEVICE_Exported_Variables
* @brief Public variables.
* @{
*/
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/*
* -- Insert your variables declaration here --
*/
/* USER CODE BEGIN VARIABLES */
/* USER CODE END VARIABLES */
/**
* @}
*/
/** @defgroup USBD_DEVICE_Exported_FunctionsPrototype USBD_DEVICE_Exported_FunctionsPrototype
* @brief Declaration of public functions for Usb device.
* @{
*/
/** USB Device initialization function. */
void MX_USB_DEVICE_Init(void);
/*
* -- Insert functions declaration here --
*/
/* USER CODE BEGIN FD */
/* USER CODE END FD */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USB_DEVICE__H__ */

View File

@@ -0,0 +1,23 @@
#include "usb_device.h"
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_dfu_bootloader.h"
USBD_HandleTypeDef hUsbDeviceFS;
void MX_USB_DEVICE_Init(void)
{
if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
{
Error_Handler();
}
if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_DFU_BOOTLOADER) != USBD_OK)
{
Error_Handler();
}
if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
{
Error_Handler();
}
}

View File

@@ -0,0 +1,23 @@
#include "usb_device.h"
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_dinput.h"
USBD_HandleTypeDef hUsbDeviceFS;
void MX_USB_DEVICE_Init(void)
{
if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
{
Error_Handler();
}
if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_DINPUT) != USBD_OK)
{
Error_Handler();
}
if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
{
Error_Handler();
}
}

View File

@@ -0,0 +1,23 @@
#include "usb_device.h"
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_xinput.h"
USBD_HandleTypeDef hUsbDeviceFS;
void MX_USB_DEVICE_Init(void)
{
if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
{
Error_Handler();
}
if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_XINPUT) != USBD_OK)
{
Error_Handler();
}
if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
{
Error_Handler();
}
}

View File

@@ -0,0 +1,394 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : App/usbd_desc.c
* @version : v2.0_Cube
* @brief : This file implements the USB device descriptors.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_conf.h"
/* USER CODE BEGIN INCLUDE */
/* USER CODE END INCLUDE */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @addtogroup USBD_DESC
* @{
*/
/** @defgroup USBD_DESC_Private_TypesDefinitions USBD_DESC_Private_TypesDefinitions
* @brief Private types.
* @{
*/
/* USER CODE BEGIN PRIVATE_TYPES */
/* USER CODE END PRIVATE_TYPES */
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Defines USBD_DESC_Private_Defines
* @brief Private defines.
* @{
*/
#define USBD_VID 0x1209U
#define USBD_LANGID_STRING 1033
#define USBD_MANUFACTURER_STRING "ERTOtech"
#define USBD_PID_FS 0xE669U
#define USBD_PRODUCT_STRING_FS "Refleks Lite DInput"
#define USBD_CONFIGURATION_STRING_FS "HID Config"
#define USBD_INTERFACE_STRING_FS "HID Interface"
/* USER CODE BEGIN PRIVATE_DEFINES */
/* USER CODE END PRIVATE_DEFINES */
/**
* @}
*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/** @defgroup USBD_DESC_Private_Macros USBD_DESC_Private_Macros
* @brief Private macros.
* @{
*/
/* USER CODE BEGIN PRIVATE_MACRO */
/* USER CODE END PRIVATE_MACRO */
/**
* @}
*/
/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes
* @brief Private functions declaration.
* @{
*/
static void Get_SerialNum(void);
static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len);
/**
* @}
*/
/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes
* @brief Private functions declaration for FS.
* @{
*/
uint8_t * USBD_FS_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t * USBD_FS_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t * USBD_FS_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t * USBD_FS_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t * USBD_FS_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables
* @brief Private variables.
* @{
*/
USBD_DescriptorsTypeDef FS_Desc =
{
USBD_FS_DeviceDescriptor
, USBD_FS_LangIDStrDescriptor
, USBD_FS_ManufacturerStrDescriptor
, USBD_FS_ProductStrDescriptor
, USBD_FS_SerialStrDescriptor
, USBD_FS_ConfigStrDescriptor
, USBD_FS_InterfaceStrDescriptor
};
#if defined ( __ICCARM__ ) /* IAR Compiler */
#pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */
/** USB standard device descriptor. */
__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
0x12, /*bLength */
USB_DESC_TYPE_DEVICE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x02,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
USB_MAX_EP0_SIZE, /*bMaxPacketSize*/
LOBYTE(USBD_VID), /*idVendor*/
HIBYTE(USBD_VID), /*idVendor*/
LOBYTE(USBD_PID_FS), /*idProduct*/
HIBYTE(USBD_PID_FS), /*idProduct*/
0x00, /*bcdDevice rel. 2.00*/
0x02,
USBD_IDX_MFC_STR, /*Index of manufacturer string*/
USBD_IDX_PRODUCT_STR, /*Index of product string*/
USBD_IDX_SERIAL_STR, /*Index of serial number string*/
USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/
};
/* USB_DeviceDescriptor */
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables
* @brief Private variables.
* @{
*/
#if defined ( __ICCARM__ ) /* IAR Compiler */
#pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */
/** USB lang identifier descriptor. */
__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
{
USB_LEN_LANGID_STR_DESC,
USB_DESC_TYPE_STRING,
LOBYTE(USBD_LANGID_STRING),
HIBYTE(USBD_LANGID_STRING)
};
#if defined ( __ICCARM__ ) /* IAR Compiler */
#pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */
/* Internal string descriptor. */
__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = {
USB_SIZ_STRING_SERIAL,
USB_DESC_TYPE_STRING,
};
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Functions USBD_DESC_Private_Functions
* @brief Private functions.
* @{
*/
/**
* @brief Return the device descriptor
* @param speed : Current device speed
* @param length : Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t * USBD_FS_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
*length = sizeof(USBD_FS_DeviceDesc);
return USBD_FS_DeviceDesc;
}
/**
* @brief Return the LangID string descriptor
* @param speed : Current device speed
* @param length : Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t * USBD_FS_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
*length = sizeof(USBD_LangIDDesc);
return USBD_LangIDDesc;
}
/**
* @brief Return the product string descriptor
* @param speed : Current device speed
* @param length : Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t * USBD_FS_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
if(speed == 0)
{
USBD_GetString((uint8_t *)USBD_PRODUCT_STRING_FS, USBD_StrDesc, length);
}
else
{
USBD_GetString((uint8_t *)USBD_PRODUCT_STRING_FS, USBD_StrDesc, length);
}
return USBD_StrDesc;
}
/**
* @brief Return the manufacturer string descriptor
* @param speed : Current device speed
* @param length : Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief Return the serial number string descriptor
* @param speed : Current device speed
* @param length : Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
*length = USB_SIZ_STRING_SERIAL;
/* Update the serial number string descriptor with the data from the unique
* ID */
Get_SerialNum();
/* USER CODE BEGIN USBD_FS_SerialStrDescriptor */
/* USER CODE END USBD_FS_SerialStrDescriptor */
return (uint8_t *) USBD_StringSerial;
}
/**
* @brief Return the configuration string descriptor
* @param speed : Current device speed
* @param length : Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t * USBD_FS_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
if(speed == USBD_SPEED_HIGH)
{
USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING_FS, USBD_StrDesc, length);
}
else
{
USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING_FS, USBD_StrDesc, length);
}
return USBD_StrDesc;
}
/**
* @brief Return the interface string descriptor
* @param speed : Current device speed
* @param length : Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t * USBD_FS_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
if(speed == 0)
{
USBD_GetString((uint8_t *)USBD_INTERFACE_STRING_FS, USBD_StrDesc, length);
}
else
{
USBD_GetString((uint8_t *)USBD_INTERFACE_STRING_FS, USBD_StrDesc, length);
}
return USBD_StrDesc;
}
/**
* @brief Create the serial number string descriptor
* @param None
* @retval None
*/
static void Get_SerialNum(void)
{
uint32_t deviceserial0;
uint32_t deviceserial1;
uint32_t deviceserial2;
deviceserial0 = *(uint32_t *) DEVICE_ID1;
deviceserial1 = *(uint32_t *) DEVICE_ID2;
deviceserial2 = *(uint32_t *) DEVICE_ID3;
deviceserial0 += deviceserial2;
if (deviceserial0 != 0)
{
IntToUnicode(deviceserial0, &USBD_StringSerial[2], 8);
IntToUnicode(deviceserial1, &USBD_StringSerial[18], 4);
}
}
/**
* @brief Convert Hex 32Bits value into char
* @param value: value to convert
* @param pbuf: pointer to the buffer
* @param len: buffer length
* @retval None
*/
static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len)
{
uint8_t idx = 0;
for (idx = 0; idx < len; idx++)
{
if (((value >> 28)) < 0xA)
{
pbuf[2 * idx] = (value >> 28) + '0';
}
else
{
pbuf[2 * idx] = (value >> 28) + 'A' - 10;
}
value = value << 4;
pbuf[2 * idx + 1] = 0;
}
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,143 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : usbd_desc.c
* @version : v2.0_Cube
* @brief : Header for usbd_conf.c file.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_DESC__C__
#define __USBD_DESC__C__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_def.h"
/* USER CODE BEGIN INCLUDE */
/* USER CODE END INCLUDE */
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_DESC USBD_DESC
* @brief Usb device descriptors module.
* @{
*/
/** @defgroup USBD_DESC_Exported_Constants USBD_DESC_Exported_Constants
* @brief Constants.
* @{
*/
#define DEVICE_ID1 (UID_BASE)
#define DEVICE_ID2 (UID_BASE + 0x4)
#define DEVICE_ID3 (UID_BASE + 0x8)
#define USB_SIZ_STRING_SERIAL 0x1A
/* USER CODE BEGIN EXPORTED_CONSTANTS */
/* USER CODE END EXPORTED_CONSTANTS */
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_Defines USBD_DESC_Exported_Defines
* @brief Defines.
* @{
*/
/* USER CODE BEGIN EXPORTED_DEFINES */
/* USER CODE END EXPORTED_DEFINES */
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_TypesDefinitions USBD_DESC_Exported_TypesDefinitions
* @brief Types.
* @{
*/
/* USER CODE BEGIN EXPORTED_TYPES */
/* USER CODE END EXPORTED_TYPES */
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_Macros USBD_DESC_Exported_Macros
* @brief Aliases.
* @{
*/
/* USER CODE BEGIN EXPORTED_MACRO */
/* USER CODE END EXPORTED_MACRO */
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_Variables USBD_DESC_Exported_Variables
* @brief Public variables.
* @{
*/
/** Descriptor for the Usb device. */
extern USBD_DescriptorsTypeDef FS_Desc;
/* USER CODE BEGIN EXPORTED_VARIABLES */
/* USER CODE END EXPORTED_VARIABLES */
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_FunctionsPrototype USBD_DESC_Exported_FunctionsPrototype
* @brief Public functions declaration.
* @{
*/
/* USER CODE BEGIN EXPORTED_FUNCTIONS */
/* USER CODE END EXPORTED_FUNCTIONS */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_DESC__C__ */

View File

@@ -0,0 +1,137 @@
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_conf.h"
#define DFU_VID 0x1209U
#define DFU_PID 0xE667U
#define DFU_LANGID 0x0409U
#define DFU_MANUFACTURER_STRING "ERTOtech"
#define DFU_PRODUCT_STRING "Refleks Lite DFU"
#define DFU_CONFIG_STRING "DFU Config"
#define DFU_INTERFACE_STRING "DFU Interface"
static uint8_t *DFU_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_LangIdDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_ManufacturerDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_ProductDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_SerialDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_ConfigDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_InterfaceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static void DFU_UpdateSerial(void);
static void DFU_IntToUnicode(uint32_t value, uint8_t *buffer, uint8_t length);
USBD_DescriptorsTypeDef FS_Desc =
{
DFU_DeviceDescriptor,
DFU_LangIdDescriptor,
DFU_ManufacturerDescriptor,
DFU_ProductDescriptor,
DFU_SerialDescriptor,
DFU_ConfigDescriptor,
DFU_InterfaceDescriptor,
};
__ALIGN_BEGIN static uint8_t dfuDeviceDescriptor[USB_LEN_DEV_DESC] __ALIGN_END =
{
USB_LEN_DEV_DESC, USB_DESC_TYPE_DEVICE,
0x00, 0x02,
0x00, 0x00, 0x00,
USB_MAX_EP0_SIZE,
LOBYTE(DFU_VID), HIBYTE(DFU_VID),
LOBYTE(DFU_PID), HIBYTE(DFU_PID),
0x00, 0x01,
USBD_IDX_MFC_STR,
USBD_IDX_PRODUCT_STR,
USBD_IDX_SERIAL_STR,
0x01,
};
__ALIGN_BEGIN static uint8_t dfuLangIdDescriptor[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
{
USB_LEN_LANGID_STR_DESC, USB_DESC_TYPE_STRING,
LOBYTE(DFU_LANGID), HIBYTE(DFU_LANGID),
};
__ALIGN_BEGIN static uint8_t dfuStringDescriptor[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
__ALIGN_BEGIN static uint8_t dfuSerialDescriptor[USB_SIZ_STRING_SERIAL] __ALIGN_END =
{
USB_SIZ_STRING_SERIAL, USB_DESC_TYPE_STRING,
};
static uint8_t *DFU_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
*length = sizeof(dfuDeviceDescriptor);
return dfuDeviceDescriptor;
}
static uint8_t *DFU_LangIdDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
*length = sizeof(dfuLangIdDescriptor);
return dfuLangIdDescriptor;
}
static uint8_t *DFU_ManufacturerDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)DFU_MANUFACTURER_STRING, dfuStringDescriptor, length);
return dfuStringDescriptor;
}
static uint8_t *DFU_ProductDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)DFU_PRODUCT_STRING, dfuStringDescriptor, length);
return dfuStringDescriptor;
}
static uint8_t *DFU_SerialDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
DFU_UpdateSerial();
*length = sizeof(dfuSerialDescriptor);
return dfuSerialDescriptor;
}
static uint8_t *DFU_ConfigDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)DFU_CONFIG_STRING, dfuStringDescriptor, length);
return dfuStringDescriptor;
}
static uint8_t *DFU_InterfaceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)DFU_INTERFACE_STRING, dfuStringDescriptor, length);
return dfuStringDescriptor;
}
static void DFU_UpdateSerial(void)
{
uint32_t serial0 = *(uint32_t *)DEVICE_ID1;
uint32_t serial1 = *(uint32_t *)DEVICE_ID2;
uint32_t serial2 = *(uint32_t *)DEVICE_ID3;
serial0 += serial2;
if (serial0 != 0U)
{
DFU_IntToUnicode(serial0, &dfuSerialDescriptor[2], 8U);
DFU_IntToUnicode(serial1, &dfuSerialDescriptor[18], 4U);
}
}
static void DFU_IntToUnicode(uint32_t value, uint8_t *buffer, uint8_t length)
{
uint8_t index;
for (index = 0U; index < length; index++)
{
uint8_t digit = (uint8_t)(value >> 28);
buffer[2U * index] = (digit < 10U) ?
(uint8_t)(digit + '0') :
(uint8_t)(digit - 10U + 'A');
buffer[(2U * index) + 1U] = 0U;
value <<= 4;
}
}

View File

@@ -0,0 +1,156 @@
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_conf.h"
#define DINPUT_VID 0x1209U
#define DINPUT_PID 0xE669U
#define DINPUT_LANGID 0x0409U
#define DINPUT_MANUFACTURER_STRING "ERTOtech"
#define DINPUT_PRODUCT_STRING "Refleks Lite DInput"
#define DINPUT_CONFIGURATION_STRING "HID Config"
#define DINPUT_INTERFACE_STRING "Gamepad"
static uint8_t *DInput_DeviceDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *DInput_LangIdDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *DInput_ManufacturerDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *DInput_ProductDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *DInput_SerialDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *DInput_ConfigurationDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *DInput_InterfaceDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static void DInput_UpdateSerial(void);
static void DInput_IntToUnicode(uint32_t value, uint8_t *buffer,
uint8_t length);
USBD_DescriptorsTypeDef FS_Desc =
{
DInput_DeviceDescriptor,
DInput_LangIdDescriptor,
DInput_ManufacturerDescriptor,
DInput_ProductDescriptor,
DInput_SerialDescriptor,
DInput_ConfigurationDescriptor,
DInput_InterfaceDescriptor,
};
__ALIGN_BEGIN static uint8_t dinputDeviceDescriptor[USB_LEN_DEV_DESC] __ALIGN_END =
{
USB_LEN_DEV_DESC, USB_DESC_TYPE_DEVICE,
0x00, 0x02,
0x00, 0x00, 0x00,
USB_MAX_EP0_SIZE,
LOBYTE(DINPUT_VID), HIBYTE(DINPUT_VID),
LOBYTE(DINPUT_PID), HIBYTE(DINPUT_PID),
0x00, 0x01,
USBD_IDX_MFC_STR,
USBD_IDX_PRODUCT_STR,
USBD_IDX_SERIAL_STR,
0x01,
};
__ALIGN_BEGIN static uint8_t dinputLangIdDescriptor[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
{
USB_LEN_LANGID_STR_DESC, USB_DESC_TYPE_STRING,
LOBYTE(DINPUT_LANGID), HIBYTE(DINPUT_LANGID),
};
__ALIGN_BEGIN static uint8_t dinputStringDescriptor[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
__ALIGN_BEGIN static uint8_t dinputSerialDescriptor[USB_SIZ_STRING_SERIAL] __ALIGN_END =
{
USB_SIZ_STRING_SERIAL, USB_DESC_TYPE_STRING,
};
static uint8_t *DInput_DeviceDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
*length = sizeof(dinputDeviceDescriptor);
return dinputDeviceDescriptor;
}
static uint8_t *DInput_LangIdDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
*length = sizeof(dinputLangIdDescriptor);
return dinputLangIdDescriptor;
}
static uint8_t *DInput_ManufacturerDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)DINPUT_MANUFACTURER_STRING,
dinputStringDescriptor, length);
return dinputStringDescriptor;
}
static uint8_t *DInput_ProductDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)DINPUT_PRODUCT_STRING,
dinputStringDescriptor, length);
return dinputStringDescriptor;
}
static uint8_t *DInput_SerialDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
DInput_UpdateSerial();
*length = sizeof(dinputSerialDescriptor);
return dinputSerialDescriptor;
}
static uint8_t *DInput_ConfigurationDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)DINPUT_CONFIGURATION_STRING,
dinputStringDescriptor, length);
return dinputStringDescriptor;
}
static uint8_t *DInput_InterfaceDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)DINPUT_INTERFACE_STRING,
dinputStringDescriptor, length);
return dinputStringDescriptor;
}
static void DInput_UpdateSerial(void)
{
uint32_t serial0 = *(uint32_t *)DEVICE_ID1;
uint32_t serial1 = *(uint32_t *)DEVICE_ID2;
uint32_t serial2 = *(uint32_t *)DEVICE_ID3;
serial0 += serial2;
if (serial0 != 0U)
{
DInput_IntToUnicode(serial0, &dinputSerialDescriptor[2], 8U);
DInput_IntToUnicode(serial1, &dinputSerialDescriptor[18], 4U);
}
}
static void DInput_IntToUnicode(uint32_t value, uint8_t *buffer,
uint8_t length)
{
uint8_t index;
for (index = 0U; index < length; index++)
{
uint8_t digit = (uint8_t)(value >> 28);
buffer[2U * index] = (digit < 10U) ?
(uint8_t)(digit + '0') :
(uint8_t)(digit - 10U + 'A');
buffer[(2U * index) + 1U] = 0U;
value <<= 4;
}
}

View File

@@ -0,0 +1,159 @@
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_conf.h"
#define XINPUT_VID 0x1209U
#define XINPUT_PID 0xE668U
#define XINPUT_LANGID 0x0409U
#define XINPUT_MANUFACTURER_STRING "ERTOtech"
#define XINPUT_PRODUCT_STRING "Refleks Lite XInput"
#define XINPUT_CONFIGURATION_STRING "XInput Config"
#define XINPUT_INTERFACE_STRING "XInput Interface"
static uint8_t *XInput_DeviceDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *XInput_LangIdDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *XInput_ManufacturerDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *XInput_ProductDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *XInput_SerialDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *XInput_ConfigurationDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static uint8_t *XInput_InterfaceDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length);
static void XInput_UpdateSerial(void);
static void XInput_IntToUnicode(uint32_t value, uint8_t *buffer, uint8_t length);
USBD_DescriptorsTypeDef FS_Desc =
{
XInput_DeviceDescriptor,
XInput_LangIdDescriptor,
XInput_ManufacturerDescriptor,
XInput_ProductDescriptor,
XInput_SerialDescriptor,
XInput_ConfigurationDescriptor,
XInput_InterfaceDescriptor,
};
__ALIGN_BEGIN static uint8_t xinputDeviceDescriptor[USB_LEN_DEV_DESC] __ALIGN_END =
{
USB_LEN_DEV_DESC,
USB_DESC_TYPE_DEVICE,
0x00, 0x02, /* USB 2.00 */
0x00, 0x00, 0x00, /* Class is defined by the interface */
USB_MAX_EP0_SIZE,
LOBYTE(XINPUT_VID), HIBYTE(XINPUT_VID),
LOBYTE(XINPUT_PID), HIBYTE(XINPUT_PID),
0x01, 0x01, /* Device release 1.01 */
USBD_IDX_MFC_STR,
USBD_IDX_PRODUCT_STR,
USBD_IDX_SERIAL_STR,
0x01,
};
__ALIGN_BEGIN static uint8_t xinputLangIdDescriptor[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
{
USB_LEN_LANGID_STR_DESC,
USB_DESC_TYPE_STRING,
LOBYTE(XINPUT_LANGID), HIBYTE(XINPUT_LANGID),
};
__ALIGN_BEGIN static uint8_t xinputStringDescriptor[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
__ALIGN_BEGIN static uint8_t xinputSerialDescriptor[USB_SIZ_STRING_SERIAL] __ALIGN_END =
{
USB_SIZ_STRING_SERIAL,
USB_DESC_TYPE_STRING,
};
static uint8_t *XInput_DeviceDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
*length = sizeof(xinputDeviceDescriptor);
return xinputDeviceDescriptor;
}
static uint8_t *XInput_LangIdDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
*length = sizeof(xinputLangIdDescriptor);
return xinputLangIdDescriptor;
}
static uint8_t *XInput_ManufacturerDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)XINPUT_MANUFACTURER_STRING,
xinputStringDescriptor, length);
return xinputStringDescriptor;
}
static uint8_t *XInput_ProductDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)XINPUT_PRODUCT_STRING,
xinputStringDescriptor, length);
return xinputStringDescriptor;
}
static uint8_t *XInput_SerialDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
XInput_UpdateSerial();
*length = sizeof(xinputSerialDescriptor);
return xinputSerialDescriptor;
}
static uint8_t *XInput_ConfigurationDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)XINPUT_CONFIGURATION_STRING,
xinputStringDescriptor, length);
return xinputStringDescriptor;
}
static uint8_t *XInput_InterfaceDescriptor(USBD_SpeedTypeDef speed,
uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)XINPUT_INTERFACE_STRING,
xinputStringDescriptor, length);
return xinputStringDescriptor;
}
static void XInput_UpdateSerial(void)
{
uint32_t serial0 = *(uint32_t *)DEVICE_ID1;
uint32_t serial1 = *(uint32_t *)DEVICE_ID2;
uint32_t serial2 = *(uint32_t *)DEVICE_ID3;
serial0 += serial2;
if (serial0 != 0U)
{
XInput_IntToUnicode(serial0, &xinputSerialDescriptor[2], 8U);
XInput_IntToUnicode(serial1, &xinputSerialDescriptor[18], 4U);
}
}
static void XInput_IntToUnicode(uint32_t value, uint8_t *buffer, uint8_t length)
{
uint8_t index;
for (index = 0U; index < length; index++)
{
uint8_t digit = (uint8_t)(value >> 28);
buffer[2U * index] = (digit < 10U) ?
(uint8_t)(digit + '0') :
(uint8_t)(digit - 10U + 'A');
buffer[(2U * index) + 1U] = 0U;
value <<= 4;
}
}

View File

@@ -0,0 +1,369 @@
#include "usbd_dfu_bootloader.h"
#include "stm32f1xx_hal.h"
#include "usbd_ctlreq.h"
#define DFU_DETACH 0x00U
#define DFU_DNLOAD 0x01U
#define DFU_UPLOAD 0x02U
#define DFU_GETSTATUS 0x03U
#define DFU_CLRSTATUS 0x04U
#define DFU_GETSTATE 0x05U
#define DFU_ABORT 0x06U
#define DFU_STATUS_OK 0x00U
#define DFU_STATUS_ERR_WRITE 0x03U
#define DFU_STATUS_ERR_ERASE 0x04U
#define DFU_STATUS_ERR_ADDRESS 0x08U
#define DFU_STATUS_ERR_STALLEDPKT 0x0FU
#define DFU_STATE_DFU_IDLE 0x02U
#define DFU_STATE_DFU_DNLOAD_SYNC 0x03U
#define DFU_STATE_DFU_DNLOAD_IDLE 0x05U
#define DFU_STATE_DFU_MANIFEST_SYNC 0x06U
#define DFU_STATE_DFU_MANIFEST_WAIT_RESET 0x08U
#define DFU_STATE_DFU_ERROR 0x0AU
#define DFU_DESCRIPTOR_TYPE 0x21U
#define STM32F103_FLASH_PAGE_SIZE 1024U
typedef struct
{
uint8_t state;
uint8_t status;
uint8_t altSetting;
uint8_t resetPending;
uint16_t blockNumber;
uint16_t downloadLength;
uint32_t resetAt;
} USBD_DFU_BootloaderHandleTypeDef;
static uint8_t DFU_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t DFU_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t DFU_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
static uint8_t DFU_EP0RxReady(USBD_HandleTypeDef *pdev);
static uint8_t DFU_SOF(USBD_HandleTypeDef *pdev);
static uint8_t *DFU_GetCfgDesc(uint16_t *length);
static uint8_t *DFU_GetDeviceQualifierDesc(uint16_t *length);
static uint8_t DFU_WriteBlock(USBD_DFU_BootloaderHandleTypeDef *handle);
static uint32_t DFU_GetSlotBase(uint8_t altSetting);
__ALIGN_BEGIN static uint32_t dfuDownloadWords[DFU_TRANSFER_SIZE / 4U] __ALIGN_END;
USBD_ClassTypeDef USBD_DFU_BOOTLOADER =
{
DFU_Init,
DFU_DeInit,
DFU_Setup,
NULL,
DFU_EP0RxReady,
NULL,
NULL,
DFU_SOF,
NULL,
NULL,
DFU_GetCfgDesc,
DFU_GetCfgDesc,
DFU_GetCfgDesc,
DFU_GetDeviceQualifierDesc,
};
/* One DFU interface with two alternate settings: App1 and App2. */
__ALIGN_BEGIN static uint8_t dfuConfigDescriptor[USB_DFU_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, USB_DESC_TYPE_CONFIGURATION,
LOBYTE(USB_DFU_CONFIG_DESC_SIZ), HIBYTE(USB_DFU_CONFIG_DESC_SIZ),
0x01, 0x01, 0x00, 0x80, 0x32,
0x09, USB_DESC_TYPE_INTERFACE,
0x00, 0x00, 0x00,
0xFE, 0x01, 0x02, 0x00,
/* DFU 1.1 functional descriptor: download only, 1024-byte transfer. */
0x09, DFU_DESCRIPTOR_TYPE,
0x01,
0xE8, 0x03,
LOBYTE(DFU_TRANSFER_SIZE), HIBYTE(DFU_TRANSFER_SIZE),
0x10, 0x01,
0x09, USB_DESC_TYPE_INTERFACE,
0x00, 0x01, 0x00,
0xFE, 0x01, 0x02, 0x00,
};
__ALIGN_BEGIN static uint8_t dfuDeviceQualifierDescriptor[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER,
0x00, 0x02,
0x00, 0x00, 0x00,
USB_MAX_EP0_SIZE,
0x01, 0x00,
};
static uint8_t DFU_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
USBD_DFU_BootloaderHandleTypeDef *handle;
UNUSED(cfgidx);
pdev->pClassData = USBD_malloc(sizeof(USBD_DFU_BootloaderHandleTypeDef));
if (pdev->pClassData == NULL)
{
return USBD_FAIL;
}
handle = (USBD_DFU_BootloaderHandleTypeDef *)pdev->pClassData;
handle->state = DFU_STATE_DFU_IDLE;
handle->status = DFU_STATUS_OK;
handle->altSetting = 0U;
handle->resetPending = 0U;
handle->blockNumber = 0U;
handle->downloadLength = 0U;
handle->resetAt = 0U;
return USBD_OK;
}
static uint8_t DFU_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
UNUSED(cfgidx);
if (pdev->pClassData != NULL)
{
USBD_free(pdev->pClassData);
pdev->pClassData = NULL;
}
return USBD_OK;
}
static uint8_t DFU_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_DFU_BootloaderHandleTypeDef *handle =
(USBD_DFU_BootloaderHandleTypeDef *)pdev->pClassData;
static uint8_t statusResponse[6];
uint16_t statusInfo = 0U;
if (handle == NULL)
{
USBD_CtlError(pdev, req);
return USBD_FAIL;
}
if ((req->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS)
{
switch (req->bRequest)
{
case DFU_DNLOAD:
if ((handle->state != DFU_STATE_DFU_IDLE) &&
(handle->state != DFU_STATE_DFU_DNLOAD_IDLE))
{
break;
}
if (req->wLength == 0U)
{
handle->state = DFU_STATE_DFU_MANIFEST_SYNC;
return USBD_OK;
}
if (req->wLength > DFU_TRANSFER_SIZE)
{
handle->status = DFU_STATUS_ERR_STALLEDPKT;
handle->state = DFU_STATE_DFU_ERROR;
break;
}
handle->blockNumber = req->wValue;
handle->downloadLength = req->wLength;
USBD_CtlPrepareRx(pdev, (uint8_t *)dfuDownloadWords, req->wLength);
return USBD_OK;
case DFU_UPLOAD:
break;
case DFU_GETSTATUS:
if (handle->state == DFU_STATE_DFU_DNLOAD_SYNC)
{
handle->state = DFU_STATE_DFU_DNLOAD_IDLE;
}
else if (handle->state == DFU_STATE_DFU_MANIFEST_SYNC)
{
handle->state = DFU_STATE_DFU_MANIFEST_WAIT_RESET;
handle->resetPending = 1U;
handle->resetAt = HAL_GetTick() + 100U;
}
statusResponse[0] = handle->status;
statusResponse[1] = 0U;
statusResponse[2] = 0U;
statusResponse[3] = 0U;
statusResponse[4] = handle->state;
statusResponse[5] = 0U;
USBD_CtlSendData(pdev, statusResponse, sizeof(statusResponse));
return USBD_OK;
case DFU_CLRSTATUS:
handle->status = DFU_STATUS_OK;
handle->state = DFU_STATE_DFU_IDLE;
return USBD_OK;
case DFU_GETSTATE:
USBD_CtlSendData(pdev, &handle->state, 1U);
return USBD_OK;
case DFU_ABORT:
handle->status = DFU_STATUS_OK;
handle->state = DFU_STATE_DFU_IDLE;
handle->downloadLength = 0U;
return USBD_OK;
case DFU_DETACH:
handle->resetPending = 1U;
handle->resetAt = HAL_GetTick() + 100U;
return USBD_OK;
default:
break;
}
}
else if ((req->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
switch (req->bRequest)
{
case USB_REQ_GET_STATUS:
USBD_CtlSendData(pdev, (uint8_t *)&statusInfo, sizeof(statusInfo));
return USBD_OK;
case USB_REQ_GET_INTERFACE:
USBD_CtlSendData(pdev, &handle->altSetting, 1U);
return USBD_OK;
case USB_REQ_SET_INTERFACE:
if (req->wValue <= 1U)
{
handle->altSetting = (uint8_t)req->wValue;
handle->state = DFU_STATE_DFU_IDLE;
handle->status = DFU_STATUS_OK;
return USBD_OK;
}
break;
case USB_REQ_GET_DESCRIPTOR:
if ((req->wValue >> 8) == DFU_DESCRIPTOR_TYPE)
{
USBD_CtlSendData(pdev, &dfuConfigDescriptor[18],
MIN(9U, req->wLength));
return USBD_OK;
}
break;
default:
break;
}
}
USBD_CtlError(pdev, req);
return USBD_FAIL;
}
static uint8_t DFU_EP0RxReady(USBD_HandleTypeDef *pdev)
{
USBD_DFU_BootloaderHandleTypeDef *handle =
(USBD_DFU_BootloaderHandleTypeDef *)pdev->pClassData;
if ((handle == NULL) || (handle->downloadLength == 0U))
{
return USBD_OK;
}
if (DFU_WriteBlock(handle) == USBD_OK)
{
handle->status = DFU_STATUS_OK;
handle->state = DFU_STATE_DFU_DNLOAD_SYNC;
}
else
{
handle->state = DFU_STATE_DFU_ERROR;
}
handle->downloadLength = 0U;
return USBD_OK;
}
static uint8_t DFU_SOF(USBD_HandleTypeDef *pdev)
{
USBD_DFU_BootloaderHandleTypeDef *handle =
(USBD_DFU_BootloaderHandleTypeDef *)pdev->pClassData;
if ((handle != NULL) && (handle->resetPending != 0U) &&
((int32_t)(HAL_GetTick() - handle->resetAt) >= 0))
{
NVIC_SystemReset();
}
return USBD_OK;
}
static uint8_t DFU_WriteBlock(USBD_DFU_BootloaderHandleTypeDef *handle)
{
FLASH_EraseInitTypeDef erase = {0};
uint32_t eraseError = 0U;
uint32_t slotBase = DFU_GetSlotBase(handle->altSetting);
uint32_t address = slotBase + ((uint32_t)handle->blockNumber * DFU_TRANSFER_SIZE);
uint32_t slotEnd = slotBase + DFU_APP_SLOT_SIZE;
uint32_t index;
if ((address < slotBase) || (address >= slotEnd) ||
(handle->downloadLength > (slotEnd - address)))
{
handle->status = DFU_STATUS_ERR_ADDRESS;
return USBD_FAIL;
}
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
erase.TypeErase = FLASH_TYPEERASE_PAGES;
erase.PageAddress = address;
erase.NbPages = 1U;
if (HAL_FLASHEx_Erase(&erase, &eraseError) != HAL_OK)
{
handle->status = DFU_STATUS_ERR_ERASE;
HAL_FLASH_Lock();
return USBD_FAIL;
}
for (index = 0U; index < handle->downloadLength; index += 2U)
{
uint8_t *bytes = (uint8_t *)dfuDownloadWords;
uint16_t halfword = bytes[index];
if ((index + 1U) < handle->downloadLength)
{
halfword |= (uint16_t)((uint16_t)bytes[index + 1U] << 8U);
}
else
{
halfword |= 0xFF00U;
}
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,
address + index, halfword) != HAL_OK)
{
handle->status = DFU_STATUS_ERR_WRITE;
HAL_FLASH_Lock();
return USBD_FAIL;
}
}
HAL_FLASH_Lock();
return USBD_OK;
}
static uint32_t DFU_GetSlotBase(uint8_t altSetting)
{
return (altSetting == 0U) ? DFU_APP1_ADDRESS : DFU_APP2_ADDRESS;
}
static uint8_t *DFU_GetCfgDesc(uint16_t *length)
{
*length = sizeof(dfuConfigDescriptor);
return dfuConfigDescriptor;
}
static uint8_t *DFU_GetDeviceQualifierDesc(uint16_t *length)
{
*length = sizeof(dfuDeviceQualifierDescriptor);
return dfuDeviceQualifierDescriptor;
}

View File

@@ -0,0 +1,22 @@
#ifndef USBD_DFU_BOOTLOADER_H
#define USBD_DFU_BOOTLOADER_H
#ifdef __cplusplus
extern "C" {
#endif
#include "usbd_ioreq.h"
#define DFU_TRANSFER_SIZE 1024U
#define DFU_APP1_ADDRESS 0x08006000U
#define DFU_APP2_ADDRESS 0x08013000U
#define DFU_APP_SLOT_SIZE 0x0000D000U
#define USB_DFU_CONFIG_DESC_SIZ 36U
extern USBD_ClassTypeDef USBD_DFU_BOOTLOADER;
#ifdef __cplusplus
}
#endif
#endif /* USBD_DFU_BOOTLOADER_H */

View File

@@ -0,0 +1,390 @@
#include "usbd_dinput.h"
#include "usbd_ctlreq.h"
#include <string.h>
#define HID_DESCRIPTOR_TYPE 0x21U
#define HID_REPORT_DESC 0x22U
#define HID_REQ_GET_REPORT 0x01U
#define HID_REQ_GET_IDLE 0x02U
#define HID_REQ_GET_PROTOCOL 0x03U
#define HID_REQ_SET_REPORT 0x09U
#define HID_REQ_SET_IDLE 0x0AU
#define HID_REQ_SET_PROTOCOL 0x0BU
typedef struct
{
uint8_t altSetting[3];
uint8_t protocol;
uint8_t idle;
uint8_t busy;
} USBD_DINPUT_HandleTypeDef;
static uint8_t DINPUT_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t DINPUT_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t DINPUT_Setup(USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req);
static uint8_t DINPUT_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t DINPUT_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t *DINPUT_GetCfgDesc(uint16_t *length);
static uint8_t *DINPUT_GetDeviceQualifierDesc(uint16_t *length);
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
static uint8_t *DINPUT_GetUserString(USBD_HandleTypeDef *pdev,
uint8_t index,
uint16_t *length);
#endif
static uint8_t dinputInBuffer[DINPUT_REPORT_SIZE];
static uint8_t dinputSetupOutBuffer[DINPUT_EP_SIZE];
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
static uint8_t dinputStringBuffer[32];
#endif
USBD_ClassTypeDef USBD_DINPUT =
{
DINPUT_Init,
DINPUT_DeInit,
DINPUT_Setup,
NULL,
NULL,
DINPUT_DataIn,
DINPUT_DataOut,
NULL,
NULL,
NULL,
DINPUT_GetCfgDesc,
DINPUT_GetCfgDesc,
DINPUT_GetCfgDesc,
DINPUT_GetDeviceQualifierDesc,
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
DINPUT_GetUserString,
#endif
};
/* Descriptor order and report sizes match the original three-interface unit.
* IF0 is the only functional interface. IF1/IF2 are inert compatibility
* shells and their data endpoints are halted in DINPUT_Init(). */
__ALIGN_BEGIN static uint8_t dinputConfigDescriptor[USB_DINPUT_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, USB_DESC_TYPE_CONFIGURATION,
LOBYTE(USB_DINPUT_CONFIG_DESC_SIZ), HIBYTE(USB_DINPUT_CONFIG_DESC_SIZ),
0x03, 0x01, 0x00, 0x80, 0x32,
0x09, USB_DESC_TYPE_INTERFACE,
0x00, 0x00, 0x01,
0x03, 0x00, 0x00, 0x05,
0x09, HID_DESCRIPTOR_TYPE,
0x11, 0x01, 0x00, 0x01, HID_REPORT_DESC,
0x51, 0x00,
0x07, USB_DESC_TYPE_ENDPOINT,
DINPUT_GAMEPAD_EPIN_ADDR, 0x03,
LOBYTE(DINPUT_EP_SIZE), HIBYTE(DINPUT_EP_SIZE), 0x01,
0x09, USB_DESC_TYPE_INTERFACE,
0x01, 0x00, 0x02,
0x03, 0x00, 0x00, 0x06,
0x09, HID_DESCRIPTOR_TYPE,
0x11, 0x01, 0x00, 0x01, HID_REPORT_DESC,
0x22, 0x00,
0x07, USB_DESC_TYPE_ENDPOINT,
DINPUT_SETUP_EPIN_ADDR, 0x03,
LOBYTE(DINPUT_EP_SIZE), HIBYTE(DINPUT_EP_SIZE), 0x01,
0x07, USB_DESC_TYPE_ENDPOINT,
DINPUT_SETUP_EPOUT_ADDR, 0x03,
LOBYTE(DINPUT_EP_SIZE), HIBYTE(DINPUT_EP_SIZE), 0x01,
0x09, USB_DESC_TYPE_INTERFACE,
0x02, 0x00, 0x01,
0x03, 0x00, 0x00, 0x07,
0x09, HID_DESCRIPTOR_TYPE,
0x11, 0x01, 0x00, 0x01, HID_REPORT_DESC,
0x15, 0x00,
0x07, USB_DESC_TYPE_ENDPOINT,
DINPUT_RAW_EPIN_ADDR, 0x03,
LOBYTE(DINPUT_EP_SIZE), HIBYTE(DINPUT_EP_SIZE), 0x01,
};
/* 11 buttons, hat and six unsigned 8-bit axes: 9 bytes total. */
__ALIGN_BEGIN static uint8_t gamepadReportDescriptor[] __ALIGN_END =
{
0x05, 0x01, 0x09, 0x05, 0xA1, 0x01,
0x05, 0x09, 0x19, 0x01, 0x29, 0x0B,
0x15, 0x00, 0x25, 0x01, 0x75, 0x01,
0x95, 0x0B, 0x81, 0x02,
0x75, 0x01, 0x95, 0x05, 0x81, 0x03,
0x05, 0x01, 0x09, 0x39, 0x15, 0x00,
0x25, 0x07, 0x35, 0x00, 0x46, 0x3B, 0x01,
0x65, 0x14, 0x75, 0x04, 0x95, 0x01,
0x81, 0x42, 0x75, 0x04, 0x95, 0x01, 0x81, 0x03,
0x05, 0x01,
0x09, 0x30, 0x09, 0x31, 0x09, 0x32,
0x09, 0x33, 0x09, 0x34, 0x09, 0x35,
0x15, 0x00, 0x26, 0xFF, 0x00,
0x75, 0x08, 0x95, 0x06, 0x81, 0x02,
0xC0
};
__ALIGN_BEGIN static uint8_t setupReportDescriptor[] __ALIGN_END =
{
0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01,
0x09, 0x10, 0x15, 0x00, 0x26, 0xFF, 0x00,
0x75, 0x08, 0x95, 0x1A, 0x81, 0x02,
0x09, 0x11, 0x15, 0x00, 0x26, 0xFF, 0x00,
0x75, 0x08, 0x95, 0x1B, 0x91, 0x02,
0xC0
};
__ALIGN_BEGIN static uint8_t rawReportDescriptor[] __ALIGN_END =
{
0x06, 0x00, 0xFF, 0x09, 0x02, 0xA1, 0x01,
0x09, 0x20, 0x15, 0x00, 0x26, 0xFF, 0x00,
0x75, 0x08, 0x95, 0x18, 0x81, 0x02,
0xC0
};
__ALIGN_BEGIN static uint8_t dinputDeviceQualifierDescriptor[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
USB_LEN_DEV_QUALIFIER_DESC, USB_DESC_TYPE_DEVICE_QUALIFIER,
0x00, 0x02, 0x00, 0x00, 0x00, USB_MAX_EP0_SIZE, 0x01, 0x00
};
_Static_assert(sizeof(gamepadReportDescriptor) == 81U,
"DInput gamepad report descriptor length changed");
_Static_assert(sizeof(setupReportDescriptor) == 34U,
"Setup report descriptor length changed");
_Static_assert(sizeof(rawReportDescriptor) == 21U,
"Raw report descriptor length changed");
static uint8_t DINPUT_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
USBD_DINPUT_HandleTypeDef *handle;
UNUSED(cfgidx);
pdev->pClassData = USBD_malloc(sizeof(USBD_DINPUT_HandleTypeDef));
if (pdev->pClassData == NULL)
{
return USBD_FAIL;
}
handle = (USBD_DINPUT_HandleTypeDef *)pdev->pClassData;
memset(handle, 0, sizeof(*handle));
USBD_LL_OpenEP(pdev, DINPUT_GAMEPAD_EPIN_ADDR,
USBD_EP_TYPE_INTR, DINPUT_EP_SIZE);
pdev->ep_in[DINPUT_GAMEPAD_EPIN_ADDR & 0x0FU].is_used = 1U;
USBD_LL_OpenEP(pdev, DINPUT_SETUP_EPIN_ADDR,
USBD_EP_TYPE_INTR, DINPUT_EP_SIZE);
pdev->ep_in[DINPUT_SETUP_EPIN_ADDR & 0x0FU].is_used = 1U;
USBD_LL_OpenEP(pdev, DINPUT_SETUP_EPOUT_ADDR,
USBD_EP_TYPE_INTR, DINPUT_EP_SIZE);
pdev->ep_out[DINPUT_SETUP_EPOUT_ADDR & 0x0FU].is_used = 1U;
USBD_LL_OpenEP(pdev, DINPUT_RAW_EPIN_ADDR,
USBD_EP_TYPE_INTR, DINPUT_EP_SIZE);
pdev->ep_in[DINPUT_RAW_EPIN_ADDR & 0x0FU].is_used = 1U;
/* Stub HID data paths: unused IN endpoints stay at NAK. Setup OUT packets
* are acknowledged and discarded so the interface can start cleanly. */
USBD_LL_PrepareReceive(pdev, DINPUT_SETUP_EPOUT_ADDR,
dinputSetupOutBuffer, DINPUT_EP_SIZE);
return USBD_OK;
}
static uint8_t DINPUT_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
UNUSED(cfgidx);
USBD_LL_CloseEP(pdev, DINPUT_GAMEPAD_EPIN_ADDR);
USBD_LL_CloseEP(pdev, DINPUT_SETUP_EPIN_ADDR);
USBD_LL_CloseEP(pdev, DINPUT_SETUP_EPOUT_ADDR);
USBD_LL_CloseEP(pdev, DINPUT_RAW_EPIN_ADDR);
pdev->ep_in[DINPUT_GAMEPAD_EPIN_ADDR & 0x0FU].is_used = 0U;
pdev->ep_in[DINPUT_SETUP_EPIN_ADDR & 0x0FU].is_used = 0U;
pdev->ep_out[DINPUT_SETUP_EPOUT_ADDR & 0x0FU].is_used = 0U;
pdev->ep_in[DINPUT_RAW_EPIN_ADDR & 0x0FU].is_used = 0U;
if (pdev->pClassData != NULL)
{
USBD_free(pdev->pClassData);
pdev->pClassData = NULL;
}
return USBD_OK;
}
static uint8_t DINPUT_Setup(USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
USBD_DINPUT_HandleTypeDef *handle =
(USBD_DINPUT_HandleTypeDef *)pdev->pClassData;
uint8_t interface = (uint8_t)req->wIndex;
uint16_t status = 0U;
uint8_t *descriptor = NULL;
uint16_t length = 0U;
if ((handle == NULL) || (interface > 2U))
{
USBD_CtlError(pdev, req);
return USBD_FAIL;
}
if ((req->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS)
{
/* The original Setup/Raw protocols are intentionally not implemented. */
if (interface != 0U)
{
USBD_CtlError(pdev, req);
return USBD_FAIL;
}
switch (req->bRequest)
{
case HID_REQ_SET_PROTOCOL:
handle->protocol = (uint8_t)req->wValue;
return USBD_OK;
case HID_REQ_GET_PROTOCOL:
USBD_CtlSendData(pdev, &handle->protocol, 1U);
return USBD_OK;
case HID_REQ_SET_IDLE:
handle->idle = (uint8_t)(req->wValue >> 8);
return USBD_OK;
case HID_REQ_GET_IDLE:
USBD_CtlSendData(pdev, &handle->idle, 1U);
return USBD_OK;
case HID_REQ_GET_REPORT:
case HID_REQ_SET_REPORT:
default:
USBD_CtlError(pdev, req);
return USBD_FAIL;
}
}
if ((req->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
switch (req->bRequest)
{
case USB_REQ_GET_STATUS:
USBD_CtlSendData(pdev, (uint8_t *)&status, sizeof(status));
return USBD_OK;
case USB_REQ_GET_INTERFACE:
USBD_CtlSendData(pdev, &handle->altSetting[interface], 1U);
return USBD_OK;
case USB_REQ_SET_INTERFACE:
if (req->wValue == 0U)
{
handle->altSetting[interface] = 0U;
return USBD_OK;
}
break;
case USB_REQ_GET_DESCRIPTOR:
if ((req->wValue >> 8) == HID_REPORT_DESC)
{
if (interface == 0U)
{
descriptor = gamepadReportDescriptor;
length = sizeof(gamepadReportDescriptor);
}
else if (interface == 1U)
{
descriptor = setupReportDescriptor;
length = sizeof(setupReportDescriptor);
}
else
{
descriptor = rawReportDescriptor;
length = sizeof(rawReportDescriptor);
}
}
else if ((req->wValue >> 8) == HID_DESCRIPTOR_TYPE)
{
static const uint8_t hidOffsets[3] = {18U, 43U, 75U};
descriptor = &dinputConfigDescriptor[hidOffsets[interface]];
length = 9U;
}
if (descriptor != NULL)
{
USBD_CtlSendData(pdev, descriptor, MIN(length, req->wLength));
return USBD_OK;
}
break;
default:
break;
}
}
USBD_CtlError(pdev, req);
return USBD_FAIL;
}
uint8_t USBD_DINPUT_SendReport(USBD_HandleTypeDef *pdev,
uint8_t *report,
uint16_t len)
{
USBD_DINPUT_HandleTypeDef *handle =
(USBD_DINPUT_HandleTypeDef *)pdev->pClassData;
if ((pdev->dev_state == USBD_STATE_CONFIGURED) &&
(handle != NULL) && (handle->busy == 0U) &&
(len == DINPUT_REPORT_SIZE))
{
handle->busy = 1U;
memcpy(dinputInBuffer, report, DINPUT_REPORT_SIZE);
return USBD_LL_Transmit(pdev, DINPUT_GAMEPAD_EPIN_ADDR,
dinputInBuffer, len);
}
return USBD_OK;
}
static uint8_t DINPUT_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
if ((epnum == (DINPUT_GAMEPAD_EPIN_ADDR & 0x0FU)) &&
(pdev->pClassData != NULL))
{
((USBD_DINPUT_HandleTypeDef *)pdev->pClassData)->busy = 0U;
return USBD_OK;
}
return USBD_FAIL;
}
static uint8_t DINPUT_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
if (epnum == (DINPUT_SETUP_EPOUT_ADDR & 0x0FU))
{
USBD_LL_PrepareReceive(pdev, DINPUT_SETUP_EPOUT_ADDR,
dinputSetupOutBuffer, DINPUT_EP_SIZE);
return USBD_OK;
}
return USBD_FAIL;
}
static uint8_t *DINPUT_GetCfgDesc(uint16_t *length)
{
*length = sizeof(dinputConfigDescriptor);
return dinputConfigDescriptor;
}
static uint8_t *DINPUT_GetDeviceQualifierDesc(uint16_t *length)
{
*length = sizeof(dinputDeviceQualifierDescriptor);
return dinputDeviceQualifierDescriptor;
}
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
static uint8_t *DINPUT_GetUserString(USBD_HandleTypeDef *pdev,
uint8_t index,
uint16_t *length)
{
const char *text;
UNUSED(pdev);
if (index == 0x06U)
{
text = "Setup";
}
else if (index == 0x07U)
{
text = "Raw";
}
else
{
*length = 0U;
return NULL;
}
USBD_GetString((uint8_t *)text, dinputStringBuffer, length);
return dinputStringBuffer;
}
#endif

View File

@@ -0,0 +1,28 @@
#ifndef USBD_DINPUT_H
#define USBD_DINPUT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "usbd_core.h"
#define DINPUT_GAMEPAD_EPIN_ADDR 0x81U
#define DINPUT_SETUP_EPIN_ADDR 0x82U
#define DINPUT_SETUP_EPOUT_ADDR 0x02U
#define DINPUT_RAW_EPIN_ADDR 0x83U
#define DINPUT_EP_SIZE 64U
#define DINPUT_REPORT_SIZE 9U
#define USB_DINPUT_CONFIG_DESC_SIZ 91U
extern USBD_ClassTypeDef USBD_DINPUT;
uint8_t USBD_DINPUT_SendReport(USBD_HandleTypeDef *pdev,
uint8_t *report,
uint16_t len);
#ifdef __cplusplus
}
#endif
#endif /* USBD_DINPUT_H */

View File

@@ -0,0 +1,437 @@
#include "usbd_xinput.h"
#include "usbd_ctlreq.h"
#include <string.h>
static uint8_t USBD_XINPUT_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_XINPUT_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_XINPUT_Setup(USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req);
static uint8_t USBD_XINPUT_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_XINPUT_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t *USBD_XINPUT_GetCfgDesc(uint16_t *length);
static uint8_t *USBD_XINPUT_GetDeviceQualifierDesc(uint16_t *length);
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
static uint8_t *USBD_XINPUT_GetUserString(USBD_HandleTypeDef *pdev,
uint8_t index,
uint16_t *length);
#endif
static uint8_t xinputOutBuffer[XINPUT_EP_SIZE];
static uint8_t xinputSetupOutBuffer[XINPUT_EP_SIZE];
static uint8_t xinputInBuffer[XINPUT_REPORT_SIZE];
static volatile uint8_t rumbleLeft;
static volatile uint8_t rumbleRight;
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
static uint8_t xinputStringBuffer[32];
#endif
USBD_ClassTypeDef USBD_XINPUT =
{
USBD_XINPUT_Init,
USBD_XINPUT_DeInit,
USBD_XINPUT_Setup,
NULL,
NULL,
USBD_XINPUT_DataIn,
USBD_XINPUT_DataOut,
NULL,
NULL,
NULL,
USBD_XINPUT_GetCfgDesc,
USBD_XINPUT_GetCfgDesc,
USBD_XINPUT_GetCfgDesc,
USBD_XINPUT_GetDeviceQualifierDesc,
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
USBD_XINPUT_GetUserString,
#endif
};
/* Original three-interface layout. Only IF0 implements device behavior. */
__ALIGN_BEGIN static uint8_t USBD_XINPUT_CfgDesc[USB_XINPUT_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, USB_DESC_TYPE_CONFIGURATION,
LOBYTE(USB_XINPUT_CONFIG_DESC_SIZ), HIBYTE(USB_XINPUT_CONFIG_DESC_SIZ),
0x03, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
0x80, /* Bus powered */
0x32, /* 100 mA */
0x09, USB_DESC_TYPE_INTERFACE,
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x02, /* bNumEndpoints */
0xFF, /* Vendor specific */
0x5D, /* XUSB */
0x01, /* Xbox 360 wired controller */
0x00, /* iInterface */
/* XUSB class-specific descriptor from the working controller firmware. */
0x11, 0x21, 0x10, 0x01, 0x01, 0x25, 0x81, 0x14,
0x03, 0x03, 0x03, 0x04, 0x13, 0x02, 0x08, 0x03, 0x03,
0x07, USB_DESC_TYPE_ENDPOINT,
XINPUT_EPIN_ADDR,
0x03, /* Interrupt */
LOBYTE(XINPUT_EP_SIZE), HIBYTE(XINPUT_EP_SIZE),
0x01,
0x07, USB_DESC_TYPE_ENDPOINT,
XINPUT_EPOUT_ADDR,
0x03, /* Interrupt */
LOBYTE(XINPUT_EP_SIZE), HIBYTE(XINPUT_EP_SIZE),
0x01,
/* IF1: descriptor-compatible Setup HID; data path intentionally stalled. */
0x09, USB_DESC_TYPE_INTERFACE,
0x01, 0x00, 0x02,
0x03, 0x00, 0x00, 0x06,
0x09, 0x21,
0x11, 0x01, 0x00, 0x01, 0x22,
0x22, 0x00,
0x07, USB_DESC_TYPE_ENDPOINT,
XINPUT_SETUP_EPIN_ADDR, 0x03,
LOBYTE(XINPUT_EP_SIZE), HIBYTE(XINPUT_EP_SIZE), 0x01,
0x07, USB_DESC_TYPE_ENDPOINT,
XINPUT_SETUP_EPOUT_ADDR, 0x03,
LOBYTE(XINPUT_EP_SIZE), HIBYTE(XINPUT_EP_SIZE), 0x01,
/* IF2: descriptor-compatible Raw HID; data path intentionally stalled. */
0x09, USB_DESC_TYPE_INTERFACE,
0x02, 0x00, 0x01,
0x03, 0x00, 0x00, 0x07,
0x09, 0x21,
0x11, 0x01, 0x00, 0x01, 0x22,
0x15, 0x00,
0x07, USB_DESC_TYPE_ENDPOINT,
XINPUT_RAW_EPIN_ADDR, 0x03,
LOBYTE(XINPUT_EP_SIZE), HIBYTE(XINPUT_EP_SIZE), 0x01,
};
__ALIGN_BEGIN static uint8_t xinputSetupReportDescriptor[] __ALIGN_END =
{
0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01,
0x09, 0x10, 0x15, 0x00, 0x26, 0xFF, 0x00,
0x75, 0x08, 0x95, 0x1A, 0x81, 0x02,
0x09, 0x11, 0x15, 0x00, 0x26, 0xFF, 0x00,
0x75, 0x08, 0x95, 0x1B, 0x91, 0x02,
0xC0
};
__ALIGN_BEGIN static uint8_t xinputRawReportDescriptor[] __ALIGN_END =
{
0x06, 0x00, 0xFF, 0x09, 0x02, 0xA1, 0x01,
0x09, 0x20, 0x15, 0x00, 0x26, 0xFF, 0x00,
0x75, 0x08, 0x95, 0x18, 0x81, 0x02,
0xC0
};
_Static_assert(sizeof(xinputSetupReportDescriptor) == 34U,
"Setup report descriptor length changed");
_Static_assert(sizeof(xinputRawReportDescriptor) == 21U,
"Raw report descriptor length changed");
__ALIGN_BEGIN static uint8_t USBD_XINPUT_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER,
0x00, 0x02,
0x00, 0x00, 0x00,
USB_MAX_EP0_SIZE,
0x01,
0x00,
};
static uint8_t USBD_XINPUT_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
USBD_XINPUT_HandleTypeDef *handle;
UNUSED(cfgidx);
USBD_LL_OpenEP(pdev, XINPUT_EPIN_ADDR, USBD_EP_TYPE_INTR, XINPUT_EP_SIZE);
pdev->ep_in[XINPUT_EPIN_ADDR & 0x0FU].is_used = 1U;
USBD_LL_OpenEP(pdev, XINPUT_EPOUT_ADDR, USBD_EP_TYPE_INTR, XINPUT_EP_SIZE);
pdev->ep_out[XINPUT_EPOUT_ADDR & 0x0FU].is_used = 1U;
USBD_LL_OpenEP(pdev, XINPUT_SETUP_EPIN_ADDR,
USBD_EP_TYPE_INTR, XINPUT_EP_SIZE);
pdev->ep_in[XINPUT_SETUP_EPIN_ADDR & 0x0FU].is_used = 1U;
USBD_LL_OpenEP(pdev, XINPUT_SETUP_EPOUT_ADDR,
USBD_EP_TYPE_INTR, XINPUT_EP_SIZE);
pdev->ep_out[XINPUT_SETUP_EPOUT_ADDR & 0x0FU].is_used = 1U;
USBD_LL_OpenEP(pdev, XINPUT_RAW_EPIN_ADDR,
USBD_EP_TYPE_INTR, XINPUT_EP_SIZE);
pdev->ep_in[XINPUT_RAW_EPIN_ADDR & 0x0FU].is_used = 1U;
pdev->pClassData = USBD_malloc(sizeof(USBD_XINPUT_HandleTypeDef));
if (pdev->pClassData == NULL)
{
return USBD_FAIL;
}
handle = (USBD_XINPUT_HandleTypeDef *)pdev->pClassData;
memset(handle, 0, sizeof(*handle));
handle->state = XINPUT_IDLE;
rumbleLeft = 0U;
rumbleRight = 0U;
USBD_LL_PrepareReceive(pdev, XINPUT_EPOUT_ADDR,
xinputOutBuffer, XINPUT_EP_SIZE);
/* Stub HID data paths: unused IN endpoints naturally answer NAK. Setup OUT
* packets are accepted and discarded so Windows can start both interfaces. */
USBD_LL_PrepareReceive(pdev, XINPUT_SETUP_EPOUT_ADDR,
xinputSetupOutBuffer, XINPUT_EP_SIZE);
return USBD_OK;
}
static uint8_t USBD_XINPUT_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
UNUSED(cfgidx);
USBD_LL_CloseEP(pdev, XINPUT_EPIN_ADDR);
pdev->ep_in[XINPUT_EPIN_ADDR & 0x0FU].is_used = 0U;
USBD_LL_CloseEP(pdev, XINPUT_EPOUT_ADDR);
pdev->ep_out[XINPUT_EPOUT_ADDR & 0x0FU].is_used = 0U;
USBD_LL_CloseEP(pdev, XINPUT_SETUP_EPIN_ADDR);
pdev->ep_in[XINPUT_SETUP_EPIN_ADDR & 0x0FU].is_used = 0U;
USBD_LL_CloseEP(pdev, XINPUT_SETUP_EPOUT_ADDR);
pdev->ep_out[XINPUT_SETUP_EPOUT_ADDR & 0x0FU].is_used = 0U;
USBD_LL_CloseEP(pdev, XINPUT_RAW_EPIN_ADDR);
pdev->ep_in[XINPUT_RAW_EPIN_ADDR & 0x0FU].is_used = 0U;
if (pdev->pClassData != NULL)
{
USBD_free(pdev->pClassData);
pdev->pClassData = NULL;
}
return USBD_OK;
}
static uint8_t USBD_XINPUT_Setup(USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
static uint8_t capability20[20] =
{
0x00, 0x14, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xC0,
0xFF, 0xC0, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static uint8_t capability8[8] =
{
0x00, 0x08, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00
};
static uint8_t status4[4] =
{
0x28, 0x00, 0x00, 0x00
};
USBD_XINPUT_HandleTypeDef *handle =
(USBD_XINPUT_HandleTypeDef *)pdev->pClassData;
uint16_t statusInfo = 0U;
uint8_t interface = (uint8_t)req->wIndex;
uint8_t *descriptor = NULL;
uint16_t descriptorLength = 0U;
if ((req->bmRequest == 0xC1U) && (req->bRequest == 0x01U) &&
(req->wValue == 0x0100U) && (req->wIndex == 0x0000U) &&
(req->wLength == sizeof(capability20)))
{
USBD_CtlSendData(pdev, capability20, sizeof(capability20));
return USBD_OK;
}
if ((req->bmRequest == 0xC1U) && (req->bRequest == 0x01U) &&
(req->wValue == 0x0000U) && (req->wIndex == 0x0000U) &&
(req->wLength == sizeof(capability8)))
{
USBD_CtlSendData(pdev, capability8, sizeof(capability8));
return USBD_OK;
}
if ((req->bmRequest == 0xC0U) && (req->bRequest == 0x01U) &&
(req->wValue == 0x0000U) && (req->wIndex == 0x0000U) &&
(req->wLength == sizeof(status4)))
{
USBD_CtlSendData(pdev, status4, sizeof(status4));
return USBD_OK;
}
/* No Microsoft OS descriptors or compatible-ID vendor request exists. */
if ((req->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS)
{
USBD_CtlError(pdev, req);
return USBD_FAIL;
}
if (((req->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) &&
(interface <= 2U))
{
switch (req->bRequest)
{
case USB_REQ_GET_STATUS:
USBD_CtlSendData(pdev, (uint8_t *)&statusInfo, sizeof(statusInfo));
return USBD_OK;
case USB_REQ_GET_INTERFACE:
if (handle == NULL)
{
break;
}
USBD_CtlSendData(pdev, &handle->AltSetting[interface], 1U);
return USBD_OK;
case USB_REQ_SET_INTERFACE:
if (handle == NULL)
{
break;
}
if (req->wValue == 0U)
{
handle->AltSetting[interface] = 0U;
return USBD_OK;
}
break;
case USB_REQ_GET_DESCRIPTOR:
if ((interface == 1U) && ((req->wValue >> 8) == 0x22U))
{
descriptor = xinputSetupReportDescriptor;
descriptorLength = sizeof(xinputSetupReportDescriptor);
}
else if ((interface == 2U) && ((req->wValue >> 8) == 0x22U))
{
descriptor = xinputRawReportDescriptor;
descriptorLength = sizeof(xinputRawReportDescriptor);
}
else if (((interface == 1U) || (interface == 2U)) &&
((req->wValue >> 8) == 0x21U))
{
descriptor = &USBD_XINPUT_CfgDesc[(interface == 1U) ? 58U : 90U];
descriptorLength = 9U;
}
if (descriptor != NULL)
{
USBD_CtlSendData(pdev, descriptor,
MIN(descriptorLength, req->wLength));
return USBD_OK;
}
break;
default:
break;
}
}
USBD_CtlError(pdev, req);
return USBD_FAIL;
}
uint8_t USBD_XINPUT_SendReport(USBD_HandleTypeDef *pdev,
uint8_t *report,
uint16_t len)
{
USBD_XINPUT_HandleTypeDef *handle =
(USBD_XINPUT_HandleTypeDef *)pdev->pClassData;
if ((pdev->dev_state == USBD_STATE_CONFIGURED) &&
(handle != NULL) && (handle->state == XINPUT_IDLE) &&
(len == XINPUT_REPORT_SIZE))
{
handle->state = XINPUT_BUSY;
memcpy(xinputInBuffer, report, XINPUT_REPORT_SIZE);
USBD_LL_Transmit(pdev, XINPUT_EPIN_ADDR, xinputInBuffer, len);
}
return USBD_OK;
}
static uint8_t USBD_XINPUT_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
if ((epnum == (XINPUT_EPIN_ADDR & 0x0FU)) &&
(pdev->pClassData != NULL))
{
((USBD_XINPUT_HandleTypeDef *)pdev->pClassData)->state = XINPUT_IDLE;
return USBD_OK;
}
return USBD_FAIL;
}
static uint8_t USBD_XINPUT_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
uint32_t length;
if (epnum == (XINPUT_SETUP_EPOUT_ADDR & 0x0FU))
{
/* No setup protocol is implemented. Discard data and keep the endpoint
* alive rather than halting the whole HID interface. */
USBD_LL_PrepareReceive(pdev, XINPUT_SETUP_EPOUT_ADDR,
xinputSetupOutBuffer, XINPUT_EP_SIZE);
return USBD_OK;
}
if (epnum != (XINPUT_EPOUT_ADDR & 0x0FU))
{
return USBD_FAIL;
}
length = USBD_LL_GetRxDataSize(pdev, XINPUT_EPOUT_ADDR);
if ((length == 8U) && (xinputOutBuffer[0] == 0x00U) &&
(xinputOutBuffer[1] == 0x08U))
{
rumbleLeft = xinputOutBuffer[3];
rumbleRight = xinputOutBuffer[4];
}
USBD_LL_PrepareReceive(pdev, XINPUT_EPOUT_ADDR,
xinputOutBuffer, XINPUT_EP_SIZE);
return USBD_OK;
}
uint8_t USBD_XINPUT_GetRumbleLeft(void)
{
return rumbleLeft;
}
uint8_t USBD_XINPUT_GetRumbleRight(void)
{
return rumbleRight;
}
static uint8_t *USBD_XINPUT_GetCfgDesc(uint16_t *length)
{
*length = sizeof(USBD_XINPUT_CfgDesc);
return USBD_XINPUT_CfgDesc;
}
static uint8_t *USBD_XINPUT_GetDeviceQualifierDesc(uint16_t *length)
{
*length = sizeof(USBD_XINPUT_DeviceQualifierDesc);
return USBD_XINPUT_DeviceQualifierDesc;
}
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
static uint8_t *USBD_XINPUT_GetUserString(USBD_HandleTypeDef *pdev,
uint8_t index,
uint16_t *length)
{
const char *text;
UNUSED(pdev);
if (index == 0x06U)
{
text = "Setup";
}
else if (index == 0x07U)
{
text = "Raw";
}
else
{
*length = 0U;
return NULL;
}
USBD_GetString((uint8_t *)text, xinputStringBuffer, length);
return xinputStringBuffer;
}
#endif

View File

@@ -0,0 +1,44 @@
#ifndef USBD_XINPUT_H
#define USBD_XINPUT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "usbd_core.h"
#include "usbd_ioreq.h"
#define XINPUT_EPIN_ADDR 0x81U
#define XINPUT_EPOUT_ADDR 0x02U
#define XINPUT_SETUP_EPIN_ADDR 0x83U
#define XINPUT_SETUP_EPOUT_ADDR 0x03U
#define XINPUT_RAW_EPIN_ADDR 0x84U
#define XINPUT_EP_SIZE 64U
#define XINPUT_REPORT_SIZE 20U
#define USB_XINPUT_CONFIG_DESC_SIZ 106U
typedef enum
{
XINPUT_IDLE = 0,
XINPUT_BUSY
} XINPUT_StateTypeDef;
typedef struct
{
uint8_t AltSetting[3];
XINPUT_StateTypeDef state;
} USBD_XINPUT_HandleTypeDef;
extern USBD_ClassTypeDef USBD_XINPUT;
uint8_t USBD_XINPUT_SendReport(USBD_HandleTypeDef *pdev,
uint8_t *report,
uint16_t len);
uint8_t USBD_XINPUT_GetRumbleLeft(void);
uint8_t USBD_XINPUT_GetRumbleRight(void);
#ifdef __cplusplus
}
#endif
#endif /* USBD_XINPUT_H */