Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 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.
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,56 @@
# Arduino XInput Library
# Arduino XInput Library

This library lets you easily emulate an Xbox 360 controller using a USB-capable Arduino microcontroller.

## Getting Started

```cpp
void setup() {
XInput.begin();
}

void loop() {
XInput.press(BUTTON_A);
delay(1000);

XInput.release(BUTTON_A);
delay(1000);
}
```

Before the library will work, you must install a compatible boards file that contains the XInput USB descriptors, otherwise the microcontroller won't behave like an XInput device. **This is not optional**. See the [compatible boards](#compatible-boards) section below for more information.

After installing a compatible boards package, you must then [download and install the library](https://www.arduino.cc/en/guide/libraries). Once the XInput library is installed, open up the Arduino IDE and load an example sketch, located in `File -> Examples -> XInput` (I suggest trying the 'Blink' sketch first). Double-check that you have the correct XInput board selected in the 'Tools' menu, then upload the sketch to your microcontroller.

On Windows, you can test that the sketch is working properly by opening up the joystick control panel ([joy.cpl](https://support.microsoft.com/en-us/help/831361/how-to-troubleshoot-game-controllers-in-microsoft-games)) or by using [GamepadViewer.com](https://gamepadviewer.com/?p=1). If you uploaded the XInput 'Blink' example, the #1 button ('A') should be slowly turning on and off.

## Control Surfaces

The library gives you access to the following controls available on the Xbox 360 controller:
* 10 + 1 Digital Buttons
* 2 Analog Joysticks (16 bit)
* 2 Analog Triggers (8 bit)
* 1 Four-Way Directional Pad (D-Pad)

The library also processes received data, so you can read the status of the controller's 2 rumble motors (8-bit), the assigned player number (1-4), and the index of the current LED animation. Data is sent and received automatically over USB.

## Compatible Boards

To function as an XInput device, you *must* use a compatible boards package with XInput USB descriptors. **This is not optional**. Without these descriptors the library will only function in "debug" mode and the microcontroller will not behave as an XInput device.

The following boards packages are available:

* #### [Arduino AVR Core Boards](https://www.github.com/dmadison/ArduinoXInput_AVR)
Modifies the Arduino AVR core to emulate an XInput device. Includes support for the Arduino Leonardo, Micro, Yun, and more.

* #### [SparkFun AVR Boards](https://www.github.com/dmadison/ArduinoXInput_SparkFun)
Provides support for the MaKey MaKey, Pro Micro, Fio, Qduino Mini, and LilyPad USB Plus. Requires the XInput AVR Core boards.

* #### [Teensy 3 Boards](https://www.github.com/dmadison/ArduinoXInput_Teensy)
Includes an 'XInput' USB mode for the Teensy 3.1, 3.2, 3.5, 3.6, and LC microcontrollers. Requires a preexisting Teensyduino installation.

For a complete list of available packages and compatible boards see [the 'supported boards' file](extras/SupportedBoards.md). For information on how to add support for another Arduino-compatible board with native USB support, see [the documentation on the USB API](extras/XInputUSB_API.md).

## License

This library is licensed under the terms of the [MIT license](https://opensource.org/licenses/MIT). See the [LICENSE](LICENSE) file for more information.
2 changes: 1 addition & 1 deletion examples/Blink/Blink.ino
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include <XInput.h>

void setup() {

XInput.begin();
}

void loop() {
Expand Down
6 changes: 3 additions & 3 deletions examples/GamepadPins/GamepadPins.ino
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ void setup() {
pinMode(Pin_DpadLeft, INPUT_PULLUP);
pinMode(Pin_DpadRight, INPUT_PULLUP);

// Set joystick range to the ADC max
XInput.setJoystickRange(0, ADC_Max);

XInput.setJoystickRange(0, ADC_Max); // Set joystick range to the ADC
XInput.setAutoSend(false); // Wait for all controls before sending

XInput.begin();
}

void loop() {
Expand Down
2 changes: 2 additions & 0 deletions examples/ReceiveCallback/ReceiveCallback.ino
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ void setup() {
// Set callback function. Function must have a 'void' return type
// and take a single uint8_t as an argument
XInput.setReceiveCallback(rumbleCallback);

XInput.begin();
}

void loop() {
Expand Down
2 changes: 2 additions & 0 deletions examples/SimulateAll/SimulateAll.ino
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ double angle = 0.0;
void setup() {
pinMode(SafetyPin, INPUT_PULLUP);
XInput.setAutoSend(false); // Wait for all controls before sending

XInput.begin();
}

void loop() {
Expand Down
2 changes: 2 additions & 0 deletions examples/WiiClassicController/WiiClassicController.ino
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ void setup() {

XInput.setAutoSend(false); // Wait for all controls before sending

XInput.begin();

while (!classic.connect()) {
delay(1000); // Controller not connected
}
Expand Down
34 changes: 34 additions & 0 deletions extras/SupportedBoards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Supported Boards

Here is a complete list of all of the currently supported boards. Each header links to the respective repository where those board files are hosted. You *must* use an XInput specific board package for the library to function properly.

## [Arduino AVR Core Boards](https://github.com/dmadison/ArduinoXInput_AVR/)

* [Adafruit Circuit Playground 32u4](https://www.adafruit.com/product/3000)
* [Arduino Esplora](https://store.arduino.cc/usa/arduino-esplora)
* [Arduino Industrial 101](https://store.arduino.cc/usa/arduino-industrial-101)
* [Arduino Leonardo](https://store.arduino.cc/usa/leonardo)
* [Arduino Leonardo ETH](https://store.arduino.cc/usa/arduino-leonardo-eth)
* [Arduino Micro](https://store.arduino.cc/usa/arduino-micro)
* [Arduino Robot Control / Motor](https://store.arduino.cc/usa/arduino-robot)
* [Arduino Yún](https://store.arduino.cc/usa/arduino-yun)
* [Arduino Yún Mini](https://store.arduino.cc/usa/arduino-yun-mini)
* [LilyPad Arduino USB](https://www.sparkfun.com/products/12049)
* [Linino One](https://store.arduino.cc/usa/linino-one)

## [SparkFun AVR Boards](https://github.com/dmadison/ArduinoXInput_Sparkfun)
(Note: requires the XInput AVR core)

* [MaKey MaKey](https://www.sparkfun.com/products/11511)
* [Pro Micro 3.3V](https://www.sparkfun.com/products/10999)
* [Pro Micro 5V](https://www.sparkfun.com/products/11098)
* [Fio v3](https://www.sparkfun.com/products/11520)
* [Qduino Mini](https://www.sparkfun.com/products/13614)
* [LilyPad USB Plus](https://www.sparkfun.com/products/14346)

## [Teensy 3 Boards](https://github.com/dmadison/ArduinoXInput_Teensy/)

* [Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
* [Teensy 3.5](https://www.pjrc.com/store/teensy35.html)
* [Teensy 3.1](https://www.pjrc.com/store/teensy31.html) / [3.2](https://www.pjrc.com/store/teensy32.html)
* [Teensy LC](https://www.pjrc.com/teensy/teensyLC.html)
86 changes: 86 additions & 0 deletions extras/XInputUSB_API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Using the XInputUSB API

The Arduino XInput implementation is broken up into three separate components, of which this library is just one part:

1. **The Library**, which is user-facing and contains lots of syntactic sugar to make it easy to manipulate the USB data.
2. **The Backend**, which handles the USB communication itself including endpoint memory management.
3. **The USB API**, which provides a standardized interface between these two components.

The goal of this document is to describe how the USB API works so that you can use it to build XInput support for other board types while maintaining compatibility with this library.

---

## Overview

Here is the C++ API header in all of its glory:

```cpp
#define USB_XINPUT

class XInputUSB {
public:
static bool connected(void);
static uint8_t available(void);
static int send(const void *buffer, uint8_t nbytes);
static int recv(void *buffer, uint8_t nbytes);
static void setRecvCallback(void(*callback)(void));
};
```

Note the `USB_XINPUT` preprocessor definition. This definition is what tells the library that the API is present and that it can send data over USB.

## Functions

The API consists of five core static functions of the `XInputUSB` class that pass the USB data back and forth from the bus to the library. Here is the breakdown:

### bool connected(void)

The `connected` function returns the state of the USB interface with respect to XInput. If the device is connected to a host and functional this should return `true`. If the device is disconnected this should return `false`.

### uint8_t available(void)

The `available` function returns the number of bytes currently stored in the USB data banks for the received control surface data. If there are no bytes available this function returns 0.

### int send(const void *buffer, uint8_t nbytes)

The `send` function is used to send control surface data to the host over USB. It takes two arguments:
1. A pointer to the start of an array of data to be sent
2. The number of bytes to be sent

The function then blocks until the data is sent, and returns the number of bytes that were transmitted. If an error occurs, the function returns -1.

### int recv(void *buffer, uint8_t nbytes)

The `recv` function is used to receive control surface data from the host. It takes two arguments:
1. A pointer to the start of a buffer to store the data
2. The number of bytes available in the buffer

The function should move any received data from the USB data banks into the user-provided buffer.

The function returns how many bytes were copied into the provided buffer. If no bytes are copied the function returns 0. If an error occurs the function should return -1.

### void setRecvCallback(void(*callback)(void))

The `setRecvCallback` function is used to set the function callback for received data. It takes one argument, a function pointer with no arguments and a 'void' return type. This function pointer should be invoked whenever a new control surface data packet has been received.

The API does not specify the storage for this callback pointer.

## Building a Board Implementation

These functions make up the API that allows the library to communicate over USB. However, the lower level USB implementation itself is up to the developer's discretion. To be detected by the Windows driver as an XInput device, your board needs to define the following, taken from an existing XInput product:

* VID / PID
* Device Descriptor
* Configuration Descriptor
* String Descriptors

This library is built around the official Xbox 360 wired controller's data layout. You can find these descriptors and an explanation of what they mean [here](http://www.partsnotincluded.com/reverse-engineering/understanding-the-xbox-360-wired-controllers-usb-data). If you're emulating another device the layout of the data packet may be different and need to be modified by your implementation.

Once the board is detected by the host as an XInput device, define the USB API per the information above. Then fire up the library and try it out!

## Examples

Here are my two API implementations for reference:

* [Arduino AVR Boards](https://github.com/dmadison/ArduinoXInput_AVR/blob/master/cores/arduino/xinput/USB_XInput_API.cpp)
* [Teensy 3 Boards](https://github.com/dmadison/ArduinoXInput_Teensy/blob/master/teensy/avr/cores/teensy3/usb_xinput.c)
7 changes: 5 additions & 2 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
XInput KEYWORD1

# Classes
XInputGamepad KEYWORD1
XInputController KEYWORD1

# Enums
XInputControl KEYWORD1
Expand All @@ -21,6 +21,10 @@ XInputLEDPattern KEYWORD1
# Methods and Functions (KEYWORD2)
#######################################

# Setup
begin KEYWORD2
reset KEYWORD2

# Set Control Data
press KEYWORD2
release KEYWORD2
Expand Down Expand Up @@ -61,7 +65,6 @@ setJoystickRange KEYWORD2
setRange KEYWORD2

# Other
reset KEYWORD2
printDebug KEYWORD2

#######################################
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=XInput
version=0.0.1
version=1.0.0
author=David Madison
maintainer=David Madison
sentence=Library for emulating an Xbox controller over USB.
Expand Down
Loading