Modification of USB Joystick to work as a Hitbox-like game controller using the F401RE. Works reasonably well under Windows.

Dependencies:   USBDevice mbed

This is a hobby project trying to recreate a Hitbox Controller for fun .

The original code was based off of http://developer.mbed.org/users/wim/notebook/usb-joystick-device/ Slight modifications were made to the USB HID descriptor to up the number of buttons reported to 13.

Currently, this works well under Windows and Linux, but no luck getting it to work with Mac OS X or a PS3 so far.

If anybody has useful information, feel free to contribute. :)

p.s: My thread for hooking up an F401RE board as a USB device is here: http://developer.mbed.org/questions/5364/Cannot-get-the-Nucleo-F401RE-to-work-as-/

p.s.2: Cabling information and <del>pictures</del> will be uploaded in the near future.

p.s.3: 2015-04-20: added support for FRDM-KL25Z board. Due to the better usb functionality, this hitbox now works on Windows, Mac OS X, Linux and PS3 too! (minus the "PS" button...)

Committer:
eimaiosatanas
Date:
Wed Dec 03 07:54:52 2014 +0000
Revision:
0:c8e9c90ca7f4
Child:
2:278b7a590311
First reasonably working modification for a hitbox game controller

Who changed what in which revision?

UserRevisionLine numberNew contents of line
eimaiosatanas 0:c8e9c90ca7f4 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
eimaiosatanas 0:c8e9c90ca7f4 2 * Modified Mouse code for Joystick - WH 2012
eimaiosatanas 0:c8e9c90ca7f4 3 *
eimaiosatanas 0:c8e9c90ca7f4 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
eimaiosatanas 0:c8e9c90ca7f4 5 * and associated documentation files (the "Software"), to deal in the Software without
eimaiosatanas 0:c8e9c90ca7f4 6 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
eimaiosatanas 0:c8e9c90ca7f4 7 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
eimaiosatanas 0:c8e9c90ca7f4 8 * Software is furnished to do so, subject to the following conditions:
eimaiosatanas 0:c8e9c90ca7f4 9 *
eimaiosatanas 0:c8e9c90ca7f4 10 * The above copyright notice and this permission notice shall be included in all copies or
eimaiosatanas 0:c8e9c90ca7f4 11 * substantial portions of the Software.
eimaiosatanas 0:c8e9c90ca7f4 12 *
eimaiosatanas 0:c8e9c90ca7f4 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
eimaiosatanas 0:c8e9c90ca7f4 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
eimaiosatanas 0:c8e9c90ca7f4 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
eimaiosatanas 0:c8e9c90ca7f4 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
eimaiosatanas 0:c8e9c90ca7f4 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
eimaiosatanas 0:c8e9c90ca7f4 18 */
eimaiosatanas 0:c8e9c90ca7f4 19
eimaiosatanas 0:c8e9c90ca7f4 20 #include "stdint.h"
eimaiosatanas 0:c8e9c90ca7f4 21 #include "USBJoystick.h"
eimaiosatanas 0:c8e9c90ca7f4 22
eimaiosatanas 0:c8e9c90ca7f4 23 bool USBJoystick::update(int16_t t, int16_t r, int16_t x, int16_t y, uint16_t button, uint8_t hat) {
eimaiosatanas 0:c8e9c90ca7f4 24 HID_REPORT report;
eimaiosatanas 0:c8e9c90ca7f4 25 _t = t;
eimaiosatanas 0:c8e9c90ca7f4 26 _r = r;
eimaiosatanas 0:c8e9c90ca7f4 27 _x = x;
eimaiosatanas 0:c8e9c90ca7f4 28 _y = y;
eimaiosatanas 0:c8e9c90ca7f4 29 _button = button;
eimaiosatanas 0:c8e9c90ca7f4 30 _hat = hat;
eimaiosatanas 0:c8e9c90ca7f4 31
eimaiosatanas 0:c8e9c90ca7f4 32 // Fill the report according to the Joystick Descriptor
eimaiosatanas 0:c8e9c90ca7f4 33 report.data[0] = _t & 0xff;
eimaiosatanas 0:c8e9c90ca7f4 34 report.data[1] = _r & 0xff;
eimaiosatanas 0:c8e9c90ca7f4 35 report.data[2] = _x & 0xff;
eimaiosatanas 0:c8e9c90ca7f4 36 report.data[3] = _y & 0xff;
eimaiosatanas 0:c8e9c90ca7f4 37 report.data[4] = ((_button & 0x0f) << 4) | (_hat & 0x0f) ;
eimaiosatanas 0:c8e9c90ca7f4 38 report.data[5] = (_button >> 4);
eimaiosatanas 0:c8e9c90ca7f4 39 //report.data[6] = 0;
eimaiosatanas 0:c8e9c90ca7f4 40 report.data[6] = ( _button >> 0x0C) & 0x01;
eimaiosatanas 0:c8e9c90ca7f4 41 report.length = 7;
eimaiosatanas 0:c8e9c90ca7f4 42
eimaiosatanas 0:c8e9c90ca7f4 43 return send(&report);
eimaiosatanas 0:c8e9c90ca7f4 44 }
eimaiosatanas 0:c8e9c90ca7f4 45
eimaiosatanas 0:c8e9c90ca7f4 46 bool USBJoystick::update() {
eimaiosatanas 0:c8e9c90ca7f4 47 HID_REPORT report;
eimaiosatanas 0:c8e9c90ca7f4 48
eimaiosatanas 0:c8e9c90ca7f4 49 // Fill the report according to the Joystick Descriptor
eimaiosatanas 0:c8e9c90ca7f4 50 report.data[0] = _t & 0xff;
eimaiosatanas 0:c8e9c90ca7f4 51 report.data[1] = _r & 0xff;
eimaiosatanas 0:c8e9c90ca7f4 52 report.data[2] = _x & 0xff;
eimaiosatanas 0:c8e9c90ca7f4 53 report.data[3] = _y & 0xff;
eimaiosatanas 0:c8e9c90ca7f4 54 report.data[4] = ((_button & 0x0f) << 4) | (_hat & 0x0f) ;
eimaiosatanas 0:c8e9c90ca7f4 55 report.data[5] = ( _button >> 4);
eimaiosatanas 0:c8e9c90ca7f4 56 report.data[6] = ( _button >> 0x0C) & 0x01;
eimaiosatanas 0:c8e9c90ca7f4 57 report.length = 7;
eimaiosatanas 0:c8e9c90ca7f4 58
eimaiosatanas 0:c8e9c90ca7f4 59 return send(&report);
eimaiosatanas 0:c8e9c90ca7f4 60 }
eimaiosatanas 0:c8e9c90ca7f4 61
eimaiosatanas 0:c8e9c90ca7f4 62 bool USBJoystick::throttle(int16_t t) {
eimaiosatanas 0:c8e9c90ca7f4 63 _t = t;
eimaiosatanas 0:c8e9c90ca7f4 64 return update();
eimaiosatanas 0:c8e9c90ca7f4 65 }
eimaiosatanas 0:c8e9c90ca7f4 66
eimaiosatanas 0:c8e9c90ca7f4 67 bool USBJoystick::rudder(int16_t r) {
eimaiosatanas 0:c8e9c90ca7f4 68 _r = r;
eimaiosatanas 0:c8e9c90ca7f4 69 return update();
eimaiosatanas 0:c8e9c90ca7f4 70 }
eimaiosatanas 0:c8e9c90ca7f4 71
eimaiosatanas 0:c8e9c90ca7f4 72 bool USBJoystick::move(int16_t x, int16_t y) {
eimaiosatanas 0:c8e9c90ca7f4 73 _x = x;
eimaiosatanas 0:c8e9c90ca7f4 74 _y = y;
eimaiosatanas 0:c8e9c90ca7f4 75 return update();
eimaiosatanas 0:c8e9c90ca7f4 76 }
eimaiosatanas 0:c8e9c90ca7f4 77
eimaiosatanas 0:c8e9c90ca7f4 78 bool USBJoystick::button(uint16_t button) {
eimaiosatanas 0:c8e9c90ca7f4 79 _button = button;
eimaiosatanas 0:c8e9c90ca7f4 80 return update();
eimaiosatanas 0:c8e9c90ca7f4 81 }
eimaiosatanas 0:c8e9c90ca7f4 82
eimaiosatanas 0:c8e9c90ca7f4 83 bool USBJoystick::hat(uint8_t hat) {
eimaiosatanas 0:c8e9c90ca7f4 84 _hat = hat;
eimaiosatanas 0:c8e9c90ca7f4 85 return update();
eimaiosatanas 0:c8e9c90ca7f4 86 }
eimaiosatanas 0:c8e9c90ca7f4 87
eimaiosatanas 0:c8e9c90ca7f4 88
eimaiosatanas 0:c8e9c90ca7f4 89 void USBJoystick::_init() {
eimaiosatanas 0:c8e9c90ca7f4 90
eimaiosatanas 0:c8e9c90ca7f4 91 _t = -127;
eimaiosatanas 0:c8e9c90ca7f4 92 _r = -127;
eimaiosatanas 0:c8e9c90ca7f4 93 _x = 0;
eimaiosatanas 0:c8e9c90ca7f4 94 _y = 0;
eimaiosatanas 0:c8e9c90ca7f4 95 _button = 0x00;
eimaiosatanas 0:c8e9c90ca7f4 96 _hat = 0x00;
eimaiosatanas 0:c8e9c90ca7f4 97 }
eimaiosatanas 0:c8e9c90ca7f4 98
eimaiosatanas 0:c8e9c90ca7f4 99
eimaiosatanas 0:c8e9c90ca7f4 100 uint8_t * USBJoystick::reportDesc() {
eimaiosatanas 0:c8e9c90ca7f4 101 static uint8_t reportDescriptor[] = {
eimaiosatanas 0:c8e9c90ca7f4 102
eimaiosatanas 0:c8e9c90ca7f4 103 USAGE_PAGE(1), 0x01, // Generic Desktop
eimaiosatanas 0:c8e9c90ca7f4 104 LOGICAL_MINIMUM(1), 0x00, // Logical_Minimum (0)
eimaiosatanas 0:c8e9c90ca7f4 105 USAGE(1), 0x04, // Usage (Joystick)
eimaiosatanas 0:c8e9c90ca7f4 106 COLLECTION(1), 0x01, // Application
eimaiosatanas 0:c8e9c90ca7f4 107 USAGE_PAGE(1), 0x02, // Simulation Controls
eimaiosatanas 0:c8e9c90ca7f4 108 USAGE(1), 0xBB, // Throttle
eimaiosatanas 0:c8e9c90ca7f4 109 USAGE(1), 0xBA, // Rudder
eimaiosatanas 0:c8e9c90ca7f4 110 LOGICAL_MINIMUM(1), 0x81, // -127
eimaiosatanas 0:c8e9c90ca7f4 111 LOGICAL_MAXIMUM(1), 0x7f, // 127
eimaiosatanas 0:c8e9c90ca7f4 112 REPORT_SIZE(1), 0x08,
eimaiosatanas 0:c8e9c90ca7f4 113 REPORT_COUNT(1), 0x02,
eimaiosatanas 0:c8e9c90ca7f4 114 INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 115 USAGE_PAGE(1), 0x01, // Generic Desktop
eimaiosatanas 0:c8e9c90ca7f4 116 USAGE(1), 0x01, // Usage (Pointer)
eimaiosatanas 0:c8e9c90ca7f4 117 COLLECTION(1), 0x00, // Physical
eimaiosatanas 0:c8e9c90ca7f4 118 USAGE(1), 0x30, // X
eimaiosatanas 0:c8e9c90ca7f4 119 USAGE(1), 0x31, // Y
eimaiosatanas 0:c8e9c90ca7f4 120 // 8 bit values
eimaiosatanas 0:c8e9c90ca7f4 121 LOGICAL_MINIMUM(1), 0x81, // -127
eimaiosatanas 0:c8e9c90ca7f4 122 LOGICAL_MAXIMUM(1), 0x7f, // 127
eimaiosatanas 0:c8e9c90ca7f4 123 REPORT_SIZE(1), 0x08,
eimaiosatanas 0:c8e9c90ca7f4 124 REPORT_COUNT(1), 0x02,
eimaiosatanas 0:c8e9c90ca7f4 125 INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 126 // 16 bit values
eimaiosatanas 0:c8e9c90ca7f4 127 // LOGICAL_MINIMUM(1), 0x00, // 0
eimaiosatanas 0:c8e9c90ca7f4 128 // LOGICAL_MAXIMUM(2), 0xff, 0x7f, // 32767
eimaiosatanas 0:c8e9c90ca7f4 129 // REPORT_SIZE(1), 0x10,
eimaiosatanas 0:c8e9c90ca7f4 130 // REPORT_COUNT(1), 0x02,
eimaiosatanas 0:c8e9c90ca7f4 131 // INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 132
eimaiosatanas 0:c8e9c90ca7f4 133 END_COLLECTION(0),
eimaiosatanas 0:c8e9c90ca7f4 134 // 4 Position Hat Switch
eimaiosatanas 0:c8e9c90ca7f4 135 // USAGE(1), 0x39, // Usage (Hat switch)
eimaiosatanas 0:c8e9c90ca7f4 136 // LOGICAL_MINIMUM(1), 0x00, // 0
eimaiosatanas 0:c8e9c90ca7f4 137 // LOGICAL_MAXIMUM(1), 0x03, // 3
eimaiosatanas 0:c8e9c90ca7f4 138 // PHYSICAL_MINIMUM(1), 0x00, // Physical_Minimum (0)
eimaiosatanas 0:c8e9c90ca7f4 139 // PHYSICAL_MAXIMUM(2), 0x0E, 0x01, // Physical_Maximum (270)
eimaiosatanas 0:c8e9c90ca7f4 140 // UNIT(1), 0x14, // Unit (Eng Rot:Angular Pos)
eimaiosatanas 0:c8e9c90ca7f4 141 // REPORT_SIZE(1), 0x04,
eimaiosatanas 0:c8e9c90ca7f4 142 // REPORT_COUNT(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 143 // INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 144 // 8 Position Hat Switch
eimaiosatanas 0:c8e9c90ca7f4 145 USAGE(1), 0x39, // Usage (Hat switch)
eimaiosatanas 0:c8e9c90ca7f4 146 LOGICAL_MINIMUM(1), 0x00, // 0
eimaiosatanas 0:c8e9c90ca7f4 147 LOGICAL_MAXIMUM(1), 0x07, // 7
eimaiosatanas 0:c8e9c90ca7f4 148 PHYSICAL_MINIMUM(1), 0x00, // Physical_Minimum (0)
eimaiosatanas 0:c8e9c90ca7f4 149 PHYSICAL_MAXIMUM(2), 0x3B, 0x01, // Physical_Maximum (315)
eimaiosatanas 0:c8e9c90ca7f4 150 UNIT(1), 0x14, // Unit (Eng Rot:Angular Pos)
eimaiosatanas 0:c8e9c90ca7f4 151 REPORT_SIZE(1), 0x04,
eimaiosatanas 0:c8e9c90ca7f4 152 REPORT_COUNT(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 153 INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 154 //
eimaiosatanas 0:c8e9c90ca7f4 155 USAGE_PAGE(1), 0x09, // Buttons
eimaiosatanas 0:c8e9c90ca7f4 156 USAGE_MINIMUM(1), 0x01, // 1
eimaiosatanas 0:c8e9c90ca7f4 157 USAGE_MAXIMUM(1), 0x0D, // 13
eimaiosatanas 0:c8e9c90ca7f4 158 LOGICAL_MINIMUM(1), 0x00, // 0
eimaiosatanas 0:c8e9c90ca7f4 159 LOGICAL_MAXIMUM(1), 0x01, // 1
eimaiosatanas 0:c8e9c90ca7f4 160 REPORT_SIZE(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 161 REPORT_COUNT(1), 0x0D,
eimaiosatanas 0:c8e9c90ca7f4 162 UNIT_EXPONENT(1), 0x00, // Unit_Exponent (0)
eimaiosatanas 0:c8e9c90ca7f4 163 UNIT(1), 0x00, // Unit (None)
eimaiosatanas 0:c8e9c90ca7f4 164 INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 165
eimaiosatanas 0:c8e9c90ca7f4 166 // Padding 7 bits
eimaiosatanas 0:c8e9c90ca7f4 167 REPORT_SIZE(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 168 REPORT_COUNT(1), 0x07,
eimaiosatanas 0:c8e9c90ca7f4 169 INPUT(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 170 END_COLLECTION(0)
eimaiosatanas 0:c8e9c90ca7f4 171
eimaiosatanas 0:c8e9c90ca7f4 172 };
eimaiosatanas 0:c8e9c90ca7f4 173
eimaiosatanas 0:c8e9c90ca7f4 174 reportLength = sizeof(reportDescriptor);
eimaiosatanas 0:c8e9c90ca7f4 175 return reportDescriptor;
eimaiosatanas 0:c8e9c90ca7f4 176 }
eimaiosatanas 0:c8e9c90ca7f4 177
eimaiosatanas 0:c8e9c90ca7f4 178