|
| 1 | +//Uno: SDA = A4, SCL = A5 |
| 2 | +//Pro Micro: SDA = D2, SCL = D3 |
| 3 | + |
| 4 | +//================================================================================ |
| 5 | +//================================================================================ |
| 6 | +// Joystick (Gamepad) |
| 7 | + |
| 8 | +#include "HID.h" |
| 9 | + |
| 10 | +#if ARDUINO < 10606 |
| 11 | +#error The Joystick2 library requires Arduino IDE 1.6.6 or greater. Please update your IDE. |
| 12 | +#endif |
| 13 | + |
| 14 | +#if !defined(USBCON) |
| 15 | +#error The Joystick2 library can only be used with a USB MCU (e.g. Arduino Leonardo, Arduino Micro, etc.). |
| 16 | +#endif |
| 17 | + |
| 18 | +#if !defined(_USING_HID) |
| 19 | +#error "Using legacy HID core (non pluggable)" |
| 20 | +#endif |
| 21 | + |
| 22 | +#define JOYSTICK_REPORT_ID 0x04 |
| 23 | +#define JOYSTICK_STATE_SIZE 7 |
| 24 | +#define JOYSTICK_DATA_SIZE 6 |
| 25 | + |
| 26 | +#define NUNCHUCK 1 |
| 27 | +#define CLASSIC_CONTROLLER 2 |
| 28 | +#define CLASSIC_CONTROLLER_PRO 3 |
| 29 | + |
| 30 | +//#define DEBUG |
| 31 | + |
| 32 | +#define HIDDESC_MACRO(REPORT_ID) \ |
| 33 | + /* Joystick # */ \ |
| 34 | + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \ |
| 35 | + 0x09, 0x04, /* USAGE (Joystick) */ \ |
| 36 | + 0xa1, 0x01, /* COLLECTION (Application) */ \ |
| 37 | + 0x85, REPORT_ID, /* REPORT_ID */ \ |
| 38 | + /* 15 Buttons */ \ |
| 39 | + 0x05, 0x09, /* USAGE_PAGE (Button) */ \ |
| 40 | + 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ \ |
| 41 | + 0x29, 0x0F, /* USAGE_MAXIMUM (Button 15) */ \ |
| 42 | + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ |
| 43 | + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ |
| 44 | + 0x75, 0x01, /* REPORT_SIZE (1) */ \ |
| 45 | + 0x95, 0x0F, /* REPORT_COUNT (15) */ \ |
| 46 | + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ |
| 47 | + 0x75, 0x01, /* REPORT_SIZE (1) */ \ |
| 48 | + 0x95, 0x01, /* REPORT_COUNT (1) */ \ |
| 49 | + 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \ |
| 50 | + /* X and Y Axis */ \ |
| 51 | + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \ |
| 52 | + 0x09, 0x01, /* USAGE (Pointer) */ \ |
| 53 | + 0xA1, 0x00, /* COLLECTION (Physical) */ \ |
| 54 | + 0x09, 0x30, /* USAGE (x) */ \ |
| 55 | + 0x09, 0x31, /* USAGE (y) */ \ |
| 56 | + 0x09, 0x33, /* USAGE (Rx) */ \ |
| 57 | + 0x09, 0x34, /* USAGE (Ry) */ \ |
| 58 | + 0x09, 0x35, /* USAGE (Rz) */ \ |
| 59 | + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ |
| 60 | + 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */ \ |
| 61 | + 0x75, 0x08, /* REPORT_SIZE (8) */ \ |
| 62 | + 0x95, 0x05, /* REPORT_COUNT (5) */ \ |
| 63 | + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ |
| 64 | + 0xc0, /* END_COLLECTION */ \ |
| 65 | + 0xc0 /* END_COLLECTION */ |
| 66 | + |
| 67 | + |
| 68 | +static const uint8_t hidReportDescriptor[] PROGMEM = { |
| 69 | + HIDDESC_MACRO(JOYSTICK_REPORT_ID) |
| 70 | +}; |
| 71 | + |
| 72 | +class Joystick_ { |
| 73 | + |
| 74 | +private: |
| 75 | + uint8_t joystickId; |
| 76 | + uint8_t reportId; |
| 77 | + uint8_t olddata[JOYSTICK_DATA_SIZE]; |
| 78 | + uint8_t state[JOYSTICK_STATE_SIZE]; |
| 79 | + uint8_t flag; |
| 80 | + |
| 81 | +public: |
| 82 | + uint8_t data[JOYSTICK_DATA_SIZE]; |
| 83 | + |
| 84 | + Joystick_(uint8_t initJoystickId, uint8_t initReportId) { |
| 85 | + // Setup HID report structure |
| 86 | + static bool usbSetup = false; |
| 87 | + |
| 88 | + if (!usbSetup) { |
| 89 | + static HIDSubDescriptor node(hidReportDescriptor, sizeof(hidReportDescriptor)); |
| 90 | + HID().AppendDescriptor(&node); |
| 91 | + usbSetup = true; |
| 92 | + } |
| 93 | + |
| 94 | + // Initalize State |
| 95 | + joystickId = initJoystickId; |
| 96 | + reportId = initReportId; |
| 97 | + memcpy(olddata, data, JOYSTICK_DATA_SIZE); |
| 98 | + state[0] = 0; |
| 99 | + state[1] = 0; |
| 100 | + state[2] = 127; |
| 101 | + state[3] = 127; |
| 102 | + state[4] = 127; |
| 103 | + state[5] = 127; |
| 104 | + state[6] = 127; |
| 105 | + sendState(1); |
| 106 | + } |
| 107 | + |
| 108 | + void updateState(uint8_t type) { |
| 109 | + if (memcmp(olddata, data, JOYSTICK_DATA_SIZE)) { |
| 110 | + memcpy(olddata, data, JOYSTICK_DATA_SIZE); |
| 111 | + flag = 1; |
| 112 | + } |
| 113 | + |
| 114 | + if (type == NUNCHUCK) { |
| 115 | + // http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck |
| 116 | + uint8_t SX = data[0]; |
| 117 | + uint8_t SY = data[1]; |
| 118 | + uint16_t AX = (data[2] << 2) | (data[5] >> 2 & B11); |
| 119 | + uint16_t AY = (data[3] << 2) | (data[5] >> 4 & B11); |
| 120 | + uint16_t AZ = (data[4] << 2) | (data[5] >> 6 & B11); |
| 121 | + uint8_t BC = (~data[5] >> 1 & 1); |
| 122 | + uint8_t BZ = (~data[5] & 1); |
| 123 | + |
| 124 | + state[0] = (BZ << 1) | BC; |
| 125 | + state[1] = 0; |
| 126 | + state[2] = SX; |
| 127 | + state[3] = ~SY; |
| 128 | + state[4] = AX >> 2; |
| 129 | + state[5] = AY >> 2; |
| 130 | + state[6] = AZ >> 2; |
| 131 | + } |
| 132 | + if (type == CLASSIC_CONTROLLER || type == CLASSIC_CONTROLLER_PRO) { |
| 133 | + // http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Classic_Controller |
| 134 | + uint8_t LX = (data[0] & 0x3f); //6bit |
| 135 | + uint8_t LY = (data[1] & 0x3f); //6bit |
| 136 | + uint8_t RX = ((data[0] & 0xc0) >> 3) + ((data[1] & 0xc0) >> 5) + ((data[2] & 0x80) >> 7); //5bit |
| 137 | + uint8_t RY = (data[2] & 0x1f); //5bit |
| 138 | + uint8_t BDU = ~data[5] & 1; |
| 139 | + uint8_t BDD = ~data[4] >> 6 & 1; |
| 140 | + uint8_t BDL = ~data[5] >> 1 & 1; |
| 141 | + uint8_t BDR = ~data[4] >> 7 & 1; |
| 142 | + uint8_t Bselect = ~data[4] >> 4 & 1; |
| 143 | + uint8_t BH = ~data[4] >> 3 & 1; |
| 144 | + uint8_t Bstart = ~data[4] >> 2 & 1; |
| 145 | + uint8_t BA = ~data[5] >> 4 & 1; |
| 146 | + uint8_t BB = ~data[5] >> 6 & 1; |
| 147 | + uint8_t BX = ~data[5] >> 3 & 1; |
| 148 | + uint8_t BY = ~data[5] >> 5 & 1; |
| 149 | + uint8_t BLT = ~data[4] >> 5 & 1; |
| 150 | + uint8_t BRT = ~data[4] >> 1 & 1; |
| 151 | + uint8_t BZL = ~data[5] >> 7 & 1; |
| 152 | + uint8_t BZR = ~data[5] >> 2 & 1; |
| 153 | + uint8_t LT = ((data[2] & 0x60) >> 2) + ((data[3] & 0xe0) >> 5); |
| 154 | + uint8_t RT = (data[3] & 0x1f); |
| 155 | + |
| 156 | + state[0] = (BZR << 7) | (BZL << 6) | (BRT << 5) | (BLT << 4) | (BY << 3) | (BX << 2) | (BB << 1) | BA; |
| 157 | + state[1] = (Bstart << 6) | (BH << 5) | (Bselect << 4) | (BDR << 3) | (BDL << 2) | (BDD << 1) | BDU; |
| 158 | + state[2] = LX << 2; |
| 159 | + state[3] = ~(LY << 2); |
| 160 | + state[4] = RX << 3; |
| 161 | + state[5] = ~(RY << 3); |
| 162 | + state[6] = 127; |
| 163 | + } |
| 164 | + } |
| 165 | + |
| 166 | + void sendState(uint8_t force = 0) { |
| 167 | + if (flag || force) { |
| 168 | + // HID().SendReport(Report number, array of values in same order as HID descriptor, length) |
| 169 | + HID().SendReport(reportId, state, JOYSTICK_STATE_SIZE); |
| 170 | + flag = 0; |
| 171 | + } |
| 172 | + } |
| 173 | + |
| 174 | +}; |
| 175 | + |
| 176 | + |
| 177 | +Joystick_ Joystick[1] = |
| 178 | +{ |
| 179 | + Joystick_(0, JOYSTICK_REPORT_ID) |
| 180 | +}; |
| 181 | + |
| 182 | +//================================================================================ |
| 183 | +//================================================================================ |
| 184 | + |
| 185 | +#include <Wire.h> |
| 186 | + |
| 187 | +#define ADDRESS 0x52 |
| 188 | + |
| 189 | +uint16_t type; |
| 190 | + |
| 191 | +const uint8_t ident_nunchuck[] = { 0x00, 0x00, 0xA4, 0x20, 0x00, 0x00 }; |
| 192 | +const uint8_t ident_classic_controller[] = { 0x00, 0x00, 0xA4, 0x20, 0x01, 0x01 }; |
| 193 | +const uint8_t ident_classic_controller_pro[] = { 0x01, 0x00, 0xA4, 0x20, 0x00, 0x00 }; |
| 194 | + |
| 195 | + |
| 196 | +void sendByte(uint8_t data, uint8_t location) { |
| 197 | + Wire.beginTransmission(ADDRESS); |
| 198 | + Wire.write(location); |
| 199 | + Wire.write(data); |
| 200 | + Wire.endTransmission(); |
| 201 | +} |
| 202 | + |
| 203 | +void sendByte(uint8_t data) { |
| 204 | + Wire.beginTransmission(ADDRESS); |
| 205 | + Wire.write(data); |
| 206 | + Wire.endTransmission(); |
| 207 | +} |
| 208 | + |
| 209 | +uint8_t initExtension() { |
| 210 | + uint8_t buf[6]; |
| 211 | + uint8_t type = CLASSIC_CONTROLLER; // default type |
| 212 | + sendByte(0x55, 0xF0); |
| 213 | + sendByte(0x00, 0xFB); |
| 214 | + sendByte(0xFA); |
| 215 | + delayMicroseconds(200); |
| 216 | + Wire.requestFrom(ADDRESS, 6); |
| 217 | + uint8_t i = 0; |
| 218 | + while(Wire.available()) { |
| 219 | + buf[i] = Wire.read(); |
| 220 | + i++; |
| 221 | + if (i >= 6) break; |
| 222 | + } |
| 223 | + if (memcmp(buf, ident_nunchuck, 6) == 0) type = NUNCHUCK; |
| 224 | + if (memcmp(buf, ident_classic_controller, 6) == 0) type = CLASSIC_CONTROLLER; |
| 225 | + if (memcmp(buf, ident_classic_controller_pro, 6) == 0) type = CLASSIC_CONTROLLER_PRO; |
| 226 | + return type; |
| 227 | +} |
| 228 | + |
| 229 | +void setup() { |
| 230 | + Wire.begin(); |
| 231 | + type = initExtension(); |
| 232 | + |
| 233 | + #ifdef DEBUG |
| 234 | + Serial.begin(115200); |
| 235 | + #endif |
| 236 | + |
| 237 | +} |
| 238 | + |
| 239 | +void loop() { |
| 240 | + |
| 241 | + #ifdef DEBUG |
| 242 | + unsigned long t = micros(); |
| 243 | + #endif |
| 244 | + |
| 245 | + sendByte(0x00); |
| 246 | + delayMicroseconds(200); |
| 247 | + Wire.requestFrom(ADDRESS, 6); //request data from wii nunchuck |
| 248 | + uint8_t i = 0; |
| 249 | + while(Wire.available()) { |
| 250 | + Joystick[0].data[i] = Wire.read(); |
| 251 | + i++; |
| 252 | + if (i >= JOYSTICK_DATA_SIZE) break; |
| 253 | + } |
| 254 | + |
| 255 | + //detect if init is needed |
| 256 | + if (i < JOYSTICK_DATA_SIZE) { |
| 257 | + delay(10); |
| 258 | + type = initExtension(); |
| 259 | + #ifdef DEBUG |
| 260 | + Serial.println("Init!"); |
| 261 | + #endif |
| 262 | + delay(10); |
| 263 | + } |
| 264 | + |
| 265 | + #ifdef DEBUG |
| 266 | + Serial.println(micros()-t); |
| 267 | + #endif |
| 268 | + |
| 269 | + #ifdef DEBUG |
| 270 | + for (uint8_t i = 0; i < JOYSTICK_DATA_SIZE; i++) { |
| 271 | + Serial.print(data[i], HEX); |
| 272 | + Serial.print(" "); |
| 273 | + } |
| 274 | + Serial.println(); |
| 275 | + #endif |
| 276 | + |
| 277 | + Joystick[0].updateState(type); |
| 278 | + Joystick[0].sendState(); |
| 279 | + #ifdef DEBUG |
| 280 | + delay(100); |
| 281 | + #endif |
| 282 | + delayMicroseconds(500); |
| 283 | +} |
0 commit comments