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:
Mon Apr 20 14:58:21 2015 +0000
Revision:
2:278b7a590311
Parent:
0:c8e9c90ca7f4
Support for FRDM-KL25Z; ; This board has better usb functionality, no it works on a PS3 too! (..minus the "PS" button...)

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 2:278b7a590311 107 // USAGE_PAGE(1), 0x02, // Simulation Controls
eimaiosatanas 2:278b7a590311 108 // USAGE(1), 0xBB, // Throttle
eimaiosatanas 2:278b7a590311 109 // USAGE(1), 0xBA, // Rudder
eimaiosatanas 2:278b7a590311 110 // LOGICAL_MINIMUM(1), 0x81, // -127
eimaiosatanas 2:278b7a590311 111 // LOGICAL_MAXIMUM(1), 0x7f, // 127
eimaiosatanas 2:278b7a590311 112 // REPORT_SIZE(1), 0x08,
eimaiosatanas 2:278b7a590311 113 // REPORT_COUNT(1), 0x02,
eimaiosatanas 2:278b7a590311 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 2:278b7a590311 120 USAGE(1), 0x32, //R
eimaiosatanas 2:278b7a590311 121 USAGE(1), 0x35, //Rz?
eimaiosatanas 0:c8e9c90ca7f4 122 // 8 bit values
eimaiosatanas 0:c8e9c90ca7f4 123 LOGICAL_MINIMUM(1), 0x81, // -127
eimaiosatanas 0:c8e9c90ca7f4 124 LOGICAL_MAXIMUM(1), 0x7f, // 127
eimaiosatanas 0:c8e9c90ca7f4 125 REPORT_SIZE(1), 0x08,
eimaiosatanas 2:278b7a590311 126 REPORT_COUNT(1), 0x04,
eimaiosatanas 0:c8e9c90ca7f4 127 INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 128 // 16 bit values
eimaiosatanas 0:c8e9c90ca7f4 129 // LOGICAL_MINIMUM(1), 0x00, // 0
eimaiosatanas 0:c8e9c90ca7f4 130 // LOGICAL_MAXIMUM(2), 0xff, 0x7f, // 32767
eimaiosatanas 0:c8e9c90ca7f4 131 // REPORT_SIZE(1), 0x10,
eimaiosatanas 0:c8e9c90ca7f4 132 // REPORT_COUNT(1), 0x02,
eimaiosatanas 0:c8e9c90ca7f4 133 // INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 134
eimaiosatanas 0:c8e9c90ca7f4 135 END_COLLECTION(0),
eimaiosatanas 0:c8e9c90ca7f4 136 // 4 Position Hat Switch
eimaiosatanas 0:c8e9c90ca7f4 137 // USAGE(1), 0x39, // Usage (Hat switch)
eimaiosatanas 0:c8e9c90ca7f4 138 // LOGICAL_MINIMUM(1), 0x00, // 0
eimaiosatanas 0:c8e9c90ca7f4 139 // LOGICAL_MAXIMUM(1), 0x03, // 3
eimaiosatanas 0:c8e9c90ca7f4 140 // PHYSICAL_MINIMUM(1), 0x00, // Physical_Minimum (0)
eimaiosatanas 0:c8e9c90ca7f4 141 // PHYSICAL_MAXIMUM(2), 0x0E, 0x01, // Physical_Maximum (270)
eimaiosatanas 0:c8e9c90ca7f4 142 // UNIT(1), 0x14, // Unit (Eng Rot:Angular Pos)
eimaiosatanas 0:c8e9c90ca7f4 143 // REPORT_SIZE(1), 0x04,
eimaiosatanas 0:c8e9c90ca7f4 144 // REPORT_COUNT(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 145 // INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 146 // 8 Position Hat Switch
eimaiosatanas 0:c8e9c90ca7f4 147 USAGE(1), 0x39, // Usage (Hat switch)
eimaiosatanas 0:c8e9c90ca7f4 148 LOGICAL_MINIMUM(1), 0x00, // 0
eimaiosatanas 0:c8e9c90ca7f4 149 LOGICAL_MAXIMUM(1), 0x07, // 7
eimaiosatanas 0:c8e9c90ca7f4 150 PHYSICAL_MINIMUM(1), 0x00, // Physical_Minimum (0)
eimaiosatanas 0:c8e9c90ca7f4 151 PHYSICAL_MAXIMUM(2), 0x3B, 0x01, // Physical_Maximum (315)
eimaiosatanas 0:c8e9c90ca7f4 152 UNIT(1), 0x14, // Unit (Eng Rot:Angular Pos)
eimaiosatanas 0:c8e9c90ca7f4 153 REPORT_SIZE(1), 0x04,
eimaiosatanas 0:c8e9c90ca7f4 154 REPORT_COUNT(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 155 INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 156 //
eimaiosatanas 0:c8e9c90ca7f4 157 USAGE_PAGE(1), 0x09, // Buttons
eimaiosatanas 0:c8e9c90ca7f4 158 USAGE_MINIMUM(1), 0x01, // 1
eimaiosatanas 0:c8e9c90ca7f4 159 USAGE_MAXIMUM(1), 0x0D, // 13
eimaiosatanas 0:c8e9c90ca7f4 160 LOGICAL_MINIMUM(1), 0x00, // 0
eimaiosatanas 0:c8e9c90ca7f4 161 LOGICAL_MAXIMUM(1), 0x01, // 1
eimaiosatanas 0:c8e9c90ca7f4 162 REPORT_SIZE(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 163 REPORT_COUNT(1), 0x0D,
eimaiosatanas 0:c8e9c90ca7f4 164 UNIT_EXPONENT(1), 0x00, // Unit_Exponent (0)
eimaiosatanas 0:c8e9c90ca7f4 165 UNIT(1), 0x00, // Unit (None)
eimaiosatanas 0:c8e9c90ca7f4 166 INPUT(1), 0x02, // Data, Variable, Absolute
eimaiosatanas 0:c8e9c90ca7f4 167
eimaiosatanas 0:c8e9c90ca7f4 168 // Padding 7 bits
eimaiosatanas 0:c8e9c90ca7f4 169 REPORT_SIZE(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 170 REPORT_COUNT(1), 0x07,
eimaiosatanas 0:c8e9c90ca7f4 171 INPUT(1), 0x01,
eimaiosatanas 0:c8e9c90ca7f4 172 END_COLLECTION(0)
eimaiosatanas 0:c8e9c90ca7f4 173
eimaiosatanas 0:c8e9c90ca7f4 174 };
eimaiosatanas 0:c8e9c90ca7f4 175
eimaiosatanas 0:c8e9c90ca7f4 176 reportLength = sizeof(reportDescriptor);
eimaiosatanas 0:c8e9c90ca7f4 177 return reportDescriptor;
eimaiosatanas 0:c8e9c90ca7f4 178 }
eimaiosatanas 0:c8e9c90ca7f4 179
eimaiosatanas 0:c8e9c90ca7f4 180