Skip to content

Instantly share code, notes, and snippets.

@halferty
Last active November 20, 2017 11:40
Show Gist options
  • Save halferty/89d7720ddc892b58a665aadee47a47c0 to your computer and use it in GitHub Desktop.
Save halferty/89d7720ddc892b58a665aadee47a47c0 to your computer and use it in GitHub Desktop.
Arduino Leonardo Gamepad
#include "HID.h"
#define BUTTON1_PIN 2
#define BUTTON2_PIN 3
#define BUTTON3_PIN 4
#define BUTTON4_PIN 5
#define BUTTON5_PIN 6
#define BUTTON6_PIN 7
#define BUTTON7_PIN 8
#define BUTTON8_PIN 9
#define BUTTON9_PIN 10
#define BUTTON10_PIN 16
#define UP_PIN 14
#define RIGHT_PIN 15
#define DOWN_PIN A0
#define LEFT_PIN A1
// Let's make it mimic the xbox controller button mappings...
#define B_BUTTON_MAPPING 1
#define X_BUTTON_MAPPING 2
#define Y_BUTTON_MAPPING 3
#define A_BUTTON_MAPPING 0
#define LT_BUTTON_MAPPING 8
#define RT_BUTTON_MAPPING 9
#define LB_BUTTON_MAPPING 4
#define RB_BUTTON_MAPPING 5
#define BACK_BUTTON_MAPPING 6
#define START_BUTTON_MAPPING 7
static const uint8_t _hidReportDescriptor[] PROGMEM = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x03, // REPORT_ID
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x10, // USAGE_MAXIMUM (Button 16)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x10, // REPORT_COUNT (16)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x33, // USAGE (Rx)
0x09, 0x34, // USAGE (Ry)
0x16, 0x00, 0x80, // LOGICAL_MINIMUM (-32768)
0x26, 0xFF, 0x7F, // LOGICAL_MAXIMUM (32767)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x32, // USAGE (Z)
0x09, 0x35, // USAGE (Rz)
0x15, 0x80, // LOGICAL_MINIMUM (-128)
0x25, 0x7F, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x39, // USAGE (Hat switch)
0x09, 0x39, // USAGE (Hat switch)
0x15, 0x01, // LOGICAL_MINIMUM (1)
0x25, 0x08, // LOGICAL_MAXIMUM (8)
0x95, 0x02, // REPORT_COUNT (2)
0x75, 0x04, // REPORT_SIZE (4)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0 // END_COLLECTION
};
typedef struct {
uint16_t buttons;
int16_t xAxis;
int16_t yAxis;
int16_t rxAxis;
int16_t ryAxis;
int8_t zAxis;
int8_t rzAxis;
uint8_t dpad;
} PadReport;
class Gamepad {
private:
PadReport padReport;
public:
Gamepad(void) {
static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
HID().AppendDescriptor(&node);
padReport.buttons = 0;
}
void begin(void) {}
void end(void) {}
void sendUpdate(void) { HID().SendReport(0x03, &padReport, sizeof(PadReport)); }
void setButtonState(uint8_t button, bool state) {
(state == true) ? bitSet(padReport.buttons, button) : bitClear(padReport.buttons, button);
}
void setDPad(bool up, bool right, bool down, bool left) {
padReport.dpad = 0;
if (up && right) {
padReport.dpad = 0x20;
} else if (up && left) {
padReport.dpad = 0x80;
} else if (down && right) {
padReport.dpad = 0x40;
} else if (down && left) {
padReport.dpad = 0x60;
} else if (up) {
padReport.dpad = 0x10;
} else if (right) {
padReport.dpad = 0x30;
} else if (down) {
padReport.dpad = 0x50;
} else if (left) {
padReport.dpad = 0x70;
}
}
};
Gamepad gamepad;
void setup() {
pinMode(BUTTON1_PIN, INPUT_PULLUP);
pinMode(BUTTON2_PIN, INPUT_PULLUP);
pinMode(BUTTON3_PIN, INPUT_PULLUP);
pinMode(BUTTON4_PIN, INPUT_PULLUP);
pinMode(BUTTON5_PIN, INPUT_PULLUP);
pinMode(BUTTON6_PIN, INPUT_PULLUP);
pinMode(BUTTON7_PIN, INPUT_PULLUP);
pinMode(BUTTON8_PIN, INPUT_PULLUP);
pinMode(BUTTON9_PIN, INPUT_PULLUP);
pinMode(BUTTON10_PIN, INPUT_PULLUP);
pinMode(UP_PIN, INPUT_PULLUP);
pinMode(RIGHT_PIN, INPUT_PULLUP);
pinMode(DOWN_PIN, INPUT_PULLUP);
pinMode(LEFT_PIN, INPUT_PULLUP);
}
void loop() {
gamepad.setButtonState(B_BUTTON_MAPPING, !digitalRead(BUTTON1_PIN));
gamepad.setButtonState(X_BUTTON_MAPPING, !digitalRead(BUTTON2_PIN));
gamepad.setButtonState(Y_BUTTON_MAPPING, !digitalRead(BUTTON3_PIN));
gamepad.setButtonState(A_BUTTON_MAPPING, !digitalRead(BUTTON4_PIN));
gamepad.setButtonState(LT_BUTTON_MAPPING, !digitalRead(BUTTON5_PIN));
gamepad.setButtonState(RT_BUTTON_MAPPING, !digitalRead(BUTTON6_PIN));
gamepad.setButtonState(LB_BUTTON_MAPPING, !digitalRead(BUTTON7_PIN));
gamepad.setButtonState(RB_BUTTON_MAPPING, !digitalRead(BUTTON8_PIN));
gamepad.setButtonState(BACK_BUTTON_MAPPING, !digitalRead(BUTTON9_PIN));
gamepad.setButtonState(START_BUTTON_MAPPING, !digitalRead(BUTTON10_PIN));
gamepad.setDPad(!digitalRead(UP_PIN),!digitalRead(RIGHT_PIN),!digitalRead(DOWN_PIN),!digitalRead(LEFT_PIN));
gamepad.sendUpdate();
delay(10);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment