diff --git a/examples/BasicGamepad/BasicGamepad.ino b/examples/BasicGamepad/BasicGamepad.ino new file mode 100644 index 0000000..20485c5 --- /dev/null +++ b/examples/BasicGamepad/BasicGamepad.ino @@ -0,0 +1,80 @@ +/* + * Project Teensy XInput Library + * @author David Madison + * @link github.com/dmadison/TeensyXInput + * @license MIT - Copyright (c) 2018 David Madison + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Example: BasicGamepad + * Description: Sets up a basic NES-style gamepad using the XInput library, + * and shows how to use the class functions. + * + */ + +#include + +// Directional Pad Pins +const int Pin_DpadUp = 0; +const int Pin_DpadDown = 1; +const int Pin_DpadLeft = 2; +const int Pin_DpadRight = 3; + +// Button Pins +const int Pin_ButtonA = 4; +const int Pin_ButtonB = 5; + +// Note: Buttons should be connected from the sensor pin (above) to ground +// when pressed + +void setup() { + // Set buttons as inputs, using internal pull-up resistors + pinMode(Pin_DpadUp, INPUT_PULLUP); + pinMode(Pin_DpadDown, INPUT_PULLUP); + pinMode(Pin_DpadLeft, INPUT_PULLUP); + pinMode(Pin_DpadRight, INPUT_PULLUP); + + pinMode(Pin_ButtonA, INPUT_PULLUP); + pinMode(Pin_ButtonB, INPUT_PULLUP); +} + +void loop() { + // Read pin values and store in variables + // (Note the "!" to invert the state, because LOW = pressed) + boolean dpadUp = !digitalRead(Pin_DpadUp); + boolean dpadDown = !digitalRead(Pin_DpadDown); + boolean dpadLeft = !digitalRead(Pin_DpadLeft); + boolean dpadRight = !digitalRead(Pin_DpadRight); + + boolean buttonA = !digitalRead(Pin_ButtonA); + boolean buttonB = !digitalRead(Pin_ButtonB); + + // Set XInput DPAD values + XInput.setDpad(dpadUp, dpadDown, dpadLeft, dpadRight); + + // Set XInput buttons + XInput.setButton(BUTTON_A, buttonA); + XInput.setButton(BUTTON_B, buttonB); + + // Send control data to the computer + XInput.send(); + + // Receive data (player number, rumble motors, etc.) + XInput.receive(); +} diff --git a/examples/Blink/Blink.ino b/examples/Blink/Blink.ino new file mode 100644 index 0000000..218cf39 --- /dev/null +++ b/examples/Blink/Blink.ino @@ -0,0 +1,45 @@ +/* + * Project Teensy XInput Library + * @author David Madison + * @link github.com/dmadison/TeensyXInput + * @license MIT - Copyright (c) 2018 David Madison + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Example: Blink + * Description: Using XInput, presses and then releases the "A" button + * every two seconds. Good for testing that the XInput + * library is working correctly. + */ + +#include + +void setup() { + +} + +void loop() { + XInput.press(BUTTON_A); + XInput.send(); + delay(1000); + + XInput.release(BUTTON_A); + XInput.send(); + delay(1000); +} diff --git a/examples/TestAll/TestAll.ino b/examples/TestAll/TestAll.ino new file mode 100644 index 0000000..13cba56 --- /dev/null +++ b/examples/TestAll/TestAll.ino @@ -0,0 +1,141 @@ +/* + * Project Teensy XInput Library + * @author David Madison + * @link github.com/dmadison/TeensyXInput + * @license MIT - Copyright (c) 2018 David Madison + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Example: TestAll + * Description: Automatically activate all possible XInput controls. + * Useful to test that everything is functioning properly. + * + * WARNING: This will spam inputs! Ground pin '0' to stop. + * + */ + +#include + +// Config Settings +const unsigned long CycleTime = 5000; // ms +const int SafetyPin = 0; // Ground this pin to prevent inputs + +// Button Setup +const int NumButtons = 10; +const int Buttons[NumButtons] = { + BUTTON_A, + BUTTON_B, + BUTTON_X, + BUTTON_Y, + BUTTON_LB, + BUTTON_RB, + BUTTON_BACK, + BUTTON_START, + BUTTON_L3, + BUTTON_R3, +}; +const unsigned long ButtonDuration = CycleTime / NumButtons; +unsigned long buttonTimeLast = 0; +int buttonID = 0; + +// DPad Setup +const int NumDirections = 4; +const unsigned long DPadDuration = CycleTime / NumDirections; +unsigned long dpadTimeLast = 0; +int dpadPosition = 0; + +// Triggers +const int TriggerMax = 255; // uint8_t max +const unsigned long TriggerDuration = CycleTime / (TriggerMax * 2); // Go up and down +unsigned long triggerTimeLast = 0; +uint8_t triggerVal = 0; +boolean triggerDirection = 0; + +// Joystick Setup +const int JoyMax = 32767; // int16_t max +const double angle_precision = (2 * PI) / (CycleTime / 4); // 4 because 250 Hz update rate +double angle = 0.0; + +void setup() { + pinMode(SafetyPin, INPUT_PULLUP); +} + +void loop() { + if (digitalRead(SafetyPin) == LOW) { + return; + } + + unsigned long t = millis(); // Get timestamp for comparison + + // DPad + if (t - dpadTimeLast >= DPadDuration) { // If enough time has passed, change the dpad + XInput.setDpad(dpadPosition == 0, dpadPosition == 1, dpadPosition == 2, dpadPosition == 3); + + dpadPosition++; // Increment the dpad counter + if (dpadPosition >= NumDirections) dpadPosition = 0; // Go back to 0 if we hit the limit + dpadTimeLast = t; // Save time we last did this + } + + // Buttons + if (t - buttonTimeLast >= ButtonDuration) { // If enough time has passed, change the button pressed + for (int i = 0; i < NumButtons; i++) { + XInput.release((XInputControl)Buttons[i]); // Relase all buttons + } + + XInput.press((XInputControl)Buttons[buttonID]); // Press the next button + buttonID++; // Increment the button counter + if (buttonID >= NumButtons) buttonID = 0; // Go back to 0 if we hit the limit + + buttonTimeLast = t; // Save time we last did this + } + + // Triggers + if (t - triggerTimeLast >= TriggerDuration) { // If enough time has passed, update the triggers + XInput.setTrigger(TRIGGER_LEFT, triggerVal); + XInput.setTrigger(TRIGGER_RIGHT, ~triggerVal); // Inverse + + // Increment trigger value based on direction + if (triggerDirection == 0) { triggerVal++; } + else { triggerVal--; } + + if (triggerVal == TriggerMax || triggerVal == 0) { // If we've hit the edge of the range + triggerDirection = !triggerDirection; // Reverse direction + } + + triggerTimeLast = t; // Save time we last did this + } + + // Calculate joystick x/y values using trig + int axis_x = sin(angle) * JoyMax; + int axis_y = cos(angle) * JoyMax; + + angle += angle_precision; + if (angle >= 360) { + angle -= 360; + } + + XInput.setJoystick(JOY_LEFT, axis_x, axis_y); // Clockwise + XInput.setJoystick(JOY_RIGHT, -axis_x, axis_y); // Counter-clockwise + + // Send values to PC + XInput.send(); + + // Receive data from PC + XInput.receive(); +} diff --git a/examples/WiiClassicController/WiiClassicController.ino b/examples/WiiClassicController/WiiClassicController.ino new file mode 100644 index 0000000..2e69018 --- /dev/null +++ b/examples/WiiClassicController/WiiClassicController.ino @@ -0,0 +1,75 @@ +/* + * Project Teensy XInput Library + * @author David Madison + * @link github.com/dmadison/TeensyXInput + * @license MIT - Copyright (c) 2018 David Madison + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Example: WiiClassicController + * Description: Maps the inputs from a Wii Classic Controller to an emulated + * Xbox 360 gamepad using XInput. Requires using the + * NintendoExtensionCtrl library and an extension adapter. + */ + +#include +#include // Library for the Wii controller communication + +ClassicController classic; + +void setup() { + classic.begin(); + + while (!classic.connect()) { + delay(1000); // Controller not connected + } +} + +void loop() { + if(classic.update()) { // Get new data! + XInput.setJoystick(JOY_LEFT, map((classic.leftJoyX() << 2), 0, 255, -32768, 32767), map((classic.leftJoyY() << 2), 0, 255, -32768, 32767)); + XInput.setJoystick(JOY_RIGHT, map((classic.rightJoyX() << 3), 0, 255, -32768, 32767), map((classic.rightJoyY() << 3), 0, 255, -32768, 32767)); + + XInput.setButton(BUTTON_A, classic.buttonB()); + XInput.setButton(BUTTON_B, classic.buttonA()); + XInput.setButton(BUTTON_X, classic.buttonY()); + XInput.setButton(BUTTON_Y, classic.buttonX()); + + XInput.setButton(BUTTON_START, classic.buttonPlus()); + XInput.setButton(BUTTON_BACK, classic.buttonMinus()); + XInput.setButton(BUTTON_LOGO, classic.buttonHome()); + + XInput.setDpad(classic.dpadUp(), classic.dpadDown(), classic.dpadLeft(), classic.dpadRight()); + + XInput.setTrigger(TRIGGER_LEFT, classic.triggerL() << 3); + XInput.setTrigger(TRIGGER_RIGHT, classic.triggerR() << 3); + + XInput.setButton(BUTTON_LB, classic.buttonZL()); + XInput.setButton(BUTTON_RB, classic.buttonZR()); + + // XInput.setButton(BUTTON_L3, classic.buttonZL()); // The Classic Controller doesn't have L3 and R3 + // XInput.setButton(BUTTON_R3, classic.buttonZR()); // but you can uncomment these to check that they work + + XInput.send(); + XInput.receive(); + } + else { // Data is bad :( + classic.reconnect(); + } +}