Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
controllercustom committed Sep 11, 2023
0 parents commit 2c8668d
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 0 deletions.
35 changes: 35 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

test.sh
work/
139 changes: 139 additions & 0 deletions JoystickWin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
JoystickWin.cpp
*/

#include "JoystickWin.h"

#if defined(_USING_HID)

static const uint8_t _hidReportDescriptor[] PROGMEM = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x85, 0x04, // Report ID (4)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x20, // Usage Maximum (0x20)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x20, // Report Count (32)
0x55, 0x00, // Unit Exponent (0)
0x65, 0x00, // Unit (None)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x39, // Usage (Hat switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x39, // Usage (Hat switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x01, // Usage (Pointer)
0x15, 0x00, // Logical Minimum (0)
0x27, 0xFF, 0xFF, 0x00, 0x00, // Logical Maximum (65534)
0x75, 0x10, // Report Size (16)
0x95, 0x06, // Report Count (6)
0xA1, 0x00, // Collection (Physical)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x09, 0x35, // Usage (Rz)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x05, 0x02, // Usage Page (Sim Ctrls)
0x15, 0x00, // Logical Minimum (0)
0x27, 0xFF, 0xFF, 0x00, 0x00, // Logical Maximum (65534)
0x75, 0x10, // Report Size (16)
0x95, 0x05, // Report Count (5)
0xA1, 0x00, // Collection (Physical)
0x09, 0xBA, // Usage (Rudder)
0x09, 0xBB, // Usage (Throttle)
0x09, 0xC4, // Usage (Accelerator)
0x09, 0xC5, // Usage (Brake)
0x09, 0xC8, // Usage (Steering)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xC0, // End Collection
};

//================================================================================
//================================================================================
// JoystickWin

JoystickWin_::JoystickWin_(void) {
static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
HID().AppendDescriptor(&node);
}

void JoystickWin_::begin(void) {
_hid_report.buttons = 0;
_hid_report.hat1 = 8;
_hid_report.hat2 = 8;
_hid_report.x = AXIS_MID;
_hid_report.y = AXIS_MID;
_hid_report.z = AXIS_MID;
_hid_report.rx = AXIS_MID;
_hid_report.ry = AXIS_MID;
_hid_report.rz = AXIS_MID;
_hid_report.rudder = AXIS_MID;
_hid_report.throttle = AXIS_MID;
_hid_report.accelerator = AXIS_MID;
_hid_report.brake = AXIS_MID;
_hid_report.steering = AXIS_MID;
sendReport();
}

void JoystickWin_::end(void) {
begin();
}

void JoystickWin_::sendReport() {
HID().SendReport(4, (void *)&_hid_report, sizeof(_hid_report));
}

void JoystickWin_::press(int b) {
constrain(b, 0, BUTTONS_MAX - 1);
_hid_report.buttons |= (uint32_t)(1UL << b);
}

void JoystickWin_::release(int b) {
constrain(b, 0, BUTTONS_MAX - 1);
_hid_report.buttons &= ~(uint32_t)(1UL << b);
}

void JoystickWin_::releaseAll() {
_hid_report.buttons = 0;
}

bool JoystickWin_::isPressed(int b) {
constrain(b, 0, BUTTONS_MAX - 1);
return ((_hid_report.buttons & (uint32_t)(1UL << b)) != 0) ? true : false;
}

void JoystickWin_::hat1(int d) {
constrain(d, 0, 15);
_hid_report.hat1 = d;
}

void JoystickWin_::hat2(int d) {
constrain(d, 0, 15);
_hid_report.hat2 = d;
}

JoystickWin_ JoystickWin;

#endif
73 changes: 73 additions & 0 deletions JoystickWin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
JoystickWin.h
*/

#ifndef JOYSTICKWIN_H_
#define JOYSTICKWIN_H_

#include "HID.h"

#if !defined(_USING_HID)

#warning "Using legacy HID core (non pluggable)"

#else

#define AXIS_MIN (0)
#define AXIS_MID (AXIS_MAX / 2)
#define AXIS_MAX (0xFFFFUL)
#define BUTTONS_MAX (32)

//================================================================================
//================================================================================
// JoystickWin

// This overlays the data format specified by the HID report descriptor in
// JoystickWin.cpp
typedef struct __attribute__((__packed__)) {
uint32_t buttons;
uint8_t hat1:4;
uint8_t hat2:4;
uint16_t x;
uint16_t y;
uint16_t z;
uint16_t rx;
uint16_t ry;
uint16_t rz;
uint16_t rudder;
uint16_t throttle;
uint16_t accelerator;
uint16_t brake;
uint16_t steering;
} JoystickWin_Report_t;

class JoystickWin_ {
private:
JoystickWin_Report_t _hid_report;
public:
JoystickWin_(void);
void begin(void);
void end(void);
void press(int b);
void release(int b);
void releaseAll();
bool isPressed(int b);
void hat1(int d);
void hat2(int d);
void x(uint16_t a) { _hid_report.x = a; }
void y(uint16_t a) { _hid_report.y = a; }
void z(uint16_t a) { _hid_report.z = a; }
void rx(uint16_t a) { _hid_report.rx = a; }
void ry(uint16_t a) { _hid_report.ry = a; }
void rz(uint16_t a) { _hid_report.rz = a; }
void rudder(uint16_t a) { _hid_report.rudder = a; }
void throttle(uint16_t a) { _hid_report.throttle = a; }
void accelerator(uint16_t a) { _hid_report.accelerator = a; }
void brake(uint16_t a) { _hid_report.brake = a; }
void steering(uint16_t a) { _hid_report.steering = a; }
void sendReport();
};
extern JoystickWin_ JoystickWin;

#endif
#endif // JOYSTICKWIN_H_
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Arduino USB Joystick for Windows

USB HID Joystick with 11 axes, 2 8-way direction pads, and 32 buttons. These
are apparently the limits of the Windows generic joystick device driver.

The following joystick class works when plugged into a computer running Windows
11 and a computer running Ubuntu Linux. The class depends only on HID.h and
does not contain board specific code so it may work on other boards.

Oddly on some boards (Uno R4 WiFi and Due), the Serial port must be opened to
use the joystick. This code is in the test sketch, not the Joystick class.

## Tested boards

The joystick properties window does not show all the axes. The Point
of View Hat has two indicator arrows because there are two direction hats.

![Arduino Micro running JoystickWin on Win11](./images/micro.jpg "Arduino Micro running JoystickWin on Win11")

<em>Arduino Micro (same processor as in Pro Micro and Leonardo) running JoystickWin on Win11</em>

![Arduino Due running JoystickWin on Win11](./images/due.jpg "Arduino Due running JoystickWin on Win11")

<em>Arduino Due running JoystickWin on Win11</em>

![Arduino Nano 33 IoT running JoystickWin on Win11](./images/nano33iot.jpg "Arduino Nano 33 IoT running JoystickWin on Win11")

<em>Arduino Nano 33 IoT running JoystickWin on Win11</em>

![Arduino Uno R4 WiFi running JoystickWin on Win11](./images/unor4wifi.jpg "Arduino Uno R4 WiFi running JoystickWin on Win11")

<em>Arduino Uno R4 WiFi running JoystickWin on Win11</em>

## Limitations

This driver does not work on Arduino boards using mbed because mbed USB
works differently. For example, Giga R1.

This driver does not work on boards without an integrated USB controller such
as Uno and Mega. See UnoJoy.

This driver is a generic jumbo joystick that does not emulate any commercial
joystick/gamepad such as PS3 or Xbox 360 so game software that require a
specific brand/model of joystick/gamepad will not work.
47 changes: 47 additions & 0 deletions examples/JoystickWin/JoystickWin.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "JoystickWin.h"

void setup() {
#if defined(ARDUINO_ARCH_RENESAS_UNO) || defined(ARDUINO_SAM_DUE)
Serial.begin(115200);
while (!Serial && (millis() < 3000)) delay(10);
Serial.print("sizeof JoystickWin_Report_t: ");
Serial.println(sizeof(JoystickWin_Report_t));
#endif
JoystickWin.begin();
}

void loop() {
static uint8_t count = 0;
if (count >= BUTTONS_MAX) {
JoystickWin.releaseAll();
count = 0;
}
JoystickWin.press(count);
count++;

// Go through all hat switch directions
static uint8_t dir = 0;
JoystickWin.hat1(dir++);
JoystickWin.hat2(dir++);
if (dir > 7)
dir = 0;

// Move axes to random positions
JoystickWin.x(random(AXIS_MAX + 1));
JoystickWin.y(random(AXIS_MAX + 1));
JoystickWin.z(random(AXIS_MAX + 1));
JoystickWin.rx(random(AXIS_MAX + 1));
JoystickWin.ry(random(AXIS_MAX + 1));
JoystickWin.rz(random(AXIS_MAX + 1));
JoystickWin.rudder(random(AXIS_MAX + 1));
JoystickWin.throttle(random(AXIS_MAX + 1));
JoystickWin.accelerator(random(AXIS_MAX + 1));
JoystickWin.brake(random(AXIS_MAX + 1));
JoystickWin.steering(random(AXIS_MAX + 1));

// The above updates values in RAM. The following
// sends the values to the USB host.
JoystickWin.sendReport();

delay(100);
}
Binary file added images/due.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/joystickwin.mp4
Binary file not shown.
Binary file added images/jstest-gtk.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/micro.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/nano33iot.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/unor4wifi.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2c8668d

Please sign in to comment.