HID Joystick - For use with X-Plane or other programs that can read HID JoySticks
Dependencies: USBDevice mbed-rtos mbed
Fork of JoyStick by
This is a simple Joystick HID that I use for xplane and a home build yoke + paddels, see this forum with the look and feel of it : http://forums.x-plane.org/index.php?showtopic=70041
The analog input are filtered with a LowPass IIR filter and the digital input's will be derived from the analog input and de-bounced.
The analog values are read at a 1Khz interval and to ensure we don't push the USB stack to much at a maximum rate of 20 updates/sec HID data is send over USB only if any values where changed. The JoyStick will send 16Bit analog values as opposite of 8 bit values that are normally used to increase accuracy of the whole system. This is well noticeable within x-plane!
The JoyStick uses the JoyStick copied from Wim Huiskamp and modified to suite my needs and the MBED RTOS libraries for reading analog inputs, sending debug data over USB and sending HID data, 3 threads in total.
Revision 4:2cc58c173de8, committed 2016-03-10
- Comitter:
- rvt
- Date:
- Thu Mar 10 14:05:02 2016 +0000
- Parent:
- 3:0742b0b42ac9
- Child:
- 5:a0bb17c379ce
- Commit message:
- expanded to read more digital ports for my new panel
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Button.cpp Thu Mar 10 14:05:02 2016 +0000
@@ -0,0 +1,26 @@
+#include "Button.h"
+
+
+Button::Button(PinName pin, bool reversed, bool pullUp) {
+ _digitalIn = new DigitalIn(pin);
+ _digitalIn->mode(pullUp?PullUp:PullDown);
+ _lastValue = _digitalIn;
+ _reversed = reversed;
+}
+
+Button::~Button() {
+}
+
+void Button::measure () {
+ _value = _digitalIn->read();
+}
+
+bool Button::getData() {
+ return _value ^_reversed;
+}
+
+bool Button::getIsChanged() {
+ bool lv = _lastValue;
+ _lastValue = _value;
+ return _value ^ lv;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Button.h Thu Mar 10 14:05:02 2016 +0000
@@ -0,0 +1,27 @@
+#ifndef BUTTON_H
+#define BUTTON_H
+
+#include "mbed.h"
+
+class Button {
+ private:
+ DigitalIn *_digitalIn;
+ bool _isChanged;
+ bool _lastValue;
+ bool _value;
+ bool _reversed;
+ public:
+ /**
+ filter : Failter chain
+ pin : Analog input to read
+ */
+ Button(PinName pin, bool reversed, bool pullUp);
+ ~Button();
+
+ void measure();
+ bool getData();
+ bool getIsChanged();
+
+};
+
+#endif
\ No newline at end of file
--- a/USBJoystick.cpp Tue Feb 10 13:48:20 2015 +0000
+++ b/USBJoystick.cpp Thu Mar 10 14:05:02 2016 +0000
@@ -20,27 +20,14 @@
#include "stdint.h"
#include "USBJoystick.h"
-bool USBJoystick::update(int16_t t, int16_t r, int16_t x, int16_t y, uint8_t button) {
- HID_REPORT report;
+bool USBJoystick::update(int16_t t, int16_t r, int16_t x, int16_t y, uint32_t button) {
_t = t;
_r = r;
_x = x;
_y = y;
_button = button;
- // Fill the report according to the Joystick Descriptor
- report.data[0] = _t & 0xff;
- report.data[1] = (_t >> 8) & 0xff;
- report.data[2] = _r & 0xff;
- report.data[3] = (_r >> 8) & 0xff;
- report.data[4] = _x & 0xff;
- report.data[5] = (_x >> 8) & 0xff;
- report.data[6] = _y & 0xff;
- report.data[7] = (_y >> 8) & 0xff;
- report.data[8] = (_button & 0xff);
- report.length = 9;
-
- return send(&report);
+ return USBJoystick::update();
}
bool USBJoystick::update() {
@@ -55,8 +42,11 @@
report.data[5] = (_x >> 8) & 0xff;
report.data[6] = _y & 0xff;
report.data[7] = (_y >> 8) & 0xff;
- report.data[8] = (_button & 0xff);
- report.length = 9;
+ report.data[8] = (_button >> 24) & 0xff;
+ report.data[9] = (_button >> 16) & 0xff;
+ report.data[10] = (_button >> 8) & 0xff;
+ report.data[11] = _button & 0xff;
+ report.length = 12;
return send(&report);
}
@@ -77,7 +67,7 @@
return update();
}
-bool USBJoystick::button(uint8_t button) {
+bool USBJoystick::button(uint32_t button) {
_button = button;
return update();
}
@@ -89,7 +79,7 @@
_r = 0;
_x = 0;
_y = 0;
- _button = 0x00;
+ _button = 0x00000000;
}
@@ -154,11 +144,11 @@
// Buttons
USAGE_PAGE(1), 0x09, // Buttons
USAGE_MINIMUM(1), 0x01, // 1
- USAGE_MAXIMUM(1), 0x08, // 4
+ USAGE_MAXIMUM(1), 0x20, // 32
LOGICAL_MINIMUM(1), 0x00, // 0
LOGICAL_MAXIMUM(1), 0x01, // 1
REPORT_SIZE(1), 0x01,
- REPORT_COUNT(1), 0x08,
+ REPORT_COUNT(1), 0x20, // 32
UNIT_EXPONENT(1), 0x00, // Unit_Exponent (0)
UNIT(1), 0x00, // Unit (None)
INPUT(1), 0x02, // Data, Variable, Absolute
--- a/USBJoystick.h Tue Feb 10 13:48:20 2015 +0000
+++ b/USBJoystick.h Thu Mar 10 14:05:02 2016 +0000
@@ -107,7 +107,7 @@
* @param buttons buttons state
* @returns true if there is no error, false otherwise
*/
- bool update(int16_t t, int16_t r, int16_t x, int16_t y, uint8_t buttons);
+ bool update(int16_t t, int16_t r, int16_t x, int16_t y, uint32_t buttons);
/**
* Write a state of the mouse
@@ -147,7 +147,7 @@
* @param button button state
* @returns true if there is no error, false otherwise
*/
- bool button(uint8_t button);
+ bool button(uint32_t button);
/*
* To define the report descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
@@ -161,7 +161,7 @@
int16_t _r;
int16_t _x;
int16_t _y;
- uint8_t _button;
+ uint32_t _button;
void _init();
};
--- a/main.cpp Tue Feb 10 13:48:20 2015 +0000
+++ b/main.cpp Thu Mar 10 14:05:02 2016 +0000
@@ -3,7 +3,7 @@
#include "USBJoystick.h"
#include "LowPassFilter.h"
#include "AnalogInFiltered.h"
-#include "SimpleButtonDecoder.h"
+#include "Button.h"
#include "rtos.h"
// When set, it will send debug data over USB serial
@@ -23,16 +23,28 @@
// Structure that hold's the dataset of the input's
Mutex analogValueMutex;
struct AnalogData {
- bool button1;
- bool button2;
- bool button3;
- bool button4;
- bool button5;
+ bool but5;
+ bool but6;
+ bool but7;
+ bool but8;
+ bool but9;
+ bool but10;
+ bool but11;
+ bool but12;
+ bool but13;
+ bool but14;
+ bool but15;
+ bool but16;
+ bool but17;
+ bool but21;
+ bool but22;
+ bool but23;
+ bool but24;
+ bool but25;
long value1;
long value2;
long value3;
long value4;
- long value5;
} analogData;
@@ -96,12 +108,11 @@
pc.printf("Analog in p19: %d diff: %d \n\r",localCopy.value2,localCopy.value2-previous.value2);
pc.printf("Analog in p18: %d diff: %d \n\r",localCopy.value3,localCopy.value3-previous.value3);
pc.printf("Analog in p17: %d diff: %d \n\r",localCopy.value4,localCopy.value4-previous.value4);
- pc.printf("Analog in p16: %d diff: %d \n\r",localCopy.value5,localCopy.value5-previous.value5);
- pc.printf("Button 1: %d \n\r",localCopy.button1);
- pc.printf("Button 2: %d \n\r",localCopy.button2);
- pc.printf("Button 3: %d \n\r",localCopy.button3);
- pc.printf("Button 4: %d \n\r",localCopy.button4);
- pc.printf("Button 5: %d \n\r",localCopy.button5);
+ pc.printf("Button 5: %d \n\r",localCopy.but5);
+ pc.printf("Button 6: %d \n\r",localCopy.but6);
+ pc.printf("Button 7: %d \n\r",localCopy.but7);
+ pc.printf("Button 8: %d \n\r",localCopy.but8);
+ pc.printf("Button 9: %d \n\r",localCopy.but9);
// Make local copy so we can show diff version
memcpy (&previous, &localCopy, sizeof(AnalogData));
@@ -122,7 +133,7 @@
// Locla copy of analog data
AnalogData localCopy;
- uint8_t buttons=0;
+ uint32_t buttons=0x00;
while (true) {
@@ -136,29 +147,32 @@
memcpy (&localCopy, &analogData, sizeof(AnalogData));
analogValueMutex.unlock();
- buttons=0;
- if (localCopy.button1==true) {
- buttons=buttons | 0x01;
- }
- if (localCopy.button2) {
- buttons=buttons | 0x02;
- }
- if (localCopy.button3) {
- buttons=buttons | 0x04;
- }
- if (localCopy.button4) {
- buttons=buttons | 0x08;
- }
- if (localCopy.button5) {
- buttons=buttons | 0x10;
- }
+ buttons=0x00;
+ buttons = buttons | localCopy.but5 ;
+ buttons = buttons | localCopy.but6 << 1;
+ buttons = buttons | localCopy.but7 << 2;
+ buttons = buttons | localCopy.but8 << 3;
+ buttons = buttons | localCopy.but9 << 4;
+ buttons = buttons | localCopy.but10 << 5;
+ buttons = buttons | localCopy.but11 << 6;
+ buttons = buttons | localCopy.but12 << 7;
+ buttons = buttons | localCopy.but13 << 8;
+ buttons = buttons | localCopy.but14 << 9;
+ buttons = buttons | localCopy.but15 << 10;
+ buttons = buttons | localCopy.but16 << 11;
+ buttons = buttons | localCopy.but17 << 12;
+ buttons = buttons | localCopy.but21 << 13;
+ buttons = buttons | localCopy.but22 << 14;
+ buttons = buttons | localCopy.but23 << 15;
+ buttons = buttons | localCopy.but24 << 16;
+ buttons = buttons | localCopy.but25 << 17;
// Update joystick's info
joystick.update(
+ localCopy.value1,
localCopy.value2,
localCopy.value3,
localCopy.value4,
- localCopy.value5,
buttons);
// Wait 50 ms to send a other USB update
@@ -170,76 +184,120 @@
int main()
{
- analogData.value1=0;
- analogData.value2=0;
- analogData.value3=0;
- analogData.value4=0;
- analogData.value5=0;
+ analogData.value1=0.;
+ analogData.value2=0.;
+ analogData.value3=0.;
+ analogData.value4=0.;
+
+ Button but5(p5, true, true);
+ Button but6(p6, true, true);
+ Button but7(p7, true, true);
+ Button but8(p8, true, true);
+ Button but9(p9, true, true);
+ Button but10(p10, true, true);
+ Button but11(p11, true, true);
+ Button but12(p12, true, true);
+ Button but13(p13, true, true);
+ Button but14(p14, true, true);
+ Button but15(p15, true, true);
+ Button but16(p16, true, true);
+ Button but17(p17, true, true);
+ Button but21(p21, true, true);
+ Button but22(p22, true, true);
+ Button but23(p23, true, true);
+ Button but24(p24, true, true);
+ Button but25(p25, true, true);
if (TTY_DEBUG) {
Thread _debugThread(debug_thread);
}
+
+
Thread _hid_thread(hid_thread);
// Initialise moving average filters
- LowPassFilter lowPassFilter1(new AnalogFilterInterface(),0.5f); // The close the alpha value is to 1, the lower the cut-off frequency
+ LowPassFilter lowPassFilter1(new AnalogFilterInterface(),0.95f); // The close the alpha value is to 1, the lower the cut-off frequency
LowPassFilter lowPassFilter2(new AnalogFilterInterface(),0.95f);
- LowPassFilter lowPassFilter3(new AnalogFilterInterface(),0.95f);
- LowPassFilter lowPassFilter4(new AnalogFilterInterface(),0.95f);
- LowPassFilter lowPassFilter5(new AnalogFilterInterface(),0.95f);
// Initialise analog input and tell it what fulters to use
- AnalogInFiltered ai1(&lowPassFilter1, p20, DATA_CHANGE_TRIGGER*4);
- AnalogInFiltered ai2(&lowPassFilter2, p19, DATA_CHANGE_TRIGGER);
- AnalogInFiltered ai3(&lowPassFilter3, p18, DATA_CHANGE_TRIGGER);
- AnalogInFiltered ai4(&lowPassFilter4, p17, DATA_CHANGE_TRIGGER);
- AnalogInFiltered ai5(&lowPassFilter5, p16, DATA_CHANGE_TRIGGER);
+ AnalogInFiltered ai2(&lowPassFilter1, p19, DATA_CHANGE_TRIGGER);
+ AnalogInFiltered ai1(&lowPassFilter2, p20, DATA_CHANGE_TRIGGER);
- SimpleButtonDecoder but1(&ai1, 49300, DEBOUNCERUNS);
- SimpleButtonDecoder but2(&ai1, 46800, DEBOUNCERUNS);
- SimpleButtonDecoder but3(&ai1, 43650, DEBOUNCERUNS);
- SimpleButtonDecoder but4(&ai1, 32500, DEBOUNCERUNS);
- SimpleButtonDecoder but5(&ai1, 39100, DEBOUNCERUNS);
-
while (true) {
// Measure analog in's
ai1.measure();
ai2.measure();
- ai3.measure();
- ai4.measure();
- ai5.measure();
+
+ but5.measure();
+ but6.measure();
+ but7.measure();
+ but8.measure();
+ but9.measure();
+ but10.measure();
+ but11.measure();
+ but12.measure();
+ but13.measure();
+ but14.measure();
+ but15.measure();
+ but16.measure();
+ but17.measure();
- but1.process();
- but2.process();
- but3.process();
- but4.process();
- but5.process();
+ but21.measure();
+ but22.measure();
+ but23.measure();
+ but24.measure();
+ but25.measure();
// test of any of the values have been changed, so we only update when data was actually changed
+ bool isChanged =
+ ai1.getIsChanged() ||
+ ai2.getIsChanged() ||
+ but5.getIsChanged() ||
+ but6.getIsChanged() ||
+ but7.getIsChanged() ||
+ but8.getIsChanged() ||
+ but9.getIsChanged() ||
+ but10.getIsChanged() ||
+ but11.getIsChanged() ||
+ but12.getIsChanged() ||
+ but13.getIsChanged() ||
+ but14.getIsChanged() ||
+ but15.getIsChanged() ||
+ but16.getIsChanged() ||
+ but17.getIsChanged() ||
+ but21.getIsChanged() ||
+ but22.getIsChanged() ||
+ but23.getIsChanged() ||
+ but24.getIsChanged() ||
+ but25.getIsChanged();
if (
- false
- || ai2.getIsChanged()
- || ai3.getIsChanged()
- || ai4.getIsChanged()
-// || ai5.getIsChanged()
- || but1.getIsChanged()
- || but2.getIsChanged()
- || but3.getIsChanged()
- || but4.getIsChanged()
- || but5.getIsChanged()
+ isChanged
) {
// Copy analog data to global data
analogValueMutex.lock();
- analogData.button1 = but1.getIsPressed();
- analogData.button2 = but2.getIsPressed();
- analogData.button3 = but3.getIsPressed();
- analogData.button4 = but4.getIsPressed();
- analogData.button5 = but5.getIsPressed();
+ analogData.but5 = but5.getData();
+ analogData.but6 = but6.getData();
+ analogData.but7 = but7.getData();
+ analogData.but8 = but8.getData();
+ analogData.but9 = but9.getData();
+ analogData.but10 = but10.getData();
+ analogData.but11 = but11.getData();
+ analogData.but12 = but12.getData();
+ analogData.but13 = but13.getData();
+ analogData.but14 = but14.getData();
+ analogData.but15 = but15.getData();
+ analogData.but16 = but16.getData();
+ analogData.but17 = but17.getData();
+ analogData.but21 = but21.getData();
+ analogData.but22 = but22.getData();
+ analogData.but23 = but23.getData();
+ analogData.but24 = but24.getData();
+ analogData.but25 = but25.getData();
+
analogData.value1 = ai1.getData();
analogData.value2 = ai2.getData();
- analogData.value3 = ai3.getData();
- analogData.value4 = ai4.getData();
- analogData.value5 = ai5.getData();
+ analogData.value3 = 0.;
+ analogData.value4 = 0.;
analogValueMutex.unlock();
// Signal that data has been changed
