模拟游戏设备 - Raspberry PI 零
Emulate a Gaming Device - Raspberry PI Zero
嗨,我想将我的 Raspberry PI 零用作 HID 设备(操纵杆)。
当我将 Raspberry PI 零 USB 端口连接到我的电脑时,我希望它显示为操纵杆并向其添加 X 和 Y 轴,我目前设法显示 raspberry pi 零作为键盘并向其发送击键。通过使用 this 页面作为参考,有人知道我的想法是否真的可行吗?
应该可以(但我没有PI硬件来测试)。
您 link 中的报告描述符指定了一个 keyboard-only HID 报告描述符 - 即使标题是 "Keyboard / Mouse / Joystick (HID)":
echo -ne \x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00
\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03
\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01
\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07
\x19\x00\x29\x65\x81\x00\xc0 > functions/hid.usb0/report_desc
...解码为:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page
09 06 (LOCAL) USAGE 0x00010006 Keyboard (CA=Application Collection)
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x00010006: Page=Generic Desktop Page, Usage=Keyboard, Type=CA)
05 07 (GLOBAL) USAGE_PAGE 0x0007 Keyboard/Keypad Page
19 E0 (LOCAL) USAGE_MINIMUM 0x000700E0 Keyboard Left Control (DV=Dynamic Value)
29 E7 (LOCAL) USAGE_MAXIMUM 0x000700E7 Keyboard Right GUI (DV=Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields
81 02 (MAIN) INPUT 0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
81 03 (MAIN) INPUT 0x00000003 (1 field x 8 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 05 (GLOBAL) REPORT_COUNT 0x05 (5) Number of fields
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
05 08 (GLOBAL) USAGE_PAGE 0x0008 LED Indicator Page
19 01 (LOCAL) USAGE_MINIMUM 0x00080001 Num Lock (OOC=On/Off Control)
29 05 (LOCAL) USAGE_MAXIMUM 0x00080005 Kana (OOC=On/Off Control)
91 02 (MAIN) OUTPUT 0x00000002 (5 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
75 03 (GLOBAL) REPORT_SIZE 0x03 (3) Number of bits per field
91 03 (MAIN) OUTPUT 0x00000003 (1 field x 3 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 06 (GLOBAL) REPORT_COUNT 0x06 (6) Number of fields
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 65 (GLOBAL) LOGICAL_MAXIMUM 0x65 (101)
05 07 (GLOBAL) USAGE_PAGE 0x0007 Keyboard/Keypad Page
19 00 (LOCAL) USAGE_MINIMUM 0x00070000 Keyboard No event indicated (Sel=Selector)
29 65 (LOCAL) USAGE_MAXIMUM 0x00070065 Keyboard Application (Sel=Selector)
81 00 (MAIN) INPUT 0x00000000 (6 fields x 8 bits) 0=Data 0=Array 0=Absolute
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Keyboard/Keypad Page inputReport (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: Keyboard
uint8_t KB_KeyboardKeyboardLeftControl : 1; // Usage 0x000700E0: Keyboard Left Control, Value = 0 to 1
uint8_t KB_KeyboardKeyboardLeftShift : 1; // Usage 0x000700E1: Keyboard Left Shift, Value = 0 to 1
uint8_t KB_KeyboardKeyboardLeftAlt : 1; // Usage 0x000700E2: Keyboard Left Alt, Value = 0 to 1
uint8_t KB_KeyboardKeyboardLeftGui : 1; // Usage 0x000700E3: Keyboard Left GUI, Value = 0 to 1
uint8_t KB_KeyboardKeyboardRightControl : 1; // Usage 0x000700E4: Keyboard Right Control, Value = 0 to 1
uint8_t KB_KeyboardKeyboardRightShift : 1; // Usage 0x000700E5: Keyboard Right Shift, Value = 0 to 1
uint8_t KB_KeyboardKeyboardRightAlt : 1; // Usage 0x000700E6: Keyboard Right Alt, Value = 0 to 1
uint8_t KB_KeyboardKeyboardRightGui : 1; // Usage 0x000700E7: Keyboard Right GUI, Value = 0 to 1
uint8_t pad_2; // Pad
uint8_t KB_Keyboard[6]; // Value = 0 to 101
} inputReport_t;
//--------------------------------------------------------------------------------
// LED Indicator Page outputReport (Device <-- Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: Keyboard
uint8_t LED_KeyboardNumLock : 1; // Usage 0x00080001: Num Lock, Value = 0 to 1
uint8_t LED_KeyboardCapsLock : 1; // Usage 0x00080002: Caps Lock, Value = 0 to 1
uint8_t LED_KeyboardScrollLock : 1; // Usage 0x00080003: Scroll Lock, Value = 0 to 1
uint8_t LED_KeyboardCompose : 1; // Usage 0x00080004: Compose, Value = 0 to 1
uint8_t LED_KeyboardKana : 1; // Usage 0x00080005: Kana, Value = 0 to 1
uint8_t : 3; // Pad
} outputReport_t;
我认为至少需要更改 HID 报告描述符字节以指定操纵杆报告而不是键盘报告。有很多替代方案,但像下面这样的东西,它定义了一个 8 位 x- 和 y-axis 以及 8 个按钮,可能是一个很好的起点:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page
09 04 (LOCAL) USAGE 0x00010004 Joystick (CA=Application Collection)
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x00010004: Page=Generic Desktop Page, Usage=Joystick, Type=CA)
15 81 (GLOBAL) LOGICAL_MINIMUM 0x81 (-127)
25 7F (GLOBAL) LOGICAL_MAXIMUM 0x7F (127)
09 01 (LOCAL) USAGE 0x00010001 Pointer (CP=Physical Collection)
A1 00 (MAIN) COLLECTION 0x00000000 Physical (Usage=0x00010001: Page=Generic Desktop Page, Usage=Pointer, Type=CP)
09 30 (LOCAL) USAGE 0x00010030 X (DV=Dynamic Value)
09 31 (LOCAL) USAGE 0x00010031 Y (DV=Dynamic Value)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
95 02 (GLOBAL) REPORT_COUNT 0x02 (2) Number of fields
81 02 (MAIN) INPUT 0x00000002 (2 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Physical
05 09 (GLOBAL) USAGE_PAGE 0x0009 Button Page
19 01 (LOCAL) USAGE_MINIMUM 0x00090001 Button 1 Primary/trigger (MULTI=Selector, On/Off, Momentary, or One Shot)
29 08 (LOCAL) USAGE_MAXIMUM 0x00090008 Button 8 (MULTI=Selector, On/Off, Momentary, or One Shot)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields
81 02 (MAIN) INPUT 0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Generic Desktop Page inputReport (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: Joystick Pointer
int8_t GD_JoystickPointerX; // Usage 0x00010030: X, Value = -127 to 127
int8_t GD_JoystickPointerY; // Usage 0x00010031: Y, Value = -127 to 127
// Collection: Joystick
uint8_t BTN_JoystickButton1 : 1; // Usage 0x00090001: Button 1 Primary/trigger, Value = 0 to 1
uint8_t BTN_JoystickButton2 : 1; // Usage 0x00090002: Button 2 Secondary, Value = 0 to 1
uint8_t BTN_JoystickButton3 : 1; // Usage 0x00090003: Button 3 Tertiary, Value = 0 to 1
uint8_t BTN_JoystickButton4 : 1; // Usage 0x00090004: Button 4, Value = 0 to 1
uint8_t BTN_JoystickButton5 : 1; // Usage 0x00090005: Button 5, Value = 0 to 1
uint8_t BTN_JoystickButton6 : 1; // Usage 0x00090006: Button 6, Value = 0 to 1
uint8_t BTN_JoystickButton7 : 1; // Usage 0x00090007: Button 7, Value = 0 to 1
uint8_t BTN_JoystickButton8 : 1; // Usage 0x00090008: Button 8, Value = 0 to 1
} inputReport_t;
您可能还需要更改:
echo 1 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass
...定义了一个BOOT键盘,为:
echo 0 > functions/hid.usb0/protocol
echo 0 > functions/hid.usb0/subclass
...表示该设备没有特定的子类(例如 BOOT 设备)或协议(例如键盘或鼠标)。
可能还需要进行其他更改,但正如我所说,我没有可用于试验的硬件。
希望对您有所帮助。
嗨,我想将我的 Raspberry PI 零用作 HID 设备(操纵杆)。
当我将 Raspberry PI 零 USB 端口连接到我的电脑时,我希望它显示为操纵杆并向其添加 X 和 Y 轴,我目前设法显示 raspberry pi 零作为键盘并向其发送击键。通过使用 this 页面作为参考,有人知道我的想法是否真的可行吗?
应该可以(但我没有PI硬件来测试)。
您 link 中的报告描述符指定了一个 keyboard-only HID 报告描述符 - 即使标题是 "Keyboard / Mouse / Joystick (HID)":
echo -ne \x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00
\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03
\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01
\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07
\x19\x00\x29\x65\x81\x00\xc0 > functions/hid.usb0/report_desc
...解码为:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page
09 06 (LOCAL) USAGE 0x00010006 Keyboard (CA=Application Collection)
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x00010006: Page=Generic Desktop Page, Usage=Keyboard, Type=CA)
05 07 (GLOBAL) USAGE_PAGE 0x0007 Keyboard/Keypad Page
19 E0 (LOCAL) USAGE_MINIMUM 0x000700E0 Keyboard Left Control (DV=Dynamic Value)
29 E7 (LOCAL) USAGE_MAXIMUM 0x000700E7 Keyboard Right GUI (DV=Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields
81 02 (MAIN) INPUT 0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
81 03 (MAIN) INPUT 0x00000003 (1 field x 8 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 05 (GLOBAL) REPORT_COUNT 0x05 (5) Number of fields
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
05 08 (GLOBAL) USAGE_PAGE 0x0008 LED Indicator Page
19 01 (LOCAL) USAGE_MINIMUM 0x00080001 Num Lock (OOC=On/Off Control)
29 05 (LOCAL) USAGE_MAXIMUM 0x00080005 Kana (OOC=On/Off Control)
91 02 (MAIN) OUTPUT 0x00000002 (5 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
75 03 (GLOBAL) REPORT_SIZE 0x03 (3) Number of bits per field
91 03 (MAIN) OUTPUT 0x00000003 (1 field x 3 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 06 (GLOBAL) REPORT_COUNT 0x06 (6) Number of fields
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 65 (GLOBAL) LOGICAL_MAXIMUM 0x65 (101)
05 07 (GLOBAL) USAGE_PAGE 0x0007 Keyboard/Keypad Page
19 00 (LOCAL) USAGE_MINIMUM 0x00070000 Keyboard No event indicated (Sel=Selector)
29 65 (LOCAL) USAGE_MAXIMUM 0x00070065 Keyboard Application (Sel=Selector)
81 00 (MAIN) INPUT 0x00000000 (6 fields x 8 bits) 0=Data 0=Array 0=Absolute
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Keyboard/Keypad Page inputReport (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: Keyboard
uint8_t KB_KeyboardKeyboardLeftControl : 1; // Usage 0x000700E0: Keyboard Left Control, Value = 0 to 1
uint8_t KB_KeyboardKeyboardLeftShift : 1; // Usage 0x000700E1: Keyboard Left Shift, Value = 0 to 1
uint8_t KB_KeyboardKeyboardLeftAlt : 1; // Usage 0x000700E2: Keyboard Left Alt, Value = 0 to 1
uint8_t KB_KeyboardKeyboardLeftGui : 1; // Usage 0x000700E3: Keyboard Left GUI, Value = 0 to 1
uint8_t KB_KeyboardKeyboardRightControl : 1; // Usage 0x000700E4: Keyboard Right Control, Value = 0 to 1
uint8_t KB_KeyboardKeyboardRightShift : 1; // Usage 0x000700E5: Keyboard Right Shift, Value = 0 to 1
uint8_t KB_KeyboardKeyboardRightAlt : 1; // Usage 0x000700E6: Keyboard Right Alt, Value = 0 to 1
uint8_t KB_KeyboardKeyboardRightGui : 1; // Usage 0x000700E7: Keyboard Right GUI, Value = 0 to 1
uint8_t pad_2; // Pad
uint8_t KB_Keyboard[6]; // Value = 0 to 101
} inputReport_t;
//--------------------------------------------------------------------------------
// LED Indicator Page outputReport (Device <-- Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: Keyboard
uint8_t LED_KeyboardNumLock : 1; // Usage 0x00080001: Num Lock, Value = 0 to 1
uint8_t LED_KeyboardCapsLock : 1; // Usage 0x00080002: Caps Lock, Value = 0 to 1
uint8_t LED_KeyboardScrollLock : 1; // Usage 0x00080003: Scroll Lock, Value = 0 to 1
uint8_t LED_KeyboardCompose : 1; // Usage 0x00080004: Compose, Value = 0 to 1
uint8_t LED_KeyboardKana : 1; // Usage 0x00080005: Kana, Value = 0 to 1
uint8_t : 3; // Pad
} outputReport_t;
我认为至少需要更改 HID 报告描述符字节以指定操纵杆报告而不是键盘报告。有很多替代方案,但像下面这样的东西,它定义了一个 8 位 x- 和 y-axis 以及 8 个按钮,可能是一个很好的起点:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page
09 04 (LOCAL) USAGE 0x00010004 Joystick (CA=Application Collection)
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x00010004: Page=Generic Desktop Page, Usage=Joystick, Type=CA)
15 81 (GLOBAL) LOGICAL_MINIMUM 0x81 (-127)
25 7F (GLOBAL) LOGICAL_MAXIMUM 0x7F (127)
09 01 (LOCAL) USAGE 0x00010001 Pointer (CP=Physical Collection)
A1 00 (MAIN) COLLECTION 0x00000000 Physical (Usage=0x00010001: Page=Generic Desktop Page, Usage=Pointer, Type=CP)
09 30 (LOCAL) USAGE 0x00010030 X (DV=Dynamic Value)
09 31 (LOCAL) USAGE 0x00010031 Y (DV=Dynamic Value)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
95 02 (GLOBAL) REPORT_COUNT 0x02 (2) Number of fields
81 02 (MAIN) INPUT 0x00000002 (2 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Physical
05 09 (GLOBAL) USAGE_PAGE 0x0009 Button Page
19 01 (LOCAL) USAGE_MINIMUM 0x00090001 Button 1 Primary/trigger (MULTI=Selector, On/Off, Momentary, or One Shot)
29 08 (LOCAL) USAGE_MAXIMUM 0x00090008 Button 8 (MULTI=Selector, On/Off, Momentary, or One Shot)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields
81 02 (MAIN) INPUT 0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Generic Desktop Page inputReport (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: Joystick Pointer
int8_t GD_JoystickPointerX; // Usage 0x00010030: X, Value = -127 to 127
int8_t GD_JoystickPointerY; // Usage 0x00010031: Y, Value = -127 to 127
// Collection: Joystick
uint8_t BTN_JoystickButton1 : 1; // Usage 0x00090001: Button 1 Primary/trigger, Value = 0 to 1
uint8_t BTN_JoystickButton2 : 1; // Usage 0x00090002: Button 2 Secondary, Value = 0 to 1
uint8_t BTN_JoystickButton3 : 1; // Usage 0x00090003: Button 3 Tertiary, Value = 0 to 1
uint8_t BTN_JoystickButton4 : 1; // Usage 0x00090004: Button 4, Value = 0 to 1
uint8_t BTN_JoystickButton5 : 1; // Usage 0x00090005: Button 5, Value = 0 to 1
uint8_t BTN_JoystickButton6 : 1; // Usage 0x00090006: Button 6, Value = 0 to 1
uint8_t BTN_JoystickButton7 : 1; // Usage 0x00090007: Button 7, Value = 0 to 1
uint8_t BTN_JoystickButton8 : 1; // Usage 0x00090008: Button 8, Value = 0 to 1
} inputReport_t;
您可能还需要更改:
echo 1 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass
...定义了一个BOOT键盘,为:
echo 0 > functions/hid.usb0/protocol
echo 0 > functions/hid.usb0/subclass
...表示该设备没有特定的子类(例如 BOOT 设备)或协议(例如键盘或鼠标)。
可能还需要进行其他更改,但正如我所说,我没有可用于试验的硬件。
希望对您有所帮助。