Initial Refleks Lite hardware and firmware release
This commit is contained in:
95
arcadestick_software/USB_DEVICE/App/usb_device.c
Normal file
95
arcadestick_software/USB_DEVICE/App/usb_device.c
Normal 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 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
102
arcadestick_software/USB_DEVICE/App/usb_device.h
Normal file
102
arcadestick_software/USB_DEVICE/App/usb_device.h
Normal 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__ */
|
||||
23
arcadestick_software/USB_DEVICE/App/usb_device_dfu.c
Normal file
23
arcadestick_software/USB_DEVICE/App/usb_device_dfu.c
Normal 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();
|
||||
}
|
||||
}
|
||||
23
arcadestick_software/USB_DEVICE/App/usb_device_dinput.c
Normal file
23
arcadestick_software/USB_DEVICE/App/usb_device_dinput.c
Normal 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();
|
||||
}
|
||||
}
|
||||
23
arcadestick_software/USB_DEVICE/App/usb_device_xinput.c
Normal file
23
arcadestick_software/USB_DEVICE/App/usb_device_xinput.c
Normal 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();
|
||||
}
|
||||
}
|
||||
394
arcadestick_software/USB_DEVICE/App/usbd_desc.c
Normal file
394
arcadestick_software/USB_DEVICE/App/usbd_desc.c
Normal 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;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
143
arcadestick_software/USB_DEVICE/App/usbd_desc.h
Normal file
143
arcadestick_software/USB_DEVICE/App/usbd_desc.h
Normal 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__ */
|
||||
|
||||
137
arcadestick_software/USB_DEVICE/App/usbd_desc_dfu.c
Normal file
137
arcadestick_software/USB_DEVICE/App/usbd_desc_dfu.c
Normal 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;
|
||||
}
|
||||
}
|
||||
156
arcadestick_software/USB_DEVICE/App/usbd_desc_dinput.c
Normal file
156
arcadestick_software/USB_DEVICE/App/usbd_desc_dinput.c
Normal 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;
|
||||
}
|
||||
}
|
||||
159
arcadestick_software/USB_DEVICE/App/usbd_desc_xinput.c
Normal file
159
arcadestick_software/USB_DEVICE/App/usbd_desc_xinput.c
Normal 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;
|
||||
}
|
||||
}
|
||||
369
arcadestick_software/USB_DEVICE/App/usbd_dfu_bootloader.c
Normal file
369
arcadestick_software/USB_DEVICE/App/usbd_dfu_bootloader.c
Normal 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;
|
||||
}
|
||||
22
arcadestick_software/USB_DEVICE/App/usbd_dfu_bootloader.h
Normal file
22
arcadestick_software/USB_DEVICE/App/usbd_dfu_bootloader.h
Normal 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 */
|
||||
390
arcadestick_software/USB_DEVICE/App/usbd_dinput.c
Normal file
390
arcadestick_software/USB_DEVICE/App/usbd_dinput.c
Normal 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
|
||||
28
arcadestick_software/USB_DEVICE/App/usbd_dinput.h
Normal file
28
arcadestick_software/USB_DEVICE/App/usbd_dinput.h
Normal 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 */
|
||||
437
arcadestick_software/USB_DEVICE/App/usbd_xinput.c
Normal file
437
arcadestick_software/USB_DEVICE/App/usbd_xinput.c
Normal 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
|
||||
44
arcadestick_software/USB_DEVICE/App/usbd_xinput.h
Normal file
44
arcadestick_software/USB_DEVICE/App/usbd_xinput.h
Normal 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 */
|
||||
Reference in New Issue
Block a user