Skip to content

Commit ebe4a68

Browse files
committed
Added hat switches
1 parent ff1b1cf commit ebe4a68

File tree

5 files changed

+267
-50
lines changed

5 files changed

+267
-50
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Simple example application that shows how to read four Arduino
2+
// digital pins and map them to the USB Joystick library's hat switch.
3+
//
4+
// The digital pins 4, 5, 6, 7, 8, 9, 10, and 11 are grounded when
5+
// they are pressed.
6+
//
7+
// Pin Mappings:
8+
// 4 - Hat Switch #0 UP
9+
// 5 - Hat Switch #0 RIGHT
10+
// 6 - Hat Switch #0 DOWN
11+
// 7 - Hat Switch #0 LEFT
12+
// 8 - Hat Switch #1 UP
13+
// 9 - Hat Switch #1 RIGHT
14+
// 10 - Hat Switch #1 DOWN
15+
// 11 - Hat Switch #1 LEFT
16+
//
17+
// NOTE: This sketch file is for use with Arduino Leonardo and
18+
// Arduino Micro only.
19+
//
20+
// by Matthew Heironimus
21+
// 2016-05-30
22+
//--------------------------------------------------------------------
23+
24+
#include <Joystick.h>
25+
26+
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, 0,
27+
JOYSTICK_DEFAULT_HATSWITCH_COUNT,
28+
false, false, false, false, false, false,
29+
false, false, false, false, false);
30+
31+
void setup() {
32+
33+
// Initialize Button Pins
34+
for (int index = 4; index < 12; index++)
35+
{
36+
pinMode(index, INPUT_PULLUP);
37+
}
38+
39+
// Initialize Joystick Library
40+
Joystick.begin();
41+
}
42+
43+
// Last state of the pins
44+
int lastButtonState[2][4] = {{0,0,0,0}, {0,0,0,0}};
45+
46+
void loop() {
47+
48+
bool valueChanged[2] = {false, false};
49+
int currentPin = 4;
50+
51+
// Read pin values
52+
for (int hatSwitch = 0; hatSwitch < 2; hatSwitch++)
53+
{
54+
for (int index = 0; index < 4; index++)
55+
{
56+
int currentButtonState = !digitalRead(currentPin++);
57+
if (currentButtonState != lastButtonState[hatSwitch][index])
58+
{
59+
valueChanged[hatSwitch] = true;
60+
lastButtonState[hatSwitch][index] = currentButtonState;
61+
}
62+
}
63+
}
64+
65+
for (int hatSwitch = 0; hatSwitch < 2; hatSwitch++)
66+
{
67+
if (valueChanged[hatSwitch]) {
68+
69+
if ((lastButtonState[hatSwitch][0] == 0)
70+
&& (lastButtonState[hatSwitch][1] == 0)
71+
&& (lastButtonState[hatSwitch][2] == 0)
72+
&& (lastButtonState[hatSwitch][3] == 0)) {
73+
Joystick.setHatSwitch(hatSwitch, -1);
74+
}
75+
if (lastButtonState[hatSwitch][0] == 1) {
76+
Joystick.setHatSwitch(hatSwitch, 0);
77+
}
78+
if (lastButtonState[hatSwitch][1] == 1) {
79+
Joystick.setHatSwitch(hatSwitch, 90);
80+
}
81+
if (lastButtonState[hatSwitch][2] == 1) {
82+
Joystick.setHatSwitch(hatSwitch, 180);
83+
}
84+
if (lastButtonState[hatSwitch][3] == 1) {
85+
Joystick.setHatSwitch(hatSwitch, 270);
86+
}
87+
88+
} // if the value changed
89+
90+
} // for each hat switch
91+
92+
delay(50);
93+
}
94+

Joystick/examples/JoystickTest/JoystickTest.ino

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,20 +168,14 @@ void testXYZAxisRotation(unsigned int degree)
168168

169169
void setup() {
170170

171-
/*
172-
* Uncomment this out for debugging...
173-
Serial.begin(9600);
174-
while (!Serial) {
175-
; // wait for serial port to connect. Needed for native USB
176-
}
177-
*/
178-
179171
Joystick.setXAxisRange(-127, 127);
180172
Joystick.setYAxisRange(-127, 127);
181173
Joystick.setZAxisRange(-127, 127);
182174
Joystick.setRxAxisRange(0, 360);
183175
Joystick.setRyAxisRange(0, 360);
184176
Joystick.setRzAxisRange(0, 720);
177+
Joystick.setThrottleRange(0, 255);
178+
Joystick.setRudderRange(0, 255);
185179

186180
if (testAutoSendMode)
187181
{

Joystick/src/Joystick.cpp

Lines changed: 155 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,10 @@ static const uint8_t _hidReportDescriptor[] PROGMEM = {
103103
};
104104
*/
105105

106-
Joystick_::Joystick_(uint8_t hidReportId,
106+
Joystick_::Joystick_(
107+
uint8_t hidReportId,
107108
uint8_t buttonCount,
109+
uint8_t hatSwitchCount,
108110
bool includeXAxis,
109111
bool includeYAxis,
110112
bool includeZAxis,
@@ -122,6 +124,7 @@ Joystick_::Joystick_(uint8_t hidReportId,
122124

123125
// Save Joystick Settings
124126
_buttonCount = buttonCount;
127+
_hatSwitchCount = hatSwitchCount;
125128
_includeXAxis = includeXAxis;
126129
_includeYAxis = includeYAxis;
127130
_includeZAxis = includeZAxis;
@@ -159,7 +162,7 @@ Joystick_::Joystick_(uint8_t hidReportId,
159162
+ (includeSteering == true);
160163

161164
// TODO: Figure out what the max for this could be and set it here...
162-
uint8_t *customHidReportDescriptor = new uint8_t[100];
165+
uint8_t *customHidReportDescriptor = new uint8_t[150];
163166
int hidReportDescriptorSize = 0;
164167

165168
// USAGE_PAGE (Generic Desktop)
@@ -237,13 +240,115 @@ Joystick_::Joystick_(uint8_t hidReportId,
237240
} // Padding Bits Needed
238241

239242
} // Buttons
240-
241-
if (axisCount > 0) {
243+
244+
if ((axisCount > 0) || (_hatSwitchCount > 0)) {
242245

243246
// USAGE_PAGE (Generic Desktop)
244247
customHidReportDescriptor[hidReportDescriptorSize++] = 0x05;
245248
customHidReportDescriptor[hidReportDescriptorSize++] = 0x01;
249+
250+
}
251+
252+
if (_hatSwitchCount > 0) {
253+
254+
// USAGE (Hat Switch)
255+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x09;
256+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x39;
257+
258+
// LOGICAL_MINIMUM (0)
259+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x15;
260+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x00;
261+
262+
// LOGICAL_MAXIMUM (7)
263+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x25;
264+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x07;
265+
266+
// PHYSICAL_MINIMUM (0)
267+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x35;
268+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x00;
269+
270+
// PHYSICAL_MAXIMUM (315)
271+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x46;
272+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x3B;
273+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x01;
274+
275+
// UNIT (Eng Rot:Angular Pos)
276+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x65;
277+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x14;
278+
279+
// REPORT_SIZE (4)
280+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x75;
281+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x04;
282+
283+
// REPORT_COUNT (1)
284+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x95;
285+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x01;
286+
287+
// INPUT (Data,Var,Abs)
288+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x81;
289+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x02;
290+
291+
if (_hatSwitchCount > 1) {
292+
293+
// USAGE (Hat Switch)
294+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x09;
295+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x39;
296+
297+
// LOGICAL_MINIMUM (0)
298+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x15;
299+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x00;
300+
301+
// LOGICAL_MAXIMUM (7)
302+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x25;
303+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x07;
304+
305+
// PHYSICAL_MINIMUM (0)
306+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x35;
307+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x00;
308+
309+
// PHYSICAL_MAXIMUM (315)
310+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x46;
311+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x3B;
312+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x01;
313+
314+
// UNIT (Eng Rot:Angular Pos)
315+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x65;
316+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x14;
317+
318+
// REPORT_SIZE (4)
319+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x75;
320+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x04;
321+
322+
// REPORT_COUNT (1)
323+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x95;
324+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x01;
325+
326+
// INPUT (Data,Var,Abs)
327+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x81;
328+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x02;
329+
330+
} else {
331+
332+
// Use Padding Bits
333+
334+
// REPORT_SIZE (1)
335+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x75;
336+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x01;
246337

338+
// REPORT_COUNT (4)
339+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x95;
340+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x04;
341+
342+
// INPUT (Const,Var,Abs)
343+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x81;
344+
customHidReportDescriptor[hidReportDescriptorSize++] = 0x03;
345+
346+
} // One or Two Hat Switches?
347+
348+
} // Hat Switches
349+
350+
if (axisCount > 0) {
351+
247352
// USAGE (Pointer)
248353
customHidReportDescriptor[hidReportDescriptorSize++] = 0x09;
249354
customHidReportDescriptor[hidReportDescriptorSize++] = 0x01;
@@ -393,20 +498,20 @@ Joystick_::Joystick_(uint8_t hidReportId,
393498
DynamicHID().AppendDescriptor(_node);
394499

395500
// Setup Joystick State
396-
_buttonValuesArraySize = _buttonCount / 8;
397-
if ((_buttonCount % 8) > 0) {
398-
_buttonValuesArraySize++;
399-
}
400-
_buttonValues = new uint8_t[_buttonValuesArraySize];
401-
501+
if (buttonCount > 0) {
502+
_buttonValuesArraySize = _buttonCount / 8;
503+
if ((_buttonCount % 8) > 0) {
504+
_buttonValuesArraySize++;
505+
}
506+
_buttonValues = new uint8_t[_buttonValuesArraySize];
507+
}
508+
402509
// Calculate HID Report Size
403510
_hidReportSize = _buttonValuesArraySize;
511+
_hidReportSize += (_hatSwitchCount > 0);
404512
_hidReportSize += (axisCount * 2);
405513
_hidReportSize += (simulationCount * 2);
406-
407-
Serial.print("_hidReportSize: ");
408-
Serial.println(_hidReportSize);
409-
514+
410515
// Initalize Joystick State
411516
_xAxis = 0;
412517
_yAxis = 0;
@@ -419,14 +524,23 @@ Joystick_::Joystick_(uint8_t hidReportId,
419524
_accelerator = 0;
420525
_brake = 0;
421526
_steering = 0;
422-
_hatSwitch[0] = -1;
423-
_hatSwitch[1] = -1;
527+
for (int index = 0; index < JOYSTICK_HATSWITCH_COUNT_MAXIMUM; index++)
528+
{
529+
_hatSwitchValues[index] = -1;
530+
}
424531
for (int index = 0; index < _buttonValuesArraySize; index++)
425532
{
426533
_buttonValues[index] = 0;
427534
}
428535
}
429536

537+
Joystick_::~Joystick_() {
538+
if (_buttonValues != NULL) {
539+
delete[] _buttonValues;
540+
_buttonValues = NULL;
541+
}
542+
}
543+
430544
void Joystick_::begin(bool initAutoSendState)
431545
{
432546
_autoSendState = initAutoSendState;
@@ -617,7 +731,9 @@ void Joystick_::setSteering(int16_t value)
617731

618732
void Joystick_::setHatSwitch(int8_t hatSwitchIndex, int16_t value)
619733
{
620-
_hatSwitch[hatSwitchIndex % 2] = value;
734+
if (hatSwitchIndex >= _hatSwitchCount) return;
735+
736+
_hatSwitchValues[hatSwitchIndex] = value;
621737
if (_autoSendState) sendState();
622738
}
623739

@@ -632,6 +748,28 @@ void Joystick_::sendState()
632748
data[index] = _buttonValues[index];
633749
}
634750

751+
// Set Hat Switch Values
752+
if (_hatSwitchCount > 0) {
753+
754+
// Calculate hat-switch values
755+
uint8_t convertedHatSwitch[JOYSTICK_HATSWITCH_COUNT_MAXIMUM];
756+
for (int hatSwitchIndex = 0; hatSwitchIndex < JOYSTICK_HATSWITCH_COUNT_MAXIMUM; hatSwitchIndex++)
757+
{
758+
if (_hatSwitchValues[hatSwitchIndex] < 0)
759+
{
760+
convertedHatSwitch[hatSwitchIndex] = 8;
761+
}
762+
else
763+
{
764+
convertedHatSwitch[hatSwitchIndex] = (_hatSwitchValues[hatSwitchIndex] % 360) / 45;
765+
}
766+
}
767+
768+
// Pack hat-switch states into a single byte
769+
data[index++] = (convertedHatSwitch[1] << 4) | (B00001111 & convertedHatSwitch[0]);
770+
771+
} // Hat Switches
772+
635773
// Set Axis Values
636774
int16_t convertedValue;
637775
uint8_t highByte;
@@ -736,26 +874,6 @@ void Joystick_::sendState()
736874
data[index++] = highByte;
737875
}
738876

739-
740-
// Calculate hat-switch values
741-
/*
742-
uint8_t convertedHatSwitch[2];
743-
for (int hatSwitchIndex = 0; hatSwitchIndex < 2; hatSwitchIndex++)
744-
{
745-
if (_hatSwitch[hatSwitchIndex] < 0)
746-
{
747-
convertedHatSwitch[hatSwitchIndex] = 8;
748-
}
749-
else
750-
{
751-
convertedHatSwitch[hatSwitchIndex] = (_hatSwitch[hatSwitchIndex] % 360) / 45;
752-
}
753-
}
754-
*/
755-
756-
// Pack hat-switch states into a single byte
757-
//data[6] = (convertedHatSwitch[1] << 4) | (B00001111 & convertedHatSwitch[0]);
758-
759877
DynamicHID().SendReport(_hidReportId, data, _hidReportSize);
760878
}
761879

0 commit comments

Comments
 (0)